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