improved PHP parser
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / ClasspathEntry.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
12
13 import java.io.File;
14 import java.util.HashMap;
15 import java.util.HashSet;
16
17 import net.sourceforge.phpdt.core.IClasspathEntry;
18 import net.sourceforge.phpdt.core.IJavaModelStatus;
19 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
20 import net.sourceforge.phpdt.core.IJavaProject;
21 import net.sourceforge.phpdt.core.IPackageFragmentRoot;
22 import net.sourceforge.phpdt.core.JavaCore;
23 import net.sourceforge.phpdt.core.JavaModelException;
24 import net.sourceforge.phpdt.core.compiler.CharOperation;
25 import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
26 import net.sourceforge.phpdt.internal.core.util.Util;
27 import net.sourceforge.phpdt.internal.corext.Assert;
28 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
29
30 import org.eclipse.core.resources.IProject;
31 import org.eclipse.core.resources.IResource;
32 import org.eclipse.core.resources.IWorkspaceRoot;
33 import org.eclipse.core.resources.ResourcesPlugin;
34 import org.eclipse.core.runtime.CoreException;
35 import org.eclipse.core.runtime.IPath;
36 import org.eclipse.core.runtime.Path;
37 import org.w3c.dom.Document;
38 import org.w3c.dom.Element;
39
40 /**
41  * @see IClasspathEntry
42  */
43 public class ClasspathEntry implements IClasspathEntry {
44
45         /**
46          * Describes the kind of classpath entry - one of 
47          * CPE_PROJECT, CPE_LIBRARY, CPE_SOURCE, CPE_VARIABLE or CPE_CONTAINER
48          */
49         public int entryKind;
50
51         /**
52          * Describes the kind of package fragment roots found on
53          * this classpath entry - either K_BINARY or K_SOURCE or
54          * K_OUTPUT.
55          */
56         public int contentKind;
57
58         /**
59          * The meaning of the path of a classpath entry depends on its entry kind:<ul>
60          *      <li>Source code in the current project (<code>CPE_SOURCE</code>) -  
61          *      The path associated with this entry is the absolute path to the root folder. </li>
62          *      <li>A binary library in the current project (<code>CPE_LIBRARY</code>) - the path
63          *              associated with this entry is the absolute path to the JAR (or root folder), and 
64          *              in case it refers to an external JAR, then there is no associated resource in 
65          *              the workbench.
66          *      <li>A required project (<code>CPE_PROJECT</code>) - the path of the entry denotes the
67          *              path to the corresponding project resource.</li>
68          *  <li>A variable entry (<code>CPE_VARIABLE</code>) - the first segment of the path 
69          *      is the name of a classpath variable. If this classpath variable
70          *              is bound to the path <it>P</it>, the path of the corresponding classpath entry
71          *              is computed by appending to <it>P</it> the segments of the returned
72          *              path without the variable.</li>
73          *  <li> A container entry (<code>CPE_CONTAINER</code>) - the first segment of the path is denoting
74          *     the unique container identifier (for which a <code>ClasspathContainerInitializer</code> could be
75          *      registered), and the remaining segments are used as additional hints for resolving the container entry to
76          *      an actual <code>IClasspathContainer</code>.</li>
77          */
78         public IPath path;
79
80         
81         /**
82          * Patterns allowing to include/exclude portions of the resource tree denoted by this entry path.
83          */
84         public IPath[] inclusionPatterns;
85         private char[][] fullCharInclusionPatterns;
86         public IPath[] exclusionPatterns;
87         private char[][] fullCharExclusionPatterns;
88         private final static char[][] UNINIT_PATTERNS = new char[][] { "Non-initialized yet".toCharArray() }; //$NON-NLS-1$
89
90         private String rootID;
91         /*
92          * Default inclusion pattern set
93          */
94         public final static IPath[] INCLUDE_ALL = {};
95         
96         /*
97          * Default exclusion pattern set
98          */
99         public final static IPath[] EXCLUDE_NONE = {};
100         /**
101          * Default exclusion pattern set
102          */
103         public final static IPath[] NO_EXCLUSION_PATTERNS = {};
104                                 
105         /**
106          * Describes the path to the source archive associated with this
107          * classpath entry, or <code>null</code> if this classpath entry has no
108          * source attachment.
109          * <p>
110          * Only library and variable classpath entries may have source attachments.
111          * For library classpath entries, the result path (if present) locates a source
112          * archive. For variable classpath entries, the result path (if present) has
113          * an analogous form and meaning as the variable path, namely the first segment 
114          * is the name of a classpath variable.
115          */
116         public IPath sourceAttachmentPath;
117
118         /**
119          * Describes the path within the source archive where package fragments
120          * are located. An empty path indicates that packages are located at
121          * the root of the source archive. Returns a non-<code>null</code> value
122          * if and only if <code>getSourceAttachmentPath</code> returns 
123          * a non-<code>null</code> value.
124          */
125         public IPath sourceAttachmentRootPath;
126
127         /**
128          * Specific output location (for this source entry)
129          */
130         public IPath specificOutputLocation;
131         
132         /**
133          * A constant indicating an output location.
134          */
135         public static final int K_OUTPUT = 10;
136
137         /**
138          * The export flag
139          */
140         public boolean isExported;
141
142         /**
143          * Creates a class path entry of the specified kind with the given path.
144          */
145         public ClasspathEntry(
146                 int contentKind,
147                 int entryKind,
148                 IPath path,
149                 IPath[] inclusionPatterns,
150                 IPath[] exclusionPatterns,
151                 IPath sourceAttachmentPath,
152                 IPath sourceAttachmentRootPath,
153                 IPath specificOutputLocation,
154                 boolean isExported) {
155
156                 this.contentKind = contentKind;
157                 this.entryKind = entryKind;
158                 this.path = path;
159                 this.inclusionPatterns = inclusionPatterns;
160             if (inclusionPatterns != INCLUDE_ALL && inclusionPatterns.length > 0) {
161                         this.fullCharInclusionPatterns = UNINIT_PATTERNS;
162             } else {
163                         this.fullCharInclusionPatterns = null; // empty inclusion pattern means everything is included
164             }
165                 this.exclusionPatterns = exclusionPatterns;
166                 if (exclusionPatterns.length > 0) {
167                         this.fullCharExclusionPatterns = UNINIT_PATTERNS;
168                 }
169                 this.sourceAttachmentPath = sourceAttachmentPath;
170                 this.sourceAttachmentRootPath = sourceAttachmentRootPath;
171                 this.specificOutputLocation = specificOutputLocation;
172                 this.isExported = isExported;
173         }
174         
175         /*
176          * Returns a char based representation of the exclusions patterns full path.
177          */
178         public char[][] fullExclusionPatternChars() {
179
180                 if (this.fullCharExclusionPatterns == UNINIT_PATTERNS) {
181                         int length = this.exclusionPatterns.length;
182                         this.fullCharExclusionPatterns = new char[length][];
183                         IPath prefixPath = this.path.removeTrailingSeparator();
184                         for (int i = 0; i < length; i++) {
185                                 this.fullCharExclusionPatterns[i] = 
186                                         prefixPath.append(this.exclusionPatterns[i]).toString().toCharArray();
187                         }
188                 }
189                 return this.fullCharExclusionPatterns;
190         }
191         
192         /*
193          * Returns a char based representation of the exclusions patterns full path.
194          */
195         public char[][] fullInclusionPatternChars() {
196
197                 if (this.fullCharInclusionPatterns == UNINIT_PATTERNS) {
198                         int length = this.inclusionPatterns.length;
199                         this.fullCharInclusionPatterns = new char[length][];
200                         IPath prefixPath = this.path.removeTrailingSeparator();
201                         for (int i = 0; i < length; i++) {
202                                 this.fullCharInclusionPatterns[i] = 
203                                         prefixPath.append(this.inclusionPatterns[i]).toString().toCharArray();
204                         }
205                 }
206                 return this.fullCharInclusionPatterns;
207         }
208         /**
209          * Returns the XML encoding of the class path.
210          */
211         public Element elementEncode(
212                 Document document,
213                 IPath projectPath)
214                 throws JavaModelException {
215
216                 Element element = document.createElement("classpathentry"); //$NON-NLS-1$
217                 element.setAttribute("kind", kindToString(this.entryKind));     //$NON-NLS-1$
218                 IPath xmlPath = this.path;
219                 if (this.entryKind != IClasspathEntry.CPE_VARIABLE && this.entryKind != IClasspathEntry.CPE_CONTAINER) {
220                         // translate to project relative from absolute (unless a device path)
221                         if (xmlPath.isAbsolute()) {
222                                 if (projectPath != null && projectPath.isPrefixOf(xmlPath)) {
223                                         if (xmlPath.segment(0).equals(projectPath.segment(0))) {
224                                                 xmlPath = xmlPath.removeFirstSegments(1);
225                                                 xmlPath = xmlPath.makeRelative();
226                                         } else {
227                                                 xmlPath = xmlPath.makeAbsolute();
228                                         }
229                                 }
230                         }
231                 }
232                 element.setAttribute("path", xmlPath.toString()); //$NON-NLS-1$
233                 if (this.sourceAttachmentPath != null) {
234                         element.setAttribute("sourcepath", this.sourceAttachmentPath.toString()); //$NON-NLS-1$
235                 }
236                 if (this.sourceAttachmentRootPath != null) {
237                         element.setAttribute("rootpath", this.sourceAttachmentRootPath.toString()); //$NON-NLS-1$
238                 }
239                 if (this.isExported) {
240                         element.setAttribute("exported", "true"); //$NON-NLS-1$ //$NON-NLS-2$
241                 }
242                 
243                 if (this.exclusionPatterns.length > 0) {
244                         StringBuffer excludeRule = new StringBuffer(10);
245                         for (int i = 0, max = this.exclusionPatterns.length; i < max; i++){
246                                 if (i > 0) excludeRule.append('|');
247                                 excludeRule.append(this.exclusionPatterns[i]);
248                         }
249                         element.setAttribute("excluding", excludeRule.toString());  //$NON-NLS-1$
250                 }
251                 
252                 if (this.specificOutputLocation != null) {
253                         IPath outputLocation = this.specificOutputLocation.removeFirstSegments(1);
254                         outputLocation = outputLocation.makeRelative();
255                         element.setAttribute("output", outputLocation.toString()); //$NON-NLS-1$ 
256                 }
257                 return element;
258         }
259         
260         public static IClasspathEntry elementDecode(Element element, IJavaProject project) {
261         
262                 IPath projectPath = project.getProject().getFullPath();
263                 String kindAttr = element.getAttribute("kind"); //$NON-NLS-1$
264                 String pathAttr = element.getAttribute("path"); //$NON-NLS-1$
265
266                 // ensure path is absolute
267                 IPath path = new Path(pathAttr);                
268                 int kind = kindFromString(kindAttr);
269                 if (kind != IClasspathEntry.CPE_VARIABLE && kind != IClasspathEntry.CPE_CONTAINER && !path.isAbsolute()) {
270                         path = projectPath.append(path);
271                 }
272                 // source attachment info (optional)
273                 IPath sourceAttachmentPath = 
274                         element.hasAttribute("sourcepath")      //$NON-NLS-1$
275                         ? new Path(element.getAttribute("sourcepath")) //$NON-NLS-1$
276                         : null;
277                 IPath sourceAttachmentRootPath = 
278                         element.hasAttribute("rootpath") //$NON-NLS-1$
279                         ? new Path(element.getAttribute("rootpath")) //$NON-NLS-1$
280                         : null;
281                 
282                 // exported flag (optional)
283                 boolean isExported = element.getAttribute("exported").equals("true"); //$NON-NLS-1$ //$NON-NLS-2$
284
285                 // exclusion patterns (optional)
286                 String exclusion = element.getAttribute("excluding"); //$NON-NLS-1$ 
287                 IPath[] exclusionPatterns = ClasspathEntry.NO_EXCLUSION_PATTERNS;
288                 if (!exclusion.equals("")) { //$NON-NLS-1$ 
289                         char[][] patterns = CharOperation.splitOn('|', exclusion.toCharArray());
290                         int patternCount;
291                         if ((patternCount  = patterns.length) > 0) {
292                                 exclusionPatterns = new IPath[patternCount];
293                                 for (int j = 0; j < patterns.length; j++){
294                                         exclusionPatterns[j] = new Path(new String(patterns[j]));
295                                 }
296                         }
297                 }
298
299                 // custom output location
300                 IPath outputLocation = element.hasAttribute("output") ? projectPath.append(element.getAttribute("output")) : null; //$NON-NLS-1$ //$NON-NLS-2$
301                 
302                 // recreate the CP entry
303                 switch (kind) {
304
305                         case IClasspathEntry.CPE_PROJECT :
306                                 return JavaCore.newProjectEntry(path, isExported);
307                                 
308 //                      case IClasspathEntry.CPE_LIBRARY :
309 //                              return JavaCore.newLibraryEntry(
310 //                                                                                              path,
311 //                                                                                              sourceAttachmentPath,
312 //                                                                                              sourceAttachmentRootPath,
313 //                                                                                              isExported);
314                                 
315                         case IClasspathEntry.CPE_SOURCE :
316                                 // must be an entry in this project or specify another project
317                                 String projSegment = path.segment(0);
318                                 if (projSegment != null && projSegment.equals(project.getElementName())) { // this project
319                                         return JavaCore.newSourceEntry(path, exclusionPatterns, outputLocation);
320                                 } else { // another project
321                                         return JavaCore.newProjectEntry(path, isExported);
322                                 }
323
324 //                      case IClasspathEntry.CPE_VARIABLE :
325 //                              return PHPCore.newVariableEntry(
326 //                                              path,
327 //                                              sourceAttachmentPath,
328 //                                              sourceAttachmentRootPath, 
329 //                                              isExported);
330                                 
331                         case IClasspathEntry.CPE_CONTAINER :
332                                 return JavaCore.newContainerEntry(
333                                                 path,
334                                                 isExported);
335
336                         case ClasspathEntry.K_OUTPUT :
337                           if (!path.isAbsolute()) return null;
338                             return new ClasspathEntry(
339                                         ClasspathEntry.K_OUTPUT,
340                                         IClasspathEntry.CPE_LIBRARY,
341                                         path,
342                                         ClasspathEntry.INCLUDE_ALL, 
343                                         ClasspathEntry.EXCLUDE_NONE, 
344                                         null, // source attachment
345                                         null, // source attachment root
346                                         null, // custom output location
347                                         false);
348                                 
349                         default :
350                                 throw new Assert.AssertionFailedException(Util.bind("classpath.unknownKind", kindAttr)); //$NON-NLS-1$
351                 }
352         }
353
354         /**
355          * Returns true if the given object is a classpath entry
356          * with equivalent attributes.
357          */
358         public boolean equals(Object object) {
359                 if (this == object)
360                         return true;
361                 if (object instanceof IClasspathEntry) {
362                         IClasspathEntry otherEntry = (IClasspathEntry) object;
363
364                         if (this.contentKind != otherEntry.getContentKind())
365                                 return false;
366
367                         if (this.entryKind != otherEntry.getEntryKind())
368                                 return false;
369
370                         if (this.isExported != otherEntry.isExported())
371                                 return false;
372
373                         if (!this.path.equals(otherEntry.getPath()))
374                                 return false;
375
376                         IPath otherPath = otherEntry.getSourceAttachmentPath();
377                         if (this.sourceAttachmentPath == null) {
378                                 if (otherPath != null)
379                                         return false;
380                         } else {
381                                 if (!this.sourceAttachmentPath.equals(otherPath))
382                                         return false;
383                         }
384
385                         otherPath = otherEntry.getSourceAttachmentRootPath();
386                         if (this.sourceAttachmentRootPath == null) {
387                                 if (otherPath != null)
388                                         return false;
389                         } else {
390                                 if (!this.sourceAttachmentRootPath.equals(otherPath))
391                                         return false;
392                         }
393
394                         IPath[] otherIncludes = otherEntry.getInclusionPatterns();
395                         if (this.inclusionPatterns != otherIncludes){
396                             if (this.inclusionPatterns == null) return false;
397                                 int includeLength = this.inclusionPatterns.length;
398                                 if (otherIncludes == null || otherIncludes.length != includeLength) 
399                                         return false;
400                                 for (int i = 0; i < includeLength; i++) {
401                                         // compare toStrings instead of IPaths 
402                                         // since IPath.equals is specified to ignore trailing separators
403                                         if (!this.inclusionPatterns[i].toString().equals(otherIncludes[i].toString()))
404                                                 return false;
405                                 }
406                         }
407                         
408                         IPath[] otherExcludes = otherEntry.getExclusionPatterns();
409                         if (this.exclusionPatterns != otherExcludes){
410                                 int excludeLength = this.exclusionPatterns.length;
411                                 if (otherExcludes.length != excludeLength) 
412                                         return false;
413                                 for (int i = 0; i < excludeLength; i++) {
414                                         // compare toStrings instead of IPaths 
415                                         // since IPath.equals is specified to ignore trailing separators
416                                         if (!this.exclusionPatterns[i].toString().equals(otherExcludes[i].toString()))
417                                                 return false;
418                                 }
419                         }
420                         
421                         otherPath = otherEntry.getOutputLocation();
422                         if (this.specificOutputLocation == null) {
423                                 if (otherPath != null)
424                                         return false;
425                         } else {
426                                 if (!this.specificOutputLocation.equals(otherPath))
427                                         return false;
428                         }
429                         return true;
430                 } else {
431                         return false;
432                 }
433         }
434
435         /**
436          * @see IClasspathEntry
437          */
438         public int getContentKind() {
439                 return this.contentKind;
440         }
441
442         /**
443          * @see IClasspathEntry
444          */
445         public int getEntryKind() {
446                 return this.entryKind;
447         }
448
449         /**
450          * @see IClasspathEntry#getExclusionPatterns()
451          */
452         public IPath[] getExclusionPatterns() {
453                 return this.exclusionPatterns;
454         }
455         /**
456          * @see IClasspathEntry#getExclusionPatterns()
457          */
458         public IPath[] getInclusionPatterns() {
459                 return this.inclusionPatterns;
460         }
461         /**
462          * @see IClasspathEntry#getOutputLocation()
463          */
464         public IPath getOutputLocation() {
465                 return this.specificOutputLocation;
466         }
467
468         /**
469          * @see IClasspathEntry
470          */
471         public IPath getPath() {
472                 return this.path;
473         }
474
475         /**
476          * @see IClasspathEntry
477          */
478         public IPath getSourceAttachmentPath() {
479                 return this.sourceAttachmentPath;
480         }
481
482         /**
483          * @see IClasspathEntry
484          */
485         public IPath getSourceAttachmentRootPath() {
486                 return this.sourceAttachmentRootPath;
487         }
488
489         /**
490          * Returns the hash code for this classpath entry
491          */
492         public int hashCode() {
493                 return this.path.hashCode();
494         }
495
496         /**
497          * @see IClasspathEntry#isExported()
498          */
499         public boolean isExported() {
500                 return this.isExported;
501         }
502
503         /**
504          * Returns the kind of a <code>PackageFragmentRoot</code> from its <code>String</code> form.
505          */
506         static int kindFromString(String kindStr) {
507
508                 if (kindStr.equalsIgnoreCase("prj")) //$NON-NLS-1$
509                         return IClasspathEntry.CPE_PROJECT;
510                 if (kindStr.equalsIgnoreCase("var")) //$NON-NLS-1$
511                         return IClasspathEntry.CPE_VARIABLE;
512                 if (kindStr.equalsIgnoreCase("con")) //$NON-NLS-1$
513                         return IClasspathEntry.CPE_CONTAINER;
514                 if (kindStr.equalsIgnoreCase("src")) //$NON-NLS-1$
515                         return IClasspathEntry.CPE_SOURCE;
516                 if (kindStr.equalsIgnoreCase("lib")) //$NON-NLS-1$
517                         return IClasspathEntry.CPE_LIBRARY;
518                 if (kindStr.equalsIgnoreCase("output")) //$NON-NLS-1$
519                         return ClasspathEntry.K_OUTPUT;
520                 return -1;
521         }
522
523         /**
524          * Returns a <code>String</code> for the kind of a class path entry.
525          */
526         static String kindToString(int kind) {
527
528                 switch (kind) {
529                         case IClasspathEntry.CPE_PROJECT :
530                                 return "src"; // backward compatibility //$NON-NLS-1$
531                         case IClasspathEntry.CPE_SOURCE :
532                                 return "src"; //$NON-NLS-1$
533                         case IClasspathEntry.CPE_LIBRARY :
534                                 return "lib"; //$NON-NLS-1$
535                         case IClasspathEntry.CPE_VARIABLE :
536                                 return "var"; //$NON-NLS-1$
537                         case IClasspathEntry.CPE_CONTAINER :
538                                 return "con"; //$NON-NLS-1$
539                         case ClasspathEntry.K_OUTPUT :
540                                 return "output"; //$NON-NLS-1$
541                         default :
542                                 return "unknown"; //$NON-NLS-1$
543                 }
544         }
545
546         /**
547          * Returns a printable representation of this classpath entry.
548          */
549         public String toString() {
550                 StringBuffer buffer = new StringBuffer();
551                 buffer.append(getPath().toString());
552                 buffer.append('[');
553                 switch (getEntryKind()) {
554                         case IClasspathEntry.CPE_LIBRARY :
555                                 buffer.append("CPE_LIBRARY"); //$NON-NLS-1$
556                                 break;
557                         case IClasspathEntry.CPE_PROJECT :
558                                 buffer.append("CPE_PROJECT"); //$NON-NLS-1$
559                                 break;
560                         case IClasspathEntry.CPE_SOURCE :
561                                 buffer.append("CPE_SOURCE"); //$NON-NLS-1$
562                                 break;
563                         case IClasspathEntry.CPE_VARIABLE :
564                                 buffer.append("CPE_VARIABLE"); //$NON-NLS-1$
565                                 break;
566                         case IClasspathEntry.CPE_CONTAINER :
567                                 buffer.append("CPE_CONTAINER"); //$NON-NLS-1$
568                                 break;
569                 }
570                 buffer.append("]["); //$NON-NLS-1$
571                 switch (getContentKind()) {
572                         case IPackageFragmentRoot.K_BINARY :
573                                 buffer.append("K_BINARY"); //$NON-NLS-1$
574                                 break;
575                         case IPackageFragmentRoot.K_SOURCE :
576                                 buffer.append("K_SOURCE"); //$NON-NLS-1$
577                                 break;
578                         case ClasspathEntry.K_OUTPUT :
579                                 buffer.append("K_OUTPUT"); //$NON-NLS-1$
580                                 break;
581                 }
582                 buffer.append(']');
583                 if (getSourceAttachmentPath() != null) {
584                         buffer.append("[sourcePath:"); //$NON-NLS-1$
585                         buffer.append(getSourceAttachmentPath());
586                         buffer.append(']');
587                 }
588                 if (getSourceAttachmentRootPath() != null) {
589                         buffer.append("[rootPath:"); //$NON-NLS-1$
590                         buffer.append(getSourceAttachmentRootPath());
591                         buffer.append(']');
592                 }
593                 buffer.append("[isExported:"); //$NON-NLS-1$
594                 buffer.append(this.isExported);
595                 buffer.append(']');
596                 IPath[] patterns = getExclusionPatterns();
597                 int length;
598                 if ((length = patterns.length) > 0) {
599                         buffer.append("[excluding:"); //$NON-NLS-1$
600                         for (int i = 0; i < length; i++) {
601                                 buffer.append(patterns[i]);
602                                 if (i != length-1) {
603                                         buffer.append('|');
604                                 }
605                         }
606                         buffer.append(']');
607                 }
608                 if (getOutputLocation() != null) {
609                         buffer.append("[output:"); //$NON-NLS-1$
610                         buffer.append(getOutputLocation());
611                         buffer.append(']');
612                 }
613                 return buffer.toString();
614         }
615         
616         /**
617          * Answers an ID which is used to distinguish entries during package
618          * fragment root computations
619          */
620         public String rootID(){
621
622                 if (this.rootID == null) {
623                         switch(this.entryKind){
624                                 case IClasspathEntry.CPE_LIBRARY :
625                                         this.rootID = "[LIB]"+this.path;  //$NON-NLS-1$
626                                         break;
627                                 case IClasspathEntry.CPE_PROJECT :
628                                         this.rootID = "[PRJ]"+this.path;  //$NON-NLS-1$
629                                         break;
630                                 case IClasspathEntry.CPE_SOURCE :
631                                         this.rootID = "[SRC]"+this.path;  //$NON-NLS-1$
632                                         break;
633                                 case IClasspathEntry.CPE_VARIABLE :
634                                         this.rootID = "[VAR]"+this.path;  //$NON-NLS-1$
635                                         break;
636                                 case IClasspathEntry.CPE_CONTAINER :
637                                         this.rootID = "[CON]"+this.path;  //$NON-NLS-1$
638                                         break;
639                                 default :
640                                         this.rootID = "";  //$NON-NLS-1$
641                                         break;
642                         }
643                 }
644                 return this.rootID;
645         }
646         
647         /**
648          * @see IClasspathEntry
649          * @deprecated
650          */
651         public IClasspathEntry getResolvedEntry() {
652         
653                 return JavaCore.getResolvedClasspathEntry(this);
654         }
655         /**
656          * Returns the XML encoding of the class path.
657          */
658         public void elementEncode(XMLWriter writer, IPath projectPath, boolean indent, boolean newLine) {
659                 HashMap parameters = new HashMap();
660                 
661                 parameters.put("kind", ClasspathEntry.kindToString(this.entryKind));//$NON-NLS-1$
662                 
663                 IPath xmlPath = this.path;
664                 if (this.entryKind != IClasspathEntry.CPE_VARIABLE && this.entryKind != IClasspathEntry.CPE_CONTAINER) {
665                         // translate to project relative from absolute (unless a device path)
666                         if (xmlPath.isAbsolute()) {
667                                 if (projectPath != null && projectPath.isPrefixOf(xmlPath)) {
668                                         if (xmlPath.segment(0).equals(projectPath.segment(0))) {
669                                                 xmlPath = xmlPath.removeFirstSegments(1);
670                                                 xmlPath = xmlPath.makeRelative();
671                                         } else {
672                                                 xmlPath = xmlPath.makeAbsolute();
673                                         }
674                                 }
675                         }
676                 }
677                 parameters.put("path", String.valueOf(xmlPath));//$NON-NLS-1$
678                 
679                 if (this.sourceAttachmentPath != null) {
680                         xmlPath = this.sourceAttachmentPath;
681                         // translate to project relative from absolute 
682                         if (this.entryKind != IClasspathEntry.CPE_VARIABLE && projectPath != null && projectPath.isPrefixOf(xmlPath)) {
683                                 if (xmlPath.segment(0).equals(projectPath.segment(0))) {
684                                         xmlPath = xmlPath.removeFirstSegments(1);
685                                         xmlPath = xmlPath.makeRelative();
686                                 }
687                         }
688                         parameters.put("sourcepath", String.valueOf(xmlPath));//$NON-NLS-1$
689                 }
690                 if (this.sourceAttachmentRootPath != null) {
691                         parameters.put("rootpath", String.valueOf(this.sourceAttachmentRootPath));//$NON-NLS-1$
692                 }
693                 if (this.isExported) {
694                         parameters.put("exported", "true");//$NON-NLS-1$//$NON-NLS-2$
695                 }
696 //              if (this.inclusionPatterns != null && this.inclusionPatterns.length > 0) {
697 //                      StringBuffer includeRule = new StringBuffer(10);
698 //                      for (int i = 0, max = this.inclusionPatterns.length; i < max; i++){
699 //                              if (i > 0) includeRule.append('|');
700 //                              includeRule.append(this.inclusionPatterns[i]);
701 //                      }
702 //                      parameters.put("including", String.valueOf(includeRule));//$NON-NLS-1$
703 //              }
704                 if (this.exclusionPatterns != null && this.exclusionPatterns.length > 0) {
705                         StringBuffer excludeRule = new StringBuffer(10);
706                         for (int i = 0, max = this.exclusionPatterns.length; i < max; i++){
707                                 if (i > 0) excludeRule.append('|');
708                                 excludeRule.append(this.exclusionPatterns[i]);
709                         }
710                         parameters.put("excluding", String.valueOf(excludeRule));//$NON-NLS-1$
711                 }
712                 
713                 if (this.specificOutputLocation != null) {
714                         IPath outputLocation = this.specificOutputLocation.removeFirstSegments(1);
715                         outputLocation = outputLocation.makeRelative();
716                         parameters.put("output", String.valueOf(outputLocation));//$NON-NLS-1$
717                 }
718
719                 writer.printTag("classpathentry", parameters, indent, newLine, true);//$NON-NLS-1$
720         }
721         
722         /**
723          * Validate a given classpath and output location for a project, using the following rules:
724          * <ul>
725          *   <li> Classpath entries cannot collide with each other; that is, all entry paths must be unique.
726          *   <li> The project output location path cannot be null, must be absolute and located inside the project.
727          *   <li> Specific output locations (specified on source entries) can be null, if not they must be located inside the project,
728          *   <li> A project entry cannot refer to itself directly (that is, a project cannot prerequisite itself).
729      *   <li> Classpath entries or output locations cannot coincidate or be nested in each other, except for the following scenarii listed below:
730          *      <ul><li> A source folder can coincidate with its own output location, in which case this output can then contain library archives. 
731          *                     However, a specific output location cannot coincidate with any library or a distinct source folder than the one referring to it. </li> 
732          *              <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>
733          *                      <li> An output location can be nested in a source folder, if the source folder coincidates with the project itself, or if the output
734          *                                      location is excluded from the source folder. </li>
735          *      </ul>
736          * </ul>
737          * 
738          *  Note that the classpath entries are not validated automatically. Only bound variables or containers are considered 
739          *  in the checking process (this allows to perform a consistency check on a classpath which has references to
740          *  yet non existing projects, folders, ...).
741          *  <p>
742          *  This validation is intended to anticipate classpath issues prior to assigning it to a project. In particular, it will automatically
743          *  be performed during the classpath setting operation (if validation fails, the classpath setting will not complete).
744          *  <p>
745          * @param javaProject the given java project
746          * @param rawClasspath a given classpath
747          * @param projectOutputLocation a given output location
748          * @return a status object with code <code>IStatus.OK</code> if
749          *              the given classpath and output location are compatible, otherwise a status 
750          *              object indicating what is wrong with the classpath or output location
751          */
752         public static IJavaModelStatus validateClasspath(IJavaProject javaProject, IClasspathEntry[] rawClasspath, IPath projectOutputLocation) {
753         
754                 IProject project = javaProject.getProject();
755                 IPath projectPath= project.getFullPath();
756                 String projectName = javaProject.getElementName();
757         
758                 /* validate output location */
759                 if (projectOutputLocation == null) {
760                         return new JavaModelStatus(IJavaModelStatusConstants.NULL_PATH);
761                 }
762                 if (projectOutputLocation.isAbsolute()) {
763                         if (!projectPath.isPrefixOf(projectOutputLocation)) {
764                                 return new JavaModelStatus(IJavaModelStatusConstants.PATH_OUTSIDE_PROJECT, javaProject, projectOutputLocation.toString());
765                         }
766                 } else {
767                         return new JavaModelStatus(IJavaModelStatusConstants.RELATIVE_PATH, projectOutputLocation);
768                 }
769         
770                 boolean hasSource = false;
771                 boolean hasLibFolder = false;
772         
773
774                 // tolerate null path, it will be reset to default
775                 if (rawClasspath == null) 
776                         return JavaModelStatus.VERIFIED_OK;
777                 
778                 // retrieve resolved classpath
779                 IClasspathEntry[] classpath; 
780                 try {
781                         classpath = ((JavaProject)javaProject).getResolvedClasspath(rawClasspath, null /*output*/, true/*ignore pb*/, false/*no marker*/, null /*no reverse map*/);
782                 } catch(JavaModelException e){
783                         return e.getJavaModelStatus();
784                 }
785                 int length = classpath.length; 
786
787                 int outputCount = 1;
788                 IPath[] outputLocations = new IPath[length+1];
789                 boolean[] allowNestingInOutputLocations = new boolean[length+1];
790                 outputLocations[0] = projectOutputLocation;
791                 
792                 // retrieve and check output locations
793                 IPath potentialNestedOutput = null; // for error reporting purpose
794                 int sourceEntryCount = 0;
795                 boolean disableExclusionPatterns = JavaCore.DISABLED.equals(javaProject.getOption(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, true));
796                 boolean disableCustomOutputLocations = JavaCore.DISABLED.equals(javaProject.getOption(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, true));
797                 
798                 for (int i = 0 ; i < length; i++) {
799                         IClasspathEntry resolvedEntry = classpath[i];
800                         switch(resolvedEntry.getEntryKind()){
801                                 case IClasspathEntry.CPE_SOURCE :
802                                         sourceEntryCount++;
803
804                                         if (disableExclusionPatterns &&
805                                                 ((resolvedEntry.getInclusionPatterns() != null && resolvedEntry.getInclusionPatterns().length > 0) 
806                                                 || (resolvedEntry.getExclusionPatterns() != null && resolvedEntry.getExclusionPatterns().length > 0))) {
807                                                 return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_EXCLUSION_PATTERNS, javaProject, resolvedEntry.getPath());
808                                         }
809                                         IPath customOutput; 
810                                         if ((customOutput = resolvedEntry.getOutputLocation()) != null) {
811
812                                                 if (disableCustomOutputLocations) {
813                                                         return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS, javaProject, resolvedEntry.getPath());
814                                                 }
815                                                 // ensure custom output is in project
816                                                 if (customOutput.isAbsolute()) {
817                                                         if (!javaProject.getPath().isPrefixOf(customOutput)) {
818                                                                 return new JavaModelStatus(IJavaModelStatusConstants.PATH_OUTSIDE_PROJECT, javaProject, customOutput.toString());
819                                                         }
820                                                 } else {
821                                                         return new JavaModelStatus(IJavaModelStatusConstants.RELATIVE_PATH, customOutput);
822                                                 }
823                                                 
824                                                 // ensure custom output doesn't conflict with other outputs
825                                                 // check exact match
826                                                 if (Util.indexOfMatchingPath(customOutput, outputLocations, outputCount) != -1) {
827                                                         continue; // already found
828                                                 }
829                                                 // accumulate all outputs, will check nesting once all available (to handle ordering issues)
830                                                 outputLocations[outputCount++] = customOutput;
831                                         }
832                         }
833                 }
834                 // check nesting across output locations
835                 for (int i = 1 /*no check for default output*/ ; i < outputCount; i++) {
836                     IPath customOutput = outputLocations[i];
837                     int index;
838                         // check nesting
839                         if ((index = Util.indexOfEnclosingPath(customOutput, outputLocations, outputCount)) != -1 && index != i) {
840                                 if (index == 0) {
841                                         // custom output is nested in project's output: need to check if all source entries have a custom
842                                         // output before complaining
843                                         if (potentialNestedOutput == null) potentialNestedOutput = customOutput;
844                                 } else {
845                                         return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestOutputInOutput", customOutput.makeRelative().toString(), outputLocations[index].makeRelative().toString())); //$NON-NLS-1$
846                                 }
847                         }
848                 }       
849                 // allow custom output nesting in project's output if all source entries have a custom output
850                 if (sourceEntryCount <= outputCount-1) {
851                     allowNestingInOutputLocations[0] = true;
852                 } else if (potentialNestedOutput != null) {
853                         return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestOutputInOutput", potentialNestedOutput.makeRelative().toString(), outputLocations[0].makeRelative().toString())); //$NON-NLS-1$
854                 }
855
856                 for (int i = 0 ; i < length; i++) {
857                         IClasspathEntry resolvedEntry = classpath[i];
858                         IPath path = resolvedEntry.getPath();
859                         int index;
860                         switch(resolvedEntry.getEntryKind()){
861                                 
862                                 case IClasspathEntry.CPE_SOURCE :
863                                         hasSource = true;
864                                         if ((index = Util.indexOfMatchingPath(path, outputLocations, outputCount)) != -1){
865                                                 allowNestingInOutputLocations[index] = true;
866                                         }
867                                         break;
868
869 //                              case IClasspathEntry.CPE_LIBRARY:
870 //                                      hasLibFolder |= !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(path.lastSegment());
871 //                                      if ((index = Util.indexOfMatchingPath(path, outputLocations, outputCount)) != -1){
872 //                                              allowNestingInOutputLocations[index] = true;
873 //                                      }
874 //                                      break;
875                         }
876                 }
877                 if (!hasSource && !hasLibFolder) { // if no source and no lib folder, then allowed
878                         for (int i = 0; i < outputCount; i++) allowNestingInOutputLocations[i] = true;
879                 }
880                 
881                 HashSet pathes = new HashSet(length);
882                 
883                 // check all entries
884                 for (int i = 0 ; i < length; i++) {
885                         IClasspathEntry entry = classpath[i];
886                         if (entry == null) continue;
887                         IPath entryPath = entry.getPath();
888                         int kind = entry.getEntryKind();
889                         
890                         // Build some common strings for status message
891                         boolean isProjectRelative = entryPath.segment(0).toString().equals(projectName);
892                         String entryPathMsg = isProjectRelative ? entryPath.removeFirstSegments(1).toString() : entryPath.makeRelative().toString();
893         
894                         // complain if duplicate path
895                         if (!pathes.add(entryPath)){
896                                 return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION, Util.bind("classpath.duplicateEntryPath", entryPathMsg, projectName)); //$NON-NLS-1$
897                         }
898                         // no further check if entry coincidates with project or output location
899                         if (entryPath.equals(projectPath)){
900                                 // complain if self-referring project entry
901                                 if (kind == IClasspathEntry.CPE_PROJECT){
902                                         return new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, Util.bind("classpath.cannotReferToItself", entryPath.makeRelative().toString()));//$NON-NLS-1$
903                                 }
904                                 // tolerate nesting output in src if src==prj
905                                 continue;
906                         }
907         
908                         // allow nesting source entries in each other as long as the outer entry excludes the inner one
909                         if (kind == IClasspathEntry.CPE_SOURCE ) {
910 //                                      || (kind == IClasspathEntry.CPE_LIBRARY && !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(entryPath.lastSegment()))){
911                                 for (int j = 0; j < classpath.length; j++){
912                                         IClasspathEntry otherEntry = classpath[j];
913                                         if (otherEntry == null) continue;
914                                         int otherKind = otherEntry.getEntryKind();
915                                         IPath otherPath = otherEntry.getPath();
916                                         if (entry != otherEntry 
917                                                 && (otherKind == IClasspathEntry.CPE_SOURCE ) ) {
918 //                                                              || (otherKind == IClasspathEntry.CPE_LIBRARY 
919 //                                                                              && !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(otherPath.lastSegment())))){
920                                                 char[][] inclusionPatterns, exclusionPatterns;
921                                                 if (otherPath.isPrefixOf(entryPath) 
922                                                                 && !otherPath.equals(entryPath)
923                                                                 && !Util.isExcluded(entryPath.append("*"), inclusionPatterns = ((ClasspathEntry)otherEntry).fullInclusionPatternChars(), exclusionPatterns = ((ClasspathEntry)otherEntry).fullExclusionPatternChars(), false)) { //$NON-NLS-1$
924                                                         String exclusionPattern = entryPath.removeFirstSegments(otherPath.segmentCount()).segment(0);
925                                                         if (Util.isExcluded(entryPath, inclusionPatterns, exclusionPatterns, false)) {
926                                                                 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.mustEndWithSlash", exclusionPattern, entryPath.makeRelative().toString())); //$NON-NLS-1$
927                                                         } else {
928                                                                 if (otherKind == IClasspathEntry.CPE_SOURCE) {
929                                                                         exclusionPattern += '/';
930                                                                         return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestEntryInEntry", new String[] {entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString(), exclusionPattern})); //$NON-NLS-1$
931                                                                 } else {
932                                                                         return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestEntryInLibrary", entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString())); //$NON-NLS-1$
933                                                                 }
934                                                         }
935                                                 }
936                                         }
937                                 }
938                         }
939                         
940                         // prevent nesting output location inside entry unless enclosing is a source entry which explicitly exclude the output location
941                     char[][] inclusionPatterns = ((ClasspathEntry)entry).fullInclusionPatternChars();
942                     char[][] exclusionPatterns = ((ClasspathEntry)entry).fullExclusionPatternChars();
943                     for (int j = 0; j < outputCount; j++){
944                         IPath currentOutput = outputLocations[j];
945                         if (entryPath.equals(currentOutput)) continue;
946                                 if (entryPath.isPrefixOf(currentOutput)) {
947                                     if (kind != IClasspathEntry.CPE_SOURCE || !Util.isExcluded(currentOutput, inclusionPatterns, exclusionPatterns, true)) {
948                                                 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestOutputInEntry", currentOutput.makeRelative().toString(), entryPath.makeRelative().toString())); //$NON-NLS-1$
949                                     }
950                                 }
951                     }
952
953                     // prevent nesting entry inside output location - when distinct from project or a source folder
954                     for (int j = 0; j < outputCount; j++){
955                         if (allowNestingInOutputLocations[j]) continue;
956                         IPath currentOutput = outputLocations[j];
957                                 if (currentOutput.isPrefixOf(entryPath)) {
958                                         return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestEntryInOutput", entryPath.makeRelative().toString(), currentOutput.makeRelative().toString())); //$NON-NLS-1$
959                                 }
960                     }                   
961                 }
962                 // ensure that no specific output is coincidating with another source folder (only allowed if matching current source folder)
963                 // 36465 - for 2.0 backward compatibility, only check specific output locations (the default can still coincidate)
964                 // perform one separate iteration so as to not take precedence over previously checked scenarii (in particular should
965                 // diagnose nesting source folder issue before this one, for example, [src]"Project/", [src]"Project/source/" and output="Project/" should
966                 // first complain about missing exclusion pattern
967                 for (int i = 0 ; i < length; i++) {
968                         IClasspathEntry entry = classpath[i];
969                         if (entry == null) continue;
970                         IPath entryPath = entry.getPath();
971                         int kind = entry.getEntryKind();
972
973                         // Build some common strings for status message
974                         boolean isProjectRelative = entryPath.segment(0).toString().equals(projectName);
975                         String entryPathMsg = isProjectRelative ? entryPath.removeFirstSegments(1).toString() : entryPath.makeRelative().toString();
976         
977                         if (kind == IClasspathEntry.CPE_SOURCE) {
978                                 IPath output = entry.getOutputLocation();
979                                 if (output == null) continue; // 36465 - for 2.0 backward compatibility, only check specific output locations (the default can still coincidate)
980                                 // if (output == null) output = projectOutputLocation; // if no specific output, still need to check using default output (this line would check default output)
981                                 for (int j = 0; j < length; j++) {
982                                         IClasspathEntry otherEntry = classpath[j];
983                                         if (otherEntry == entry) continue;
984
985                                         // Build some common strings for status message
986                                         boolean opStartsWithProject = otherEntry.getPath().segment(0).toString().equals(projectName);
987                                         String otherPathMsg = opStartsWithProject ? otherEntry.getPath().removeFirstSegments(1).toString() : otherEntry.getPath().makeRelative().toString();
988         
989                                         switch (otherEntry.getEntryKind()) {
990                                                 case IClasspathEntry.CPE_SOURCE :
991                                                         if (otherEntry.getPath().equals(output)) {
992                                                                 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotUseDistinctSourceFolderAsOutput", new String[] {entryPathMsg, otherPathMsg, projectName})); //$NON-NLS-1$
993                                                         }
994                                                         break;
995                                                 case IClasspathEntry.CPE_LIBRARY :
996                                                         if (otherEntry.getPath().equals(output)) {
997                                                                 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotUseLibraryAsOutput", new String[] {entryPathMsg, otherPathMsg, projectName})); //$NON-NLS-1$
998                                                         }
999                                         }
1000                                 }
1001                         }                       
1002                 }
1003                 return JavaModelStatus.VERIFIED_OK;     
1004         }
1005         
1006         /**
1007          * Returns a Java model status describing the problem related to this classpath entry if any, 
1008          * a status object with code <code>IStatus.OK</code> if the entry is fine (that is, if the
1009          * given classpath entry denotes a valid element to be referenced onto a classpath).
1010          * 
1011          * @param project the given java project
1012          * @param entry the given classpath entry
1013          * @param checkSourceAttachment a flag to determine if source attachement should be checked
1014          * @param recurseInContainers flag indicating whether validation should be applied to container entries recursively
1015          * @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
1016          */
1017         public static IJavaModelStatus validateClasspathEntry(IJavaProject project, IClasspathEntry entry, boolean checkSourceAttachment, boolean recurseInContainers){
1018                 
1019                 IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();                        
1020                 IPath path = entry.getPath();
1021         
1022                 // Build some common strings for status message
1023                 String projectName = project.getElementName();
1024                 boolean pathStartsWithProject = path.segment(0).toString().equals(projectName);
1025                 String entryPathMsg = pathStartsWithProject ? path.removeFirstSegments(1).toString() : path.makeRelative().toString();
1026         
1027                 switch(entry.getEntryKind()){
1028         
1029                         // container entry check
1030 //                      case IClasspathEntry.CPE_CONTAINER :
1031 //                              if (path != null && path.segmentCount() >= 1){
1032 //                                      try {
1033 //                                              IClasspathContainer container = JavaModelManager.getJavaModelManager().getClasspathContainer(path, project);
1034 //                                              // container retrieval is performing validation check on container entry kinds.
1035 //                                              if (container == null){
1036 //                                                      return new JavaModelStatus(IJavaModelStatusConstants.CP_CONTAINER_PATH_UNBOUND, project, path);
1037 //                                              } else if (container == JavaModelManager.CONTAINER_INITIALIZATION_IN_PROGRESS) {
1038 //                                                      // don't create a marker if initialization is in progress (case of cp initialization batching)
1039 //                                                      return JavaModelStatus.VERIFIED_OK;
1040 //                                              }
1041 //                                              IClasspathEntry[] containerEntries = container.getClasspathEntries();
1042 //                                              if (containerEntries != null){
1043 //                                                      for (int i = 0, length = containerEntries.length; i < length; i++){
1044 //                                                              IClasspathEntry containerEntry = containerEntries[i];
1045 //                                                              int kind = containerEntry == null ? 0 : containerEntry.getEntryKind();
1046 //                                                              if (containerEntry == null
1047 //                                                                      || kind == IClasspathEntry.CPE_SOURCE
1048 //                                                                      || kind == IClasspathEntry.CPE_VARIABLE
1049 //                                                                      || kind == IClasspathEntry.CPE_CONTAINER){
1050 //                                                                              String description = container.getDescription();
1051 //                                                                              if (description == null) description = path.makeRelative().toString();
1052 //                                                                              return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CP_CONTAINER_ENTRY, project, path);
1053 //                                                              }
1054 //                                                              if (recurseInContainers) {
1055 //                                                                      IJavaModelStatus containerEntryStatus = validateClasspathEntry(project, containerEntry, checkSourceAttachment, recurseInContainers);
1056 //                                                                      if (!containerEntryStatus.isOK()){
1057 //                                                                              return containerEntryStatus;
1058 //                                                                      }
1059 //                                                              } 
1060 //                                                      }
1061 //                                              }
1062 //                                      } catch(JavaModelException e){
1063 //                                              return new JavaModelStatus(e);
1064 //                                      }
1065 //                              } else {
1066 //                                      return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalContainerPath", entryPathMsg, projectName));                                         //$NON-NLS-1$
1067 //                              }
1068 //                              break;
1069                                 
1070                         // variable entry check
1071                         case IClasspathEntry.CPE_VARIABLE :
1072                                 if (path != null && path.segmentCount() >= 1){
1073                                         try {
1074                                                 entry = JavaCore.getResolvedClasspathEntry(entry);
1075                                         } catch (Assert.AssertionFailedException e) {
1076                                                 // Catch the assertion failure and throw java model exception instead
1077                                                 // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=55992
1078                                                 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, e.getMessage());
1079                                         }
1080                                         if (entry == null){
1081                                                 return new JavaModelStatus(IJavaModelStatusConstants.CP_VARIABLE_PATH_UNBOUND, project, path);
1082                                         }
1083                                         return validateClasspathEntry(project, entry, checkSourceAttachment, recurseInContainers);
1084                                 } else {
1085                                         return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalVariablePath", path.makeRelative().toString(), projectName));                                        //$NON-NLS-1$
1086                                 }
1087         
1088                         // library entry check
1089 //                      case IClasspathEntry.CPE_LIBRARY :
1090 //                              if (path != null && path.isAbsolute() && !path.isEmpty()) {
1091 //                                      IPath sourceAttachment = entry.getSourceAttachmentPath();
1092 //                                      Object target = JavaModel.getTarget(workspaceRoot, path, true);
1093 //                                      if (target != null && project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true) != JavaCore.IGNORE) {
1094 //                                              long projectTargetJDK = CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
1095 //                                              long libraryJDK = Util.getJdkLevel(target);
1096 //                                              if (libraryJDK != 0 && libraryJDK > projectTargetJDK) {
1097 //                                                      return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL, project, path, CompilerOptions.versionFromJdkLevel(libraryJDK)); 
1098 //                                              }
1099 //                                      }
1100 //                                      if (target instanceof IResource){
1101 //                                              IResource resolvedResource = (IResource) target;
1102 //                                              switch(resolvedResource.getType()){
1103 //                                                      case IResource.FILE :
1104 //                                                              if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(resolvedResource.getName())) {
1105 //                                                                      if (checkSourceAttachment 
1106 //                                                                              && sourceAttachment != null
1107 //                                                                              && !sourceAttachment.isEmpty()
1108 //                                                                              && JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
1109 //                                                                              return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundSourceAttachment", new String [] {sourceAttachment.makeRelative().toString(), path.makeRelative().toString(), projectName})); //$NON-NLS-1$
1110 //                                                                      }
1111 //                                                              } else {
1112 //                                                                      return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalLibraryArchive", entryPathMsg, projectName)); //$NON-NLS-1$
1113 //                                                              }
1114 //                                                              break;
1115 //                                                      case IResource.FOLDER : // internal binary folder
1116 //                                                              if (checkSourceAttachment 
1117 //                                                                      && sourceAttachment != null 
1118 //                                                                      && !sourceAttachment.isEmpty()
1119 //                                                                      && JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
1120 //                                                                      return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundSourceAttachment", new String [] {sourceAttachment.makeRelative().toString(), path.makeRelative().toString(), projectName})); //$NON-NLS-1$
1121 //                                                              }
1122 //                                              }
1123 //                                      } else if (target instanceof File){
1124 //                                          File file = (File) target;
1125 //                                          if (!file.isFile()) {
1126 //                                                      return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalExternalFolder", path.toOSString(), projectName)); //$NON-NLS-1$
1127 //                                          } else if (!org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(file.getName())) {
1128 //                                                      return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalLibraryArchive", path.toOSString(), projectName)); //$NON-NLS-1$
1129 //                                          } else if (checkSourceAttachment 
1130 //                                                              && sourceAttachment != null 
1131 //                                                              && !sourceAttachment.isEmpty()
1132 //                                                              && JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
1133 //                                                              return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundSourceAttachment", new String [] {sourceAttachment.toString(), path.makeRelative().toString(), projectName})); //$NON-NLS-1$
1134 //                                          }
1135 //                                      } else {
1136 //                                              return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundLibrary", path.makeRelative().toString(), projectName)); //$NON-NLS-1$
1137 //                                      }
1138 //                              } else {
1139 //                                      return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalLibraryPath", path.makeRelative().toString(), projectName)); //$NON-NLS-1$
1140 //                              }
1141 //                              break;
1142         
1143                         // project entry check
1144                         case IClasspathEntry.CPE_PROJECT :
1145                                 if (path != null && path.isAbsolute() && !path.isEmpty()) {
1146                                         IProject prereqProjectRsc = workspaceRoot.getProject(path.segment(0));
1147                                         IJavaProject prereqProject = JavaCore.create(prereqProjectRsc);
1148                                         try {
1149                                                 if (!prereqProjectRsc.exists() || !prereqProjectRsc.hasNature(PHPeclipsePlugin.PHP_NATURE_ID)){
1150                                                         return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundProject", path.makeRelative().segment(0).toString(), projectName)); //$NON-NLS-1$
1151                                                 }
1152                                                 if (!prereqProjectRsc.isOpen()){
1153                                                         return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.closedProject", path.segment(0).toString())); //$NON-NLS-1$
1154                                                 }
1155 //                                              if (project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true) != JavaCore.IGNORE) {
1156 //                                                      long projectTargetJDK = CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
1157 //                                                      long prereqProjectTargetJDK = CompilerOptions.versionToJdkLevel(prereqProject.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
1158 //                                                      if (prereqProjectTargetJDK > projectTargetJDK) {
1159 //                                                              return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL, project, path, CompilerOptions.versionFromJdkLevel(prereqProjectTargetJDK)); 
1160 //                                                      }
1161 //                                              }
1162                                         } catch (CoreException e){
1163                                                 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundProject", path.segment(0).toString(), projectName)); //$NON-NLS-1$
1164                                         }
1165                                 } else {
1166                                         return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalProjectPath", path.segment(0).toString(), projectName)); //$NON-NLS-1$
1167                                 }
1168                                 break;
1169         
1170                         // project source folder
1171                         case IClasspathEntry.CPE_SOURCE :
1172                                 if (((entry.getInclusionPatterns() != null && entry.getInclusionPatterns().length > 0)
1173                                                 || (entry.getExclusionPatterns() != null && entry.getExclusionPatterns().length > 0))
1174                                                 && JavaCore.DISABLED.equals(project.getOption(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, true))) {
1175                                         return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_EXCLUSION_PATTERNS, project, path);
1176                                 }
1177                                 if (entry.getOutputLocation() != null && JavaCore.DISABLED.equals(project.getOption(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, true))) {
1178                                         return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS, project, path);
1179                                 }
1180                                 if (path != null && path.isAbsolute() && !path.isEmpty()) {
1181                                         IPath projectPath= project.getProject().getFullPath();
1182                                         if (!projectPath.isPrefixOf(path) || JavaModel.getTarget(workspaceRoot, path, true) == null){
1183                                                 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundSourceFolder", entryPathMsg, projectName)); //$NON-NLS-1$
1184                                         }
1185                                 } else {
1186                                         return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalSourceFolderPath", entryPathMsg, projectName)); //$NON-NLS-1$
1187                                 }
1188                                 break;
1189                 }
1190                 return JavaModelStatus.VERIFIED_OK;             
1191         }
1192 }
1193