ext.org.eclipse.jdt.internal.ui.jarpackager.JarFileExportOperation.java Source code

Java tutorial

Introduction

Here is the source code for ext.org.eclipse.jdt.internal.ui.jarpackager.JarFileExportOperation.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2011 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * 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 ext.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.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 patch.org.eclipse.jdt.internal.ui.JavaPlugin;

import ext.org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import ext.org.eclipse.jdt.internal.corext.util.Messages;
import ext.org.eclipse.jdt.internal.corext.util.Resources;
import ext.org.eclipse.jdt.internal.ui.IJavaStatusConstants;
import ext.org.eclipse.jdt.internal.ui.util.BusyIndicatorRunnableContext;
import ext.org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;

/**
 * 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<IJavaProject>(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 (int i = 0; i < outputContainers.length; i++)
                    count += getTotalChildCount(outputContainers[i]);

            }
        }

        return count;
    }

    private int getClassFileCount(IJavaElement[] children) throws JavaModelException {
        int result = 0;
        for (int i = 0; i < children.length; i++) {
            if (children[i] instanceof IClassFile) {
                result++;
            } else if (children[i] instanceof IPackageFragment) {
                IPackageFragment fragment = (IPackageFragment) children[i];
                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 (int i = 0; i < members.length; i++) {
            if (members[i].getType() == IResource.FILE)
                count++;
            else
                count += getTotalChildCount((IContainer) members[i]);
        }
        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;
        }

        Object[] children = fJavaElementContentProvider.getChildren(je);
        for (int i = 0; i < children.length; i++)
            exportElement(children[i], progressMonitor);
    }

    private void exportExternalClassFolder(IPackageFragmentRoot classFolder, IProgressMonitor progressMonitor)
            throws InterruptedException {
        try {
            IJavaElement[] children = classFolder.getChildren();
            for (int i = 0; i < children.length; i++) {
                exportExternalClassFolderElement(children[i], 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) {
            IJavaElement[] children = ((IPackageFragment) javaElement).getChildren();
            for (int i = 0; i < children.length; i++) {
                exportExternalClassFolderElement(children[i], 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 (int i = 0; i < children.length; i++)
                exportResource(progressMonitor, children[i], 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 (int i = 0; i < children.length; i++) {
                IResource child = children[i];
                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<IContainer>(10);
        Set<IJavaProject> enclosingJavaProjects = new HashSet<IJavaProject>(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 (int i = 0; i < outputContainers.length; i++)
                exportResource(progressMonitor, outputContainers[i],
                        outputContainers[i].getFullPath().segmentCount());

        }
    }

    private IContainer[] getOutputContainers(IJavaProject javaProject) throws CoreException {
        Set<IPath> outputPaths = new HashSet<IPath>();
        boolean includeDefaultOutputPath = false;
        IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots();
        for (int i = 0; i < roots.length; i++) {
            if (roots[i] != null) {
                IClasspathEntry cpEntry = roots[i].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<IContainer>(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);
        if (!canBeExported)
            return Collections.EMPTY_LIST.iterator();
        reportPossibleCompileProblems(file, hasErrors, hasWarnings, canBeExported);
        IContainer classContainer = outputContainer;
        if (pathInJar.segmentCount() > 1)
            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<IResource>(resources.length);
        for (int i = 0; i < resources.length; i++)
            if (resources[i].getType() == IResource.FILE && isClassFile(resources[i]))
                files.add(resources[i]);
        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<String, ArrayList<IResource>>(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<String, ArrayList<IResource>>(members.length);
        for (int i = 0; i < members.length; i++) {
            if (isClassFile(members[i])) {
                IFile classFile = (IFile) members[i];
                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<IResource>(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
     */
    public IStatus getStatus() {
        String message = null;
        switch (fStatus.getSeverity()) {
        case IStatus.OK:
            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;
        default:
            // defensive code in case new severity is defined
            message = ""; //$NON-NLS-1$
            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
                addWarning(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
                addWarning(
                        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(new Runnable() {
                public void run() {
                    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 ex) {
                addError(JarPackagerMessages.JarFileExportOperation_errorSavingManifest, ex);
            } catch (IOException ex) {
                addError(JarPackagerMessages.JarFileExportOperation_errorSavingManifest, ex);
            }
        }

        // Save the description
        if (fJarPackage.isDescriptionSaved()) {
            try {
                saveDescription();
            } catch (CoreException ex) {
                addError(JarPackagerMessages.JarFileExportOperation_errorSavingDescription, ex);
            } catch (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<IProject>(10);
        Object[] elements = fJarPackage.getElements();
        for (int i = 0; i < elements.length; i++) {
            IProject project = null;
            Object element = elements[i];
            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 {
        IMarker[] problemMarkers = resource.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, true,
                IResource.DEPTH_INFINITE);
        for (int i = 0; i < problemMarkers.length; i++) {
            if (problemMarkers[i].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 {
        IMarker[] problemMarkers = resource.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, true,
                IResource.DEPTH_INFINITE);
        for (int i = 0; i < problemMarkers.length; i++) {
            if (problemMarkers[i].getAttribute(IMarker.SEVERITY, -1) == IMarker.SEVERITY_WARNING)
                return true;
        }
        return false;
    }

    private boolean mustUseSourceFolderHierarchy() {
        return fJarPackage.useSourceFolderHierarchy() && fJarPackage.areJavaFilesExported()
                && !fJarPackage.areGeneratedFilesExported();
    }
}