org.eclipse.pde.internal.ui.wizards.plugin.NewLibraryPluginCreationOperation.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.pde.internal.ui.wizards.plugin.NewLibraryPluginCreationOperation.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2013 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
 *     Code 9 Corporation - ongoing enhancements
 *     Bartosz Michalik <bartosz.michalik@gmail.com> - bug 109440
 *     Benjamin Cabe <benjamin.cabe@anyware-tech.com> - bug 248852, bug 247553
 *******************************************************************************/
package org.eclipse.pde.internal.ui.wizards.plugin;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.zip.ZipFile;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.core.*;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.osgi.util.ManifestElement;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.core.build.*;
import org.eclipse.pde.core.plugin.*;
import org.eclipse.pde.internal.core.ICoreConstants;
import org.eclipse.pde.internal.core.build.Build;
import org.eclipse.pde.internal.core.build.WorkspaceBuildModel;
import org.eclipse.pde.internal.core.bundle.BundlePluginBase;
import org.eclipse.pde.internal.core.ibundle.IBundle;
import org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase;
import org.eclipse.pde.internal.core.natures.PDE;
import org.eclipse.pde.internal.core.plugin.WorkspacePluginModelBase;
import org.eclipse.pde.internal.core.project.PDEProject;
import org.eclipse.pde.internal.ui.*;
import org.eclipse.pde.internal.ui.search.dependencies.AddNewBinaryDependenciesOperation;
import org.eclipse.pde.internal.ui.wizards.IProjectProvider;
import org.eclipse.pde.ui.IFieldData;
import org.eclipse.pde.ui.IPluginContentWizard;
import org.eclipse.ui.dialogs.IOverwriteQuery;
import org.eclipse.ui.wizards.datatransfer.ImportOperation;
import org.eclipse.ui.wizards.datatransfer.ZipFileStructureProvider;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;

public class NewLibraryPluginCreationOperation extends NewProjectCreationOperation {

    private static final String SOURCE_PREFIX = "source."; //$NON-NLS-1$

    private LibraryPluginFieldData fData;

    public NewLibraryPluginCreationOperation(LibraryPluginFieldData data, IProjectProvider provider,
            IPluginContentWizard contentWizard) {
        super(data, provider, contentWizard);
        fData = data;
    }

    private void addJar(File jarFile, IProject project, IProgressMonitor monitor) throws CoreException {
        String jarName = jarFile.getName();
        IFile file = project.getFile(jarName);
        monitor.subTask(NLS.bind(PDEUIMessages.NewProjectCreationOperation_copyingJar, jarName));
        InputStream in = null;
        try {
            in = new FileInputStream(jarFile);
            file.create(in, true, monitor);
        } catch (FileNotFoundException fnfe) {
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException ioe) {
                }
            }
        }
    }

    private void adjustExportRoot(IProject project, IBundle bundle) throws CoreException {
        IResource[] resources = project.members(false);
        for (int j = 0; j < resources.length; j++) {
            if (resources[j] instanceof IFile) {
                if (".project".equals(resources[j].getName()) //$NON-NLS-1$
                        || ".classpath".equals(resources[j] //$NON-NLS-1$
                                .getName())
                        || ICoreConstants.PLUGIN_FILENAME_DESCRIPTOR.equals(resources[j].getName())
                        || ICoreConstants.BUILD_FILENAME_DESCRIPTOR.equals(resources[j].getName())) {
                    continue;
                }
                // resource at the root, export root
                return;
            }
        }
        removeExportRoot(bundle);
    }

    @Override
    protected void adjustManifests(IProgressMonitor monitor, IProject project, IPluginBase base)
            throws CoreException {
        super.adjustManifests(monitor, project, base);
        int units = fData.doFindDependencies() ? 4 : 2;
        units += fData.isUpdateReferences() ? 1 : 0;
        monitor.beginTask(new String(), units);
        IBundle bundle = (base instanceof BundlePluginBase) ? ((BundlePluginBase) base).getBundle() : null;
        if (bundle != null) {
            adjustExportRoot(project, bundle);
            monitor.worked(1);
            addExportedPackages(project, bundle);
            monitor.worked(1);
            if (fData.doFindDependencies()) {
                addDependencies(project, base.getModel(), new SubProgressMonitor(monitor, 2));
            }
            if (fData.isUpdateReferences()) {
                updateReferences(monitor, project);
                monitor.worked(1);
            }
        }
        monitor.done();
    }

    protected void updateReferences(IProgressMonitor monitor, IProject project) throws JavaModelException {
        IJavaProject currentProject = JavaCore.create(project);
        IPluginModelBase[] pluginstoUpdate = fData.getPluginsToUpdate();
        for (int i = 0; i < pluginstoUpdate.length; ++i) {
            IProject proj = pluginstoUpdate[i].getUnderlyingResource().getProject();
            if (currentProject.getProject().equals(proj))
                continue;
            IJavaProject javaProject = JavaCore.create(proj);
            IClasspathEntry[] cp = javaProject.getRawClasspath();
            IClasspathEntry[] updated = getUpdatedClasspath(cp, currentProject);
            if (updated != null) {
                javaProject.setRawClasspath(updated, monitor);
            }
            try {
                updateRequiredPlugins(javaProject, monitor, pluginstoUpdate[i]);
            } catch (CoreException e) {
                PDEPlugin.log(e);
            }
        }
    }

    private static void updateRequiredPlugins(IJavaProject javaProject, IProgressMonitor monitor,
            IPluginModelBase model) throws CoreException {
        IClasspathEntry[] entries = javaProject.getRawClasspath();
        List<IClasspathEntry> classpath = new ArrayList<IClasspathEntry>();
        List<IClasspathEntry> requiredProjects = new ArrayList<IClasspathEntry>();
        for (int i = 0; i < entries.length; i++) {
            if (isPluginProjectEntry(entries[i])) {
                requiredProjects.add(entries[i]);
            } else {
                classpath.add(entries[i]);
            }
        }
        if (requiredProjects.size() <= 0)
            return;
        IFile file = PDEProject.getManifest(javaProject.getProject());
        try {
            // TODO format manifest
            Manifest manifest = new Manifest(file.getContents());
            String value = manifest.getMainAttributes().getValue(Constants.REQUIRE_BUNDLE);
            StringBuffer sb = value != null ? new StringBuffer(value) : new StringBuffer();
            if (sb.length() > 0)
                sb.append(","); //$NON-NLS-1$
            for (int i = 0; i < requiredProjects.size(); i++) {
                IClasspathEntry entry = requiredProjects.get(i);
                if (i > 0)
                    sb.append(","); //$NON-NLS-1$
                sb.append(entry.getPath().segment(0));
                if (entry.isExported())
                    sb.append(";visibility:=reexport"); // TODO is there a //$NON-NLS-1$
                // constant?
            }
            manifest.getMainAttributes().putValue(Constants.REQUIRE_BUNDLE, sb.toString());
            ByteArrayOutputStream content = new ByteArrayOutputStream();
            manifest.write(content);
            file.setContents(new ByteArrayInputStream(content.toByteArray()), true, false, monitor);
            // now update .classpath
            javaProject.setRawClasspath(classpath.toArray(new IClasspathEntry[classpath.size()]), monitor);
            //         ClasspathComputer.setClasspath(javaProject.getProject(), model);
        } catch (IOException e) {
        } catch (CoreException e) {
        }
    }

    private static boolean isPluginProjectEntry(IClasspathEntry entry) {
        if (IClasspathEntry.CPE_PROJECT != entry.getEntryKind())
            return false;
        IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
        IProject other = workspaceRoot.getProject(entry.getPath().segment(0));
        if (!PDE.hasPluginNature(other))
            return false;
        if (PDEProject.getFragmentXml(other).exists())
            return false;
        try {
            InputStream is = PDEProject.getManifest(other).getContents();
            try {
                Manifest mf = new Manifest(is);
                if (mf.getMainAttributes().getValue(Constants.FRAGMENT_HOST) != null)
                    return false;
            } finally {
                is.close();
            }
        } catch (IOException e) {
            // assume "not a fragment"
        } catch (CoreException e) {
            // assume "not a fragment"
        }
        return true;
    }

    /**
     * @return updated classpath or null if there were no changes
     */
    private IClasspathEntry[] getUpdatedClasspath(IClasspathEntry[] cp, IJavaProject currentProject) {
        boolean exposed = false;
        int refIndex = -1;
        List<IClasspathEntry> result = new ArrayList<IClasspathEntry>();
        Set<Manifest> manifests = new HashSet<Manifest>();
        for (int i = 0; i < fData.getLibraryPaths().length; ++i) {
            try {
                manifests.add(new JarFile(fData.getLibraryPaths()[i]).getManifest());
            } catch (IOException e) {
                PDEPlugin.log(e);
            }
        }
        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
        for (int i = 0; i < cp.length; ++i) {
            IClasspathEntry cpe = cp[i];
            switch (cpe.getEntryKind()) {
            case IClasspathEntry.CPE_LIBRARY:
                String path = null;
                IPath location = root.getFile(cpe.getPath()).getLocation();
                if (location != null) {
                    path = location.toString();
                }
                //try maybe path is absolute
                if (path == null) {
                    path = cpe.getPath().toString();
                }
                JarFile jarFile = null;
                try {
                    jarFile = new JarFile(path);
                    if (manifests.contains(jarFile.getManifest())) {
                        if (refIndex < 0) {
                            // allocate slot
                            refIndex = result.size();
                            result.add(null);
                        }
                        exposed |= cpe.isExported();
                    } else {
                        result.add(cpe);
                    }
                } catch (IOException e) {
                    PDEPlugin.log(e);
                } finally {
                    if (jarFile != null) {
                        try {
                            jarFile.close();
                        } catch (IOException e) {
                            PDEPlugin.log(e);
                        }
                    }
                }
                break;
            default:
                result.add(cpe);
                break;
            }
        }
        if (refIndex >= 0) {
            result.set(refIndex, JavaCore.newProjectEntry(currentProject.getPath(), exposed));
            return result.toArray(new IClasspathEntry[result.size()]);
        }
        return null;
    }

    @Override
    protected void createContents(IProgressMonitor monitor, IProject project)
            throws CoreException, JavaModelException, InvocationTargetException, InterruptedException {
        // copy jars
        String[] paths = fData.getLibraryPaths();
        for (int i = paths.length - 1; i >= 0; i--) {
            File jarFile = new File(paths[i]);
            if (fData.isUnzipLibraries()) {
                importJar(jarFile, project, monitor);
            } else {
                addJar(jarFile, project, monitor);
            }
            monitor.worked(1);
        }

        // delete manifest.mf imported from libraries
        IFile importedManifest = PDEProject.getManifest(project);
        if (importedManifest.exists()) {
            importedManifest.delete(true, false, monitor);
            if (!fData.hasBundleStructure()) {
                IFolder meta_inf = project.getFolder("META-INF"); //$NON-NLS-1$
                if (meta_inf.members().length == 0) {
                    meta_inf.delete(true, false, monitor);
                }
            }
        }
    }

    @Override
    protected void fillBinIncludes(IProject project, IBuildEntry binEntry) throws CoreException {
        if (fData.hasBundleStructure())
            binEntry.addToken(ICoreConstants.MANIFEST_FOLDER_NAME);
        else
            binEntry.addToken(ICoreConstants.PLUGIN_FILENAME_DESCRIPTOR);

        if (fData.isUnzipLibraries()) {
            IResource[] resources = project.members(false);
            for (int j = 0; j < resources.length; j++) {
                String resourceName = resources[j].getName();
                if (resources[j] instanceof IFolder) {
                    if (!".settings".equals(resourceName) && !binEntry.contains(resourceName + "/")) //$NON-NLS-1$ //$NON-NLS-2$
                        binEntry.addToken(resourceName + "/"); //$NON-NLS-1$
                } else {
                    if (".project".equals(resourceName) //$NON-NLS-1$
                            || ".classpath".equals(resourceName) //$NON-NLS-1$
                            || ICoreConstants.BUILD_FILENAME_DESCRIPTOR.equals(resourceName)) {
                        continue;
                    }
                    if (!binEntry.contains(resourceName))
                        binEntry.addToken(resourceName);
                }
            }
        } else {
            String[] libraryPaths = fData.getLibraryPaths();
            for (int j = 0; j < libraryPaths.length; j++) {
                File jarFile = new File(libraryPaths[j]);
                String name = jarFile.getName();
                if (!binEntry.contains(name))
                    binEntry.addToken(name);
            }
        }
    }

    @Override
    protected IClasspathEntry[] getInternalClassPathEntries(IJavaProject project, IFieldData data) {
        String[] libraryPaths;
        if (fData.isUnzipLibraries()) {
            libraryPaths = new String[] { "" }; //$NON-NLS-1$
        } else {
            libraryPaths = fData.getLibraryPaths();
        }
        IClasspathEntry[] entries = new IClasspathEntry[libraryPaths.length];
        for (int j = 0; j < libraryPaths.length; j++) {
            File jarFile = new File(libraryPaths[j]);
            String jarName = jarFile.getName();
            IPath path = project.getProject().getFullPath().append(jarName);
            entries[j] = JavaCore.newLibraryEntry(path, null, null, true);
        }
        return entries;
    }

    @Override
    protected int getNumberOfWorkUnits() {
        int numUnits = super.getNumberOfWorkUnits();
        numUnits += fData.getLibraryPaths().length;
        return numUnits;
    }

    private void importJar(File jar, IResource destination, IProgressMonitor monitor)
            throws CoreException, InvocationTargetException, InterruptedException {
        ZipFile input = null;
        try {
            try {
                input = new ZipFile(jar);
                ZipFileStructureProvider provider = new ZipFileStructureProvider(input);
                ImportOperation op = new ImportOperation(destination.getFullPath(), provider.getRoot(), provider,
                        new IOverwriteQuery() {
                            public String queryOverwrite(String pathString) {
                                return IOverwriteQuery.ALL;
                            }
                        });
                op.run(monitor);
            } finally {
                if (input != null)
                    input.close();
            }
        } catch (IOException e) {
            throw new CoreException(new Status(IStatus.ERROR, IPDEUIConstants.PLUGIN_ID, IStatus.OK,
                    NLS.bind(PDEUIMessages.NewProjectCreationOperation_errorImportingJar, jar), e));
        }
    }

    private void removeExportRoot(IBundle bundle) {
        String value = bundle.getHeader(Constants.BUNDLE_CLASSPATH);
        if (value == null)
            value = "."; //$NON-NLS-1$
        try {
            ManifestElement[] elems = ManifestElement.parseHeader(Constants.BUNDLE_CLASSPATH, value);
            StringBuffer buff = new StringBuffer(value.length());
            for (int i = 0; i < elems.length; i++) {
                if (!elems[i].getValue().equals(".")) //$NON-NLS-1$
                    buff.append(elems[i].getValue());
            }
            bundle.setHeader(Constants.BUNDLE_CLASSPATH, buff.toString());
        } catch (BundleException e) {
        }
    }

    @Override
    protected void setPluginLibraries(WorkspacePluginModelBase model) throws CoreException {
        IPluginBase pluginBase = model.getPluginBase();
        if (fData.isUnzipLibraries()) {
            IPluginLibrary library = model.getPluginFactory().createLibrary();
            library.setName("."); //$NON-NLS-1$
            library.setExported(true);
            pluginBase.add(library);
        } else {
            String[] paths = fData.getLibraryPaths();
            for (int i = 0; i < paths.length; i++) {
                File jarFile = new File(paths[i]);
                IPluginLibrary library = model.getPluginFactory().createLibrary();
                library.setName(jarFile.getName());
                library.setExported(true);
                pluginBase.add(library);
            }
        }
    }

    @Override
    protected void createSourceOutputBuildEntries(WorkspaceBuildModel model, IBuildModelFactory factory)
            throws CoreException {
        if (fData.isUnzipLibraries()) {
            // SOURCE.<LIBRARY_NAME>
            IBuildEntry entry = factory.createEntry(IBuildEntry.JAR_PREFIX + "."); //$NON-NLS-1$
            entry.addToken("."); //$NON-NLS-1$
            model.getBuild().add(entry);

            // OUTPUT.<LIBRARY_NAME>
            entry = factory.createEntry(IBuildEntry.OUTPUT_PREFIX + "."); //$NON-NLS-1$
            entry.addToken("."); //$NON-NLS-1$
            model.getBuild().add(entry);
        }
    }

    private void addExportedPackages(IProject project, IBundle bundle) {
        String value = bundle.getHeader(Constants.BUNDLE_CLASSPATH);
        if (value == null)
            value = "."; //$NON-NLS-1$
        try {
            ManifestElement[] elems = ManifestElement.parseHeader(Constants.BUNDLE_CLASSPATH, value);
            HashMap<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();
            for (int i = 0; i < elems.length; i++) {
                ArrayList<String> filter = new ArrayList<String>();
                filter.add("*"); //$NON-NLS-1$
                map.put(elems[i].getValue(), filter);
            }
            Set<String> packages = getExports(project, map);
            String pkgValue = getCommaValuesFromPackagesSet(packages, fData.getVersion());
            bundle.setHeader(Constants.EXPORT_PACKAGE, pkgValue);
        } catch (BundleException e) {
        }
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public Set<String> getExports(IProject proj, Map libs) {
        IFile buildProperties = PDEProject.getBuildProperties(proj);
        IBuild build = null;
        if (buildProperties != null) {
            WorkspaceBuildModel buildModel = new WorkspaceBuildModel(buildProperties);
            build = buildModel.getBuild();
        } else
            build = new Build();
        return findPackages(proj, libs, build);
    }

    private Set<String> findPackages(IProject proj, Map<?, List<?>> libs, IBuild build) {
        TreeSet<String> result = new TreeSet<String>();
        IJavaProject jp = JavaCore.create(proj);
        Iterator<?> it = libs.entrySet().iterator();
        while (it.hasNext()) {
            @SuppressWarnings("rawtypes")
            Map.Entry entry = (Map.Entry) it.next();
            String libName = entry.getKey().toString();
            List<?> filter = (List<?>) entry.getValue();
            IBuildEntry libEntry = build.getEntry(SOURCE_PREFIX + libName);
            if (libEntry != null) {
                String[] tokens = libEntry.getTokens();
                for (int i = 0; i < tokens.length; i++) {
                    IResource folder = null;
                    if (tokens[i].equals(".")) //$NON-NLS-1$
                        folder = proj;
                    else
                        folder = proj.getFolder(tokens[i]);
                    if (folder != null)
                        addPackagesFromFragRoot(jp.getPackageFragmentRoot(folder), result, filter);
                }
            } else {
                IResource res = proj.findMember(libName);
                if (res != null)
                    addPackagesFromFragRoot(jp.getPackageFragmentRoot(res), result, filter);
            }
        }
        return result;
    }

    private void addPackagesFromFragRoot(IPackageFragmentRoot root, Collection<String> result, List<?> filter) {
        if (root == null)
            return;
        try {
            if (filter != null && !filter.contains("*")) { //$NON-NLS-1$
                ListIterator<?> li = filter.listIterator();
                while (li.hasNext()) {
                    String pkgName = li.next().toString();
                    if (pkgName.endsWith(".*")) //$NON-NLS-1$
                        pkgName = pkgName.substring(0, pkgName.length() - 2);

                    IPackageFragment frag = root.getPackageFragment(pkgName);
                    if (frag != null)
                        result.add(pkgName);
                }
                return;
            }
            IJavaElement[] children = root.getChildren();
            for (int j = 0; j < children.length; j++) {
                IPackageFragment fragment = (IPackageFragment) children[j];
                String name = fragment.getElementName();
                if (fragment.hasChildren() && !result.contains(name)) {
                    result.add(name);
                }
            }
        } catch (JavaModelException e) {
        }
    }

    private void addDependencies(IProject project, ISharedPluginModel model, IProgressMonitor monitor) {
        if (!(model instanceof IBundlePluginModelBase)) {
            monitor.done();
            return;
        }
        final boolean unzip = fData.isUnzipLibraries();
        try {
            new AddNewBinaryDependenciesOperation(project, (IBundlePluginModelBase) model) {
                // Need to override this function to include every bundle in the
                // target platform as a possible dependency
                @Override
                protected String[] findSecondaryBundles(IBundle bundle, Set<String> ignorePkgs) {
                    IPluginModelBase[] bases = PluginRegistry.getActiveModels();
                    String[] ids = new String[bases.length];
                    for (int i = 0; i < bases.length; i++) {
                        BundleDescription desc = bases[i].getBundleDescription();
                        if (desc == null)
                            ids[i] = bases[i].getPluginBase().getId();
                        else
                            ids[i] = desc.getSymbolicName();
                    }
                    return ids;
                }

                // Need to override this function because when jar is unzipped,
                // build.properties does not contain entry for '.'.
                // Therefore, the super.addProjectPackages will not find the
                // project packages(it includes only things in bin.includes)
                @Override
                protected void addProjectPackages(IBundle bundle, Set<String> ignorePkgs) {
                    if (!unzip)
                        super.addProjectPackages(bundle, ignorePkgs);
                    Stack<IResource> stack = new Stack<IResource>();
                    stack.push(fProject);
                    try {
                        while (!stack.isEmpty()) {
                            IContainer folder = (IContainer) stack.pop();
                            IResource[] children = folder.members();
                            for (int i = 0; i < children.length; i++) {
                                if (children[i] instanceof IContainer)
                                    stack.push(children[i]);
                                else if ("class".equals(((IFile) children[i]).getFileExtension())) { //$NON-NLS-1$
                                    String path = folder.getProjectRelativePath().toString();
                                    ignorePkgs.add(path.replace('/', '.'));
                                }
                            }
                        }
                    } catch (CoreException e) {
                    }

                }
            }.run(monitor);
        } catch (InvocationTargetException e) {
        } catch (InterruptedException e) {
        }
    }

}