| /******************************************************************************* |
| * Copyright (c) 2000, 2016 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Matt Chapman, mpchapman@gmail.com - 89977 Make JDT .java agnostic |
| * Ferenc Hechler, ferenc_hechler@users.sourceforge.net - 83258 [jar exporter] Deploy java application as executable jar |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.ui.jarpackager; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.lang.reflect.InvocationTargetException; |
| import java.net.URI; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.jar.Manifest; |
| import java.util.zip.ZipException; |
| import java.util.zip.ZipFile; |
| |
| import org.eclipse.swt.widgets.Shell; |
| |
| import org.eclipse.core.filesystem.EFS; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.MultiStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| |
| import org.eclipse.core.resources.IContainer; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IFolder; |
| import org.eclipse.core.resources.IMarker; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IncrementalProjectBuilder; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| |
| import org.eclipse.jface.operation.ModalContext; |
| |
| import org.eclipse.ui.actions.WorkspaceModifyOperation; |
| |
| import org.eclipse.jdt.core.IClassFile; |
| import org.eclipse.jdt.core.IClasspathEntry; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IJavaModelMarker; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.IPackageFragment; |
| import org.eclipse.jdt.core.IPackageFragmentRoot; |
| import org.eclipse.jdt.core.IRegion; |
| import org.eclipse.jdt.core.ITypeRoot; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.ToolFactory; |
| import org.eclipse.jdt.core.util.IClassFileReader; |
| import org.eclipse.jdt.core.util.ISourceAttribute; |
| |
| import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels; |
| import org.eclipse.jdt.internal.corext.util.JavaModelUtil; |
| import org.eclipse.jdt.internal.corext.util.Messages; |
| import org.eclipse.jdt.internal.corext.util.Resources; |
| |
| import org.eclipse.jdt.ui.JavaElementLabels; |
| import org.eclipse.jdt.ui.StandardJavaElementContentProvider; |
| import org.eclipse.jdt.ui.jarpackager.IJarBuilder; |
| import org.eclipse.jdt.ui.jarpackager.IJarBuilderExtension; |
| import org.eclipse.jdt.ui.jarpackager.IJarDescriptionWriter; |
| import org.eclipse.jdt.ui.jarpackager.IJarExportRunnable; |
| import org.eclipse.jdt.ui.jarpackager.JarPackageData; |
| import org.eclipse.jdt.ui.refactoring.RefactoringSaveHelper; |
| |
| import org.eclipse.jdt.internal.ui.IJavaStatusConstants; |
| import org.eclipse.jdt.internal.ui.JavaPlugin; |
| import org.eclipse.jdt.internal.ui.util.BusyIndicatorRunnableContext; |
| |
| /** |
| * Operation for exporting a resource and its children to a new JAR file. |
| */ |
| public class JarFileExportOperation extends WorkspaceModifyOperation implements IJarExportRunnable { |
| |
| private static class MessageMultiStatus extends MultiStatus { |
| MessageMultiStatus(String pluginId, int code, String message, Throwable exception) { |
| super(pluginId, code, message, exception); |
| } |
| /* |
| * allows to change the message |
| */ |
| @Override |
| protected void setMessage(String message) { |
| super.setMessage(message); |
| } |
| } |
| |
| private IJarBuilder fJarBuilder; |
| private JarPackageData fJarPackage; |
| private JarPackageData[] fJarPackages; |
| private Shell fParentShell; |
| private Map<String, ArrayList<IResource>> fJavaNameToClassFilesMap; |
| private IContainer fClassFilesMapContainer; |
| private Set<IContainer> fExportedClassContainers; |
| private MessageMultiStatus fStatus; |
| private StandardJavaElementContentProvider fJavaElementContentProvider; |
| private boolean fFilesSaved; |
| |
| /** |
| * Creates an instance of this class. |
| * |
| * @param jarPackage the JAR package specification |
| * @param parent the parent for the dialog, |
| * or <code>null</code> if no dialog should be presented |
| */ |
| public JarFileExportOperation(JarPackageData jarPackage, Shell parent) { |
| this(new JarPackageData[] {jarPackage}, parent); |
| } |
| |
| /** |
| * Creates an instance of this class. |
| * |
| * @param jarPackages an array with JAR package data objects |
| * @param parent the parent for the dialog, |
| * or <code>null</code> if no dialog should be presented |
| */ |
| public JarFileExportOperation(JarPackageData[] jarPackages, Shell parent) { |
| this(parent); |
| fJarPackages= jarPackages; |
| } |
| |
| private JarFileExportOperation(Shell parent) { |
| fParentShell= parent; |
| fStatus= new MessageMultiStatus(JavaPlugin.getPluginId(), IStatus.OK, "", null); //$NON-NLS-1$ |
| fJavaElementContentProvider= new StandardJavaElementContentProvider(); |
| } |
| |
| private void addToStatus(CoreException ex) { |
| IStatus status= ex.getStatus(); |
| String message= ex.getLocalizedMessage(); |
| if (message == null || message.length() < 1) { |
| message= JarPackagerMessages.JarFileExportOperation_coreErrorDuringExport; |
| status= new Status(status.getSeverity(), status.getPlugin(), status.getCode(), message, ex); |
| } |
| fStatus.add(status); |
| } |
| |
| /** |
| * Adds a new info to the list with the passed information. |
| * Normally the export operation continues after a warning. |
| * @param message the message |
| * @param error the throwable that caused the warning, or <code>null</code> |
| */ |
| protected void addInfo(String message, Throwable error) { |
| fStatus.add(new Status(IStatus.INFO, JavaPlugin.getPluginId(), IJavaStatusConstants.INTERNAL_ERROR, message, error)); |
| } |
| |
| /** |
| * Adds a new warning to the list with the passed information. |
| * Normally the export operation continues after a warning. |
| * @param message the message |
| * @param error the throwable that caused the warning, or <code>null</code> |
| */ |
| private void addWarning(String message, Throwable error) { |
| fStatus.add(new Status(IStatus.WARNING, JavaPlugin.getPluginId(), IJavaStatusConstants.INTERNAL_ERROR, message, error)); |
| } |
| |
| /** |
| * Adds a new error to the list with the passed information. |
| * Normally an error terminates the export operation. |
| * @param message the message |
| * @param error the throwable that caused the error, or <code>null</code> |
| */ |
| private void addError(String message, Throwable error) { |
| fStatus.add(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IJavaStatusConstants.INTERNAL_ERROR, message, error)); |
| } |
| |
| /** |
| * Answers the number of file resources specified by the JAR package. |
| * |
| * @return int |
| */ |
| private int countSelectedElements() { |
| Set<IJavaProject> enclosingJavaProjects= new HashSet<>(10); |
| int count= 0; |
| |
| int n= fJarPackage.getElements().length; |
| for (int i= 0; i < n; i++) { |
| Object element= fJarPackage.getElements()[i]; |
| |
| IJavaProject javaProject= getEnclosingJavaProject(element); |
| if (javaProject != null) |
| enclosingJavaProjects.add(javaProject); |
| |
| IResource resource= null; |
| if (element instanceof IJavaElement) { |
| IJavaElement je= (IJavaElement)element; |
| resource= je.getResource(); |
| if (resource == null) { |
| if (element instanceof IPackageFragmentRoot) { |
| IPackageFragmentRoot root= (IPackageFragmentRoot) element; |
| if (root.isArchive()) { |
| ZipFile file= null; |
| try { |
| file= JarPackagerUtil.getArchiveFile(root.getPath()); |
| if (file != null) |
| count+= file.size(); |
| } catch (CoreException e) { |
| JavaPlugin.log(e); |
| } finally { |
| try { |
| if (file != null) { |
| file.close(); |
| } |
| } catch (IOException e) { |
| addWarning(Messages.format(JarPackagerMessages.JarFileExportOperation_CloseZipFileError_message, new Object[] { JavaElementLabels.getElementLabel(root, JavaElementLabels.ALL_DEFAULT), e.getLocalizedMessage() }), e); |
| } |
| } |
| } else if (root.isExternal()) { |
| try { |
| count+= getClassFileCount(root.getChildren()); |
| } catch (JavaModelException e) { |
| JavaPlugin.log(e); |
| } |
| } |
| } |
| continue; |
| } |
| } else if (element instanceof IResource) { |
| resource= (IResource) element; |
| } |
| if (resource != null) { |
| if (resource.getType() == IResource.FILE) |
| count++; |
| else |
| count+= getTotalChildCount((IContainer) resource); |
| } |
| } |
| |
| if (fJarPackage.areOutputFoldersExported()) { |
| if (!fJarPackage.areJavaFilesExported()) |
| count= 0; |
| Iterator<IJavaProject> iter= enclosingJavaProjects.iterator(); |
| while (iter.hasNext()) { |
| IJavaProject javaProject= iter.next(); |
| IContainer[] outputContainers; |
| try { |
| outputContainers= getOutputContainers(javaProject); |
| } catch (CoreException ex) { |
| addToStatus(ex); |
| continue; |
| } |
| for (IContainer outputContainer : outputContainers) { |
| count += getTotalChildCount(outputContainer); |
| } |
| |
| } |
| } |
| |
| return count; |
| } |
| |
| private int getClassFileCount(IJavaElement[] children) throws JavaModelException { |
| int result= 0; |
| for (IJavaElement child : children) { |
| if (child instanceof IClassFile) { |
| result++; |
| } else if (child instanceof IPackageFragment) { |
| IPackageFragment fragment= (IPackageFragment) child; |
| result+= getClassFileCount(fragment.getChildren()); |
| } |
| } |
| return result; |
| } |
| |
| private int getTotalChildCount(IContainer container) { |
| IResource[] members; |
| try { |
| members= container.members(); |
| } catch (CoreException ex) { |
| return 0; |
| } |
| int count= 0; |
| for (IResource member : members) { |
| if (member.getType() == IResource.FILE) { |
| count++; |
| } else { |
| count += getTotalChildCount((IContainer) member); |
| } |
| } |
| return count; |
| } |
| |
| /** |
| * Exports the passed resource to the JAR file |
| * |
| * @param element the resource or JavaElement to export |
| * @param progressMonitor the progress monitor |
| * @throws InterruptedException thrown on cancel |
| */ |
| private void exportElement(Object element, IProgressMonitor progressMonitor) throws InterruptedException { |
| int leadSegmentsToRemove= 1; |
| IPackageFragmentRoot pkgRoot= null; |
| boolean isInJavaProject= false; |
| IResource resource= null; |
| ITypeRoot typeRootElement= null; |
| IJavaProject jProject= null; |
| if (element instanceof IJavaElement) { |
| isInJavaProject= true; |
| IJavaElement je= (IJavaElement)element; |
| if (!(je instanceof ITypeRoot)) { |
| exportJavaElement(progressMonitor, je); |
| return; |
| } |
| typeRootElement= (ITypeRoot) je; |
| jProject= typeRootElement.getJavaProject(); |
| pkgRoot= JavaModelUtil.getPackageFragmentRoot(je); |
| resource= typeRootElement.getResource(); |
| } else if (element instanceof IResource) { |
| resource= (IResource) element; |
| } else { |
| return; |
| } |
| |
| if (!resource.isAccessible()) { |
| addWarning(Messages.format(JarPackagerMessages.JarFileExportOperation_resourceNotFound, BasicElementLabels.getPathLabel(resource.getFullPath(), false)), null); |
| return; |
| } |
| |
| if (resource.getType() == IResource.FILE) { |
| if (!isInJavaProject) { |
| // check if it's a Java resource |
| try { |
| isInJavaProject= resource.getProject().hasNature(JavaCore.NATURE_ID); |
| } catch (CoreException ex) { |
| addWarning(Messages.format(JarPackagerMessages.JarFileExportOperation_projectNatureNotDeterminable, BasicElementLabels.getPathLabel(resource.getFullPath(), false)), ex); |
| return; |
| } |
| if (isInJavaProject) { |
| IJavaElement je= JavaCore.create(resource); |
| if (je instanceof ITypeRoot && je.exists()) { |
| exportElement(je, progressMonitor); |
| return; |
| } |
| |
| jProject= JavaCore.create(resource.getProject()); |
| try { |
| IPackageFragment pkgFragment= jProject.findPackageFragment(resource.getFullPath().removeLastSegments(1)); |
| if (pkgFragment != null) |
| pkgRoot= JavaModelUtil.getPackageFragmentRoot(pkgFragment); |
| else |
| pkgRoot= findPackageFragmentRoot(jProject, resource.getFullPath().removeLastSegments(1)); |
| } catch (JavaModelException ex) { |
| addWarning(Messages.format(JarPackagerMessages.JarFileExportOperation_javaPackageNotDeterminable, BasicElementLabels.getPathLabel(resource.getFullPath(), false)), ex); |
| return; |
| } |
| } |
| } |
| |
| if (pkgRoot != null && jProject != null) { |
| leadSegmentsToRemove= pkgRoot.getPath().segmentCount(); |
| boolean isOnBuildPath; |
| isOnBuildPath= jProject.isOnClasspath(resource); |
| if (!isOnBuildPath || (mustUseSourceFolderHierarchy() && !pkgRoot.getElementName().equals(IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH))) |
| leadSegmentsToRemove--; |
| } |
| |
| IPath destinationPath= resource.getFullPath().removeFirstSegments(leadSegmentsToRemove); |
| |
| if (typeRootElement != null) { |
| exportClassFiles(progressMonitor, typeRootElement, destinationPath); |
| } |
| |
| exportResource(progressMonitor, pkgRoot, isInJavaProject, resource, destinationPath); |
| |
| progressMonitor.worked(1); |
| ModalContext.checkCanceled(progressMonitor); |
| |
| } else |
| exportContainer(progressMonitor, (IContainer)resource); |
| } |
| |
| private void exportJavaElement(IProgressMonitor progressMonitor, IJavaElement je) throws InterruptedException { |
| if (je.getElementType() == IJavaElement.PACKAGE_FRAGMENT_ROOT && ((IPackageFragmentRoot) je).isArchive()) { |
| IPackageFragmentRoot root= (IPackageFragmentRoot) je; |
| ZipFile jarFile= null; |
| try { |
| jarFile= JarPackagerUtil.getArchiveFile(root.getPath()); |
| fJarBuilder.writeArchive(jarFile, progressMonitor); |
| } catch (CoreException e) { |
| addWarning(Messages.format(JarPackagerMessages.JarFileExportOperation_OpenZipFileError_message, new Object[] { JavaElementLabels.getElementLabel(root, JavaElementLabels.ALL_DEFAULT), e.getLocalizedMessage() }), e); |
| } finally { |
| try { |
| if (jarFile != null) { |
| jarFile.close(); |
| } |
| } catch (IOException e) { |
| addWarning(Messages.format(JarPackagerMessages.JarFileExportOperation_CloseZipFileError_message, new Object[] { JavaElementLabels.getElementLabel(root, JavaElementLabels.ALL_DEFAULT), e.getLocalizedMessage() }), e); |
| } |
| } |
| return; |
| } else if (je.getElementType() == IJavaElement.PACKAGE_FRAGMENT_ROOT && ((IPackageFragmentRoot) je).isExternal()) { |
| //External class folder |
| if (fJarBuilder instanceof IJarBuilderExtension) { |
| exportExternalClassFolder(((IPackageFragmentRoot) je), progressMonitor); |
| } else { |
| addWarning(Messages.format(JarPackagerMessages.JarFileExportOperation_canNotExportExternalClassFolder_warning, BasicElementLabels.getPathLabel(je.getPath(), true)), null); |
| } |
| return; |
| } |
| |
| for (Object child : fJavaElementContentProvider.getChildren(je)) { |
| exportElement(child, progressMonitor); |
| } |
| } |
| |
| private void exportExternalClassFolder(IPackageFragmentRoot classFolder, IProgressMonitor progressMonitor) throws InterruptedException { |
| try { |
| for (IJavaElement child : classFolder.getChildren()) { |
| exportExternalClassFolderElement(child, classFolder.getPath(), progressMonitor); |
| } |
| } catch (JavaModelException e) { |
| addToStatus(e); |
| } |
| } |
| |
| private void exportExternalClassFolderElement(IJavaElement javaElement, IPath classFolderPath, IProgressMonitor progressMonitor) throws JavaModelException, InterruptedException { |
| if (javaElement instanceof IClassFile) { |
| IClassFile classFile= (IClassFile) javaElement; |
| IPath path= classFile.getPath(); |
| |
| IPath destination= path.removeFirstSegments(classFolderPath.segmentCount()).setDevice(null); |
| |
| try { |
| ((IJarBuilderExtension) fJarBuilder).writeFile(path.toFile(), destination); |
| } catch (CoreException e) { |
| handleCoreExceptionOnExport(e); |
| } finally { |
| progressMonitor.worked(1); |
| ModalContext.checkCanceled(progressMonitor); |
| } |
| } else if (javaElement instanceof IPackageFragment) { |
| for (IJavaElement child : ((IPackageFragment) javaElement).getChildren()) { |
| exportExternalClassFolderElement(child, classFolderPath, progressMonitor); |
| } |
| } |
| } |
| |
| private void exportResource(IProgressMonitor progressMonitor, IResource resource, int leadingSegmentsToRemove) throws InterruptedException { |
| if (resource instanceof IContainer) { |
| IContainer container= (IContainer)resource; |
| IResource[] children; |
| try { |
| children= container.members(); |
| } catch (CoreException e) { |
| // this should never happen because an #isAccessible check is done before #members is invoked |
| addWarning(Messages.format(JarPackagerMessages.JarFileExportOperation_errorDuringExport, BasicElementLabels.getPathLabel(container.getFullPath(), false)), e); |
| return; |
| } |
| for (IResource child : children) { |
| exportResource(progressMonitor, child, leadingSegmentsToRemove); |
| } |
| } else if (resource instanceof IFile) { |
| try { |
| IPath destinationPath= resource.getFullPath().removeFirstSegments(leadingSegmentsToRemove); |
| progressMonitor.subTask(Messages.format(JarPackagerMessages.JarFileExportOperation_exporting, BasicElementLabels.getPathLabel(destinationPath, false))); |
| fJarBuilder.writeFile((IFile)resource, destinationPath); |
| } catch (CoreException ex) { |
| handleCoreExceptionOnExport(ex); |
| } finally { |
| progressMonitor.worked(1); |
| ModalContext.checkCanceled(progressMonitor); |
| } |
| } |
| } |
| |
| private void exportContainer(IProgressMonitor progressMonitor, IContainer container) throws InterruptedException { |
| if (container.getType() == IResource.FOLDER && isOutputFolder((IFolder)container)) |
| return; |
| |
| |
| |
| IResource[] children= null; |
| try { |
| children= container.members(); |
| } catch (CoreException exception) { |
| // this should never happen because an #isAccessible check is done before #members is invoked |
| addWarning(Messages.format(JarPackagerMessages.JarFileExportOperation_errorDuringExport, BasicElementLabels.getPathLabel(container.getFullPath(), false)), exception); |
| } |
| if (children != null) { |
| IJavaProject javaProject= JavaCore.create(container.getProject()); |
| boolean isOnCP= javaProject.isOnClasspath(container); |
| for (IResource child : children) { |
| if (isOnCP || !javaProject.isOnClasspath(child) || isInternalJar(child)) |
| exportElement(child, progressMonitor); |
| } |
| } |
| } |
| |
| /** |
| * Tells whether the given resource is an internal JAR. |
| * |
| * @param resource the resource to test |
| * @return <code>true</code> if it is an internal JAR, <code>false</code> otherwise |
| * @since 3.6 |
| */ |
| private boolean isInternalJar(IResource resource) { |
| if (resource.getType() != IResource.FILE) |
| return false; |
| |
| IJavaElement je= JavaCore.create(resource); |
| if (je == null || je.getElementType() != IJavaElement.PACKAGE_FRAGMENT_ROOT) |
| return false; |
| |
| IPackageFragmentRoot root= (IPackageFragmentRoot)je; |
| return root.isArchive() && !root.isExternal(); |
| } |
| |
| private IPackageFragmentRoot findPackageFragmentRoot(IJavaProject jProject, IPath path) throws JavaModelException { |
| if (jProject == null || path == null || path.segmentCount() <= 0) |
| return null; |
| IPackageFragmentRoot pkgRoot= jProject.findPackageFragmentRoot(path); |
| if (pkgRoot != null) |
| return pkgRoot; |
| else |
| return findPackageFragmentRoot(jProject, path.removeLastSegments(1)); |
| } |
| |
| private void exportResource(IProgressMonitor progressMonitor, IPackageFragmentRoot pkgRoot, boolean isInJavaProject, IResource resource, IPath destinationPath) { |
| |
| // Handle case where META-INF/MANIFEST.MF is part of the exported files |
| if (fJarPackage.areClassFilesExported() && destinationPath.toString().equals("META-INF/MANIFEST.MF")) {//$NON-NLS-1$ |
| if (fJarPackage.isManifestGenerated()) |
| addWarning(Messages.format(JarPackagerMessages.JarFileExportOperation_didNotAddManifestToJar, BasicElementLabels.getPathLabel(resource.getFullPath(), false)), null); |
| return; |
| } |
| |
| boolean isNonJavaResource= !isInJavaProject || pkgRoot == null; |
| boolean isInClassFolder= false; |
| try { |
| isInClassFolder= pkgRoot != null && !pkgRoot.isArchive() && pkgRoot.getKind() == IPackageFragmentRoot.K_BINARY; |
| } catch (JavaModelException ex) { |
| addWarning(Messages.format(JarPackagerMessages.JarFileExportOperation_cantGetRootKind, BasicElementLabels.getPathLabel(resource.getFullPath(), false)), ex); |
| } |
| if ((fJarPackage.areClassFilesExported() && |
| ((isNonJavaResource || (pkgRoot != null && !isJavaFile(resource) && !isClassFile(resource))) |
| || isInClassFolder && isClassFile(resource))) |
| || (fJarPackage.areJavaFilesExported() && (isNonJavaResource || (pkgRoot != null && !isClassFile(resource)) || (isInClassFolder && isClassFile(resource) && !fJarPackage.areClassFilesExported())))) { |
| try { |
| progressMonitor.subTask(Messages.format(JarPackagerMessages.JarFileExportOperation_exporting, BasicElementLabels.getPathLabel(destinationPath, false))); |
| fJarBuilder.writeFile((IFile)resource, destinationPath); |
| } catch (CoreException ex) { |
| handleCoreExceptionOnExport(ex); |
| } |
| } |
| } |
| |
| private boolean isOutputFolder(IFolder folder) { |
| try { |
| IJavaProject javaProject= JavaCore.create(folder.getProject()); |
| IPath outputFolderPath= javaProject.getOutputLocation(); |
| return folder.getFullPath().equals(outputFolderPath); |
| } catch (JavaModelException ex) { |
| return false; |
| } |
| } |
| |
| private void exportClassFiles(IProgressMonitor progressMonitor, ITypeRoot typeRootElement, IPath destinationPath) { |
| if (fJarPackage.areClassFilesExported()) { |
| try { |
| if (!typeRootElement.exists()) |
| return; |
| |
| // find corresponding file(s) on classpath and export |
| Iterator<? extends IResource> iter= filesOnClasspath(typeRootElement, destinationPath, progressMonitor); |
| IPath baseDestinationPath= destinationPath.removeLastSegments(1); |
| while (iter.hasNext()) { |
| IFile file= (IFile)iter.next(); |
| IPath classFilePath= baseDestinationPath.append(file.getName()); |
| progressMonitor.subTask(Messages.format(JarPackagerMessages.JarFileExportOperation_exporting, BasicElementLabels.getPathLabel(classFilePath, false))); |
| try { |
| fJarBuilder.writeFile(file, classFilePath); |
| } catch (CoreException ex) { |
| handleCoreExceptionOnExport(ex); |
| } |
| } |
| } catch (CoreException ex) { |
| addToStatus(ex); |
| } |
| } |
| } |
| |
| /** |
| * Exports the resources as specified by the JAR package. |
| * @param progressMonitor the progress monitor |
| * @throws InterruptedException thrown when cancelled |
| */ |
| private void exportSelectedElements(IProgressMonitor progressMonitor) throws InterruptedException { |
| fExportedClassContainers= new HashSet<>(10); |
| Set<IJavaProject> enclosingJavaProjects= new HashSet<>(10); |
| int n= fJarPackage.getElements().length; |
| for (int i= 0; i < n; i++) { |
| Object element= fJarPackage.getElements()[i]; |
| exportElement(element, progressMonitor); |
| if (fJarPackage.areOutputFoldersExported()) { |
| IJavaProject javaProject= getEnclosingJavaProject(element); |
| if (javaProject != null) |
| enclosingJavaProjects.add(javaProject); |
| } |
| } |
| if (fJarPackage.areOutputFoldersExported()) |
| exportOutputFolders(progressMonitor, enclosingJavaProjects); |
| } |
| |
| private IJavaProject getEnclosingJavaProject(Object element) { |
| if (element instanceof IJavaElement) { |
| return ((IJavaElement)element).getJavaProject(); |
| } else if (element instanceof IResource) { |
| IProject project= ((IResource)element).getProject(); |
| try { |
| if (project.hasNature(JavaCore.NATURE_ID)) |
| return JavaCore.create(project); |
| } catch (CoreException ex) { |
| addWarning(Messages.format(JarPackagerMessages.JarFileExportOperation_projectNatureNotDeterminable, BasicElementLabels.getPathLabel(project.getFullPath(), false)), ex); |
| } |
| } |
| return null; |
| } |
| |
| private void exportOutputFolders(IProgressMonitor progressMonitor, Set<IJavaProject> javaProjects) throws InterruptedException { |
| if (javaProjects == null) |
| return; |
| |
| Iterator<IJavaProject> iter= javaProjects.iterator(); |
| while (iter.hasNext()) { |
| IJavaProject javaProject= iter.next(); |
| IContainer[] outputContainers; |
| try { |
| outputContainers= getOutputContainers(javaProject); |
| } catch (CoreException ex) { |
| addToStatus(ex); |
| continue; |
| } |
| for (IContainer outputContainer : outputContainers) { |
| exportResource(progressMonitor, outputContainer, outputContainer.getFullPath().segmentCount()); |
| } |
| |
| } |
| } |
| |
| private IContainer[] getOutputContainers(IJavaProject javaProject) throws CoreException { |
| Set<IPath> outputPaths= new HashSet<>(); |
| boolean includeDefaultOutputPath= false; |
| for (IPackageFragmentRoot root : javaProject.getPackageFragmentRoots()) { |
| if (root != null) { |
| IClasspathEntry cpEntry = root.getRawClasspathEntry(); |
| if (cpEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { |
| IPath location= cpEntry.getOutputLocation(); |
| if (location != null) |
| outputPaths.add(location); |
| else |
| includeDefaultOutputPath= true; |
| } |
| } |
| } |
| |
| if (includeDefaultOutputPath) { |
| // Use default output location |
| outputPaths.add(javaProject.getOutputLocation()); |
| } |
| |
| // Convert paths to containers |
| Set<IContainer> outputContainers= new HashSet<>(outputPaths.size()); |
| Iterator<IPath> iter= outputPaths.iterator(); |
| while (iter.hasNext()) { |
| IPath path= iter.next(); |
| if (javaProject.getProject().getFullPath().equals(path)) |
| outputContainers.add(javaProject.getProject()); |
| else { |
| IFolder outputFolder= createFolderHandle(path); |
| if (outputFolder == null || !outputFolder.isAccessible()) { |
| String msg= JarPackagerMessages.JarFileExportOperation_outputContainerNotAccessible; |
| addToStatus(new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IJavaStatusConstants.INTERNAL_ERROR, msg, null))); |
| } else |
| outputContainers.add(outputFolder); |
| } |
| } |
| return outputContainers.toArray(new IContainer[outputContainers.size()]); |
| } |
| |
| /** |
| * Returns an iterator on a list with files that correspond to the |
| * passed file and that are on the classpath of its project. |
| * |
| * @param typeRootElement the class file or compilation unit to evaluate the class files for |
| * @param pathInJar the path that the file has in the JAR (i.e. project and source folder segments removed) |
| * @param progressMonitor the progressMonitor to use |
| * @return the iterator over the corresponding classpath files for the given file |
| * @throws CoreException if an exception occurs when looking for the files |
| */ |
| private Iterator<? extends IResource> filesOnClasspath(ITypeRoot typeRootElement, IPath pathInJar, IProgressMonitor progressMonitor) throws CoreException { |
| IFile file= (IFile) typeRootElement.getResource(); |
| IJavaProject javaProject= typeRootElement.getJavaProject(); |
| IPackageFragmentRoot pkgRoot= JavaModelUtil.getPackageFragmentRoot(typeRootElement); |
| |
| // Allow JAR Package to provide its own strategy |
| IFile[] classFiles= fJarPackage.findClassfilesFor(file); |
| if (classFiles != null) |
| return Arrays.asList(classFiles).iterator(); |
| |
| if (!isJavaFile(file)) |
| return Collections.EMPTY_LIST.iterator(); |
| |
| IPath outputPath= null; |
| if (pkgRoot != null) { |
| IClasspathEntry cpEntry= pkgRoot.getRawClasspathEntry(); |
| if (cpEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) |
| outputPath= cpEntry.getOutputLocation(); |
| } |
| if (outputPath == null) |
| // Use default output location |
| outputPath= javaProject.getOutputLocation(); |
| |
| IContainer outputContainer; |
| if (javaProject.getProject().getFullPath().equals(outputPath)) |
| outputContainer= javaProject.getProject(); |
| else { |
| outputContainer= createFolderHandle(outputPath); |
| if (outputContainer == null || !outputContainer.isAccessible()) { |
| String msg= JarPackagerMessages.JarFileExportOperation_outputContainerNotAccessible; |
| throw new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IJavaStatusConstants.INTERNAL_ERROR, msg, null)); |
| } |
| } |
| |
| // Java CU - search files with .class ending |
| boolean hasErrors= hasCompileErrors(file); |
| boolean hasWarnings= hasCompileWarnings(file); |
| boolean canBeExported= canBeExported(hasErrors, hasWarnings); |
| reportPossibleCompileProblems(file, hasErrors, hasWarnings, canBeExported); |
| if (!canBeExported) |
| return Collections.EMPTY_LIST.iterator(); |
| IContainer classContainer= outputContainer; |
| if (pathInJar.segmentCount() > 1) { |
| String lastSegment= pathInJar.segment(pathInJar.segmentCount() - 1); |
| if (!JavaModelUtil.MODULE_INFO_JAVA.equals(lastSegment) |
| || !JavaModelUtil.is9OrHigher(javaProject)) { |
| classContainer= outputContainer.getFolder(pathInJar.removeLastSegments(1)); |
| } |
| } |
| |
| if (fExportedClassContainers.contains(classContainer)) |
| return Collections.EMPTY_LIST.iterator(); |
| |
| if (JavaCore.DO_NOT_GENERATE.equals(javaProject.getOption(JavaCore.COMPILER_SOURCE_FILE_ATTR, true))) { |
| IRegion region= JavaCore.newRegion(); |
| region.add(typeRootElement); |
| IResource[] generatedResources= JavaCore.getGeneratedResources(region, false); |
| if (generatedResources.length > 0) |
| return Arrays.asList(generatedResources).iterator(); |
| // give the old code a last chance |
| } |
| if (fClassFilesMapContainer == null || !fClassFilesMapContainer.equals(classContainer)) { |
| fJavaNameToClassFilesMap= buildJavaToClassMap(classContainer, progressMonitor); |
| if (fJavaNameToClassFilesMap == null) { |
| // Could not fully build map. fallback is to export whole directory |
| String containerName= BasicElementLabels.getPathLabel(classContainer.getFullPath(), false); |
| String msg= Messages.format(JarPackagerMessages.JarFileExportOperation_missingSourceFileAttributeExportedAll, containerName); |
| addInfo(msg, null); |
| fExportedClassContainers.add(classContainer); |
| return getClassesIn(classContainer); |
| } |
| fClassFilesMapContainer= classContainer; |
| } |
| ArrayList<IResource> classFileList= fJavaNameToClassFilesMap.get(file.getName()); |
| if (classFileList == null || classFileList.isEmpty()) { |
| String msg= Messages.format(JarPackagerMessages.JarFileExportOperation_classFileOnClasspathNotAccessible, BasicElementLabels.getPathLabel(file.getFullPath(), false)); |
| throw new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IJavaStatusConstants.INTERNAL_ERROR, msg, null)); |
| } |
| return classFileList.iterator(); |
| } |
| |
| private Iterator<IResource> getClassesIn(IContainer classContainer) throws CoreException { |
| IResource[] resources= classContainer.members(); |
| List<IResource> files= new ArrayList<>(resources.length); |
| for (IResource resource : resources) { |
| if (resource.getType() == IResource.FILE && isClassFile(resource)) { |
| files.add(resource); |
| } |
| } |
| return files.iterator(); |
| } |
| |
| /** |
| * Answers whether the given resource is a Java file. |
| * The resource must be a file whose file name ends with ".java", |
| * or an extension defined as Java source. |
| * |
| * @param file the file to test |
| * @return a <code>true<code> if the given resource is a Java file |
| */ |
| private boolean isJavaFile(IResource file) { |
| return file != null |
| && file.getType() == IResource.FILE |
| && file.getFileExtension() != null |
| && JavaCore.isJavaLikeFileName(file.getName()); |
| } |
| |
| /** |
| * Answers whether the given resource is a class file. |
| * The resource must be a file whose file name ends with ".class". |
| * |
| * @param file the file to test |
| * @return a <code>true<code> if the given resource is a class file |
| */ |
| private boolean isClassFile(IResource file) { |
| return file != null |
| && file.getType() == IResource.FILE |
| && file.getFileExtension() != null |
| && file.getFileExtension().equalsIgnoreCase("class"); //$NON-NLS-1$ |
| } |
| |
| /* |
| * Builds and returns a map that has the class files |
| * for each java file in a given directory |
| */ |
| private Map<String, ArrayList<IResource>> buildJavaToClassMap(IContainer container, IProgressMonitor monitor) throws CoreException { |
| if (container == null || !container.isAccessible()) |
| return new HashMap<>(0); |
| /* |
| * XXX: Bug 6584: Need a way to get class files for a java file (or CU) |
| */ |
| IClassFileReader cfReader= null; |
| IResource[] members= container.members(); |
| Map<String, ArrayList<IResource>> map= new HashMap<>(members.length); |
| for (IResource member : members) { |
| if (isClassFile(member)) { |
| IFile classFile = (IFile) member; |
| URI location= classFile.getLocationURI(); |
| if (location != null) { |
| InputStream contents= null; |
| try { |
| contents= EFS.getStore(location).openInputStream(EFS.NONE, monitor); |
| cfReader= ToolFactory.createDefaultClassFileReader(contents, IClassFileReader.CLASSFILE_ATTRIBUTES); |
| } finally { |
| try { |
| if (contents != null) |
| contents.close(); |
| } catch (IOException e) { |
| throw new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.ERROR, |
| Messages.format(JarPackagerMessages.JarFileExportOperation_errorCannotCloseConnection, BasicElementLabels.getURLPart(Resources.getLocationString(classFile))), |
| e)); |
| } |
| } |
| if (cfReader != null) { |
| ISourceAttribute sourceAttribute= cfReader.getSourceFileAttribute(); |
| if (sourceAttribute == null) { |
| /* |
| * Can't fully build the map because one or more |
| * class file does not contain the name of its |
| * source file. |
| */ |
| addWarning(Messages.format( |
| JarPackagerMessages.JarFileExportOperation_classFileWithoutSourceFileAttribute, |
| BasicElementLabels.getURLPart(Resources.getLocationString(classFile))), null); |
| return null; |
| } |
| String javaName= new String(sourceAttribute.getSourceFileName()); |
| ArrayList<IResource> classFiles= map.get(javaName); |
| if (classFiles == null) { |
| classFiles= new ArrayList<>(3); |
| map.put(javaName, classFiles); |
| } |
| classFiles.add(classFile); |
| } |
| } |
| } |
| } |
| return map; |
| } |
| |
| /** |
| * Creates a folder resource handle for the folder with the given workspace path. |
| * |
| * @param folderPath the path of the folder to create a handle for |
| * @return the new folder resource handle |
| */ |
| private IFolder createFolderHandle(IPath folderPath) { |
| if (folderPath.isValidPath(folderPath.toString()) && folderPath.segmentCount() >= 2) |
| return JavaPlugin.getWorkspace().getRoot().getFolder(folderPath); |
| else |
| return null; |
| } |
| |
| /** |
| * Handles core exceptions that are thrown by {@link IJarBuilder#writeFile(IFile, IPath)}. |
| * |
| * @param ex the core exception |
| * @since 3.5 |
| */ |
| private void handleCoreExceptionOnExport(CoreException ex) { |
| Throwable realEx= ex.getStatus().getException(); |
| if (realEx instanceof ZipException && realEx.getMessage() != null |
| && realEx.getMessage().startsWith("duplicate entry:")) //$NON-NLS-1$ hardcoded message string from java.util.zip.ZipOutputStream.putNextEntry(ZipEntry) |
| addWarning(ex.getMessage(), realEx); |
| else |
| addToStatus(ex); |
| } |
| |
| /** |
| * Returns the status of this operation. |
| * The result is a status object containing individual |
| * status objects. |
| * |
| * @return the status of this operation |
| */ |
| @Override |
| public IStatus getStatus() { |
| String message= null; |
| switch (fStatus.getSeverity()) { |
| case IStatus.OK: |
| default: |
| // defensive code in case new severity is defined |
| message= ""; //$NON-NLS-1$ |
| break; |
| case IStatus.INFO: |
| message= JarPackagerMessages.JarFileExportOperation_exportFinishedWithInfo; |
| break; |
| case IStatus.WARNING: |
| message= JarPackagerMessages.JarFileExportOperation_exportFinishedWithWarnings; |
| break; |
| case IStatus.ERROR: |
| if (fJarPackages.length > 1) |
| message= JarPackagerMessages.JarFileExportOperation_creationOfSomeJARsFailed; |
| else |
| message= JarPackagerMessages.JarFileExportOperation_jarCreationFailed; |
| break; |
| } |
| fStatus.setMessage(message); |
| return fStatus; |
| } |
| |
| private boolean canBeExported(boolean hasErrors, boolean hasWarnings) { |
| return (!hasErrors && !hasWarnings) |
| || (hasErrors && fJarPackage.areErrorsExported()) |
| || (hasWarnings && fJarPackage.exportWarnings()); |
| } |
| |
| private void reportPossibleCompileProblems(IFile file, boolean hasErrors, boolean hasWarnings, boolean canBeExported) { |
| if (hasErrors) { |
| if (canBeExported) |
| addWarning(Messages.format(JarPackagerMessages.JarFileExportOperation_exportedWithCompileErrors, BasicElementLabels.getPathLabel(file.getFullPath(), false)), null); |
| else |
| addError(Messages.format(JarPackagerMessages.JarFileExportOperation_notExportedDueToCompileErrors, BasicElementLabels.getPathLabel(file.getFullPath(), false)), null); |
| } |
| if (hasWarnings) { |
| if (canBeExported) |
| addWarning(Messages.format(JarPackagerMessages.JarFileExportOperation_exportedWithCompileWarnings, BasicElementLabels.getPathLabel(file.getFullPath(), false)), null); |
| else |
| addError(Messages.format(JarPackagerMessages.JarFileExportOperation_notExportedDueToCompileWarnings, BasicElementLabels.getPathLabel(file.getFullPath(), false)), null); |
| } |
| } |
| |
| /** |
| * Exports the resources as specified by the JAR package. |
| * |
| * @param progressMonitor the progress monitor that displays the progress |
| * @throws InvocationTargetException thrown when an ecxeption occurred |
| * @throws InterruptedException thrown when cancelled |
| * @see #getStatus() |
| */ |
| @Override |
| protected void execute(IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException { |
| int count= fJarPackages.length; |
| progressMonitor.beginTask("", count); //$NON-NLS-1$ |
| try { |
| for (int i= 0; i < count; i++) { |
| SubProgressMonitor subProgressMonitor= new SubProgressMonitor(progressMonitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); |
| fJarPackage= fJarPackages[i]; |
| if (fJarPackage != null) |
| singleRun(subProgressMonitor); |
| } |
| } finally { |
| progressMonitor.done(); |
| } |
| } |
| |
| private void singleRun(IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException { |
| try { |
| if (!preconditionsOK()) |
| throw new InvocationTargetException(null, JarPackagerMessages.JarFileExportOperation_jarCreationFailedSeeDetails); |
| int totalWork= countSelectedElements(); |
| if (fJarPackage.areGeneratedFilesExported() |
| && ((!isAutoBuilding() && fJarPackage.isBuildingIfNeeded()) |
| || (isAutoBuilding() && fFilesSaved))) { |
| int subMonitorTicks= totalWork/10; |
| totalWork += subMonitorTicks; |
| progressMonitor.beginTask("", totalWork); //$NON-NLS-1$ |
| SubProgressMonitor subProgressMonitor= new SubProgressMonitor(progressMonitor, subMonitorTicks, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); |
| buildProjects(subProgressMonitor); |
| } else |
| progressMonitor.beginTask("", totalWork); //$NON-NLS-1$ |
| |
| fJarBuilder = fJarPackage.getJarBuilder(); |
| fJarBuilder.open(fJarPackage, fParentShell, fStatus); |
| |
| exportSelectedElements(progressMonitor); |
| if (getStatus().getSeverity() != IStatus.ERROR) { |
| progressMonitor.subTask(JarPackagerMessages.JarFileExportOperation_savingFiles); |
| saveFiles(); |
| } |
| } catch (CoreException ex) { |
| addToStatus(ex); |
| } finally { |
| try { |
| if (fJarBuilder != null) |
| fJarBuilder.close(); |
| } catch (CoreException ex) { |
| addToStatus(ex); |
| } |
| progressMonitor.done(); |
| } |
| } |
| |
| private boolean preconditionsOK() { |
| if (!fJarPackage.areGeneratedFilesExported() && !fJarPackage.areJavaFilesExported()) { |
| addError(JarPackagerMessages.JarFileExportOperation_noExportTypeChosen, null); |
| return false; |
| } |
| if (fJarPackage.getElements() == null || fJarPackage.getElements().length == 0) { |
| addError(JarPackagerMessages.JarFileExportOperation_noResourcesSelected, null); |
| return false; |
| } |
| if (fJarPackage.getAbsoluteJarLocation() == null) { |
| addError(JarPackagerMessages.JarFileExportOperation_invalidJarLocation, null); |
| return false; |
| } |
| File targetFile= fJarPackage.getAbsoluteJarLocation().toFile(); |
| if (targetFile.exists() && !targetFile.canWrite()) { |
| addError(JarPackagerMessages.JarFileExportOperation_jarFileExistsAndNotWritable, null); |
| return false; |
| } |
| if (!fJarPackage.isManifestAccessible()) { |
| addError(JarPackagerMessages.JarFileExportOperation_manifestDoesNotExist, null); |
| return false; |
| } |
| if (!fJarPackage.isMainClassValid(new BusyIndicatorRunnableContext())) { |
| addError(JarPackagerMessages.JarFileExportOperation_invalidMainClass, null); |
| return false; |
| } |
| |
| if (fParentShell != null) { |
| final boolean[] res= { false }; |
| fParentShell.getDisplay().syncExec(() -> { |
| RefactoringSaveHelper refactoringSaveHelper= new RefactoringSaveHelper(RefactoringSaveHelper.SAVE_ALL_ALWAYS_ASK); |
| res[0]= refactoringSaveHelper.saveEditors(fParentShell); |
| fFilesSaved= refactoringSaveHelper.didSaveFiles(); |
| }); |
| if (!res[0]) { |
| addError(JarPackagerMessages.JarFileExportOperation_fileUnsaved, null); |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| private void saveFiles() { |
| // Save the manifest |
| if (fJarPackage.areGeneratedFilesExported() && fJarPackage.isManifestGenerated() && fJarPackage.isManifestSaved()) { |
| try { |
| saveManifest(); |
| } catch (CoreException | IOException ex) { |
| addError(JarPackagerMessages.JarFileExportOperation_errorSavingManifest, ex); |
| } |
| } |
| |
| // Save the description |
| if (fJarPackage.isDescriptionSaved()) { |
| try { |
| saveDescription(); |
| } catch (CoreException | IOException ex) { |
| addError(JarPackagerMessages.JarFileExportOperation_errorSavingDescription, ex); |
| } |
| } |
| } |
| |
| private void saveDescription() throws CoreException, IOException { |
| // Adjust JAR package attributes |
| if (fJarPackage.isManifestReused()) |
| fJarPackage.setGenerateManifest(false); |
| ByteArrayOutputStream objectStreamOutput= new ByteArrayOutputStream(); |
| IFile descriptionFile= fJarPackage.getDescriptionFile(); |
| String encoding= "UTF-8"; //$NON-NLS-1$ |
| try { |
| encoding= descriptionFile.getCharset(true); |
| } catch (CoreException exception) { |
| JavaPlugin.log(exception); |
| } |
| IJarDescriptionWriter writer= fJarPackage.createJarDescriptionWriter(objectStreamOutput, encoding); |
| ByteArrayInputStream fileInput= null; |
| try { |
| writer.write(fJarPackage); |
| fileInput= new ByteArrayInputStream(objectStreamOutput.toByteArray()); |
| if (descriptionFile.isAccessible()) { |
| if (fJarPackage.allowOverwrite() || JarPackagerUtil.askForOverwritePermission(fParentShell, descriptionFile.getFullPath(), false)) |
| descriptionFile.setContents(fileInput, true, true, null); |
| } else |
| descriptionFile.create(fileInput, true, null); |
| } finally { |
| if (fileInput != null) |
| fileInput.close(); |
| if (writer != null) |
| writer.close(); |
| } |
| } |
| |
| private void saveManifest() throws CoreException, IOException { |
| ByteArrayOutputStream manifestOutput= new ByteArrayOutputStream(); |
| Manifest manifest= fJarPackage.getManifestProvider().create(fJarPackage); |
| manifest.write(manifestOutput); |
| ByteArrayInputStream fileInput= new ByteArrayInputStream(manifestOutput.toByteArray()); |
| IFile manifestFile= fJarPackage.getManifestFile(); |
| if (manifestFile.isAccessible()) { |
| if (fJarPackage.allowOverwrite() || JarPackagerUtil.askForOverwritePermission(fParentShell, manifestFile.getFullPath(), false)) |
| manifestFile.setContents(fileInput, true, true, null); |
| } else |
| manifestFile.create(fileInput, true, null); |
| } |
| |
| private boolean isAutoBuilding() { |
| return ResourcesPlugin.getWorkspace().getDescription().isAutoBuilding(); |
| } |
| |
| private void buildProjects(IProgressMonitor progressMonitor) { |
| Set<IProject> builtProjects= new HashSet<>(10); |
| for (Object e : fJarPackage.getElements()) { |
| IProject project= null; |
| Object element= e; |
| if (element instanceof IResource) |
| project= ((IResource)element).getProject(); |
| else if (element instanceof IJavaElement) |
| project= ((IJavaElement)element).getJavaProject().getProject(); |
| if (project != null && !builtProjects.contains(project)) { |
| try { |
| project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, progressMonitor); |
| } catch (CoreException ex) { |
| String message= Messages.format(JarPackagerMessages.JarFileExportOperation_errorDuringProjectBuild, BasicElementLabels.getResourceName(project)); |
| addError(message, ex); |
| } finally { |
| // don't try to build same project a second time even if it failed |
| builtProjects.add(project); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Tells whether the given resource (or its children) have compile errors. |
| * The method acts on the current build state and does not recompile. |
| * |
| * @param resource the resource to check for errors |
| * @return <code>true</code> if the resource (and its children) are error free |
| * @throws CoreException import org.eclipse.core.runtime.CoreException if there's a marker problem |
| */ |
| private boolean hasCompileErrors(IResource resource) throws CoreException { |
| for (IMarker problemMarker : resource.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE)) { |
| if (problemMarker.getAttribute(IMarker.SEVERITY, -1) == IMarker.SEVERITY_ERROR) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Tells whether the given resource (or its children) have compile errors. |
| * The method acts on the current build state and does not recompile. |
| * |
| * @param resource the resource to check for errors |
| * @return <code>true</code> if the resource (and its children) are error free |
| * @throws CoreException import org.eclipse.core.runtime.CoreException if there's a marker problem |
| */ |
| private boolean hasCompileWarnings(IResource resource) throws CoreException { |
| for (IMarker problemMarker : resource.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE)) { |
| if (problemMarker.getAttribute(IMarker.SEVERITY, -1) == IMarker.SEVERITY_WARNING) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private boolean mustUseSourceFolderHierarchy() { |
| return fJarPackage.useSourceFolderHierarchy() && fJarPackage.areJavaFilesExported() && !fJarPackage.areGeneratedFilesExported(); |
| } |
| } |