org.eclipse.che.jdt.internal.core.ClasspathEntry.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.che.jdt.internal.core.ClasspathEntry.java

Source

/*******************************************************************************
 * Copyright (c) 2004, 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.che.jdt.internal.core;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IAccessRule;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaModelStatus;
import org.eclipse.jdt.core.IJavaModelStatusConstants;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
import org.eclipse.jdt.internal.compiler.env.AccessRule;
import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
import org.eclipse.jdt.internal.compiler.util.ManifestAnalyzer;
import org.eclipse.jdt.internal.core.ClasspathAccessRule;
import org.eclipse.jdt.internal.core.ClasspathAttribute;
import org.eclipse.jdt.internal.core.JavaModel;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.core.JavaModelStatus;
import org.eclipse.jdt.internal.core.util.Messages;
import org.eclipse.jdt.internal.core.util.Util;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * @see org.eclipse.jdt.core.IClasspathEntry
 */
public class ClasspathEntry implements IClasspathEntry {

    public static final String TAG_CLASSPATH = "classpath"; //$NON-NLS-1$
    public static final String TAG_CLASSPATHENTRY = "classpathentry"; //$NON-NLS-1$
    public static final String TAG_REFERENCED_ENTRY = "referencedentry"; //$NON-NLS-1$
    public static final String TAG_OUTPUT = "output"; //$NON-NLS-1$
    public static final String TAG_KIND = "kind"; //$NON-NLS-1$
    public static final String TAG_PATH = "path"; //$NON-NLS-1$
    public static final String TAG_SOURCEPATH = "sourcepath"; //$NON-NLS-1$
    public static final String TAG_ROOTPATH = "rootpath"; //$NON-NLS-1$
    public static final String TAG_EXPORTED = "exported"; //$NON-NLS-1$
    public static final String TAG_INCLUDING = "including"; //$NON-NLS-1$
    public static final String TAG_EXCLUDING = "excluding"; //$NON-NLS-1$
    public static final String TAG_ATTRIBUTES = "attributes"; //$NON-NLS-1$
    public static final String TAG_ATTRIBUTE = "attribute"; //$NON-NLS-1$
    public static final String TAG_ATTRIBUTE_NAME = "name"; //$NON-NLS-1$
    public static final String TAG_ATTRIBUTE_VALUE = "value"; //$NON-NLS-1$
    public static final String TAG_COMBINE_ACCESS_RULES = "combineaccessrules"; //$NON-NLS-1$
    public static final String TAG_ACCESS_RULES = "accessrules"; //$NON-NLS-1$
    public static final String TAG_ACCESS_RULE = "accessrule"; //$NON-NLS-1$
    public static final String TAG_PATTERN = "pattern"; //$NON-NLS-1$
    public static final String TAG_ACCESSIBLE = "accessible"; //$NON-NLS-1$
    public static final String TAG_NON_ACCESSIBLE = "nonaccessible"; //$NON-NLS-1$
    public static final String TAG_DISCOURAGED = "discouraged"; //$NON-NLS-1$
    public static final String TAG_IGNORE_IF_BETTER = "ignoreifbetter"; //$NON-NLS-1$
    //$NON-NLS-1$
    public final static ClasspathEntry[] NO_ENTRIES = new ClasspathEntry[0];
    /*
     * Default inclusion pattern set
     */
    public final static IPath[] INCLUDE_ALL = {};
    /*
     * Default exclusion pattern set
     */
    public final static IPath[] EXCLUDE_NONE = {};
    /*
     * Default extra attributes
     */
    public final static IClasspathAttribute[] NO_EXTRA_ATTRIBUTES = {};
    /*
     * Default access rules
     */
    public final static IAccessRule[] NO_ACCESS_RULES = {};
    /**
     * A constant indicating an output location.
     */
    public static final int K_OUTPUT = 10;
    public static final String DOT_DOT = ".."; //$NON-NLS-1$
    private final static char[][] UNINIT_PATTERNS = new char[][] { "Non-initialized yet".toCharArray() };
    private final static IPath[] NO_PATHS = new IPath[0];
    /**
     * Describes the kind of classpath entry - one of
     * CPE_PROJECT, CPE_LIBRARY, CPE_SOURCE, CPE_VARIABLE or CPE_CONTAINER
     */
    public int entryKind;
    /**
     * Describes the kind of package fragment roots found on
     * this classpath entry - either K_BINARY or K_SOURCE or
     * K_OUTPUT.
     */
    public int contentKind;
    //    private final static IWorkspaceRoot                                 workspaceRoot   = ResourcesPlugin.getWorkspace().getRoot();
    /**
     * The meaning of the path of a classpath entry depends on its entry kind:<ul>
     * <li>Source code in the current project (<code>CPE_SOURCE</code>) -
     * The path associated with this entry is the absolute path to the root folder. </li>
     * <li>A binary library in the current project (<code>CPE_LIBRARY</code>) - the path
     * associated with this entry is the absolute path to the JAR (or root folder), and
     * in case it refers to an external JAR, then there is no associated resource in
     * the workbench.
     * <li>A required project (<code>CPE_PROJECT</code>) - the path of the entry denotes the
     * path to the corresponding project resource.</li>
     * <li>A variable entry (<code>CPE_VARIABLE</code>) - the first segment of the path
     * is the name of a classpath variable. If this classpath variable
     * is bound to the path <it>P</it>, the path of the corresponding classpath entry
     * is computed by appending to <it>P</it> the segments of the returned
     * path without the variable.</li>
     * <li> A container entry (<code>CPE_CONTAINER</code>) - the first segment of the path is denoting
     * the unique container identifier (for which a <code>ClasspathContainerInitializer</code> could be
     * registered), and the remaining segments are used as additional hints for resolving the container entry to
     * an actual <code>IClasspathContainer</code>.</li>
     */
    public IPath path;
    /**
     * Describes the path to the source archive associated with this
     * classpath entry, or <code>null</code> if this classpath entry has no
     * source attachment.
     * <p/>
     * Only library and variable classpath entries may have source attachments.
     * For library classpath entries, the result path (if present) locates a source
     * archive. For variable classpath entries, the result path (if present) has
     * an analogous form and meaning as the variable path, namely the first segment
     * is the name of a classpath variable.
     */
    public IPath sourceAttachmentPath;
    /**
     * Describes the path within the source archive where package fragments
     * are located. An empty path indicates that packages are located at
     * the root of the source archive. Returns a non-<code>null</code> value
     * if and only if <code>getSourceAttachmentPath</code> returns
     * a non-<code>null</code> value.
     */
    public IPath sourceAttachmentRootPath;
    /**
     * See {@link org.eclipse.jdt.core.IClasspathEntry#getReferencingEntry()}
     */
    public IClasspathEntry referencingEntry;
    /**
     * Specific output location (for this source entry)
     */
    public IPath specificOutputLocation;
    /**
     * The export flag
     */
    public boolean isExported;
    /**
     * The extra attributes
     */
    public IClasspathAttribute[] extraAttributes;
    /**
     * Patterns allowing to include/exclude portions of the resource tree denoted by this entry path.
     */
    private IPath[] inclusionPatterns;
    private char[][] fullInclusionPatternChars;
    private IPath[] exclusionPatterns;
    private char[][] fullExclusionPatternChars;
    private boolean combineAccessRules;
    private String rootID;
    private AccessRuleSet accessRuleSet;

    public ClasspathEntry(int contentKind, int entryKind, IPath path, IPath[] inclusionPatterns,
            IPath[] exclusionPatterns, IPath sourceAttachmentPath, IPath sourceAttachmentRootPath,
            IPath specificOutputLocation, boolean isExported, IAccessRule[] accessRules, boolean combineAccessRules,
            IClasspathAttribute[] extraAttributes) {

        this(contentKind, entryKind, path, inclusionPatterns, exclusionPatterns, sourceAttachmentPath,
                sourceAttachmentRootPath, specificOutputLocation, null, isExported, accessRules, combineAccessRules,
                extraAttributes);
    }

    /**
     * Creates a class path entry of the specified kind with the given path.
     */
    public ClasspathEntry(int contentKind, int entryKind, IPath path, IPath[] inclusionPatterns,
            IPath[] exclusionPatterns, IPath sourceAttachmentPath, IPath sourceAttachmentRootPath,
            IPath specificOutputLocation, IClasspathEntry referencingEntry, boolean isExported,
            IAccessRule[] accessRules, boolean combineAccessRules, IClasspathAttribute[] extraAttributes) {

        this.contentKind = contentKind;
        this.entryKind = entryKind;
        this.path = path;
        this.inclusionPatterns = inclusionPatterns;
        this.exclusionPatterns = exclusionPatterns;
        this.referencingEntry = referencingEntry;

        int length;
        if (accessRules != null && (length = accessRules.length) > 0) {
            AccessRule[] rules = new AccessRule[length];
            System.arraycopy(accessRules, 0, rules, 0, length);
            byte classpathEntryType;
            String classpathEntryName;
            JavaModelManager manager = JavaModelManager.getJavaModelManager();
            if (this.entryKind == CPE_PROJECT || this.entryKind == CPE_SOURCE) { // can be remote source entry when reconciling
                classpathEntryType = AccessRestriction.PROJECT;
                classpathEntryName = manager.intern(getPath().segment(0));
            } else {
                classpathEntryType = AccessRestriction.LIBRARY;
                //                Object target = JavaModel.getWorkspaceTarget(path);
                //                if (target == null) {
                classpathEntryName = manager.intern(path.toOSString());
                //                } else {
                //                    classpathEntryName = manager.intern(path.makeRelative().toString());
                //                }
            }
            this.accessRuleSet = new AccessRuleSet(rules, classpathEntryType, classpathEntryName);
        }
        //      else { -- implicit!
        //         this.accessRuleSet = null;
        //      }

        this.combineAccessRules = combineAccessRules;
        this.extraAttributes = extraAttributes;

        if (inclusionPatterns != INCLUDE_ALL && inclusionPatterns.length > 0) {
            this.fullInclusionPatternChars = UNINIT_PATTERNS;
        }
        if (exclusionPatterns.length > 0) {
            this.fullExclusionPatternChars = UNINIT_PATTERNS;
        }
        this.sourceAttachmentPath = sourceAttachmentPath;
        this.sourceAttachmentRootPath = sourceAttachmentRootPath;
        this.specificOutputLocation = specificOutputLocation;
        this.isExported = isExported;
    }

    static IClasspathAttribute[] decodeExtraAttributes(NodeList attributes) {
        if (attributes == null)
            return NO_EXTRA_ATTRIBUTES;
        int length = attributes.getLength();
        if (length == 0)
            return NO_EXTRA_ATTRIBUTES;
        IClasspathAttribute[] result = new IClasspathAttribute[length];
        int index = 0;
        for (int i = 0; i < length; ++i) {
            Node node = attributes.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element attribute = (Element) node;
                String name = attribute.getAttribute(TAG_ATTRIBUTE_NAME);
                if (name == null)
                    continue;
                String value = attribute.getAttribute(TAG_ATTRIBUTE_VALUE);
                if (value == null)
                    continue;
                result[index++] = new ClasspathAttribute(name, value);
            }
        }
        if (index != length)
            System.arraycopy(result, 0, result = new IClasspathAttribute[index], 0, index);
        return result;
    }

    static IAccessRule[] decodeAccessRules(NodeList list) {
        if (list == null)
            return null;
        int length = list.getLength();
        if (length == 0)
            return null;
        IAccessRule[] result = new IAccessRule[length];
        int index = 0;
        for (int i = 0; i < length; i++) {
            Node accessRule = list.item(i);
            if (accessRule.getNodeType() == Node.ELEMENT_NODE) {
                Element elementAccessRule = (Element) accessRule;
                String pattern = elementAccessRule.getAttribute(TAG_PATTERN);
                if (pattern == null)
                    continue;
                String tagKind = elementAccessRule.getAttribute(TAG_KIND);
                int kind;
                if (TAG_ACCESSIBLE.equals(tagKind))
                    kind = IAccessRule.K_ACCESSIBLE;
                else if (TAG_NON_ACCESSIBLE.equals(tagKind))
                    kind = IAccessRule.K_NON_ACCESSIBLE;
                else if (TAG_DISCOURAGED.equals(tagKind))
                    kind = IAccessRule.K_DISCOURAGED;
                else
                    continue;
                boolean ignoreIfBetter = "true".equals(elementAccessRule.getAttribute(TAG_IGNORE_IF_BETTER)); //$NON-NLS-1$
                result[index++] = new ClasspathAccessRule(new Path(pattern),
                        ignoreIfBetter ? kind | IAccessRule.IGNORE_IF_BETTER : kind);
            }
        }
        if (index != length)
            System.arraycopy(result, 0, result = new IAccessRule[index], 0, index);
        return result;
    }

    /**
     * Decode some element tag containing a sequence of patterns into IPath[]
     */
    private static IPath[] decodePatterns(NamedNodeMap nodeMap, String tag) {
        String sequence = removeAttribute(tag, nodeMap);
        if (!sequence.equals("")) { //$NON-NLS-1$
            char[][] patterns = CharOperation.splitOn('|', sequence.toCharArray());
            int patternCount;
            if ((patternCount = patterns.length) > 0) {
                IPath[] paths = new IPath[patternCount];
                int index = 0;
                for (int j = 0; j < patternCount; j++) {
                    char[] pattern = patterns[j];
                    if (pattern.length == 0)
                        continue; // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=105581
                    paths[index++] = new Path(new String(pattern));
                }
                if (index < patternCount)
                    System.arraycopy(paths, 0, paths = new IPath[index], 0, index);
                return paths;
            }
        }
        return null;
    }

    /*
     * Returns whether the given path as a ".." segment
     */
    public static boolean hasDotDot(IPath path) {
        for (int i = 0, length = path.segmentCount(); i < length; i++) {
            if (DOT_DOT.equals(path.segment(i)))
                return true;
        }
        return false;
    }

    public static NodeList getChildAttributes(String childName, NodeList children, boolean[] foundChildren) {
        for (int i = 0, length = foundChildren.length; i < length; i++) {
            Node node = children.item(i);
            if (childName.equals(node.getNodeName())) {
                foundChildren[i] = true;
                return node.getChildNodes();
            }
        }
        return null;
    }

    private static String removeAttribute(String nodeName, NamedNodeMap nodeMap) {
        Node node = removeNode(nodeName, nodeMap);
        if (node == null)
            return ""; // //$NON-NLS-1$
        return node.getNodeValue();
    }

    private static Node removeNode(String nodeName, NamedNodeMap nodeMap) {
        try {
            return nodeMap.removeNamedItem(nodeName);
        } catch (DOMException e) {
            if (e.code != DOMException.NOT_FOUND_ERR)
                throw e;
            return null;
        }
    }

    /*
     * Read the Class-Path clause of the manifest of the jar pointed by this path, and return
     * the corresponding paths.
     */
    public static IPath[] resolvedChainedLibraries(IPath jarPath) {
        ArrayList result = new ArrayList();
        resolvedChainedLibraries(jarPath, new HashSet(), result);
        if (result.size() == 0)
            return NO_PATHS;
        return (IPath[]) result.toArray(new IPath[result.size()]);
    }

    //    private static void decodeUnknownNode(Node node, StringBuffer buffer, IJavaProject project) {
    //        ByteArrayOutputStream s = new ByteArrayOutputStream();
    //        OutputStreamWriter writer;
    //        try {
    //            writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
    //            XMLWriter xmlWriter = new XMLWriter(writer, project, false/*don't print XML version*/);
    //            decodeUnknownNode(node, xmlWriter, true/*insert new line*/);
    //         xmlWriter.flush();
    //         xmlWriter.close();
    //         buffer.append(s.toString("UTF8")); //$NON-NLS-1$
    //      } catch (UnsupportedEncodingException e) {
    //         // ignore (UTF8 is always supported)
    //      }
    //   }
    //
    //   private static void decodeUnknownNode(Node node, XMLWriter xmlWriter, boolean insertNewLine) {
    //      switch (node.getNodeType()) {
    //      case Node.ELEMENT_NODE:
    //         NamedNodeMap attributes;
    //         HashMap parameters = null;
    //         if ((attributes = node.getAttributes()) != null) {
    //            int length = attributes.getLength();
    //            if (length > 0) {
    //               parameters = new HashMap();
    //               for (int i = 0; i < length; i++) {
    //                  Node attribute = attributes.item(i);
    //                  parameters.put(attribute.getNodeName(), attribute.getNodeValue());
    //               }
    //            }
    //         }
    //         NodeList children = node.getChildNodes();
    //         int childrenLength = children.getLength();
    //         String nodeName = node.getNodeName();
    //         xmlWriter.printTag(nodeName, parameters, false/*don't insert tab*/, false/*don't insert new line*/, childrenLength == 0/*close
    // tag if no children*/);
    //         if (childrenLength > 0) {
    //            for (int i = 0; i < childrenLength; i++) {
    //               decodeUnknownNode(children.item(i), xmlWriter, false/*don't insert new line*/);
    //            }
    //            xmlWriter.endTag(nodeName, false/*don't insert tab*/, insertNewLine);
    //         }
    //         break;
    //      case Node.TEXT_NODE:
    //         String data = ((Text) node).getData();
    //         xmlWriter.printString(data, false/*don't insert tab*/, false/*don't insert new line*/);
    //         break;
    //      }
    //   }

    private static void resolvedChainedLibraries(IPath jarPath, HashSet visited, ArrayList result) {
        if (visited.contains(jarPath))
            return;
        visited.add(jarPath);
        JavaModelManager manager = JavaModelManager.getJavaModelManager();
        if (manager.isNonChainingJar(jarPath))
            return;
        List calledFileNames = getCalledFileNames(jarPath);
        if (calledFileNames == null) {
            manager.addNonChainingJar(jarPath);
        } else {
            Iterator calledFilesIterator = calledFileNames.iterator();
            IPath directoryPath = jarPath.removeLastSegments(1);
            while (calledFilesIterator.hasNext()) {
                String calledFileName = (String) calledFilesIterator.next();
                if (!directoryPath.isValidPath(calledFileName)) {
                    if (JavaModelManager.CP_RESOLVE_VERBOSE_FAILURE) {
                        Util.verbose("Invalid Class-Path entry " + calledFileName + " in manifest of jar file: "
                                + jarPath.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
                    }
                } else {
                    IPath calledJar = directoryPath.append(new Path(calledFileName));
                    // Ignore if segment count is Zero (https://bugs.eclipse.org/bugs/show_bug.cgi?id=308150)
                    if (calledJar.segmentCount() == 0) {
                        if (JavaModelManager.CP_RESOLVE_VERBOSE_FAILURE) {
                            Util.verbose("Invalid Class-Path entry " + calledFileName + " in manifest of jar file: "
                                    + jarPath.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
                        }
                        continue;
                    }
                    resolvedChainedLibraries(calledJar, visited, result);
                    result.add(calledJar);
                }
            }
        }
    }

    private static List getCalledFileNames(IPath jarPath) {
        Object target = JavaModel.getTarget(jarPath,
                true/*check existence, otherwise the manifest cannot be read*/);
        if (!(target instanceof IFile || target instanceof File))
            return null;
        JavaModelManager manager = JavaModelManager.getJavaModelManager();
        ZipFile zip = null;
        InputStream inputStream = null;
        List calledFileNames = null;
        try {
            zip = manager.getZipFile(jarPath);
            ZipEntry manifest = zip.getEntry("META-INF/MANIFEST.MF"); //$NON-NLS-1$
            if (manifest == null)
                return null;
            // non-null implies regular file
            ManifestAnalyzer analyzer = new ManifestAnalyzer();
            inputStream = zip.getInputStream(manifest);
            boolean success = analyzer.analyzeManifestContents(inputStream);
            calledFileNames = analyzer.getCalledFileNames();
            if (!success || analyzer.getClasspathSectionsCount() == 1 && calledFileNames == null) {
                if (JavaModelManager.CP_RESOLVE_VERBOSE_FAILURE) {
                    Util.verbose("Invalid Class-Path header in manifest of jar file: " + jarPath.toOSString()); //$NON-NLS-1$
                }
                return null;
            } else if (analyzer.getClasspathSectionsCount() > 1) {
                if (JavaModelManager.CP_RESOLVE_VERBOSE_FAILURE) {
                    Util.verbose("Multiple Class-Path headers in manifest of jar file: " + jarPath.toOSString()); //$NON-NLS-1$
                }
                return null;
            }
        } catch (CoreException e) {
            // not a zip file
            if (JavaModelManager.CP_RESOLVE_VERBOSE_FAILURE) {
                Util.verbose("Could not read Class-Path header in manifest of jar file: " + jarPath.toOSString()); //$NON-NLS-1$
                e.printStackTrace();
            }
        } catch (IOException e) {
            // not a zip file
            if (JavaModelManager.CP_RESOLVE_VERBOSE_FAILURE) {
                Util.verbose("Could not read Class-Path header in manifest of jar file: " + jarPath.toOSString()); //$NON-NLS-1$
                e.printStackTrace();
            }
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    // best effort
                }
            }
            manager.closeZipFile(zip);
        }
        return calledFileNames;
    }

    //   /**
    //    * Returns the XML encoding of the class path.
    //    */
    //   public void elementEncode(XMLWriter writer, IPath projectPath, boolean indent, boolean newLine, Map unknownElements, boolean
    // isReferencedEntry) {
    //      HashMap parameters = new HashMap();
    //
    //      parameters.put(TAG_KIND, ClasspathEntry.kindToString(this.entryKind));
    //
    //      IPath xmlPath = this.path;
    //      if (this.entryKind != IClasspathEntry.CPE_VARIABLE && this.entryKind != IClasspathEntry.CPE_CONTAINER) {
    //         // translate to project relative from absolute (unless a device path)
    //         if (xmlPath.isAbsolute()) {
    //            if (projectPath != null && projectPath.isPrefixOf(xmlPath)) {
    //               if (xmlPath.segment(0).equals(projectPath.segment(0))) {
    //                  xmlPath = xmlPath.removeFirstSegments(1);
    //                  xmlPath = xmlPath.makeRelative();
    //               } else {
    //                  xmlPath = xmlPath.makeAbsolute();
    //               }
    //            }
    //         }
    //      }
    //      parameters.put(TAG_PATH, String.valueOf(xmlPath));
    //
    //      if (this.sourceAttachmentPath != null) {
    //         xmlPath = this.sourceAttachmentPath;
    //         // translate to project relative from absolute
    //         if (this.entryKind != IClasspathEntry.CPE_VARIABLE && projectPath != null && projectPath.isPrefixOf(xmlPath)) {
    //            if (xmlPath.segment(0).equals(projectPath.segment(0))) {
    //               xmlPath = xmlPath.removeFirstSegments(1);
    //               xmlPath = xmlPath.makeRelative();
    //            }
    //         }
    //         parameters.put(TAG_SOURCEPATH, String.valueOf(xmlPath));
    //      }
    //      if (this.sourceAttachmentRootPath != null) {
    //         parameters.put(TAG_ROOTPATH, String.valueOf(this.sourceAttachmentRootPath));
    //      }
    //      if (this.isExported) {
    //         parameters.put(TAG_EXPORTED, "true");//$NON-NLS-1$
    //      }
    //      encodePatterns(this.inclusionPatterns, TAG_INCLUDING, parameters);
    //      encodePatterns(this.exclusionPatterns, TAG_EXCLUDING, parameters);
    //      if (this.entryKind == CPE_PROJECT && !this.combineAccessRules)
    //         parameters.put(TAG_COMBINE_ACCESS_RULES, "false"); //$NON-NLS-1$
    //
    //
    //      // unknown attributes
    //      UnknownXmlElements unknownXmlElements = unknownElements == null ? null : (UnknownXmlElements) unknownElements.get(this.path);
    //      String[] unknownAttributes;
    //      if (unknownXmlElements != null && (unknownAttributes = unknownXmlElements.attributes) != null)
    //         for (int i = 0, length = unknownAttributes.length; i < length; i+=2) {
    //            String tagName = unknownAttributes[i];
    //            String tagValue = unknownAttributes[i+1];
    //            parameters.put(tagName, tagValue);
    //         }
    //
    //      if (this.specificOutputLocation != null) {
    //         IPath outputLocation = this.specificOutputLocation.removeFirstSegments(1);
    //         outputLocation = outputLocation.makeRelative();
    //         parameters.put(TAG_OUTPUT, String.valueOf(outputLocation));
    //      }
    //
    //      boolean hasExtraAttributes = this.extraAttributes.length != 0;
    //      boolean hasRestrictions = getAccessRuleSet() != null; // access rule set is null if no access rules
    //      ArrayList unknownChildren = unknownXmlElements != null ? unknownXmlElements.children : null;
    //      boolean hasUnknownChildren = unknownChildren != null;
    //
    //      /* close tag if no extra attributes, no restriction and no unknown children */
    //      String tagName = isReferencedEntry ? TAG_REFERENCED_ENTRY : TAG_CLASSPATHENTRY;
    //      writer.printTag(
    //         tagName,
    //         parameters,
    //         indent,
    //         newLine,
    //         !hasExtraAttributes && !hasRestrictions && !hasUnknownChildren);
    //
    //      if (hasExtraAttributes)
    //         encodeExtraAttributes(writer, indent, newLine);
    //
    //      if (hasRestrictions)
    //         encodeAccessRules(writer, indent, newLine);
    //
    //      if (hasUnknownChildren)
    //         encodeUnknownChildren(writer, indent, newLine, unknownChildren);
    //
    //      if (hasExtraAttributes || hasRestrictions || hasUnknownChildren)
    //         writer.endTag(tagName, indent, true/*insert new line*/);
    //   }
    //
    //   void encodeExtraAttributes(XMLWriter writer, boolean indent, boolean newLine) {
    //      writer.startTag(TAG_ATTRIBUTES, indent);
    //      for (int i = 0; i < this.extraAttributes.length; i++) {
    //         IClasspathAttribute attribute = this.extraAttributes[i];
    //         HashMap parameters = new HashMap();
    //          parameters.put(TAG_ATTRIBUTE_NAME, attribute.getName());
    //         parameters.put(TAG_ATTRIBUTE_VALUE, attribute.getValue());
    //         writer.printTag(TAG_ATTRIBUTE, parameters, indent, newLine, true);
    //      }
    //      writer.endTag(TAG_ATTRIBUTES, indent, true/*insert new line*/);
    //   }
    //
    //   void encodeAccessRules(XMLWriter writer, boolean indent, boolean newLine) {
    //
    //      writer.startTag(TAG_ACCESS_RULES, indent);
    //      AccessRule[] rules = getAccessRuleSet().getAccessRules();
    //      for (int i = 0, length = rules.length; i < length; i++) {
    //         encodeAccessRule(rules[i], writer, indent, newLine);
    //      }
    //      writer.endTag(TAG_ACCESS_RULES, indent, true/*insert new line*/);
    //   }
    //
    //   private void encodeAccessRule(AccessRule accessRule, XMLWriter writer, boolean indent, boolean newLine) {
    //
    //      HashMap parameters = new HashMap();
    //      parameters.put(TAG_PATTERN, new String(accessRule.pattern));
    //
    //      switch (accessRule.getProblemId()) {
    //         case IProblem.ForbiddenReference:
    //            parameters.put(TAG_KIND, TAG_NON_ACCESSIBLE);
    //            break;
    //         case IProblem.DiscouragedReference:
    //            parameters.put(TAG_KIND, TAG_DISCOURAGED);
    //            break;
    //         default:
    //            parameters.put(TAG_KIND, TAG_ACCESSIBLE);
    //            break;
    //      }
    //      if (accessRule.ignoreIfBetter())
    //         parameters.put(TAG_IGNORE_IF_BETTER, "true"); //$NON-NLS-1$
    //
    //      writer.printTag(TAG_ACCESS_RULE, parameters, indent, newLine, true);
    //
    //   }
    //
    //   private void encodeUnknownChildren(XMLWriter writer, boolean indent, boolean newLine, ArrayList unknownChildren) {
    //      for (int i = 0, length = unknownChildren.size(); i < length; i++) {
    //         String child = (String) unknownChildren.get(i);
    //         writer.printString(child, indent, false/*don't insert new line*/);
    //      }
    //   }

    //   public static IClasspathEntry elementDecode(Element element, IJavaProject project, Map unknownElements) {
    //
    //      IPath projectPath = project.getProject().getFullPath();
    //      NamedNodeMap attributes = element.getAttributes();
    //      NodeList children = element.getChildNodes();
    //      boolean[] foundChildren = new boolean[children.getLength()];
    //      String kindAttr = removeAttribute(TAG_KIND, attributes);
    //      String pathAttr = removeAttribute(TAG_PATH, attributes);
    //
    //      // ensure path is absolute
    //      IPath path = new Path(pathAttr);
    //      int kind = kindFromString(kindAttr);
    //      if (kind != IClasspathEntry.CPE_VARIABLE && kind != IClasspathEntry.CPE_CONTAINER && !path.isAbsolute()) {
    //         if (!(path.segmentCount() > 0 && path.segment(0).equals(ClasspathEntry.DOT_DOT))) {
    //            path = projectPath.append(path);
    //         }
    //      }
    //      // source attachment info (optional)
    //      IPath sourceAttachmentPath =
    //         element.hasAttribute(TAG_SOURCEPATH)
    //         ? new Path(removeAttribute(TAG_SOURCEPATH, attributes))
    //         : null;
    //      if (kind != IClasspathEntry.CPE_VARIABLE && sourceAttachmentPath != null && !sourceAttachmentPath.isAbsolute()) {
    //         sourceAttachmentPath = projectPath.append(sourceAttachmentPath);
    //      }
    //      IPath sourceAttachmentRootPath =
    //         element.hasAttribute(TAG_ROOTPATH)
    //         ? new Path(removeAttribute(TAG_ROOTPATH, attributes))
    //         : null;
    //
    //      // exported flag (optional)
    //      boolean isExported = removeAttribute(TAG_EXPORTED, attributes).equals("true"); //$NON-NLS-1$
    //
    //      // inclusion patterns (optional)
    //      IPath[] inclusionPatterns = decodePatterns(attributes, TAG_INCLUDING);
    //      if (inclusionPatterns == null) inclusionPatterns = INCLUDE_ALL;
    //
    //      // exclusion patterns (optional)
    //      IPath[] exclusionPatterns = decodePatterns(attributes, TAG_EXCLUDING);
    //      if (exclusionPatterns == null) exclusionPatterns = EXCLUDE_NONE;
    //
    //      // access rules (optional)
    //      NodeList attributeList = getChildAttributes(TAG_ACCESS_RULES, children, foundChildren);
    //      IAccessRule[] accessRules = decodeAccessRules(attributeList);
    //
    //      // backward compatibility
    //      if (accessRules == null) {
    //         accessRules = getAccessRules(inclusionPatterns, exclusionPatterns);
    //      }
    //
    //      // combine access rules (optional)
    //      boolean combineAccessRestrictions = !removeAttribute(TAG_COMBINE_ACCESS_RULES, attributes).equals("false"); //$NON-NLS-1$
    //
    //      // extra attributes (optional)
    //      attributeList = getChildAttributes(TAG_ATTRIBUTES, children, foundChildren);
    //      IClasspathAttribute[] extraAttributes = decodeExtraAttributes(attributeList);
    //
    //      // custom output location
    //      IPath outputLocation = element.hasAttribute(TAG_OUTPUT) ? projectPath.append(removeAttribute(TAG_OUTPUT, attributes)) : null;
    //
    //      String[] unknownAttributes = null;
    //      ArrayList unknownChildren = null;
    //
    //      if (unknownElements != null) {
    //         // unknown attributes
    //         int unknownAttributeLength = attributes.getLength();
    //         if (unknownAttributeLength != 0) {
    //            unknownAttributes = new String[unknownAttributeLength*2];
    //            for (int i = 0; i < unknownAttributeLength; i++) {
    //               Node attribute = attributes.item(i);
    //               unknownAttributes[i*2] = attribute.getNodeName();
    //               unknownAttributes[i*2 + 1] = attribute.getNodeValue();
    //            }
    //         }
    //
    //         // unknown children
    //         for (int i = 0, length = foundChildren.length; i < length; i++) {
    //            if (!foundChildren[i]) {
    //               Node node = children.item(i);
    //               if (node.getNodeType() != Node.ELEMENT_NODE) continue;
    //               if (unknownChildren == null)
    //                  unknownChildren = new ArrayList();
    //               StringBuffer buffer = new StringBuffer();
    //               decodeUnknownNode(node, buffer, project);
    //               unknownChildren.add(buffer.toString());
    //            }
    //         }
    //      }
    //
    //      // recreate the CP entry
    //      IClasspathEntry entry = null;
    //      switch (kind) {
    //
    //         case IClasspathEntry.CPE_PROJECT :
    //            entry = new ClasspathEntry(
    //                                    IPackageFragmentRoot.K_SOURCE,
    //                                    IClasspathEntry.CPE_PROJECT,
    //                                    path,
    //                                    ClasspathEntry.INCLUDE_ALL, // inclusion patterns
    //                                    ClasspathEntry.EXCLUDE_NONE, // exclusion patterns
    //                                    null, // source attachment
    //                                    null, // source attachment root
    //                                    null, // specific output folder
    //                                    isExported,
    //                                    accessRules,
    //                                    combineAccessRestrictions,
    //                                    extraAttributes);
    //            break;
    //         case IClasspathEntry.CPE_LIBRARY :
    //            entry = JavaCore.newLibraryEntry(
    //                        path,
    //                        sourceAttachmentPath,
    //                        sourceAttachmentRootPath,
    //                        accessRules,
    //                        extraAttributes,
    //                        isExported);
    //            break;
    //         case IClasspathEntry.CPE_SOURCE :
    //            // must be an entry in this project or specify another project
    //            String projSegment = path.segment(0);
    //            if (projSegment != null && projSegment.equals(project.getElementName())) { // this project
    //               entry = JavaCore.newSourceEntry(
    //                            path,
    //                            inclusionPatterns,
    //                            exclusionPatterns,
    //                            outputLocation,
    //                            extraAttributes);
    //            } else {
    //               if (path.segmentCount() == 1) {
    //                  // another project
    //                  entry = JavaCore.newProjectEntry(
    //                                path,
    //                                accessRules,
    //                                combineAccessRestrictions,
    //                                extraAttributes,
    //                                isExported);
    //               } else {
    //                  // an invalid source folder
    //                  entry = JavaCore.newSourceEntry(
    //                                path,
    //                                inclusionPatterns,
    //                                exclusionPatterns,
    //                                outputLocation,
    //                                extraAttributes);
    //               }
    //            }
    //            break;
    //         case IClasspathEntry.CPE_VARIABLE :
    //            entry = JavaCore.newVariableEntry(
    //                        path,
    //                        sourceAttachmentPath,
    //                        sourceAttachmentRootPath,
    //                        accessRules,
    //                        extraAttributes,
    //                        isExported);
    //            break;
    //         case IClasspathEntry.CPE_CONTAINER :
    //            entry = JavaCore.newContainerEntry(
    //                        path,
    //                        accessRules,
    //                        extraAttributes,
    //                        isExported);
    //            break;
    //         case ClasspathEntry.K_OUTPUT :
    //            if (!path.isAbsolute()) return null;
    //            entry = new ClasspathEntry(
    //                                    ClasspathEntry.K_OUTPUT,
    //                                    IClasspathEntry.CPE_LIBRARY,
    //                                    path,
    //                                    INCLUDE_ALL,
    //                                    EXCLUDE_NONE,
    //                                    null, // source attachment
    //                                    null, // source attachment root
    //                                    null, // custom output location
    //                                    false,
    //                                    null, // no access rules
    //                                    false, // no accessible files to combine
    //                                    NO_EXTRA_ATTRIBUTES);
    //            break;
    //         default :
    //            throw new AssertionFailedException(Messages.bind(Messages.classpath_unknownKind, kindAttr));
    //      }
    //
    //      if (unknownAttributes != null || unknownChildren != null) {
    //         UnknownXmlElements unknownXmlElements = new UnknownXmlElements();
    //         unknownXmlElements.attributes = unknownAttributes;
    //         unknownXmlElements.children = unknownChildren;
    //         unknownElements.put(path, unknownXmlElements);
    //      }
    //
    //      return entry;
    //   }

    /**
     * Encode some patterns into XML parameter tag
     */
    private static void encodePatterns(IPath[] patterns, String tag, Map parameters) {
        if (patterns != null && patterns.length > 0) {
            StringBuffer rule = new StringBuffer(10);
            for (int i = 0, max = patterns.length; i < max; i++) {
                if (i > 0)
                    rule.append('|');
                rule.append(patterns[i]);
            }
            parameters.put(tag, String.valueOf(rule));
        }
    }

    private static boolean equalAttributes(IClasspathAttribute[] firstAttributes,
            IClasspathAttribute[] secondAttributes) {
        if (firstAttributes != secondAttributes) {
            if (firstAttributes == null)
                return false;
            int length = firstAttributes.length;
            if (secondAttributes == null || secondAttributes.length != length)
                return false;
            for (int i = 0; i < length; i++) {
                if (!firstAttributes[i].equals(secondAttributes[i]))
                    return false;
            }
        }
        return true;
    }

    private static boolean equalPatterns(IPath[] firstPatterns, IPath[] secondPatterns) {
        if (firstPatterns != secondPatterns) {
            if (firstPatterns == null)
                return false;
            int length = firstPatterns.length;
            if (secondPatterns == null || secondPatterns.length != length)
                return false;
            for (int i = 0; i < length; i++) {
                // compare toStrings instead of IPaths
                // since IPath.equals is specified to ignore trailing separators
                if (!firstPatterns[i].toString().equals(secondPatterns[i].toString()))
                    return false;
            }
        }
        return true;
    }

    /**
     * Returns the kind of a <code>PackageFragmentRoot</code> from its <code>String</code> form.
     */
    static int kindFromString(String kindStr) {

        if (kindStr.equalsIgnoreCase("prj")) //$NON-NLS-1$
            return IClasspathEntry.CPE_PROJECT;
        if (kindStr.equalsIgnoreCase("var")) //$NON-NLS-1$
            return IClasspathEntry.CPE_VARIABLE;
        if (kindStr.equalsIgnoreCase("con")) //$NON-NLS-1$
            return IClasspathEntry.CPE_CONTAINER;
        if (kindStr.equalsIgnoreCase("src")) //$NON-NLS-1$
            return IClasspathEntry.CPE_SOURCE;
        if (kindStr.equalsIgnoreCase("lib")) //$NON-NLS-1$
            return IClasspathEntry.CPE_LIBRARY;
        if (kindStr.equalsIgnoreCase("output")) //$NON-NLS-1$
            return ClasspathEntry.K_OUTPUT;
        return -1;
    }

    /**
     * Returns a <code>String</code> for the kind of a class path entry.
     */
    static String kindToString(int kind) {

        switch (kind) {
        case IClasspathEntry.CPE_PROJECT:
            return "src"; // backward compatibility //$NON-NLS-1$
        case IClasspathEntry.CPE_SOURCE:
            return "src"; //$NON-NLS-1$
        case IClasspathEntry.CPE_LIBRARY:
            return "lib"; //$NON-NLS-1$
        case IClasspathEntry.CPE_VARIABLE:
            return "var"; //$NON-NLS-1$
        case IClasspathEntry.CPE_CONTAINER:
            return "con"; //$NON-NLS-1$
        case ClasspathEntry.K_OUTPUT:
            return "output"; //$NON-NLS-1$
        default:
            return "unknown"; //$NON-NLS-1$
        }
    }

    /*
     * Backward compatibility: only accessible and non-accessible files are suported.
     */
    public static IAccessRule[] getAccessRules(IPath[] accessibleFiles, IPath[] nonAccessibleFiles) {
        int accessibleFilesLength = accessibleFiles == null ? 0 : accessibleFiles.length;
        int nonAccessibleFilesLength = nonAccessibleFiles == null ? 0 : nonAccessibleFiles.length;
        int length = accessibleFilesLength + nonAccessibleFilesLength;
        if (length == 0)
            return null;
        IAccessRule[] accessRules = new IAccessRule[length];
        for (int i = 0; i < accessibleFilesLength; i++) {
            accessRules[i] = JavaCore.newAccessRule(accessibleFiles[i], IAccessRule.K_ACCESSIBLE);
        }
        for (int i = 0; i < nonAccessibleFilesLength; i++) {
            accessRules[accessibleFilesLength + i] = JavaCore.newAccessRule(nonAccessibleFiles[i],
                    IAccessRule.K_NON_ACCESSIBLE);
        }
        return accessRules;
    }

    private static IJavaModelStatus validateLibraryContents(IPath path, IJavaProject project, String entryPathMsg) {
        JavaModelManager manager = JavaModelManager.getJavaModelManager();
        try {
            manager.verifyArchiveContent(path);
        } catch (CoreException e) {
            if (e.getStatus().getMessage() == Messages.status_IOException) {
                return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
                        Messages.bind(Messages.classpath_archiveReadError,
                                new String[] { entryPathMsg, project.getElementName() }));
            }
        }
        return JavaModelStatus.VERIFIED_OK;
    }

    //   /*
    //    * Resolves the ".." in the given path. Returns the given path if it contains no ".." segment.
    //    */
    //   public static IPath resolveDotDot(IPath reference, IPath path) {
    //      IPath newPath = null;
    //      IPath workspaceLocation = workspaceRoot.getLocation();
    //      if (reference == null || workspaceLocation.isPrefixOf(reference)) {
    //         for (int i = 0, length = path.segmentCount(); i < length; i++) {
    //            String segment = path.segment(i);
    //            if (DOT_DOT.equals(segment)) {
    //               if (newPath == null) {
    //                  if (i == 0) {
    //                     newPath = workspaceLocation;
    //                  } else {
    //                     newPath = path.removeFirstSegments(i);
    //                  }
    //               } else {
    //                  if (newPath.segmentCount() > 0) {
    //                     newPath = newPath.removeLastSegments(1);
    //                  } else {
    //                     newPath = workspaceLocation;
    //                  }
    //               }
    //            } else if (newPath != null) {
    //               if (newPath.equals(workspaceLocation) && workspaceRoot.getProject(segment).isAccessible()) {
    //                  newPath = new Path(segment).makeAbsolute();
    //               } else {
    //                  newPath = newPath.append(segment);
    //               }
    //            }
    //         }
    //      }
    //      else {
    //         for (int i = 0, length = path.segmentCount(); i < length; i++) {
    //            String segment = path.segment(i);
    //            if (DOT_DOT.equals(segment)) {
    //               if (newPath == null){
    //                  newPath = reference;
    //               }
    //               if (newPath.segmentCount() > 0) {
    //                  newPath = newPath.removeLastSegments(1);
    //                }
    //            } else if (newPath != null) {
    //               newPath = newPath.append(segment);
    //             }
    //         }
    //      }
    //      if (newPath == null)
    //         return path;
    //      return newPath;
    //   }

    public boolean combineAccessRules() {
        return this.combineAccessRules;
    }

    /**
     * Used to perform export/restriction propagation across referring projects/containers
     */
    public ClasspathEntry combineWith(ClasspathEntry referringEntry) {
        if (referringEntry == null)
            return this;
        if (referringEntry.isExported() || referringEntry.getAccessRuleSet() != null) {
            boolean combine = this.entryKind == CPE_SOURCE || referringEntry.combineAccessRules();
            return new ClasspathEntry(getContentKind(), getEntryKind(), getPath(), this.inclusionPatterns,
                    this.exclusionPatterns, getSourceAttachmentPath(), getSourceAttachmentRootPath(),
                    getOutputLocation(), referringEntry.isExported() || this.isExported, // duplicate container entry for tagging it as exported
                    combine(referringEntry.getAccessRules(), getAccessRules(), combine), this.combineAccessRules,
                    this.extraAttributes);
        }
        // no need to clone
        return this;
    }

    private IAccessRule[] combine(IAccessRule[] referringRules, IAccessRule[] rules, boolean combine) {
        if (!combine)
            return rules;
        if (rules == null || rules.length == 0)
            return referringRules;

        // concat access rules
        int referringRulesLength = referringRules.length;
        int accessRulesLength = rules.length;
        int rulesLength = referringRulesLength + accessRulesLength;
        IAccessRule[] result = new IAccessRule[rulesLength];
        System.arraycopy(referringRules, 0, result, 0, referringRulesLength);
        System.arraycopy(rules, 0, result, referringRulesLength, accessRulesLength);

        return result;
    }

    /*
     * Returns a char based representation of the exclusions patterns full path.
     */
    public char[][] fullExclusionPatternChars() {

        if (this.fullExclusionPatternChars == UNINIT_PATTERNS) {
            int length = this.exclusionPatterns.length;
            this.fullExclusionPatternChars = new char[length][];
            IPath prefixPath = this.path.removeTrailingSeparator();
            for (int i = 0; i < length; i++) {
                this.fullExclusionPatternChars[i] = prefixPath.append(this.exclusionPatterns[i]).toString()
                        .toCharArray();
            }
        }
        return this.fullExclusionPatternChars;
    }

    /*
     * Returns a char based representation of the exclusions patterns full path.
     */
    public char[][] fullInclusionPatternChars() {

        if (this.fullInclusionPatternChars == UNINIT_PATTERNS) {
            int length = this.inclusionPatterns.length;
            this.fullInclusionPatternChars = new char[length][];
            IPath prefixPath = this.path.removeTrailingSeparator();
            for (int i = 0; i < length; i++) {
                this.fullInclusionPatternChars[i] = prefixPath.append(this.inclusionPatterns[i]).toString()
                        .toCharArray();
            }
        }
        return this.fullInclusionPatternChars;
    }

    /**
     * Returns true if the given object is a classpath entry
     * with equivalent attributes.
     */
    public boolean equals(Object object) {
        if (this == object)
            return true;
        if (object instanceof ClasspathEntry) {
            ClasspathEntry otherEntry = (ClasspathEntry) object;

            if (this.contentKind != otherEntry.getContentKind())
                return false;

            if (this.entryKind != otherEntry.getEntryKind())
                return false;

            if (this.isExported != otherEntry.isExported())
                return false;

            if (!this.path.equals(otherEntry.getPath()))
                return false;

            IPath otherPath = otherEntry.getSourceAttachmentPath();
            if (this.sourceAttachmentPath == null) {
                if (otherPath != null)
                    return false;
            } else {
                if (!this.sourceAttachmentPath.equals(otherPath))
                    return false;
            }

            otherPath = otherEntry.getSourceAttachmentRootPath();
            if (this.sourceAttachmentRootPath == null) {
                if (otherPath != null)
                    return false;
            } else {
                if (!this.sourceAttachmentRootPath.equals(otherPath))
                    return false;
            }

            if (!equalPatterns(this.inclusionPatterns, otherEntry.getInclusionPatterns()))
                return false;
            if (!equalPatterns(this.exclusionPatterns, otherEntry.getExclusionPatterns()))
                return false;
            AccessRuleSet otherRuleSet = otherEntry.getAccessRuleSet();
            if (getAccessRuleSet() != null) {
                if (!getAccessRuleSet().equals(otherRuleSet))
                    return false;
            } else if (otherRuleSet != null)
                return false;
            if (this.combineAccessRules != otherEntry.combineAccessRules())
                return false;
            otherPath = otherEntry.getOutputLocation();
            if (this.specificOutputLocation == null) {
                if (otherPath != null)
                    return false;
            } else {
                if (!this.specificOutputLocation.equals(otherPath))
                    return false;
            }
            if (!equalAttributes(this.extraAttributes, otherEntry.getExtraAttributes()))
                return false;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @see org.eclipse.jdt.core.IClasspathEntry#getAccessRules()
     */
    public IAccessRule[] getAccessRules() {
        if (this.accessRuleSet == null)
            return NO_ACCESS_RULES;
        AccessRule[] rules = this.accessRuleSet.getAccessRules();
        int length = rules.length;
        if (length == 0)
            return NO_ACCESS_RULES;
        IAccessRule[] result = new IAccessRule[length];
        System.arraycopy(rules, 0, result, 0, length);
        return result;
    }

    public AccessRuleSet getAccessRuleSet() {
        return this.accessRuleSet;
    }

    /**
     * @see org.eclipse.jdt.core.IClasspathEntry
     */
    public int getContentKind() {
        return this.contentKind;
    }

    /**
     * @see org.eclipse.jdt.core.IClasspathEntry
     */
    public int getEntryKind() {
        return this.entryKind;
    }

    /**
     * @see org.eclipse.jdt.core.IClasspathEntry#getExclusionPatterns()
     */
    public IPath[] getExclusionPatterns() {
        return this.exclusionPatterns;
    }

    public IClasspathAttribute[] getExtraAttributes() {
        return this.extraAttributes;
    }

    /**
     * @see org.eclipse.jdt.core.IClasspathEntry#getExclusionPatterns()
     */
    public IPath[] getInclusionPatterns() {
        return this.inclusionPatterns;
    }

    /**
     * @see org.eclipse.jdt.core.IClasspathEntry#getOutputLocation()
     */
    public IPath getOutputLocation() {
        return this.specificOutputLocation;
    }

    /**
     * @see org.eclipse.jdt.core.IClasspathEntry
     */
    public IPath getPath() {
        return this.path;
    }

    /**
     * @see org.eclipse.jdt.core.IClasspathEntry
     */
    public IPath getSourceAttachmentPath() {
        return this.sourceAttachmentPath;
    }

    /**
     * @see org.eclipse.jdt.core.IClasspathEntry
     */
    public IPath getSourceAttachmentRootPath() {
        return this.sourceAttachmentRootPath;
    }

    public IClasspathEntry getReferencingEntry() {
        return this.referencingEntry;
    }

    /**
     * Returns the hash code for this classpath entry
     */
    public int hashCode() {
        return this.path.hashCode();
    }

    /**
     * @see org.eclipse.jdt.core.IClasspathEntry#isExported()
     */
    public boolean isExported() {
        return this.isExported;
    }

    public boolean isOptional() {
        for (int i = 0, length = this.extraAttributes.length; i < length; i++) {
            IClasspathAttribute attribute = this.extraAttributes[i];
            if (IClasspathAttribute.OPTIONAL.equals(attribute.getName()) && "true".equals(attribute.getValue())) //$NON-NLS-1$
                return true;
        }
        return false;
    }

    public String getSourceAttachmentEncoding() {
        for (int i = 0, length = this.extraAttributes.length; i < length; i++) {
            IClasspathAttribute attribute = this.extraAttributes[i];
            if (IClasspathAttribute.SOURCE_ATTACHMENT_ENCODING.equals(attribute.getName()))
                return attribute.getValue();
        }
        return null;
    }

    /**
     * Returns a printable representation of this classpath entry.
     */
    public String toString() {
        StringBuffer buffer = new StringBuffer();
        //      Object target = JavaModel.getTarget(getPath(), true);
        //      if (target instanceof File)
        buffer.append(getPath().toOSString());
        //      else
        //         buffer.append(String.valueOf(getPath()));
        buffer.append('[');
        switch (getEntryKind()) {
        case IClasspathEntry.CPE_LIBRARY:
            buffer.append("CPE_LIBRARY"); //$NON-NLS-1$
            break;
        case IClasspathEntry.CPE_PROJECT:
            buffer.append("CPE_PROJECT"); //$NON-NLS-1$
            break;
        case IClasspathEntry.CPE_SOURCE:
            buffer.append("CPE_SOURCE"); //$NON-NLS-1$
            break;
        case IClasspathEntry.CPE_VARIABLE:
            buffer.append("CPE_VARIABLE"); //$NON-NLS-1$
            break;
        case IClasspathEntry.CPE_CONTAINER:
            buffer.append("CPE_CONTAINER"); //$NON-NLS-1$
            break;
        }
        buffer.append("]["); //$NON-NLS-1$
        switch (getContentKind()) {
        case IPackageFragmentRoot.K_BINARY:
            buffer.append("K_BINARY"); //$NON-NLS-1$
            break;
        case IPackageFragmentRoot.K_SOURCE:
            buffer.append("K_SOURCE"); //$NON-NLS-1$
            break;
        case ClasspathEntry.K_OUTPUT:
            buffer.append("K_OUTPUT"); //$NON-NLS-1$
            break;
        }
        buffer.append(']');
        if (getSourceAttachmentPath() != null) {
            buffer.append("[sourcePath:"); //$NON-NLS-1$
            buffer.append(getSourceAttachmentPath());
            buffer.append(']');
        }
        if (getSourceAttachmentRootPath() != null) {
            buffer.append("[rootPath:"); //$NON-NLS-1$
            buffer.append(getSourceAttachmentRootPath());
            buffer.append(']');
        }
        buffer.append("[isExported:"); //$NON-NLS-1$
        buffer.append(this.isExported);
        buffer.append(']');
        IPath[] patterns = this.inclusionPatterns;
        int length;
        if ((length = patterns == null ? 0 : patterns.length) > 0) {
            buffer.append("[including:"); //$NON-NLS-1$
            for (int i = 0; i < length; i++) {
                buffer.append(patterns[i]);
                if (i != length - 1) {
                    buffer.append('|');
                }
            }
            buffer.append(']');
        }
        patterns = this.exclusionPatterns;
        if ((length = patterns == null ? 0 : patterns.length) > 0) {
            buffer.append("[excluding:"); //$NON-NLS-1$
            for (int i = 0; i < length; i++) {
                buffer.append(patterns[i]);
                if (i != length - 1) {
                    buffer.append('|');
                }
            }
            buffer.append(']');
        }
        if (this.accessRuleSet != null) {
            buffer.append('[');
            buffer.append(this.accessRuleSet.toString(false/*on one line*/));
            buffer.append(']');
        }
        if (this.entryKind == CPE_PROJECT) {
            buffer.append("[combine access rules:"); //$NON-NLS-1$
            buffer.append(this.combineAccessRules);
            buffer.append(']');
        }
        if (getOutputLocation() != null) {
            buffer.append("[output:"); //$NON-NLS-1$
            buffer.append(getOutputLocation());
            buffer.append(']');
        }
        if ((length = this.extraAttributes == null ? 0 : this.extraAttributes.length) > 0) {
            buffer.append("[attributes:"); //$NON-NLS-1$
            for (int i = 0; i < length; i++) {
                buffer.append(this.extraAttributes[i]);
                if (i != length - 1) {
                    buffer.append(',');
                }
            }
            buffer.append(']');
        }
        return buffer.toString();
    }

    /*
     * Read the Class-Path clause of the manifest of the jar pointed by this entry, and return
     * the corresponding library entries.
     */
    public ClasspathEntry[] resolvedChainedLibraries() {
        IPath[] paths = resolvedChainedLibraries(getPath());
        int length = paths.length;
        if (length == 0)
            return NO_ENTRIES;
        ClasspathEntry[] result = new ClasspathEntry[length];
        for (int i = 0; i < length; i++) {
            // Chained(referenced) libraries can have their own attachment path. Hence, set them to null
            result[i] = new ClasspathEntry(getContentKind(), getEntryKind(), paths[i], this.inclusionPatterns,
                    this.exclusionPatterns, null, null, getOutputLocation(), this, this.isExported,
                    getAccessRules(), this.combineAccessRules, NO_EXTRA_ATTRIBUTES);
        }
        return result;
    }

    //   public ClasspathEntry resolvedDotDot(IPath reference) {
    //      IPath resolvedPath = resolveDotDot(reference, this.path);
    //      if (resolvedPath == this.path)
    //         return this;
    //      return new ClasspathEntry(
    //                     getContentKind(),
    //                     getEntryKind(),
    //                     resolvedPath,
    //                     this.inclusionPatterns,
    //                     this.exclusionPatterns,
    //                     getSourceAttachmentPath(),
    //                     getSourceAttachmentRootPath(),
    //                     getOutputLocation(),
    //                     this.getReferencingEntry(),
    //                     this.isExported,
    //                     getAccessRules(),
    //                     this.combineAccessRules,
    //                     this.extraAttributes);
    //   }

    /**
     * Answers an ID which is used to distinguish entries during package
     * fragment root computations
     */
    public String rootID() {

        if (this.rootID == null) {
            switch (this.entryKind) {
            case IClasspathEntry.CPE_LIBRARY:
                this.rootID = "[LIB]" + this.path; //$NON-NLS-1$
                break;
            case IClasspathEntry.CPE_PROJECT:
                this.rootID = "[PRJ]" + this.path; //$NON-NLS-1$
                break;
            case IClasspathEntry.CPE_SOURCE:
                this.rootID = "[SRC]" + this.path; //$NON-NLS-1$
                break;
            case IClasspathEntry.CPE_VARIABLE:
                this.rootID = "[VAR]" + this.path; //$NON-NLS-1$
                break;
            case IClasspathEntry.CPE_CONTAINER:
                this.rootID = "[CON]" + this.path; //$NON-NLS-1$
                break;
            default:
                this.rootID = ""; //$NON-NLS-1$
                break;
            }
        }
        return this.rootID;
    }

    /**
     * @see org.eclipse.jdt.core.IClasspathEntry
     * @deprecated
     */
    public IClasspathEntry getResolvedEntry() {

        return JavaCore.getResolvedClasspathEntry(this);
    }

    /**
     * This function computes the URL of the index location for this classpath entry. It returns null if the URL is
     * invalid.
     */
    public URL getLibraryIndexLocation() {
        switch (getEntryKind()) {
        case IClasspathEntry.CPE_LIBRARY:
        case IClasspathEntry.CPE_VARIABLE:
            break;
        default:
            return null;
        }
        if (this.extraAttributes == null)
            return null;
        for (int i = 0; i < this.extraAttributes.length; i++) {
            IClasspathAttribute attrib = this.extraAttributes[i];
            if (IClasspathAttribute.INDEX_LOCATION_ATTRIBUTE_NAME.equals(attrib.getName())) {
                String value = attrib.getValue();
                try {
                    return new URL(value);
                } catch (MalformedURLException e) {
                    return null;
                }
            }
        }
        return null;
    }

    public boolean ignoreOptionalProblems() {
        if (this.entryKind == IClasspathEntry.CPE_SOURCE) {
            for (int i = 0; i < this.extraAttributes.length; i++) {
                IClasspathAttribute attrib = this.extraAttributes[i];
                if (IClasspathAttribute.IGNORE_OPTIONAL_PROBLEMS.equals(attrib.getName())) {
                    return "true".equals(attrib.getValue()); //$NON-NLS-1$
                }
            }
        }
        return false;
    }

    public static class AssertionFailedException extends RuntimeException {

        private static final long serialVersionUID = -171699380721189572L;

        public AssertionFailedException(String message) {
            super(message);
        }
    }

    //   /**
    //    * Validate a given classpath and output location for a project, using the following rules:
    //    * <ul>
    //    *   <li> Classpath entries cannot collide with each other; that is, all entry paths must be unique.
    //    *   <li> The project output location path cannot be null, must be absolute and located inside the project.
    //    *   <li> Specific output locations (specified on source entries) can be null, if not they must be located inside the project,
    //    *   <li> A project entry cannot refer to itself directly (that is, a project cannot prerequisite itself).
    //    *   <li> Classpath entries or output locations cannot coincidate or be nested in each other, except for the following scenario listed
    // below:
    //    *      <ul><li> A source folder can coincidate with its own output location, in which case this output can then contain library
    // archives.
    //    *                     However, a specific output location cannot coincidate with any library or a distinct source folder than the one
    //     *                     referring to it. </li>
    //    *              <li> A source/library folder can be nested in any source folder as long as the nested folder is excluded from the
    // enclosing one. </li>
    //    *          <li> An output location can be nested in a source folder, if the source folder coincidates with the project itself, or if
    // the output
    //    *                location is excluded from the source folder. </li>
    //    *      </ul>
    //    * </ul>
    //    *
    //    *  Note that the classpath entries are not validated automatically. Only bound variables or containers are considered
    //    *  in the checking process (this allows to perform a consistency check on a classpath which has references to
    //    *  yet non existing projects, folders, ...).
    //    *  <p>
    //    *  This validation is intended to anticipate classpath issues prior to assigning it to a project. In particular, it will automatically
    //    *  be performed during the classpath setting operation (if validation fails, the classpath setting will not complete).
    //    *  <p>
    //    * @param javaProject the given java project
    //    * @param rawClasspath a given classpath
    //    * @param projectOutputLocation a given output location
    //    * @return a status object with code <code>IStatus.OK</code> if
    //    *      the given classpath and output location are compatible, otherwise a status
    //    *      object indicating what is wrong with the classpath or output location
    //    */
    //   public static IJavaModelStatus validateClasspath(IJavaProject javaProject, IClasspathEntry[] rawClasspath, IPath
    // projectOutputLocation) {
    //
    //      IProject project = javaProject.getProject();
    //      IPath projectPath= project.getFullPath();
    //      String projectName = javaProject.getElementName();
    //
    //      /* validate output location */
    //      if (projectOutputLocation == null) {
    //         return new JavaModelStatus(IJavaModelStatusConstants.NULL_PATH);
    //      }
    //      if (projectOutputLocation.isAbsolute()) {
    //         if (!projectPath.isPrefixOf(projectOutputLocation)) {
    //            return new JavaModelStatus(IJavaModelStatusConstants.PATH_OUTSIDE_PROJECT, javaProject, projectOutputLocation.toString());
    //         }
    //      } else {
    //         return new JavaModelStatus(IJavaModelStatusConstants.RELATIVE_PATH, projectOutputLocation);
    //      }
    //
    //      boolean hasSource = false;
    //      boolean hasLibFolder = false;
    //
    //
    //      // tolerate null path, it will be reset to default
    //      if (rawClasspath == null)
    //         return JavaModelStatus.VERIFIED_OK;
    //
    //      // check duplicate entries on raw classpath only (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=175226 )
    //      int rawLength = rawClasspath.length;
    //      HashSet pathes = new HashSet(rawLength);
    //      for (int i = 0 ; i < rawLength; i++) {
    //         IPath entryPath = rawClasspath[i].getPath();
    //         if (!pathes.add(entryPath)){
    //            String entryPathMsg = projectName.equals(entryPath.segment(0)) ? entryPath.removeFirstSegments(1).toString() : entryPath
    // .makeRelative().toString();
    //            return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION, Messages
    //                        .bind(Messages.classpath_duplicateEntryPath, new String[]{entryPathMsg, projectName}));
    //         }
    //      }
    //
    //      // retrieve resolved classpath
    //      IClasspathEntry[] classpath;
    //      try {
    //         // don't resolve chained libraries: see https://bugs.eclipse.org/bugs/show_bug.cgi?id=259685
    //         classpath = ((JavaProject)javaProject).resolveClasspath(rawClasspath, false/*don't use previous session*/, false/*don't
    // resolve chained libraries*/).resolvedClasspath;
    //      } catch(JavaModelException e){
    //         return e.getJavaModelStatus();
    //      }
    //      int length = classpath.length;
    //
    //      int outputCount = 1;
    //      IPath[] outputLocations   = new IPath[length+1];
    //      boolean[] allowNestingInOutputLocations = new boolean[length+1];
    //      outputLocations[0] = projectOutputLocation;
    //
    //      // retrieve and check output locations
    //      IPath potentialNestedOutput = null; // for error reporting purpose
    //      int sourceEntryCount = 0;
    //      boolean disableExclusionPatterns = JavaCore.DISABLED.equals(javaProject.getOption(JavaCore
    // .CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, true));
    //      boolean disableCustomOutputLocations = JavaCore.DISABLED.equals(javaProject.getOption(JavaCore
    // .CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, true));
    //
    //      for (int i = 0 ; i < length; i++) {
    //         IClasspathEntry resolvedEntry = classpath[i];
    //         if (disableExclusionPatterns &&
    //                 ((resolvedEntry.getInclusionPatterns() != null && resolvedEntry.getInclusionPatterns().length > 0)
    //                 || (resolvedEntry.getExclusionPatterns() != null && resolvedEntry.getExclusionPatterns().length > 0))) {
    //            return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_EXCLUSION_PATTERNS, javaProject, resolvedEntry.getPath());
    //         }
    //         switch(resolvedEntry.getEntryKind()){
    //            case IClasspathEntry.CPE_SOURCE :
    //               sourceEntryCount++;
    //
    //               IPath customOutput;
    //               if ((customOutput = resolvedEntry.getOutputLocation()) != null) {
    //
    //                  if (disableCustomOutputLocations) {
    //                     return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS, javaProject,
    // resolvedEntry.getPath());
    //                  }
    //                  // ensure custom output is in project
    //                  if (customOutput.isAbsolute()) {
    //                     if (!javaProject.getPath().isPrefixOf(customOutput)) {
    //                        return new JavaModelStatus(IJavaModelStatusConstants.PATH_OUTSIDE_PROJECT, javaProject, customOutput
    // .toString());
    //                     }
    //                  } else {
    //                     return new JavaModelStatus(IJavaModelStatusConstants.RELATIVE_PATH, customOutput);
    //                  }
    //
    //                  // ensure custom output doesn't conflict with other outputs
    //                  // check exact match
    //                  if (Util.indexOfMatchingPath(customOutput, outputLocations, outputCount) != -1) {
    //                     continue; // already found
    //                  }
    //                  // accumulate all outputs, will check nesting once all available (to handle ordering issues)
    //                  outputLocations[outputCount++] = customOutput;
    //               }
    //         }
    //      }
    //      // check nesting across output locations
    //      for (int i = 1 /*no check for default output*/ ; i < outputCount; i++) {
    //         IPath customOutput = outputLocations[i];
    //         int index;
    //         // check nesting
    //         if ((index = Util.indexOfEnclosingPath(customOutput, outputLocations, outputCount)) != -1 && index != i) {
    //            if (index == 0) {
    //               // custom output is nested in project's output: need to check if all source entries have a custom
    //               // output before complaining
    //               if (potentialNestedOutput == null) potentialNestedOutput = customOutput;
    //            } else {
    //               return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                            .bind(Messages.classpath_cannotNestOutputInOutput,
    //                                  new String[]{customOutput.makeRelative().toString(), outputLocations[index].makeRelative().toString()
    // }));
    //            }
    //         }
    //      }
    //      // allow custom output nesting in project's output if all source entries have a custom output
    //      if (sourceEntryCount <= outputCount-1) {
    //          allowNestingInOutputLocations[0] = true;
    //      } else if (potentialNestedOutput != null) {
    //         return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                    .bind(Messages.classpath_cannotNestOutputInOutput,
    //                          new String[]{potentialNestedOutput.makeRelative().toString(), outputLocations[0].makeRelative().toString()}));
    //      }
    //
    //      for (int i = 0 ; i < length; i++) {
    //         IClasspathEntry resolvedEntry = classpath[i];
    //         IPath path = resolvedEntry.getPath();
    //         int index;
    //         switch(resolvedEntry.getEntryKind()){
    //
    //            case IClasspathEntry.CPE_SOURCE :
    //               hasSource = true;
    //               if ((index = Util.indexOfMatchingPath(path, outputLocations, outputCount)) != -1){
    //                  allowNestingInOutputLocations[index] = true;
    //               }
    //               break;
    //
    //            case IClasspathEntry.CPE_LIBRARY:
    //               Object target = JavaModel.getTarget(path, false/*don't check resource existence*/);
    //               hasLibFolder |= target instanceof IContainer;
    //               if ((index = Util.indexOfMatchingPath(path, outputLocations, outputCount)) != -1){
    //                  allowNestingInOutputLocations[index] = true;
    //               }
    //               break;
    //         }
    //      }
    //      if (!hasSource && !hasLibFolder) { // if no source and no lib folder, then allowed
    //         for (int i = 0; i < outputCount; i++) allowNestingInOutputLocations[i] = true;
    //      }
    //
    //      // check all entries
    //      for (int i = 0 ; i < length; i++) {
    //         IClasspathEntry entry = classpath[i];
    //         if (entry == null) continue;
    //         IPath entryPath = entry.getPath();
    //         int kind = entry.getEntryKind();
    //
    //         // no further check if entry coincidates with project or output location
    //         if (entryPath.equals(projectPath)){
    //            // complain if self-referring project entry
    //            if (kind == IClasspathEntry.CPE_PROJECT){
    //               return new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, Messages
    //                            .bind(Messages.classpath_cannotReferToItself, entryPath.makeRelative().toString()));
    //            }
    //            // tolerate nesting output in src if src==prj
    //            continue;
    //         }
    //
    //         // allow nesting source entries in each other as long as the outer entry excludes the inner one
    //         if (kind == IClasspathEntry.CPE_SOURCE
    //               || (kind == IClasspathEntry.CPE_LIBRARY && (JavaModel
    //                    .getTarget(entryPath, false/*don't check existence*/) instanceof IContainer))) {
    //            for (int j = 0; j < classpath.length; j++){
    //               IClasspathEntry otherEntry = classpath[j];
    //               if (otherEntry == null) continue;
    //               int otherKind = otherEntry.getEntryKind();
    //               IPath otherPath = otherEntry.getPath();
    //               if (entry != otherEntry
    //                  && (otherKind == IClasspathEntry.CPE_SOURCE
    //                        || (otherKind == IClasspathEntry.CPE_LIBRARY
    //                              && (JavaModel.getTarget(otherPath, false/*don't check existence*/) instanceof IContainer)))) {
    //                  char[][] inclusionPatterns, exclusionPatterns;
    //                  if (otherPath.isPrefixOf(entryPath)
    //                        && !otherPath.equals(entryPath)
    //                        && !Util.isExcluded(entryPath.append("*"), inclusionPatterns =
    //                                ((ClasspathEntry)otherEntry).fullInclusionPatternChars(), exclusionPatterns =
    //                                                            ((ClasspathEntry)otherEntry)
    //                                                                    .fullExclusionPatternChars(), false)) { //$NON-NLS-1$
    //                     String exclusionPattern = entryPath.removeFirstSegments(otherPath.segmentCount()).segment(0);
    //                     if (Util.isExcluded(entryPath, inclusionPatterns, exclusionPatterns, false)) {
    //                        return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                        .bind(Messages.classpath_mustEndWithSlash,
    //                                              new String[]{exclusionPattern, entryPath.makeRelative().toString()}));
    //                     } else {
    //                        if (otherKind == IClasspathEntry.CPE_SOURCE) {
    //                           exclusionPattern += '/';
    //                           if (!disableExclusionPatterns) {
    //                              return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                                .bind(Messages.classpath_cannotNestEntryInEntry,
    //                                                      new String[]{entryPath.makeRelative().toString(),
    //                                                                   otherEntry.getPath().makeRelative().toString(), exclusionPattern}));
    //                           } else {
    //                              return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                                .bind(Messages.classpath_cannotNestEntryInEntryNoExclusion,
    //                                                      new String[]{entryPath.makeRelative().toString(),
    //                                                                   otherEntry.getPath().makeRelative().toString(), exclusionPattern}));
    //                           }
    //                        } else {
    //                           return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                            .bind(Messages.classpath_cannotNestEntryInLibrary,
    //                                                  new String[]{entryPath.makeRelative().toString(),
    //                                                               otherEntry.getPath().makeRelative().toString()}));
    //                        }
    //                     }
    //                  }
    //               }
    //            }
    //         }
    //
    //         // prevent nesting output location inside entry unless enclosing is a source entry which explicitly exclude the output location
    //         char[][] inclusionPatterns = ((ClasspathEntry)entry).fullInclusionPatternChars();
    //         char[][] exclusionPatterns = ((ClasspathEntry)entry).fullExclusionPatternChars();
    //         for (int j = 0; j < outputCount; j++){
    //            IPath currentOutput = outputLocations[j];
    //            if (entryPath.equals(currentOutput)) continue;
    //            if (entryPath.isPrefixOf(currentOutput)) {
    //                if (kind != IClasspathEntry.CPE_SOURCE || !Util.isExcluded(currentOutput, inclusionPatterns, exclusionPatterns,
    // true)) {
    //                  return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                .bind(Messages.classpath_cannotNestOutputInEntry,
    //                                      new String[]{currentOutput.makeRelative().toString(), entryPath.makeRelative().toString()}));
    //                }
    //            }
    //         }
    //
    //         // prevent nesting entry inside output location - when distinct from project or a source folder
    //         for (int j = 0; j < outputCount; j++){
    //            if (allowNestingInOutputLocations[j]) continue;
    //            IPath currentOutput = outputLocations[j];
    //            if (currentOutput.isPrefixOf(entryPath)) {
    //               return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                            .bind(Messages.classpath_cannotNestEntryInOutput,
    //                                  new String[]{entryPath.makeRelative().toString(), currentOutput.makeRelative().toString()}));
    //            }
    //         }
    //      }
    //      // ensure that no specific output is coincidating with another source folder (only allowed if matching current source folder)
    //      // 36465 - for 2.0 backward compatibility, only check specific output locations (the default can still coincidate)
    //      // perform one separate iteration so as to not take precedence over previously checked scenarii (in particular should
    //      // diagnose nesting source folder issue before this one, for example, [src]"Project/", [src]"Project/source/" and
    // output="Project/" should
    //      // first complain about missing exclusion pattern
    //      IJavaModelStatus cachedStatus = null;
    //      for (int i = 0 ; i < length; i++) {
    //         IClasspathEntry entry = classpath[i];
    //         if (entry == null) continue;
    //         IPath entryPath = entry.getPath();
    //         int kind = entry.getEntryKind();
    //
    //         // Build some common strings for status message
    //         boolean isProjectRelative = projectName.equals(entryPath.segment(0));
    //         String entryPathMsg = isProjectRelative ? entryPath.removeFirstSegments(1).toString() : entryPath.makeRelative().toString();
    //
    //         if (kind == IClasspathEntry.CPE_SOURCE) {
    //            IPath output = entry.getOutputLocation();
    //            if (output == null) output = projectOutputLocation; // if no specific output, still need to check using default output
    // (this line would check default output)
    //            for (int j = 0; j < length; j++) {
    //               IClasspathEntry otherEntry = classpath[j];
    //               if (otherEntry == entry) continue;
    //
    //               switch (otherEntry.getEntryKind()) {
    //                  case IClasspathEntry.CPE_SOURCE :
    //                     // Bug 287164 : Report errors of overlapping output locations only if the user sets the corresponding
    // preference.
    //                     // The check is required for backward compatibility with bug-fix 36465.
    //                     String option = javaProject.getOption(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, true);
    //                     if (otherEntry.getPath().equals(output)
    //                           && !JavaCore.IGNORE.equals(option)) {
    //                        boolean opStartsWithProject = projectName.equals(otherEntry.getPath().segment(0));
    //                        String otherPathMsg = opStartsWithProject ? otherEntry.getPath().removeFirstSegments(1).toString() :
    // otherEntry.getPath().makeRelative().toString();
    //                        if (JavaCore.ERROR.equals(option)) {
    //                           return new JavaModelStatus(IStatus.ERROR, IJavaModelStatusConstants
    // .OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE,
    //                                 Messages.bind(Messages.classpath_cannotUseDistinctSourceFolderAsOutput, new String[]{
    //                                                    entryPathMsg, otherPathMsg, projectName}));
    //                        }
    //                        if (cachedStatus == null) {
    //                           // Note that the isOK() is being overridden to return true. This is an exceptional scenario
    //                           cachedStatus = new JavaModelStatus(IStatus.OK, IJavaModelStatusConstants
    // .OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE,
    //                              Messages.bind(Messages.classpath_cannotUseDistinctSourceFolderAsOutput, new String[]{
    //                                                entryPathMsg, otherPathMsg, projectName})){
    //                              public boolean isOK() {
    //                                 return true;
    //                              }
    //                           };
    //                        }
    //                     }
    //                     break;
    //                  case IClasspathEntry.CPE_LIBRARY :
    //                     if (output != projectOutputLocation && otherEntry.getPath().equals(output)) {
    //                        boolean opStartsWithProject = projectName.equals(otherEntry.getPath().segment(0));
    //                        String otherPathMsg = opStartsWithProject ? otherEntry.getPath().removeFirstSegments(1).toString() :
    //                                                      otherEntry.getPath().makeRelative().toString();
    //                        return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                        .bind(Messages.classpath_cannotUseLibraryAsOutput,
    //                                              new String[]{entryPathMsg, otherPathMsg, projectName}));
    //                     }
    //               }
    //            }
    //         }
    //      }
    //
    //      // NOTE: The above code that checks for IJavaModelStatusConstants.OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, can be configured to
    // return
    //      // a WARNING status and hence should be at the end of this validation method. Any other code that might return a more severe ERROR
    //      // should be
    //      // inserted before the mentioned code.
    //      if (cachedStatus != null) return cachedStatus;
    //
    //      return JavaModelStatus.VERIFIED_OK;
    //   }
    //
    //   /**
    //    * Returns a Java model status describing the problem related to this classpath entry if any,
    //    * a status object with code <code>IStatus.OK</code> if the entry is fine (that is, if the
    //    * given classpath entry denotes a valid element to be referenced onto a classpath).
    //    *
    //    * @param project the given java project
    //    * @param entry the given classpath entry
    //    * @param checkSourceAttachment a flag to determine if source attachment should be checked
    //    * @param referredByContainer flag indicating whether the given entry is referred by a classpath container
    //    * @return a java model status describing the problem related to this classpath entry if any, a status object with code <code>IStatus
    // .OK</code> if the entry is fine
    //    */
    //   public static IJavaModelStatus validateClasspathEntry(IJavaProject project, IClasspathEntry entry, boolean checkSourceAttachment,
    // boolean referredByContainer){
    //      if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
    //         JavaModelManager.getJavaModelManager().removeFromInvalidArchiveCache(entry.getPath());
    //      }
    //      IJavaModelStatus status = validateClasspathEntry(project, entry, null, checkSourceAttachment, referredByContainer);
    //      // https://bugs.eclipse.org/bugs/show_bug.cgi?id=171136 and https://bugs.eclipse.org/bugs/show_bug.cgi?id=300136
    //      // Ignore class path errors from optional entries.
    //      int statusCode = status.getCode();
    //      if ( (statusCode == IJavaModelStatusConstants.INVALID_CLASSPATH ||
    //            statusCode == IJavaModelStatusConstants.CP_CONTAINER_PATH_UNBOUND ||
    //            statusCode == IJavaModelStatusConstants.CP_VARIABLE_PATH_UNBOUND ||
    //            statusCode == IJavaModelStatusConstants.INVALID_PATH) &&
    //            ((ClasspathEntry) entry).isOptional())
    //         return JavaModelStatus.VERIFIED_OK;
    //      return status;
    //   }

    //   private static IJavaModelStatus validateClasspathEntry(IJavaProject project, IClasspathEntry entry, IClasspathContainer
    // entryContainer, boolean checkSourceAttachment, boolean referredByContainer){
    //
    //      IPath path = entry.getPath();
    //
    //      // Build some common strings for status message
    //      String projectName = project.getElementName();
    //      String entryPathMsg = projectName.equals(path.segment(0)) ? path.removeFirstSegments(1).makeRelative().toString() : path
    // .toString();
    //
    //      switch(entry.getEntryKind()){
    //
    //         // container entry check
    //         case IClasspathEntry.CPE_CONTAINER :
    //            if (path.segmentCount() >= 1){
    //               try {
    //                  IJavaModelStatus status = null;
    //                  // Validate extra attributes
    //                  IClasspathAttribute[] extraAttributes = entry.getExtraAttributes();
    //                  if (extraAttributes != null) {
    //                     int length = extraAttributes.length;
    //                     HashSet set = new HashSet(length);
    //                     for (int i=0; i<length; i++) {
    //                        String attName = extraAttributes[i].getName();
    //                        if (!set.add(attName)) {
    //                           status = new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION, Messages
    //                                            .bind(Messages.classpath_duplicateEntryExtraAttribute,
    //                                                  new String[]{attName, entryPathMsg, projectName}));
    //                           break;
    //                        }
    //                     }
    //                  }
    //                  IClasspathContainer container = JavaModelManager.getJavaModelManager().getClasspathContainer(path, project);
    //                  // container retrieval is performing validation check on container entry kinds.
    //                  if (container == null) {
    //                     if (status != null)
    //                        return status;
    //                     return new JavaModelStatus(IJavaModelStatusConstants.CP_CONTAINER_PATH_UNBOUND, project, path);
    //                  } else if (container == JavaModelManager.CONTAINER_INITIALIZATION_IN_PROGRESS) {
    //                     // don't create a marker if initialization is in progress (case of cp initialization batching)
    //                     return JavaModelStatus.VERIFIED_OK;
    //                  }
    //                  IClasspathEntry[] containerEntries = container.getClasspathEntries();
    //                  if (containerEntries != null){
    //                     for (int i = 0, length = containerEntries.length; i < length; i++){
    //                        IClasspathEntry containerEntry = containerEntries[i];
    //                        int kind = containerEntry == null ? 0 : containerEntry.getEntryKind();
    //                        if (containerEntry == null
    //                           || kind == IClasspathEntry.CPE_SOURCE
    //                           || kind == IClasspathEntry.CPE_VARIABLE
    //                           || kind == IClasspathEntry.CPE_CONTAINER){
    //                              return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CP_CONTAINER_ENTRY, project, path);
    //                        }
    //                        IJavaModelStatus containerEntryStatus = validateClasspathEntry(project, containerEntry, container,
    // checkSourceAttachment, true/*referred by container*/);
    //                        if (!containerEntryStatus.isOK()){
    //                           return containerEntryStatus;
    //                        }
    //                     }
    //                  }
    //               } catch(JavaModelException e){
    //                  return new JavaModelStatus(e);
    //               }
    //            } else {
    //               return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                            .bind(Messages.classpath_illegalContainerPath, new String[]{entryPathMsg, projectName}));
    //            }
    //            break;
    //
    //         // variable entry check
    //         case IClasspathEntry.CPE_VARIABLE :
    //            if (path.segmentCount() >= 1){
    //               try {
    //                  entry = JavaCore.getResolvedClasspathEntry(entry);
    //               } catch (AssertionFailedException e) {
    //                  // Catch the assertion failure and throw java model exception instead
    //                  // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=55992
    //                  return new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, e.getMessage());
    //               }
    //               if (entry == null){
    //                  return new JavaModelStatus(IJavaModelStatusConstants.CP_VARIABLE_PATH_UNBOUND, project, path);
    //               }
    //
    //               // get validation status
    //               IJavaModelStatus status = validateClasspathEntry(project, entry, null, checkSourceAttachment, false/*not referred by
    // container*/);
    //               if (!status.isOK()) return status;
    //
    //               // return deprecation status if any
    //               String variableName = path.segment(0);
    //               String deprecatedMessage = JavaCore.getClasspathVariableDeprecationMessage(variableName);
    //               if (deprecatedMessage != null) {
    //                  return new JavaModelStatus(IStatus.WARNING, IJavaModelStatusConstants.DEPRECATED_VARIABLE, project, path,
    // deprecatedMessage);
    //               }
    //               return status;
    //            } else {
    //               return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                            .bind(Messages.classpath_illegalVariablePath, new String[]{entryPathMsg, projectName}));
    //            }
    //
    //         // library entry check
    //         case IClasspathEntry.CPE_LIBRARY :
    //            path = ClasspathEntry.resolveDotDot(project.getProject().getLocation(), path);
    //
    //            // do not validate entries from Class-Path: in manifest
    //            // (these entries are considered optional since the user cannot act on them)
    //            // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=252392
    //
    //            String containerInfo = null;
    //            if (entryContainer != null) {
    //               if (entryContainer instanceof UserLibraryClasspathContainer) {
    //                  containerInfo = Messages.bind(Messages.classpath_userLibraryInfo, new String[]{entryContainer.getDescription()});
    //               } else {
    //                  containerInfo = Messages.bind(Messages.classpath_containerInfo, new String[]{entryContainer.getDescription()});
    //               }
    //            }
    //            IJavaModelStatus status = validateLibraryEntry(path, project, containerInfo, checkSourceAttachment ? entry
    // .getSourceAttachmentPath() : null, entryPathMsg);
    //            // https://bugs.eclipse.org/bugs/show_bug.cgi?id=171136, ignore class path errors from optional entries
    //            if (status.getCode() == IJavaModelStatusConstants.INVALID_CLASSPATH && ((ClasspathEntry) entry).isOptional())
    //               status = JavaModelStatus.VERIFIED_OK;
    //            if (!status.isOK())
    //               return status;
    //            break;
    //
    //         // project entry check
    //         case IClasspathEntry.CPE_PROJECT :
    //            if (path.isAbsolute() && path.segmentCount() == 1) {
    //               IProject prereqProjectRsc = workspaceRoot.getProject(path.segment(0));
    //               IJavaProject prereqProject = JavaCore.create(prereqProjectRsc);
    //               try {
    //                  if (!prereqProjectRsc.exists() || !prereqProjectRsc.hasNature(JavaCore.NATURE_ID)){
    //                     return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                    .bind(Messages.classpath_unboundProject, new String[]{path.segment(0), projectName}));
    //                  }
    //                  if (!prereqProjectRsc.isOpen()){
    //                     return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                    .bind(Messages.classpath_closedProject, new String[]{path.segment(0)}));
    //                  }
    //                  if (!JavaCore.IGNORE.equals(project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true))) {
    //                     long projectTargetJDK = CompilerOptions
    //                                    .versionToJdkLevel(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
    //                     long prereqProjectTargetJDK = CompilerOptions
    //                                    .versionToJdkLevel(prereqProject.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
    //                     if (prereqProjectTargetJDK > projectTargetJDK) {
    //                        return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL,
    //                              project, path,
    //                              Messages.bind(Messages.classpath_incompatibleLibraryJDKLevel,
    //                                                      new String[]{
    //                                                              project.getElementName(),
    //                                                              CompilerOptions.versionFromJdkLevel(projectTargetJDK),
    //                                                              path.makeRelative().toString(),
    //                                                              CompilerOptions.versionFromJdkLevel(prereqProjectTargetJDK)}));
    //                     }
    //                  }
    //               } catch (CoreException e){
    //                  return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                .bind(Messages.classpath_unboundProject, new String[]{path.segment(0), projectName}));
    //               }
    //            } else {
    //               return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                            .bind(Messages.classpath_illegalProjectPath, new String[]{path.toString(), projectName}));
    //            }
    //            break;
    //
    //         // project source folder
    //         case IClasspathEntry.CPE_SOURCE :
    //            if (((entry.getInclusionPatterns() != null && entry.getInclusionPatterns().length > 0)
    //                  || (entry.getExclusionPatterns() != null && entry.getExclusionPatterns().length > 0))
    //                  && JavaCore.DISABLED.equals(project.getOption(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, true))) {
    //               return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_EXCLUSION_PATTERNS, project, path);
    //            }
    //            if (entry.getOutputLocation() != null && JavaCore.DISABLED.equals(project.getOption(JavaCore
    // .CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, true))) {
    //               return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS, project, path);
    //            }
    //            if (path.isAbsolute() && !path.isEmpty()) {
    //               IPath projectPath= project.getProject().getFullPath();
    //               if (!projectPath.isPrefixOf(path) || JavaModel.getTarget(path, true) == null){
    //                  return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                .bind(Messages.classpath_unboundSourceFolder, new String[]{entryPathMsg, projectName}));
    //               }
    //            } else {
    //               return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                            .bind(Messages.classpath_illegalSourceFolderPath, new String[]{entryPathMsg, projectName}));
    //            }
    //            break;
    //      }
    //
    //      // Validate extra attributes
    //      IClasspathAttribute[] extraAttributes = entry.getExtraAttributes();
    //      if (extraAttributes != null) {
    //         int length = extraAttributes.length;
    //         HashSet set = new HashSet(length);
    //         for (int i=0; i<length; i++) {
    //            String attName = extraAttributes[i].getName();
    //            if (!set.add(attName)) {
    //               return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION, Messages
    //                            .bind(Messages.classpath_duplicateEntryExtraAttribute, new String[]{attName, entryPathMsg, projectName}));
    //            }
    //         }
    //      }
    //
    //      return JavaModelStatus.VERIFIED_OK;
    //   }
    //
    //   // https://bugs.eclipse.org/bugs/show_bug.cgi?id=232816, Now we have the facility to include a container
    //   // name in diagnostics. If the parameter ``container'' is not null, it is used to point to the library
    //   // more fully.
    //   private static IJavaModelStatus validateLibraryEntry(IPath path, IJavaProject project, String container, IPath sourceAttachment,
    // String entryPathMsg) {
    //      if (path.isAbsolute() && !path.isEmpty()) {
    //         Object target = JavaModel.getTarget(path, true);
    //         if (target == null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=248661
    //            IPath workspaceLocation = workspaceRoot.getLocation();
    //            if (workspaceLocation.isPrefixOf(path)) {
    //               target = JavaModel.getTarget(path.makeRelativeTo(workspaceLocation).makeAbsolute(), true);
    //            }
    //         }
    //         if (target != null && !JavaCore.IGNORE.equals(project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true))) {
    //            long projectTargetJDK = CompilerOptions
    //                        .versionToJdkLevel(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
    //            long libraryJDK = Util.getJdkLevel(target);
    //            if (libraryJDK != 0 && libraryJDK > projectTargetJDK) {
    //               if (container != null) {
    //                  return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL,
    //                        project, path,
    //                        Messages.bind(Messages.classpath_incompatibleLibraryJDKLevelInContainer,
    //                                              new String[]{
    //                                                      project.getElementName(),
    //                                                      CompilerOptions.versionFromJdkLevel(projectTargetJDK),
    //                                                      path.makeRelative().toString(),
    //                                                      container,
    //                                                      CompilerOptions.versionFromJdkLevel(libraryJDK)}));
    //               } else {
    //                  return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL,
    //                        project, path,
    //                        Messages.bind(Messages.classpath_incompatibleLibraryJDKLevel,
    //                                              new String[]{
    //                                                      project.getElementName(),
    //                                                      CompilerOptions.versionFromJdkLevel(projectTargetJDK),
    //                                                      path.makeRelative().toString(),
    //                                                      CompilerOptions.versionFromJdkLevel(libraryJDK)}));
    //               }
    //            }
    //         }
    //         if (target instanceof IResource){
    //            IResource resolvedResource = (IResource) target;
    //            switch(resolvedResource.getType()){
    //               case IResource.FILE :
    //                  if (sourceAttachment != null
    //                     && !sourceAttachment.isEmpty()
    //                     && JavaModel.getTarget(sourceAttachment, true) == null){
    //                     if (container != null) {
    //                        return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                        .bind(Messages.classpath_unboundSourceAttachmentInContainedLibrary,
    //                                              new String[]{sourceAttachment.toString(), path.toString(), container}));
    //                     } else {
    //                        return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                        .bind(Messages.classpath_unboundSourceAttachment,
    //                                              new String[]{sourceAttachment.toString(), path.toString(), project.getElementName()}));
    //                     }
    //                  }
    //                  // https://bugs.eclipse.org/bugs/show_bug.cgi?id=229042
    //                  // Validate the contents of the archive
    //                  IJavaModelStatus status = validateLibraryContents(path, project, entryPathMsg);
    //                  if (status != JavaModelStatus.VERIFIED_OK)
    //                     return status;
    //                  break;
    //               case IResource.FOLDER :   // internal binary folder
    //                  if (sourceAttachment != null
    //                     && !sourceAttachment.isEmpty()
    //                     && JavaModel.getTarget(sourceAttachment, true) == null){
    //                     if (container != null) {
    //                        return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                        .bind(Messages.classpath_unboundSourceAttachmentInContainedLibrary,
    //                                              new String[]{sourceAttachment.toString(), path.toString(), container}));
    //                     } else {
    //                        return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                        .bind(Messages.classpath_unboundSourceAttachment,
    //                                              new String[]{sourceAttachment.toString(), path.toString(), project.getElementName()}));
    //                     }
    //                  }
    //            }
    //         } else if (target instanceof File){
    //            File file = JavaModel.getFile(target);
    //            if (file == null) {
    //               if (container != null) {
    //                  return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                .bind(Messages.classpath_illegalExternalFolderInContainer, new String[]{path.toOSString(), container}));
    //               } else {
    //                  return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                .bind(Messages.classpath_illegalExternalFolder, new String[]{path.toOSString(), project.getElementName()}));
    //               }
    //            } else {
    //               if (sourceAttachment != null
    //                     && !sourceAttachment.isEmpty()
    //                     && JavaModel.getTarget(sourceAttachment, true) == null){
    //                  if (container != null) {
    //                     return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                    .bind(Messages.classpath_unboundSourceAttachmentInContainedLibrary,
    //                                          new String[]{sourceAttachment.toString(), path.toOSString(), container}));
    //                  } else {
    //                     return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                    .bind(Messages.classpath_unboundSourceAttachment,
    //                                          new String[]{sourceAttachment.toString(), path.toOSString(), project.getElementName()}));
    //                  }
    //               }
    //               // https://bugs.eclipse.org/bugs/show_bug.cgi?id=229042
    //               // Validate the contents of the archive
    //               if(file.isFile()) {
    //                  IJavaModelStatus status = validateLibraryContents(path, project, entryPathMsg);
    //                  if (status != JavaModelStatus.VERIFIED_OK)
    //                     return status;
    //               }
    //            }
    //         } else {
    //            boolean isExternal = path.getDevice() != null || !ResourcesPlugin.getWorkspace().getRoot().getProject(path.segment(0)).exists();
    //            if (isExternal) {
    //               if (container != null) {
    //                  return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                .bind(Messages.classpath_unboundLibraryInContainer, new String[]{path.toOSString(), container}));
    //               } else {
    //                  return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                .bind(Messages.classpath_unboundLibrary, new String[]{path.toOSString(), project.getElementName()}));
    //               }
    //            } else {
    //               if (entryPathMsg == null)
    //                  entryPathMsg =    project.getElementName().equals(path.segment(0)) ? path.removeFirstSegments(1).makeRelative().toString() : path.toString();
    //               if (container!= null) {
    //                  return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                .bind(Messages.classpath_unboundLibraryInContainer, new String[]{entryPathMsg, container}));
    //               } else {
    //                  return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                                .bind(Messages.classpath_unboundLibrary, new String[]{entryPathMsg, project.getElementName()}));
    //               }
    //            }
    //         }
    //      } else {
    //         if (entryPathMsg == null)
    //            entryPathMsg =    project.getElementName().equals(path.segment(0)) ? path.removeFirstSegments(1).makeRelative().toString() : path.toString();
    //            if (container != null) {
    //               return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                            .bind(Messages.classpath_illegalLibraryPathInContainer, new String[]{entryPathMsg, container}));
    //            } else {
    //               return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages
    //                            .bind(Messages.classpath_illegalLibraryPath, new String[]{entryPathMsg, project.getElementName()}));
    //            }
    //      }
    //      return JavaModelStatus.VERIFIED_OK;
    //   }

    static class UnknownXmlElements {
        String[] attributes;
        ArrayList children;
    }
}