org.eclipse.ajdt.core.AspectJCorePreferences.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.ajdt.core.AspectJCorePreferences.java

Source

/*******************************************************************************
 * Copyright (c) 2005 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 - initial version
 *******************************************************************************/
package org.eclipse.ajdt.core;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.eclipse.jdt.core.IAccessRule;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.JavaProject;
import org.osgi.service.prefs.BackingStoreException;

/**
 * Project specific settings. These used to be in the UI plugin, so the UI node
 * names have been kept for compatibility.
 */
public class AspectJCorePreferences {

    public static final String OPTION_IncrementalCompilationOptimizations = "org.eclipse.ajdt.core.builder.incrementalCompilationOptimizations"; //$NON-NLS-1$

    public static final String ASPECTPATH_ATTRIBUTE_NAME = "org.eclipse.ajdt.aspectpath"; //$NON-NLS-1$
    public static final String INPATH_ATTRIBUTE_NAME = "org.eclipse.ajdt.inpath"; //$NON-NLS-1$

    // see ajdt.ui's plugin.xml and the org.eclipse.jdt.ui.classpathAttributeConfiguration extension point
    public static final String INPATH_RESTRICTION_ATTRIBUTE_NAME = "org.eclipse.ajdt.inpath.restriction"; //$NON-NLS-1$
    public static final String ASPECTPATH_RESTRICTION_ATTRIBUTE_NAME = "org.eclipse.ajdt.aspectpath.restriction"; //$NON-NLS-1$

    /**
     *  The value may be filled in with the container that contains this classpath entry
     *  So when checking to see if a classpath entry has this attribute, use {@link #isOnAspectpath(IClasspathEntry)} 
     */
    public static final IClasspathAttribute ASPECTPATH_ATTRIBUTE = JavaCore
            .newClasspathAttribute(ASPECTPATH_ATTRIBUTE_NAME, ASPECTPATH_ATTRIBUTE_NAME); //$NON-NLS-1$

    /**
     *  The value may be filled in with the container that contains this classpath entry
     *  So when checking to see if a classpath entry has this attribute, use {@link #isOnInpath(IClasspathEntry)} 
     */
    public static final IClasspathAttribute INPATH_ATTRIBUTE = JavaCore.newClasspathAttribute(INPATH_ATTRIBUTE_NAME,
            INPATH_ATTRIBUTE_NAME); //$NON-NLS-1$

    public static final String OUT_JAR = "org.eclipse.ajdt.ui.outJar"; //$NON-NLS-1$

    public static final String INPATH_OUT_FOLDER = "org.eclipse.ajdt.ui.inpathOutFolder"; //$NON-NLS-1$

    public static final String ASPECTPATH = "org.eclipse.ajdt.ui.aspectPath"; //$NON-NLS-1$

    public static final String ASPECTPATH_CON_KINDS = "org.eclipse.ajdt.ui.aspectPath.contentKind"; //$NON-NLS-1$

    public static final String ASPECTPATH_ENT_KINDS = "org.eclipse.ajdt.ui.aspectPath.entryKind"; //$NON-NLS-1$

    public static final String INPATH = "org.eclipse.ajdt.ui.inPath"; //$NON-NLS-1$

    public static final String INPATH_CON_KINDS = "org.eclipse.ajdt.ui.inPath.contentKind"; //$NON-NLS-1$

    public static final String INPATH_ENT_KINDS = "org.eclipse.ajdt.ui.inPath.entryKind"; //$NON-NLS-1$

    public static String getProjectOutJar(IProject project) {
        IScopeContext projectScope = new ProjectScope(project);
        IEclipsePreferences projectNode = projectScope.getNode(AspectJPlugin.UI_PLUGIN_ID);
        return projectNode.get(OUT_JAR, ""); //$NON-NLS-1$
    }

    public static String getProjectInpathOutFolder(IProject project) {
        IScopeContext projectScope = new ProjectScope(project);
        IEclipsePreferences projectNode = projectScope.getNode(AspectJPlugin.UI_PLUGIN_ID);
        return projectNode.get(INPATH_OUT_FOLDER, null);
    }

    public static void setProjectOutJar(IProject project, String value) {
        IScopeContext projectScope = new ProjectScope(project);
        IEclipsePreferences projectNode = projectScope.getNode(AspectJPlugin.UI_PLUGIN_ID);
        projectNode.put(OUT_JAR, value);
        if (value.length() == 0) {
            projectNode.remove(OUT_JAR);
        }
        try {
            projectNode.flush();
        } catch (BackingStoreException e) {
        }
    }

    public static void setProjectInpathOutFolder(IProject project, String value) {
        IScopeContext projectScope = new ProjectScope(project);
        IEclipsePreferences projectNode = projectScope.getNode(AspectJPlugin.UI_PLUGIN_ID);
        if (value == null || value.length() == 0) {
            projectNode.remove(INPATH_OUT_FOLDER);
        } else {
            projectNode.put(INPATH_OUT_FOLDER, value);
        }
        try {
            projectNode.flush();
        } catch (BackingStoreException e) {
        }
    }

    public static void setProjectAspectPath(IProject project, String path, String cKinds, String eKinds) {
        setProjectPath(project, path, cKinds, eKinds, ASPECTPATH_ATTRIBUTE);
    }

    public static String[] getRawProjectAspectPath(IProject project) {
        return internalGetProjectPath(project, ASPECTPATH_ATTRIBUTE, false);
    }

    public static String[] getResolvedProjectAspectPath(IProject project) {
        return internalGetProjectPath(project, ASPECTPATH_ATTRIBUTE, true);
    }

    public static void addToAspectPath(IProject project, IClasspathEntry entry) {
        IJavaProject jp = JavaCore.create(project);
        addAttribute(jp, entry, AspectJCorePreferences.ASPECTPATH_ATTRIBUTE);
    }

    public static void removeFromAspectPath(IProject project, IClasspathEntry entry) {
        IJavaProject jp = JavaCore.create(project);
        removeAttribute(jp, entry, AspectJCorePreferences.ASPECTPATH_ATTRIBUTE);
    }

    public static void addToAspectPath(IProject project, String jarPath, int eKind) {
        addAttribute(project, jarPath, eKind, ASPECTPATH_ATTRIBUTE);
    }

    public static boolean isOnAspectpath(IClasspathEntry entry) {
        IClasspathAttribute[] attributes = entry.getExtraAttributes();
        for (int j = 0; j < attributes.length; j++) {
            if (isAspectPathAttribute(attributes[j])) {
                return true;
            }
        }
        return false;
    }

    public static boolean isAspectPathAttribute(IClasspathAttribute attribute) {
        return attribute.getName().equals(AspectJCorePreferences.ASPECTPATH_ATTRIBUTE.getName());
    }

    /**
     * determines if an element is on the aspect path taking into account
     * the restrictions of the classpath container entry
     */
    public static boolean isOnAspectpathWithRestrictions(IClasspathEntry entry, String item) {
        if (!isOnAspectpath(entry)) {
            return false;
        }

        Set<String> restrictions = findContainerRestrictions(entry, true);
        if (restrictions == null) {
            // no restrictions, assume the jar entry is on the path
            return true;
        } else {
            for (String restriction : restrictions) {
                if (item.indexOf(restriction) != -1) {
                    return true;
                }
            }
            return false;
        }
    }

    /**
     * determines if an element is on the aspect path taking into account
     * the restrictions of the classpath container entry
     */
    public static boolean isOnInpathWithRestrictions(IClasspathEntry entry, String item) {
        if (!isOnInpath(entry)) {
            return false;
        }

        Set<String> restrictions = findContainerRestrictions(entry, false);
        if (restrictions == null || restrictions.isEmpty()) {
            // no restrictions, assume the jar entry is on the path
            return true;
        } else {
            for (String restriction : restrictions) {
                if (item.indexOf(restriction) != -1) {
                    return true;
                }
            }
            return false;
        }
    }

    /**
     * Checks to see if an entry is already on the aspect path
     */
    public static boolean isOnAspectpath(IProject project, String path) {
        IJavaProject jp = JavaCore.create(project);
        try {
            IClasspathEntry[] cp = jp.getRawClasspath();
            for (int i = 0; i < cp.length; i++) {
                if ((cp[i].getEntryKind() == IClasspathEntry.CPE_LIBRARY)
                        || (cp[i].getEntryKind() == IClasspathEntry.CPE_VARIABLE)
                        || (cp[i].getEntryKind() == IClasspathEntry.CPE_CONTAINER)
                        || (cp[i].getEntryKind() == IClasspathEntry.CPE_PROJECT)) {
                    IClasspathEntry resolvedClasspathEntry = JavaCore.getResolvedClasspathEntry(cp[i]);
                    if (resolvedClasspathEntry != null) {
                        String entry = resolvedClasspathEntry.getPath().toPortableString();
                        if (entry.equals(path)) {
                            if (isOnAspectpath(cp[i])) {
                                return true;
                            }
                        }
                    }
                }
            }
        } catch (JavaModelException e) {
        }
        return false;
    }

    public static String[] getRawProjectInpath(IProject project) {
        return internalGetProjectPath(project, INPATH_ATTRIBUTE, false);
    }

    public static String[] getResolvedProjectInpath(IProject project) {
        return internalGetProjectPath(project, INPATH_ATTRIBUTE, true);
    }

    public static List<IClasspathEntry> resolveDependentProjectClasspath(IClasspathEntry projEntry,
            IProject requiredProj) {
        // add all output locations and exported classpath entities
        // AspectJ compiler doesn't understand the concept of a java project
        List<IClasspathEntry> actualEntries = new ArrayList<IClasspathEntry>();

        try {
            JavaProject requiredJavaProj = (JavaProject) JavaCore.create(requiredProj);
            // bug 288395 Do not use the default mechanism for resolving classpath here
            // this will look into jar files at the Classpath header in the jar's manifest
            // and include jar files that are potentially missing, but have no effect on
            // the build.
            Object resolvedClasspath = requiredJavaProj.resolveClasspath(requiredJavaProj.getRawClasspath(), true,
                    false);
            IClasspathEntry[] requiredEntries = extractRequiredEntries(resolvedClasspath);
            for (int i = 0; i < requiredEntries.length; i++) {
                IClasspathEntry requiredEntry = requiredEntries[i];
                if (requiredEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {

                    // always add source entries even if not explicitly exported
                    // don't add the source folder itself, but instead add the outfolder
                    IPath outputLocation = requiredEntry.getOutputLocation();
                    if (outputLocation != null) {
                        IAccessRule[] rules = projEntry.getAccessRules();
                        IClasspathAttribute[] attributes = projEntry.getExtraAttributes();

                        // only add the out folder if it already exists
                        if (requiredProj.getFolder(outputLocation.removeFirstSegments(1)).exists()) {
                            IClasspathEntry outFolder = JavaCore.newLibraryEntry(outputLocation,
                                    requiredEntry.getPath(), requiredProj.getFullPath(), rules, attributes,
                                    projEntry.isExported());
                            actualEntries.add(outFolder);
                        }
                    }
                } else if (requiredEntry.isExported()) {
                    // must recur through this entry and add entries that it contains
                    actualEntries.addAll(resolveClasspath(requiredEntry, requiredProj));

                }
            } // for (int i = 0; i < requiredEntries.length; i++)

            IPath outputLocation = requiredJavaProj.getOutputLocation();
            // Output location may not exist.  Do not put output location of required project
            // on path unless it exists
            boolean exists = false;
            // bug 244330 check to see if the project folder is also the output folder
            if (outputLocation.segmentCount() == 1) {
                exists = true;
            } else {
                if (requiredProj.getWorkspace().getRoot().getFolder(outputLocation).exists()) {
                    exists = true;
                }
            }

            if (exists) {
                IClasspathEntry outFolder = JavaCore.newLibraryEntry(outputLocation, null,
                        requiredProj.getFullPath());
                actualEntries.add(outFolder);
            }
        } catch (JavaModelException e) {
        }
        return actualEntries;
    }

    /**
     * resolvedClasspath is a package protected static class inside JavaProject
     * must use reflection to access it 
     */
    @SuppressWarnings({ "unchecked" })
    private static IClasspathEntry[] extractRequiredEntries(Object resolvedClasspath) {

        try {
            Class resolvedClasspathClass = Class
                    .forName("org.eclipse.jdt.internal.core.JavaProject$ResolvedClasspath");
            return (IClasspathEntry[]) ReflectionUtils.getPrivateField(resolvedClasspathClass, "resolvedClasspath",
                    resolvedClasspath);
        } catch (Exception e) {
            return new IClasspathEntry[0];
        }
    }

    public static List<IClasspathEntry> resolveClasspathContainer(IClasspathEntry classpathContainerEntry,
            IProject thisProject) throws JavaModelException {
        IJavaProject thisJavaProject = JavaCore.create(thisProject);
        IClasspathContainer container = JavaCore.getClasspathContainer(classpathContainerEntry.getPath(),
                thisJavaProject);
        if (container != null) {
            List<IClasspathEntry> actualEntries = new ArrayList<IClasspathEntry>();
            IClasspathEntry[] containerEntries = container.getClasspathEntries();
            for (int i = 0; i < containerEntries.length; i++) {
                // projects must be resolved specially since the AspectJ doesn't understand the 
                // concept of project
                switch (containerEntries[i].getEntryKind()) {
                case IClasspathEntry.CPE_PROJECT:
                    IProject requiredProj = thisProject.getWorkspace().getRoot()
                            .getProject(containerEntries[i].getPath().makeRelative().toPortableString());
                    if (!requiredProj.getName().equals(thisProject.getName()) && requiredProj.exists()) {
                        actualEntries.addAll(resolveDependentProjectClasspath(containerEntries[i], requiredProj));
                    }
                    break;

                case IClasspathEntry.CPE_VARIABLE:
                    IClasspathEntry resolvedClasspathEntry = JavaCore
                            .getResolvedClasspathEntry(containerEntries[i]);
                    if (resolvedClasspathEntry != null) {
                        actualEntries.add(resolvedClasspathEntry);
                    }
                    break;

                case IClasspathEntry.CPE_CONTAINER:
                    // not sure if we can have this, but try anyway
                    actualEntries.addAll(resolveClasspathContainer(containerEntries[i], thisProject));
                    break;
                case IClasspathEntry.CPE_LIBRARY:
                    actualEntries.add(containerEntries[i]);
                    break;
                default:
                    // do nothing
                }
            }
            return actualEntries;
        } else {
            return Collections.emptyList();
        }
    }

    /**
     * Resolves a single classpath entry
     * @param entry the classpath entry to resolve
     * @param thisProject the java project that has this entry
     * @return the resolved list of classpath entries
     * @throws JavaModelException 
     */
    public static List<IClasspathEntry> resolveClasspath(IClasspathEntry entry, IProject thisProject)
            throws JavaModelException {
        switch (entry.getEntryKind()) {
        case IClasspathEntry.CPE_CONTAINER:
            return resolveClasspathContainer(entry, thisProject);

        case IClasspathEntry.CPE_LIBRARY:
            return Collections.singletonList(entry);

        case IClasspathEntry.CPE_PROJECT:
            IProject containedProj = thisProject.getWorkspace().getRoot()
                    .getProject(entry.getPath().makeRelative().toPortableString());
            if (!containedProj.getName().equals(thisProject.getName()) && containedProj.exists()) {
                return resolveDependentProjectClasspath(entry, containedProj);
            } else {
                return Collections.emptyList();
            }

        case IClasspathEntry.CPE_VARIABLE:
            IClasspathEntry resolvedClasspathEntry = JavaCore.getResolvedClasspathEntry(entry);
            if (resolvedClasspathEntry != null) {
                return Collections.singletonList(resolvedClasspathEntry);
            } else {
                return Collections.emptyList();
            }
        default:
            return Collections.emptyList();
        }
    }

    public static void setProjectInPath(IProject project, String path, String cKinds, String eKinds) {
        setProjectPath(project, path, cKinds, eKinds, INPATH_ATTRIBUTE);
    }

    public static void addToInPath(IProject project, IClasspathEntry entry) {
        IJavaProject jp = JavaCore.create(project);
        addAttribute(jp, entry, AspectJCorePreferences.INPATH_ATTRIBUTE);
    }

    public static void removeFromInPath(IProject project, IClasspathEntry entry) {
        IJavaProject jp = JavaCore.create(project);
        removeAttribute(jp, entry, AspectJCorePreferences.INPATH_ATTRIBUTE);
    }

    public static void addToInPath(IProject project, String jarPath, int eKind) {
        addAttribute(project, jarPath, eKind, INPATH_ATTRIBUTE);
    }

    public static boolean isOnInpath(IClasspathEntry entry) {
        IClasspathAttribute[] attributes = entry.getExtraAttributes();
        for (int j = 0; j < attributes.length; j++) {
            if (isInPathAttribute(attributes[j])) {
                return true;
            }
        }
        return false;
    }

    public static boolean isOnPath(IClasspathEntry entry, boolean aspectpath) {
        return aspectpath ? isOnAspectpath(entry) : isOnInpath(entry);
    }

    /**
      * Checks to see if an entry is already on the Inpath
      */
    public static boolean isOnInpath(IProject project, String jarPath) {
        IJavaProject jp = JavaCore.create(project);
        try {
            IClasspathEntry[] cp = jp.getRawClasspath();
            for (int i = 0; i < cp.length; i++) {
                if ((cp[i].getEntryKind() == IClasspathEntry.CPE_LIBRARY)
                        || (cp[i].getEntryKind() == IClasspathEntry.CPE_VARIABLE)
                        || (cp[i].getEntryKind() == IClasspathEntry.CPE_CONTAINER)
                        || (cp[i].getEntryKind() == IClasspathEntry.CPE_PROJECT)) {
                    IClasspathEntry resolvedClasspathEntry = JavaCore.getResolvedClasspathEntry(cp[i]);
                    if (resolvedClasspathEntry != null) {
                        String entry = resolvedClasspathEntry.getPath().toPortableString();
                        if (entry.equals(jarPath)) {
                            if (isOnInpath(cp[i])) {
                                return true;
                            }
                        }
                    }
                }
            }
        } catch (JavaModelException e) {
        }
        return false;
    }

    public static boolean isInPathAttribute(IClasspathAttribute attribute) {
        return attribute.getName().equals(AspectJCorePreferences.INPATH_ATTRIBUTE.getName());
    }

    public static void setIncrementalCompilationOptimizationsEnabled(boolean value) {
        IEclipsePreferences store = AspectJPlugin.getDefault().getPreferences();
        store.putBoolean(OPTION_IncrementalCompilationOptimizations, value);
    }

    /**
     * Searches the raw classpath for entries whose paths contain
     * the strings in putOnPath.
     * 
     * Then ensures that these classpath entries are on the aspect path
     */
    public static void augmentAspectPath(IProject project, String[] putOnAspectPath) {
        if (putOnAspectPath.length == 0) {
            // nothing to do!
            return;
        }
        IJavaProject jp = JavaCore.create(project);
        List<IClasspathEntry> toPutOnAspectPath = new ArrayList<IClasspathEntry>();
        try {
            IClasspathEntry[] cp = jp.getRawClasspath();
            for (int i = 0; i < cp.length; i++) {
                String path = cp[i].getPath().toPortableString();
                for (int j = 0; j < putOnAspectPath.length; j++) {
                    if (path.indexOf(putOnAspectPath[j]) != -1) {
                        toPutOnAspectPath.add(cp[i]);
                    }
                }
            }

            for (IClasspathEntry entry : toPutOnAspectPath) {
                if (!isOnAspectpath(entry)) {
                    addToAspectPath(project, entry);
                }
            }
        } catch (JavaModelException e) {
        }
    }

    /**
     * Checks to see if the compiler option for incremental build optimizations
     * is on or off
     * 
     * On by default
     * @return
     */
    public static boolean isIncrementalCompilationOptimizationsEnabled() {
        IEclipsePreferences store = AspectJPlugin.getDefault().getPreferences();
        return store.getBoolean(OPTION_IncrementalCompilationOptimizations, true);
    }

    private static void setProjectPath(IProject project, String path, String cKinds, String eKinds,
            IClasspathAttribute attribute) {
        IJavaProject javaProject = JavaCore.create(project);
        removeAttribute(javaProject, attribute);

        StringTokenizer pathTok = new StringTokenizer(path, File.pathSeparator);
        StringTokenizer eKindsTok = new StringTokenizer(eKinds, File.pathSeparator);
        int index = 1;
        while (pathTok.hasMoreTokens() && eKindsTok.hasMoreTokens()) {
            String entry = pathTok.nextToken();
            int eKind = Integer.parseInt(eKindsTok.nextToken());
            if (ASPECTPATH_ATTRIBUTE.equals(attribute)) {
                addToAspectPath(project, entry, eKind);
            } else if (INPATH_ATTRIBUTE.equals(attribute)) {
                addToInPath(project, entry, eKind);
            }
            index++;
        }
    }

    private static boolean shouldCheckOldStylePath(IProject project, String pathKind) {
        IScopeContext projectScope = new ProjectScope(project);
        IEclipsePreferences projectNode = projectScope.getNode(AspectJPlugin.UI_PLUGIN_ID);
        return projectNode.get(pathKind, "").length() == 0 && projectNode.get(pathKind + "1", "").length() > 0;
    }

    private static void markOldStylePathAsRead(IProject project, String pathKind) {
        IScopeContext projectScope = new ProjectScope(project);
        IEclipsePreferences projectNode = projectScope.getNode(AspectJPlugin.UI_PLUGIN_ID);
        projectNode.put(pathKind, "visited");
        try {
            projectNode.flush();
        } catch (BackingStoreException e) {
        }
    }

    private static String[] getOldProjectPath(IProject project, boolean aspectPath) {
        String pathName;
        String pathConKinds;
        String pathEntKinds;
        if (aspectPath) {
            pathName = ASPECTPATH;
            pathConKinds = ASPECTPATH_CON_KINDS;
            pathEntKinds = ASPECTPATH_ENT_KINDS;
        } else {
            pathName = INPATH;
            pathConKinds = INPATH_CON_KINDS;
            pathEntKinds = INPATH_ENT_KINDS;
        }

        IScopeContext projectScope = new ProjectScope(project);
        IEclipsePreferences projectNode = projectScope.getNode(AspectJPlugin.UI_PLUGIN_ID);
        String pathString = ""; //$NON-NLS-1$
        int index = 1;
        String value = projectNode.get(pathName + index, ""); //$NON-NLS-1$
        if (value.length() == 0) {
            return null;
        }
        while (value.length() > 0) {
            pathString += value;
            pathString += File.pathSeparator;
            index++;
            value = projectNode.get(pathName + index, ""); //$NON-NLS-1$
        }

        String contentString = ""; //$NON-NLS-1$
        index = 1;
        value = projectNode.get(pathConKinds + index, ""); //$NON-NLS-1$
        while (value.length() > 0) {
            contentString += toContentKind(value.toUpperCase());
            contentString += File.pathSeparator;
            index++;
            value = projectNode.get(pathConKinds + index, ""); //$NON-NLS-1$
        }

        String entryString = ""; //$NON-NLS-1$
        index = 1;
        value = projectNode.get(pathEntKinds + index, ""); //$NON-NLS-1$
        while (value.length() > 0) {
            entryString += toEntryKind(value.toUpperCase());
            entryString += File.pathSeparator;
            index++;
            value = projectNode.get(pathEntKinds + index, ""); //$NON-NLS-1$
        }
        return new String[] { pathString, contentString, entryString };
    }

    /**
     * Firstly, add library to the Java build path if it's not there already,
     * then mark the entry as being on the aspect path
     * @param project
     * @param path
     */
    private static void addAttribute(IProject project, String jarPath, int eKind, IClasspathAttribute attribute) {
        IJavaProject jp = JavaCore.create(project);

        try {
            IClasspathEntry[] cp = jp.getRawClasspath();
            int cpIndex = getIndexInBuildPathEntry(cp, jarPath);
            if (cpIndex >= 0) { // already on classpath
                // add attribute to classpath entry
                // if it doesn't already exist
                IClasspathEntry pathAdd = cp[cpIndex];
                // only add attribute if this element is not already on the path
                if (isAspectPathAttribute(attribute) ? !isOnAspectpath(pathAdd) : !isOnInpath(pathAdd)) {
                    IClasspathAttribute[] attributes = pathAdd.getExtraAttributes();
                    IClasspathAttribute[] newattrib = new IClasspathAttribute[attributes.length + 1];
                    System.arraycopy(attributes, 0, newattrib, 0, attributes.length);
                    newattrib[attributes.length] = attribute;
                    switch (pathAdd.getEntryKind()) {
                    case IClasspathEntry.CPE_LIBRARY:
                        pathAdd = JavaCore.newLibraryEntry(pathAdd.getPath(), pathAdd.getSourceAttachmentPath(),
                                pathAdd.getSourceAttachmentRootPath(), pathAdd.getAccessRules(), newattrib,
                                pathAdd.isExported());
                        break;

                    case IClasspathEntry.CPE_VARIABLE:
                        pathAdd = JavaCore.newVariableEntry(pathAdd.getPath(), pathAdd.getSourceAttachmentPath(),
                                pathAdd.getSourceAttachmentRootPath(), pathAdd.getAccessRules(), newattrib,
                                pathAdd.isExported());
                        break;

                    case IClasspathEntry.CPE_CONTAINER:
                        pathAdd = JavaCore.newContainerEntry(pathAdd.getPath(), pathAdd.getAccessRules(), newattrib,
                                pathAdd.isExported());
                        break;

                    case IClasspathEntry.CPE_PROJECT:
                        pathAdd = JavaCore.newProjectEntry(pathAdd.getPath(), pathAdd.getAccessRules(), true,
                                newattrib, pathAdd.isExported());
                        break;
                    }

                    cp[cpIndex] = pathAdd;
                    jp.setRawClasspath(cp, null);
                }
            } else {
                addEntryToJavaBuildPath(jp, attribute, jarPath, eKind);
            }
        } catch (JavaModelException e) {
        }
    }

    private static String[] internalGetProjectPath(IProject project, IClasspathAttribute attribute,
            boolean useResolvedPath) {
        if (isAspectPathAttribute(attribute)) {
            if (shouldCheckOldStylePath(project, ASPECTPATH)) {
                String[] old = getOldProjectPath(project, true);
                if (old != null) {
                    AJLog.log("Migrating aspect path settings for project " + project.getName()); //$NON-NLS-1$
                    setProjectAspectPath(project, old[0], old[1], old[2]);
                }
                markOldStylePathAsRead(project, ASPECTPATH);
            }
        } else { // INPATH_ATTRIBUTE
            if (shouldCheckOldStylePath(project, INPATH)) {
                String[] old = getOldProjectPath(project, false);
                if (old != null) {
                    AJLog.log("Migrating aspect path settings for project " + project.getName()); //$NON-NLS-1$
                    setProjectInPath(project, old[0], old[1], old[2]);
                }
                markOldStylePathAsRead(project, INPATH);
            }
        }
        String pathString = ""; //$NON-NLS-1$
        String contentString = ""; //$NON-NLS-1$
        String entryString = ""; //$NON-NLS-1$

        IJavaProject javaProject = JavaCore.create(project);
        try {
            IClasspathEntry[] cp = javaProject.getRawClasspath();
            for (int i = 0; i < cp.length; i++) {
                IClasspathAttribute[] attributes = cp[i].getExtraAttributes();
                boolean attributeFound = false;
                for (int j = 0; j < attributes.length; j++) {
                    if (attributes[j].getName().equals(attribute.getName())) {
                        attributeFound = true;
                        List<IClasspathEntry> actualEntries = new ArrayList<IClasspathEntry>();

                        if (useResolvedPath) {
                            // this entry is on the path.  must resolve it
                            if (cp[i].getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
                                List<IClasspathEntry> containerEntries = resolveClasspathContainer(cp[i], project);
                                // Bug 273770 - look for the XXXPATH_RESTRICTION_ATTRIBUTE_NAME classpath attribute
                                Set<String> extraPathElements = findContainerRestrictions(cp[i],
                                        isAspectPathAttribute(attribute));
                                if (extraPathElements != null && extraPathElements.size() > 0) {
                                    // must filter
                                    for (Iterator<IClasspathEntry> cpIter = containerEntries.iterator(); cpIter
                                            .hasNext();) {
                                        IClasspathEntry containerEntry = cpIter.next();
                                        if (!containsAsPathFragment(extraPathElements, containerEntry)) {
                                            cpIter.remove();
                                        }
                                    }
                                }
                                actualEntries.addAll(containerEntries);
                            } else if (cp[i].getEntryKind() == IClasspathEntry.CPE_PROJECT) {
                                IProject requiredProj = project.getWorkspace().getRoot()
                                        .getProject(cp[i].getPath().makeRelative().toPortableString());
                                if (!requiredProj.getName().equals(project.getName()) && requiredProj.exists()) {
                                    actualEntries.addAll(resolveDependentProjectClasspath(cp[i], requiredProj));
                                }
                            } else { // resolve the classpath variable
                                IClasspathEntry resolved = JavaCore.getResolvedClasspathEntry(cp[i]);
                                if (resolved != null) {
                                    if (resolved.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
                                        // must resolve the project
                                        actualEntries.addAll(
                                                resolveDependentProjectClasspath(resolved, project.getWorkspace()
                                                        .getRoot().getProject(resolved.getPath().toString())));
                                    } else {
                                        actualEntries.add(resolved);
                                    }
                                }
                            } // cp[i].getEntryKind()
                        } else {
                            actualEntries.add(cp[i]);
                        } // useResolvedEntry

                        for (IClasspathEntry actualEntry : actualEntries) {
                            // we can get null for actualEntry if the raw entry corresponds to 
                            // an unbound classpath variable
                            if (actualEntry != null) {
                                pathString += actualEntry.getPath().toPortableString() + File.pathSeparator;
                                contentString += actualEntry.getContentKind() + File.pathSeparator;
                                entryString += actualEntry.getEntryKind() + File.pathSeparator;
                            }
                        }
                    } // attributes[j].equals(attribute)
                } // for (int j = 0; j < attributes.length; j++)

                // there is a special case that we must look inside the classpath container for entries with
                // attributes if we are returning the resolved path and the container itself isn't already
                // on the path.
                if (!attributeFound && useResolvedPath && cp[i].getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
                    List<IClasspathEntry> containerEntries = resolveClasspathContainer(cp[i], project);

                    for (IClasspathEntry containerEntry : containerEntries) {
                        if (isOnPath(containerEntry, isAspectPathAttribute(attribute))) {
                            pathString += containerEntry.getPath().toPortableString() + File.pathSeparator;
                            contentString += containerEntry.getContentKind() + File.pathSeparator;
                            entryString += containerEntry.getEntryKind() + File.pathSeparator;
                        }
                    } // for (Iterator cpIter = containerEntries.iterator(); cpIter.hasNext(); ) 
                } // !attributeFound && useResolvedPath && cp[i].getEntryKind() == IClasspathEntry.CPE_CONTAINER
            } // for (int i = 0; i < cp.length; i++)
        } catch (JavaModelException e) {
        }
        return new String[] { pathString, contentString, entryString };
    }

    public static boolean containsAsPathFragment(Set<String> extraPathElements, IClasspathEntry containerEntry) {
        if (extraPathElements.size() == 0) {
            return false;
        }
        String pathStr = containerEntry.getPath().toString();
        for (String extraPathStr : extraPathElements) {
            if (pathStr.indexOf(extraPathStr) != -1) {
                return true;
            }
        }
        return false;
    }

    private static Set<String> findContainerRestrictions(IClasspathEntry containerEntry,
            boolean isAspectPathAttribute) {
        if (containerEntry.getEntryKind() != IClasspathEntry.CPE_CONTAINER) {
            return Collections.emptySet();
        }
        Set<String> restrictionPaths = new HashSet<String>();
        String restrictions = getRestriction(containerEntry,
                isAspectPathAttribute ? ASPECTPATH_RESTRICTION_ATTRIBUTE_NAME : INPATH_RESTRICTION_ATTRIBUTE_NAME);
        if (restrictions != null) {
            String[] restrictionsArr = restrictions.split(",");
            for (int j = 0; j < restrictionsArr.length; j++) {
                restrictionPaths.add(restrictionsArr[j].trim());
            }
            return restrictionPaths;
        } else {
            return null;
        }
    }

    private static void addAttribute(IJavaProject jp, IClasspathEntry entry, IClasspathAttribute attr) {
        try {
            IClasspathEntry[] cp = jp.getRawClasspath();
            for (int i = 0; i < cp.length; i++) {
                if (cp[i].equals(entry)) {
                    IClasspathAttribute[] attributes = cp[i].getExtraAttributes();
                    IClasspathAttribute[] newattrib = new IClasspathAttribute[attributes.length + 1];
                    System.arraycopy(attributes, 0, newattrib, 0, attributes.length);
                    newattrib[attributes.length] = attr;
                    switch (cp[i].getEntryKind()) {
                    case IClasspathEntry.CPE_LIBRARY:
                        cp[i] = JavaCore.newLibraryEntry(cp[i].getPath(), cp[i].getSourceAttachmentPath(),
                                cp[i].getSourceAttachmentRootPath(), cp[i].getAccessRules(), newattrib,
                                cp[i].isExported());
                        break;

                    case IClasspathEntry.CPE_VARIABLE:
                        cp[i] = JavaCore.newVariableEntry(cp[i].getPath(), cp[i].getSourceAttachmentPath(),
                                cp[i].getSourceAttachmentRootPath(), cp[i].getAccessRules(), newattrib,
                                cp[i].isExported());
                        break;

                    case IClasspathEntry.CPE_CONTAINER:
                        cp[i] = JavaCore.newContainerEntry(cp[i].getPath(), cp[i].getAccessRules(), newattrib,
                                cp[i].isExported());
                        break;

                    case IClasspathEntry.CPE_PROJECT:
                        cp[i] = JavaCore.newProjectEntry(cp[i].getPath(), cp[i].getAccessRules(), true, newattrib,
                                cp[i].isExported());
                        break;

                    }
                }
            }
            jp.setRawClasspath(cp, null);
        } catch (JavaModelException e) {
        }
    }

    public static void removeAttribute(IJavaProject jp, IClasspathEntry entry, IClasspathAttribute attr) {
        try {
            IClasspathEntry[] cp = jp.getRawClasspath();
            for (int i = 0; i < cp.length; i++) {
                if (cp[i].equals(entry)) {
                    IClasspathAttribute[] attributes = cp[i].getExtraAttributes();
                    IClasspathAttribute[] newattrib = new IClasspathAttribute[attributes.length - 1];
                    int count = 0;
                    for (int j = 0; j < attributes.length; j++) {
                        if (!attributes[j].getName().equals(attr.getName())) {
                            newattrib[count++] = attributes[j];
                        }
                    }
                    switch (cp[i].getEntryKind()) {
                    case IClasspathEntry.CPE_LIBRARY:
                        cp[i] = JavaCore.newLibraryEntry(cp[i].getPath(), cp[i].getSourceAttachmentPath(),
                                cp[i].getSourceAttachmentRootPath(), cp[i].getAccessRules(), newattrib,
                                cp[i].isExported());
                        break;

                    case IClasspathEntry.CPE_VARIABLE:
                        cp[i] = JavaCore.newVariableEntry(cp[i].getPath(), cp[i].getSourceAttachmentPath(),
                                cp[i].getSourceAttachmentRootPath(), cp[i].getAccessRules(), newattrib,
                                cp[i].isExported());
                        break;

                    case IClasspathEntry.CPE_CONTAINER:
                        cp[i] = JavaCore.newContainerEntry(cp[i].getPath(), cp[i].getAccessRules(), newattrib,
                                cp[i].isExported());
                        break;

                    case IClasspathEntry.CPE_PROJECT:
                        cp[i] = JavaCore.newProjectEntry(cp[i].getPath(), cp[i].getAccessRules(), true, newattrib,
                                cp[i].isExported());
                        break;
                    }
                }
            }
            jp.setRawClasspath(cp, null);
        } catch (JavaModelException e) {
        }
    }

    /**
    * Remove all occurrences of an attribute
    * @param javaProject
    * @param attribute
    */
    private static void removeAttribute(IJavaProject javaProject, IClasspathAttribute attribute) {
        try {
            IClasspathEntry[] cp = javaProject.getRawClasspath();
            boolean changed = false;
            for (int i = 0; i < cp.length; i++) {
                IClasspathAttribute[] attributes = cp[i].getExtraAttributes();
                boolean found = false;
                for (int j = 0; !found && (j < attributes.length); j++) {
                    if (attributes[j].getName().equals(attribute.getName())) {
                        found = true;
                    }
                }
                if (found) {
                    changed = true;
                    IClasspathAttribute[] newattrib = new IClasspathAttribute[attributes.length - 1];
                    int count = 0;
                    for (int j = 0; j < attributes.length; j++) {
                        if (!attributes[j].getName().equals(attribute.getName())) {
                            newattrib[count++] = attributes[j];
                        }
                    }
                    switch (cp[i].getEntryKind()) {
                    case IClasspathEntry.CPE_LIBRARY:
                        cp[i] = JavaCore.newLibraryEntry(cp[i].getPath(), cp[i].getSourceAttachmentPath(),
                                cp[i].getSourceAttachmentRootPath(), cp[i].getAccessRules(), newattrib,
                                cp[i].isExported());
                        break;

                    case IClasspathEntry.CPE_VARIABLE:
                        cp[i] = JavaCore.newVariableEntry(cp[i].getPath(), cp[i].getSourceAttachmentPath(),
                                cp[i].getSourceAttachmentRootPath(), cp[i].getAccessRules(), newattrib,
                                cp[i].isExported());
                        break;

                    case IClasspathEntry.CPE_CONTAINER:
                        cp[i] = JavaCore.newContainerEntry(cp[i].getPath(), cp[i].getAccessRules(), newattrib,
                                cp[i].isExported());
                        break;

                    case IClasspathEntry.CPE_PROJECT:
                        cp[i] = JavaCore.newProjectEntry(cp[i].getPath(), cp[i].getAccessRules(), true, newattrib,
                                cp[i].isExported());
                        break;
                    }
                }
            }
            if (changed) {
                javaProject.setRawClasspath(cp, null);
            }
        } catch (JavaModelException e) {
        }
    }

    private static int getIndexInBuildPathEntry(IClasspathEntry[] cp, String jarPath) {
        for (int i = 0; i < cp.length; i++) {
            String entry = cp[i].getPath().toPortableString();
            if (entry.equals(jarPath)) {
                return i;
            }
        }
        return -1;
    }

    private static void addEntryToJavaBuildPath(IJavaProject jp, IClasspathAttribute attribute, String path,
            int eKind) {
        IClasspathAttribute[] attributes = new IClasspathAttribute[] { attribute };
        try {
            IClasspathEntry[] originalCP = jp.getRawClasspath();
            IClasspathEntry[] newCP = new IClasspathEntry[originalCP.length + 1];
            IClasspathEntry cp = null;
            if (eKind == IClasspathEntry.CPE_LIBRARY) {
                cp = JavaCore.newLibraryEntry(new Path(path), null, null, new IAccessRule[0], attributes, false);
            } else if (eKind == IClasspathEntry.CPE_VARIABLE) {
                cp = JavaCore.newVariableEntry(new Path(path), null, null, new IAccessRule[0], attributes, false);
            } else if (eKind == IClasspathEntry.CPE_CONTAINER) {
                cp = JavaCore.newContainerEntry(new Path(path), null, attributes, false);
            } else if (eKind == IClasspathEntry.CPE_PROJECT) {
                cp = JavaCore.newProjectEntry(new Path(path), null, true, attributes, false);
            }

            // Update the raw classpath with the new entry.
            if (cp != null) {
                System.arraycopy(originalCP, 0, newCP, 0, originalCP.length);
                newCP[originalCP.length] = cp;
                jp.setRawClasspath(newCP, new NullProgressMonitor());
            }
        } catch (JavaModelException e) {
        } catch (NumberFormatException e) {
        }
    }

    private static String toContentKind(String contentStr) {
        int content = 0;
        if (contentStr.equals("SOURCE")) { //$NON-NLS-1$
            content = IPackageFragmentRoot.K_SOURCE;
        } else if (contentStr.equals("BINARY")) { //$NON-NLS-1$
            content = IPackageFragmentRoot.K_BINARY;
        }
        return new Integer(content).toString();
    }

    private static String toEntryKind(String entryStr) {
        int entry = 0;
        if (entryStr.equals("SOURCE")) { //$NON-NLS-1$
            entry = IClasspathEntry.CPE_SOURCE;
        } else if (entryStr.equals("LIBRARY")) { //$NON-NLS-1$
            entry = IClasspathEntry.CPE_LIBRARY;
        } else if (entryStr.equals("PROJECT")) { //$NON-NLS-1$
            entry = IClasspathEntry.CPE_PROJECT;
        } else if (entryStr.equals("VARIABLE")) { //$NON-NLS-1$
            entry = IClasspathEntry.CPE_VARIABLE;
        } else if (entryStr.equals("CONTAINER")) { //$NON-NLS-1$
            entry = IClasspathEntry.CPE_CONTAINER;
        }
        return new Integer(entry).toString();
    }

    public static String getRestriction(IClasspathEntry pathEntry, String attributeName) {
        IClasspathAttribute[] attributes = pathEntry.getExtraAttributes();
        for (int i = 0; i < attributes.length; i++) {
            IClasspathAttribute attribute = attributes[i];
            if (attribute.getName().equals(attributeName)) {
                String extraStr = attribute.getValue();
                if (extraStr != null) {
                    return extraStr;
                }
            }
        }

        return null;
    }

    /**
     * adds the classpath attribute to the entry with the default value if it doesn't already exist
     * else does nothing
     */
    public static IClasspathEntry ensureHasAttribute(IClasspathEntry curr, String attributeName,
            String defaultVal) {
        int index = indexOfAttribute(curr.getExtraAttributes(), attributeName);
        if (index < 0) {
            IClasspathAttribute[] attrs = curr.getExtraAttributes();
            // must create a new entry with more extra attributes
            IClasspathAttribute newAttr = JavaCore.newClasspathAttribute(attributeName, defaultVal);
            IClasspathAttribute[] newAttrs;
            if (attrs == null || attrs.length == 0) {
                newAttrs = new IClasspathAttribute[] { newAttr };
            } else {
                newAttrs = new IClasspathAttribute[attrs.length + 1];
                System.arraycopy(attrs, 0, newAttrs, 0, attrs.length);
                newAttrs[attrs.length] = newAttr;
            }
            return copyContainerEntry(curr, newAttrs);
        } else {
            return curr;
        }
    }

    /**
     * adds the classpath attribute to the entry with the default value if it doesn't already exist
     * else does nothing
     */
    public static IClasspathEntry ensureHasNoAttribute(IClasspathEntry curr, String attributeName) {
        int index = indexOfAttribute(curr.getExtraAttributes(), attributeName);
        if (index < 0) {
            return curr;
        } else {
            IClasspathAttribute[] attrs = curr.getExtraAttributes();
            // must create a new entry with more extra attributes
            IClasspathAttribute[] newAttrs = new IClasspathAttribute[attrs.length - 1];
            for (int i = 0, j = 0; i < newAttrs.length; i++) {
                if (i != index) {
                    newAttrs[j] = attrs[i];
                    j++;
                }
            }
            return copyContainerEntry(curr, newAttrs);
        }
    }

    public static IClasspathEntry copyContainerEntry(IClasspathEntry containerEntry,
            IClasspathAttribute[] extraAttrs) {
        return JavaCore.newContainerEntry(containerEntry.getPath(), containerEntry.getAccessRules(), extraAttrs,
                containerEntry.isExported());
    }

    private static int indexOfAttribute(IClasspathAttribute[] attrs, String attrName) {
        for (int i = 0; i < attrs.length; i++) {
            if (attrs[i].getName().equals(attrName)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * Adds the classpath restriction to the given classpath entry.
     * Returns the new classpath entry
     */
    public static IClasspathEntry updatePathRestrictions(IClasspathEntry entry, String restrictionStr,
            String restrictionKind) {
        IClasspathAttribute[] attrs = entry.getExtraAttributes();
        int index = indexOfAttribute(attrs, restrictionKind);
        IClasspathAttribute newAttr = JavaCore.newClasspathAttribute(restrictionKind, restrictionStr);
        if (index >= 0) {
            // just replace
            attrs[index] = newAttr;
        } else {
            // must create a new entry with more extra attributes
            IClasspathAttribute[] newAttrs;
            if (attrs == null || attrs.length == 0) {
                newAttrs = new IClasspathAttribute[] { newAttr };
            } else {
                newAttrs = new IClasspathAttribute[attrs.length + 1];
                System.arraycopy(attrs, 0, newAttrs, 0, attrs.length);
                newAttrs[attrs.length] = newAttr;
            }
            entry = copyContainerEntry(entry, newAttrs);
        }
        return entry;
    }

    /**
     * If this classpath entry's path already exists on the classpath, then it is replaced
     * else it is added
     */
    public static void updateClasspathEntry(IProject project, IClasspathEntry newEntry) {
        IJavaProject jProject = JavaCore.create(project);
        try {
            IClasspathEntry[] entries = jProject.getRawClasspath();
            for (int i = 0; i < entries.length; i++) {
                IClasspathEntry entry = entries[i];
                if (newEntry.getPath().equals(entry.getPath())) {
                    entries[i] = newEntry;
                    jProject.setRawClasspath(entries, null);
                    return;
                }
            }

            // entry not found on classpath...add it
            IClasspathEntry[] newEntries = new IClasspathEntry[entries.length + 1];
            System.arraycopy(entries, 0, newEntries, 0, entries.length);
            newEntries[entries.length] = newEntry;
            jProject.setRawClasspath(newEntries, null);
        } catch (JavaModelException e) {
        }
    }
}