org.eclipse.jst.j2ee.classpathdep.ClasspathDependencyUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jst.j2ee.classpathdep.ClasspathDependencyUtil.java

Source

/*******************************************************************************
 * Copyright (c) 2007-2013 BEA Systems, Inc. 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:
 * BEA Systems, Inc. - initial API and implementation
 * Fred Bricon (Red Hat, Inc.) - 359385 : override classpath entry's archive name 
 *******************************************************************************/
package org.eclipse.jst.j2ee.classpathdep;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.util.URI;
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.jst.common.internal.modulecore.IClasspathDependencyComponent;
import org.eclipse.jst.common.jdt.internal.javalite.IJavaProjectLite;
import org.eclipse.jst.common.jdt.internal.javalite.JavaCoreLite;
import org.eclipse.jst.j2ee.componentcore.J2EEModuleVirtualComponent;
import org.eclipse.jst.j2ee.internal.J2EEVersionConstants;
import org.eclipse.jst.j2ee.internal.classpathdep.ClasspathDependencyValidator;
import org.eclipse.jst.j2ee.internal.classpathdep.ClasspathDependencyVirtualComponent;
import org.eclipse.jst.j2ee.internal.classpathdep.ClasspathDependencyValidator.ClasspathDependencyValidatorData;
import org.eclipse.jst.j2ee.model.ModelProviderManager;
import org.eclipse.jst.j2ee.project.EarUtilities;
import org.eclipse.jst.j2ee.project.JavaEEProjectUtilities;
import org.eclipse.jst.javaee.application.Application;
import org.eclipse.wst.common.componentcore.ComponentCore;
import org.eclipse.wst.common.componentcore.internal.impl.ModuleURIUtil;
import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
import org.eclipse.wst.common.componentcore.resources.IVirtualReference;
import org.eclipse.wst.validation.internal.provisional.core.IMessage;

/**
 * Contains utility code for working manipulating the WTP classpath component
 * dependency attribute.
 */
public class ClasspathDependencyUtil implements IClasspathDependencyConstants {

    /**
     * This is equivalent to calling getRawComponentClasspathDependencies(javaProject, DependencyAttributeType.CLASSPATH_COMPONENT_DEPENDENCY);
     * 
     * @deprecated use {@link #getRawComponentClasspathDependencies(IJavaProject, org.eclipse.jst.j2ee.classpathdep.IClasspathDependencyConstants.DependencyAttributeType)}
     * 
     * @param javaProject
     * @return
     * @throws CoreException
     */
    @Deprecated
    public static Map<IClasspathEntry, IClasspathAttribute> getRawComponentClasspathDependencies(
            final IJavaProject javaProject) throws CoreException {
        return getRawComponentClasspathDependencies(javaProject,
                DependencyAttributeType.CLASSPATH_COMPONENT_DEPENDENCY);
    }

    /**
     * @deprecated use {@link #getRawComponentClasspathDependencies(IJavaProjectLite, org.eclipse.jst.j2ee.classpathdep.IClasspathDependencyConstants.DependencyAttributeType)}
     * @param javaProject
     * @param attributeType
     * @return
     * @throws CoreException
     */
    @Deprecated
    public static Map<IClasspathEntry, IClasspathAttribute> getRawComponentClasspathDependencies(
            final IJavaProject javaProject, DependencyAttributeType attributeType) throws CoreException {
        return getRawComponentClasspathDependencies(JavaCoreLite.create(javaProject), attributeType);
    }

    /**
     * Returns all unresolved classpath entries for the specified Java project that
     * have the special WTP classpath component dependency attribute.
     *  
     * @param javaProjectLite Java project whose component classpath dependencies are being retrieved.
     * @parem attributeType the attribute to search for
     * @return Map from IClasspathEntry to IClasspathAttribute for classpath component dependency.
     * @return IClasspathEntries with the special component dependency attribute.
     * @throws CoreException Thrown if an error is encountered accessing the unresolved classpath.
     */
    public static Map<IClasspathEntry, IClasspathAttribute> getRawComponentClasspathDependencies(
            final IJavaProjectLite javaProjectLite, DependencyAttributeType attributeType) throws CoreException {
        return getRawComponentClasspathDependencies(javaProjectLite, attributeType, false);
    }

    public static Map<IClasspathEntry, IClasspathAttribute> getRawComponentClasspathDependencies(
            final IJavaProjectLite javaProjectLite, DependencyAttributeType attributeType,
            final boolean isLegacyJ2EE) throws CoreException {
        if (javaProjectLite == null) {
            return Collections.emptyMap();
        }
        final Map<IClasspathEntry, IClasspathAttribute> referencedRawEntries = new HashMap<IClasspathEntry, IClasspathAttribute>();
        final IClasspathEntry[] entries = javaProjectLite.readRawClasspath();
        for (IClasspathEntry entry : entries) {
            final IClasspathAttribute attrib = checkForComponentDependencyAttribute(entry, attributeType,
                    isLegacyJ2EE);
            if (attrib != null) {
                referencedRawEntries.put(entry, attrib);
            }
        }
        return referencedRawEntries;
    }

    /**
     * @deprecated use {@link #getPotentialComponentClasspathDependencies(IJavaProjectLite)}
     * @param javaProject
     * @return
     * @throws CoreException
     */
    @Deprecated
    public static List<IClasspathEntry> getPotentialComponentClasspathDependencies(final IJavaProject javaProject)
            throws CoreException {
        return getPotentialComponentClasspathDependencies(JavaCoreLite.create(javaProject));
    }

    /**
     * Retrieves the unresolved classpath entries for the specified Java project that
     * could potentially be mapped into the virtual component tree for the project via
     * the special WTP classpath component dependence attribute. Classpath entries that
     * currently have the attribute are not returned by this method (@see {@link #getRawComponentClasspathDependencies(IJavaProject, boolean)})
     * 
     * @param javaProjectLite Java project whose potential component classpath dependencies will be retrieved.
     * @return List of raw IClasspathEntries for potential classpath component dependencies.
     * @throws CoreException Thrown if an error is encountered. 
     */
    public static List<IClasspathEntry> getPotentialComponentClasspathDependencies(
            final IJavaProjectLite javaProjectLite) throws CoreException {
        return getPotentialComponentClasspathDependencies(javaProjectLite, false);
    }

    public static List<IClasspathEntry> getPotentialComponentClasspathDependencies(
            final IJavaProjectLite javaProjectLite, final boolean isLegacyJ2EE) throws CoreException {

        final List<IClasspathEntry> potentialRawEntries = new ArrayList<IClasspathEntry>();

        if (javaProjectLite == null || !javaProjectLite.getProject().isAccessible()) {
            return Collections.emptyList();
        }
        final IProject project = javaProjectLite.getProject();
        final boolean isWebApp = JavaEEProjectUtilities.isDynamicWebProject(project);
        final boolean isRAR = JavaEEProjectUtilities.isJCAProject(project);
        final ClasspathDependencyValidatorData data = new ClasspathDependencyValidatorData(project);
        final IClasspathEntry[] entries = javaProjectLite.readRawClasspath();
        for (int i = 0; i < entries.length; i++) {
            final IClasspathEntry entry = entries[i];
            final IClasspathAttribute attrib = checkForComponentDependencyAttribute(entry,
                    DependencyAttributeType.DEPENDENCY_OR_NONDEPENDENCY, isLegacyJ2EE);
            if (attrib != null) {
                continue; // already has the attribute
            }
            // check validation logic for entry
            // always mark the "isWebApp" param as true so that we get both exported and non-exported entries; for non-web projects,
            // want to let a user have the option to see and select the non-exported entries and then just generate a validation
            // error if they happen to select one.
            final IMessage[] msgs = ClasspathDependencyValidator.validateVirtualComponentEntry(entry, null, true,
                    project, data);
            boolean error = false;
            for (int j = 0; j < msgs.length; j++) {
                if (msgs[j].getSeverity() == IMessage.HIGH_SEVERITY) {
                    error = true;
                    break;
                }
            }
            if (error) {
                continue;
            }
            if (IClasspathEntry.CPE_LIBRARY == entry.getEntryKind()) {
                final boolean isFile = !ClasspathDependencyUtil.isClassFolderEntry(entry);
                if (isFile) {
                    boolean foundEntry = false;
                    IVirtualComponent component = ComponentCore.createComponent(project);
                    if (isWebApp) { // checks for web libs
                        IContainer[] webLibFolders = component.getRootFolder().getFolder(WEB_INF_LIB_PATH)
                                .getUnderlyingFolders();
                        for (IContainer webLib : webLibFolders) {
                            IPath webLibFolderPath = webLib.getFullPath();
                            if (webLibFolderPath.equals(entry.getPath().removeLastSegments(1))) {
                                foundEntry = true;
                                break;
                            }
                        }
                    } else if (isRAR) {
                        IContainer[] rootFolders = component.getRootFolder().getUnderlyingFolders();
                        for (IContainer root : rootFolders) {
                            IPath rootPath = root.getFullPath();
                            if (rootPath.isPrefixOf(entry.getPath())) {
                                foundEntry = true;
                                break;
                            }
                        }
                    }
                    if (foundEntry) {
                        continue;
                    }
                    // checks for manifest references
                    List manifestRefs = J2EEModuleVirtualComponent.getManifestReferences(component, null);
                    if (manifestRefs != null) {
                        for (int j = 0; j < manifestRefs.size(); j++) {
                            IVirtualReference ref = (IVirtualReference) manifestRefs.get(j);
                            IVirtualComponent c = ref.getReferencedComponent();
                            if (c.isBinary()) {
                                IFile file = (IFile) c.getAdapter(IFile.class);
                                if (file != null && file.getFullPath().equals(entry.getPath())) {
                                    foundEntry = true;
                                    break;
                                }
                            }
                        }
                        if (foundEntry) {
                            continue;
                        }
                    }
                    // checks for ear library-directory entries
                    IProject[] earProjects = EarUtilities.getReferencingEARProjects(project);
                    for (IProject earProject : earProjects) {
                        String earDDVersion = EarUtilities.getJ2EEDDProjectVersion(earProject);
                        if (!earDDVersion.equals(J2EEVersionConstants.VERSION_1_2_TEXT)
                                && !earDDVersion.equals(J2EEVersionConstants.VERSION_1_3_TEXT)
                                && !earDDVersion.equals(J2EEVersionConstants.VERSION_1_4_TEXT)) {
                            IVirtualComponent earComponent = ComponentCore.createComponent(earProject);
                            Application app = (Application) ModelProviderManager.getModelProvider(earComponent)
                                    .getModelObject();
                            String libDir = app.getLibraryDirectory();
                            if (libDir == null) {
                                // lib is the default if no library-directory is set
                                libDir = "lib"; //$NON-NLS-1$
                            }
                            IContainer[] earLibFolders = earComponent.getRootFolder().getFolder(new Path(libDir))
                                    .getUnderlyingFolders();
                            for (IContainer earLib : earLibFolders) {
                                IPath earLibFolderPath = earLib.getFullPath();
                                if (earLibFolderPath.equals(entry.getPath().removeLastSegments(1))) {
                                    foundEntry = true;
                                    break;
                                }
                            }
                            if (foundEntry) {
                                break;
                            }
                        }
                    }
                    if (foundEntry) {
                        continue;
                    }
                }
            }

            // entry can potentially be tagged as a component dependency
            potentialRawEntries.add(entry);
        }
        return potentialRawEntries;
    }

    private static boolean isValid(final IClasspathEntry entry, final IClasspathAttribute attrib,
            final boolean isWebApp, final IProject project, final ClasspathDependencyValidatorData data) {
        final IMessage[] msgs = ClasspathDependencyValidator.validateVirtualComponentEntry(entry, attrib, isWebApp,
                project, data);
        boolean valid = true;
        for (int j = 0; j < msgs.length; j++) {
            if (msgs[j].getSeverity() == IMessage.HIGH_SEVERITY) {
                valid = false;
                break;
            }
        }
        return valid;
    }

    /**
     * Returns all resolved classpath entries for the specified Java project that
     * have one of the special WTP classpath component dependency attributes and pass the set of rules
     * that govern valid classpath dependencies.
     *  
     * @param javaProject Java project whose component classpath dependencies are being retrieved.
     * @param isWebApp True if the target project is associated with a web project.
     * @return Map from IClasspathEntry to IClasspathAttribute for classpath component dependencies.
     * @throws CoreException Thrown if an error is encountered accessing the unresolved classpath.
     */
    public static Map<IClasspathEntry, IClasspathAttribute> getComponentClasspathDependencies(
            final IJavaProjectLite javaProjectLite, final boolean isLegacyJ2EE) throws CoreException {
        return getComponentClasspathDependencies(javaProjectLite, isLegacyJ2EE, true);
    }

    /**
     * @deprecated use {@link #getComponentClasspathDependencies(IJavaProjectLite, boolean)}
     * @param javaProject
     * @param isWebApp
     * @return
     * @throws CoreException
     */
    @Deprecated
    public static Map<IClasspathEntry, IClasspathAttribute> getComponentClasspathDependencies(
            final IJavaProject javaProject, final boolean isLegacyJ2EE) throws CoreException {
        return getComponentClasspathDependencies(JavaCoreLite.create(javaProject), isLegacyJ2EE);
    }

    /**
     * @deprecated use {@link #getComponentClasspathDependencies(IJavaProjectLite, boolean, boolean)}
     * @param javaProject
     * @param isWebApp
     * @param onlyValid
     * @return
     * @throws CoreException
     */
    @Deprecated
    public static Map<IClasspathEntry, IClasspathAttribute> getComponentClasspathDependencies(
            final IJavaProject javaProject, final boolean isWebApp, final boolean onlyValid) throws CoreException {
        return getComponentClasspathDependencies(JavaCoreLite.create(javaProject), isWebApp, onlyValid);
    }

    /**
     * Returns all resolved classpath entries for the specified Java project that
     * have one of the special WTP classpath component dependency attributes.
     *  
     * @param javaProject Java project whose component classpath dependencies are being retrieved.
     * @param isWebApp True if the target project is associated with a web project.
     * @param onlyValid If true, only valid dependencies will be returned. If false, the raw entry must be valid but the
     * resolved can be invalid. 
     * @return Map from IClasspathEntry to IClasspathAttribute for classpath component dependencies.
     * @throws CoreException Thrown if an error is encountered accessing the unresolved classpath.
     */
    public static Map<IClasspathEntry, IClasspathAttribute> getComponentClasspathDependencies(
            final IJavaProjectLite javaProjectLite, final boolean isLegacyJ2EE, final boolean onlyValid)
            throws CoreException {
        final ClasspathDependencyValidatorData data = new ClasspathDependencyValidatorData(
                javaProjectLite.getProject());
        final boolean isWebApp = JavaEEProjectUtilities.isDynamicWebProject(javaProjectLite.getProject());
        // get the raw entries
        final Map<IClasspathEntry, IClasspathAttribute> referencedRawEntries = getRawComponentClasspathDependencies(
                javaProjectLite, DependencyAttributeType.CLASSPATH_COMPONENT_DEPENDENCY, isLegacyJ2EE);
        final Map<IClasspathEntry, IClasspathAttribute> validRawEntries = new HashMap<IClasspathEntry, IClasspathAttribute>();
        final Map<IClasspathEntry, IClasspathAttribute> validRawClassPathContainerEntries = new HashMap<IClasspathEntry, IClasspathAttribute>();

        // filter out non-valid referenced raw entries
        final Iterator<IClasspathEntry> i = referencedRawEntries.keySet().iterator();
        while (i.hasNext()) {
            final IClasspathEntry entry = i.next();
            final IClasspathAttribute attrib = referencedRawEntries.get(entry);
            if (isValid(entry, attrib, isWebApp, javaProjectLite.getProject(), data)) {
                if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
                    //Put in a separate map the classpath container entries, since they will be handled differently
                    validRawClassPathContainerEntries.put(entry, attrib);
                } else {
                    validRawEntries.put(entry, attrib);
                }
            }
        }

        // if we have no valid raw entries, return empty map
        if (validRawEntries.isEmpty() && validRawClassPathContainerEntries.isEmpty()) {
            return Collections.emptyMap();
        }

        // XXX Would like to replace the code below with use of a public JDT API that returns
        // the raw IClasspathEntry for a given resolved IClasspathEntry (see see https://bugs.eclipse.org/bugs/show_bug.cgi?id=183995)
        // The code must currently leverage IPackageFragmentRoot to determine this
        // mapping and, because IPackageFragmentRoots do not maintain IClasspathEntry data, a prior
        // call is needed to getResolvedClasspath() and the resolved IClasspathEntries have to be stored in a Map from IPath-to-IClasspathEntry to
        // support retrieval using the resolved IPackageFragmentRoot

        // retrieve the resolved classpath
        //TODO this call to javaProject needs to be removed.  Need to figure out what exactly this is attempting to do.
        IJavaProject javaProject = JavaCore.create(javaProjectLite.getProject());
        //TODO this call to javaProject needs to be removed.  Need to figure out what exactly this is attempting to do.
        final IClasspathEntry[] entries = javaProject.getResolvedClasspath(true);
        final Map<IPath, IClasspathEntry> pathToResolvedEntry = new HashMap<IPath, IClasspathEntry>();

        // store in a map from path to entry
        for (int j = 0; j < entries.length; j++) {
            pathToResolvedEntry.put(entries[j].getPath(), entries[j]);
        }

        //Gather all resolved entries from the package roots and the classpath containers
        final Map<IClasspathEntry, IClasspathAttribute> resolvedEntries = new LinkedHashMap<IClasspathEntry, IClasspathAttribute>();

        // grab all IPackageFragmentRoots

        // TODO this ignores project cp entries; can easily add in the raw project cp entries, however, do not have a good way to 
        // map project cp entries resolved from cp containers back to the corresponding raw entry (and thereby determine if the
        // entry has the publish/export attribute)
        //TODO this call to javaProject needs to be removed.  Need to figure out what exactly this is attempting to do.
        final IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots();

        for (IPackageFragmentRoot root : roots) {
            final IClasspathEntry rawEntry = root.getRawClasspathEntry();

            // is the raw entry valid?
            IClasspathAttribute attrib = validRawEntries.get(rawEntry);
            if (attrib == null) {
                continue;
            }

            final IPath pkgFragPath = root.getPath();
            final IClasspathEntry resolvedEntry = pathToResolvedEntry.get(pkgFragPath);
            resolvedEntries.put(resolvedEntry, attrib);
        }

        // Add entries coming from classpath containers to the list of resolved entries
        for (Map.Entry<IClasspathEntry, IClasspathAttribute> entry : validRawClassPathContainerEntries.entrySet()) {
            IClasspathContainer classpathContainer = JavaCore.getClasspathContainer(entry.getKey().getPath(),
                    javaProject);
            if (classpathContainer != null) {
                IClasspathEntry[] classpathContainerEntries = classpathContainer.getClasspathEntries();
                if (classpathContainerEntries != null) {
                    for (int j = 0; j < classpathContainerEntries.length; j++) {
                        resolvedEntries.put(classpathContainerEntries[j], entry.getValue());
                    }
                }
            }
        }

        //Setup the final result
        final Map<IClasspathEntry, IClasspathAttribute> referencedEntries = new LinkedHashMap<IClasspathEntry, IClasspathAttribute>();
        for (Map.Entry<IClasspathEntry, IClasspathAttribute> mapEntry : resolvedEntries.entrySet()) {
            final IClasspathEntry resolvedEntry = mapEntry.getKey();
            IClasspathAttribute attrib = mapEntry.getValue();

            final IClasspathAttribute resolvedAttrib = checkForComponentDependencyAttribute(resolvedEntry,
                    DependencyAttributeType.DEPENDENCY_OR_NONDEPENDENCY, isLegacyJ2EE);
            // attribute for the resolved entry must either be unspecified or it must be the
            // dependency attribute for it to be included
            if (resolvedAttrib == null || resolvedAttrib.getName().equals(CLASSPATH_COMPONENT_DEPENDENCY)) {
                // filter out resolved entry if it doesn't pass the validation rules
                if (!onlyValid || isValid(resolvedEntry, resolvedAttrib != null ? resolvedAttrib : attrib, isWebApp,
                        javaProjectLite.getProject(), data)) {
                    if (resolvedAttrib != null) {
                        // if there is an attribute on the sub-entry, use that
                        attrib = resolvedAttrib;
                    }
                    referencedEntries.put(resolvedEntry, attrib);
                }
            }
        }

        return referencedEntries;
    }

    /**
     * Retrieves the location (as a absolute file system path) for the specified classpath entry.
     * @param entry Classpath entry. If null, returns null.
     * @return Absolute file system path.
     */
    public static IPath getEntryLocation(final IClasspathEntry entry) {

        if (entry == null) {
            return null;
        }
        final IPath entryPath = entry.getPath();
        IPath entryLocation = entryPath;
        final IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(entryPath);
        if (resource != null) {
            entryLocation = resource.getLocation();
        }
        return entryLocation;
    }

    /**
     * Retrieves the IResource corresponding to the specified classpath entry or null if it does not represent a Workspace resource.
     * @param entry Classpath entry. If null, returns null.
     * @return IResource or null.
     */
    public static IResource getEntryResource(final IClasspathEntry entry) {
        if (entry == null) {
            return null;
        }
        final IPath entryPath = entry.getPath();
        return ResourcesPlugin.getWorkspace().getRoot().findMember(entryPath);
    }

    /**
     * Checks if the specified IVirtualReference represents an project cp entry. If so, returns the underlying IProject, otherwise,
     * returns null.
     * @param ref The IVirtualReference
     * @return IProject referenced by the project cp entry or null if the specified reference is null or does not refer to 
     * a VirtualArchiveComponent with type VirtualArchiveComponent.CLASSPATHARCHIVETYPE that represents a project cp entry.
     */
    public static IProject isClasspathProjectReference(final IVirtualReference ref) {
        if (ref != null && ref.getReferencedComponent() instanceof IClasspathDependencyComponent)
            return ref.getReferencedComponent().getProject();
        return null;
    }

    /**
     * Checks if the specified classpath entry represents a class folder.
     * @param entry The entry to check.
     * @return True if it is a library entry that points to a class folder. False otherwise.
     */
    public static boolean isClassFolderEntry(final IClasspathEntry entry) {
        if (entry == null || entry.getEntryKind() != IClasspathEntry.CPE_LIBRARY) {
            return false;
        }
        // does the path refer to a file or a folder?
        final IPath entryPath = entry.getPath();
        IPath entryLocation = entryPath;
        final IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(entryPath);
        if (resource != null) {
            entryLocation = resource.getLocation();
        }
        boolean isFile = true; // by default, assume a jar file
        if (entryLocation.toFile().isDirectory()) {
            isFile = false;
        }
        return !isFile;
    }

    /**
     * Retrieves the location (as an absolute local file system path) for the classpath dependency represented
     * by the specified IVirtualReference. Will return null for a project cp entry.
     * @param ref The IVirtualReference
     * @return Absolute path in the local file system or null if the specified reference is null or does not refer to 
     * a VirtualArchiveComponent with type VirtualArchiveComponent.CLASSPATHARCHIVETYPE.
     */
    public static IPath getClasspathVirtualReferenceLocation(final IVirtualReference ref) {
        if (ref != null && ref.getReferencedComponent() instanceof IClasspathDependencyComponent) {
            return (IPath) ref.getReferencedComponent().getAdapter(IPath.class);
        }
        return null;
    }

    /**
     * Retrieves the runtime path to which the resolved classpath entry components will be
     * added within the deployed application.
     * @param attrib The IClasspathAttribute with the WTP classpath component dependency value. If null,
     * will return the default path.
     * @param isWebApp True for web projects, false otherwise.
     * @param isClassFolder True if the default value should be computed for a class folder. Ignored if calculating for
     * a valid IClasspathAttribute.
     * @return Runtime path. Will be null if the attribute is not a WTP classpath component dependency 
     * attribute.
     */
    public static IPath getRuntimePath(final IClasspathAttribute attrib, final boolean isWebApp,
            final boolean isClassFolder) {
        if (attrib != null && !attrib.getName().equals(CLASSPATH_COMPONENT_DEPENDENCY)) {
            return null;
        }
        if (attrib == null || attrib.getValue() == null || attrib.getValue().length() == 0) {
            return getDefaultRuntimePath(isWebApp, isClassFolder);
        }
        return new Path(attrib.getValue());
    }

    /**
     * Checks if the specified IVirtualReference represents a class folder that has been marked for publish/export.
     * @param ref IVirtualReference to test.
     * @return True if this is a publish/export class folder.
     */
    public static boolean isClassFolderReference(final IVirtualReference ref) {
        final IVirtualComponent comp = ref.getReferencedComponent();
        // must refer to a ClasspathDependencyVirtualComponent
        if (comp instanceof ClasspathDependencyVirtualComponent) {
            final ClasspathDependencyVirtualComponent cpComp = (ClasspathDependencyVirtualComponent) comp;
            return cpComp.isClassFolder();
        }
        return false;
    }

    /**
     * Returns the container for the specified VirtualArchiveComponent or null if this reference does not match to a container.
     * @param comp IVirtualComponent.
     * @return IContainer for the class folder or null if this reference does not match a container.
     */
    public static IContainer getClassFolder(final IVirtualComponent comp) {
        if (comp instanceof ClasspathDependencyVirtualComponent) {
            final ClasspathDependencyVirtualComponent cpComp = (ClasspathDependencyVirtualComponent) comp;
            return cpComp.getClassFolder();
        }
        return null;
    }

    /**
     * Retrieves the default runtime path to which the resolved classpath entry components will be
     * added within the deployed application. This method is only valid for non-class folder entries.
     * @param isWebApp True if the default runtime path for web apps should be returned, false otherwise.
     * @return The default runtime path. 
     */
    public static IPath getDefaultRuntimePath(final boolean isWebApp) {
        return getDefaultRuntimePath(isWebApp, false);
    }

    /**
     * Retrieves the default runtime path to which the resolved classpath entry components will be
     * added within the deployed application.
     * @param isWebApp True if the default runtime path for web apps should be returned, false otherwise.
     * @param isClassFolder True if the path is a class folder.
     * @return The default runtime path. 
     */
    public static IPath getDefaultRuntimePath(final boolean isWebApp, final boolean isClassFolder) {
        if (isWebApp) {
            return isClassFolder ? WEB_INF_CLASSES_PATH : WEB_INF_LIB_PATH;
        }
        return isClassFolder ? RUNTIME_MAPPING_INTO_COMPONENT_PATH : RUNTIME_MAPPING_INTO_CONTAINER_PATH;
    }

    public static IPath getDefaultRuntimePath(final IVirtualComponent virtualComponent, IClasspathEntry entry) {
        boolean isClassFolderEntry = isClassFolderEntry(entry);
        if (virtualComponent == null) {
            //null, use default
            return getDefaultRuntimePath(false, isClassFolderEntry);
        }
        boolean isWebApp = JavaEEProjectUtilities.isDynamicWebComponent(virtualComponent);
        if (isWebApp || isClassFolderEntry) {
            return getDefaultRuntimePath(isWebApp, isClassFolderEntry);
        }

        //not a WAR
        //if part of EE5 or greature ear, map into the EAR's lib folder
        IProject[] earProjects = EarUtilities.getReferencingEARProjects(virtualComponent.getProject());
        if (earProjects.length > 0) {
            IVirtualComponent earComponent = ComponentCore.createComponent(earProjects[0]);
            if (earComponent != null) {
                return calculateDefaultRuntimePath(earComponent, virtualComponent);
            }
        }
        return getDefaultRuntimePath(false, false);

    }

    public static IPath calculateDefaultRuntimePath(IVirtualComponent parentComponent,
            IVirtualComponent targetComponent) {
        IVirtualReference targetRef = parentComponent.getReference(targetComponent.getName());
        String libDir = EarUtilities.getEARLibDir(parentComponent);
        if (libDir != null && libDir.length() > 0) {
            IPath libDirPath = new Path(libDir);

            // If project is at root level, go up a level and add lib dir path absolute path
            if (targetRef == null || targetRef.getRuntimePath().equals("/")) //$NON-NLS-1$
                return new Path(RUNTIME_MAPPING_INTO_CONTAINER).append(libDirPath.makeAbsolute());
            IPath childProjectRuntimePath = targetRef.getRuntimePath();

            String[] childProjectFolders = childProjectRuntimePath.segments();
            String[] libFolders = libDirPath.segments();
            int commonFolderCount = 0;
            for (int i = 0; i < childProjectFolders.length; i++) {
                if (i >= libFolders.length || !childProjectFolders[i].equals(libFolders[i]))
                    break;
                commonFolderCount++;
            }
            String resultString = RUNTIME_MAPPING_INTO_CONTAINER;
            for (int i = 0; i < childProjectFolders.length - commonFolderCount; i++) {
                resultString += RUNTIME_MAPPING_INTO_CONTAINER;
            }
            return new Path(resultString).append(libDirPath.removeFirstSegments(commonFolderCount));
        }
        return getDefaultRuntimePath(false, false);
    }

    /**
     * Retrieves the archive name for the specified classpath entry. 
     * For library entries, if a classpath attribute with {@link IClasspathDependencyConstants.CLASSPATH_ARCHIVENAME_ATTRIBUTE} was set, 
     * its value will be returned.
     *   
     * @param entry The entry.
     * @return The archive name.
     */
    public static String getArchiveName(final IClasspathEntry entry) {
        if (entry == null) {
            return null;
        }
        final boolean isClassFolder = isClassFolderEntry(entry);
        if (isClassFolder) {
            IResource resource = getEntryResource(entry);
            if (resource == null) {
                return getEntryLocation(entry).lastSegment();
            }
            return resource.getFullPath().toString();
        }

        //bug 359385 : Override default archive name
        String customArchiveName = getCustomArchiveName(entry);
        if (customArchiveName != null) {
            return customArchiveName;
        }
        final IPath entryLocation = getEntryLocation(entry);
        return entryLocation.lastSegment();
    }

    private static String getCustomArchiveName(IClasspathEntry entry) {
        IClasspathAttribute[] extraAttributes = entry.getExtraAttributes();
        if (extraAttributes != null) {
            for (IClasspathAttribute cpa : extraAttributes) {
                if (cpa != null && CLASSPATH_ARCHIVENAME_ATTRIBUTE.equals(cpa.getName())) {
                    return cpa.getValue();
                }
            }
        }
        return null;
    }

    /**
     * Checks if the specified IClasspathEntry has either of the special WTP component dependency
     * attributes that indicate it should be mapped into the virtual component for the associated project.
     * 
     * @param entry The IClasspathEntry.
     * @return The IClasspathAttribute that holds the special WTP attribute or null if one was not found.
     */
    public static IClasspathAttribute checkForComponentDependencyAttribute(final IClasspathEntry entry) {
        return checkForComponentDependencyAttribute(entry, DependencyAttributeType.DEPENDENCY_OR_NONDEPENDENCY);
    }

    /**
     * Checks if the specified IClasspathEntry has one of the special WTP component dependency
     * attributes that indicate it should be mapped into the virtual component for the associated project.
     * 
     * @param entry The IClasspathEntry.
     * @param componentDependency Controls which type of dependency attribute should be checked for (or whether both should be checked).
     * @return The IClasspathAttribute that holds the special WTP attribute or null if one was not found.
     */
    public static IClasspathAttribute checkForComponentDependencyAttribute(final IClasspathEntry entry,
            final DependencyAttributeType attributeType) {
        return checkForComponentDependencyAttribute(entry, attributeType, false);
    }

    public static IClasspathAttribute checkForComponentDependencyAttribute(final IClasspathEntry entry,
            final DependencyAttributeType attributeType, final boolean isLegacyJ2EE) {
        if (entry == null)
            return null;

        final IClasspathAttribute[] attributes = entry.getExtraAttributes();
        for (int i = 0; i < attributes.length; i++) {
            final IClasspathAttribute attribute = attributes[i];
            final String name = attribute.getName();
            if (name.equals(CLASSPATH_COMPONENT_DEPENDENCY)) {
                if (attributeType == DependencyAttributeType.DEPENDENCY_OR_NONDEPENDENCY
                        || attributeType == DependencyAttributeType.CLASSPATH_COMPONENT_DEPENDENCY) {
                    return attribute;
                }
            } else if (name.equals(CLASSPATH_COMPONENT_NON_DEPENDENCY)) {
                if (attributeType == DependencyAttributeType.DEPENDENCY_OR_NONDEPENDENCY
                        || attributeType == DependencyAttributeType.CLASSPATH_COMPONENT_NONDEPENDENCY) {
                    return attribute;
                }
            }
        }
        return null;
    }

    /**
     * Determines if the specified virtual component represents a classpath component dependency.
     * @param component Virtual component to test
     * @return True if a classpath component dependency, false otherwise.
     */
    public static boolean isClasspathComponentDependency(final IVirtualComponent component) {
        return component != null && component instanceof IClasspathDependencyComponent;
    }

    /**
     * Retrieves the classpath component display string for the specified component.
     * @param component Component that represents a classpath component.
     * @return Display string.
     */
    public static String getClasspathComponentDependencyDisplayString(final IVirtualComponent component) {
        final URI archiveURI = URI.createURI(ModuleURIUtil.getHandleString(component));
        return archiveURI.lastSegment();
    }

    public static boolean isMappedIntoContainer(String path) {
        if (path.startsWith(IClasspathDependencyConstants.RUNTIME_MAPPING_INTO_CONTAINER))
            return true;

        return false;
    }

    public static IClasspathEntry modifyDependencyPath(IClasspathEntry entry, IPath dependencyPath) {
        IClasspathEntry newEntry = null;
        IClasspathAttribute[] newAttributes = modifyDependencyPath(entry.getExtraAttributes(), dependencyPath);

        switch (entry.getEntryKind()) {
        case IClasspathEntry.CPE_CONTAINER:
            newEntry = JavaCore.newContainerEntry(entry.getPath(), entry.getAccessRules(), newAttributes,
                    entry.isExported());
            break;
        case IClasspathEntry.CPE_LIBRARY:
            newEntry = JavaCore.newLibraryEntry(entry.getPath(), entry.getSourceAttachmentPath(),
                    entry.getSourceAttachmentRootPath(), entry.getAccessRules(), newAttributes, entry.isExported());
            break;
        case IClasspathEntry.CPE_VARIABLE:
            newEntry = JavaCore.newVariableEntry(entry.getPath(), entry.getSourceAttachmentPath(),
                    entry.getSourceAttachmentRootPath(), entry.getAccessRules(), newAttributes, entry.isExported());
            break;
        case IClasspathEntry.CPE_PROJECT:
            newEntry = JavaCore.newProjectEntry(entry.getPath(), entry.getAccessRules(), entry.combineAccessRules(),
                    newAttributes, entry.isExported());
            break;
        case IClasspathEntry.CPE_SOURCE:
            newEntry = JavaCore.newSourceEntry(entry.getPath(), entry.getInclusionPatterns(),
                    entry.getExclusionPatterns(), entry.getOutputLocation(), newAttributes);
            break;
        }
        return newEntry;
    }

    public static IPath getRuntimePath(final IClasspathEntry entry) {
        IClasspathAttribute[] attributes = entry.getExtraAttributes();
        for (IClasspathAttribute attribute : attributes) {
            if (attribute.getName().equals(CLASSPATH_COMPONENT_DEPENDENCY)) {
                return new Path(attribute.getValue());
            }
        }
        return null;
    }

    private static IClasspathAttribute[] modifyDependencyPath(final IClasspathAttribute[] currentAttributes,
            IPath runtimePath) {
        final List<IClasspathAttribute> updatedAttributes = new ArrayList<IClasspathAttribute>();
        boolean modified = false;
        for (IClasspathAttribute currentAttribute : currentAttributes) {
            if (currentAttribute.getName().equals(CLASSPATH_COMPONENT_DEPENDENCY)) {
                modified = true;
                if (runtimePath == null) {
                    continue;
                }
                try {
                    IClasspathAttribute newAttribute = UpdateClasspathAttributeUtil
                            .createDependencyAttribute(runtimePath);
                    updatedAttributes.add(newAttribute);
                } catch (CoreException e) {
                    org.eclipse.jst.j2ee.internal.plugin.J2EEPlugin.logError(e);
                }
            } else {
                updatedAttributes.add(currentAttribute);
            }
        }
        if (!modified) {
            try {
                IClasspathAttribute newAttribute = UpdateClasspathAttributeUtil
                        .createDependencyAttribute(runtimePath);
                updatedAttributes.add(newAttribute);
            } catch (CoreException e) {
                org.eclipse.jst.j2ee.internal.plugin.J2EEPlugin.logError(e);
            }
        }
        return updatedAttributes.toArray(new IClasspathAttribute[updatedAttributes.size()]);
    }

}