Refactory: removed unnecessary local variables and imports.
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / ClasspathEntry.java
index df61b62..463e7ea 100644 (file)
  *******************************************************************************/
 package net.sourceforge.phpdt.internal.core;
 
+import java.util.HashMap;
+import java.util.HashSet;
+
 import net.sourceforge.phpdt.core.IClasspathEntry;
+import net.sourceforge.phpdt.core.IJavaModelStatus;
+import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
 import net.sourceforge.phpdt.core.IJavaProject;
 import net.sourceforge.phpdt.core.IPackageFragmentRoot;
-import net.sourceforge.phpdt.core.JavaModelException;
 import net.sourceforge.phpdt.core.JavaCore;
+import net.sourceforge.phpdt.core.JavaModelException;
 import net.sourceforge.phpdt.core.compiler.CharOperation;
+import net.sourceforge.phpdt.internal.core.util.Util;
 import net.sourceforge.phpdt.internal.corext.Assert;
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
 
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
 import org.w3c.dom.Document;
@@ -29,74 +40,93 @@ import org.w3c.dom.Element;
 public class ClasspathEntry implements IClasspathEntry {
 
        /**
-        * Describes the kind of classpath entry - one of 
-        * CPE_PROJECT, CPE_LIBRARY, CPE_SOURCE, CPE_VARIABLE or CPE_CONTAINER
+        * 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.
+        * Describes the kind of package fragment roots found on this classpath
+        * entry - either K_BINARY or K_SOURCE or K_OUTPUT.
         */
        public int contentKind;
 
        /**
-        * 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>
+        * 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;
 
        /**
-        * Patterns allowing to exclude portions of the resource tree denoted by this entry path.
+        * Patterns allowing to include/exclude portions of the resource tree
+        * denoted by this entry path.
         */
-       
+       public IPath[] inclusionPatterns;
+
+       private char[][] fullCharInclusionPatterns;
+
        public IPath[] exclusionPatterns;
+
        private char[][] fullCharExclusionPatterns;
+
        private final static char[][] UNINIT_PATTERNS = new char[][] { "Non-initialized yet".toCharArray() }; //$NON-NLS-1$
 
        private String rootID;
-       
+
+       /*
+        * Default inclusion pattern set
+        */
+       public final static IPath[] INCLUDE_ALL = {};
+
+       /*
+        * Default exclusion pattern set
+        */
+       public final static IPath[] EXCLUDE_NONE = {};
+
        /**
         * Default exclusion pattern set
         */
        public final static IPath[] NO_EXCLUSION_PATTERNS = {};
-                               
+
        /**
-        * Describes the path to the source archive associated with this
-        * classpath entry, or <code>null</code> if this classpath entry has no
-        * source attachment.
+        * 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.
+        * 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.
+        * 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;
 
@@ -104,7 +134,7 @@ public class ClasspathEntry implements IClasspathEntry {
         * Specific output location (for this source entry)
         */
        public IPath specificOutputLocation;
-       
+
        /**
         * A constant indicating an output location.
         */
@@ -118,19 +148,22 @@ public class ClasspathEntry implements IClasspathEntry {
        /**
         * Creates a class path entry of the specified kind with the given path.
         */
-       public ClasspathEntry(
-               int contentKind,
-               int entryKind,
-               IPath path,
-               IPath[] exclusionPatterns,
-               IPath sourceAttachmentPath,
-               IPath sourceAttachmentRootPath,
-               IPath specificOutputLocation,
-               boolean isExported) {
+       public ClasspathEntry(int contentKind, int entryKind, IPath path,
+                       IPath[] inclusionPatterns, IPath[] exclusionPatterns,
+                       IPath sourceAttachmentPath, IPath sourceAttachmentRootPath,
+                       IPath specificOutputLocation, boolean isExported) {
 
                this.contentKind = contentKind;
                this.entryKind = entryKind;
                this.path = path;
+               this.inclusionPatterns = inclusionPatterns;
+               if (inclusionPatterns != INCLUDE_ALL && inclusionPatterns.length > 0) {
+                       this.fullCharInclusionPatterns = UNINIT_PATTERNS;
+               } else {
+                       this.fullCharInclusionPatterns = null; // empty inclusion pattern
+                                                                                                       // means everything is
+                                                                                                       // included
+               }
                this.exclusionPatterns = exclusionPatterns;
                if (exclusionPatterns.length > 0) {
                        this.fullCharExclusionPatterns = UNINIT_PATTERNS;
@@ -140,7 +173,7 @@ public class ClasspathEntry implements IClasspathEntry {
                this.specificOutputLocation = specificOutputLocation;
                this.isExported = isExported;
        }
-       
+
        /*
         * Returns a char based representation of the exclusions patterns full path.
         */
@@ -149,28 +182,45 @@ public class ClasspathEntry implements IClasspathEntry {
                if (this.fullCharExclusionPatterns == UNINIT_PATTERNS) {
                        int length = this.exclusionPatterns.length;
                        this.fullCharExclusionPatterns = new char[length][];
-                       IPath prefixPath = path.removeTrailingSeparator();
+                       IPath prefixPath = this.path.removeTrailingSeparator();
                        for (int i = 0; i < length; i++) {
-                               this.fullCharExclusionPatterns[i] = 
-                                       prefixPath.append(this.exclusionPatterns[i]).toString().toCharArray();
+                               this.fullCharExclusionPatterns[i] = prefixPath.append(
+                                               this.exclusionPatterns[i]).toString().toCharArray();
                        }
                }
                return this.fullCharExclusionPatterns;
        }
-       
+
+       /*
+        * Returns a char based representation of the exclusions patterns full path.
+        */
+       public char[][] fullInclusionPatternChars() {
+
+               if (this.fullCharInclusionPatterns == UNINIT_PATTERNS) {
+                       int length = this.inclusionPatterns.length;
+                       this.fullCharInclusionPatterns = new char[length][];
+                       IPath prefixPath = this.path.removeTrailingSeparator();
+                       for (int i = 0; i < length; i++) {
+                               this.fullCharInclusionPatterns[i] = prefixPath.append(
+                                               this.inclusionPatterns[i]).toString().toCharArray();
+                       }
+               }
+               return this.fullCharInclusionPatterns;
+       }
+
        /**
         * Returns the XML encoding of the class path.
         */
-       public Element elementEncode(
-               Document document,
-               IPath projectPath)
-               throws JavaModelException {
+       public Element elementEncode(Document document, IPath projectPath)
+                       throws JavaModelException {
 
                Element element = document.createElement("classpathentry"); //$NON-NLS-1$
-               element.setAttribute("kind", kindToString(this.entryKind));     //$NON-NLS-1$
+               element.setAttribute("kind", kindToString(this.entryKind)); //$NON-NLS-1$
                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 (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))) {
@@ -184,54 +234,58 @@ public class ClasspathEntry implements IClasspathEntry {
                }
                element.setAttribute("path", xmlPath.toString()); //$NON-NLS-1$
                if (this.sourceAttachmentPath != null) {
-                       element.setAttribute("sourcepath", this.sourceAttachmentPath.toString()); //$NON-NLS-1$
+                       element.setAttribute(
+                                       "sourcepath", this.sourceAttachmentPath.toString()); //$NON-NLS-1$
                }
                if (this.sourceAttachmentRootPath != null) {
-                       element.setAttribute("rootpath", this.sourceAttachmentRootPath.toString()); //$NON-NLS-1$
+                       element.setAttribute(
+                                       "rootpath", this.sourceAttachmentRootPath.toString()); //$NON-NLS-1$
                }
                if (this.isExported) {
                        element.setAttribute("exported", "true"); //$NON-NLS-1$ //$NON-NLS-2$
                }
-               
+
                if (this.exclusionPatterns.length > 0) {
                        StringBuffer excludeRule = new StringBuffer(10);
-                       for (int i = 0, max = this.exclusionPatterns.length; i < max; i++){
-                               if (i > 0) excludeRule.append('|');
+                       for (int i = 0, max = this.exclusionPatterns.length; i < max; i++) {
+                               if (i > 0)
+                                       excludeRule.append('|');
                                excludeRule.append(this.exclusionPatterns[i]);
                        }
-                       element.setAttribute("excluding", excludeRule.toString());  //$NON-NLS-1$
+                       element.setAttribute("excluding", excludeRule.toString()); //$NON-NLS-1$
                }
-               
+
                if (this.specificOutputLocation != null) {
-                       IPath outputLocation = this.specificOutputLocation.removeFirstSegments(1);
+                       IPath outputLocation = this.specificOutputLocation
+                                       .removeFirstSegments(1);
                        outputLocation = outputLocation.makeRelative();
                        element.setAttribute("output", outputLocation.toString()); //$NON-NLS-1$ 
                }
                return element;
        }
-       
-       public static IClasspathEntry elementDecode(Element element, IJavaProject project) {
-       
+
+       public static IClasspathEntry elementDecode(Element element,
+                       IJavaProject project) {
+
                IPath projectPath = project.getProject().getFullPath();
                String kindAttr = element.getAttribute("kind"); //$NON-NLS-1$
                String pathAttr = element.getAttribute("path"); //$NON-NLS-1$
 
                // ensure path is absolute
-               IPath path = new Path(pathAttr);                
+               IPath path = new Path(pathAttr);
                int kind = kindFromString(kindAttr);
-               if (kind != IClasspathEntry.CPE_VARIABLE && kind != IClasspathEntry.CPE_CONTAINER && !path.isAbsolute()) {
+               if (kind != IClasspathEntry.CPE_VARIABLE
+                               && kind != IClasspathEntry.CPE_CONTAINER && !path.isAbsolute()) {
                        path = projectPath.append(path);
                }
                // source attachment info (optional)
-               IPath sourceAttachmentPath = 
-                       element.hasAttribute("sourcepath")      //$NON-NLS-1$
-                       ? new Path(element.getAttribute("sourcepath")) //$NON-NLS-1$
-                       : null;
-               IPath sourceAttachmentRootPath = 
-                       element.hasAttribute("rootpath") //$NON-NLS-1$
-                       ? new Path(element.getAttribute("rootpath")) //$NON-NLS-1$
-                       : null;
-               
+//             IPath sourceAttachmentPath = element.hasAttribute("sourcepath") //$NON-NLS-1$
+//             ? new Path(element.getAttribute("sourcepath")) //$NON-NLS-1$
+//                             : null;
+//             IPath sourceAttachmentRootPath = element.hasAttribute("rootpath") //$NON-NLS-1$
+//             ? new Path(element.getAttribute("rootpath")) //$NON-NLS-1$
+//                             : null;
+
                // exported flag (optional)
                boolean isExported = element.getAttribute("exported").equals("true"); //$NON-NLS-1$ //$NON-NLS-2$
 
@@ -239,11 +293,12 @@ public class ClasspathEntry implements IClasspathEntry {
                String exclusion = element.getAttribute("excluding"); //$NON-NLS-1$ 
                IPath[] exclusionPatterns = ClasspathEntry.NO_EXCLUSION_PATTERNS;
                if (!exclusion.equals("")) { //$NON-NLS-1$ 
-                       char[][] patterns = CharOperation.splitOn('|', exclusion.toCharArray());
+                       char[][] patterns = CharOperation.splitOn('|', exclusion
+                                       .toCharArray());
                        int patternCount;
-                       if ((patternCount  = patterns.length) > 0) {
+                       if ((patternCount = patterns.length) > 0) {
                                exclusionPatterns = new IPath[patternCount];
-                               for (int j = 0; j < patterns.length; j++){
+                               for (int j = 0; j < patterns.length; j++) {
                                        exclusionPatterns[j] = new Path(new String(patterns[j]));
                                }
                        }
@@ -251,60 +306,62 @@ public class ClasspathEntry implements IClasspathEntry {
 
                // custom output location
                IPath outputLocation = element.hasAttribute("output") ? projectPath.append(element.getAttribute("output")) : null; //$NON-NLS-1$ //$NON-NLS-2$
-               
+
                // recreate the CP entry
                switch (kind) {
 
-                       case IClasspathEntry.CPE_PROJECT :
+               case IClasspathEntry.CPE_PROJECT:
+                       return JavaCore.newProjectEntry(path, isExported);
+
+                       // case IClasspathEntry.CPE_LIBRARY :
+                       // return JavaCore.newLibraryEntry(
+                       // path,
+                       // sourceAttachmentPath,
+                       // sourceAttachmentRootPath,
+                       // isExported);
+
+               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
+                               return JavaCore.newSourceEntry(path, exclusionPatterns,
+                                               outputLocation);
+                       } else { // another project
                                return JavaCore.newProjectEntry(path, isExported);
-                               
-//                     case IClasspathEntry.CPE_LIBRARY :
-//                             return JavaCore.newLibraryEntry(
-//                                                                                             path,
-//                                                                                             sourceAttachmentPath,
-//                                                                                             sourceAttachmentRootPath,
-//                                                                                             isExported);
-                               
-                       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
-                                       return JavaCore.newSourceEntry(path, exclusionPatterns, outputLocation);
-                               } else { // another project
-                                       return JavaCore.newProjectEntry(path, isExported);
-                               }
+                       }
+
+                       // case IClasspathEntry.CPE_VARIABLE :
+                       // return PHPCore.newVariableEntry(
+                       // path,
+                       // sourceAttachmentPath,
+                       // sourceAttachmentRootPath,
+                       // isExported);
+
+               case IClasspathEntry.CPE_CONTAINER:
+                       return JavaCore.newContainerEntry(path, isExported);
+
+               case ClasspathEntry.K_OUTPUT:
+                       if (!path.isAbsolute())
+                               return null;
+                       return new ClasspathEntry(ClasspathEntry.K_OUTPUT,
+                                       IClasspathEntry.CPE_LIBRARY, path,
+                                       ClasspathEntry.INCLUDE_ALL, ClasspathEntry.EXCLUDE_NONE,
+                                       null, // source attachment
+                                       null, // source attachment root
+                                       null, // custom output location
+                                       false);
 
-//                     case IClasspathEntry.CPE_VARIABLE :
-//                             return PHPCore.newVariableEntry(
-//                                             path,
-//                                             sourceAttachmentPath,
-//                                             sourceAttachmentRootPath, 
-//                                             isExported);
-                               
-                       case IClasspathEntry.CPE_CONTAINER :
-                               return JavaCore.newContainerEntry(
-                                               path,
-                                               isExported);
-
-                       case ClasspathEntry.K_OUTPUT :
-                               if (!path.isAbsolute()) return null;
-                               return new ClasspathEntry(
-                                               ClasspathEntry.K_OUTPUT,
-                                               IClasspathEntry.CPE_LIBRARY,
-                                               path,
-                                               ClasspathEntry.NO_EXCLUSION_PATTERNS, 
-                                               null, // source attachment
-                                               null, // source attachment root
-                                               null, // custom output location
-                                               false);
-                       default :
-                               throw new Assert.AssertionFailedException(Util.bind("classpath.unknownKind", kindAttr)); //$NON-NLS-1$
+               default:
+                       throw new Assert.AssertionFailedException(Util.bind(
+                                       "classpath.unknownKind", kindAttr)); //$NON-NLS-1$
                }
        }
 
        /**
-        * Returns true if the given object is a classpath entry
-        * with equivalent attributes.
+        * Returns true if the given object is a classpath entry with equivalent
+        * attributes.
         */
        public boolean equals(Object object) {
                if (this == object)
@@ -342,19 +399,39 @@ public class ClasspathEntry implements IClasspathEntry {
                                        return false;
                        }
 
+                       IPath[] otherIncludes = otherEntry.getInclusionPatterns();
+                       if (this.inclusionPatterns != otherIncludes) {
+                               if (this.inclusionPatterns == null)
+                                       return false;
+                               int includeLength = this.inclusionPatterns.length;
+                               if (otherIncludes == null
+                                               || otherIncludes.length != includeLength)
+                                       return false;
+                               for (int i = 0; i < includeLength; i++) {
+                                       // compare toStrings instead of IPaths
+                                       // since IPath.equals is specified to ignore trailing
+                                       // separators
+                                       if (!this.inclusionPatterns[i].toString().equals(
+                                                       otherIncludes[i].toString()))
+                                               return false;
+                               }
+                       }
+
                        IPath[] otherExcludes = otherEntry.getExclusionPatterns();
-                       if (this.exclusionPatterns != otherExcludes){
+                       if (this.exclusionPatterns != otherExcludes) {
                                int excludeLength = this.exclusionPatterns.length;
-                               if (otherExcludes.length != excludeLength) 
+                               if (otherExcludes.length != excludeLength)
                                        return false;
                                for (int i = 0; i < excludeLength; i++) {
-                                       // compare toStrings instead of IPaths 
-                                       // since IPath.equals is specified to ignore trailing separators
-                                       if (!this.exclusionPatterns[i].toString().equals(otherExcludes[i].toString()))
+                                       // compare toStrings instead of IPaths
+                                       // since IPath.equals is specified to ignore trailing
+                                       // separators
+                                       if (!this.exclusionPatterns[i].toString().equals(
+                                                       otherExcludes[i].toString()))
                                                return false;
                                }
                        }
-                       
+
                        otherPath = otherEntry.getOutputLocation();
                        if (this.specificOutputLocation == null) {
                                if (otherPath != null)
@@ -391,6 +468,13 @@ public class ClasspathEntry implements IClasspathEntry {
        }
 
        /**
+        * @see IClasspathEntry#getExclusionPatterns()
+        */
+       public IPath[] getInclusionPatterns() {
+               return this.inclusionPatterns;
+       }
+
+       /**
         * @see IClasspathEntry#getOutputLocation()
         */
        public IPath getOutputLocation() {
@@ -433,7 +517,8 @@ public class ClasspathEntry implements IClasspathEntry {
        }
 
        /**
-        * Returns the kind of a <code>PackageFragmentRoot</code> from its <code>String</code> form.
+        * Returns the kind of a <code>PackageFragmentRoot</code> from its
+        * <code>String</code> form.
         */
        static int kindFromString(String kindStr) {
 
@@ -458,20 +543,20 @@ public class ClasspathEntry implements IClasspathEntry {
        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$
+               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$
                }
        }
 
@@ -483,33 +568,33 @@ public class ClasspathEntry implements IClasspathEntry {
                buffer.append(getPath().toString());
                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;
+               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;
+               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) {
@@ -531,7 +616,7 @@ public class ClasspathEntry implements IClasspathEntry {
                        buffer.append("[excluding:"); //$NON-NLS-1$
                        for (int i = 0; i < length; i++) {
                                buffer.append(patterns[i]);
-                               if (i != length-1) {
+                               if (i != length - 1) {
                                        buffer.append('|');
                                }
                        }
@@ -544,44 +629,856 @@ public class ClasspathEntry implements IClasspathEntry {
                }
                return buffer.toString();
        }
-       
+
        /**
         * Answers an ID which is used to distinguish entries during package
         * fragment root computations
         */
-       public String rootID(){
+       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;
+                       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 IClasspathEntry
         * @deprecated
         */
        public IClasspathEntry getResolvedEntry() {
-       
+
                return JavaCore.getResolvedClasspathEntry(this);
        }
+
+       /**
+        * Returns the XML encoding of the class path.
+        */
+       public void elementEncode(XMLWriter writer, IPath projectPath,
+                       boolean indent, boolean newLine) {
+               HashMap parameters = new HashMap();
+
+               parameters.put("kind", ClasspathEntry.kindToString(this.entryKind));//$NON-NLS-1$
+
+               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("path", String.valueOf(xmlPath));//$NON-NLS-1$
+
+               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("sourcepath", String.valueOf(xmlPath));//$NON-NLS-1$
+               }
+               if (this.sourceAttachmentRootPath != null) {
+                       parameters.put(
+                                       "rootpath", String.valueOf(this.sourceAttachmentRootPath));//$NON-NLS-1$
+               }
+               if (this.isExported) {
+                       parameters.put("exported", "true");//$NON-NLS-1$//$NON-NLS-2$
+               }
+               // if (this.inclusionPatterns != null && this.inclusionPatterns.length >
+               // 0) {
+               // StringBuffer includeRule = new StringBuffer(10);
+               // for (int i = 0, max = this.inclusionPatterns.length; i < max; i++){
+               // if (i > 0) includeRule.append('|');
+               // includeRule.append(this.inclusionPatterns[i]);
+               // }
+               // parameters.put("including",
+               // String.valueOf(includeRule));//$NON-NLS-1$
+               // }
+               if (this.exclusionPatterns != null && this.exclusionPatterns.length > 0) {
+                       StringBuffer excludeRule = new StringBuffer(10);
+                       for (int i = 0, max = this.exclusionPatterns.length; i < max; i++) {
+                               if (i > 0)
+                                       excludeRule.append('|');
+                               excludeRule.append(this.exclusionPatterns[i]);
+                       }
+                       parameters.put("excluding", String.valueOf(excludeRule));//$NON-NLS-1$
+               }
+
+               if (this.specificOutputLocation != null) {
+                       IPath outputLocation = this.specificOutputLocation
+                                       .removeFirstSegments(1);
+                       outputLocation = outputLocation.makeRelative();
+                       parameters.put("output", String.valueOf(outputLocation));//$NON-NLS-1$
+               }
+
+               writer.printTag("classpathentry", parameters, indent, newLine, true);//$NON-NLS-1$
+       }
+
+       /**
+        * 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 scenarii 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;
+
+               // retrieve resolved classpath
+               IClasspathEntry[] classpath;
+               try {
+                       classpath = ((JavaProject) javaProject).getResolvedClasspath(
+                                       rawClasspath, null /* output */, true/* ignore pb */,
+                                       false/* no marker */, null /* no reverse map */);
+               } 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];
+                       switch (resolvedEntry.getEntryKind()) {
+                       case IClasspathEntry.CPE_SOURCE:
+                               sourceEntryCount++;
+
+                               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());
+                               }
+                               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,
+                                                       Util
+                                                                       .bind(
+                                                                                       "classpath.cannotNestOutputInOutput", customOutput.makeRelative().toString(), outputLocations[index].makeRelative().toString())); //$NON-NLS-1$
+                               }
+                       }
+               }
+               // 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,
+                                       Util
+                                                       .bind(
+                                                                       "classpath.cannotNestOutputInOutput", potentialNestedOutput.makeRelative().toString(), outputLocations[0].makeRelative().toString())); //$NON-NLS-1$
+               }
+
+               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:
+                       // hasLibFolder |=
+                       // !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(path.lastSegment());
+                       // 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;
+               }
+
+               HashSet pathes = new HashSet(length);
+
+               // 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();
+
+                       // Build some common strings for status message
+                       boolean isProjectRelative = entryPath.segment(0).toString().equals(
+                                       projectName);
+                       String entryPathMsg = isProjectRelative ? entryPath
+                                       .removeFirstSegments(1).toString() : entryPath
+                                       .makeRelative().toString();
+
+                       // complain if duplicate path
+                       if (!pathes.add(entryPath)) {
+                               return new JavaModelStatus(
+                                               IJavaModelStatusConstants.NAME_COLLISION,
+                                               Util
+                                                               .bind(
+                                                                               "classpath.duplicateEntryPath", entryPathMsg, projectName)); //$NON-NLS-1$
+                       }
+                       // 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,
+                                                       Util
+                                                                       .bind(
+                                                                                       "classpath.cannotReferToItself", entryPath.makeRelative().toString()));//$NON-NLS-1$
+                               }
+                               // 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 &&
+                               // !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(entryPath.lastSegment()))){
+                               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
+                                               // &&
+                                               // !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(otherPath.lastSegment())))){
+                                               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,
+                                                                               Util
+                                                                                               .bind(
+                                                                                                               "classpath.mustEndWithSlash", exclusionPattern, entryPath.makeRelative().toString())); //$NON-NLS-1$
+                                                       } else {
+                                                               if (otherKind == IClasspathEntry.CPE_SOURCE) {
+                                                                       exclusionPattern += '/';
+                                                                       return new JavaModelStatus(
+                                                                                       IJavaModelStatusConstants.INVALID_CLASSPATH,
+                                                                                       Util
+                                                                                                       .bind(
+                                                                                                                       "classpath.cannotNestEntryInEntry", new String[] { entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString(), exclusionPattern })); //$NON-NLS-1$
+                                                               } else {
+                                                                       return new JavaModelStatus(
+                                                                                       IJavaModelStatusConstants.INVALID_CLASSPATH,
+                                                                                       Util
+                                                                                                       .bind(
+                                                                                                                       "classpath.cannotNestEntryInLibrary", entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString())); //$NON-NLS-1$
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       // 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,
+                                                               Util
+                                                                               .bind(
+                                                                                               "classpath.cannotNestOutputInEntry", currentOutput.makeRelative().toString(), entryPath.makeRelative().toString())); //$NON-NLS-1$
+                                       }
+                               }
+                       }
+
+                       // 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,
+                                                       Util
+                                                                       .bind(
+                                                                                       "classpath.cannotNestEntryInOutput", entryPath.makeRelative().toString(), currentOutput.makeRelative().toString())); //$NON-NLS-1$
+                               }
+                       }
+               }
+               // 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
+               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 = entryPath.segment(0).toString().equals(
+                                       projectName);
+                       String entryPathMsg = isProjectRelative ? entryPath
+                                       .removeFirstSegments(1).toString() : entryPath
+                                       .makeRelative().toString();
+
+                       if (kind == IClasspathEntry.CPE_SOURCE) {
+                               IPath output = entry.getOutputLocation();
+                               if (output == null)
+                                       continue; // 36465 - for 2.0 backward compatibility, only
+                                                               // check specific output locations (the default
+                                                               // can still coincidate)
+                               // 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;
+
+                                       // Build some common strings for status message
+                                       boolean opStartsWithProject = otherEntry.getPath().segment(
+                                                       0).toString().equals(projectName);
+                                       String otherPathMsg = opStartsWithProject ? otherEntry
+                                                       .getPath().removeFirstSegments(1).toString()
+                                                       : otherEntry.getPath().makeRelative().toString();
+
+                                       switch (otherEntry.getEntryKind()) {
+                                       case IClasspathEntry.CPE_SOURCE:
+                                               if (otherEntry.getPath().equals(output)) {
+                                                       return new JavaModelStatus(
+                                                                       IJavaModelStatusConstants.INVALID_CLASSPATH,
+                                                                       Util
+                                                                                       .bind(
+                                                                                                       "classpath.cannotUseDistinctSourceFolderAsOutput", new String[] { entryPathMsg, otherPathMsg, projectName })); //$NON-NLS-1$
+                                               }
+                                               break;
+                                       case IClasspathEntry.CPE_LIBRARY:
+                                               if (otherEntry.getPath().equals(output)) {
+                                                       return new JavaModelStatus(
+                                                                       IJavaModelStatusConstants.INVALID_CLASSPATH,
+                                                                       Util
+                                                                                       .bind(
+                                                                                                       "classpath.cannotUseLibraryAsOutput", new String[] { entryPathMsg, otherPathMsg, projectName })); //$NON-NLS-1$
+                                               }
+                                       }
+                               }
+                       }
+               }
+               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 attachement should be checked
+        * @param recurseInContainers
+        *            flag indicating whether validation should be applied to
+        *            container entries recursively
+        * @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 recurseInContainers) {
+
+               IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
+               IPath path = entry.getPath();
+
+               // Build some common strings for status message
+               String projectName = project.getElementName();
+               boolean pathStartsWithProject = path.segment(0).toString().equals(
+                               projectName);
+               String entryPathMsg = pathStartsWithProject ? path.removeFirstSegments(
+                               1).toString() : path.makeRelative().toString();
+
+               switch (entry.getEntryKind()) {
+
+               // container entry check
+               // case IClasspathEntry.CPE_CONTAINER :
+               // if (path != null && path.segmentCount() >= 1){
+               // try {
+               // IClasspathContainer container =
+               // JavaModelManager.getJavaModelManager().getClasspathContainer(path,
+               // project);
+               // // container retrieval is performing validation check on container
+               // entry kinds.
+               // if (container == null){
+               // 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){
+               // String description = container.getDescription();
+               // if (description == null) description =
+               // path.makeRelative().toString();
+               // return new
+               // JavaModelStatus(IJavaModelStatusConstants.INVALID_CP_CONTAINER_ENTRY,
+               // project, path);
+               // }
+               // if (recurseInContainers) {
+               // IJavaModelStatus containerEntryStatus =
+               // validateClasspathEntry(project, containerEntry,
+               // checkSourceAttachment, recurseInContainers);
+               // if (!containerEntryStatus.isOK()){
+               // return containerEntryStatus;
+               // }
+               // }
+               // }
+               // }
+               // } catch(JavaModelException e){
+               // return new JavaModelStatus(e);
+               // }
+               // } else {
+               // return new
+               // JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
+               // Util.bind("classpath.illegalContainerPath", entryPathMsg,
+               // projectName)); //$NON-NLS-1$
+               // }
+               // break;
+
+               // variable entry check
+               case IClasspathEntry.CPE_VARIABLE:
+                       if (path != null && path.segmentCount() >= 1) {
+                               try {
+                                       entry = JavaCore.getResolvedClasspathEntry(entry);
+                               } catch (Assert.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);
+                               }
+                               return validateClasspathEntry(project, entry,
+                                               checkSourceAttachment, recurseInContainers);
+                       } else {
+                               return new JavaModelStatus(
+                                               IJavaModelStatusConstants.INVALID_CLASSPATH,
+                                               Util
+                                                               .bind(
+                                                                               "classpath.illegalVariablePath", path.makeRelative().toString(), projectName)); //$NON-NLS-1$
+                       }
+
+                       // library entry check
+                       // case IClasspathEntry.CPE_LIBRARY :
+                       // if (path != null && path.isAbsolute() && !path.isEmpty()) {
+                       // IPath sourceAttachment = entry.getSourceAttachmentPath();
+                       // Object target = JavaModel.getTarget(workspaceRoot, path, true);
+                       // if (target != null &&
+                       // project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true) !=
+                       // JavaCore.IGNORE) {
+                       // long projectTargetJDK =
+                       // CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM,
+                       // true));
+                       // long libraryJDK = Util.getJdkLevel(target);
+                       // if (libraryJDK != 0 && libraryJDK > projectTargetJDK) {
+                       // return new
+                       // JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL,
+                       // project, path, CompilerOptions.versionFromJdkLevel(libraryJDK));
+                       // }
+                       // }
+                       // if (target instanceof IResource){
+                       // IResource resolvedResource = (IResource) target;
+                       // switch(resolvedResource.getType()){
+                       // case IResource.FILE :
+                       // if
+                       // (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(resolvedResource.getName()))
+                       // {
+                       // if (checkSourceAttachment
+                       // && sourceAttachment != null
+                       // && !sourceAttachment.isEmpty()
+                       // && JavaModel.getTarget(workspaceRoot, sourceAttachment, true) ==
+                       // null){
+                       // return new
+                       // JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
+                       // Util.bind("classpath.unboundSourceAttachment", new String []
+                       // {sourceAttachment.makeRelative().toString(),
+                       // path.makeRelative().toString(), projectName})); //$NON-NLS-1$
+                       // }
+                       // } else {
+                       // return new
+                       // JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
+                       // Util.bind("classpath.illegalLibraryArchive", entryPathMsg,
+                       // projectName)); //$NON-NLS-1$
+                       // }
+                       // break;
+                       // case IResource.FOLDER : // internal binary folder
+                       // if (checkSourceAttachment
+                       // && sourceAttachment != null
+                       // && !sourceAttachment.isEmpty()
+                       // && JavaModel.getTarget(workspaceRoot, sourceAttachment, true) ==
+                       // null){
+                       // return new
+                       // JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
+                       // Util.bind("classpath.unboundSourceAttachment", new String []
+                       // {sourceAttachment.makeRelative().toString(),
+                       // path.makeRelative().toString(), projectName})); //$NON-NLS-1$
+                       // }
+                       // }
+                       // } else if (target instanceof File){
+                       // File file = (File) target;
+                       // if (!file.isFile()) {
+                       // return new
+                       // JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
+                       // Util.bind("classpath.illegalExternalFolder", path.toOSString(),
+                       // projectName)); //$NON-NLS-1$
+                       // } else if
+                       // (!org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(file.getName()))
+                       // {
+                       // return new
+                       // JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
+                       // Util.bind("classpath.illegalLibraryArchive", path.toOSString(),
+                       // projectName)); //$NON-NLS-1$
+                       // } else if (checkSourceAttachment
+                       // && sourceAttachment != null
+                       // && !sourceAttachment.isEmpty()
+                       // && JavaModel.getTarget(workspaceRoot, sourceAttachment, true) ==
+                       // null){
+                       // return new
+                       // JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
+                       // Util.bind("classpath.unboundSourceAttachment", new String []
+                       // {sourceAttachment.toString(), path.makeRelative().toString(),
+                       // projectName})); //$NON-NLS-1$
+                       // }
+                       // } else {
+                       // return new
+                       // JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
+                       // Util.bind("classpath.unboundLibrary",
+                       // path.makeRelative().toString(), projectName)); //$NON-NLS-1$
+                       // }
+                       // } else {
+                       // return new
+                       // JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
+                       // Util.bind("classpath.illegalLibraryPath",
+                       // path.makeRelative().toString(), projectName)); //$NON-NLS-1$
+                       // }
+                       // break;
+
+                       // project entry check
+               case IClasspathEntry.CPE_PROJECT:
+                       if (path != null && path.isAbsolute() && !path.isEmpty()) {
+                               IProject prereqProjectRsc = workspaceRoot.getProject(path
+                                               .segment(0));
+                               //IJavaProject prereqProject = JavaCore.create(prereqProjectRsc);
+                               try {
+                                       if (!prereqProjectRsc.exists()
+                                                       || !prereqProjectRsc
+                                                                       .hasNature(PHPeclipsePlugin.PHP_NATURE_ID)) {
+                                               return new JavaModelStatus(
+                                                               IJavaModelStatusConstants.INVALID_CLASSPATH,
+                                                               Util
+                                                                               .bind(
+                                                                                               "classpath.unboundProject", path.makeRelative().segment(0).toString(), projectName)); //$NON-NLS-1$
+                                       }
+                                       if (!prereqProjectRsc.isOpen()) {
+                                               return new JavaModelStatus(
+                                                               IJavaModelStatusConstants.INVALID_CLASSPATH,
+                                                               Util
+                                                                               .bind(
+                                                                                               "classpath.closedProject", path.segment(0).toString())); //$NON-NLS-1$
+                                       }
+                                       // if
+                                       // (project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL,
+                                       // true) != JavaCore.IGNORE) {
+                                       // 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,
+                                       // CompilerOptions.versionFromJdkLevel(prereqProjectTargetJDK));
+                                       // }
+                                       // }
+                               } catch (CoreException e) {
+                                       return new JavaModelStatus(
+                                                       IJavaModelStatusConstants.INVALID_CLASSPATH,
+                                                       Util
+                                                                       .bind(
+                                                                                       "classpath.unboundProject", path.segment(0).toString(), projectName)); //$NON-NLS-1$
+                               }
+                       } else {
+                               return new JavaModelStatus(
+                                               IJavaModelStatusConstants.INVALID_CLASSPATH,
+                                               Util
+                                                               .bind(
+                                                                               "classpath.illegalProjectPath", path.segment(0).toString(), projectName)); //$NON-NLS-1$
+                       }
+                       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 != null && path.isAbsolute() && !path.isEmpty()) {
+                               IPath projectPath = project.getProject().getFullPath();
+                               if (!projectPath.isPrefixOf(path)
+                                               || JavaModel.getTarget(workspaceRoot, path, true) == null) {
+                                       return new JavaModelStatus(
+                                                       IJavaModelStatusConstants.INVALID_CLASSPATH,
+                                                       Util
+                                                                       .bind(
+                                                                                       "classpath.unboundSourceFolder", entryPathMsg, projectName)); //$NON-NLS-1$
+                               }
+                       } else {
+                               return new JavaModelStatus(
+                                               IJavaModelStatusConstants.INVALID_CLASSPATH,
+                                               Util
+                                                               .bind(
+                                                                               "classpath.illegalSourceFolderPath", entryPathMsg, projectName)); //$NON-NLS-1$
+                       }
+                       break;
+               }
+               return JavaModelStatus.VERIFIED_OK;
+       }
 }