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