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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
13 import net.sourceforge.phpdt.core.IClasspathEntry;
14 import net.sourceforge.phpdt.core.IJavaProject;
15 import net.sourceforge.phpdt.core.IPackageFragmentRoot;
16 import net.sourceforge.phpdt.core.JavaModelException;
17 import net.sourceforge.phpdt.core.JavaCore;
18 import net.sourceforge.phpdt.core.compiler.CharOperation;
19 import net.sourceforge.phpdt.internal.corext.Assert;
21 import org.eclipse.core.runtime.IPath;
22 import org.eclipse.core.runtime.Path;
23 import org.w3c.dom.Document;
24 import org.w3c.dom.Element;
27 * @see IClasspathEntry
29 public class ClasspathEntry implements IClasspathEntry {
32 * Describes the kind of classpath entry - one of
33 * CPE_PROJECT, CPE_LIBRARY, CPE_SOURCE, CPE_VARIABLE or CPE_CONTAINER
38 * Describes the kind of package fragment roots found on
39 * this classpath entry - either K_BINARY or K_SOURCE or
42 public int contentKind;
45 * The meaning of the path of a classpath entry depends on its entry kind:<ul>
46 * <li>Source code in the current project (<code>CPE_SOURCE</code>) -
47 * The path associated with this entry is the absolute path to the root folder. </li>
48 * <li>A binary library in the current project (<code>CPE_LIBRARY</code>) - the path
49 * associated with this entry is the absolute path to the JAR (or root folder), and
50 * in case it refers to an external JAR, then there is no associated resource in
52 * <li>A required project (<code>CPE_PROJECT</code>) - the path of the entry denotes the
53 * path to the corresponding project resource.</li>
54 * <li>A variable entry (<code>CPE_VARIABLE</code>) - the first segment of the path
55 * is the name of a classpath variable. If this classpath variable
56 * is bound to the path <it>P</it>, the path of the corresponding classpath entry
57 * is computed by appending to <it>P</it> the segments of the returned
58 * path without the variable.</li>
59 * <li> A container entry (<code>CPE_CONTAINER</code>) - the first segment of the path is denoting
60 * the unique container identifier (for which a <code>ClasspathContainerInitializer</code> could be
61 * registered), and the remaining segments are used as additional hints for resolving the container entry to
62 * an actual <code>IClasspathContainer</code>.</li>
67 * Patterns allowing to exclude portions of the resource tree denoted by this entry path.
70 public IPath[] exclusionPatterns;
71 private char[][] fullCharExclusionPatterns;
72 private final static char[][] UNINIT_PATTERNS = new char[][] { "Non-initialized yet".toCharArray() }; //$NON-NLS-1$
74 private String rootID;
77 * Default exclusion pattern set
79 public final static IPath[] NO_EXCLUSION_PATTERNS = {};
82 * Describes the path to the source archive associated with this
83 * classpath entry, or <code>null</code> if this classpath entry has no
86 * Only library and variable classpath entries may have source attachments.
87 * For library classpath entries, the result path (if present) locates a source
88 * archive. For variable classpath entries, the result path (if present) has
89 * an analogous form and meaning as the variable path, namely the first segment
90 * is the name of a classpath variable.
92 public IPath sourceAttachmentPath;
95 * Describes the path within the source archive where package fragments
96 * are located. An empty path indicates that packages are located at
97 * the root of the source archive. Returns a non-<code>null</code> value
98 * if and only if <code>getSourceAttachmentPath</code> returns
99 * a non-<code>null</code> value.
101 public IPath sourceAttachmentRootPath;
104 * Specific output location (for this source entry)
106 public IPath specificOutputLocation;
109 * A constant indicating an output location.
111 public static final int K_OUTPUT = 10;
116 public boolean isExported;
119 * Creates a class path entry of the specified kind with the given path.
121 public ClasspathEntry(
125 IPath[] exclusionPatterns,
126 IPath sourceAttachmentPath,
127 IPath sourceAttachmentRootPath,
128 IPath specificOutputLocation,
129 boolean isExported) {
131 this.contentKind = contentKind;
132 this.entryKind = entryKind;
134 this.exclusionPatterns = exclusionPatterns;
135 if (exclusionPatterns.length > 0) {
136 this.fullCharExclusionPatterns = UNINIT_PATTERNS;
138 this.sourceAttachmentPath = sourceAttachmentPath;
139 this.sourceAttachmentRootPath = sourceAttachmentRootPath;
140 this.specificOutputLocation = specificOutputLocation;
141 this.isExported = isExported;
145 * Returns a char based representation of the exclusions patterns full path.
147 public char[][] fullExclusionPatternChars() {
149 if (this.fullCharExclusionPatterns == UNINIT_PATTERNS) {
150 int length = this.exclusionPatterns.length;
151 this.fullCharExclusionPatterns = new char[length][];
152 IPath prefixPath = path.removeTrailingSeparator();
153 for (int i = 0; i < length; i++) {
154 this.fullCharExclusionPatterns[i] =
155 prefixPath.append(this.exclusionPatterns[i]).toString().toCharArray();
158 return this.fullCharExclusionPatterns;
162 * Returns the XML encoding of the class path.
164 public Element elementEncode(
167 throws JavaModelException {
169 Element element = document.createElement("classpathentry"); //$NON-NLS-1$
170 element.setAttribute("kind", kindToString(this.entryKind)); //$NON-NLS-1$
171 IPath xmlPath = this.path;
172 if (this.entryKind != IClasspathEntry.CPE_VARIABLE && this.entryKind != IClasspathEntry.CPE_CONTAINER) {
173 // translate to project relative from absolute (unless a device path)
174 if (xmlPath.isAbsolute()) {
175 if (projectPath != null && projectPath.isPrefixOf(xmlPath)) {
176 if (xmlPath.segment(0).equals(projectPath.segment(0))) {
177 xmlPath = xmlPath.removeFirstSegments(1);
178 xmlPath = xmlPath.makeRelative();
180 xmlPath = xmlPath.makeAbsolute();
185 element.setAttribute("path", xmlPath.toString()); //$NON-NLS-1$
186 if (this.sourceAttachmentPath != null) {
187 element.setAttribute("sourcepath", this.sourceAttachmentPath.toString()); //$NON-NLS-1$
189 if (this.sourceAttachmentRootPath != null) {
190 element.setAttribute("rootpath", this.sourceAttachmentRootPath.toString()); //$NON-NLS-1$
192 if (this.isExported) {
193 element.setAttribute("exported", "true"); //$NON-NLS-1$ //$NON-NLS-2$
196 if (this.exclusionPatterns.length > 0) {
197 StringBuffer excludeRule = new StringBuffer(10);
198 for (int i = 0, max = this.exclusionPatterns.length; i < max; i++){
199 if (i > 0) excludeRule.append('|');
200 excludeRule.append(this.exclusionPatterns[i]);
202 element.setAttribute("excluding", excludeRule.toString()); //$NON-NLS-1$
205 if (this.specificOutputLocation != null) {
206 IPath outputLocation = this.specificOutputLocation.removeFirstSegments(1);
207 outputLocation = outputLocation.makeRelative();
208 element.setAttribute("output", outputLocation.toString()); //$NON-NLS-1$
213 public static IClasspathEntry elementDecode(Element element, IJavaProject project) {
215 IPath projectPath = project.getProject().getFullPath();
216 String kindAttr = element.getAttribute("kind"); //$NON-NLS-1$
217 String pathAttr = element.getAttribute("path"); //$NON-NLS-1$
219 // ensure path is absolute
220 IPath path = new Path(pathAttr);
221 int kind = kindFromString(kindAttr);
222 if (kind != IClasspathEntry.CPE_VARIABLE && kind != IClasspathEntry.CPE_CONTAINER && !path.isAbsolute()) {
223 path = projectPath.append(path);
225 // source attachment info (optional)
226 IPath sourceAttachmentPath =
227 element.hasAttribute("sourcepath") //$NON-NLS-1$
228 ? new Path(element.getAttribute("sourcepath")) //$NON-NLS-1$
230 IPath sourceAttachmentRootPath =
231 element.hasAttribute("rootpath") //$NON-NLS-1$
232 ? new Path(element.getAttribute("rootpath")) //$NON-NLS-1$
235 // exported flag (optional)
236 boolean isExported = element.getAttribute("exported").equals("true"); //$NON-NLS-1$ //$NON-NLS-2$
238 // exclusion patterns (optional)
239 String exclusion = element.getAttribute("excluding"); //$NON-NLS-1$
240 IPath[] exclusionPatterns = ClasspathEntry.NO_EXCLUSION_PATTERNS;
241 if (!exclusion.equals("")) { //$NON-NLS-1$
242 char[][] patterns = CharOperation.splitOn('|', exclusion.toCharArray());
244 if ((patternCount = patterns.length) > 0) {
245 exclusionPatterns = new IPath[patternCount];
246 for (int j = 0; j < patterns.length; j++){
247 exclusionPatterns[j] = new Path(new String(patterns[j]));
252 // custom output location
253 IPath outputLocation = element.hasAttribute("output") ? projectPath.append(element.getAttribute("output")) : null; //$NON-NLS-1$ //$NON-NLS-2$
255 // recreate the CP entry
258 case IClasspathEntry.CPE_PROJECT :
259 return JavaCore.newProjectEntry(path, isExported);
261 // case IClasspathEntry.CPE_LIBRARY :
262 // return JavaCore.newLibraryEntry(
264 // sourceAttachmentPath,
265 // sourceAttachmentRootPath,
268 case IClasspathEntry.CPE_SOURCE :
269 // must be an entry in this project or specify another project
270 String projSegment = path.segment(0);
271 if (projSegment != null && projSegment.equals(project.getElementName())) { // this project
272 return JavaCore.newSourceEntry(path, exclusionPatterns, outputLocation);
273 } else { // another project
274 return JavaCore.newProjectEntry(path, isExported);
277 // case IClasspathEntry.CPE_VARIABLE :
278 // return PHPCore.newVariableEntry(
280 // sourceAttachmentPath,
281 // sourceAttachmentRootPath,
284 case IClasspathEntry.CPE_CONTAINER :
285 return JavaCore.newContainerEntry(
289 case ClasspathEntry.K_OUTPUT :
290 if (!path.isAbsolute()) return null;
291 return new ClasspathEntry(
292 ClasspathEntry.K_OUTPUT,
293 IClasspathEntry.CPE_LIBRARY,
295 ClasspathEntry.NO_EXCLUSION_PATTERNS,
296 null, // source attachment
297 null, // source attachment root
298 null, // custom output location
301 throw new Assert.AssertionFailedException(Util.bind("classpath.unknownKind", kindAttr)); //$NON-NLS-1$
306 * Returns true if the given object is a classpath entry
307 * with equivalent attributes.
309 public boolean equals(Object object) {
312 if (object instanceof IClasspathEntry) {
313 IClasspathEntry otherEntry = (IClasspathEntry) object;
315 if (this.contentKind != otherEntry.getContentKind())
318 if (this.entryKind != otherEntry.getEntryKind())
321 if (this.isExported != otherEntry.isExported())
324 if (!this.path.equals(otherEntry.getPath()))
327 IPath otherPath = otherEntry.getSourceAttachmentPath();
328 if (this.sourceAttachmentPath == null) {
329 if (otherPath != null)
332 if (!this.sourceAttachmentPath.equals(otherPath))
336 otherPath = otherEntry.getSourceAttachmentRootPath();
337 if (this.sourceAttachmentRootPath == null) {
338 if (otherPath != null)
341 if (!this.sourceAttachmentRootPath.equals(otherPath))
345 IPath[] otherExcludes = otherEntry.getExclusionPatterns();
346 if (this.exclusionPatterns != otherExcludes){
347 int excludeLength = this.exclusionPatterns.length;
348 if (otherExcludes.length != excludeLength)
350 for (int i = 0; i < excludeLength; i++) {
351 // compare toStrings instead of IPaths
352 // since IPath.equals is specified to ignore trailing separators
353 if (!this.exclusionPatterns[i].toString().equals(otherExcludes[i].toString()))
358 otherPath = otherEntry.getOutputLocation();
359 if (this.specificOutputLocation == null) {
360 if (otherPath != null)
363 if (!this.specificOutputLocation.equals(otherPath))
373 * @see IClasspathEntry
375 public int getContentKind() {
376 return this.contentKind;
380 * @see IClasspathEntry
382 public int getEntryKind() {
383 return this.entryKind;
387 * @see IClasspathEntry#getExclusionPatterns()
389 public IPath[] getExclusionPatterns() {
390 return this.exclusionPatterns;
394 * @see IClasspathEntry#getOutputLocation()
396 public IPath getOutputLocation() {
397 return this.specificOutputLocation;
401 * @see IClasspathEntry
403 public IPath getPath() {
408 * @see IClasspathEntry
410 public IPath getSourceAttachmentPath() {
411 return this.sourceAttachmentPath;
415 * @see IClasspathEntry
417 public IPath getSourceAttachmentRootPath() {
418 return this.sourceAttachmentRootPath;
422 * Returns the hash code for this classpath entry
424 public int hashCode() {
425 return this.path.hashCode();
429 * @see IClasspathEntry#isExported()
431 public boolean isExported() {
432 return this.isExported;
436 * Returns the kind of a <code>PackageFragmentRoot</code> from its <code>String</code> form.
438 static int kindFromString(String kindStr) {
440 if (kindStr.equalsIgnoreCase("prj")) //$NON-NLS-1$
441 return IClasspathEntry.CPE_PROJECT;
442 if (kindStr.equalsIgnoreCase("var")) //$NON-NLS-1$
443 return IClasspathEntry.CPE_VARIABLE;
444 if (kindStr.equalsIgnoreCase("con")) //$NON-NLS-1$
445 return IClasspathEntry.CPE_CONTAINER;
446 if (kindStr.equalsIgnoreCase("src")) //$NON-NLS-1$
447 return IClasspathEntry.CPE_SOURCE;
448 if (kindStr.equalsIgnoreCase("lib")) //$NON-NLS-1$
449 return IClasspathEntry.CPE_LIBRARY;
450 if (kindStr.equalsIgnoreCase("output")) //$NON-NLS-1$
451 return ClasspathEntry.K_OUTPUT;
456 * Returns a <code>String</code> for the kind of a class path entry.
458 static String kindToString(int kind) {
461 case IClasspathEntry.CPE_PROJECT :
462 return "src"; // backward compatibility //$NON-NLS-1$
463 case IClasspathEntry.CPE_SOURCE :
464 return "src"; //$NON-NLS-1$
465 case IClasspathEntry.CPE_LIBRARY :
466 return "lib"; //$NON-NLS-1$
467 case IClasspathEntry.CPE_VARIABLE :
468 return "var"; //$NON-NLS-1$
469 case IClasspathEntry.CPE_CONTAINER :
470 return "con"; //$NON-NLS-1$
471 case ClasspathEntry.K_OUTPUT :
472 return "output"; //$NON-NLS-1$
474 return "unknown"; //$NON-NLS-1$
479 * Returns a printable representation of this classpath entry.
481 public String toString() {
482 StringBuffer buffer = new StringBuffer();
483 buffer.append(getPath().toString());
485 switch (getEntryKind()) {
486 case IClasspathEntry.CPE_LIBRARY :
487 buffer.append("CPE_LIBRARY"); //$NON-NLS-1$
489 case IClasspathEntry.CPE_PROJECT :
490 buffer.append("CPE_PROJECT"); //$NON-NLS-1$
492 case IClasspathEntry.CPE_SOURCE :
493 buffer.append("CPE_SOURCE"); //$NON-NLS-1$
495 case IClasspathEntry.CPE_VARIABLE :
496 buffer.append("CPE_VARIABLE"); //$NON-NLS-1$
498 case IClasspathEntry.CPE_CONTAINER :
499 buffer.append("CPE_CONTAINER"); //$NON-NLS-1$
502 buffer.append("]["); //$NON-NLS-1$
503 switch (getContentKind()) {
504 case IPackageFragmentRoot.K_BINARY :
505 buffer.append("K_BINARY"); //$NON-NLS-1$
507 case IPackageFragmentRoot.K_SOURCE :
508 buffer.append("K_SOURCE"); //$NON-NLS-1$
510 case ClasspathEntry.K_OUTPUT :
511 buffer.append("K_OUTPUT"); //$NON-NLS-1$
515 if (getSourceAttachmentPath() != null) {
516 buffer.append("[sourcePath:"); //$NON-NLS-1$
517 buffer.append(getSourceAttachmentPath());
520 if (getSourceAttachmentRootPath() != null) {
521 buffer.append("[rootPath:"); //$NON-NLS-1$
522 buffer.append(getSourceAttachmentRootPath());
525 buffer.append("[isExported:"); //$NON-NLS-1$
526 buffer.append(this.isExported);
528 IPath[] patterns = getExclusionPatterns();
530 if ((length = patterns.length) > 0) {
531 buffer.append("[excluding:"); //$NON-NLS-1$
532 for (int i = 0; i < length; i++) {
533 buffer.append(patterns[i]);
540 if (getOutputLocation() != null) {
541 buffer.append("[output:"); //$NON-NLS-1$
542 buffer.append(getOutputLocation());
545 return buffer.toString();
549 * Answers an ID which is used to distinguish entries during package
550 * fragment root computations
552 public String rootID(){
554 if (this.rootID == null) {
555 switch(this.entryKind){
556 case IClasspathEntry.CPE_LIBRARY :
557 this.rootID = "[LIB]"+this.path; //$NON-NLS-1$
559 case IClasspathEntry.CPE_PROJECT :
560 this.rootID = "[PRJ]"+this.path; //$NON-NLS-1$
562 case IClasspathEntry.CPE_SOURCE :
563 this.rootID = "[SRC]"+this.path; //$NON-NLS-1$
565 case IClasspathEntry.CPE_VARIABLE :
566 this.rootID = "[VAR]"+this.path; //$NON-NLS-1$
568 case IClasspathEntry.CPE_CONTAINER :
569 this.rootID = "[CON]"+this.path; //$NON-NLS-1$
572 this.rootID = ""; //$NON-NLS-1$
580 * @see IClasspathEntry
583 public IClasspathEntry getResolvedEntry() {
585 return JavaCore.getResolvedClasspathEntry(this);