org.eclipse.pde.internal.core.ClasspathHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.pde.internal.core.ClasspathHelper.java

Source

/*******************************************************************************
 * Copyright (c) 2003, 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
 *******************************************************************************/
package org.eclipse.pde.internal.core;

import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.Map.Entry;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.jdt.core.*;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.core.IBundleClasspathResolver;
import org.eclipse.pde.core.build.IBuild;
import org.eclipse.pde.core.build.IBuildEntry;
import org.eclipse.pde.core.plugin.*;
import org.eclipse.pde.internal.core.build.WorkspaceBuildModel;
import org.eclipse.pde.internal.core.project.PDEProject;

public class ClasspathHelper {

    private static final String DOT = "."; //$NON-NLS-1$
    private static final String FRAGMENT_ANNOTATION = "@fragment@"; //$NON-NLS-1$

    public static String getDevEntriesProperties(String fileName, boolean checkExcluded) {
        File file = new File(fileName);
        if (!file.exists()) {
            File directory = file.getParentFile();
            if (directory != null && (!directory.exists() || directory.isFile())) {
                directory.mkdirs();
            }
        }
        Properties properties = new Properties();
        // account for cascading workspaces
        TargetWeaver.weaveDevProperties(properties);
        IPluginModelBase[] models = PluginRegistry.getWorkspaceModels();
        for (int i = 0; i < models.length; i++) {
            String id = models[i].getPluginBase().getId();
            if (id == null)
                continue;
            String entry = writeEntry(getDevPaths(models[i], checkExcluded, null));
            if (entry.length() > 0) {
                String currentValue = (String) properties.get(id);
                if (!entry.equals(currentValue)) {
                    if (currentValue != null)
                        entry = currentValue.concat(",").concat(entry); //$NON-NLS-1$
                    properties.put(id, entry);
                }
            }
        }
        properties.put("@ignoredot@", "true"); //$NON-NLS-1$ //$NON-NLS-2$

        FileOutputStream stream = null;
        try {
            stream = new FileOutputStream(fileName);
            properties.store(stream, ""); //$NON-NLS-1$
            stream.flush();
            return new URL("file:" + fileName).toString(); //$NON-NLS-1$
        } catch (IOException e) {
            PDECore.logException(e);
        } finally {
            try {
                if (stream != null)
                    stream.close();
            } catch (IOException e) {
            }
        }
        return getDevEntries(checkExcluded);
    }

    public static String getDevEntriesProperties(String fileName, Map<?, ?> map) {
        File file = new File(fileName);
        if (!file.exists()) {
            File directory = file.getParentFile();
            if (directory != null && (!directory.exists() || directory.isFile())) {
                directory.mkdirs();
            }
        }
        Properties properties = new Properties();
        // account for cascading workspaces
        TargetWeaver.weaveDevProperties(properties);
        Iterator<?> iter = map.values().iterator();
        while (iter.hasNext()) {
            IPluginModelBase model = (IPluginModelBase) iter.next();
            if (model.getUnderlyingResource() != null) {
                String entry = writeEntry(getDevPaths(model, true, map));
                if (entry.length() > 0) {
                    String id = model.getPluginBase().getId();
                    String currentValue = (String) properties.get(id);
                    if (!entry.equals(currentValue)) {
                        if (currentValue != null)
                            entry = currentValue.concat(",").concat(entry); //$NON-NLS-1$
                        properties.put(id, entry);
                    }
                }
            }
        }
        properties.put("@ignoredot@", "true"); //$NON-NLS-1$ //$NON-NLS-2$

        FileOutputStream stream = null;
        try {
            stream = new FileOutputStream(fileName);
            properties.store(stream, ""); //$NON-NLS-1$
            stream.flush();
            return new URL("file:" + fileName).toString(); //$NON-NLS-1$
        } catch (IOException e) {
            PDECore.logException(e);
        } finally {
            try {
                if (stream != null)
                    stream.close();
            } catch (IOException e) {
            }
        }
        return getDevEntries(true);
    }

    private static String getDevEntries(boolean checkExcluded) {
        IPluginModelBase[] models = PluginRegistry.getWorkspaceModels();
        ArrayList<IPath> list = new ArrayList<IPath>();
        for (int i = 0; i < models.length; i++) {
            String id = models[i].getPluginBase().getId();
            if (id == null || id.trim().length() == 0)
                continue;
            IPath[] paths = getDevPaths(models[i], checkExcluded, null);
            for (int j = 0; j < paths.length; j++) {
                list.add(paths[j]);
            }
        }
        String entry = writeEntry(list.toArray(new IPath[list.size()]));
        return entry.length() > 0 ? entry : "bin"; //$NON-NLS-1$
    }

    private static String writeEntry(IPath[] paths) {
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < paths.length; i++) {
            buffer.append(paths[i].toString());
            if (i < paths.length - 1)
                buffer.append(","); //$NON-NLS-1$
        }
        return buffer.toString();
    }

    // TODO remove - no longer used after bug 217870
    public static Dictionary<String, String> getDevDictionary(IPluginModelBase model) {
        if (model.getUnderlyingResource() == null)
            return null;

        String id = model.getPluginBase().getId();
        if (id == null || id.trim().length() == 0)
            return null;
        IPath[] paths = getDevPaths(model, false, null);
        String entry = writeEntry(paths);
        Hashtable<String, String> map = new Hashtable<String, String>(2);
        map.put("@ignoredot@", "true"); //$NON-NLS-1$ //$NON-NLS-2$
        map.put(id, entry.length() > 0 ? entry : "bin"); //$NON-NLS-1$
        return map;
    }

    // creates a map whose key is a Path to the source directory/jar and the value is a Path output directory or jar.
    private static Map<IPath, ArrayList<IPath>> getClasspathMap(IProject project, boolean checkExcluded,
            boolean absolutePaths) throws JavaModelException {
        List<Path> excluded = getFoldersToExclude(project, checkExcluded);
        IJavaProject jProject = JavaCore.create(project);
        HashMap<IPath, ArrayList<IPath>> map = new HashMap<IPath, ArrayList<IPath>>();
        IClasspathEntry[] entries = jProject.getRawClasspath();
        for (int i = 0; i < entries.length; i++) {
            // most of the paths we get will be project relative, so we need to make the paths relative
            // we will have problems adding an "absolute" path that is workspace relative
            IPath output = null, source = null;
            if (entries[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) {
                source = entries[i].getPath();
                output = entries[i].getOutputLocation();
                if (output == null)
                    output = jProject.getOutputLocation();
            } else if (entries[i].getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
                source = entries[i].getPath();
                output = entries[i].getPath();
                if (source.segmentCount() == 1)
                    source = new Path(DOT);
            }
            if (output != null && !excluded.contains(output)) {
                IResource file = project.findMember(output.removeFirstSegments(1));
                // make the path either relative or absolute
                if (file != null) {
                    boolean isLinked = file.isLinked(IResource.CHECK_ANCESTORS);
                    if (isLinked || absolutePaths) {
                        IPath location = file.getLocation();
                        if (location != null) {
                            output = location.makeAbsolute();
                        } else {
                            PDECore.log(new Status(IStatus.ERROR, PDECore.PLUGIN_ID,
                                    NLS.bind(PDECoreMessages.ClasspathHelper_BadFileLocation, file.getFullPath())));
                            continue;
                        }
                    } else {
                        output = output.makeRelative();
                    }
                } else
                    continue;
                ArrayList<IPath> list = map.get(source);
                if (list == null)
                    list = new ArrayList<IPath>();
                list.add(output);
                map.put(source, list);
            }
        }

        // Add additional entries from contributed bundle classpath resolvers
        IBundleClasspathResolver[] resolvers = PDECore.getDefault().getClasspathContainerResolverManager()
                .getBundleClasspathResolvers(project);
        for (int i = 0; i < resolvers.length; i++) {
            Map<IPath, Collection<IPath>> resolved = resolvers[i].getAdditionalClasspathEntries(jProject);
            Iterator<Entry<IPath, Collection<IPath>>> resolvedIter = resolved.entrySet().iterator();
            while (resolvedIter.hasNext()) {
                Map.Entry<IPath, Collection<IPath>> resolvedEntry = resolvedIter.next();
                IPath ceSource = resolvedEntry.getKey();
                ArrayList<IPath> list = map.get(ceSource);
                if (list == null) {
                    list = new ArrayList<IPath>();
                    map.put(ceSource, list);
                }
                list.addAll(resolvedEntry.getValue());
            }
        }

        return map;
    }

    // find the corresponding paths for a library name.  Searches for source folders first, but includes any libraries on the buildpath with the same name
    private static IPath[] findLibrary(String libName, IProject project, Map<IPath, ArrayList<IPath>> classpathMap,
            IBuild build) {
        ArrayList<IPath> paths = new ArrayList<IPath>();
        IBuildEntry entry = (build != null) ? build.getEntry(IBuildEntry.JAR_PREFIX + libName) : null;
        if (entry != null) {
            String[] resources = entry.getTokens();
            for (int j = 0; j < resources.length; j++) {
                IResource res = project.findMember(resources[j]);
                if (res != null) {
                    ArrayList<IPath> list = classpathMap.get(res.getFullPath());
                    if (list != null) {
                        Iterator<IPath> li = list.iterator();
                        while (li.hasNext())
                            paths.add(li.next());
                    }
                }
            }
        }

        // search for a library that exists in jar form on the buildpath
        IPath path = null;
        if (libName.equals(DOT))
            path = new Path(DOT);
        else {
            IResource res = project.findMember(libName);
            if (res != null)
                path = res.getFullPath();
            else
                path = new Path(libName);
        }

        List<IPath> list = classpathMap.get(path);
        if (list != null) {
            Iterator<IPath> li = list.iterator();
            while (li.hasNext())
                paths.add(li.next());
        }
        return paths.toArray(new IPath[paths.size()]);
    }

    private static IPath[] getDevPaths(IPluginModelBase model, boolean checkExcluded, Map<?, ?> pluginsMap) {
        ArrayList<IPath> result = new ArrayList<IPath>();
        IProject project = model.getUnderlyingResource().getProject();
        IPluginBase base = model.getPluginBase();
        IPluginLibrary[] libraries = base.getLibraries();
        try {
            if (project.hasNature(JavaCore.NATURE_ID)) {
                Map<IPath, ArrayList<IPath>> classpathMap = getClasspathMap(project, checkExcluded, false);
                IFile file = PDEProject.getBuildProperties(project);
                IPath filePath = file.getLocation();
                boolean searchBuild = filePath != null && filePath.toFile().exists();
                if (searchBuild) {
                    WorkspaceBuildModel bModel = new WorkspaceBuildModel(file);
                    IBuild build = bModel.getBuild();
                    // if it is a custom build, act like there is no build.properties (add everything)
                    IBuildEntry entry = build.getEntry("custom"); //$NON-NLS-1$
                    if (entry != null)
                        searchBuild = false;
                    else {
                        if (libraries.length == 0) {
                            IPath[] paths = findLibrary(DOT, project, classpathMap, build);
                            if (paths.length == 0) {
                                // No mapping for default library, if there are source folders just add their corresponding output folders to the build path.
                                // This likely indicates an error in the build.properties, but to be friendly we should add the output folders so running/debugging
                                // works (see bug 237025)
                                if (!classpathMap.isEmpty()) {
                                    Iterator<ArrayList<IPath>> iterator = classpathMap.values().iterator();
                                    List<IPath> collect = new ArrayList<IPath>();
                                    while (iterator.hasNext()) {
                                        collect.addAll(iterator.next());
                                    }
                                    paths = collect.toArray(new IPath[collect.size()]);
                                }
                            }
                            for (int j = 0; j < paths.length; j++)
                                addPath(result, project, paths[j]);
                        } else {
                            for (int i = 0; i < libraries.length; i++) {
                                IPath[] paths = findLibrary(libraries[i].getName(), project, classpathMap, build);
                                if (paths.length == 0 && !libraries[i].getName().equals(DOT)) {
                                    paths = findLibraryFromFragments(libraries[i].getName(), model, checkExcluded,
                                            pluginsMap);
                                }
                                for (int j = 0; j < paths.length; j++)
                                    addPath(result, project, paths[j]);
                            }
                        }
                    }
                }
                if (!searchBuild) {
                    // if no build.properties, add all output folders
                    Iterator<Entry<IPath, ArrayList<IPath>>> it = classpathMap.entrySet().iterator();
                    while (it.hasNext()) {
                        Map.Entry<IPath, ArrayList<IPath>> entry = it.next();
                        ArrayList<IPath> list = entry.getValue();
                        ListIterator<IPath> li = list.listIterator();
                        while (li.hasNext())
                            addPath(result, project, li.next());
                    }
                }
            }
        } catch (JavaModelException e) {
        } catch (CoreException e) {
        }
        return result.toArray(new IPath[result.size()]);
    }

    // looks for fragments for a plug-in.  Then searches the fragments for a specific library.  Will return paths which are absolute (required by runtime)
    private static IPath[] findLibraryFromFragments(String libName, IPluginModelBase model, boolean checkExcluded,
            Map<?, ?> plugins) {
        IFragmentModel[] frags = PDEManager.findFragmentsFor(model);
        for (int i = 0; i < frags.length; i++) {
            if (plugins != null && !plugins.containsKey(frags[i].getBundleDescription().getSymbolicName()))
                continue;
            // look in project first
            if (frags[i].getUnderlyingResource() != null) {
                try {
                    IProject project = frags[i].getUnderlyingResource().getProject();
                    Map<IPath, ArrayList<IPath>> classpathMap = getClasspathMap(project, checkExcluded, true);
                    IFile file = PDEProject.getBuildProperties(project);
                    IBuild build = null;
                    if (file.exists()) {
                        WorkspaceBuildModel bModel = new WorkspaceBuildModel(file);
                        build = bModel.getBuild();
                    }
                    IPath[] paths = findLibrary(libName, project, classpathMap, build);
                    if (paths.length > 0)
                        return postfixFragmentAnnotation(paths);

                } catch (JavaModelException e) {
                    continue;
                }
                // if external plugin, look in child directories for library
            } else {
                File file = new File(frags[i].getInstallLocation());
                if (file.isDirectory()) {
                    file = new File(file, libName);
                    if (file.exists())
                        // Postfix fragment annotation for fragment path (fix bug 294211)
                        return new IPath[] { new Path(file.getPath() + FRAGMENT_ANNOTATION) };
                }
            }
        }
        return new IPath[0];
    }

    /*
     * Postfixes the fragment annotation for the paths that we know come
     * from fragments.  This is needed to fix bug 294211.
     */
    private static IPath[] postfixFragmentAnnotation(IPath[] paths) {
        for (int i = 0; i < paths.length; i++)
            paths[i] = new Path(paths[i].toString() + FRAGMENT_ANNOTATION);
        return paths;
    }

    private static void addPath(ArrayList<IPath> result, IProject project, IPath path) {
        IPath resultPath = null;
        if (path.isAbsolute())
            resultPath = path;
        else if (path.segmentCount() > 0 && path.segment(0).equals(project.getName())) {
            IContainer bundleRoot = PDEProject.getBundleRoot(project);
            IPath rootPath = bundleRoot.getFullPath();
            // make path relative to bundle root
            path = path.makeRelativeTo(rootPath);
            if (path.segmentCount() == 0)
                resultPath = new Path(DOT);
            else {
                IResource resource = bundleRoot.findMember(path);
                if (resource != null)
                    resultPath = path;
            }
        }

        if (resultPath != null && !result.contains(resultPath))
            result.add(resultPath);
    }

    private static List<Path> getFoldersToExclude(IProject project, boolean checkExcluded) {
        ArrayList<Path> list = new ArrayList<Path>();
        if (checkExcluded) {
            IEclipsePreferences pref = new ProjectScope(project).getNode(PDECore.PLUGIN_ID);
            if (pref != null) {
                String binExcludes = pref.get(ICoreConstants.SELFHOSTING_BIN_EXCLUDES, ""); //$NON-NLS-1$
                StringTokenizer tokenizer = new StringTokenizer(binExcludes, ","); //$NON-NLS-1$
                while (tokenizer.hasMoreTokens()) {
                    list.add(new Path(tokenizer.nextToken().trim()));
                }
            }
        }
        return list;
    }

}