KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > JavaProject


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.core;
12
13 import java.io.*;
14 import java.net.URI JavaDoc;
15 import java.util.ArrayList JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.HashSet JavaDoc;
18 import java.util.Hashtable JavaDoc;
19 import java.util.Iterator JavaDoc;
20 import java.util.Map JavaDoc;
21
22 import javax.xml.parsers.DocumentBuilder JavaDoc;
23 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
24 import javax.xml.parsers.ParserConfigurationException JavaDoc;
25 import org.eclipse.core.resources.ICommand;
26 import org.eclipse.core.resources.IFile;
27 import org.eclipse.core.resources.IFolder;
28 import org.eclipse.core.resources.IMarker;
29 import org.eclipse.core.resources.IProject;
30 import org.eclipse.core.resources.IProjectDescription;
31 import org.eclipse.core.resources.IProjectNature;
32 import org.eclipse.core.resources.IResource;
33 import org.eclipse.core.resources.IWorkspace;
34 import org.eclipse.core.resources.IWorkspaceRoot;
35 import org.eclipse.core.resources.ProjectScope;
36 import org.eclipse.core.resources.ResourcesPlugin;
37 import org.eclipse.core.runtime.AssertionFailedException;
38 import org.eclipse.core.runtime.CoreException;
39 import org.eclipse.core.runtime.IPath;
40 import org.eclipse.core.runtime.IProgressMonitor;
41 import org.eclipse.core.runtime.IStatus;
42 import org.eclipse.core.runtime.Path;
43 import org.eclipse.core.runtime.Preferences;
44 import org.eclipse.core.runtime.QualifiedName;
45 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
46 import org.eclipse.core.runtime.preferences.IScopeContext;
47 import org.eclipse.jdt.core.IClasspathContainer;
48 import org.eclipse.jdt.core.IClasspathEntry;
49 import org.eclipse.jdt.core.ICompilationUnit;
50 import org.eclipse.jdt.core.IJavaElement;
51 import org.eclipse.jdt.core.IJavaModelMarker;
52 import org.eclipse.jdt.core.IJavaModelStatus;
53 import org.eclipse.jdt.core.IJavaModelStatusConstants;
54 import org.eclipse.jdt.core.IJavaProject;
55 import org.eclipse.jdt.core.IPackageFragment;
56 import org.eclipse.jdt.core.IPackageFragmentRoot;
57 import org.eclipse.jdt.core.IRegion;
58 import org.eclipse.jdt.core.IType;
59 import org.eclipse.jdt.core.ITypeHierarchy;
60 import org.eclipse.jdt.core.JavaCore;
61 import org.eclipse.jdt.core.JavaModelException;
62 import org.eclipse.jdt.core.WorkingCopyOwner;
63 import org.eclipse.jdt.core.compiler.CategorizedProblem;
64 import org.eclipse.jdt.core.compiler.CharOperation;
65 import org.eclipse.jdt.core.eval.IEvaluationContext;
66 import org.eclipse.jdt.internal.compiler.util.ObjectVector;
67 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
68 import org.eclipse.jdt.internal.core.JavaModelManager.PerProjectInfo;
69 import org.eclipse.jdt.internal.core.JavaProjectElementInfo.ProjectCache;
70 import org.eclipse.jdt.internal.core.builder.JavaBuilder;
71 import org.eclipse.jdt.internal.core.eval.EvaluationContextWrapper;
72 import org.eclipse.jdt.internal.core.util.MementoTokenizer;
73 import org.eclipse.jdt.internal.core.util.Messages;
74 import org.eclipse.jdt.internal.core.util.Util;
75 import org.eclipse.jdt.internal.eval.EvaluationContext;
76 import org.osgi.service.prefs.BackingStoreException;
77 import org.w3c.dom.Element JavaDoc;
78 import org.w3c.dom.Node JavaDoc;
79 import org.w3c.dom.NodeList JavaDoc;
80 import org.xml.sax.InputSource JavaDoc;
81 import org.xml.sax.SAXException JavaDoc;
82
83 /**
84  * Handle for a Java Project.
85  *
86  * <p>A Java Project internally maintains a devpath that corresponds
87  * to the project's classpath. The classpath may include source folders
88  * from the current project; jars in the current project, other projects,
89  * and the local file system; and binary folders (output location) of other
90  * projects. The Java Model presents source elements corresponding to output
91  * .class files in other projects, and thus uses the devpath rather than
92  * the classpath (which is really a compilation path). The devpath mimics
93  * the classpath, except has source folder entries in place of output
94  * locations in external projects.
95  *
96  * <p>Each JavaProject has a NameLookup facility that locates elements
97  * on by name, based on the devpath.
98  *
99  * @see IJavaProject
100  */

101 public class JavaProject
102     extends Openable
103     implements IJavaProject, IProjectNature, SuffixConstants {
104     
105     /**
106      * Name of file containing project classpath
107      */

108     public static final String JavaDoc CLASSPATH_FILENAME = ".classpath"; //$NON-NLS-1$
109

110     /**
111      * Value of the project's raw classpath if the .classpath file contains invalid entries.
112      */

113     public static final IClasspathEntry[] INVALID_CLASSPATH = new IClasspathEntry[0];
114
115     /**
116      * Whether the underlying file system is case sensitive.
117      */

118     protected static final boolean IS_CASE_SENSITIVE = !new File("Temp").equals(new File("temp")); //$NON-NLS-1$ //$NON-NLS-2$
119

120     /**
121      * An empty array of strings indicating that a project doesn't have any prerequesite projects.
122      */

123     protected static final String JavaDoc[] NO_PREREQUISITES = CharOperation.NO_STRINGS;
124
125     /**
126      * Name of file containing custom project preferences
127      * @see <a HREF="https://bugs.eclipse.org/bugs/show_bug.cgi?id=59258">bug 59258</a>
128      */

129     private static final String JavaDoc PREF_FILENAME = ".jprefs"; //$NON-NLS-1$
130

131     /**
132      * Name of directory containing preferences file
133      */

134     public static final String JavaDoc DEFAULT_PREFERENCES_DIRNAME = ".settings"; //$NON-NLS-1$
135

136     /**
137      * Extension for file containing custom project preferences
138      */

139     public static final String JavaDoc JAVA_CORE_PREFS_FILE = JavaCore.PLUGIN_ID+".prefs"; //$NON-NLS-1$
140

141     /*
142      * Value of project's resolved classpath while it is being resolved
143      */

144     private static final IClasspathEntry[] RESOLUTION_IN_PROGRESS = new IClasspathEntry[0];
145
146     /**
147      * The platform project this <code>IJavaProject</code> is based on
148      */

149     protected IProject project;
150     
151     /**
152      * Constructor needed for <code>IProject.getNature()</code> and <code>IProject.addNature()</code>.
153      *
154      * @see #setProject(IProject)
155      */

156     public JavaProject() {
157         super(null);
158     }
159     
160     public JavaProject(IProject project, JavaElement parent) {
161         super(parent);
162         this.project = project;
163     }
164
165     public static boolean areClasspathsEqual(
166             IClasspathEntry[] firstClasspath, IClasspathEntry[] secondClasspath,
167             IPath firstOutputLocation, IPath secondOutputLocation) {
168         int length = firstClasspath.length;
169         if (length != secondClasspath.length) return false;
170         for (int i = 0; i < length; i++) {
171             if (!firstClasspath[i].equals(secondClasspath[i]))
172                 return false;
173         }
174         if (firstOutputLocation == null)
175             return secondOutputLocation == null;
176         return firstOutputLocation.equals(secondOutputLocation);
177     }
178
179     /**
180      * Compare current classpath with given one to see if any different.
181      * Note that the argument classpath contains its binary output.
182      * @param newClasspath IClasspathEntry[]
183      * @param newOutputLocation IPath
184      * @param otherClasspathWithOutput IClasspathEntry[]
185      * @return boolean
186      */

187     private static boolean areClasspathsEqual(IClasspathEntry[] newClasspath, IPath newOutputLocation, IClasspathEntry[] otherClasspathWithOutput) {
188
189         if (otherClasspathWithOutput == null || otherClasspathWithOutput.length == 0)
190             return false;
191
192         int length = otherClasspathWithOutput.length;
193         if (length != newClasspath.length + 1)
194                 // output is amongst file entries (last one)
195
return false;
196         
197         
198         // compare classpath entries
199
for (int i = 0; i < length - 1; i++) {
200             if (!otherClasspathWithOutput[i].equals(newClasspath[i]))
201                 return false;
202         }
203         // compare binary outputs
204
IClasspathEntry output = otherClasspathWithOutput[length - 1];
205         if (output.getContentKind() != ClasspathEntry.K_OUTPUT
206                 || !output.getPath().equals(newOutputLocation))
207             return false;
208         return true;
209     }
210
211     /**
212      * Returns a canonicalized path from the given external path.
213      * Note that the return path contains the same number of segments
214      * and it contains a device only if the given path contained one.
215      * @param externalPath IPath
216      * @see java.io.File for the definition of a canonicalized path
217      * @return IPath
218      */

219     public static IPath canonicalizedPath(IPath externalPath) {
220         
221         if (externalPath == null)
222             return null;
223
224 // if (JavaModelManager.VERBOSE) {
225
// System.out.println("JAVA MODEL - Canonicalizing " + externalPath.toString());
226
// }
227

228         if (IS_CASE_SENSITIVE) {
229 // if (JavaModelManager.VERBOSE) {
230
// System.out.println("JAVA MODEL - Canonical path is original path (file system is case sensitive)");
231
// }
232
return externalPath;
233         }
234
235         // if not external path, return original path
236
IWorkspace workspace = ResourcesPlugin.getWorkspace();
237         if (workspace == null) return externalPath; // protection during shutdown (30487)
238
if (workspace.getRoot().findMember(externalPath) != null) {
239 // if (JavaModelManager.VERBOSE) {
240
// System.out.println("JAVA MODEL - Canonical path is original path (member of workspace)");
241
// }
242
return externalPath;
243         }
244
245         IPath canonicalPath = null;
246         try {
247             canonicalPath =
248                 new Path(new File(externalPath.toOSString()).getCanonicalPath());
249         } catch (IOException e) {
250             // default to original path
251
// if (JavaModelManager.VERBOSE) {
252
// System.out.println("JAVA MODEL - Canonical path is original path (IOException)");
253
// }
254
return externalPath;
255         }
256         
257         IPath result;
258         int canonicalLength = canonicalPath.segmentCount();
259         if (canonicalLength == 0) {
260             // the java.io.File canonicalization failed
261
// if (JavaModelManager.VERBOSE) {
262
// System.out.println("JAVA MODEL - Canonical path is original path (canonical path is empty)");
263
// }
264
return externalPath;
265         } else if (externalPath.isAbsolute()) {
266             result = canonicalPath;
267         } else {
268             // if path is relative, remove the first segments that were added by the java.io.File canonicalization
269
// e.g. 'lib/classes.zip' was converted to 'd:/myfolder/lib/classes.zip'
270
int externalLength = externalPath.segmentCount();
271             if (canonicalLength >= externalLength) {
272                 result = canonicalPath.removeFirstSegments(canonicalLength - externalLength);
273             } else {
274 // if (JavaModelManager.VERBOSE) {
275
// System.out.println("JAVA MODEL - Canonical path is original path (canonical path is " + canonicalPath.toString() + ")");
276
// }
277
return externalPath;
278             }
279         }
280         
281         // keep device only if it was specified (this is because File.getCanonicalPath() converts '/lib/classed.zip' to 'd:/lib/classes/zip')
282
if (externalPath.getDevice() == null) {
283             result = result.setDevice(null);
284         }
285 // if (JavaModelManager.VERBOSE) {
286
// System.out.println("JAVA MODEL - Canonical path is " + result.toString());
287
// }
288
return result;
289     }
290
291     /**
292      * Returns true if the given project is accessible and it has
293      * a java nature, otherwise false.
294      * @param project IProject
295      * @return boolean
296      */

297     public static boolean hasJavaNature(IProject project) {
298         try {
299             return project.hasNature(JavaCore.NATURE_ID);
300         } catch (CoreException e) {
301             if (ExternalJavaProject.EXTERNAL_PROJECT_NAME.equals(project.getName()))
302                 return true;
303             // project does not exist or is not open
304
}
305         return false;
306     }
307
308     /*
309      * Detect cycles in the classpath of the workspace's projects
310      * and create markers if necessary.
311      * @param preferredClasspaths Map
312      * @throws JavaModelException
313      */

314     public static void validateCycles(Map JavaDoc preferredClasspaths) throws JavaModelException {
315
316         //long start = System.currentTimeMillis();
317

318         IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
319         IProject[] rscProjects = workspaceRoot.getProjects();
320         int length = rscProjects.length;
321         JavaProject[] projects = new JavaProject[length];
322                 
323         HashSet JavaDoc cycleParticipants = new HashSet JavaDoc();
324         HashSet JavaDoc traversed = new HashSet JavaDoc();
325         
326         // compute cycle participants
327
ArrayList JavaDoc prereqChain = new ArrayList JavaDoc();
328         for (int i = 0; i < length; i++){
329             if (hasJavaNature(rscProjects[i])) {
330                 JavaProject project = (projects[i] = (JavaProject)JavaCore.create(rscProjects[i]));
331                 if (!traversed.contains(project.getPath())){
332                     prereqChain.clear();
333                     project.updateCycleParticipants(prereqChain, cycleParticipants, workspaceRoot, traversed, preferredClasspaths);
334                 }
335             }
336         }
337         //System.out.println("updateAllCycleMarkers: " + (System.currentTimeMillis() - start) + " ms");
338

339         for (int i = 0; i < length; i++){
340             JavaProject project = projects[i];
341             if (project != null) {
342                 if (cycleParticipants.contains(project.getPath())){
343                     IMarker cycleMarker = project.getCycleMarker();
344                     String JavaDoc circularCPOption = project.getOption(JavaCore.CORE_CIRCULAR_CLASSPATH, true);
345                     int circularCPSeverity = JavaCore.ERROR.equals(circularCPOption) ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING;
346                     if (cycleMarker != null) {
347                         // update existing cycle marker if needed
348
try {
349                             int existingSeverity = ((Integer JavaDoc)cycleMarker.getAttribute(IMarker.SEVERITY)).intValue();
350                             if (existingSeverity != circularCPSeverity) {
351                                 cycleMarker.setAttribute(IMarker.SEVERITY, circularCPSeverity);
352                             }
353                         } catch (CoreException e) {
354                             throw new JavaModelException(e);
355                         }
356                     } else {
357                         // create new marker
358
project.createClasspathProblemMarker(
359                             new JavaModelStatus(IJavaModelStatusConstants.CLASSPATH_CYCLE, project));
360                     }
361                 } else {
362                     project.flushClasspathProblemMarkers(true, false);
363                 }
364             }
365         }
366     }
367
368     /**
369      * Adds a builder to the build spec for the given project.
370      */

371     protected void addToBuildSpec(String JavaDoc builderID) throws CoreException {
372
373         IProjectDescription description = this.project.getDescription();
374         int javaCommandIndex = getJavaCommandIndex(description.getBuildSpec());
375
376         if (javaCommandIndex == -1) {
377
378             // Add a Java command to the build spec
379
ICommand command = description.newCommand();
380             command.setBuilderName(builderID);
381             setJavaCommand(description, command);
382         }
383     }
384     /**
385      * @see Openable
386      */

387     protected boolean buildStructure(OpenableElementInfo info, IProgressMonitor pm, Map JavaDoc newElements, IResource underlyingResource) throws JavaModelException {
388     
389         // check whether the java project can be opened
390
if (!hasJavaNature((IProject) underlyingResource)) {
391             throw newNotPresentException();
392         }
393         
394         // cannot refresh cp markers on opening (emulate cp check on startup) since can create deadlocks (see bug 37274)
395
IClasspathEntry[] resolvedClasspath = getResolvedClasspath();
396
397         // compute the pkg fragment roots
398
info.setChildren(computePackageFragmentRoots(resolvedClasspath, false, null /*no reverse map*/));
399         
400         // remember the timestamps of external libraries the first time they are looked up
401
getPerProjectInfo().rememberExternalLibTimestamps();
402
403         return true;
404     }
405
406     /**
407      * Computes the collection of package fragment roots (local ones) and set it on the given info.
408      * Need to check *all* package fragment roots in order to reset NameLookup
409      * @param info JavaProjectElementInfo
410      * @throws JavaModelException
411      */

412     public void computeChildren(JavaProjectElementInfo info) throws JavaModelException {
413         IClasspathEntry[] classpath = getResolvedClasspath();
414         JavaProjectElementInfo.ProjectCache projectCache = info.projectCache;
415         if (projectCache != null) {
416             IPackageFragmentRoot[] newRoots = computePackageFragmentRoots(classpath, true, null /*no reverse map*/);
417             checkIdentical: { // compare all pkg fragment root lists
418
IPackageFragmentRoot[] oldRoots = projectCache.allPkgFragmentRootsCache;
419                 if (oldRoots.length == newRoots.length){
420                     for (int i = 0, length = oldRoots.length; i < length; i++){
421                         if (!oldRoots[i].equals(newRoots[i])){
422                             break checkIdentical;
423                         }
424                     }
425                     return; // no need to update
426
}
427             }
428         }
429         info.setNonJavaResources(null);
430         info.setChildren(
431             computePackageFragmentRoots(classpath, false, null /*no reverse map*/));
432     }
433     
434     /**
435      * Internal computation of an expanded classpath. It will eliminate duplicates, and produce copies
436      * of exported or restricted classpath entries to avoid possible side-effects ever after.
437      */

438     private void computeExpandedClasspath(
439         ClasspathEntry referringEntry,
440         HashSet JavaDoc rootIDs,
441         ObjectVector accumulatedEntries) throws JavaModelException {
442         
443         String JavaDoc projectRootId = this.rootID();
444         if (rootIDs.contains(projectRootId)){
445             return; // break cycles if any
446
}
447         rootIDs.add(projectRootId);
448
449         IClasspathEntry[] resolvedClasspath = getResolvedClasspath();
450             
451         IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
452         boolean isInitialProject = referringEntry == null;
453         for (int i = 0, length = resolvedClasspath.length; i < length; i++){
454             ClasspathEntry entry = (ClasspathEntry) resolvedClasspath[i];
455             if (isInitialProject || entry.isExported()){
456                 String JavaDoc rootID = entry.rootID();
457                 if (rootIDs.contains(rootID)) {
458                     continue;
459                 }
460                 // combine restrictions along the project chain
461
ClasspathEntry combinedEntry = entry.combineWith(referringEntry);
462                 accumulatedEntries.add(combinedEntry);
463                 
464                 // recurse in project to get all its indirect exports (only consider exported entries from there on)
465
if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
466                     IResource member = workspaceRoot.findMember(entry.getPath());
467                     if (member != null && member.getType() == IResource.PROJECT){ // double check if bound to project (23977)
468
IProject projRsc = (IProject) member;
469                         if (JavaProject.hasJavaNature(projRsc)) {
470                             JavaProject javaProject = (JavaProject) JavaCore.create(projRsc);
471                             javaProject.computeExpandedClasspath(
472                                 combinedEntry,
473                                 rootIDs,
474                                 accumulatedEntries);
475                         }
476                     }
477                 } else {
478                     rootIDs.add(rootID);
479                 }
480             }
481         }
482     }
483     
484     /**
485      * Computes the package fragment roots identified by the given entry.
486      * Only works with resolved entry
487      * @param resolvedEntry IClasspathEntry
488      * @return IPackageFragmentRoot[]
489      */

490     public IPackageFragmentRoot[] computePackageFragmentRoots(IClasspathEntry resolvedEntry) {
491         try {
492             return
493                 computePackageFragmentRoots(
494                     new IClasspathEntry[]{ resolvedEntry },
495                     false, // don't retrieve exported roots
496
null /* no reverse map */
497                 );
498         } catch (JavaModelException e) {
499             return new IPackageFragmentRoot[] {};
500         }
501     }
502
503     /**
504      * Returns the package fragment roots identified by the given entry. In case it refers to
505      * a project, it will follow its classpath so as to find exported roots as well.
506      * Only works with resolved entry
507      * @param resolvedEntry IClasspathEntry
508      * @param accumulatedRoots ObjectVector
509      * @param rootIDs HashSet
510      * @param referringEntry the CP entry (project) referring to this entry, or null if initial project
511      * @param checkExistency boolean
512      * @param retrieveExportedRoots boolean
513      * @throws JavaModelException
514      */

515     public void computePackageFragmentRoots(
516         IClasspathEntry resolvedEntry,
517         ObjectVector accumulatedRoots,
518         HashSet JavaDoc rootIDs,
519         IClasspathEntry referringEntry,
520         boolean checkExistency,
521         boolean retrieveExportedRoots,
522         Map JavaDoc rootToResolvedEntries) throws JavaModelException {
523             
524         String JavaDoc rootID = ((ClasspathEntry)resolvedEntry).rootID();
525         if (rootIDs.contains(rootID)) return;
526
527         IPath projectPath = this.project.getFullPath();
528         IPath entryPath = resolvedEntry.getPath();
529         IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
530         IPackageFragmentRoot root = null;
531         
532         switch(resolvedEntry.getEntryKind()){
533             
534             // source folder
535
case IClasspathEntry.CPE_SOURCE :
536
537                 if (projectPath.isPrefixOf(entryPath)){
538                     if (checkExistency) {
539                         Object JavaDoc target = JavaModel.getTarget(workspaceRoot, entryPath, checkExistency);
540                         if (target == null) return;
541     
542                         if (target instanceof IFolder || target instanceof IProject){
543                             root = getPackageFragmentRoot((IResource)target);
544                         }
545                     } else {
546                         root = getFolderPackageFragmentRoot(entryPath);
547                     }
548                 }
549                 break;
550
551             // internal/external JAR or folder
552
case IClasspathEntry.CPE_LIBRARY :
553             
554                 if (referringEntry != null && !resolvedEntry.isExported()) return;
555                 
556                 if (checkExistency) {
557                     Object JavaDoc target = JavaModel.getTarget(workspaceRoot, entryPath, checkExistency);
558                     if (target == null) return;
559     
560                     if (target instanceof IResource){
561                         // internal target
562
root = getPackageFragmentRoot((IResource) target);
563                     } else {
564                         // external target - only JARs allowed
565
if (JavaModel.isFile(target) && (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(entryPath.lastSegment()))) {
566                             root = new JarPackageFragmentRoot(entryPath, this);
567                         }
568                     }
569                 } else {
570                     root = getPackageFragmentRoot(entryPath);
571                 }
572                 break;
573
574             // recurse into required project
575
case IClasspathEntry.CPE_PROJECT :
576
577                 if (!retrieveExportedRoots) return;
578                 if (referringEntry != null && !resolvedEntry.isExported()) return;
579
580                 IResource member = workspaceRoot.findMember(entryPath);
581                 if (member != null && member.getType() == IResource.PROJECT){// double check if bound to project (23977)
582
IProject requiredProjectRsc = (IProject) member;
583                     if (JavaProject.hasJavaNature(requiredProjectRsc)){ // special builder binary output
584
rootIDs.add(rootID);
585                         JavaProject requiredProject = (JavaProject)JavaCore.create(requiredProjectRsc);
586                         requiredProject.computePackageFragmentRoots(
587                             requiredProject.getResolvedClasspath(),
588                             accumulatedRoots,
589                             rootIDs,
590                             rootToResolvedEntries == null ? resolvedEntry : ((ClasspathEntry)resolvedEntry).combineWith((ClasspathEntry) referringEntry), // only combine if need to build the reverse map
591
checkExistency,
592                             retrieveExportedRoots,
593                             rootToResolvedEntries);
594                     }
595                 break;
596             }
597         }
598         if (root != null) {
599             accumulatedRoots.add(root);
600             rootIDs.add(rootID);
601             if (rootToResolvedEntries != null) rootToResolvedEntries.put(root, ((ClasspathEntry)resolvedEntry).combineWith((ClasspathEntry) referringEntry));
602         }
603     }
604
605     /**
606      * Returns (local/all) the package fragment roots identified by the given project's classpath.
607      * Note: this follows project classpath references to find required project contributions,
608      * eliminating duplicates silently.
609      * Only works with resolved entries
610      * @param resolvedClasspath IClasspathEntry[]
611      * @param retrieveExportedRoots boolean
612      * @return IPackageFragmentRoot[]
613      * @throws JavaModelException
614      */

615     public IPackageFragmentRoot[] computePackageFragmentRoots(
616                     IClasspathEntry[] resolvedClasspath,
617                     boolean retrieveExportedRoots,
618                     Map JavaDoc rootToResolvedEntries) throws JavaModelException {
619
620         ObjectVector accumulatedRoots = new ObjectVector();
621         computePackageFragmentRoots(
622             resolvedClasspath,
623             accumulatedRoots,
624             new HashSet JavaDoc(5), // rootIDs
625
null, // inside original project
626
true, // check existency
627
retrieveExportedRoots,
628             rootToResolvedEntries);
629         IPackageFragmentRoot[] rootArray = new IPackageFragmentRoot[accumulatedRoots.size()];
630         accumulatedRoots.copyInto(rootArray);
631         return rootArray;
632     }
633     
634     /**
635      * Returns (local/all) the package fragment roots identified by the given project's classpath.
636      * Note: this follows project classpath references to find required project contributions,
637      * eliminating duplicates silently.
638      * Only works with resolved entries
639      * @param resolvedClasspath IClasspathEntry[]
640      * @param accumulatedRoots ObjectVector
641      * @param rootIDs HashSet
642      * @param referringEntry project entry referring to this CP or null if initial project
643      * @param checkExistency boolean
644      * @param retrieveExportedRoots boolean
645      * @throws JavaModelException
646      */

647     public void computePackageFragmentRoots(
648         IClasspathEntry[] resolvedClasspath,
649         ObjectVector accumulatedRoots,
650         HashSet JavaDoc rootIDs,
651         IClasspathEntry referringEntry,
652         boolean checkExistency,
653         boolean retrieveExportedRoots,
654         Map JavaDoc rootToResolvedEntries) throws JavaModelException {
655
656         if (referringEntry == null){
657             rootIDs.add(rootID());
658         }
659         for (int i = 0, length = resolvedClasspath.length; i < length; i++){
660             computePackageFragmentRoots(
661                 resolvedClasspath[i],
662                 accumulatedRoots,
663                 rootIDs,
664                 referringEntry,
665                 checkExistency,
666                 retrieveExportedRoots,
667                 rootToResolvedEntries);
668         }
669     }
670     /**
671      * Compute the file name to use for a given shared property
672      * @param qName QualifiedName
673      * @return String
674      */

675     public String JavaDoc computeSharedPropertyFileName(QualifiedName qName) {
676
677         return '.' + qName.getLocalName();
678     }
679
680     /**
681      * Configure the project with Java nature.
682      */

683     public void configure() throws CoreException {
684
685         // register Java builder
686
addToBuildSpec(JavaCore.BUILDER_ID);
687     }
688     
689     /*
690      * Returns whether the given resource is accessible through the children or the non-Java resources of this project.
691      * Returns true if the resource is not in the project.
692      * Assumes that the resource is a folder or a file.
693      */

694     public boolean contains(IResource resource) {
695             
696         IClasspathEntry[] classpath;
697         IPath output;
698         try {
699             classpath = getResolvedClasspath();
700             output = getOutputLocation();
701         } catch (JavaModelException e) {
702             return false;
703         }
704         
705         IPath fullPath = resource.getFullPath();
706         IPath innerMostOutput = output.isPrefixOf(fullPath) ? output : null;
707         IClasspathEntry innerMostEntry = null;
708         for (int j = 0, cpLength = classpath.length; j < cpLength; j++) {
709             IClasspathEntry entry = classpath[j];
710         
711             IPath entryPath = entry.getPath();
712             if ((innerMostEntry == null || innerMostEntry.getPath().isPrefixOf(entryPath))
713                     && entryPath.isPrefixOf(fullPath)) {
714                 innerMostEntry = entry;
715             }
716             IPath entryOutput = classpath[j].getOutputLocation();
717             if (entryOutput != null && entryOutput.isPrefixOf(fullPath)) {
718                 innerMostOutput = entryOutput;
719             }
720         }
721         if (innerMostEntry != null) {
722             // special case prj==src and nested output location
723
if (innerMostOutput != null && innerMostOutput.segmentCount() > 1 // output isn't project
724
&& innerMostEntry.getPath().segmentCount() == 1) { // 1 segment must be project name
725
return false;
726             }
727             if (resource instanceof IFolder) {
728                  // folders are always included in src/lib entries
729
return true;
730             }
731             switch (innerMostEntry.getEntryKind()) {
732                 case IClasspathEntry.CPE_SOURCE:
733                     // .class files are not visible in source folders
734
return !org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(fullPath.lastSegment());
735                 case IClasspathEntry.CPE_LIBRARY:
736                     // .java files are not visible in library folders
737
return !org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(fullPath.lastSegment());
738             }
739         }
740         if (innerMostOutput != null) {
741             return false;
742         }
743         return true;
744     }
745
746     /**
747      * Record a new marker denoting a classpath problem
748      */

749     public void createClasspathProblemMarker(IJavaModelStatus status) {
750             
751         IMarker marker = null;
752         int severity;
753         String JavaDoc[] arguments = CharOperation.NO_STRINGS;
754         boolean isCycleProblem = false, isClasspathFileFormatProblem = false;
755         switch (status.getCode()) {
756     
757             case IJavaModelStatusConstants.CLASSPATH_CYCLE :
758                 isCycleProblem = true;
759                 if (JavaCore.ERROR.equals(getOption(JavaCore.CORE_CIRCULAR_CLASSPATH, true))) {
760                     severity = IMarker.SEVERITY_ERROR;
761                 } else {
762                     severity = IMarker.SEVERITY_WARNING;
763                 }
764                 break;
765     
766             case IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT :
767                 isClasspathFileFormatProblem = true;
768                 severity = IMarker.SEVERITY_ERROR;
769                 break;
770     
771             case IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL :
772                 String JavaDoc setting = getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true);
773                 if (JavaCore.ERROR.equals(setting)) {
774                     severity = IMarker.SEVERITY_ERROR;
775                 } else if (JavaCore.WARNING.equals(setting)) {
776                     severity = IMarker.SEVERITY_WARNING;
777                 } else {
778                     return; // setting == IGNORE
779
}
780                 break;
781                 
782             default:
783                 IPath path = status.getPath();
784                 if (path != null) arguments = new String JavaDoc[] { path.toString() };
785                 if (JavaCore.ERROR.equals(getOption(JavaCore.CORE_INCOMPLETE_CLASSPATH, true)) &&
786                     status.getSeverity() != IStatus.WARNING) {
787                     severity = IMarker.SEVERITY_ERROR;
788                 } else {
789                     severity = IMarker.SEVERITY_WARNING;
790                 }
791                 break;
792         }
793         
794         try {
795             marker = this.project.createMarker(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER);
796             marker.setAttributes(
797                 new String JavaDoc[] {
798                     IMarker.MESSAGE,
799                     IMarker.SEVERITY,
800                     IMarker.LOCATION,
801                     IJavaModelMarker.CYCLE_DETECTED,
802                     IJavaModelMarker.CLASSPATH_FILE_FORMAT,
803                     IJavaModelMarker.ID,
804                     IJavaModelMarker.ARGUMENTS ,
805                     IJavaModelMarker.CATEGORY_ID,
806                     IMarker.SOURCE_ID,
807                 },
808                 new Object JavaDoc[] {
809                     status.getMessage(),
810                     new Integer JavaDoc(severity),
811                     Messages.classpath_buildPath,
812                     isCycleProblem ? "true" : "false",//$NON-NLS-1$ //$NON-NLS-2$
813
isClasspathFileFormatProblem ? "true" : "false",//$NON-NLS-1$ //$NON-NLS-2$
814
new Integer JavaDoc(status.getCode()),
815                     Util.getProblemArgumentsForMarker(arguments) ,
816                     new Integer JavaDoc(CategorizedProblem.CAT_BUILDPATH),
817                     JavaBuilder.SOURCE_ID,
818                 }
819             );
820         } catch (CoreException e) {
821             // could not create marker: cannot do much
822
if (JavaModelManager.VERBOSE) {
823                 e.printStackTrace();
824             }
825         }
826     }
827
828     /**
829      * Returns a new element info for this element.
830      */

831     protected Object JavaDoc createElementInfo() {
832         return new JavaProjectElementInfo();
833     }
834
835     /*
836      * Reads and decode an XML classpath string
837      */

838     public IClasspathEntry[] decodeClasspath(String JavaDoc xmlClasspath, Map JavaDoc unknownElements) throws IOException, AssertionFailedException {
839     
840         ArrayList JavaDoc paths = new ArrayList JavaDoc();
841         IClasspathEntry defaultOutput = null;
842         StringReader reader = new StringReader(xmlClasspath);
843         Element cpElement;
844         try {
845             DocumentBuilder JavaDoc parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
846             cpElement = parser.parse(new InputSource JavaDoc(reader)).getDocumentElement();
847         } catch (SAXException JavaDoc e) {
848             throw new IOException(Messages.file_badFormat);
849         } catch (ParserConfigurationException JavaDoc e) {
850             throw new IOException(Messages.file_badFormat);
851         } finally {
852             reader.close();
853         }
854     
855         if (!cpElement.getNodeName().equalsIgnoreCase("classpath")) { //$NON-NLS-1$
856
throw new IOException(Messages.file_badFormat);
857         }
858         NodeList JavaDoc list = cpElement.getElementsByTagName("classpathentry"); //$NON-NLS-1$
859
int length = list.getLength();
860     
861         for (int i = 0; i < length; ++i) {
862             Node JavaDoc node = list.item(i);
863             if (node.getNodeType() == Node.ELEMENT_NODE) {
864                 IClasspathEntry entry = ClasspathEntry.elementDecode((Element)node, this, unknownElements);
865                 if (entry != null){
866                     if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
867                         defaultOutput = entry; // separate output
868
} else {
869                         paths.add(entry);
870             }
871         }
872             }
873         }
874         // return a new empty classpath is it size is 0, to differenciate from an INVALID_CLASSPATH
875
int pathSize = paths.size();
876         IClasspathEntry[] entries = new IClasspathEntry[pathSize + (defaultOutput == null ? 0 : 1)];
877         paths.toArray(entries);
878         if (defaultOutput != null) entries[pathSize] = defaultOutput; // ensure output is last item
879
return entries;
880     }
881     
882     public IClasspathEntry decodeClasspathEntry(String JavaDoc encodedEntry) {
883
884         try {
885             if (encodedEntry == null) return null;
886             StringReader reader = new StringReader(encodedEntry);
887             Element node;
888     
889             try {
890                 DocumentBuilder JavaDoc parser =
891                     DocumentBuilderFactory.newInstance().newDocumentBuilder();
892                 node = parser.parse(new InputSource JavaDoc(reader)).getDocumentElement();
893             } catch (SAXException JavaDoc e) {
894                 return null;
895             } catch (ParserConfigurationException JavaDoc e) {
896                 return null;
897             } finally {
898                 reader.close();
899             }
900     
901             if (!node.getNodeName().equalsIgnoreCase("classpathentry") //$NON-NLS-1$
902
|| node.getNodeType() != Node.ELEMENT_NODE) {
903                 return null;
904             }
905             return ClasspathEntry.elementDecode(node, this, null/*not interested in unknown elements*/);
906         } catch (IOException e) {
907             // bad format
908
return null;
909         }
910     }
911     
912     /**
913     /**
914      * Removes the Java nature from the project.
915      */

916     public void deconfigure() throws CoreException {
917
918         // deregister Java builder
919
removeFromBuildSpec(JavaCore.BUILDER_ID);
920         
921         // remove .classpath file
922
// getProject().getFile(ClasspathHelper.CLASSPATH_FILENAME).delete(false, null);
923
}
924
925     /**
926      * Returns a default class path.
927      * This is the root of the project
928      */

929     protected IClasspathEntry[] defaultClasspath() {
930
931         return new IClasspathEntry[] {
932              JavaCore.newSourceEntry(this.project.getFullPath())};
933     }
934     
935     /**
936      * Returns a default output location.
937      * This is the project bin folder
938      */

939     protected IPath defaultOutputLocation() {
940         return this.project.getFullPath().append("bin"); //$NON-NLS-1$
941
}
942
943     /**
944      * Returns the XML String encoding of the class path.
945      */

946     protected String JavaDoc encodeClasspath(IClasspathEntry[] classpath, IPath outputLocation, boolean indent, Map JavaDoc unknownElements) throws JavaModelException {
947         try {
948             ByteArrayOutputStream s = new ByteArrayOutputStream();
949             OutputStreamWriter writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
950
XMLWriter xmlWriter = new XMLWriter(writer, this, true/*print XML version*/);
951             
952             xmlWriter.startTag(ClasspathEntry.TAG_CLASSPATH, indent);
953             for (int i = 0; i < classpath.length; ++i) {
954                 ((ClasspathEntry)classpath[i]).elementEncode(xmlWriter, this.project.getFullPath(), indent, true, unknownElements);
955             }
956     
957             if (outputLocation != null) {
958                 outputLocation = outputLocation.removeFirstSegments(1);
959                 outputLocation = outputLocation.makeRelative();
960                 HashMap JavaDoc parameters = new HashMap JavaDoc();
961                 parameters.put(ClasspathEntry.TAG_KIND, ClasspathEntry.kindToString(ClasspathEntry.K_OUTPUT));
962                 parameters.put(ClasspathEntry.TAG_PATH, String.valueOf(outputLocation));
963                 xmlWriter.printTag(ClasspathEntry.TAG_CLASSPATHENTRY, parameters, indent, true, true);
964             }
965     
966             xmlWriter.endTag(ClasspathEntry.TAG_CLASSPATH, indent, true/*insert new line*/);
967             writer.flush();
968             writer.close();
969             return s.toString("UTF8");//$NON-NLS-1$
970
} catch (IOException e) {
971             throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
972         }
973     }
974
975     public String JavaDoc encodeClasspathEntry(IClasspathEntry classpathEntry) {
976         try {
977             ByteArrayOutputStream s = new ByteArrayOutputStream();
978             OutputStreamWriter writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
979
XMLWriter xmlWriter = new XMLWriter(writer, this, false/*don't print XML version*/);
980             
981             ((ClasspathEntry)classpathEntry).elementEncode(xmlWriter, this.project.getFullPath(), true/*indent*/, true/*insert new line*/, null/*not interested in unknown elements*/);
982     
983             writer.flush();
984             writer.close();
985             return s.toString("UTF8");//$NON-NLS-1$
986
} catch (IOException e) {
987             return null; // never happens since all is done in memory
988
}
989     }
990
991     /**
992      * Returns true if this handle represents the same Java project
993      * as the given handle. Two handles represent the same
994      * project if they are identical or if they represent a project with
995      * the same underlying resource and occurrence counts.
996      *
997      * @see JavaElement#equals(Object)
998      */

999     public boolean equals(Object JavaDoc o) {
1000    
1001        if (this == o)
1002            return true;
1003    
1004        if (!(o instanceof JavaProject))
1005            return false;
1006    
1007        JavaProject other = (JavaProject) o;
1008        return this.project.equals(other.getProject());
1009    }
1010
1011    public boolean exists() {
1012        try {
1013            return this.project.hasNature(JavaCore.NATURE_ID);
1014        } catch (CoreException e) {
1015            // project does not exist or is not open
1016
}
1017        return false;
1018    }
1019
1020    /**
1021     * @see IJavaProject#findElement(IPath)
1022     */

1023    public IJavaElement findElement(IPath path) throws JavaModelException {
1024        return findElement(path, DefaultWorkingCopyOwner.PRIMARY);
1025    }
1026
1027    /**
1028     * @see IJavaProject#findElement(IPath, WorkingCopyOwner)
1029     */

1030    public IJavaElement findElement(IPath path, WorkingCopyOwner owner) throws JavaModelException {
1031        
1032        if (path == null || path.isAbsolute()) {
1033            throw new JavaModelException(
1034                new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, path));
1035        }
1036        try {
1037
1038            String JavaDoc extension = path.getFileExtension();
1039            if (extension == null) {
1040                String JavaDoc packageName = path.toString().replace(IPath.SEPARATOR, '.');
1041
1042                NameLookup lookup = newNameLookup((WorkingCopyOwner)null/*no need to look at working copies for pkgs*/);
1043                IPackageFragment[] pkgFragments = lookup.findPackageFragments(packageName, false);
1044                if (pkgFragments == null) {
1045                    return null;
1046
1047                } else {
1048                    // try to return one that is a child of this project
1049
for (int i = 0, length = pkgFragments.length; i < length; i++) {
1050
1051                        IPackageFragment pkgFragment = pkgFragments[i];
1052                        if (this.equals(pkgFragment.getParent().getParent())) {
1053                            return pkgFragment;
1054                        }
1055                    }
1056                    // default to the first one
1057
return pkgFragments[0];
1058                }
1059            } else if (Util.isJavaLikeFileName(path.lastSegment())
1060                    || extension.equalsIgnoreCase(EXTENSION_class)) {
1061                IPath packagePath = path.removeLastSegments(1);
1062                String JavaDoc packageName = packagePath.toString().replace(IPath.SEPARATOR, '.');
1063                String JavaDoc typeName = path.lastSegment();
1064                typeName = typeName.substring(0, typeName.length() - extension.length() - 1);
1065                String JavaDoc qualifiedName = null;
1066                if (packageName.length() > 0) {
1067                    qualifiedName = packageName + "." + typeName; //$NON-NLS-1$
1068
} else {
1069                    qualifiedName = typeName;
1070                }
1071
1072                // lookup type
1073
NameLookup lookup = newNameLookup(owner);
1074                NameLookup.Answer answer = lookup.findType(
1075                    qualifiedName,
1076                    false,
1077                    NameLookup.ACCEPT_ALL,
1078                    true/* consider secondary types */,
1079                    false/* do NOT wait for indexes */,
1080                    false/*don't check restrictions*/,
1081                    null);
1082
1083                if (answer != null) {
1084                    return answer.type.getParent();
1085                } else {
1086                    return null;
1087                }
1088            } else {
1089                // unsupported extension
1090
return null;
1091            }
1092        } catch (JavaModelException e) {
1093            if (e.getStatus().getCode()
1094                == IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST) {
1095                return null;
1096            } else {
1097                throw e;
1098            }
1099        }
1100    }
1101
1102    /**
1103     * @see IJavaProject
1104     */

1105    public IPackageFragment findPackageFragment(IPath path)
1106        throws JavaModelException {
1107
1108        return findPackageFragment0(JavaProject.canonicalizedPath(path));
1109    }
1110    /*
1111     * non path canonicalizing version
1112     */

1113    private IPackageFragment findPackageFragment0(IPath path)
1114        throws JavaModelException {
1115
1116        NameLookup lookup = newNameLookup((WorkingCopyOwner)null/*no need to look at working copies for pkgs*/);
1117        return lookup.findPackageFragment(path);
1118    }
1119
1120    /**
1121     * @see IJavaProject
1122     */

1123    public IPackageFragmentRoot findPackageFragmentRoot(IPath path)
1124        throws JavaModelException {
1125
1126        return findPackageFragmentRoot0(JavaProject.canonicalizedPath(path));
1127    }
1128    /*
1129     * no path canonicalization
1130     */

1131    public IPackageFragmentRoot findPackageFragmentRoot0(IPath path)
1132        throws JavaModelException {
1133
1134        IPackageFragmentRoot[] allRoots = this.getAllPackageFragmentRoots();
1135        if (!path.isAbsolute()) {
1136            throw new IllegalArgumentException JavaDoc(Messages.path_mustBeAbsolute);
1137        }
1138        for (int i= 0; i < allRoots.length; i++) {
1139            IPackageFragmentRoot classpathRoot= allRoots[i];
1140            if (classpathRoot.getPath().equals(path)) {
1141                return classpathRoot;
1142            }
1143        }
1144        return null;
1145    }
1146    /**
1147     * @see IJavaProject
1148     */

1149    public IPackageFragmentRoot[] findPackageFragmentRoots(IClasspathEntry entry) {
1150        try {
1151            IClasspathEntry[] classpath = this.getRawClasspath();
1152            for (int i = 0, length = classpath.length; i < length; i++) {
1153                if (classpath[i].equals(entry)) { // entry may need to be resolved
1154
return
1155                        computePackageFragmentRoots(
1156                            resolveClasspath(new IClasspathEntry[] {entry}),
1157                            false, // don't retrieve exported roots
1158
null); /*no reverse map*/
1159                }
1160            }
1161        } catch (JavaModelException e) {
1162            // project doesn't exist: return an empty array
1163
}
1164        return new IPackageFragmentRoot[] {};
1165    }
1166    /**
1167     * @see IJavaProject#findType(String)
1168     */

1169    public IType findType(String JavaDoc fullyQualifiedName) throws JavaModelException {
1170        return findType(fullyQualifiedName, DefaultWorkingCopyOwner.PRIMARY);
1171    }
1172    /**
1173     * @see IJavaProject#findType(String, IProgressMonitor)
1174     */

1175    public IType findType(String JavaDoc fullyQualifiedName, IProgressMonitor progressMonitor) throws JavaModelException {
1176        return findType(fullyQualifiedName, DefaultWorkingCopyOwner.PRIMARY, progressMonitor);
1177    }
1178
1179    /*
1180     * Internal findType with instanciated name lookup
1181     */

1182    IType findType(String JavaDoc fullyQualifiedName, NameLookup lookup, boolean considerSecondaryTypes, IProgressMonitor progressMonitor) throws JavaModelException {
1183        NameLookup.Answer answer = lookup.findType(
1184            fullyQualifiedName,
1185            false,
1186            NameLookup.ACCEPT_ALL,
1187            considerSecondaryTypes,
1188            true, /* wait for indexes (only if consider secondary types)*/
1189            false/*don't check restrictions*/,
1190            progressMonitor);
1191        if (answer == null) {
1192            // try to find enclosing type
1193
int lastDot = fullyQualifiedName.lastIndexOf('.');
1194            if (lastDot == -1) return null;
1195            IType type = findType(fullyQualifiedName.substring(0, lastDot), lookup, considerSecondaryTypes, progressMonitor);
1196            if (type != null) {
1197                type = type.getType(fullyQualifiedName.substring(lastDot+1));
1198                if (!type.exists()) {
1199                    return null;
1200                }
1201            }
1202            return type;
1203        }
1204        return answer.type;
1205    }
1206    /**
1207     * @see IJavaProject#findType(String, String)
1208     */

1209    public IType findType(String JavaDoc packageName, String JavaDoc typeQualifiedName) throws JavaModelException {
1210        return findType(packageName, typeQualifiedName, DefaultWorkingCopyOwner.PRIMARY);
1211    }
1212    /**
1213     * @see IJavaProject#findType(String, String, IProgressMonitor)
1214     */

1215    public IType findType(String JavaDoc packageName, String JavaDoc typeQualifiedName, IProgressMonitor progressMonitor) throws JavaModelException {
1216        return findType(packageName, typeQualifiedName, DefaultWorkingCopyOwner.PRIMARY, progressMonitor);
1217    }
1218    /*
1219     * Internal findType with instanciated name lookup
1220     */

1221    IType findType(String JavaDoc packageName, String JavaDoc typeQualifiedName, NameLookup lookup, boolean considerSecondaryTypes, IProgressMonitor progressMonitor) throws JavaModelException {
1222        NameLookup.Answer answer = lookup.findType(
1223            typeQualifiedName,
1224            packageName,
1225            false,
1226            NameLookup.ACCEPT_ALL,
1227            considerSecondaryTypes,
1228            true, // wait for indexes (in case we need to consider secondary types)
1229
false/*don't check restrictions*/,
1230            progressMonitor);
1231        return answer == null ? null : answer.type;
1232    }
1233    /**
1234     * @see IJavaProject#findType(String, String, WorkingCopyOwner)
1235     */

1236    public IType findType(String JavaDoc packageName, String JavaDoc typeQualifiedName, WorkingCopyOwner owner) throws JavaModelException {
1237        NameLookup lookup = newNameLookup(owner);
1238        return findType(
1239            packageName,
1240            typeQualifiedName,
1241            lookup,
1242            false, // do not consider secondary types
1243
null);
1244    }
1245    
1246    /**
1247     * @see IJavaProject#findType(String, String, WorkingCopyOwner, IProgressMonitor)
1248     */

1249    public IType findType(String JavaDoc packageName, String JavaDoc typeQualifiedName, WorkingCopyOwner owner, IProgressMonitor progressMonitor) throws JavaModelException {
1250        NameLookup lookup = newNameLookup(owner);
1251        return findType(
1252            packageName,
1253            typeQualifiedName,
1254            lookup,
1255            true, // consider secondary types
1256
progressMonitor);
1257    }
1258
1259    /**
1260     * @see IJavaProject#findType(String, WorkingCopyOwner)
1261     */

1262    public IType findType(String JavaDoc fullyQualifiedName, WorkingCopyOwner owner) throws JavaModelException {
1263        NameLookup lookup = newNameLookup(owner);
1264        return findType(fullyQualifiedName, lookup, false, null);
1265    }
1266
1267    /**
1268     * @see IJavaProject#findType(String, WorkingCopyOwner, IProgressMonitor)
1269     */

1270    public IType findType(String JavaDoc fullyQualifiedName, WorkingCopyOwner owner, IProgressMonitor progressMonitor) throws JavaModelException {
1271        NameLookup lookup = newNameLookup(owner);
1272        return findType(fullyQualifiedName, lookup, true, progressMonitor);
1273    }
1274
1275    /**
1276     * Remove all markers denoting classpath problems
1277     */
//TODO (philippe) should improve to use a bitmask instead of booleans (CYCLE, FORMAT, VALID)
1278
protected void flushClasspathProblemMarkers(boolean flushCycleMarkers, boolean flushClasspathFormatMarkers) {
1279        try {
1280            if (this.project.isAccessible()) {
1281                IMarker[] markers = this.project.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
1282                for (int i = 0, length = markers.length; i < length; i++) {
1283                    IMarker marker = markers[i];
1284                    if (flushCycleMarkers && flushClasspathFormatMarkers) {
1285                        marker.delete();
1286                    } else {
1287                        String JavaDoc cycleAttr = (String JavaDoc)marker.getAttribute(IJavaModelMarker.CYCLE_DETECTED);
1288                        String JavaDoc classpathFileFormatAttr = (String JavaDoc)marker.getAttribute(IJavaModelMarker.CLASSPATH_FILE_FORMAT);
1289                        if ((flushCycleMarkers == (cycleAttr != null && cycleAttr.equals("true"))) //$NON-NLS-1$
1290
&& (flushClasspathFormatMarkers == (classpathFileFormatAttr != null && classpathFileFormatAttr.equals("true")))){ //$NON-NLS-1$
1291
marker.delete();
1292                        }
1293                    }
1294                }
1295            }
1296        } catch (CoreException e) {
1297            // could not flush markers: not much we can do
1298
if (JavaModelManager.VERBOSE) {
1299                e.printStackTrace();
1300            }
1301        }
1302    }
1303    
1304    /**
1305     * Returns the set of patterns corresponding to this project visibility given rules
1306     * @return an array of IPath or null if none
1307     */

1308    public IPath[] getAccessRestrictions(String JavaDoc optionName) {
1309        String JavaDoc sequence = getOption(optionName, true); // inherit from workspace
1310
if (sequence == null || sequence.length() == 0) return null;
1311        IPath[] rules = null;
1312        char[][] patterns = CharOperation.splitOn('|', sequence.toCharArray());
1313        int patternCount;
1314        if ((patternCount = patterns.length) > 0) {
1315            rules = new IPath[patternCount];
1316            for (int j = 0; j < patterns.length; j++){
1317                rules[j] = new Path(new String JavaDoc(patterns[j]));
1318            }
1319        }
1320        return rules;
1321    }
1322
1323    /**
1324     * @see IJavaProject
1325     */

1326    public IPackageFragmentRoot[] getAllPackageFragmentRoots()
1327        throws JavaModelException {
1328
1329        return getAllPackageFragmentRoots(null /*no reverse map*/);
1330    }
1331
1332    public IPackageFragmentRoot[] getAllPackageFragmentRoots(Map JavaDoc rootToResolvedEntries) throws JavaModelException {
1333
1334        return computePackageFragmentRoots(getResolvedClasspath(), true/*retrieveExportedRoots*/, rootToResolvedEntries);
1335    }
1336
1337    /**
1338     * Returns the classpath entry that refers to the given path
1339     * or <code>null</code> if there is no reference to the path.
1340     * @param path IPath
1341     * @return IClasspathEntry
1342     * @throws JavaModelException
1343     */

1344    public IClasspathEntry getClasspathEntryFor(IPath path) throws JavaModelException {
1345        getResolvedClasspath(); // force resolution
1346
PerProjectInfo perProjectInfo = getPerProjectInfo();
1347        if (perProjectInfo == null)
1348            return null;
1349        Map JavaDoc rootPathToResolvedEntries = perProjectInfo.rootPathToResolvedEntries;
1350        if (rootPathToResolvedEntries == null)
1351            return null;
1352        return (IClasspathEntry) rootPathToResolvedEntries.get(path);
1353    }
1354    
1355    /*
1356     * Returns the cycle marker associated with this project or null if none.
1357     */

1358    public IMarker getCycleMarker(){
1359        try {
1360            if (this.project.isAccessible()) {
1361                IMarker[] markers = this.project.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
1362                for (int i = 0, length = markers.length; i < length; i++) {
1363                    IMarker marker = markers[i];
1364                    String JavaDoc cycleAttr = (String JavaDoc)marker.getAttribute(IJavaModelMarker.CYCLE_DETECTED);
1365                    if (cycleAttr != null && cycleAttr.equals("true")){ //$NON-NLS-1$
1366
return marker;
1367                    }
1368                }
1369            }
1370        } catch (CoreException e) {
1371            // could not get markers: return null
1372
}
1373        return null;
1374    }
1375
1376        /**
1377         * Returns the project custom preference pool.
1378         * Project preferences may include custom encoding.
1379         * @return IEclipsePreferences
1380         */

1381        public IEclipsePreferences getEclipsePreferences(){
1382            if (!JavaProject.hasJavaNature(this.project)) return null;
1383            // Get cached preferences if exist
1384
JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfo(this.project, true);
1385            if (perProjectInfo.preferences != null) return perProjectInfo.preferences;
1386            // Init project preferences
1387
IScopeContext context = new ProjectScope(getProject());
1388            final IEclipsePreferences eclipsePreferences = context.getNode(JavaCore.PLUGIN_ID);
1389            updatePreferences(eclipsePreferences);
1390            perProjectInfo.preferences = eclipsePreferences;
1391    
1392            // Listen to node removal from parent in order to reset cache (see bug 68993)
1393
IEclipsePreferences.INodeChangeListener nodeListener = new IEclipsePreferences.INodeChangeListener() {
1394                public void added(IEclipsePreferences.NodeChangeEvent event) {
1395                    // do nothing
1396
}
1397                public void removed(IEclipsePreferences.NodeChangeEvent event) {
1398                    if (event.getChild() == eclipsePreferences) {
1399                        JavaModelManager.getJavaModelManager().resetProjectPreferences(JavaProject.this);
1400                    }
1401                }
1402            };
1403            ((IEclipsePreferences) eclipsePreferences.parent()).addNodeChangeListener(nodeListener);
1404    
1405            // Listen to preference changes
1406
IEclipsePreferences.IPreferenceChangeListener preferenceListener = new IEclipsePreferences.IPreferenceChangeListener() {
1407                public void preferenceChange(IEclipsePreferences.PreferenceChangeEvent event) {
1408                    String JavaDoc propertyName = event.getKey();
1409                    JavaModelManager manager = JavaModelManager.getJavaModelManager();
1410                    if (propertyName.startsWith(JavaCore.PLUGIN_ID)) {
1411                        if (propertyName.equals(JavaCore.CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER) ||
1412                            propertyName.equals(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER) ||
1413                            propertyName.equals(JavaCore.CORE_JAVA_BUILD_DUPLICATE_RESOURCE) ||
1414                            propertyName.equals(JavaCore.CORE_JAVA_BUILD_RECREATE_MODIFIED_CLASS_FILES_IN_OUTPUT_FOLDER) ||
1415                            propertyName.equals(JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH) ||
1416                            propertyName.equals(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS) ||
1417                            propertyName.equals(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS) ||
1418                            propertyName.equals(JavaCore.CORE_INCOMPLETE_CLASSPATH) ||
1419                            propertyName.equals(JavaCore.CORE_CIRCULAR_CLASSPATH) ||
1420                            propertyName.equals(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL))
1421                        {
1422                            manager.deltaState.addClasspathValidation(JavaProject.this);
1423                        }
1424                        manager.resetProjectOptions(JavaProject.this);
1425                    }
1426                }
1427            };
1428            eclipsePreferences.addPreferenceChangeListener(preferenceListener);
1429            return eclipsePreferences;
1430        }
1431        
1432    public String JavaDoc getElementName() {
1433        return this.project.getName();
1434    }
1435
1436    /**
1437     * @see IJavaElement
1438     */

1439    public int getElementType() {
1440        return JAVA_PROJECT;
1441    }
1442
1443    /**
1444     * This is a helper method returning the expanded classpath for the project, as a list of classpath entries,
1445     * where all classpath variable entries have been resolved and substituted with their final target entries.
1446     * All project exports have been appended to project entries.
1447     * @return IClasspathEntry[]
1448     * @throws JavaModelException
1449     */

1450    public IClasspathEntry[] getExpandedClasspath() throws JavaModelException {
1451            
1452            ObjectVector accumulatedEntries = new ObjectVector();
1453            computeExpandedClasspath(null, new HashSet JavaDoc(5), accumulatedEntries);
1454            
1455            IClasspathEntry[] expandedPath = new IClasspathEntry[accumulatedEntries.size()];
1456            accumulatedEntries.copyInto(expandedPath);
1457            
1458            return expandedPath;
1459    }
1460
1461    /**
1462     * The path is known to match a source/library folder entry.
1463     * @param path IPath
1464     * @return IPackageFragmentRoot
1465     */

1466    public IPackageFragmentRoot getFolderPackageFragmentRoot(IPath path) {
1467        if (path.segmentCount() == 1) { // default project root
1468
return getPackageFragmentRoot(this.project);
1469        }
1470        return getPackageFragmentRoot(this.project.getWorkspace().getRoot().getFolder(path));
1471    }
1472
1473    /*
1474     * @see JavaElement
1475     */

1476    public IJavaElement getHandleFromMemento(String JavaDoc token, MementoTokenizer memento, WorkingCopyOwner owner) {
1477        switch (token.charAt(0)) {
1478            case JEM_PACKAGEFRAGMENTROOT:
1479                String JavaDoc rootPath = IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH;
1480                token = null;
1481                while (memento.hasMoreTokens()) {
1482                    token = memento.nextToken();
1483                    char firstChar = token.charAt(0);
1484                    if (firstChar != JEM_PACKAGEFRAGMENT && firstChar != JEM_COUNT) {
1485                        rootPath += token;
1486                    } else {
1487                        break;
1488                    }
1489                }
1490                JavaElement root = (JavaElement)getPackageFragmentRoot(new Path(rootPath));
1491                if (token != null && token.charAt(0) == JEM_PACKAGEFRAGMENT) {
1492                    return root.getHandleFromMemento(token, memento, owner);
1493                } else {
1494                    return root.getHandleFromMemento(memento, owner);
1495                }
1496        }
1497        return null;
1498    }
1499
1500    /**
1501     * Returns the <code>char</code> that marks the start of this handles
1502     * contribution to a memento.
1503     */

1504    protected char getHandleMementoDelimiter() {
1505
1506        return JEM_JAVAPROJECT;
1507    }
1508
1509    /**
1510     * Find the specific Java command amongst the given build spec
1511     * and return its index or -1 if not found.
1512     */

1513    private int getJavaCommandIndex(ICommand[] buildSpec) {
1514
1515        for (int i = 0; i < buildSpec.length; ++i) {
1516            if (buildSpec[i].getBuilderName().equals(JavaCore.BUILDER_ID)) {
1517                return i;
1518            }
1519        }
1520        return -1;
1521    }
1522    
1523    /**
1524     * Convenience method that returns the specific type of info for a Java project.
1525     */

1526    protected JavaProjectElementInfo getJavaProjectElementInfo()
1527        throws JavaModelException {
1528
1529        return (JavaProjectElementInfo) getElementInfo();
1530    }
1531
1532    /**
1533     * Returns an array of non-java resources contained in the receiver.
1534     */

1535    public Object JavaDoc[] getNonJavaResources() throws JavaModelException {
1536
1537        return ((JavaProjectElementInfo) getElementInfo()).getNonJavaResources(this);
1538    }
1539    
1540    /**
1541     * @see org.eclipse.jdt.core.IJavaProject#getOption(String, boolean)
1542     */

1543    public String JavaDoc getOption(String JavaDoc optionName, boolean inheritJavaCoreOptions) {
1544        
1545        String JavaDoc propertyName = optionName;
1546        if (JavaModelManager.getJavaModelManager().optionNames.contains(propertyName)){
1547            IEclipsePreferences projectPreferences = getEclipsePreferences();
1548            String JavaDoc javaCoreDefault = inheritJavaCoreOptions ? JavaCore.getOption(propertyName) : null;
1549            if (projectPreferences == null) return javaCoreDefault;
1550            String JavaDoc value = projectPreferences.get(propertyName, javaCoreDefault);
1551            return value == null ? null : value.trim();
1552        }
1553        return null;
1554    }
1555    
1556    /**
1557     * @see org.eclipse.jdt.core.IJavaProject#getOptions(boolean)
1558     */

1559    public Map JavaDoc getOptions(boolean inheritJavaCoreOptions) {
1560
1561        // initialize to the defaults from JavaCore options pool
1562
Map JavaDoc options = inheritJavaCoreOptions ? JavaCore.getOptions() : new Hashtable JavaDoc(5);
1563
1564        // Get project specific options
1565
JavaModelManager.PerProjectInfo perProjectInfo = null;
1566        Hashtable JavaDoc projectOptions = null;
1567        HashSet JavaDoc optionNames = JavaModelManager.getJavaModelManager().optionNames;
1568        try {
1569            perProjectInfo = getPerProjectInfo();
1570            projectOptions = perProjectInfo.options;
1571            if (projectOptions == null) {
1572                // get eclipse preferences
1573
IEclipsePreferences projectPreferences= getEclipsePreferences();
1574                if (projectPreferences == null) return options; // cannot do better (non-Java project)
1575
// create project options
1576
String JavaDoc[] propertyNames = projectPreferences.keys();
1577                projectOptions = new Hashtable JavaDoc(propertyNames.length);
1578                for (int i = 0; i < propertyNames.length; i++){
1579                    String JavaDoc propertyName = propertyNames[i];
1580                    String JavaDoc value = projectPreferences.get(propertyName, null);
1581                    if (value != null && optionNames.contains(propertyName)){
1582                        projectOptions.put(propertyName, value.trim());
1583                    }
1584                }
1585                // cache project options
1586
perProjectInfo.options = projectOptions;
1587            }
1588        } catch (JavaModelException jme) {
1589            projectOptions = new Hashtable JavaDoc();
1590        } catch (BackingStoreException e) {
1591            projectOptions = new Hashtable JavaDoc();
1592        }
1593
1594        // Inherit from JavaCore options if specified
1595
if (inheritJavaCoreOptions) {
1596            Iterator JavaDoc propertyNames = projectOptions.entrySet().iterator();
1597            while (propertyNames.hasNext()) {
1598                Map.Entry JavaDoc entry = (Map.Entry JavaDoc) propertyNames.next();
1599                String JavaDoc propertyName = (String JavaDoc) entry.getKey();
1600                String JavaDoc propertyValue = (String JavaDoc) entry.getValue();
1601                if (propertyValue != null && optionNames.contains(propertyName)){
1602                    options.put(propertyName, propertyValue.trim());
1603                }
1604            }
1605            return options;
1606        }
1607        return projectOptions;
1608    }
1609
1610    /**
1611     * @see IJavaProject
1612     */

1613    public IPath getOutputLocation() throws JavaModelException {
1614        // Do not create marker while getting output location
1615
JavaModelManager.PerProjectInfo perProjectInfo = this.getPerProjectInfo();
1616        IPath outputLocation = perProjectInfo.outputLocation;
1617        if (outputLocation != null) return outputLocation;
1618        
1619        // force to read classpath - will position output location as well
1620
getRawClasspath();
1621        
1622        outputLocation = perProjectInfo.outputLocation;
1623        if (outputLocation == null) {
1624            return this.defaultOutputLocation();
1625        }
1626        return outputLocation;
1627    }
1628    
1629    /**
1630     * @param path IPath
1631     * @return A handle to the package fragment root identified by the given path.
1632     * This method is handle-only and the element may or may not exist. Returns
1633     * <code>null</code> if unable to generate a handle from the path (for example,
1634     * an absolute path that has less than 1 segment. The path may be relative or
1635     * absolute.
1636     */

1637    public IPackageFragmentRoot getPackageFragmentRoot(IPath path) {
1638        if (!path.isAbsolute()) {
1639            path = getPath().append(path);
1640        }
1641        int segmentCount = path.segmentCount();
1642        switch (segmentCount) {
1643            case 0:
1644                return null;
1645            case 1:
1646                if (path.equals(getPath())) { // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=75814
1647
// default root
1648
return getPackageFragmentRoot(this.project);
1649                }
1650            default:
1651                // a path ending with .jar/.zip is still ambiguous and could still resolve to a source/lib folder
1652
// thus will try to guess based on existing resource
1653
if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(path.lastSegment())) {
1654                    IResource resource = this.project.getWorkspace().getRoot().findMember(path);
1655                    if (resource != null && resource.getType() == IResource.FOLDER){
1656                        return getPackageFragmentRoot(resource);
1657                    }
1658                    return getPackageFragmentRoot0(path);
1659                } else if (segmentCount == 1) {
1660                    // lib being another project
1661
return getPackageFragmentRoot(this.project.getWorkspace().getRoot().getProject(path.lastSegment()));
1662                } else {
1663                    // lib being a folder
1664
return getPackageFragmentRoot(this.project.getWorkspace().getRoot().getFolder(path));
1665                }
1666        }
1667    }
1668
1669    /**
1670     * @see IJavaProject
1671     */

1672    public IPackageFragmentRoot getPackageFragmentRoot(IResource resource) {
1673
1674        switch (resource.getType()) {
1675            case IResource.FILE:
1676                if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(resource.getName())) {
1677                    return new JarPackageFragmentRoot(resource, this);
1678                } else {
1679                    return null;
1680                }
1681            case IResource.FOLDER:
1682                return new PackageFragmentRoot(resource, this);
1683            case IResource.PROJECT:
1684                return new PackageFragmentRoot(resource, this);
1685            default:
1686                return null;
1687        }
1688    }
1689
1690    /**
1691     * @see IJavaProject
1692     */

1693    public IPackageFragmentRoot getPackageFragmentRoot(String JavaDoc jarPath) {
1694
1695        return getPackageFragmentRoot0(JavaProject.canonicalizedPath(new Path(jarPath)));
1696    }
1697
1698    /*
1699     * no path canonicalization
1700     */

1701    public IPackageFragmentRoot getPackageFragmentRoot0(IPath jarPath) {
1702
1703        return new JarPackageFragmentRoot(jarPath, this);
1704    }
1705
1706    /**
1707     * @see IJavaProject
1708     */

1709    public IPackageFragmentRoot[] getPackageFragmentRoots()
1710        throws JavaModelException {
1711
1712        Object JavaDoc[] children;
1713        int length;
1714        IPackageFragmentRoot[] roots;
1715
1716        System.arraycopy(
1717            children = getChildren(),
1718            0,
1719            roots = new IPackageFragmentRoot[length = children.length],
1720            0,
1721            length);
1722            
1723        return roots;
1724    }
1725
1726    /**
1727     * @see IJavaProject
1728     * @deprecated
1729     */

1730    public IPackageFragmentRoot[] getPackageFragmentRoots(IClasspathEntry entry) {
1731        return findPackageFragmentRoots(entry);
1732    }
1733    
1734    /**
1735     * @see IJavaProject
1736     */

1737    public IPackageFragment[] getPackageFragments() throws JavaModelException {
1738
1739        IPackageFragmentRoot[] roots = getPackageFragmentRoots();
1740        return getPackageFragmentsInRoots(roots);
1741    }
1742
1743    /**
1744     * Returns all the package fragments found in the specified
1745     * package fragment roots.
1746     * @param roots IPackageFragmentRoot[]
1747     * @return IPackageFragment[]
1748     */

1749    public IPackageFragment[] getPackageFragmentsInRoots(IPackageFragmentRoot[] roots) {
1750
1751        ArrayList JavaDoc frags = new ArrayList JavaDoc();
1752        for (int i = 0; i < roots.length; i++) {
1753            IPackageFragmentRoot root = roots[i];
1754            try {
1755                IJavaElement[] rootFragments = root.getChildren();
1756                for (int j = 0; j < rootFragments.length; j++) {
1757                    frags.add(rootFragments[j]);
1758                }
1759            } catch (JavaModelException e) {
1760                // do nothing
1761
}
1762        }
1763        IPackageFragment[] fragments = new IPackageFragment[frags.size()];
1764        frags.toArray(fragments);
1765        return fragments;
1766    }
1767
1768    /**
1769     * @see IJavaElement
1770     */

1771    public IPath getPath() {
1772        return this.project.getFullPath();
1773    }
1774
1775    public JavaModelManager.PerProjectInfo getPerProjectInfo() throws JavaModelException {
1776        return JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(this.project);
1777    }
1778
1779    private IPath getPluginWorkingLocation() {
1780        return this.project.getWorkingLocation(JavaCore.PLUGIN_ID);
1781    }
1782
1783    /**
1784     * Returns the project custom preference pool.
1785     * Project preferences may include custom encoding.
1786     * @return Preferences
1787     * @deprecated WARNING: this method do nothing from now and will be removed soon!
1788     * If you use it, switch as soon as possible to new preferences API by using
1789     * {@link #getEclipsePreferences()} to avoid future compilation error...
1790     * @see <a HREF="https://bugs.eclipse.org/bugs/show_bug.cgi?id=59258">bug 59258</a>
1791     * TODO (frederic) remove for 3.1...
1792     */

1793    public Preferences getPreferences(){
1794        /*
1795        if (!JavaProject.hasJavaNature(this.project)) return null;
1796        JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfo(this.project, true);
1797        Preferences preferences = perProjectInfo.preferences;
1798        if (preferences != null) return preferences;
1799        preferences = loadPreferences();
1800        if (preferences == null) preferences = new Preferences();
1801        perProjectInfo.preferences = preferences;
1802        return preferences;
1803        */

1804        return new Preferences();
1805    }
1806    
1807    /**
1808     * @see IJavaProject#getProject()
1809     */

1810    public IProject getProject() {
1811        return this.project;
1812    }
1813    
1814    public ProjectCache getProjectCache() throws JavaModelException {
1815        return ((JavaProjectElementInfo) getElementInfo()).getProjectCache(this);
1816    }
1817
1818    /**
1819     * @see IJavaProject
1820     */

1821    public IClasspathEntry[] getRawClasspath() throws JavaModelException {
1822        JavaModelManager.PerProjectInfo perProjectInfo = getPerProjectInfo();
1823        IClasspathEntry[] classpath = perProjectInfo.rawClasspath;
1824        if (classpath != null) return classpath;
1825        
1826        classpath = perProjectInfo.readAndCacheClasspath(this);
1827
1828        if (classpath == JavaProject.INVALID_CLASSPATH)
1829            return defaultClasspath();
1830        
1831        return classpath;
1832    }
1833    
1834    /**
1835     * @see IJavaProject#getRequiredProjectNames()
1836     */

1837    public String JavaDoc[] getRequiredProjectNames() throws JavaModelException {
1838
1839        return this.projectPrerequisites(getResolvedClasspath());
1840    }
1841    
1842    /*
1843     * Returns the cached resolved classpath, or compute it ignoring unresolved entries and cache it.
1844     */

1845    public IClasspathEntry[] getResolvedClasspath() throws JavaModelException {
1846        PerProjectInfo perProjectInfo = getPerProjectInfo();
1847        if (perProjectInfo.resolvedClasspath == null)
1848            resolveClasspath(perProjectInfo);
1849        return perProjectInfo.resolvedClasspath;
1850    }
1851
1852    /**
1853     * @see IJavaProject
1854     */

1855    public IClasspathEntry[] getResolvedClasspath(boolean ignoreUnresolvedEntry) throws JavaModelException {
1856        if (JavaModelManager.getJavaModelManager().isClasspathBeingResolved(this)) {
1857            if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED)
1858                verbose_reentering_classpath_resolution();
1859            return RESOLUTION_IN_PROGRESS;
1860        }
1861        PerProjectInfo perProjectInfo = getPerProjectInfo();
1862
1863        // use synchronized block to ensure consistency
1864
IClasspathEntry[] resolvedClasspath;
1865        IJavaModelStatus unresolvedEntryStatus;
1866        synchronized (perProjectInfo) {
1867            resolvedClasspath = perProjectInfo.resolvedClasspath;
1868            unresolvedEntryStatus = perProjectInfo.unresolvedEntryStatus;
1869        }
1870        
1871        if (resolvedClasspath == null
1872                || (unresolvedEntryStatus != null && !unresolvedEntryStatus.isOK())) { // force resolution to ensure initializers are run again
1873
resolveClasspath(perProjectInfo);
1874            synchronized (perProjectInfo) {
1875                resolvedClasspath = perProjectInfo.resolvedClasspath;
1876                unresolvedEntryStatus = perProjectInfo.unresolvedEntryStatus;
1877            }
1878        }
1879        if (!ignoreUnresolvedEntry && unresolvedEntryStatus != null && !unresolvedEntryStatus.isOK())
1880            throw new JavaModelException(unresolvedEntryStatus);
1881        return resolvedClasspath;
1882    }
1883
1884    private void verbose_reentering_classpath_resolution() {
1885        Util.verbose(
1886            "CPResolution: reentering raw classpath resolution, will use empty classpath instead" + //$NON-NLS-1$
1887
" project: " + getElementName() + '\n' + //$NON-NLS-1$
1888
" invocation stack trace:"); //$NON-NLS-1$
1889
new Exception JavaDoc("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
1890
}
1891
1892    /**
1893     * @see IJavaElement
1894     */

1895    public IResource getResource() {
1896        return this.project;
1897    }
1898
1899    /**
1900     * Retrieve a shared property on a project. If the property is not defined, answers null.
1901     * Note that it is orthogonal to IResource persistent properties, and client code has to decide
1902     * which form of storage to use appropriately. Shared properties produce real resource files which
1903     * can be shared through a VCM onto a server. Persistent properties are not shareable.
1904     *
1905     * @param key String
1906     * @see JavaProject#setSharedProperty(String, String)
1907     * @return String
1908     * @throws CoreException
1909     */

1910    public String JavaDoc getSharedProperty(String JavaDoc key) throws CoreException {
1911
1912        String JavaDoc property = null;
1913        IFile rscFile = this.project.getFile(key);
1914        if (rscFile.exists()) {
1915            byte[] bytes = Util.getResourceContentsAsByteArray(rscFile);
1916            try {
1917                property = new String JavaDoc(bytes, org.eclipse.jdt.internal.compiler.util.Util.UTF_8); // .classpath always encoded with UTF-8
1918
} catch (UnsupportedEncodingException e) {
1919                Util.log(e, "Could not read .classpath with UTF-8 encoding"); //$NON-NLS-1$
1920
// fallback to default
1921
property = new String JavaDoc(bytes);
1922            }
1923        } else {
1924            // when a project is imported, we get a first delta for the addition of the .project, but the .classpath is not accessible
1925
// so default to using java.io.File
1926
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=96258
1927
URI JavaDoc location = rscFile.getLocationURI();
1928            if (location != null) {
1929                File file = Util.toLocalFile(location, null/*no progress monitor available*/);
1930                if (file != null && file.exists()) {
1931                    byte[] bytes;
1932                    try {
1933                        bytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(file);
1934                    } catch (IOException e) {
1935                        return null;
1936                    }
1937                    try {
1938                        property = new String JavaDoc(bytes, org.eclipse.jdt.internal.compiler.util.Util.UTF_8); // .classpath always encoded with UTF-8
1939
} catch (UnsupportedEncodingException e) {
1940                        Util.log(e, "Could not read .classpath with UTF-8 encoding"); //$NON-NLS-1$
1941
// fallback to default
1942
property = new String JavaDoc(bytes);
1943                    }
1944                }
1945            }
1946        }
1947        return property;
1948    }
1949    
1950    /**
1951     * @see JavaElement
1952     */

1953    public SourceMapper getSourceMapper() {
1954
1955        return null;
1956    }
1957
1958    /**
1959     * @see IJavaElement
1960     */

1961    public IResource getUnderlyingResource() throws JavaModelException {
1962        if (!exists()) throw newNotPresentException();
1963        return this.project;
1964    }
1965
1966    /**
1967     * @see IJavaProject
1968     */

1969    public boolean hasBuildState() {
1970
1971        return JavaModelManager.getJavaModelManager().getLastBuiltState(this.project, null) != null;
1972    }
1973    
1974    /**
1975     * @see IJavaProject
1976     */

1977    public boolean hasClasspathCycle(IClasspathEntry[] preferredClasspath) {
1978        HashSet JavaDoc cycleParticipants = new HashSet JavaDoc();
1979        HashMap JavaDoc preferredClasspaths = new HashMap JavaDoc(1);
1980        preferredClasspaths.put(this, preferredClasspath);
1981        updateCycleParticipants(new ArrayList JavaDoc(2), cycleParticipants, ResourcesPlugin.getWorkspace().getRoot(), new HashSet JavaDoc(2), preferredClasspaths);
1982        return !cycleParticipants.isEmpty();
1983    }
1984
1985    public boolean hasCycleMarker(){
1986        return this.getCycleMarker() != null;
1987    }
1988    
1989    public int hashCode() {
1990        return this.project.hashCode();
1991    }
1992
1993    /**
1994     * Answers true if the project potentially contains any source. A project which has no source is immutable.
1995     * @return boolean
1996     */

1997    public boolean hasSource() {
1998
1999        // look if any source folder on the classpath
2000
// no need for resolved path given source folder cannot be abstracted
2001
IClasspathEntry[] entries;
2002        try {
2003            entries = this.getRawClasspath();
2004        } catch (JavaModelException e) {
2005            return true; // unsure
2006
}
2007        for (int i = 0, max = entries.length; i < max; i++) {
2008            if (entries[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) {
2009                return true;
2010            }
2011        }
2012        return false;
2013    }
2014    
2015
2016    
2017    /*
2018     * @see IJavaProject
2019     */

2020    public boolean isOnClasspath(IJavaElement element) {
2021        IClasspathEntry[] rawClasspath;
2022        try {
2023            rawClasspath = getRawClasspath();
2024        } catch(JavaModelException e){
2025            return false; // not a Java project
2026
}
2027        int elementType = element.getElementType();
2028        boolean isPackageFragmentRoot = false;
2029        boolean isFolderPath = false;
2030        boolean isSource = false;
2031        switch (elementType) {
2032            case IJavaElement.JAVA_MODEL:
2033                return false;
2034            case IJavaElement.JAVA_PROJECT:
2035                break;
2036            case IJavaElement.PACKAGE_FRAGMENT_ROOT:
2037                isPackageFragmentRoot = true;
2038                break;
2039            case IJavaElement.PACKAGE_FRAGMENT:
2040                isFolderPath = !((IPackageFragmentRoot)element.getParent()).isArchive();
2041                break;
2042            case IJavaElement.COMPILATION_UNIT:
2043                isSource = true;
2044                break;
2045            default:
2046                isSource = element.getAncestor(IJavaElement.COMPILATION_UNIT) != null;
2047                break;
2048        }
2049        IPath elementPath = element.getPath();
2050        
2051        // first look at unresolved entries
2052
int length = rawClasspath.length;
2053        for (int i = 0; i < length; i++) {
2054            IClasspathEntry entry = rawClasspath[i];
2055            switch (entry.getEntryKind()) {
2056                case IClasspathEntry.CPE_LIBRARY:
2057                case IClasspathEntry.CPE_PROJECT:
2058                case IClasspathEntry.CPE_SOURCE:
2059                    if (isOnClasspathEntry(elementPath, isFolderPath, isPackageFragmentRoot, entry))
2060                        return true;
2061                    break;
2062            }
2063        }
2064        
2065        // no need to go further for compilation units and elements inside a compilation unit
2066
// it can only be in a source folder, thus on the raw classpath
2067
if (isSource)
2068            return false;
2069        
2070        // then look at resolved entries
2071
for (int i = 0; i < length; i++) {
2072            IClasspathEntry rawEntry = rawClasspath[i];
2073            switch (rawEntry.getEntryKind()) {
2074                case IClasspathEntry.CPE_CONTAINER:
2075                    IClasspathContainer container;
2076                    try {
2077                        container = JavaCore.getClasspathContainer(rawEntry.getPath(), this);
2078                    } catch (JavaModelException e) {
2079                        break;
2080                    }
2081                    if (container == null)
2082                        break;
2083                    IClasspathEntry[] containerEntries = container.getClasspathEntries();
2084                    if (containerEntries == null)
2085                        break;
2086                    // container was bound
2087
for (int j = 0, containerLength = containerEntries.length; j < containerLength; j++){
2088                        IClasspathEntry resolvedEntry = containerEntries[j];
2089                        if (resolvedEntry == null) {
2090                            if (JavaModelManager.CP_RESOLVE_VERBOSE) {
2091                                JavaModelManager.getJavaModelManager().verbose_missbehaving_container(this, rawEntry.getPath(), containerEntries);
2092                            }
2093                            return false;
2094                        }
2095                        if (isOnClasspathEntry(elementPath, isFolderPath, isPackageFragmentRoot, resolvedEntry))
2096                            return true;
2097                    }
2098                    break;
2099                case IClasspathEntry.CPE_VARIABLE:
2100                    IClasspathEntry resolvedEntry = JavaCore.getResolvedClasspathEntry(rawEntry);
2101                    if (resolvedEntry == null)
2102                        break;
2103                    if (isOnClasspathEntry(elementPath, isFolderPath, isPackageFragmentRoot, resolvedEntry))
2104                        return true;
2105                    break;
2106            }
2107        }
2108        
2109        return false;
2110    }
2111    
2112    /*
2113     * @see IJavaProject
2114     */

2115    public boolean isOnClasspath(IResource resource) {
2116        IPath exactPath = resource.getFullPath();
2117        IPath path = exactPath;
2118        
2119        // ensure that folders are only excluded if all of their children are excluded
2120
int resourceType = resource.getType();
2121        boolean isFolderPath = resourceType == IResource.FOLDER || resourceType == IResource.PROJECT;
2122        
2123        IClasspathEntry[] classpath;
2124        try {
2125            classpath = this.getResolvedClasspath();
2126        } catch(JavaModelException e){
2127            return false; // not a Java project
2128
}
2129        for (int i = 0; i < classpath.length; i++) {
2130            IClasspathEntry entry = classpath[i];
2131            IPath entryPath = entry.getPath();
2132            if (entryPath.equals(exactPath)) { // package fragment roots must match exactly entry pathes (no exclusion there)
2133
return true;
2134            }
2135            if (entryPath.isPrefixOf(path)
2136                    && !Util.isExcluded(path, ((ClasspathEntry)entry).fullInclusionPatternChars(), ((ClasspathEntry)entry).fullExclusionPatternChars(), isFolderPath)) {
2137                return true;
2138            }
2139        }
2140        return false;
2141    }
2142
2143    private boolean isOnClasspathEntry(IPath elementPath, boolean isFolderPath, boolean isPackageFragmentRoot, IClasspathEntry entry) {
2144        IPath entryPath = entry.getPath();
2145        if (isPackageFragmentRoot) {
2146            // package fragment roots must match exactly entry pathes (no exclusion there)
2147
if (entryPath.equals(elementPath))
2148                return true;
2149        } else {
2150            if (entryPath.isPrefixOf(elementPath)
2151                    && !Util.isExcluded(elementPath, ((ClasspathEntry)entry).fullInclusionPatternChars(), ((ClasspathEntry)entry).fullExclusionPatternChars(), isFolderPath))
2152                return true;
2153        }
2154        return false;
2155    }
2156
2157    /**
2158     * load preferences from a shareable format (VCM-wise)
2159     */

2160     private Preferences loadPreferences() {
2161        
2162        Preferences preferences = new Preferences();
2163        IPath projectMetaLocation = getPluginWorkingLocation();
2164        if (projectMetaLocation != null) {
2165            File prefFile = projectMetaLocation.append(PREF_FILENAME).toFile();
2166            if (prefFile.exists()) { // load preferences from file
2167
InputStream in = null;
2168                try {
2169                    in = new BufferedInputStream(new FileInputStream(prefFile));
2170                    preferences.load(in);
2171                } catch (IOException e) { // problems loading preference store - quietly ignore
2172
} finally {
2173                    if (in != null) {
2174                        try {
2175                            in.close();
2176                        } catch (IOException e) { // ignore problems with close
2177
}
2178                    }
2179                }
2180                // one shot read, delete old preferences
2181
prefFile.delete();
2182                return preferences;
2183            }
2184        }
2185        return null;
2186     }
2187
2188    /**
2189     * @see IJavaProject#newEvaluationContext()
2190     */

2191    public IEvaluationContext newEvaluationContext() {
2192        EvaluationContext context = new EvaluationContext();
2193        context.setLineSeparator(Util.getLineSeparator(null/*no existing source*/, this));
2194        return new EvaluationContextWrapper(context, this);
2195    }
2196
2197    /*
2198     * Returns a new name lookup. This name lookup first looks in the given working copies.
2199     */

2200    public NameLookup newNameLookup(ICompilationUnit[] workingCopies) throws JavaModelException {
2201        return getJavaProjectElementInfo().newNameLookup(this, workingCopies);
2202    }
2203
2204    /*
2205     * Returns a new name lookup. This name lookup first looks in the working copies of the given owner.
2206     */

2207    public NameLookup newNameLookup(WorkingCopyOwner owner) throws JavaModelException {
2208        
2209        JavaModelManager manager = JavaModelManager.getJavaModelManager();
2210        ICompilationUnit[] workingCopies = owner == null ? null : manager.getWorkingCopies(owner, true/*add primary WCs*/);
2211        return newNameLookup(workingCopies);
2212    }
2213
2214    /*
2215     * Returns a new search name environment for this project. This name environment first looks in the given working copies.
2216     */

2217    public SearchableEnvironment newSearchableNameEnvironment(ICompilationUnit[] workingCopies) throws JavaModelException {
2218        return new SearchableEnvironment(this, workingCopies);
2219    }
2220
2221    /*
2222     * Returns a new search name environment for this project. This name environment first looks in the working copies
2223     * of the given owner.
2224     */

2225    public SearchableEnvironment newSearchableNameEnvironment(WorkingCopyOwner owner) throws JavaModelException {
2226        return new SearchableEnvironment(this, owner);
2227    }
2228
2229    /**
2230     * @see IJavaProject
2231     */

2232    public ITypeHierarchy newTypeHierarchy(
2233        IRegion region,
2234        IProgressMonitor monitor)
2235        throws JavaModelException {
2236            
2237        return newTypeHierarchy(region, DefaultWorkingCopyOwner.PRIMARY, monitor);
2238    }
2239
2240    /**
2241     * @see IJavaProject
2242     */

2243    public ITypeHierarchy newTypeHierarchy(
2244        IRegion region,
2245        WorkingCopyOwner owner,
2246        IProgressMonitor monitor)
2247        throws JavaModelException {
2248
2249        if (region == null) {
2250            throw new IllegalArgumentException JavaDoc(Messages.hierarchy_nullRegion);
2251        }
2252        ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner, true/*add primary working copies*/);
2253        CreateTypeHierarchyOperation op =
2254            new CreateTypeHierarchyOperation(region, workingCopies, null, true);
2255        op.runOperation(monitor);
2256        return op.getResult();
2257    }
2258
2259    /**
2260     * @see IJavaProject
2261     */

2262    public ITypeHierarchy newTypeHierarchy(
2263        IType type,
2264        IRegion region,
2265        IProgressMonitor monitor)
2266        throws JavaModelException {
2267            
2268        return newTypeHierarchy(type, region, DefaultWorkingCopyOwner.PRIMARY, monitor);
2269    }
2270
2271    /**
2272     * @see IJavaProject
2273     */

2274    public ITypeHierarchy newTypeHierarchy(
2275        IType type,
2276        IRegion region,
2277        WorkingCopyOwner owner,
2278        IProgressMonitor monitor)
2279        throws JavaModelException {
2280
2281        if (type == null) {
2282            throw new IllegalArgumentException JavaDoc(Messages.hierarchy_nullFocusType);
2283        }
2284        if (region == null) {
2285            throw new IllegalArgumentException JavaDoc(Messages.hierarchy_nullRegion);
2286        }
2287        ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner, true/*add primary working copies*/);
2288        CreateTypeHierarchyOperation op =
2289            new CreateTypeHierarchyOperation(region, workingCopies, type, true/*compute subtypes*/);
2290        op.runOperation(monitor);
2291        return op.getResult();
2292    }
2293    public String JavaDoc[] projectPrerequisites(IClasspathEntry[] entries)
2294        throws JavaModelException {
2295            
2296        ArrayList JavaDoc prerequisites = new ArrayList JavaDoc();
2297        // need resolution
2298
entries = resolveClasspath(entries);
2299        for (int i = 0, length = entries.length; i < length; i++) {
2300            IClasspathEntry entry = entries[i];
2301            if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
2302                prerequisites.add(entry.getPath().lastSegment());
2303            }
2304        }
2305        int size = prerequisites.size();
2306        if (size == 0) {
2307            return NO_PREREQUISITES;
2308        } else {
2309            String JavaDoc[] result = new String JavaDoc[size];
2310            prerequisites.toArray(result);
2311            return result;
2312        }
2313    }
2314
2315    /*
2316     * Reads the classpath file entries of this project's .classpath file.
2317     * This includes the output entry.
2318     * As a side effect, unknown elements are stored in the given map (if not null)
2319     * Throws exceptions if the file cannot be accessed or is malformed.
2320     */

2321    public IClasspathEntry[] readFileEntriesWithException(Map JavaDoc unknownElements) throws CoreException, IOException, AssertionFailedException {
2322        String JavaDoc xmlClasspath;
2323        IFile rscFile = this.project.getFile(JavaProject.CLASSPATH_FILENAME);
2324        if (rscFile.exists()) {
2325            byte[] bytes = Util.getResourceContentsAsByteArray(rscFile);
2326            try {
2327                xmlClasspath = new String JavaDoc(bytes, org.eclipse.jdt.internal.compiler.util.Util.UTF_8); // .classpath always encoded with UTF-8
2328
} catch (UnsupportedEncodingException e) {
2329                Util.log(e, "Could not read .classpath with UTF-8 encoding"); //$NON-NLS-1$
2330
// fallback to default
2331
xmlClasspath = new String JavaDoc(bytes);
2332            }
2333        } else {
2334            // when a project is imported, we get a first delta for the addition of the .project, but the .classpath is not accessible
2335
// so default to using java.io.File
2336
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=96258
2337
URI JavaDoc location = rscFile.getLocationURI();
2338            if (location == null)
2339                throw new IOException("Cannot obtain a location URI for " + rscFile); //$NON-NLS-1$
2340
File file = Util.toLocalFile(location, null/*no progress monitor available*/);
2341            if (file == null)
2342                throw new IOException("Unable to fetch file from " + location); //$NON-NLS-1$
2343
byte[] bytes;
2344            try {
2345                bytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(file);
2346            } catch (IOException e) {
2347                if (!file.exists())
2348                    return defaultClasspath();
2349                throw e;
2350            }
2351            try {
2352                xmlClasspath = new String JavaDoc(bytes, org.eclipse.jdt.internal.compiler.util.Util.UTF_8); // .classpath always encoded with UTF-8
2353
} catch (UnsupportedEncodingException e) {
2354                Util.log(e, "Could not read .classpath with UTF-8 encoding"); //$NON-NLS-1$
2355
// fallback to default
2356
xmlClasspath = new String JavaDoc(bytes);
2357            }
2358        }
2359        return decodeClasspath(xmlClasspath, unknownElements);
2360    }
2361
2362    /*
2363     * Reads the classpath file entries of this project's .classpath file.
2364     * This includes the output entry.
2365     * As a side effect, unknown elements are stored in the given map (if not null)
2366     */

2367    private IClasspathEntry[] readFileEntries(Map JavaDoc unkwownElements) {
2368        try {
2369            return readFileEntriesWithException(unkwownElements);
2370        } catch (CoreException e) {
2371            Util.log(e, "Exception while reading " + getPath().append(JavaProject.CLASSPATH_FILENAME)); //$NON-NLS-1$
2372
return JavaProject.INVALID_CLASSPATH;
2373        } catch (IOException e) {
2374            Util.log(e, "Exception while reading " + getPath().append(JavaProject.CLASSPATH_FILENAME)); //$NON-NLS-1$
2375
return JavaProject.INVALID_CLASSPATH;
2376        } catch (AssertionFailedException e) {
2377            Util.log(e, "Exception while reading " + getPath().append(JavaProject.CLASSPATH_FILENAME)); //$NON-NLS-1$
2378
return JavaProject.INVALID_CLASSPATH;
2379        }
2380    }
2381
2382    /**
2383     * @see IJavaProject
2384     */

2385    public IPath readOutputLocation() {
2386        // Read classpath file without creating markers nor logging problems
2387
IClasspathEntry[] classpath = readFileEntries(null/*not interested in unknown elements*/);
2388        if (classpath == JavaProject.INVALID_CLASSPATH)
2389            return defaultOutputLocation();
2390        
2391        // extract the output location
2392
IPath outputLocation = null;
2393        if (classpath.length > 0) {
2394            IClasspathEntry entry = classpath[classpath.length - 1];
2395            if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
2396                outputLocation = entry.getPath();
2397            }
2398        }
2399        return outputLocation;
2400    }
2401    
2402    /**
2403     * @see IJavaProject
2404     */

2405    public IClasspathEntry[] readRawClasspath() {
2406        // Read classpath file without creating markers nor logging problems
2407
IClasspathEntry[] classpath = readFileEntries(null/*not interested in unknown elements*/);
2408        if (classpath == JavaProject.INVALID_CLASSPATH)
2409            return defaultClasspath();
2410        
2411        // discard the output location
2412
if (classpath.length > 0) {
2413            IClasspathEntry entry = classpath[classpath.length - 1];
2414            if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
2415                IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1];
2416                System.arraycopy(classpath, 0, copy, 0, copy.length);
2417                classpath = copy;
2418            }
2419        }
2420        return classpath;
2421    }
2422
2423    /**
2424     * Removes the given builder from the build spec for the given project.
2425     */

2426    protected void removeFromBuildSpec(String JavaDoc builderID) throws CoreException {
2427
2428        IProjectDescription description = this.project.getDescription();
2429        ICommand[] commands = description.getBuildSpec();
2430        for (int i = 0; i < commands.length; ++i) {
2431            if (commands[i].getBuilderName().equals(builderID)) {
2432                ICommand[] newCommands = new ICommand[commands.length - 1];
2433                System.arraycopy(commands, 0, newCommands, 0, i);
2434                System.arraycopy(commands, i + 1, newCommands, i, commands.length - i - 1);
2435                description.setBuildSpec(newCommands);
2436                this.project.setDescription(description, null);
2437                return;
2438            }
2439        }
2440    }
2441    
2442    /*
2443     * Resets this project's caches
2444     */

2445    public void resetCaches() {
2446        JavaProjectElementInfo info = (JavaProjectElementInfo) JavaModelManager.getJavaModelManager().peekAtInfo(this);
2447        if (info != null){
2448            info.resetCaches();
2449        }
2450    }
2451
2452    /*
2453     * Resolve the given raw classpath.
2454     */

2455    public IClasspathEntry[] resolveClasspath(IClasspathEntry[] rawClasspath) throws JavaModelException {
2456        ArrayList JavaDoc resolvedEntries = new ArrayList JavaDoc();
2457        for (int i = 0, length = rawClasspath.length; i < length; i++) {
2458            IClasspathEntry rawEntry = rawClasspath[i];
2459            switch (rawEntry.getEntryKind()){
2460                case IClasspathEntry.CPE_VARIABLE:
2461                    IClasspathEntry resolvedEntry = null;
2462                    try {
2463                        resolvedEntry = JavaCore.getResolvedClasspathEntry(rawEntry);
2464                    } catch (AssertionFailedException e) {
2465                        // Catch the assertion failure
2466
// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=55992
2467
break;
2468                    }
2469                    if (resolvedEntry != null)
2470                        resolvedEntries.add(resolvedEntry);
2471                    break;
2472                case IClasspathEntry.CPE_CONTAINER:
2473                    IClasspathContainer container = JavaCore.getClasspathContainer(rawEntry.getPath(), this);
2474                    if (container == null)
2475                        break;
2476                    IClasspathEntry[] containerEntries = container.getClasspathEntries();
2477                    if (containerEntries == null)
2478                        break;
2479
2480                    // container was bound
2481
for (int j = 0, containerLength = containerEntries.length; j < containerLength; j++){
2482                        ClasspathEntry cEntry = (ClasspathEntry) containerEntries[j];
2483                        if (cEntry == null) {
2484                            if (JavaModelManager.CP_RESOLVE_VERBOSE) {
2485                                JavaModelManager.getJavaModelManager().verbose_missbehaving_container(this, rawEntry.getPath(), containerEntries);
2486                            }
2487                            break;
2488                        }
2489                        // if container is exported or restricted, then its nested entries must in turn be exported (21749) and/or propagate restrictions
2490
cEntry = cEntry.combineWith((ClasspathEntry) rawEntry);
2491                        resolvedEntries.add(cEntry);
2492                    }
2493                    break;
2494                default:
2495                    resolvedEntries.add(rawEntry);
2496            }
2497        }
2498        IClasspathEntry[] result = new IClasspathEntry[resolvedEntries.size()];
2499        resolvedEntries.toArray(result);
2500        return result;
2501    }
2502
2503    /*
2504     * Resolve the given perProjectInfo's raw classpath and store the resolved classpath in the perProjectInfo.
2505     */

2506    public void resolveClasspath(PerProjectInfo perProjectInfo) throws JavaModelException {
2507        JavaModelManager manager = JavaModelManager.getJavaModelManager();
2508        try {
2509            manager.setClasspathBeingResolved(this, true);
2510            
2511            // get raw info inside a synchronized block to ensure that it is consistent
2512
IClasspathEntry[] rawClasspath;
2513            IPath outputLocation;
2514            IJavaModelStatus rawClasspathStatus;
2515            synchronized (perProjectInfo) {
2516                rawClasspath= perProjectInfo.rawClasspath;
2517                if (rawClasspath == null)
2518                    rawClasspath = perProjectInfo.readAndCacheClasspath(this);
2519                outputLocation = perProjectInfo.outputLocation;
2520                rawClasspathStatus = perProjectInfo.rawClasspathStatus;
2521            }
2522                        
2523            IJavaModelStatus unresolvedEntryStatus = JavaModelStatus.VERIFIED_OK;
2524            HashMap JavaDoc rawReverseMap = new HashMap JavaDoc();
2525            Map JavaDoc rootPathToResolvedEntries = new HashMap JavaDoc();
2526            
2527            ArrayList JavaDoc resolvedEntries = new ArrayList JavaDoc();
2528            int length = rawClasspath.length;
2529            for (int i = 0; i < length; i++) {
2530    
2531                IClasspathEntry rawEntry = rawClasspath[i];
2532                IPath resolvedPath;
2533                
2534                switch (rawEntry.getEntryKind()){
2535                    
2536                    case IClasspathEntry.CPE_VARIABLE :
2537                        IClasspathEntry resolvedEntry = null;
2538                        try {
2539                            resolvedEntry = JavaCore.getResolvedClasspathEntry(rawEntry);
2540                        } catch (AssertionFailedException e) {
2541                            // Catch the assertion failure and set ststus instead
2542
// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=55992
2543
unresolvedEntryStatus = new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, e.getMessage());
2544                            break;
2545                        }
2546                        if (resolvedEntry == null) {
2547                            unresolvedEntryStatus = new JavaModelStatus(IJavaModelStatusConstants.CP_VARIABLE_PATH_UNBOUND, this, rawEntry.getPath());
2548                        } else {
2549                            if (rawReverseMap.get(resolvedPath = resolvedEntry.getPath()) == null) {
2550                                rawReverseMap.put(resolvedPath , rawEntry);
2551                                rootPathToResolvedEntries.put(resolvedPath, resolvedEntry);
2552                            }
2553                            resolvedEntries.add(resolvedEntry);
2554                        }
2555                        break;
2556    
2557                    case IClasspathEntry.CPE_CONTAINER :
2558                        IClasspathContainer container = JavaCore.getClasspathContainer(rawEntry.getPath(), this);
2559                        if (container == null){
2560                            unresolvedEntryStatus = new JavaModelStatus(IJavaModelStatusConstants.CP_CONTAINER_PATH_UNBOUND, this, rawEntry.getPath());
2561                            break;
2562                        }
2563    
2564                        IClasspathEntry[] containerEntries = container.getClasspathEntries();
2565                        if (containerEntries == null) break;
2566    
2567                        // container was bound
2568
for (int j = 0, containerLength = containerEntries.length; j < containerLength; j++){
2569                            ClasspathEntry cEntry = (ClasspathEntry) containerEntries[j];
2570                            if (cEntry == null) {
2571                                if (JavaModelManager.CP_RESOLVE_VERBOSE) {
2572                                    JavaModelManager.getJavaModelManager().verbose_missbehaving_container(this, rawEntry.getPath(), containerEntries);
2573                                }
2574                                break;
2575                            }
2576                            // if container is exported or restricted, then its nested entries must in turn be exported (21749) and/or propagate restrictions
2577
cEntry = cEntry.combineWith((ClasspathEntry) rawEntry);
2578                            if (rawReverseMap.get(resolvedPath = cEntry.getPath()) == null) {
2579                                rawReverseMap.put(resolvedPath , rawEntry);
2580                                rootPathToResolvedEntries.put(resolvedPath, cEntry);
2581                            }
2582                            resolvedEntries.add(cEntry);
2583                        }
2584                        break;
2585                                            
2586                    default :
2587                        if (rawReverseMap.get(resolvedPath = rawEntry.getPath()) == null) {
2588                            rawReverseMap.put(resolvedPath , rawEntry);
2589                            rootPathToResolvedEntries.put(resolvedPath, rawEntry);
2590                        }
2591                        resolvedEntries.add(rawEntry);
2592
2593                }
2594            }
2595    
2596            // store resolved info along with the raw info to ensure consistency
2597
IClasspathEntry[] resolvedClasspath = new IClasspathEntry[resolvedEntries.size()];
2598            resolvedEntries.toArray(resolvedClasspath);
2599            perProjectInfo.setClasspath(rawClasspath, outputLocation, rawClasspathStatus, resolvedClasspath, rawReverseMap, rootPathToResolvedEntries, unresolvedEntryStatus);
2600        } finally {
2601            manager.setClasspathBeingResolved(this, false);
2602        }
2603    }
2604
2605    /**
2606     * Answers an ID which is used to distinguish project/entries during package
2607     * fragment root computations
2608     * @return String
2609     */

2610    public String JavaDoc rootID(){
2611        return "[PRJ]"+this.project.getFullPath(); //$NON-NLS-1$
2612
}
2613
2614    /**
2615     * Saves the classpath in a shareable format (VCM-wise) only when necessary, that is, if it is semantically different
2616     * from the existing one in file. Will never write an identical one.
2617     *
2618     * @param newClasspath IClasspathEntry[]
2619     * @param newOutputLocation IPath
2620     * @return boolean Return whether the .classpath file was modified.
2621     * @throws JavaModelException
2622     */

2623    public boolean saveClasspath(IClasspathEntry[] newClasspath, IPath newOutputLocation) throws JavaModelException {
2624
2625        if (!this.project.isAccessible()) return false;
2626
2627        Map JavaDoc unknownElements = new HashMap JavaDoc();
2628        IClasspathEntry[] fileEntries = readFileEntries(unknownElements);
2629        if (fileEntries != JavaProject.INVALID_CLASSPATH && areClasspathsEqual(newClasspath, newOutputLocation, fileEntries)) {
2630            // no need to save it, it is the same
2631
return false;
2632        }
2633
2634        // actual file saving
2635
try {
2636            setSharedProperty(JavaProject.CLASSPATH_FILENAME, encodeClasspath(newClasspath, newOutputLocation, true, unknownElements));
2637            return true;
2638        } catch (CoreException e) {
2639            throw new JavaModelException(e);
2640        }
2641    }
2642
2643    /**
2644     * Update the Java command in the build spec (replace existing one if present,
2645     * add one first if none).
2646     */

2647    private void setJavaCommand(
2648        IProjectDescription description,
2649        ICommand newCommand)
2650        throws CoreException {
2651
2652        ICommand[] oldBuildSpec = description.getBuildSpec();
2653        int oldJavaCommandIndex = getJavaCommandIndex(oldBuildSpec);
2654        ICommand[] newCommands;
2655
2656        if (oldJavaCommandIndex == -1) {
2657            // Add a Java build spec before other builders (1FWJK7I)
2658
newCommands = new ICommand[oldBuildSpec.length + 1];
2659            System.arraycopy(oldBuildSpec, 0, newCommands, 1, oldBuildSpec.length);
2660            newCommands[0] = newCommand;
2661        } else {
2662            oldBuildSpec[oldJavaCommandIndex] = newCommand;
2663            newCommands = oldBuildSpec;
2664        }
2665
2666        // Commit the spec change into the project
2667
description.setBuildSpec(newCommands);
2668        this.project.setDescription(description, null);
2669    }
2670
2671    /**
2672     * @see org.eclipse.jdt.core.IJavaProject#setOption(java.lang.String, java.lang.String)
2673     */

2674    public void setOption(String JavaDoc optionName, String JavaDoc optionValue) {
2675        if (!JavaModelManager.getJavaModelManager().optionNames.contains(optionName)) return; // unrecognized option
2676
if (optionValue == null) return; // invalid value
2677
IEclipsePreferences projectPreferences = getEclipsePreferences();
2678        String JavaDoc defaultValue = JavaCore.getOption(optionName);
2679        if (optionValue.equals(defaultValue)) {
2680            // set default value => remove preference
2681
projectPreferences.remove(optionName);
2682        } else {
2683            projectPreferences.put(optionName, optionValue);
2684        }
2685        
2686        // Dump changes
2687
try {
2688            projectPreferences.flush();
2689        } catch (BackingStoreException e) {
2690            // problem with pref store - quietly ignore
2691
}
2692    }
2693
2694    /**
2695     * @see org.eclipse.jdt.core.IJavaProject#setOptions(Map)
2696     */

2697    public void setOptions(Map JavaDoc newOptions) {
2698
2699        IEclipsePreferences projectPreferences = getEclipsePreferences();
2700        try {
2701            if (newOptions == null){
2702                projectPreferences.clear();
2703            } else {
2704                Iterator JavaDoc entries = newOptions.entrySet().iterator();
2705                while (entries.hasNext()){
2706                    Map.Entry JavaDoc entry = (Map.Entry JavaDoc) entries.next();
2707                    String JavaDoc key = (String JavaDoc) entry.getKey();
2708                    if (!JavaModelManager.getJavaModelManager().optionNames.contains(key)) continue; // unrecognized option
2709
// no filtering for encoding (custom encoding for project is allowed)
2710
projectPreferences.put(key, (String JavaDoc) entry.getValue());
2711                }
2712                
2713                // reset to default all options not in new map
2714
// @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=26255
2715
// @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=49691
2716
String JavaDoc[] pNames = projectPreferences.keys();
2717                int ln = pNames.length;
2718                for (int i=0; i<ln; i++) {
2719                    String JavaDoc key = pNames[i];
2720                    if (!newOptions.containsKey(key)) {
2721                        projectPreferences.remove(key); // old preferences => remove from preferences table
2722
}
2723                }
2724            }
2725
2726            // persist options
2727
projectPreferences.flush();
2728            
2729            // flush cache immediately
2730
try {
2731                getPerProjectInfo().options = null;
2732            } catch (JavaModelException e) {
2733                // do nothing
2734
}
2735        } catch (BackingStoreException e) {
2736            // problem with pref store - quietly ignore
2737
}
2738    }
2739    /**
2740     * @see IJavaProject
2741     */

2742    public void setOutputLocation(IPath path, IProgressMonitor monitor) throws JavaModelException {
2743        if (path == null) {
2744            throw new IllegalArgumentException JavaDoc(Messages.path_nullPath);
2745        }
2746        if (path.equals(getOutputLocation())) {
2747            return;
2748        }
2749        setRawClasspath(getRawClasspath(), path, monitor);
2750    }
2751
2752    /**
2753     * Sets the underlying kernel project of this Java project,
2754     * and fills in its parent and name.
2755     * Called by IProject.getNature().
2756     *
2757     * @see IProjectNature#setProject(IProject)
2758     */

2759    public void setProject(IProject project) {
2760
2761        this.project = project;
2762        this.parent = JavaModelManager.getJavaModelManager().getJavaModel();
2763    }
2764
2765    /**
2766     * @see IJavaProject#setRawClasspath(IClasspathEntry[],boolean,IProgressMonitor)
2767     */

2768    public void setRawClasspath(
2769        IClasspathEntry[] entries,
2770        boolean canModifyResources,
2771        IProgressMonitor monitor)
2772        throws JavaModelException {
2773
2774        setRawClasspath(
2775            entries,
2776            getOutputLocation()/*don't change output*/,
2777            canModifyResources,
2778            monitor);
2779    }
2780
2781    /**
2782     * @see IJavaProject#setRawClasspath(IClasspathEntry[],IPath,boolean,IProgressMonitor)
2783     */

2784    public void setRawClasspath(
2785            IClasspathEntry[] newRawClasspath,
2786            IPath newOutputLocation,
2787            boolean canModifyResources,
2788            IProgressMonitor monitor)
2789            throws JavaModelException {
2790        
2791        try {
2792            if (newRawClasspath == null) //are we already with the default classpath
2793
newRawClasspath = defaultClasspath();
2794
2795            SetClasspathOperation op =
2796                new SetClasspathOperation(
2797                    this,
2798                    newRawClasspath,
2799                    newOutputLocation,
2800                    canModifyResources);
2801            op.runOperation(monitor);
2802        } catch (JavaModelException e) {
2803            JavaModelManager.getJavaModelManager().getDeltaProcessor().flush();
2804            throw e;
2805        }
2806    }
2807    
2808    /**
2809     * @see IJavaProject#setRawClasspath(IClasspathEntry[],IPath,IProgressMonitor)
2810     */

2811    public void setRawClasspath(
2812        IClasspathEntry[] entries,
2813        IPath outputLocation,
2814        IProgressMonitor monitor)
2815        throws JavaModelException {
2816
2817        setRawClasspath(
2818            entries,
2819            outputLocation,
2820            true/*can change resource (as per API contract)*/,
2821            monitor);
2822    }
2823    
2824    /**
2825     * @see IJavaProject
2826     */

2827    public void setRawClasspath(
2828        IClasspathEntry[] entries,
2829        IProgressMonitor monitor)
2830        throws JavaModelException {
2831
2832        setRawClasspath(
2833            entries,
2834            getOutputLocation()/*don't change output*/,
2835            true/*can change resource (as per API contract)*/,
2836            monitor);
2837    }
2838
2839    /**
2840     * Record a shared persistent property onto a project.
2841     * Note that it is orthogonal to IResource persistent properties, and client code has to decide
2842     * which form of storage to use appropriately. Shared properties produce real resource files which
2843     * can be shared through a VCM onto a server. Persistent properties are not shareable.
2844     *
2845     * shared properties end up in resource files, and thus cannot be modified during
2846     * delta notifications (a CoreException would then be thrown).
2847     *
2848     * @param key String
2849     * @param value String
2850     * @see JavaProject#getSharedProperty(String key)
2851     * @throws CoreException
2852     */

2853    public void setSharedProperty(String JavaDoc key, String JavaDoc value) throws CoreException {
2854
2855        IFile rscFile = this.project.getFile(key);
2856        byte[] bytes = null;
2857        try {
2858            bytes = value.getBytes(org.eclipse.jdt.internal.compiler.util.Util.UTF_8); // .classpath always encoded with UTF-8
2859
} catch (UnsupportedEncodingException e) {
2860            Util.log(e, "Could not write .classpath with UTF-8 encoding "); //$NON-NLS-1$
2861
// fallback to default
2862
bytes = value.getBytes();
2863        }
2864        InputStream inputStream = new ByteArrayInputStream(bytes);
2865        // update the resource content
2866
if (rscFile.exists()) {
2867            if (rscFile.isReadOnly()) {
2868                // provide opportunity to checkout read-only .classpath file (23984)
2869
ResourcesPlugin.getWorkspace().validateEdit(new IFile[]{rscFile}, null);
2870            }
2871            rscFile.setContents(inputStream, IResource.FORCE, null);
2872        } else {
2873            rscFile.create(inputStream, IResource.FORCE, null);
2874        }
2875    }
2876
2877    /**
2878     * If a cycle is detected, then cycleParticipants contains all the paths of projects involved in this cycle (directly and indirectly),
2879     * no cycle if the set is empty (and started empty)
2880     * @param prereqChain ArrayList
2881     * @param cycleParticipants HashSet
2882     * @param workspaceRoot IWorkspaceRoot
2883     * @param traversed HashSet
2884     * @param preferredClasspaths Map
2885     */

2886    public void updateCycleParticipants(
2887            ArrayList JavaDoc prereqChain,
2888            HashSet JavaDoc cycleParticipants,
2889            IWorkspaceRoot workspaceRoot,
2890            HashSet JavaDoc traversed,
2891            Map JavaDoc preferredClasspaths){
2892
2893        IPath path = this.getPath();
2894        prereqChain.add(path);
2895        traversed.add(path);
2896        try {
2897            IClasspathEntry[] classpath = null;
2898            if (preferredClasspaths != null) classpath = (IClasspathEntry[])preferredClasspaths.get(this);
2899            if (classpath == null) classpath = getResolvedClasspath();
2900            for (int i = 0, length = classpath.length; i < length; i++) {
2901                IClasspathEntry entry = classpath[i];
2902                
2903                if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT){
2904                    IPath prereqProjectPath = entry.getPath();
2905                    int index = cycleParticipants.contains(prereqProjectPath) ? 0 : prereqChain.indexOf(prereqProjectPath);
2906                    if (index >= 0) { // refer to cycle, or in cycle itself
2907
for (int size = prereqChain.size(); index < size; index++) {
2908                            cycleParticipants.add(prereqChain.get(index));
2909                        }
2910                    } else {
2911                        if (!traversed.contains(prereqProjectPath)) {
2912                            IResource member = workspaceRoot.findMember(prereqProjectPath);
2913                            if (member != null && member.getType() == IResource.PROJECT){
2914                                JavaProject javaProject = (JavaProject)JavaCore.create((IProject)member);
2915                                javaProject.updateCycleParticipants(prereqChain, cycleParticipants, workspaceRoot, traversed, preferredClasspaths);
2916                            }
2917                        }
2918                    }
2919                }
2920            }
2921        } catch(JavaModelException e){
2922            // project doesn't exist: ignore
2923
}
2924        prereqChain.remove(path);
2925    }
2926
2927    /**
2928     * Reset the collection of package fragment roots (local ones) - only if opened.
2929     */

2930    public void updatePackageFragmentRoots(){
2931        
2932            if (this.isOpen()) {
2933                try {
2934                    JavaProjectElementInfo info = getJavaProjectElementInfo();
2935                    computeChildren(info);
2936                    info.resetCaches(); // discard caches (hold onto roots and pkg fragments)
2937
} catch(JavaModelException e){
2938                    try {
2939                        close(); // could not do better
2940
} catch(JavaModelException ex){
2941                        // ignore
2942
}
2943                }
2944            }
2945    }
2946
2947    /*
2948     * Update eclipse preferences from old preferences.
2949     */

2950     private void updatePreferences(IEclipsePreferences preferences) {
2951        
2952        Preferences oldPreferences = loadPreferences();
2953        if (oldPreferences != null) {
2954            String JavaDoc[] propertyNames = oldPreferences.propertyNames();
2955            for (int i = 0; i < propertyNames.length; i++){
2956                String JavaDoc propertyName = propertyNames[i];
2957                String JavaDoc propertyValue = oldPreferences.getString(propertyName);
2958                if (!"".equals(propertyValue)) { //$NON-NLS-1$
2959
preferences.put(propertyName, propertyValue);
2960                }
2961            }
2962            try {
2963                // save immediately new preferences
2964
preferences.flush();
2965            } catch (BackingStoreException e) {
2966                // fails silently
2967
}
2968        }
2969     }
2970}
2971
Popular Tags