0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: * Matt Chapman, mpchapman@gmail.com - 89977 Make JDT .java agnostic
0011: *******************************************************************************/package org.eclipse.jdt.internal.ui.jarpackager;
0012:
0013: import java.io.ByteArrayInputStream;
0014: import java.io.ByteArrayOutputStream;
0015: import java.io.File;
0016: import java.io.IOException;
0017: import java.io.InputStream;
0018: import java.lang.reflect.InvocationTargetException;
0019: import java.net.URI;
0020: import java.util.ArrayList;
0021: import java.util.Arrays;
0022: import java.util.Collections;
0023: import java.util.HashMap;
0024: import java.util.HashSet;
0025: import java.util.Iterator;
0026: import java.util.List;
0027: import java.util.Map;
0028: import java.util.Set;
0029: import java.util.jar.Manifest;
0030: import java.util.zip.ZipException;
0031:
0032: import org.eclipse.core.filesystem.EFS;
0033: import org.eclipse.core.runtime.CoreException;
0034: import org.eclipse.core.runtime.IPath;
0035: import org.eclipse.core.runtime.IProgressMonitor;
0036: import org.eclipse.core.runtime.IStatus;
0037: import org.eclipse.core.runtime.MultiStatus;
0038: import org.eclipse.core.runtime.Status;
0039: import org.eclipse.core.runtime.SubProgressMonitor;
0040:
0041: import org.eclipse.core.resources.IContainer;
0042: import org.eclipse.core.resources.IFile;
0043: import org.eclipse.core.resources.IFolder;
0044: import org.eclipse.core.resources.IMarker;
0045: import org.eclipse.core.resources.IProject;
0046: import org.eclipse.core.resources.IResource;
0047: import org.eclipse.core.resources.IncrementalProjectBuilder;
0048: import org.eclipse.core.resources.ResourcesPlugin;
0049:
0050: import org.eclipse.swt.widgets.Shell;
0051:
0052: import org.eclipse.jface.operation.ModalContext;
0053:
0054: import org.eclipse.ui.actions.WorkspaceModifyOperation;
0055:
0056: import org.eclipse.jdt.core.IClasspathEntry;
0057: import org.eclipse.jdt.core.IJavaElement;
0058: import org.eclipse.jdt.core.IJavaModelMarker;
0059: import org.eclipse.jdt.core.IJavaProject;
0060: import org.eclipse.jdt.core.IPackageFragment;
0061: import org.eclipse.jdt.core.IPackageFragmentRoot;
0062: import org.eclipse.jdt.core.IRegion;
0063: import org.eclipse.jdt.core.ITypeRoot;
0064: import org.eclipse.jdt.core.JavaCore;
0065: import org.eclipse.jdt.core.JavaModelException;
0066: import org.eclipse.jdt.core.ToolFactory;
0067: import org.eclipse.jdt.core.util.IClassFileReader;
0068: import org.eclipse.jdt.core.util.ISourceAttribute;
0069:
0070: import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
0071: import org.eclipse.jdt.internal.corext.util.Messages;
0072: import org.eclipse.jdt.internal.corext.util.Resources;
0073:
0074: import org.eclipse.jdt.ui.StandardJavaElementContentProvider;
0075: import org.eclipse.jdt.ui.jarpackager.IJarDescriptionWriter;
0076: import org.eclipse.jdt.ui.jarpackager.IJarExportRunnable;
0077: import org.eclipse.jdt.ui.jarpackager.JarPackageData;
0078: import org.eclipse.jdt.ui.jarpackager.JarWriter3;
0079:
0080: import org.eclipse.jdt.internal.ui.IJavaStatusConstants;
0081: import org.eclipse.jdt.internal.ui.JavaPlugin;
0082: import org.eclipse.jdt.internal.ui.refactoring.RefactoringSaveHelper;
0083: import org.eclipse.jdt.internal.ui.util.BusyIndicatorRunnableContext;
0084:
0085: /**
0086: * Operation for exporting a resource and its children to a new JAR file.
0087: */
0088: public class JarFileExportOperation extends WorkspaceModifyOperation
0089: implements IJarExportRunnable {
0090:
0091: private static class MessageMultiStatus extends MultiStatus {
0092: MessageMultiStatus(String pluginId, int code, String message,
0093: Throwable exception) {
0094: super (pluginId, code, message, exception);
0095: }
0096:
0097: /*
0098: * allows to change the message
0099: */
0100: protected void setMessage(String message) {
0101: super .setMessage(message);
0102: }
0103: }
0104:
0105: private JarWriter3 fJarWriter;
0106: private JarPackageData fJarPackage;
0107: private JarPackageData[] fJarPackages;
0108: private Shell fParentShell;
0109: private Map fJavaNameToClassFilesMap;
0110: private IContainer fClassFilesMapContainer;
0111: private Set fExportedClassContainers;
0112: private MessageMultiStatus fStatus;
0113: private StandardJavaElementContentProvider fJavaElementContentProvider;
0114: private boolean fFilesSaved;
0115:
0116: /**
0117: * Creates an instance of this class.
0118: *
0119: * @param jarPackage the JAR package specification
0120: * @param parent the parent for the dialog,
0121: * or <code>null</code> if no dialog should be presented
0122: */
0123: public JarFileExportOperation(JarPackageData jarPackage,
0124: Shell parent) {
0125: this (new JarPackageData[] { jarPackage }, parent);
0126: }
0127:
0128: /**
0129: * Creates an instance of this class.
0130: *
0131: * @param jarPackages an array with JAR package data objects
0132: * @param parent the parent for the dialog,
0133: * or <code>null</code> if no dialog should be presented
0134: */
0135: public JarFileExportOperation(JarPackageData[] jarPackages,
0136: Shell parent) {
0137: this (parent);
0138: fJarPackages = jarPackages;
0139: }
0140:
0141: private JarFileExportOperation(Shell parent) {
0142: fParentShell = parent;
0143: fStatus = new MessageMultiStatus(JavaPlugin.getPluginId(),
0144: IStatus.OK, "", null); //$NON-NLS-1$
0145: fJavaElementContentProvider = new StandardJavaElementContentProvider();
0146: }
0147:
0148: private void addToStatus(CoreException ex) {
0149: IStatus status = ex.getStatus();
0150: String message = ex.getLocalizedMessage();
0151: if (message == null || message.length() < 1) {
0152: message = JarPackagerMessages.JarFileExportOperation_coreErrorDuringExport;
0153: status = new Status(status.getSeverity(), status
0154: .getPlugin(), status.getCode(), message, ex);
0155: }
0156: fStatus.add(status);
0157: }
0158:
0159: /**
0160: * Adds a new info to the list with the passed information.
0161: * Normally the export operation continues after a warning.
0162: * @param message the message
0163: * @param error the throwable that caused the warning, or <code>null</code>
0164: */
0165: protected void addInfo(String message, Throwable error) {
0166: fStatus.add(new Status(IStatus.INFO, JavaPlugin.getPluginId(),
0167: IJavaStatusConstants.INTERNAL_ERROR, message, error));
0168: }
0169:
0170: /**
0171: * Adds a new warning to the list with the passed information.
0172: * Normally the export operation continues after a warning.
0173: * @param message the message
0174: * @param error the throwable that caused the warning, or <code>null</code>
0175: */
0176: private void addWarning(String message, Throwable error) {
0177: fStatus.add(new Status(IStatus.WARNING, JavaPlugin
0178: .getPluginId(), IJavaStatusConstants.INTERNAL_ERROR,
0179: message, error));
0180: }
0181:
0182: /**
0183: * Adds a new error to the list with the passed information.
0184: * Normally an error terminates the export operation.
0185: * @param message the message
0186: * @param error the throwable that caused the error, or <code>null</code>
0187: */
0188: private void addError(String message, Throwable error) {
0189: fStatus.add(new Status(IStatus.ERROR, JavaPlugin.getPluginId(),
0190: IJavaStatusConstants.INTERNAL_ERROR, message, error));
0191: }
0192:
0193: /**
0194: * Answers the number of file resources specified by the JAR package.
0195: *
0196: * @return int
0197: */
0198: private int countSelectedElements() {
0199: Set enclosingJavaProjects = new HashSet(10);
0200: int count = 0;
0201:
0202: int n = fJarPackage.getElements().length;
0203: for (int i = 0; i < n; i++) {
0204: Object element = fJarPackage.getElements()[i];
0205:
0206: IJavaProject javaProject = getEnclosingJavaProject(element);
0207: if (javaProject != null)
0208: enclosingJavaProjects.add(javaProject);
0209:
0210: IResource resource = null;
0211: if (element instanceof IJavaElement) {
0212: IJavaElement je = (IJavaElement) element;
0213: try {
0214: resource = je.getUnderlyingResource();
0215: } catch (JavaModelException ex) {
0216: continue;
0217: }
0218:
0219: // Should not happen since we only export source files
0220: if (resource == null)
0221: continue;
0222: } else
0223: resource = (IResource) element;
0224: if (resource != null) {
0225: if (resource.getType() == IResource.FILE)
0226: count++;
0227: else
0228: count += getTotalChildCount((IContainer) resource);
0229: }
0230: }
0231:
0232: if (fJarPackage.areOutputFoldersExported()) {
0233: if (!fJarPackage.areJavaFilesExported())
0234: count = 0;
0235: Iterator iter = enclosingJavaProjects.iterator();
0236: while (iter.hasNext()) {
0237: IJavaProject javaProject = (IJavaProject) iter.next();
0238: IContainer[] outputContainers;
0239: try {
0240: outputContainers = getOutputContainers(javaProject);
0241: } catch (CoreException ex) {
0242: addToStatus(ex);
0243: continue;
0244: }
0245: for (int i = 0; i < outputContainers.length; i++)
0246: count += getTotalChildCount(outputContainers[i]);
0247:
0248: }
0249: }
0250:
0251: return count;
0252: }
0253:
0254: private int getTotalChildCount(IContainer container) {
0255: IResource[] members;
0256: try {
0257: members = container.members();
0258: } catch (CoreException ex) {
0259: return 0;
0260: }
0261: int count = 0;
0262: for (int i = 0; i < members.length; i++) {
0263: if (members[i].getType() == IResource.FILE)
0264: count++;
0265: else
0266: count += getTotalChildCount((IContainer) members[i]);
0267: }
0268: return count;
0269: }
0270:
0271: /**
0272: * Exports the passed resource to the JAR file
0273: *
0274: * @param element the resource or JavaElement to export
0275: * @param progressMonitor the progress monitor
0276: * @throws InterruptedException thrown on cancel
0277: */
0278: private void exportElement(Object element,
0279: IProgressMonitor progressMonitor)
0280: throws InterruptedException {
0281: int leadSegmentsToRemove = 1;
0282: IPackageFragmentRoot pkgRoot = null;
0283: boolean isInJavaProject = false;
0284: IResource resource = null;
0285: ITypeRoot typeRootElement = null;
0286: IJavaProject jProject = null;
0287: if (element instanceof IJavaElement) {
0288: isInJavaProject = true;
0289: IJavaElement je = (IJavaElement) element;
0290: if (!(je instanceof ITypeRoot)) {
0291: exportJavaElement(progressMonitor, je);
0292: return;
0293: }
0294: typeRootElement = (ITypeRoot) je;
0295: jProject = typeRootElement.getJavaProject();
0296: pkgRoot = JavaModelUtil.getPackageFragmentRoot(je);
0297: resource = typeRootElement.getResource();
0298: } else
0299: resource = (IResource) element;
0300:
0301: if (!resource.isAccessible()) {
0302: addWarning(
0303: Messages
0304: .format(
0305: JarPackagerMessages.JarFileExportOperation_resourceNotFound,
0306: resource.getFullPath()), null);
0307: return;
0308: }
0309:
0310: if (resource.getType() == IResource.FILE) {
0311: if (!isInJavaProject) {
0312: // check if it's a Java resource
0313: try {
0314: isInJavaProject = resource.getProject().hasNature(
0315: JavaCore.NATURE_ID);
0316: } catch (CoreException ex) {
0317: addWarning(
0318: Messages
0319: .format(
0320: JarPackagerMessages.JarFileExportOperation_projectNatureNotDeterminable,
0321: resource.getFullPath()), ex);
0322: return;
0323: }
0324: if (isInJavaProject) {
0325: jProject = JavaCore.create(resource.getProject());
0326: try {
0327: IPackageFragment pkgFragment = jProject
0328: .findPackageFragment(resource
0329: .getFullPath()
0330: .removeLastSegments(1));
0331: if (pkgFragment != null)
0332: pkgRoot = JavaModelUtil
0333: .getPackageFragmentRoot(pkgFragment);
0334: else
0335: pkgRoot = findPackageFragmentRoot(jProject,
0336: resource.getFullPath()
0337: .removeLastSegments(1));
0338: } catch (JavaModelException ex) {
0339: addWarning(
0340: Messages
0341: .format(
0342: JarPackagerMessages.JarFileExportOperation_javaPackageNotDeterminable,
0343: resource.getFullPath()),
0344: ex);
0345: return;
0346: }
0347: }
0348: }
0349:
0350: if (pkgRoot != null && jProject != null) {
0351: leadSegmentsToRemove = pkgRoot.getPath().segmentCount();
0352: boolean isOnBuildPath;
0353: isOnBuildPath = jProject.isOnClasspath(resource);
0354: if (!isOnBuildPath
0355: || (mustUseSourceFolderHierarchy() && !pkgRoot
0356: .getElementName()
0357: .equals(
0358: IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH)))
0359: leadSegmentsToRemove--;
0360: }
0361:
0362: IPath destinationPath = resource.getFullPath()
0363: .removeFirstSegments(leadSegmentsToRemove);
0364:
0365: if (typeRootElement != null) {
0366: exportClassFiles(progressMonitor, typeRootElement,
0367: destinationPath);
0368: }
0369:
0370: exportResource(progressMonitor, pkgRoot, isInJavaProject,
0371: resource, destinationPath);
0372:
0373: progressMonitor.worked(1);
0374: ModalContext.checkCanceled(progressMonitor);
0375:
0376: } else
0377: exportContainer(progressMonitor, (IContainer) resource);
0378: }
0379:
0380: private void exportJavaElement(IProgressMonitor progressMonitor,
0381: IJavaElement je) throws InterruptedException {
0382: if (je.getElementType() == IJavaElement.PACKAGE_FRAGMENT_ROOT
0383: && ((IPackageFragmentRoot) je).isArchive())
0384: return;
0385:
0386: Object[] children = fJavaElementContentProvider.getChildren(je);
0387: for (int i = 0; i < children.length; i++)
0388: exportElement(children[i], progressMonitor);
0389: }
0390:
0391: private void exportResource(IProgressMonitor progressMonitor,
0392: IResource resource, int leadingSegmentsToRemove)
0393: throws InterruptedException {
0394: if (resource instanceof IContainer) {
0395: IContainer container = (IContainer) resource;
0396: IResource[] children;
0397: try {
0398: children = container.members();
0399: } catch (CoreException e) {
0400: // this should never happen because an #isAccessible check is done before #members is invoked
0401: addWarning(
0402: Messages
0403: .format(
0404: JarPackagerMessages.JarFileExportOperation_errorDuringExport,
0405: container.getFullPath()), e);
0406: return;
0407: }
0408: for (int i = 0; i < children.length; i++)
0409: exportResource(progressMonitor, children[i],
0410: leadingSegmentsToRemove);
0411: } else if (resource instanceof IFile) {
0412: try {
0413: IPath destinationPath = resource.getFullPath()
0414: .removeFirstSegments(leadingSegmentsToRemove);
0415: progressMonitor
0416: .subTask(Messages
0417: .format(
0418: JarPackagerMessages.JarFileExportOperation_exporting,
0419: destinationPath.toString()));
0420: fJarWriter.write((IFile) resource, destinationPath);
0421: } catch (CoreException ex) {
0422: Throwable realEx = ex.getStatus().getException();
0423: if (realEx instanceof ZipException
0424: && realEx.getMessage() != null
0425: && realEx.getMessage().startsWith(
0426: "duplicate entry:")) //$NON-NLS-1$
0427: addWarning(ex.getMessage(), realEx);
0428: else
0429: addToStatus(ex);
0430: } finally {
0431: progressMonitor.worked(1);
0432: ModalContext.checkCanceled(progressMonitor);
0433: }
0434: }
0435: }
0436:
0437: private void exportContainer(IProgressMonitor progressMonitor,
0438: IContainer container) throws InterruptedException {
0439: if (container.getType() == IResource.FOLDER
0440: && isOutputFolder((IFolder) container))
0441: return;
0442:
0443: IResource[] children = null;
0444: try {
0445: children = container.members();
0446: } catch (CoreException exception) {
0447: // this should never happen because an #isAccessible check is done before #members is invoked
0448: addWarning(
0449: Messages
0450: .format(
0451: JarPackagerMessages.JarFileExportOperation_errorDuringExport,
0452: container.getFullPath()), exception);
0453: }
0454: if (children != null) {
0455: for (int i = 0; i < children.length; i++)
0456: exportElement(children[i], progressMonitor);
0457: }
0458: }
0459:
0460: private IPackageFragmentRoot findPackageFragmentRoot(
0461: IJavaProject jProject, IPath path)
0462: throws JavaModelException {
0463: if (jProject == null || path == null
0464: || path.segmentCount() <= 0)
0465: return null;
0466: IPackageFragmentRoot pkgRoot = jProject
0467: .findPackageFragmentRoot(path);
0468: if (pkgRoot != null)
0469: return pkgRoot;
0470: else
0471: return findPackageFragmentRoot(jProject, path
0472: .removeLastSegments(1));
0473: }
0474:
0475: private void exportResource(IProgressMonitor progressMonitor,
0476: IPackageFragmentRoot pkgRoot, boolean isInJavaProject,
0477: IResource resource, IPath destinationPath) {
0478:
0479: // Handle case where META-INF/MANIFEST.MF is part of the exported files
0480: if (fJarPackage.areClassFilesExported()
0481: && destinationPath.toString().equals(
0482: "META-INF/MANIFEST.MF")) {//$NON-NLS-1$
0483: if (fJarPackage.isManifestGenerated())
0484: addWarning(
0485: Messages
0486: .format(
0487: JarPackagerMessages.JarFileExportOperation_didNotAddManifestToJar,
0488: resource.getFullPath()), null);
0489: return;
0490: }
0491:
0492: boolean isNonJavaResource = !isInJavaProject || pkgRoot == null;
0493: boolean isInClassFolder = false;
0494: try {
0495: isInClassFolder = pkgRoot != null
0496: && !pkgRoot.isArchive()
0497: && pkgRoot.getKind() == IPackageFragmentRoot.K_BINARY;
0498: } catch (JavaModelException ex) {
0499: addWarning(
0500: Messages
0501: .format(
0502: JarPackagerMessages.JarFileExportOperation_cantGetRootKind,
0503: resource.getFullPath()), ex);
0504: }
0505: if ((fJarPackage.areClassFilesExported() && ((isNonJavaResource || (pkgRoot != null
0506: && !isJavaFile(resource) && !isClassFile(resource))) || isInClassFolder
0507: && isClassFile(resource)))
0508: || (fJarPackage.areJavaFilesExported() && (isNonJavaResource
0509: || (pkgRoot != null && !isClassFile(resource)) || (isInClassFolder
0510: && isClassFile(resource) && !fJarPackage
0511: .areClassFilesExported())))) {
0512: try {
0513: progressMonitor
0514: .subTask(Messages
0515: .format(
0516: JarPackagerMessages.JarFileExportOperation_exporting,
0517: destinationPath.toString()));
0518: fJarWriter.write((IFile) resource, destinationPath);
0519: } catch (CoreException ex) {
0520: Throwable realEx = ex.getStatus().getException();
0521: if (realEx instanceof ZipException
0522: && realEx.getMessage() != null
0523: && realEx.getMessage().startsWith(
0524: "duplicate entry:")) //$NON-NLS-1$
0525: addWarning(ex.getMessage(), realEx);
0526: else
0527: addToStatus(ex);
0528: }
0529: }
0530: }
0531:
0532: private boolean isOutputFolder(IFolder folder) {
0533: try {
0534: IJavaProject javaProject = JavaCore.create(folder
0535: .getProject());
0536: IPath outputFolderPath = javaProject.getOutputLocation();
0537: return folder.getFullPath().equals(outputFolderPath);
0538: } catch (JavaModelException ex) {
0539: return false;
0540: }
0541: }
0542:
0543: private void exportClassFiles(IProgressMonitor progressMonitor,
0544: ITypeRoot typeRootElement, IPath destinationPath) {
0545: if (fJarPackage.areClassFilesExported()) {
0546: try {
0547: if (!typeRootElement.exists())
0548: return;
0549:
0550: // find corresponding file(s) on classpath and export
0551: Iterator iter = filesOnClasspath(typeRootElement,
0552: destinationPath, progressMonitor);
0553: IPath baseDestinationPath = destinationPath
0554: .removeLastSegments(1);
0555: while (iter.hasNext()) {
0556: IFile file = (IFile) iter.next();
0557: IPath classFilePath = baseDestinationPath
0558: .append(file.getName());
0559: progressMonitor
0560: .subTask(Messages
0561: .format(
0562: JarPackagerMessages.JarFileExportOperation_exporting,
0563: classFilePath.toString()));
0564: fJarWriter.write(file, classFilePath);
0565: }
0566: } catch (CoreException ex) {
0567: addToStatus(ex);
0568: }
0569: }
0570: }
0571:
0572: /**
0573: * Exports the resources as specified by the JAR package.
0574: * @param progressMonitor the progress monitor
0575: * @throws InterruptedException thrown when cancelled
0576: */
0577: private void exportSelectedElements(IProgressMonitor progressMonitor)
0578: throws InterruptedException {
0579: fExportedClassContainers = new HashSet(10);
0580: Set enclosingJavaProjects = new HashSet(10);
0581: int n = fJarPackage.getElements().length;
0582: for (int i = 0; i < n; i++) {
0583: Object element = fJarPackage.getElements()[i];
0584: exportElement(element, progressMonitor);
0585: if (fJarPackage.areOutputFoldersExported()) {
0586: IJavaProject javaProject = getEnclosingJavaProject(element);
0587: if (javaProject != null)
0588: enclosingJavaProjects.add(javaProject);
0589: }
0590: }
0591: if (fJarPackage.areOutputFoldersExported())
0592: exportOutputFolders(progressMonitor, enclosingJavaProjects);
0593: }
0594:
0595: private IJavaProject getEnclosingJavaProject(Object element) {
0596: if (element instanceof IJavaElement) {
0597: return ((IJavaElement) element).getJavaProject();
0598: } else if (element instanceof IResource) {
0599: IProject project = ((IResource) element).getProject();
0600: try {
0601: if (project.hasNature(JavaCore.NATURE_ID))
0602: return JavaCore.create(project);
0603: } catch (CoreException ex) {
0604: addWarning(
0605: Messages
0606: .format(
0607: JarPackagerMessages.JarFileExportOperation_projectNatureNotDeterminable,
0608: project.getFullPath()), ex);
0609: }
0610: }
0611: return null;
0612: }
0613:
0614: private void exportOutputFolders(IProgressMonitor progressMonitor,
0615: Set javaProjects) throws InterruptedException {
0616: if (javaProjects == null)
0617: return;
0618:
0619: Iterator iter = javaProjects.iterator();
0620: while (iter.hasNext()) {
0621: IJavaProject javaProject = (IJavaProject) iter.next();
0622: IContainer[] outputContainers;
0623: try {
0624: outputContainers = getOutputContainers(javaProject);
0625: } catch (CoreException ex) {
0626: addToStatus(ex);
0627: continue;
0628: }
0629: for (int i = 0; i < outputContainers.length; i++)
0630: exportResource(progressMonitor, outputContainers[i],
0631: outputContainers[i].getFullPath()
0632: .segmentCount());
0633:
0634: }
0635: }
0636:
0637: private IContainer[] getOutputContainers(IJavaProject javaProject)
0638: throws CoreException {
0639: Set outputPaths = new HashSet();
0640: boolean includeDefaultOutputPath = false;
0641: IPackageFragmentRoot[] roots = javaProject
0642: .getPackageFragmentRoots();
0643: for (int i = 0; i < roots.length; i++) {
0644: if (roots[i] != null) {
0645: IClasspathEntry cpEntry = roots[i]
0646: .getRawClasspathEntry();
0647: if (cpEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
0648: IPath location = cpEntry.getOutputLocation();
0649: if (location != null)
0650: outputPaths.add(location);
0651: else
0652: includeDefaultOutputPath = true;
0653: }
0654: }
0655: }
0656:
0657: if (includeDefaultOutputPath) {
0658: // Use default output location
0659: outputPaths.add(javaProject.getOutputLocation());
0660: }
0661:
0662: // Convert paths to containers
0663: Set outputContainers = new HashSet(outputPaths.size());
0664: Iterator iter = outputPaths.iterator();
0665: while (iter.hasNext()) {
0666: IPath path = (IPath) iter.next();
0667: if (javaProject.getProject().getFullPath().equals(path))
0668: outputContainers.add(javaProject.getProject());
0669: else {
0670: IFolder outputFolder = createFolderHandle(path);
0671: if (outputFolder == null
0672: || !outputFolder.isAccessible()) {
0673: String msg = JarPackagerMessages.JarFileExportOperation_outputContainerNotAccessible;
0674: addToStatus(new CoreException(new Status(
0675: IStatus.ERROR, JavaPlugin.getPluginId(),
0676: IJavaStatusConstants.INTERNAL_ERROR, msg,
0677: null)));
0678: } else
0679: outputContainers.add(outputFolder);
0680: }
0681: }
0682: return (IContainer[]) outputContainers
0683: .toArray(new IContainer[outputContainers.size()]);
0684: }
0685:
0686: /**
0687: * Returns an iterator on a list with files that correspond to the
0688: * passed file and that are on the classpath of its project.
0689: *
0690: * @param typeRootElement the class file or compilation unit to evaluate the class files for
0691: * @param pathInJar the path that the file has in the JAR (i.e. project and source folder segments removed)
0692: * @param progressMonitor the progressMonitor to use
0693: * @return the iterator over the corresponding classpath files for the given file
0694: * @throws CoreException
0695: */
0696: private Iterator filesOnClasspath(ITypeRoot typeRootElement,
0697: IPath pathInJar, IProgressMonitor progressMonitor)
0698: throws CoreException {
0699: IFile file = (IFile) typeRootElement.getResource();
0700: IJavaProject javaProject = typeRootElement.getJavaProject();
0701: IPackageFragmentRoot pkgRoot = JavaModelUtil
0702: .getPackageFragmentRoot(typeRootElement);
0703:
0704: // Allow JAR Package to provide its own strategy
0705: IFile[] classFiles = fJarPackage.findClassfilesFor(file);
0706: if (classFiles != null)
0707: return Arrays.asList(classFiles).iterator();
0708:
0709: if (!isJavaFile(file))
0710: return Collections.EMPTY_LIST.iterator();
0711:
0712: IPath outputPath = null;
0713: if (pkgRoot != null) {
0714: IClasspathEntry cpEntry = pkgRoot.getRawClasspathEntry();
0715: if (cpEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE)
0716: outputPath = cpEntry.getOutputLocation();
0717: }
0718: if (outputPath == null)
0719: // Use default output location
0720: outputPath = javaProject.getOutputLocation();
0721:
0722: IContainer outputContainer;
0723: if (javaProject.getProject().getFullPath().equals(outputPath))
0724: outputContainer = javaProject.getProject();
0725: else {
0726: outputContainer = createFolderHandle(outputPath);
0727: if (outputContainer == null
0728: || !outputContainer.isAccessible()) {
0729: String msg = JarPackagerMessages.JarFileExportOperation_outputContainerNotAccessible;
0730: throw new CoreException(new Status(IStatus.ERROR,
0731: JavaPlugin.getPluginId(),
0732: IJavaStatusConstants.INTERNAL_ERROR, msg, null));
0733: }
0734: }
0735:
0736: // Java CU - search files with .class ending
0737: boolean hasErrors = hasCompileErrors(file);
0738: boolean hasWarnings = hasCompileWarnings(file);
0739: boolean canBeExported = canBeExported(hasErrors, hasWarnings);
0740: if (!canBeExported)
0741: return Collections.EMPTY_LIST.iterator();
0742: reportPossibleCompileProblems(file, hasErrors, hasWarnings,
0743: canBeExported);
0744: IContainer classContainer = outputContainer;
0745: if (pathInJar.segmentCount() > 1)
0746: classContainer = outputContainer.getFolder(pathInJar
0747: .removeLastSegments(1));
0748:
0749: if (fExportedClassContainers.contains(classContainer))
0750: return Collections.EMPTY_LIST.iterator();
0751:
0752: if (JavaCore.DO_NOT_GENERATE.equals(javaProject.getOption(
0753: JavaCore.COMPILER_SOURCE_FILE_ATTR, true))) {
0754: IRegion region = JavaCore.newRegion();
0755: region.add(typeRootElement);
0756: IResource[] generatedResources = JavaCore
0757: .getGeneratedResources(region, false);
0758: if (generatedResources.length > 0)
0759: return Arrays.asList(generatedResources).iterator();
0760: // give the old code a last chance
0761: }
0762: if (fClassFilesMapContainer == null
0763: || !fClassFilesMapContainer.equals(classContainer)) {
0764: fJavaNameToClassFilesMap = buildJavaToClassMap(
0765: classContainer, progressMonitor);
0766: if (fJavaNameToClassFilesMap == null) {
0767: // Could not fully build map. fallback is to export whole directory
0768: String containerName = classContainer.getFullPath()
0769: .toString();
0770: String msg = Messages
0771: .format(
0772: JarPackagerMessages.JarFileExportOperation_missingSourceFileAttributeExportedAll,
0773: containerName);
0774: addInfo(msg, null);
0775: fExportedClassContainers.add(classContainer);
0776: return getClassesIn(classContainer);
0777: }
0778: fClassFilesMapContainer = classContainer;
0779: }
0780: ArrayList classFileList = (ArrayList) fJavaNameToClassFilesMap
0781: .get(file.getName());
0782: if (classFileList == null || classFileList.isEmpty()) {
0783: String msg = Messages
0784: .format(
0785: JarPackagerMessages.JarFileExportOperation_classFileOnClasspathNotAccessible,
0786: file.getFullPath());
0787: throw new CoreException(new Status(IStatus.ERROR,
0788: JavaPlugin.getPluginId(),
0789: IJavaStatusConstants.INTERNAL_ERROR, msg, null));
0790: }
0791: return classFileList.iterator();
0792: }
0793:
0794: private Iterator getClassesIn(IContainer classContainer)
0795: throws CoreException {
0796: IResource[] resources = classContainer.members();
0797: List files = new ArrayList(resources.length);
0798: for (int i = 0; i < resources.length; i++)
0799: if (resources[i].getType() == IResource.FILE
0800: && isClassFile(resources[i]))
0801: files.add(resources[i]);
0802: return files.iterator();
0803: }
0804:
0805: /**
0806: * Answers whether the given resource is a Java file.
0807: * The resource must be a file whose file name ends with ".java",
0808: * or an extension defined as Java source.
0809: *
0810: * @param file the file to test
0811: * @return a <code>true<code> if the given resource is a Java file
0812: */
0813: private boolean isJavaFile(IResource file) {
0814: return file != null && file.getType() == IResource.FILE
0815: && file.getFileExtension() != null
0816: && JavaCore.isJavaLikeFileName(file.getName());
0817: }
0818:
0819: /**
0820: * Answers whether the given resource is a class file.
0821: * The resource must be a file whose file name ends with ".class".
0822: *
0823: * @param file the file to test
0824: * @return a <code>true<code> if the given resource is a class file
0825: */
0826: private boolean isClassFile(IResource file) {
0827: return file != null && file.getType() == IResource.FILE
0828: && file.getFileExtension() != null
0829: && file.getFileExtension().equalsIgnoreCase("class"); //$NON-NLS-1$
0830: }
0831:
0832: /*
0833: * Builds and returns a map that has the class files
0834: * for each java file in a given directory
0835: */
0836: private Map buildJavaToClassMap(IContainer container,
0837: IProgressMonitor monitor) throws CoreException {
0838: if (container == null || !container.isAccessible())
0839: return new HashMap(0);
0840: /*
0841: * XXX: Bug 6584: Need a way to get class files for a java file (or CU)
0842: */
0843: IClassFileReader cfReader = null;
0844: IResource[] members = container.members();
0845: Map map = new HashMap(members.length);
0846: for (int i = 0; i < members.length; i++) {
0847: if (isClassFile(members[i])) {
0848: IFile classFile = (IFile) members[i];
0849: URI location = classFile.getLocationURI();
0850: if (location != null) {
0851: InputStream contents = null;
0852: try {
0853: contents = EFS.getStore(location)
0854: .openInputStream(EFS.NONE, monitor);
0855: cfReader = ToolFactory
0856: .createDefaultClassFileReader(
0857: contents,
0858: IClassFileReader.CLASSFILE_ATTRIBUTES);
0859: } finally {
0860: try {
0861: if (contents != null)
0862: contents.close();
0863: } catch (IOException e) {
0864: throw new CoreException(
0865: new Status(
0866: IStatus.ERROR,
0867: JavaPlugin.getPluginId(),
0868: IStatus.ERROR,
0869: Messages
0870: .format(
0871: JarPackagerMessages.JarFileExportOperation_errorCannotCloseConnection,
0872: Resources
0873: .getLocationString(classFile)),
0874: e));
0875: }
0876: }
0877: if (cfReader != null) {
0878: ISourceAttribute sourceAttribute = cfReader
0879: .getSourceFileAttribute();
0880: if (sourceAttribute == null) {
0881: /*
0882: * Can't fully build the map because one or more
0883: * class file does not contain the name of its
0884: * source file.
0885: */
0886: addWarning(
0887: Messages
0888: .format(
0889: JarPackagerMessages.JarFileExportOperation_classFileWithoutSourceFileAttribute,
0890: Resources
0891: .getLocationString(classFile)),
0892: null);
0893: return null;
0894: }
0895: String javaName = new String(sourceAttribute
0896: .getSourceFileName());
0897: Object classFiles = map.get(javaName);
0898: if (classFiles == null) {
0899: classFiles = new ArrayList(3);
0900: map.put(javaName, classFiles);
0901: }
0902: ((ArrayList) classFiles).add(classFile);
0903: }
0904: }
0905: }
0906: }
0907: return map;
0908: }
0909:
0910: /**
0911: * Creates a folder resource handle for the folder with the given workspace path.
0912: *
0913: * @param folderPath the path of the folder to create a handle for
0914: * @return the new folder resource handle
0915: */
0916: private IFolder createFolderHandle(IPath folderPath) {
0917: if (folderPath.isValidPath(folderPath.toString())
0918: && folderPath.segmentCount() >= 2)
0919: return JavaPlugin.getWorkspace().getRoot().getFolder(
0920: folderPath);
0921: else
0922: return null;
0923: }
0924:
0925: /**
0926: * Returns the status of this operation.
0927: * The result is a status object containing individual
0928: * status objects.
0929: *
0930: * @return the status of this operation
0931: */
0932: public IStatus getStatus() {
0933: String message = null;
0934: switch (fStatus.getSeverity()) {
0935: case IStatus.OK:
0936: message = ""; //$NON-NLS-1$
0937: break;
0938: case IStatus.INFO:
0939: message = JarPackagerMessages.JarFileExportOperation_exportFinishedWithInfo;
0940: break;
0941: case IStatus.WARNING:
0942: message = JarPackagerMessages.JarFileExportOperation_exportFinishedWithWarnings;
0943: break;
0944: case IStatus.ERROR:
0945: if (fJarPackages.length > 1)
0946: message = JarPackagerMessages.JarFileExportOperation_creationOfSomeJARsFailed;
0947: else
0948: message = JarPackagerMessages.JarFileExportOperation_jarCreationFailed;
0949: break;
0950: default:
0951: // defensive code in case new severity is defined
0952: message = ""; //$NON-NLS-1$
0953: break;
0954: }
0955: fStatus.setMessage(message);
0956: return fStatus;
0957: }
0958:
0959: private boolean canBeExported(boolean hasErrors, boolean hasWarnings)
0960: throws CoreException {
0961: return (!hasErrors && !hasWarnings)
0962: || (hasErrors && fJarPackage.areErrorsExported())
0963: || (hasWarnings && fJarPackage.exportWarnings());
0964: }
0965:
0966: private void reportPossibleCompileProblems(IFile file,
0967: boolean hasErrors, boolean hasWarnings,
0968: boolean canBeExported) {
0969: if (hasErrors) {
0970: if (canBeExported)
0971: addWarning(
0972: Messages
0973: .format(
0974: JarPackagerMessages.JarFileExportOperation_exportedWithCompileErrors,
0975: file.getFullPath()), null);
0976: else
0977: addWarning(
0978: Messages
0979: .format(
0980: JarPackagerMessages.JarFileExportOperation_notExportedDueToCompileErrors,
0981: file.getFullPath()), null);
0982: }
0983: if (hasWarnings) {
0984: if (canBeExported)
0985: addWarning(
0986: Messages
0987: .format(
0988: JarPackagerMessages.JarFileExportOperation_exportedWithCompileWarnings,
0989: file.getFullPath()), null);
0990: else
0991: addWarning(
0992: Messages
0993: .format(
0994: JarPackagerMessages.JarFileExportOperation_notExportedDueToCompileWarnings,
0995: file.getFullPath()), null);
0996: }
0997: }
0998:
0999: /**
1000: * Exports the resources as specified by the JAR package.
1001: *
1002: * @param progressMonitor the progress monitor that displays the progress
1003: * @throws InvocationTargetException thrown when an ecxeption occurred
1004: * @throws InterruptedException thrown when cancelled
1005: * @see #getStatus()
1006: */
1007: protected void execute(IProgressMonitor progressMonitor)
1008: throws InvocationTargetException, InterruptedException {
1009: int count = fJarPackages.length;
1010: progressMonitor.beginTask("", count); //$NON-NLS-1$
1011: try {
1012: for (int i = 0; i < count; i++) {
1013: SubProgressMonitor subProgressMonitor = new SubProgressMonitor(
1014: progressMonitor,
1015: 1,
1016: SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
1017: fJarPackage = fJarPackages[i];
1018: if (fJarPackage != null)
1019: singleRun(subProgressMonitor);
1020: }
1021: } finally {
1022: progressMonitor.done();
1023: }
1024: }
1025:
1026: private void singleRun(IProgressMonitor progressMonitor)
1027: throws InvocationTargetException, InterruptedException {
1028: try {
1029: if (!preconditionsOK())
1030: throw new InvocationTargetException(
1031: null,
1032: JarPackagerMessages.JarFileExportOperation_jarCreationFailedSeeDetails);
1033: int totalWork = countSelectedElements();
1034: if (fJarPackage.areGeneratedFilesExported()
1035: && ((!isAutoBuilding() && fJarPackage
1036: .isBuildingIfNeeded()) || (isAutoBuilding() && fFilesSaved))) {
1037: int subMonitorTicks = totalWork / 10;
1038: totalWork += subMonitorTicks;
1039: progressMonitor.beginTask("", totalWork); //$NON-NLS-1$
1040: SubProgressMonitor subProgressMonitor = new SubProgressMonitor(
1041: progressMonitor,
1042: subMonitorTicks,
1043: SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
1044: buildProjects(subProgressMonitor);
1045: } else
1046: progressMonitor.beginTask("", totalWork); //$NON-NLS-1$
1047:
1048: fJarWriter = fJarPackage.createJarWriter3(fParentShell);
1049: exportSelectedElements(progressMonitor);
1050: if (getStatus().getSeverity() != IStatus.ERROR) {
1051: progressMonitor
1052: .subTask(JarPackagerMessages.JarFileExportOperation_savingFiles);
1053: saveFiles();
1054: }
1055: } catch (CoreException ex) {
1056: addToStatus(ex);
1057: } finally {
1058: try {
1059: if (fJarWriter != null)
1060: fJarWriter.close();
1061: } catch (CoreException ex) {
1062: addToStatus(ex);
1063: }
1064: progressMonitor.done();
1065: }
1066: }
1067:
1068: private boolean preconditionsOK() {
1069: if (!fJarPackage.areGeneratedFilesExported()
1070: && !fJarPackage.areJavaFilesExported()) {
1071: addError(
1072: JarPackagerMessages.JarFileExportOperation_noExportTypeChosen,
1073: null);
1074: return false;
1075: }
1076: if (fJarPackage.getElements() == null
1077: || fJarPackage.getElements().length == 0) {
1078: addError(
1079: JarPackagerMessages.JarFileExportOperation_noResourcesSelected,
1080: null);
1081: return false;
1082: }
1083: if (fJarPackage.getAbsoluteJarLocation() == null) {
1084: addError(
1085: JarPackagerMessages.JarFileExportOperation_invalidJarLocation,
1086: null);
1087: return false;
1088: }
1089: File targetFile = fJarPackage.getAbsoluteJarLocation().toFile();
1090: if (targetFile.exists() && !targetFile.canWrite()) {
1091: addError(
1092: JarPackagerMessages.JarFileExportOperation_jarFileExistsAndNotWritable,
1093: null);
1094: return false;
1095: }
1096: if (!fJarPackage.isManifestAccessible()) {
1097: addError(
1098: JarPackagerMessages.JarFileExportOperation_manifestDoesNotExist,
1099: null);
1100: return false;
1101: }
1102: if (!fJarPackage
1103: .isMainClassValid(new BusyIndicatorRunnableContext())) {
1104: addError(
1105: JarPackagerMessages.JarFileExportOperation_invalidMainClass,
1106: null);
1107: return false;
1108: }
1109:
1110: if (fParentShell != null) {
1111: final boolean[] res = { false };
1112: fParentShell.getDisplay().syncExec(new Runnable() {
1113: public void run() {
1114: RefactoringSaveHelper refactoringSaveHelper = new RefactoringSaveHelper(
1115: RefactoringSaveHelper.SAVE_ALL_ALWAYS_ASK);
1116: res[0] = refactoringSaveHelper
1117: .saveEditors(fParentShell);
1118: fFilesSaved = refactoringSaveHelper.hasFilesSaved();
1119: }
1120: });
1121: if (!res[0]) {
1122: addError(
1123: JarPackagerMessages.JarFileExportOperation_fileUnsaved,
1124: null);
1125: return false;
1126: }
1127: }
1128:
1129: return true;
1130: }
1131:
1132: private void saveFiles() {
1133: // Save the manifest
1134: if (fJarPackage.areGeneratedFilesExported()
1135: && fJarPackage.isManifestGenerated()
1136: && fJarPackage.isManifestSaved()) {
1137: try {
1138: saveManifest();
1139: } catch (CoreException ex) {
1140: addError(
1141: JarPackagerMessages.JarFileExportOperation_errorSavingManifest,
1142: ex);
1143: } catch (IOException ex) {
1144: addError(
1145: JarPackagerMessages.JarFileExportOperation_errorSavingManifest,
1146: ex);
1147: }
1148: }
1149:
1150: // Save the description
1151: if (fJarPackage.isDescriptionSaved()) {
1152: try {
1153: saveDescription();
1154: } catch (CoreException ex) {
1155: addError(
1156: JarPackagerMessages.JarFileExportOperation_errorSavingDescription,
1157: ex);
1158: } catch (IOException ex) {
1159: addError(
1160: JarPackagerMessages.JarFileExportOperation_errorSavingDescription,
1161: ex);
1162: }
1163: }
1164: }
1165:
1166: private void saveDescription() throws CoreException, IOException {
1167: // Adjust JAR package attributes
1168: if (fJarPackage.isManifestReused())
1169: fJarPackage.setGenerateManifest(false);
1170: ByteArrayOutputStream objectStreamOutput = new ByteArrayOutputStream();
1171: IFile descriptionFile = fJarPackage.getDescriptionFile();
1172: String encoding = "UTF-8"; //$NON-NLS-1$
1173: try {
1174: encoding = descriptionFile.getCharset(true);
1175: } catch (CoreException exception) {
1176: JavaPlugin.log(exception);
1177: }
1178: IJarDescriptionWriter writer = fJarPackage
1179: .createJarDescriptionWriter(objectStreamOutput,
1180: encoding);
1181: ByteArrayInputStream fileInput = null;
1182: try {
1183: writer.write(fJarPackage);
1184: fileInput = new ByteArrayInputStream(objectStreamOutput
1185: .toByteArray());
1186: if (descriptionFile.isAccessible()) {
1187: if (fJarPackage.allowOverwrite()
1188: || JarPackagerUtil.askForOverwritePermission(
1189: fParentShell, descriptionFile
1190: .getFullPath().toString()))
1191: descriptionFile.setContents(fileInput, true, true,
1192: null);
1193: } else
1194: descriptionFile.create(fileInput, true, null);
1195: } finally {
1196: if (fileInput != null)
1197: fileInput.close();
1198: if (writer != null)
1199: writer.close();
1200: }
1201: }
1202:
1203: private void saveManifest() throws CoreException, IOException {
1204: ByteArrayOutputStream manifestOutput = new ByteArrayOutputStream();
1205: Manifest manifest = fJarPackage.getManifestProvider().create(
1206: fJarPackage);
1207: manifest.write(manifestOutput);
1208: ByteArrayInputStream fileInput = new ByteArrayInputStream(
1209: manifestOutput.toByteArray());
1210: IFile manifestFile = fJarPackage.getManifestFile();
1211: if (manifestFile.isAccessible()) {
1212: if (fJarPackage.allowOverwrite()
1213: || JarPackagerUtil.askForOverwritePermission(
1214: fParentShell, manifestFile.getFullPath()
1215: .toString()))
1216: manifestFile.setContents(fileInput, true, true, null);
1217: } else
1218: manifestFile.create(fileInput, true, null);
1219: }
1220:
1221: private boolean isAutoBuilding() {
1222: return ResourcesPlugin.getWorkspace().getDescription()
1223: .isAutoBuilding();
1224: }
1225:
1226: private void buildProjects(IProgressMonitor progressMonitor) {
1227: Set builtProjects = new HashSet(10);
1228: Object[] elements = fJarPackage.getElements();
1229: for (int i = 0; i < elements.length; i++) {
1230: IProject project = null;
1231: Object element = elements[i];
1232: if (element instanceof IResource)
1233: project = ((IResource) element).getProject();
1234: else if (element instanceof IJavaElement)
1235: project = ((IJavaElement) element).getJavaProject()
1236: .getProject();
1237: if (project != null && !builtProjects.contains(project)) {
1238: try {
1239: project
1240: .build(
1241: IncrementalProjectBuilder.INCREMENTAL_BUILD,
1242: progressMonitor);
1243: } catch (CoreException ex) {
1244: String message = Messages
1245: .format(
1246: JarPackagerMessages.JarFileExportOperation_errorDuringProjectBuild,
1247: project.getFullPath());
1248: addError(message, ex);
1249: } finally {
1250: // don't try to build same project a second time even if it failed
1251: builtProjects.add(project);
1252: }
1253: }
1254: }
1255: }
1256:
1257: /**
1258: * Tells whether the given resource (or its children) have compile errors.
1259: * The method acts on the current build state and does not recompile.
1260: *
1261: * @param resource the resource to check for errors
1262: * @return <code>true</code> if the resource (and its children) are error free
1263: * @throws CoreException import org.eclipse.core.runtime.CoreException if there's a marker problem
1264: */
1265: private boolean hasCompileErrors(IResource resource)
1266: throws CoreException {
1267: IMarker[] problemMarkers = resource.findMarkers(
1268: IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, true,
1269: IResource.DEPTH_INFINITE);
1270: for (int i = 0; i < problemMarkers.length; i++) {
1271: if (problemMarkers[i].getAttribute(IMarker.SEVERITY, -1) == IMarker.SEVERITY_ERROR)
1272: return true;
1273: }
1274: return false;
1275: }
1276:
1277: /**
1278: * Tells whether the given resource (or its children) have compile errors.
1279: * The method acts on the current build state and does not recompile.
1280: *
1281: * @param resource the resource to check for errors
1282: * @return <code>true</code> if the resource (and its children) are error free
1283: * @throws CoreException import org.eclipse.core.runtime.CoreException if there's a marker problem
1284: */
1285: private boolean hasCompileWarnings(IResource resource)
1286: throws CoreException {
1287: IMarker[] problemMarkers = resource.findMarkers(
1288: IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, true,
1289: IResource.DEPTH_INFINITE);
1290: for (int i = 0; i < problemMarkers.length; i++) {
1291: if (problemMarkers[i].getAttribute(IMarker.SEVERITY, -1) == IMarker.SEVERITY_WARNING)
1292: return true;
1293: }
1294: return false;
1295: }
1296:
1297: private boolean mustUseSourceFolderHierarchy() {
1298: return fJarPackage.useSourceFolderHierarchy()
1299: && fJarPackage.areJavaFilesExported()
1300: && !fJarPackage.areGeneratedFilesExported();
1301: }
1302: }
|