988a7187e99183fe1291702dc005c981782c22e3
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / JavaProject.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
12
13 import java.io.BufferedInputStream;
14 import java.io.BufferedOutputStream;
15 import java.io.ByteArrayInputStream;
16 import java.io.ByteArrayOutputStream;
17 import java.io.File;
18 import java.io.FileInputStream;
19 import java.io.FileOutputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23 import java.io.OutputStreamWriter;
24 import java.io.StringReader;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.Hashtable;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Map;
32
33 import javax.xml.parsers.DocumentBuilder;
34 import javax.xml.parsers.DocumentBuilderFactory;
35 import javax.xml.parsers.ParserConfigurationException;
36 import javax.xml.parsers.SAXParserFactory;
37
38 import net.sourceforge.phpdt.core.IClasspathEntry;
39 import net.sourceforge.phpdt.core.ICompilationUnit;
40 import net.sourceforge.phpdt.core.IJavaElement;
41 import net.sourceforge.phpdt.core.IJavaModelMarker;
42 import net.sourceforge.phpdt.core.IJavaModelStatus;
43 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
44 import net.sourceforge.phpdt.core.IJavaProject;
45 import net.sourceforge.phpdt.core.IPackageFragment;
46 import net.sourceforge.phpdt.core.IPackageFragmentRoot;
47 import net.sourceforge.phpdt.core.JavaCore;
48 import net.sourceforge.phpdt.core.JavaModelException;
49 import net.sourceforge.phpdt.core.WorkingCopyOwner;
50 import net.sourceforge.phpdt.internal.codeassist.ISearchableNameEnvironment;
51 import net.sourceforge.phpdt.internal.compiler.util.ObjectVector;
52 import net.sourceforge.phpdt.internal.core.util.MementoTokenizer;
53 import net.sourceforge.phpdt.internal.core.util.Util;
54 import net.sourceforge.phpdt.internal.corext.Assert;
55 import net.sourceforge.phpeclipse.LoadPathEntry;
56 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
57
58 import org.eclipse.core.resources.ICommand;
59 import org.eclipse.core.resources.IFile;
60 import org.eclipse.core.resources.IFolder;
61 import org.eclipse.core.resources.IMarker;
62 import org.eclipse.core.resources.IProject;
63 import org.eclipse.core.resources.IProjectDescription;
64 import org.eclipse.core.resources.IProjectNature;
65 import org.eclipse.core.resources.IResource;
66 import org.eclipse.core.resources.IWorkspace;
67 import org.eclipse.core.resources.IWorkspaceRoot;
68 import org.eclipse.core.resources.ResourcesPlugin;
69 import org.eclipse.core.runtime.CoreException;
70 import org.eclipse.core.runtime.IPath;
71 import org.eclipse.core.runtime.IProgressMonitor;
72 import org.eclipse.core.runtime.Path;
73 import org.eclipse.core.runtime.Preferences;
74 import org.eclipse.core.runtime.QualifiedName;
75 import org.w3c.dom.Element;
76 import org.w3c.dom.Node;
77 import org.w3c.dom.NodeList;
78 import org.xml.sax.Attributes;
79 import org.xml.sax.ContentHandler;
80 import org.xml.sax.InputSource;
81 import org.xml.sax.Locator;
82 import org.xml.sax.SAXException;
83 import org.xml.sax.XMLReader;
84
85 /**
86  * Handle for a Java Project.
87  * 
88  * <p>
89  * A Java Project internally maintains a devpath that corresponds to the
90  * project's classpath. The classpath may include source folders from the
91  * current project; jars in the current project, other projects, and the local
92  * file system; and binary folders (output location) of other projects. The Java
93  * Model presents source elements corresponding to output .class files in other
94  * projects, and thus uses the devpath rather than the classpath (which is
95  * really a compilation path). The devpath mimics the classpath, except has
96  * source folder entries in place of output locations in external projects.
97  * 
98  * <p>
99  * Each JavaProject has a NameLookup facility that locates elements on by name,
100  * based on the devpath.
101  * 
102  * @see IJavaProject
103  */
104 public class JavaProject extends Openable implements IJavaProject,
105                 IProjectNature {
106
107         /**
108          * Whether the underlying file system is case sensitive.
109          */
110         protected static final boolean IS_CASE_SENSITIVE = !new File("Temp").equals(new File("temp")); //$NON-NLS-1$ //$NON-NLS-2$
111
112         /**
113          * An empty array of strings indicating that a project doesn't have any
114          * prerequesite projects.
115          */
116         protected static final String[] NO_PREREQUISITES = new String[0];
117
118         /**
119          * The platform project this <code>IJavaProject</code> is based on
120          */
121         protected IProject project;
122
123         protected List fLoadPathEntries;
124
125         protected boolean fScratched;
126
127         /**
128          * Name of file containing project classpath
129          */
130         public static final String CLASSPATH_FILENAME = ".classpath"; //$NON-NLS-1$
131
132         /**
133          * Name of file containing custom project preferences
134          */
135         public static final String PREF_FILENAME = ".jprefs"; //$NON-NLS-1$
136
137         /**
138          * Value of the project's raw classpath if the .classpath file contains
139          * invalid entries.
140          */
141         public static final IClasspathEntry[] INVALID_CLASSPATH = new IClasspathEntry[0];
142
143         private static final String CUSTOM_DEFAULT_OPTION_VALUE = "#\r\n\r#custom-non-empty-default-value#\r\n\r#"; //$NON-NLS-1$
144
145         /*
146          * Value of project's resolved classpath while it is being resolved
147          */
148         private static final IClasspathEntry[] RESOLUTION_IN_PROGRESS = new IClasspathEntry[0];
149
150         /**
151          * Returns a canonicalized path from the given external path. Note that the
152          * return path contains the same number of segments and it contains a device
153          * only if the given path contained one.
154          * 
155          * @see java.io.File for the definition of a canonicalized path
156          */
157         public static IPath canonicalizedPath(IPath externalPath) {
158
159                 if (externalPath == null)
160                         return null;
161
162                 if (JavaModelManager.VERBOSE) {
163                         System.out
164                                         .println("JAVA MODEL - Canonicalizing " + externalPath.toString()); //$NON-NLS-1$
165                 }
166
167                 if (IS_CASE_SENSITIVE) {
168                         if (JavaModelManager.VERBOSE) {
169                                 System.out
170                                                 .println("JAVA MODEL - Canonical path is original path (file system is case sensitive)"); //$NON-NLS-1$
171                         }
172                         return externalPath;
173                 }
174
175                 // if not external path, return original path
176                 IWorkspace workspace = ResourcesPlugin.getWorkspace();
177                 if (workspace == null)
178                         return externalPath; // protection during shutdown (30487)
179                 if (workspace.getRoot().findMember(externalPath) != null) {
180                         if (JavaModelManager.VERBOSE) {
181                                 System.out
182                                                 .println("JAVA MODEL - Canonical path is original path (member of workspace)"); //$NON-NLS-1$
183                         }
184                         return externalPath;
185                 }
186
187                 IPath canonicalPath = null;
188                 try {
189                         canonicalPath = new Path(new File(externalPath.toOSString())
190                                         .getCanonicalPath());
191                 } catch (IOException e) {
192                         // default to original path
193                         if (JavaModelManager.VERBOSE) {
194                                 System.out
195                                                 .println("JAVA MODEL - Canonical path is original path (IOException)"); //$NON-NLS-1$
196                         }
197                         return externalPath;
198                 }
199
200                 IPath result;
201                 int canonicalLength = canonicalPath.segmentCount();
202                 if (canonicalLength == 0) {
203                         // the java.io.File canonicalization failed
204                         if (JavaModelManager.VERBOSE) {
205                                 System.out
206                                                 .println("JAVA MODEL - Canonical path is original path (canonical path is empty)"); //$NON-NLS-1$
207                         }
208                         return externalPath;
209                 } else if (externalPath.isAbsolute()) {
210                         result = canonicalPath;
211                 } else {
212                         // if path is relative, remove the first segments that were added by
213                         // the java.io.File canonicalization
214                         // e.g. 'lib/classes.zip' was converted to
215                         // 'd:/myfolder/lib/classes.zip'
216                         int externalLength = externalPath.segmentCount();
217                         if (canonicalLength >= externalLength) {
218                                 result = canonicalPath.removeFirstSegments(canonicalLength
219                                                 - externalLength);
220                         } else {
221                                 if (JavaModelManager.VERBOSE) {
222                                         System.out
223                                                         .println("JAVA MODEL - Canonical path is original path (canonical path is " + canonicalPath.toString() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
224                                 }
225                                 return externalPath;
226                         }
227                 }
228
229                 // keep device only if it was specified (this is because
230                 // File.getCanonicalPath() converts '/lib/classed.zip' to
231                 // 'd:/lib/classes/zip')
232                 if (externalPath.getDevice() == null) {
233                         result = result.setDevice(null);
234                 }
235                 if (JavaModelManager.VERBOSE) {
236                         System.out
237                                         .println("JAVA MODEL - Canonical path is " + result.toString()); //$NON-NLS-1$
238                 }
239                 return result;
240         }
241
242         /**
243          * Constructor needed for <code>IProject.getNature()</code> and
244          * <code>IProject.addNature()</code>.
245          * 
246          * @see #setProject(IProject)
247          */
248         public JavaProject() {
249                 super(null, null);
250         }
251
252         public JavaProject(IProject project, JavaElement parent) {
253                 super(parent, project.getName());
254                 this.project = project;
255         }
256
257         public void addLoadPathEntry(IProject anotherPHPProject) {
258                 fScratched = true;
259
260                 LoadPathEntry newEntry = new LoadPathEntry(anotherPHPProject);
261                 getLoadPathEntries().add(newEntry);
262         }
263
264         public void configure() throws CoreException {
265                 // get project description and then the associated build commands
266                 IProjectDescription desc = project.getDescription();
267                 ICommand[] commands = desc.getBuildSpec();
268
269                 // determine if builder already associated
270                 boolean found = false;
271                 for (int i = 0; i < commands.length; ++i) {
272                         if (commands[i].getBuilderName().equals(
273                                         PHPeclipsePlugin.BUILDER_PARSER_ID)) {
274                                 found = true;
275                                 break;
276                         }
277                 }
278
279                 // add builder if not already in project
280                 if (!found) {
281                         ICommand command = desc.newCommand();
282                         command.setBuilderName(PHPeclipsePlugin.BUILDER_PARSER_ID);
283                         ICommand[] newCommands = new ICommand[commands.length + 1];
284
285                         // Add it before other builders.
286                         System.arraycopy(commands, 0, newCommands, 1, commands.length);
287                         newCommands[0] = command;
288                         desc.setBuildSpec(newCommands);
289                         project.setDescription(desc, null);
290                 }
291         }
292
293         protected void loadLoadPathEntries() {
294                 fLoadPathEntries = new ArrayList();
295
296                 IFile loadPathsFile = getLoadPathEntriesFile();
297
298                 XMLReader reader = null;
299                 try {
300                         reader = SAXParserFactory.newInstance().newSAXParser()
301                                         .getXMLReader();
302                         reader.setContentHandler(getLoadPathEntriesContentHandler());
303                         reader.parse(new InputSource(loadPathsFile.getContents()));
304                 } catch (Exception e) {
305                         // the file is nonextant or unreadable
306                 }
307         }
308
309         public List getLoadPathEntries() {
310                 if (fLoadPathEntries == null) {
311                         loadLoadPathEntries();
312                 }
313
314                 return fLoadPathEntries;
315         }
316
317         protected ContentHandler getLoadPathEntriesContentHandler() {
318                 return new ContentHandler() {
319                         public void characters(char[] arg0, int arg1, int arg2)
320                                         throws SAXException {
321                         }
322
323                         public void endDocument() throws SAXException {
324                         }
325
326                         public void endElement(String arg0, String arg1, String arg2)
327                                         throws SAXException {
328                         }
329
330                         public void endPrefixMapping(String arg0) throws SAXException {
331                         }
332
333                         public void ignorableWhitespace(char[] arg0, int arg1, int arg2)
334                                         throws SAXException {
335                         }
336
337                         public void processingInstruction(String arg0, String arg1)
338                                         throws SAXException {
339                         }
340
341                         public void setDocumentLocator(Locator arg0) {
342                         }
343
344                         public void skippedEntity(String arg0) throws SAXException {
345                         }
346
347                         public void startDocument() throws SAXException {
348                         }
349
350                         public void startElement(String namespaceURI, String localName,
351                                         String qName, Attributes atts) throws SAXException {
352                                 if ("pathentry".equals(qName))
353                                         if ("project".equals(atts.getValue("type"))) {
354                                                 IPath referencedProjectPath = new Path(atts
355                                                                 .getValue("path"));
356                                                 IProject referencedProject = getProject(referencedProjectPath
357                                                                 .lastSegment());
358                                                 fLoadPathEntries.add(new LoadPathEntry(
359                                                                 referencedProject));
360                                         }
361                         }
362
363                         public void startPrefixMapping(String arg0, String arg1)
364                                         throws SAXException {
365                         }
366                 };
367         }
368
369         protected IFile getLoadPathEntriesFile() {
370                 return project.getFile(".loadpath");
371         }
372
373         protected String getLoadPathXML() {
374                 StringBuffer buffer = new StringBuffer();
375                 buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><loadpath>");
376
377                 Iterator pathEntriesIterator = fLoadPathEntries.iterator();
378
379                 while (pathEntriesIterator.hasNext()) {
380                         LoadPathEntry entry = (LoadPathEntry) pathEntriesIterator.next();
381                         buffer.append(entry.toXML());
382                 }
383
384                 buffer.append("</loadpath>");
385                 return buffer.toString();
386         }
387
388         /**
389          * Adds a builder to the build spec for the given project.
390          */
391         protected void addToBuildSpec(String builderID) throws CoreException {
392
393                 IProjectDescription description = getProject().getDescription();
394                 ICommand javaCommand = getJavaCommand(description);
395
396                 if (javaCommand == null) {
397
398                         // Add a Java command to the build spec
399                         ICommand command = description.newCommand();
400                         command.setBuilderName(builderID);
401                         setJavaCommand(description, command);
402                 }
403         }
404
405         /**
406          * @see Openable
407          */
408         protected boolean buildStructure(OpenableElementInfo info,
409                         IProgressMonitor pm, Map newElements, IResource underlyingResource)
410                         throws JavaModelException {
411
412                 // check whether the java project can be opened
413                 if (!underlyingResource.isAccessible()) {
414                         throw newNotPresentException();
415                 }
416
417                 //IWorkspace workspace = ResourcesPlugin.getWorkspace();
418                 //IWorkspaceRoot wRoot = workspace.getRoot();
419                 // cannot refresh cp markers on opening (emulate cp check on startup)
420                 // since can create deadlocks (see bug 37274)
421                 // IClasspathEntry[] resolvedClasspath =
422                 // getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't
423                 // generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
424
425                 // // compute the pkg fragment roots
426                 // info.setChildren(computePackageFragmentRoots(resolvedClasspath,
427                 // false));
428                 //              
429                 // // remember the timestamps of external libraries the first time they
430                 // are looked up
431                 // for (int i = 0, length = resolvedClasspath.length; i < length; i++) {
432                 // IClasspathEntry entry = resolvedClasspath[i];
433                 // if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
434                 // IPath path = entry.getPath();
435                 // Object target = JavaModel.getTarget(wRoot, path, true);
436                 // if (target instanceof java.io.File) {
437                 // Map externalTimeStamps =
438                 // JavaModelManager.getJavaModelManager().deltaState.externalTimeStamps;
439                 // if (externalTimeStamps.get(path) == null) {
440                 // long timestamp = DeltaProcessor.getTimeStamp((java.io.File)target);
441                 // externalTimeStamps.put(path, new Long(timestamp));
442                 // }
443                 // }
444                 // }
445                 // }
446
447                 return true;
448         }
449
450         protected void closing(Object info) {
451
452                 // // forget source attachment recommendations
453                 // Object[] children = ((JavaElementInfo)info).children;
454                 // for (int i = 0, length = children.length; i < length; i++) {
455                 // Object child = children[i];
456                 // if (child instanceof JarPackageFragmentRoot){
457                 // ((JarPackageFragmentRoot)child).setSourceAttachmentProperty(null);
458                 // }
459                 // }
460
461                 super.closing(info);
462         }
463
464         // protected void closing(Object info) throws JavaModelException {
465         //              
466         // // forget source attachment recommendations
467         // IPackageFragmentRoot[] roots = this.getPackageFragmentRoots();
468         // // for (int i = 0; i < roots.length; i++) {
469         // // if (roots[i] instanceof JarPackageFragmentRoot){
470         // // ((JarPackageFragmentRoot) roots[i]).setSourceAttachmentProperty(null);
471         // // }
472         // // }
473         //              
474         // super.closing(info);
475         // }
476
477         /**
478          * Internal computation of an expanded classpath. It will eliminate
479          * duplicates, and produce copies of exported classpath entries to avoid
480          * possible side-effects ever after.
481          */
482         private void computeExpandedClasspath(JavaProject initialProject,
483                         boolean ignoreUnresolvedVariable, boolean generateMarkerOnError,
484                         HashSet rootIDs, ObjectVector accumulatedEntries,
485                         Map preferredClasspaths, Map preferredOutputs)
486                         throws JavaModelException {
487
488                 String projectRootId = this.rootID();
489                 if (rootIDs.contains(projectRootId)) {
490                         return; // break cycles if any
491                 }
492                 rootIDs.add(projectRootId);
493
494                 IClasspathEntry[] preferredClasspath = preferredClasspaths != null ? (IClasspathEntry[]) preferredClasspaths
495                                 .get(this)
496                                 : null;
497                 IPath preferredOutput = preferredOutputs != null ? (IPath) preferredOutputs
498                                 .get(this)
499                                 : null;
500                 IClasspathEntry[] immediateClasspath = preferredClasspath != null ? getResolvedClasspath(
501                                 preferredClasspath, preferredOutput, ignoreUnresolvedVariable,
502                                 generateMarkerOnError, null)
503                                 : getResolvedClasspath(ignoreUnresolvedVariable,
504                                                 generateMarkerOnError, false/*
505                                                                                                          * don't
506                                                                                                          * returnResolutionInProgress
507                                                                                                          */);
508
509                 IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
510                 boolean isInitialProject = this.equals(initialProject);
511                 for (int i = 0, length = immediateClasspath.length; i < length; i++) {
512                         ClasspathEntry entry = (ClasspathEntry) immediateClasspath[i];
513                         if (isInitialProject || entry.isExported()) {
514                                 String rootID = entry.rootID();
515                                 if (rootIDs.contains(rootID)) {
516                                         continue;
517                                 }
518
519                                 accumulatedEntries.add(entry);
520
521                                 // recurse in project to get all its indirect exports (only
522                                 // consider exported entries from there on)
523                                 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
524                                         IResource member = workspaceRoot
525                                                         .findMember(entry.getPath());
526                                         if (member != null && member.getType() == IResource.PROJECT) { // double
527                                                                                                                                                                         // check
528                                                                                                                                                                         // if
529                                                                                                                                                                         // bound
530                                                                                                                                                                         // to
531                                                                                                                                                                         // project
532                                                                                                                                                                         // (23977)
533                                                 IProject projRsc = (IProject) member;
534                                                 if (JavaProject.hasJavaNature(projRsc)) {
535                                                         JavaProject javaProject = (JavaProject) JavaCore
536                                                                         .create(projRsc);
537                                                         javaProject
538                                                                         .computeExpandedClasspath(
539                                                                                         initialProject,
540                                                                                         ignoreUnresolvedVariable,
541                                                                                         false /*
542                                                                                                          * no marker when recursing
543                                                                                                          * in prereq
544                                                                                                          */,
545                                                                                         rootIDs, accumulatedEntries,
546                                                                                         preferredClasspaths,
547                                                                                         preferredOutputs);
548                                                 }
549                                         }
550                                 } else {
551                                         rootIDs.add(rootID);
552                                 }
553                         }
554                 }
555         }
556
557         /**
558          * Internal computation of an expanded classpath. It will eliminate
559          * duplicates, and produce copies of exported classpath entries to avoid
560          * possible side-effects ever after.
561          */
562         // private void computeExpandedClasspath(
563         // JavaProject initialProject,
564         // boolean ignoreUnresolvedVariable,
565         // boolean generateMarkerOnError,
566         // HashSet visitedProjects,
567         // ObjectVector accumulatedEntries) throws JavaModelException {
568         //              
569         // if (visitedProjects.contains(this)){
570         // return; // break cycles if any
571         // }
572         // visitedProjects.add(this);
573         //
574         // if (generateMarkerOnError && !this.equals(initialProject)){
575         // generateMarkerOnError = false;
576         // }
577         // IClasspathEntry[] immediateClasspath =
578         // getResolvedClasspath(ignoreUnresolvedVariable, generateMarkerOnError);
579         //                      
580         // IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
581         // for (int i = 0, length = immediateClasspath.length; i < length; i++){
582         // IClasspathEntry entry = immediateClasspath[i];
583         //
584         // boolean isInitialProject = this.equals(initialProject);
585         // if (isInitialProject || entry.isExported()){
586         //                              
587         // accumulatedEntries.add(entry);
588         //                              
589         // // recurse in project to get all its indirect exports (only consider
590         // exported entries from there on)
591         // if (entry.getEntryKind() == ClasspathEntry.CPE_PROJECT) {
592         // IResource member = workspaceRoot.findMember(entry.getPath());
593         // if (member != null && member.getType() == IResource.PROJECT){ // double
594         // check if bound to project (23977)
595         // IProject projRsc = (IProject) member;
596         // if (JavaProject.hasJavaNature(projRsc)) {
597         // JavaProject project = (JavaProject) JavaCore.create(projRsc);
598         // project.computeExpandedClasspath(
599         // initialProject,
600         // ignoreUnresolvedVariable,
601         // generateMarkerOnError,
602         // visitedProjects,
603         // accumulatedEntries);
604         // }
605         // }
606         // }
607         // }
608         // }
609         // }
610         /**
611          * Returns (local/all) the package fragment roots identified by the given
612          * project's classpath. Note: this follows project classpath references to
613          * find required project contributions, eliminating duplicates silently.
614          * Only works with resolved entries
615          */
616         public IPackageFragmentRoot[] computePackageFragmentRoots(
617                         IClasspathEntry[] resolvedClasspath, boolean retrieveExportedRoots)
618                         throws JavaModelException {
619
620                 ObjectVector accumulatedRoots = new ObjectVector();
621                 computePackageFragmentRoots(resolvedClasspath, accumulatedRoots,
622                                 new HashSet(5), // rootIDs
623                                 true, // inside original project
624                                 true, // check existency
625                                 retrieveExportedRoots);
626                 IPackageFragmentRoot[] rootArray = new IPackageFragmentRoot[accumulatedRoots
627                                 .size()];
628                 accumulatedRoots.copyInto(rootArray);
629                 return rootArray;
630         }
631
632         /**
633          * Computes the package fragment roots identified by the given entry. Only
634          * works with resolved entry
635          */
636         public IPackageFragmentRoot[] computePackageFragmentRoots(
637                         IClasspathEntry resolvedEntry) {
638                 try {
639                         return computePackageFragmentRoots(
640                                         new IClasspathEntry[] { resolvedEntry }, false // don't
641                                                                                                                                         // retrieve
642                                                                                                                                         // exported
643                                                                                                                                         // roots
644                         );
645                 } catch (JavaModelException e) {
646                         return new IPackageFragmentRoot[] {};
647                 }
648         }
649
650         /**
651          * Returns the package fragment roots identified by the given entry. In case
652          * it refers to a project, it will follow its classpath so as to find
653          * exported roots as well. Only works with resolved entry
654          */
655         public void computePackageFragmentRoots(IClasspathEntry resolvedEntry,
656                         ObjectVector accumulatedRoots, HashSet rootIDs,
657                         boolean insideOriginalProject, boolean checkExistency,
658                         boolean retrieveExportedRoots) throws JavaModelException {
659
660                 String rootID = ((ClasspathEntry) resolvedEntry).rootID();
661                 if (rootIDs.contains(rootID))
662                         return;
663
664                 IPath projectPath = getProject().getFullPath();
665                 IPath entryPath = resolvedEntry.getPath();
666                 IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
667
668                 switch (resolvedEntry.getEntryKind()) {
669
670                 // source folder
671                 case IClasspathEntry.CPE_SOURCE:
672
673                         if (projectPath.isPrefixOf(entryPath)) {
674                                 if (checkExistency) {
675                                         Object target = JavaModel.getTarget(workspaceRoot,
676                                                         entryPath, checkExistency);
677                                         if (target == null)
678                                                 return;
679
680                                         if (target instanceof IFolder || target instanceof IProject) {
681                                                 accumulatedRoots
682                                                                 .add(getPackageFragmentRoot((IResource) target));
683                                                 rootIDs.add(rootID);
684                                         }
685                                 } else {
686                                         IPackageFragmentRoot root = getFolderPackageFragmentRoot(entryPath);
687                                         if (root != null) {
688                                                 accumulatedRoots.add(root);
689                                                 rootIDs.add(rootID);
690                                         }
691                                 }
692                         }
693                         break;
694
695                 // internal/external JAR or folder
696                 case IClasspathEntry.CPE_LIBRARY:
697
698                         if (!insideOriginalProject && !resolvedEntry.isExported())
699                                 return;
700
701                         if (checkExistency) {
702                                 Object target = JavaModel.getTarget(workspaceRoot, entryPath,
703                                                 checkExistency);
704                                 if (target == null)
705                                         return;
706
707                                 if (target instanceof IResource) {
708                                         // internal target
709                                         IResource resource = (IResource) target;
710                                         IPackageFragmentRoot root = getPackageFragmentRoot(resource);
711                                         if (root != null) {
712                                                 accumulatedRoots.add(root);
713                                                 rootIDs.add(rootID);
714                                         }
715                                 } else {
716                                         // external target - only JARs allowed
717                                         // if (((java.io.File)target).isFile() &&
718                                         // (ProjectPrefUtil.isArchiveFileName(entryPath.lastSegment())))
719                                         // {
720                                         // accumulatedRoots.add(
721                                         // new JarPackageFragmentRoot(entryPath, this));
722                                         // rootIDs.add(rootID);
723                                         // }
724                                 }
725                         } else {
726                                 IPackageFragmentRoot root = getPackageFragmentRoot(entryPath);
727                                 if (root != null) {
728                                         accumulatedRoots.add(root);
729                                         rootIDs.add(rootID);
730                                 }
731                         }
732                         break;
733
734                 // recurse into required project
735                 case IClasspathEntry.CPE_PROJECT:
736
737                         if (!retrieveExportedRoots)
738                                 return;
739                         if (!insideOriginalProject && !resolvedEntry.isExported())
740                                 return;
741
742                         IResource member = workspaceRoot.findMember(entryPath);
743                         if (member != null && member.getType() == IResource.PROJECT) {// double
744                                                                                                                                                         // check
745                                                                                                                                                         // if
746                                                                                                                                                         // bound
747                                                                                                                                                         // to
748                                                                                                                                                         // project
749                                                                                                                                                         // (23977)
750                                 IProject requiredProjectRsc = (IProject) member;
751                                 if (JavaProject.hasJavaNature(requiredProjectRsc)) { // special
752                                                                                                                                                 // builder
753                                                                                                                                                 // binary
754                                                                                                                                                 // output
755                                         rootIDs.add(rootID);
756                                         JavaProject requiredProject = (JavaProject) JavaCore
757                                                         .create(requiredProjectRsc);
758                                         requiredProject.computePackageFragmentRoots(requiredProject
759                                                         .getResolvedClasspath(true), accumulatedRoots,
760                                                         rootIDs, false, checkExistency,
761                                                         retrieveExportedRoots);
762                                 }
763                                 break;
764                         }
765                 }
766         }
767
768         /**
769          * Returns (local/all) the package fragment roots identified by the given
770          * project's classpath. Note: this follows project classpath references to
771          * find required project contributions, eliminating duplicates silently.
772          * Only works with resolved entries
773          */
774         public void computePackageFragmentRoots(
775                         IClasspathEntry[] resolvedClasspath, ObjectVector accumulatedRoots,
776                         HashSet rootIDs, boolean insideOriginalProject,
777                         boolean checkExistency, boolean retrieveExportedRoots)
778                         throws JavaModelException {
779
780                 if (insideOriginalProject) {
781                         rootIDs.add(rootID());
782                 }
783                 for (int i = 0, length = resolvedClasspath.length; i < length; i++) {
784                         computePackageFragmentRoots(resolvedClasspath[i], accumulatedRoots,
785                                         rootIDs, insideOriginalProject, checkExistency,
786                                         retrieveExportedRoots);
787                 }
788         }
789
790         /**
791          * Compute the file name to use for a given shared property
792          */
793         public String computeSharedPropertyFileName(QualifiedName qName) {
794
795                 return '.' + qName.getLocalName();
796         }
797
798         /*
799          * Returns whether the given resource is accessible through the children or
800          * the non-Java resources of this project. Returns true if the resource is
801          * not in the project. Assumes that the resource is a folder or a file.
802          */
803         public boolean contains(IResource resource) {
804
805                 IClasspathEntry[] classpath;
806                 IPath output;
807                 try {
808                         classpath = getResolvedClasspath(true);
809                         output = getOutputLocation();
810                 } catch (JavaModelException e) {
811                         return false;
812                 }
813
814                 IPath fullPath = resource.getFullPath();
815                 IPath innerMostOutput = output.isPrefixOf(fullPath) ? output : null;
816                 IClasspathEntry innerMostEntry = null;
817                 for (int j = 0, cpLength = classpath.length; j < cpLength; j++) {
818                         IClasspathEntry entry = classpath[j];
819
820                         IPath entryPath = entry.getPath();
821                         if ((innerMostEntry == null || innerMostEntry.getPath().isPrefixOf(
822                                         entryPath))
823                                         && entryPath.isPrefixOf(fullPath)) {
824                                 innerMostEntry = entry;
825                         }
826                         IPath entryOutput = classpath[j].getOutputLocation();
827                         if (entryOutput != null && entryOutput.isPrefixOf(fullPath)) {
828                                 innerMostOutput = entryOutput;
829                         }
830                 }
831                 if (innerMostEntry != null) {
832                         // special case prj==src and nested output location
833                         if (innerMostOutput != null && innerMostOutput.segmentCount() > 1 // output
834                                                                                                                                                                 // isn't
835                                                                                                                                                                 // project
836                                         && innerMostEntry.getPath().segmentCount() == 1) { // 1
837                                                                                                                                                 // segment
838                                                                                                                                                 // must
839                                                                                                                                                 // be
840                                                                                                                                                 // project
841                                                                                                                                                 // name
842                                 return false;
843                         }
844                         if (resource instanceof IFolder) {
845                                 // folders are always included in src/lib entries
846                                 return true;
847                         }
848                         switch (innerMostEntry.getEntryKind()) {
849                         case IClasspathEntry.CPE_SOURCE:
850                                 // .class files are not visible in source folders
851                                 return true; // !net.sourceforge.phpdt.internal.compiler.util.ProjectPrefUtil.isClassFileName(fullPath.lastSegment());
852                         case IClasspathEntry.CPE_LIBRARY:
853                                 // .java files are not visible in library folders
854                                 return !net.sourceforge.phpdt.internal.compiler.util.Util
855                                                 .isJavaFileName(fullPath.lastSegment());
856                         }
857                 }
858                 if (innerMostOutput != null) {
859                         return false;
860                 }
861                 return true;
862         }
863
864         /**
865          * Record a new marker denoting a classpath problem
866          */
867         IMarker createClasspathProblemMarker(IJavaModelStatus status) {
868
869                 IMarker marker = null;
870                 int severity;
871                 String[] arguments = new String[0];
872                 boolean isCycleProblem = false, isClasspathFileFormatProblem = false;
873                 switch (status.getCode()) {
874
875                 case IJavaModelStatusConstants.CLASSPATH_CYCLE:
876                         isCycleProblem = true;
877                         if (JavaCore.ERROR.equals(getOption(
878                                         JavaCore.CORE_CIRCULAR_CLASSPATH, true))) {
879                                 severity = IMarker.SEVERITY_ERROR;
880                         } else {
881                                 severity = IMarker.SEVERITY_WARNING;
882                         }
883                         break;
884
885                 case IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT:
886                         isClasspathFileFormatProblem = true;
887                         severity = IMarker.SEVERITY_ERROR;
888                         break;
889
890                 default:
891                         IPath path = status.getPath();
892                         if (path != null)
893                                 arguments = new String[] { path.toString() };
894                         if (JavaCore.ERROR.equals(getOption(
895                                         JavaCore.CORE_INCOMPLETE_CLASSPATH, true))) {
896                                 severity = IMarker.SEVERITY_ERROR;
897                         } else {
898                                 severity = IMarker.SEVERITY_WARNING;
899                         }
900                         break;
901                 }
902
903                 try {
904                         marker = getProject().createMarker(
905                                         IJavaModelMarker.BUILDPATH_PROBLEM_MARKER);
906                         marker.setAttributes(new String[] { IMarker.MESSAGE,
907                                         IMarker.SEVERITY, IMarker.LOCATION,
908                                         IJavaModelMarker.CYCLE_DETECTED,
909                                         IJavaModelMarker.CLASSPATH_FILE_FORMAT,
910                                         IJavaModelMarker.ID, IJavaModelMarker.ARGUMENTS, },
911                                         new Object[] { status.getMessage(),
912                                                         new Integer(severity),
913                                                         Util.bind("classpath.buildPath"),//$NON-NLS-1$
914                                                         isCycleProblem ? "true" : "false",//$NON-NLS-1$ //$NON-NLS-2$
915                                                         isClasspathFileFormatProblem ? "true" : "false",//$NON-NLS-1$ //$NON-NLS-2$
916                                                         new Integer(status.getCode()),
917                                                         Util.getProblemArgumentsForMarker(arguments), });
918                 } catch (CoreException e) {
919                 }
920                 return marker;
921         }
922
923         /**
924          * Returns a new element info for this element.
925          */
926         protected Object createElementInfo() {
927                 return new JavaProjectElementInfo();
928         }
929
930         /*
931          * Returns a new search name environment for this project. This name
932          * environment first looks in the given working copies.
933          */
934         // public ISearchableNameEnvironment
935         // newSearchableNameEnvironment(ICompilationUnit[] workingCopies) throws
936         // JavaModelException {
937         // return new SearchableEnvironment(this, workingCopies);
938         // }
939         /*
940          * Returns a new search name environment for this project. This name
941          * environment first looks in the working copies of the given owner.
942          */
943         public ISearchableNameEnvironment newSearchableNameEnvironment(
944                         WorkingCopyOwner owner) throws JavaModelException {
945                 return new SearchableEnvironment(this, owner);
946         }
947
948         /**
949          * Reads and decode an XML classpath string
950          */
951         protected IClasspathEntry[] decodeClasspath(String xmlClasspath,
952                         boolean createMarker, boolean logProblems) {
953
954                 ArrayList paths = new ArrayList();
955                 IClasspathEntry defaultOutput = null;
956                 try {
957                         if (xmlClasspath == null)
958                                 return null;
959                         StringReader reader = new StringReader(xmlClasspath);
960                         Element cpElement;
961
962                         try {
963                                 DocumentBuilder parser = DocumentBuilderFactory.newInstance()
964                                                 .newDocumentBuilder();
965                                 cpElement = parser.parse(new InputSource(reader))
966                                                 .getDocumentElement();
967                         } catch (SAXException e) {
968                                 throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$
969                         } catch (ParserConfigurationException e) {
970                                 throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$
971                         } finally {
972                                 reader.close();
973                         }
974
975                         if (!cpElement.getNodeName().equalsIgnoreCase("classpath")) { //$NON-NLS-1$
976                                 throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$
977                         }
978                         NodeList list = cpElement.getElementsByTagName("classpathentry"); //$NON-NLS-1$
979                         int length = list.getLength();
980
981                         for (int i = 0; i < length; ++i) {
982                                 Node node = list.item(i);
983                                 if (node.getNodeType() == Node.ELEMENT_NODE) {
984                                         IClasspathEntry entry = ClasspathEntry.elementDecode(
985                                                         (Element) node, this);
986                                         if (entry != null) {
987                                                 if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
988                                                         defaultOutput = entry; // separate output
989                                                 } else {
990                                                         paths.add(entry);
991                                                 }
992                                         }
993                                 }
994                         }
995                 } catch (IOException e) {
996                         // bad format
997                         if (createMarker && this.getProject().isAccessible()) {
998                                 this
999                                                 .createClasspathProblemMarker(new JavaModelStatus(
1000                                                                 IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
1001                                                                 Util
1002                                                                                 .bind(
1003                                                                                                 "classpath.xmlFormatError", this.getElementName(), e.getMessage()))); //$NON-NLS-1$
1004                         }
1005                         if (logProblems) {
1006                                 Util.log(e, "Exception while retrieving " + this.getPath() //$NON-NLS-1$
1007                                                 + "/.classpath, will mark classpath as invalid"); //$NON-NLS-1$
1008                         }
1009                         return INVALID_CLASSPATH;
1010                 } catch (Assert.AssertionFailedException e) {
1011                         // failed creating CP entries from file
1012                         if (createMarker && this.getProject().isAccessible()) {
1013                                 this
1014                                                 .createClasspathProblemMarker(new JavaModelStatus(
1015                                                                 IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
1016                                                                 Util
1017                                                                                 .bind(
1018                                                                                                 "classpath.illegalEntryInClasspathFile", this.getElementName(), e.getMessage()))); //$NON-NLS-1$
1019                         }
1020                         if (logProblems) {
1021                                 Util.log(e, "Exception while retrieving " + this.getPath() //$NON-NLS-1$
1022                                                 + "/.classpath, will mark classpath as invalid"); //$NON-NLS-1$
1023                         }
1024                         return INVALID_CLASSPATH;
1025                 }
1026                 int pathSize = paths.size();
1027                 if (pathSize > 0 || defaultOutput != null) {
1028                         IClasspathEntry[] entries = new IClasspathEntry[pathSize
1029                                         + (defaultOutput == null ? 0 : 1)];
1030                         paths.toArray(entries);
1031                         if (defaultOutput != null)
1032                                 entries[pathSize] = defaultOutput; // ensure output is last
1033                                                                                                         // item
1034                         return entries;
1035                 } else {
1036                         return null;
1037                 }
1038         }
1039
1040         /**
1041          * /** Removes the Java nature from the project.
1042          */
1043         public void deconfigure() throws CoreException {
1044
1045                 // deregister Java builder
1046                 removeFromBuildSpec(PHPeclipsePlugin.BUILDER_PARSER_ID);
1047         }
1048
1049         /**
1050          * Returns a default class path. This is the root of the project
1051          */
1052         protected IClasspathEntry[] defaultClasspath() throws JavaModelException {
1053
1054                 return new IClasspathEntry[] { JavaCore.newSourceEntry(getProject()
1055                                 .getFullPath()) };
1056         }
1057
1058         /**
1059          * Returns a default output location. This is the project bin folder
1060          */
1061         protected IPath defaultOutputLocation() throws JavaModelException {
1062                 return null; // getProject().getFullPath().append("bin");
1063                                                 // //$NON-NLS-1$
1064         }
1065
1066         /**
1067          * Returns the XML String encoding of the class path.
1068          */
1069         protected String encodeClasspath(IClasspathEntry[] classpath,
1070                         IPath outputLocation, boolean indent) throws JavaModelException {
1071                 try {
1072                         ByteArrayOutputStream s = new ByteArrayOutputStream();
1073                         OutputStreamWriter writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
1074                         XMLWriter xmlWriter = new XMLWriter(writer);
1075
1076                         xmlWriter.startTag("classpath", indent); //$NON-NLS-1$
1077                         for (int i = 0; i < classpath.length; ++i) {
1078                                 ((ClasspathEntry) classpath[i]).elementEncode(xmlWriter,
1079                                                 this.project.getFullPath(), indent, true);
1080                         }
1081
1082                         if (outputLocation != null) {
1083                                 outputLocation = outputLocation.removeFirstSegments(1);
1084                                 outputLocation = outputLocation.makeRelative();
1085                                 HashMap parameters = new HashMap();
1086                                 parameters
1087                                                 .put(
1088                                                                 "kind", ClasspathEntry.kindToString(ClasspathEntry.K_OUTPUT));//$NON-NLS-1$
1089                                 parameters.put("path", String.valueOf(outputLocation));//$NON-NLS-1$
1090                                 xmlWriter.printTag(
1091                                                 "classpathentry", parameters, indent, true, true);//$NON-NLS-1$
1092                         }
1093
1094                         xmlWriter.endTag("classpath", indent);//$NON-NLS-1$
1095                         writer.flush();
1096                         writer.close();
1097                         return s.toString("UTF8");//$NON-NLS-1$
1098                 } catch (IOException e) {
1099                         throw new JavaModelException(e,
1100                                         IJavaModelStatusConstants.IO_EXCEPTION);
1101                 }
1102         }
1103
1104         /**
1105          * Returns the XML String encoding of the class path.
1106          */
1107         // protected String encodeClasspath(IClasspathEntry[] classpath, IPath
1108         // outputLocation, boolean useLineSeparator) throws JavaModelException {
1109         //
1110         // Document document = new DocumentImpl();
1111         // Element cpElement = document.createElement("classpath"); //$NON-NLS-1$
1112         // document.appendChild(cpElement);
1113         //
1114         // for (int i = 0; i < classpath.length; ++i) {
1115         // cpElement.appendChild(((ClasspathEntry)classpath[i]).elementEncode(document,
1116         // getProject().getFullPath()));
1117         // }
1118         //
1119         // if (outputLocation != null) {
1120         // outputLocation = outputLocation.removeFirstSegments(1);
1121         // outputLocation = outputLocation.makeRelative();
1122         // Element oElement = document.createElement("classpathentry");
1123         // //$NON-NLS-1$
1124         // oElement.setAttribute("kind",
1125         // ClasspathEntry.kindToString(ClasspathEntry.K_OUTPUT)); //$NON-NLS-1$
1126         // oElement.setAttribute("path", outputLocation.toString()); //$NON-NLS-1$
1127         // cpElement.appendChild(oElement);
1128         // }
1129         //
1130         // // produce a String output
1131         // try {
1132         // ByteArrayOutputStream s = new ByteArrayOutputStream();
1133         // OutputFormat format = new OutputFormat();
1134         // if (useLineSeparator) {
1135         // format.setIndenting(true);
1136         // format.setLineSeparator(System.getProperty("line.separator"));
1137         // //$NON-NLS-1$
1138         // } else {
1139         // format.setPreserveSpace(true);
1140         // }
1141         // Serializer serializer =
1142         // SerializerFactory.getSerializerFactory(Method.XML).makeSerializer(
1143         // new OutputStreamWriter(s, "UTF8"), //$NON-NLS-1$
1144         // format);
1145         // serializer.asDOMSerializer().serialize(document);
1146         // return s.toString("UTF8"); //$NON-NLS-1$
1147         // } catch (IOException e) {
1148         // throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
1149         // }
1150         // }
1151         /**
1152          * Returns true if this handle represents the same Java project as the given
1153          * handle. Two handles represent the same project if they are identical or
1154          * if they represent a project with the same underlying resource and
1155          * occurrence counts.
1156          * 
1157          * @see JavaElement#equals
1158          */
1159         public boolean equals(Object o) {
1160
1161                 if (this == o)
1162                         return true;
1163
1164                 if (!(o instanceof JavaProject))
1165                         return false;
1166
1167                 JavaProject other = (JavaProject) o;
1168                 return getProject().equals(other.getProject())
1169                                 && occurrenceCount == other.occurrenceCount;
1170         }
1171
1172         public boolean exists() {
1173                 if (!hasJavaNature(project))
1174                         return false;
1175                 return super.exists();
1176         }
1177
1178         /**
1179          * @see IJavaProject
1180          */
1181         public IJavaElement findElement(IPath path) throws JavaModelException {
1182
1183                 if (path == null || path.isAbsolute()) {
1184                         throw new JavaModelException(new JavaModelStatus(
1185                                         IJavaModelStatusConstants.INVALID_PATH, path));
1186                 }
1187                 // try {
1188
1189                 String extension = path.getFileExtension();
1190                 if (extension == null) {
1191                         //String packageName = path.toString().replace(IPath.SEPARATOR, '.');
1192
1193                         // IPackageFragment[] pkgFragments =
1194                         // getNameLookup().findPackageFragments(packageName, false);
1195                         // if (pkgFragments == null) {
1196                         return null;
1197
1198                         // } else {
1199                         // // try to return one that is a child of this project
1200                         // for (int i = 0, length = pkgFragments.length; i < length; i++) {
1201                         //
1202                         // IPackageFragment pkgFragment = pkgFragments[i];
1203                         // if (this.equals(pkgFragment.getParent().getParent())) {
1204                         // return pkgFragment;
1205                         // }
1206                         // }
1207                         // // default to the first one
1208                         // return pkgFragments[0];
1209                         // }
1210                 } else if (extension.equalsIgnoreCase("java") //$NON-NLS-1$
1211                                 || extension.equalsIgnoreCase("class")) { //$NON-NLS-1$
1212                         IPath packagePath = path.removeLastSegments(1);
1213                         String packageName = packagePath.toString().replace(
1214                                         IPath.SEPARATOR, '.');
1215                         String typeName = path.lastSegment();
1216                         typeName = typeName.substring(0, typeName.length()
1217                                         - extension.length() - 1);
1218                         String qualifiedName = null;
1219                         if (packageName.length() > 0) {
1220                                 qualifiedName = packageName + "." + typeName; //$NON-NLS-1$
1221                         } else {
1222                                 qualifiedName = typeName;
1223                         }
1224                         // IType type =
1225                         // getNameLookup().findType(
1226                         // qualifiedName,
1227                         // false,
1228                         // NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
1229                         // if (type != null) {
1230                         // return type.getParent();
1231                         // } else {
1232                         return null;
1233                         // }
1234                 } else {
1235                         // unsupported extension
1236                         return null;
1237                 }
1238                 // } catch (JavaModelException e) {
1239                 // if (e.getStatus().getCode()
1240                 // == IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST) {
1241                 // return null;
1242                 // } else {
1243                 // throw e;
1244                 // }
1245                 // }
1246         }
1247
1248         /**
1249          * @see IJavaProject
1250          */
1251         // public IPackageFragment findPackageFragment(IPath path)
1252         // throws JavaModelException {
1253         //
1254         // return findPackageFragment0(JavaProject.canonicalizedPath(path));
1255         // }
1256         //
1257         // /**
1258         // * non path canonicalizing version
1259         // */
1260         // public IPackageFragment findPackageFragment0(IPath path)
1261         // throws JavaModelException {
1262         //
1263         // return getNameLookup().findPackageFragment(path);
1264         // }
1265         /**
1266          * @see IJavaProject
1267          */
1268         public IPackageFragmentRoot findPackageFragmentRoot(IPath path)
1269                         throws JavaModelException {
1270
1271                 return findPackageFragmentRoot0(JavaProject.canonicalizedPath(path));
1272         }
1273
1274         /**
1275          * no path canonicalization
1276          */
1277         public IPackageFragmentRoot findPackageFragmentRoot0(IPath path)
1278                         throws JavaModelException {
1279
1280                 IPackageFragmentRoot[] allRoots = this.getAllPackageFragmentRoots();
1281                 if (!path.isAbsolute()) {
1282                         throw new IllegalArgumentException(Util.bind("path.mustBeAbsolute")); //$NON-NLS-1$
1283                 }
1284                 for (int i = 0; i < allRoots.length; i++) {
1285                         IPackageFragmentRoot classpathRoot = allRoots[i];
1286                         if (classpathRoot.getPath().equals(path)) {
1287                                 return classpathRoot;
1288                         }
1289                 }
1290                 return null;
1291         }
1292
1293         /**
1294          * @see IJavaProject
1295          */
1296         public IPackageFragmentRoot[] findPackageFragmentRoots(IClasspathEntry entry) {
1297                 try {
1298                         IClasspathEntry[] classpath = this.getRawClasspath();
1299                         for (int i = 0, length = classpath.length; i < length; i++) {
1300                                 if (classpath[i].equals(entry)) { // entry may need to be
1301                                                                                                         // resolved
1302                                         return computePackageFragmentRoots(getResolvedClasspath(
1303                                                         new IClasspathEntry[] { entry }, null, true, false,
1304                                                         null/* no reverse map */), false); // don't
1305                                                                                                                                 // retrieve
1306                                                                                                                                 // exported
1307                                                                                                                                 // roots
1308                                 }
1309                         }
1310                 } catch (JavaModelException e) {
1311                 }
1312                 return new IPackageFragmentRoot[] {};
1313         }
1314
1315         /**
1316          * @see IJavaProject#findType(String)
1317          */
1318         // public IType findType(String fullyQualifiedName) throws
1319         // JavaModelException {
1320         // IType type =
1321         // this.getNameLookup().findType(
1322         // fullyQualifiedName,
1323         // false,
1324         // NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
1325         // if (type == null) {
1326         // // try to find enclosing type
1327         // int lastDot = fullyQualifiedName.lastIndexOf('.');
1328         // if (lastDot == -1) return null;
1329         // type = this.findType(fullyQualifiedName.substring(0, lastDot));
1330         // if (type != null) {
1331         // type = type.getType(fullyQualifiedName.substring(lastDot+1));
1332         // if (!type.exists()) {
1333         // return null;
1334         // }
1335         // }
1336         // }
1337         // return type;
1338         // }
1339         /**
1340          * @see IJavaProject#findType(String, String)
1341          */
1342         // public IType findType(String packageName, String typeQualifiedName)
1343         // throws JavaModelException {
1344         // return
1345         // this.getNameLookup().findType(
1346         // typeQualifiedName,
1347         // packageName,
1348         // false,
1349         // NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
1350         // }
1351         //      
1352         /**
1353          * Remove all markers denoting classpath problems
1354          */
1355         protected void flushClasspathProblemMarkers(boolean flushCycleMarkers,
1356                         boolean flushClasspathFormatMarkers) {
1357                 try {
1358                         IProject project = getProject();
1359                         if (project.exists()) {
1360                                 IMarker[] markers = project.findMarkers(
1361                                                 IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false,
1362                                                 IResource.DEPTH_ZERO);
1363                                 for (int i = 0, length = markers.length; i < length; i++) {
1364                                         IMarker marker = markers[i];
1365                                         if (flushCycleMarkers && flushClasspathFormatMarkers) {
1366                                                 marker.delete();
1367                                         } else {
1368                                                 String cycleAttr = (String) marker
1369                                                                 .getAttribute(IJavaModelMarker.CYCLE_DETECTED);
1370                                                 String classpathFileFormatAttr = (String) marker
1371                                                                 .getAttribute(IJavaModelMarker.CLASSPATH_FILE_FORMAT);
1372                                                 if ((flushCycleMarkers == (cycleAttr != null && cycleAttr
1373                                                                 .equals("true"))) //$NON-NLS-1$
1374                                                                 && (flushClasspathFormatMarkers == (classpathFileFormatAttr != null && classpathFileFormatAttr
1375                                                                                 .equals("true")))) { //$NON-NLS-1$
1376                                                         marker.delete();
1377                                                 }
1378                                         }
1379                                 }
1380                         }
1381                 } catch (CoreException e) {
1382                 }
1383         }
1384
1385         // /**
1386         // * @see Openable
1387         // */
1388         // protected boolean generateInfos(
1389         // OpenableElementInfo info,
1390         // IProgressMonitor pm,
1391         // Map newElements,
1392         // IResource underlyingResource) throws JavaModelException {
1393         //
1394         // boolean validInfo = false;
1395         // try {
1396         // if (getProject().isOpen()) {
1397         // // put the info now, because computing the roots requires it
1398         // JavaModelManager.getJavaModelManager().putInfo(this, info);
1399         //
1400         // // compute the pkg fragment roots
1401         // updatePackageFragmentRoots();
1402         //      
1403         // // remember the timestamps of external libraries the first time they are
1404         // looked up
1405         // IClasspathEntry[] resolvedClasspath = getResolvedClasspath(true/*ignore
1406         // unresolved variable*/);
1407         // for (int i = 0, length = resolvedClasspath.length; i < length; i++) {
1408         // IClasspathEntry entry = resolvedClasspath[i];
1409         // if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
1410         // IPath path = entry.getPath();
1411         // Object target =
1412         // JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), path,
1413         // true);
1414         // if (target instanceof java.io.File) {
1415         // Map externalTimeStamps =
1416         // JavaModelManager.getJavaModelManager().deltaProcessor.externalTimeStamps;
1417         // if (externalTimeStamps.get(path) == null) {
1418         // long timestamp = DeltaProcessor.getTimeStamp((java.io.File)target);
1419         // externalTimeStamps.put(path, new Long(timestamp));
1420         // }
1421         // }
1422         // }
1423         // }
1424         //
1425         // // only valid if reaches here
1426         // validInfo = true;
1427         // }
1428         // } finally {
1429         // if (!validInfo)
1430         // JavaModelManager.getJavaModelManager().removeInfo(this);
1431         // }
1432         // return validInfo;
1433         // }
1434
1435         /**
1436          * @see IJavaProject
1437          */
1438         public IPackageFragmentRoot[] getAllPackageFragmentRoots()
1439                         throws JavaModelException {
1440
1441                 return computePackageFragmentRoots(getResolvedClasspath(true), true);
1442         }
1443
1444         /**
1445          * Returns the classpath entry that refers to the given path or
1446          * <code>null</code> if there is no reference to the path.
1447          */
1448         public IClasspathEntry getClasspathEntryFor(IPath path)
1449                         throws JavaModelException {
1450
1451                 IClasspathEntry[] entries = getExpandedClasspath(true);
1452                 for (int i = 0; i < entries.length; i++) {
1453                         if (entries[i].getPath().equals(path)) {
1454                                 return entries[i];
1455                         }
1456                 }
1457                 return null;
1458         }
1459
1460         /*
1461          * Returns the cycle marker associated with this project or null if none.
1462          */
1463         public IMarker getCycleMarker() {
1464                 try {
1465                         IProject project = getProject();
1466                         if (project.exists()) {
1467                                 IMarker[] markers = project.findMarkers(
1468                                                 IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false,
1469                                                 IResource.DEPTH_ZERO);
1470                                 for (int i = 0, length = markers.length; i < length; i++) {
1471                                         IMarker marker = markers[i];
1472                                         String cycleAttr = (String) marker
1473                                                         .getAttribute(IJavaModelMarker.CYCLE_DETECTED);
1474                                         if (cycleAttr != null && cycleAttr.equals("true")) { //$NON-NLS-1$
1475                                                 return marker;
1476                                         }
1477                                 }
1478                         }
1479                 } catch (CoreException e) {
1480                 }
1481                 return null;
1482         }
1483
1484         /**
1485          * @see IJavaElement
1486          */
1487         public int getElementType() {
1488                 return JAVA_PROJECT;
1489         }
1490
1491         /**
1492          * This is a helper method returning the expanded classpath for the project,
1493          * as a list of classpath entries, where all classpath variable entries have
1494          * been resolved and substituted with their final target entries. All
1495          * project exports have been appended to project entries.
1496          * 
1497          * @param ignoreUnresolvedVariable
1498          *            boolean
1499          * @return IClasspathEntry[]
1500          * @throws JavaModelException
1501          */
1502         public IClasspathEntry[] getExpandedClasspath(
1503                         boolean ignoreUnresolvedVariable) throws JavaModelException {
1504
1505                 return getExpandedClasspath(ignoreUnresolvedVariable,
1506                                 false/* don't create markers */, null, null);
1507         }
1508
1509         /*
1510          * @see JavaElement
1511          */
1512         public IJavaElement getHandleFromMemento(String token,
1513                         MementoTokenizer memento, WorkingCopyOwner owner) {
1514                 switch (token.charAt(0)) {
1515                 case JEM_COUNT:
1516                         return getHandleUpdatingCountFromMemento(memento, owner);
1517                 case JEM_PACKAGEFRAGMENTROOT:
1518                         String rootPath = IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH;
1519                         token = null;
1520                         while (memento.hasMoreTokens()) {
1521                                 token = memento.nextToken();
1522                                 char firstChar = token.charAt(0);
1523                                 if (firstChar != JEM_PACKAGEFRAGMENT && firstChar != JEM_COUNT) {
1524                                         rootPath += token;
1525                                 } else {
1526                                         break;
1527                                 }
1528                         }
1529                         JavaElement root = (JavaElement) getPackageFragmentRoot(new Path(
1530                                         rootPath));
1531                         if (token != null && token.charAt(0) == JEM_PACKAGEFRAGMENT) {
1532                                 return root.getHandleFromMemento(token, memento, owner);
1533                         } else {
1534                                 return root.getHandleFromMemento(memento, owner);
1535                         }
1536                 }
1537                 return null;
1538         }
1539
1540         /**
1541          * Returns the <code>char</code> that marks the start of this handles
1542          * contribution to a memento.
1543          */
1544         protected char getHandleMementoDelimiter() {
1545
1546                 return JEM_JAVAPROJECT;
1547         }
1548
1549         /**
1550          * Internal variant which can create marker on project for invalid entries,
1551          * it will also perform classpath expansion in presence of project
1552          * prerequisites exporting their entries.
1553          * 
1554          * @param ignoreUnresolvedVariable
1555          *            boolean
1556          * @param generateMarkerOnError
1557          *            boolean
1558          * @param preferredClasspaths
1559          *            Map
1560          * @param preferredOutputs
1561          *            Map
1562          * @return IClasspathEntry[]
1563          * @throws JavaModelException
1564          */
1565         public IClasspathEntry[] getExpandedClasspath(
1566                         boolean ignoreUnresolvedVariable, boolean generateMarkerOnError,
1567                         Map preferredClasspaths, Map preferredOutputs)
1568                         throws JavaModelException {
1569
1570                 ObjectVector accumulatedEntries = new ObjectVector();
1571                 computeExpandedClasspath(this, ignoreUnresolvedVariable,
1572                                 generateMarkerOnError, new HashSet(5), accumulatedEntries,
1573                                 preferredClasspaths, preferredOutputs);
1574
1575                 IClasspathEntry[] expandedPath = new IClasspathEntry[accumulatedEntries
1576                                 .size()];
1577                 accumulatedEntries.copyInto(expandedPath);
1578
1579                 return expandedPath;
1580         }
1581
1582         // /**
1583         // * Internal variant which can create marker on project for invalid
1584         // entries,
1585         // * it will also perform classpath expansion in presence of project
1586         // prerequisites
1587         // * exporting their entries.
1588         // */
1589         // public IClasspathEntry[] getExpandedClasspath(
1590         // boolean ignoreUnresolvedVariable,
1591         // boolean generateMarkerOnError) throws JavaModelException {
1592         //      
1593         // ObjectVector accumulatedEntries = new ObjectVector();
1594         // computeExpandedClasspath(this, ignoreUnresolvedVariable,
1595         // generateMarkerOnError, new HashSet(5), accumulatedEntries);
1596         //              
1597         // IClasspathEntry[] expandedPath = new
1598         // IClasspathEntry[accumulatedEntries.size()];
1599         // accumulatedEntries.copyInto(expandedPath);
1600         //
1601         // return expandedPath;
1602         // }
1603
1604         /**
1605          * Find the specific Java command amongst the build spec of a given
1606          * description
1607          */
1608         private ICommand getJavaCommand(IProjectDescription description)
1609                         throws CoreException {
1610
1611                 ICommand[] commands = description.getBuildSpec();
1612                 for (int i = 0; i < commands.length; ++i) {
1613                         if (commands[i].getBuilderName().equals(
1614                                         PHPeclipsePlugin.BUILDER_PARSER_ID)) {
1615                                 return commands[i];
1616                         }
1617                 }
1618                 return null;
1619         }
1620
1621         /**
1622          * Convenience method that returns the specific type of info for a Java
1623          * project.
1624          */
1625         protected JavaProjectElementInfo getJavaProjectElementInfo()
1626                         throws JavaModelException {
1627
1628                 return (JavaProjectElementInfo) getElementInfo();
1629         }
1630
1631         /**
1632          * @see IJavaProject
1633          */
1634         public NameLookup getNameLookup() throws JavaModelException {
1635
1636                 JavaProjectElementInfo info = getJavaProjectElementInfo();
1637                 // lock on the project info to avoid race condition
1638                 synchronized (info) {
1639                         NameLookup nameLookup;
1640                         if ((nameLookup = info.getNameLookup()) == null) {
1641                                 info.setNameLookup(nameLookup = new NameLookup(this));
1642                         }
1643                         return nameLookup;
1644                 }
1645         }
1646
1647         /*
1648          * Returns a new name lookup. This name lookup first looks in the given
1649          * working copies.
1650          */
1651         public NameLookup newNameLookup(ICompilationUnit[] workingCopies)
1652                         throws JavaModelException {
1653
1654                 //JavaProjectElementInfo info = getJavaProjectElementInfo();
1655                 // lock on the project info to avoid race condition while computing the
1656                 // pkg fragment roots and package fragment caches
1657                 // synchronized(info){
1658                 // return new NameLookup(info.getAllPackageFragmentRoots(this),
1659                 // info.getAllPackageFragments(this), workingCopies);
1660                 // }
1661                 return null;
1662         }
1663
1664         /*
1665          * Returns a new name lookup. This name lookup first looks in the working
1666          * copies of the given owner.
1667          */
1668         public NameLookup newNameLookup(WorkingCopyOwner owner)
1669                         throws JavaModelException {
1670
1671                 JavaModelManager manager = JavaModelManager.getJavaModelManager();
1672                 ICompilationUnit[] workingCopies = owner == null ? null : manager
1673                                 .getWorkingCopies(owner, true/* add primary WCs */);
1674                 return newNameLookup(workingCopies);
1675         }
1676
1677         //
1678         // /**
1679         // * Returns an array of non-java resources contained in the receiver.
1680         // */
1681         // public Object[] getNonJavaResources() throws JavaModelException {
1682         //
1683         // return ((JavaProjectElementInfo)
1684         // getElementInfo()).getNonJavaResources(this);
1685         // }
1686
1687         /**
1688          * @see net.sourceforge.phpdt.core.IJavaProject#getOption(String, boolean)
1689          */
1690         public String getOption(String optionName, boolean inheritJavaCoreOptions) {
1691
1692                 if (JavaModelManager.OptionNames.contains(optionName)) {
1693
1694                         Preferences preferences = getPreferences();
1695                         if (preferences == null || preferences.isDefault(optionName)) {
1696                                 return inheritJavaCoreOptions ? JavaCore.getOption(optionName)
1697                                                 : null;
1698                         }
1699                         return preferences.getString(optionName).trim();
1700                 }
1701                 return null;
1702         }
1703
1704         /**
1705          * @see net.sourceforge.phpdt.core.IJavaProject#getOptions(boolean)
1706          */
1707         public Map getOptions(boolean inheritJavaCoreOptions) {
1708
1709                 // initialize to the defaults from JavaCore options pool
1710                 Map options = inheritJavaCoreOptions ? JavaCore.getOptions()
1711                                 : new Hashtable(5);
1712
1713                 Preferences preferences = getPreferences();
1714                 if (preferences == null)
1715                         return options; // cannot do better (non-Java project)
1716                 HashSet optionNames = JavaModelManager.OptionNames;
1717
1718                 // get preferences set to their default
1719                 if (inheritJavaCoreOptions) {
1720                         String[] defaultPropertyNames = preferences.defaultPropertyNames();
1721                         for (int i = 0; i < defaultPropertyNames.length; i++) {
1722                                 String propertyName = defaultPropertyNames[i];
1723                                 if (optionNames.contains(propertyName)) {
1724                                         options.put(propertyName, preferences.getDefaultString(
1725                                                         propertyName).trim());
1726                                 }
1727                         }
1728                 }
1729                 // get custom preferences not set to their default
1730                 String[] propertyNames = preferences.propertyNames();
1731                 for (int i = 0; i < propertyNames.length; i++) {
1732                         String propertyName = propertyNames[i];
1733                         if (optionNames.contains(propertyName)) {
1734                                 options.put(propertyName, preferences.getString(propertyName)
1735                                                 .trim());
1736                         }
1737                 }
1738                 return options;
1739         }
1740
1741         /**
1742          * @see IJavaProject
1743          */
1744         // public IPath getOutputLocation() throws JavaModelException {
1745         //
1746         // JavaModelManager.PerProjectInfo perProjectInfo =
1747         // JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project);
1748         // IPath outputLocation = perProjectInfo.outputLocation;
1749         // if (outputLocation != null) return outputLocation;
1750         //
1751         // // force to read classpath - will position output location as well
1752         // this.getRawClasspath();
1753         // outputLocation = perProjectInfo.outputLocation;
1754         // if (outputLocation == null) {
1755         // return defaultOutputLocation();
1756         // }
1757         // return outputLocation;
1758         // }
1759         /**
1760          * @see IJavaProject
1761          */
1762         public IPath getOutputLocation() throws JavaModelException {
1763                 // Do not create marker but log problems while getting output location
1764                 return this.getOutputLocation(false, true);
1765         }
1766
1767         /**
1768          * @param createMarkers
1769          *            boolean
1770          * @param logProblems
1771          *            boolean
1772          * @return IPath
1773          * @throws JavaModelException
1774          */
1775         public IPath getOutputLocation(boolean createMarkers, boolean logProblems)
1776                         throws JavaModelException {
1777
1778                 JavaModelManager.PerProjectInfo perProjectInfo = getPerProjectInfo();
1779                 IPath outputLocation = perProjectInfo.outputLocation;
1780                 if (outputLocation != null)
1781                         return outputLocation;
1782
1783                 // force to read classpath - will position output location as well
1784                 this.getRawClasspath(createMarkers, logProblems);
1785                 outputLocation = perProjectInfo.outputLocation;
1786                 if (outputLocation == null) {
1787                         return defaultOutputLocation();
1788                 }
1789                 return outputLocation;
1790         }
1791
1792         /**
1793          * @return A handle to the package fragment root identified by the given
1794          *         path. This method is handle-only and the element may or may not
1795          *         exist. Returns <code>null</code> if unable to generate a handle
1796          *         from the path (for example, an absolute path that has less than 1
1797          *         segment. The path may be relative or absolute.
1798          */
1799         public IPackageFragmentRoot getPackageFragmentRoot(IPath path) {
1800                 if (!path.isAbsolute()) {
1801                         path = getPath().append(path);
1802                 }
1803                 int segmentCount = path.segmentCount();
1804                 switch (segmentCount) {
1805                 case 0:
1806                         return null;
1807                 case 1:
1808                         // default root
1809                         return getPackageFragmentRoot(getProject());
1810                 default:
1811                         // a path ending with .jar/.zip is still ambiguous and could still
1812                         // resolve to a source/lib folder
1813                         // thus will try to guess based on existing resource
1814                         // if (ProjectPrefUtil.isArchiveFileName(path.lastSegment())) {
1815                         // IResource resource =
1816                         // getProject().getWorkspace().getRoot().findMember(path);
1817                         // if (resource != null && resource.getType() == IResource.FOLDER){
1818                         // return getPackageFragmentRoot(resource);
1819                         // }
1820                         // return getPackageFragmentRoot0(path);
1821                         // } else {
1822                         return getPackageFragmentRoot(getProject().getWorkspace().getRoot()
1823                                         .getFolder(path));
1824                         // }
1825                 }
1826         }
1827
1828         /**
1829          * The path is known to match a source/library folder entry.
1830          */
1831         public IPackageFragmentRoot getFolderPackageFragmentRoot(IPath path) {
1832                 if (path.segmentCount() == 1) { // default project root
1833                         return getPackageFragmentRoot(getProject());
1834                 }
1835                 return getPackageFragmentRoot(getProject().getWorkspace().getRoot()
1836                                 .getFolder(path));
1837         }
1838
1839         /**
1840          * @see IJavaProject
1841          */
1842         public IPackageFragmentRoot getPackageFragmentRoot(IResource resource) {
1843
1844                 switch (resource.getType()) {
1845                 case IResource.FILE:
1846                         // if (ProjectPrefUtil.isArchiveFileName(resource.getName())) {
1847                         // return new JarPackageFragmentRoot(resource, this);
1848                         // } else {
1849                         return null;
1850                         // }
1851                 case IResource.FOLDER:
1852                         return new PackageFragmentRoot(resource, this, resource.getName());
1853                 case IResource.PROJECT:
1854                         return new PackageFragmentRoot(resource, this, ""); //$NON-NLS-1$
1855                 default:
1856                         return null;
1857                 }
1858         }
1859
1860         /**
1861          * @see IJavaProject
1862          */
1863         // public IPackageFragmentRoot getPackageFragmentRoot(String jarPath) {
1864         //
1865         // return getPackageFragmentRoot0(JavaProject.canonicalizedPath(new
1866         // Path(jarPath)));
1867         // }
1868         //      
1869         // /**
1870         // * no path canonicalization
1871         // */
1872         // public IPackageFragmentRoot getPackageFragmentRoot0(IPath jarPath) {
1873         //
1874         // return new JarPackageFragmentRoot(jarPath, this);
1875         // }
1876         /**
1877          * @see IJavaProject
1878          */
1879         public IPackageFragmentRoot[] getPackageFragmentRoots()
1880                         throws JavaModelException {
1881
1882                 Object[] children;
1883                 int length;
1884                 IPackageFragmentRoot[] roots;
1885
1886                 System.arraycopy(children = getChildren(), 0,
1887                                 roots = new IPackageFragmentRoot[length = children.length], 0,
1888                                 length);
1889
1890                 return roots;
1891         }
1892
1893         /**
1894          * @see IJavaProject
1895          * @deprecated
1896          */
1897         public IPackageFragmentRoot[] getPackageFragmentRoots(IClasspathEntry entry) {
1898                 return findPackageFragmentRoots(entry);
1899         }
1900
1901         /**
1902          * Returns the package fragment root prefixed by the given path, or an empty
1903          * collection if there are no such elements in the model.
1904          */
1905         protected IPackageFragmentRoot[] getPackageFragmentRoots(IPath path)
1906
1907         throws JavaModelException {
1908                 IPackageFragmentRoot[] roots = getAllPackageFragmentRoots();
1909                 ArrayList matches = new ArrayList();
1910
1911                 for (int i = 0; i < roots.length; ++i) {
1912                         if (path.isPrefixOf(roots[i].getPath())) {
1913                                 matches.add(roots[i]);
1914                         }
1915                 }
1916                 IPackageFragmentRoot[] copy = new IPackageFragmentRoot[matches.size()];
1917                 matches.toArray(copy);
1918                 return copy;
1919         }
1920
1921         /**
1922          * @see IJavaProject
1923          */
1924         public IPackageFragment[] getPackageFragments() throws JavaModelException {
1925
1926                 IPackageFragmentRoot[] roots = getPackageFragmentRoots();
1927                 return getPackageFragmentsInRoots(roots);
1928         }
1929
1930         /**
1931          * Returns all the package fragments found in the specified package fragment
1932          * roots.
1933          */
1934         public IPackageFragment[] getPackageFragmentsInRoots(
1935                         IPackageFragmentRoot[] roots) {
1936
1937                 ArrayList frags = new ArrayList();
1938                 for (int i = 0; i < roots.length; i++) {
1939                         IPackageFragmentRoot root = roots[i];
1940                         try {
1941                                 IJavaElement[] rootFragments = root.getChildren();
1942                                 for (int j = 0; j < rootFragments.length; j++) {
1943                                         frags.add(rootFragments[j]);
1944                                 }
1945                         } catch (JavaModelException e) {
1946                                 // do nothing
1947                         }
1948                 }
1949                 IPackageFragment[] fragments = new IPackageFragment[frags.size()];
1950                 frags.toArray(fragments);
1951                 return fragments;
1952         }
1953
1954         /*
1955          * @see IJavaElement
1956          */
1957         public IPath getPath() {
1958                 return this.getProject().getFullPath();
1959         }
1960
1961         public JavaModelManager.PerProjectInfo getPerProjectInfo()
1962                         throws JavaModelException {
1963                 return JavaModelManager.getJavaModelManager()
1964                                 .getPerProjectInfoCheckExistence(this.project);
1965         }
1966
1967         /**
1968          * @see IJavaProject
1969          */
1970         public IProject getProject() {
1971
1972                 return project;
1973         }
1974
1975         /**
1976          * Sets the underlying kernel project of this Java project, and fills in its
1977          * parent and name. Called by IProject.getNature().
1978          * 
1979          * @see IProjectNature#setProject(IProject)
1980          */
1981         public void setProject(IProject project) {
1982
1983                 this.project = project;
1984                 this.parent = JavaModelManager.getJavaModelManager().getJavaModel();
1985                 this.name = project.getName();
1986         }
1987
1988         protected IProject getProject(String name) {
1989                 return PHPeclipsePlugin.getWorkspace().getRoot().getProject(name);
1990         }
1991
1992         public List getReferencedProjects() {
1993                 List referencedProjects = new ArrayList();
1994
1995                 Iterator iterator = getLoadPathEntries().iterator();
1996                 while (iterator.hasNext()) {
1997                         LoadPathEntry pathEntry = (LoadPathEntry) iterator.next();
1998                         if (pathEntry.getType() == LoadPathEntry.TYPE_PROJECT)
1999                                 referencedProjects.add(pathEntry.getProject());
2000                 }
2001
2002                 return referencedProjects;
2003         }
2004
2005         /**
2006          * Returns the project custom preference pool. Project preferences may
2007          * include custom encoding.
2008          */
2009         public Preferences getPreferences() {
2010                 IProject project = getProject();
2011                 if (!JavaProject.hasJavaNature(project))
2012                         return null;
2013                 JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager
2014                                 .getJavaModelManager().getPerProjectInfo(project, true);
2015                 Preferences preferences = perProjectInfo.preferences;
2016                 if (preferences != null)
2017                         return preferences;
2018                 preferences = loadPreferences();
2019                 if (preferences == null)
2020                         preferences = new Preferences();
2021                 perProjectInfo.preferences = preferences;
2022                 return preferences;
2023         }
2024
2025         /**
2026          * @see IJavaProject
2027          */
2028         // public IClasspathEntry[] getRawClasspath() throws JavaModelException {
2029         //
2030         // JavaModelManager.PerProjectInfo perProjectInfo =
2031         // JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project);
2032         // IClasspathEntry[] classpath = perProjectInfo.classpath;
2033         // if (classpath != null) return classpath;
2034         // classpath = this.readClasspathFile(false/*don't create markers*/,
2035         // true/*log problems*/);
2036         //              
2037         // // extract out the output location
2038         // IPath outputLocation = null;
2039         // if (classpath != null && classpath.length > 0) {
2040         // IClasspathEntry entry = classpath[classpath.length - 1];
2041         // if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
2042         // outputLocation = entry.getPath();
2043         // IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1];
2044         // System.arraycopy(classpath, 0, copy, 0, copy.length);
2045         // classpath = copy;
2046         // }
2047         // }
2048         // if (classpath == null) {
2049         // return defaultClasspath();
2050         // }
2051         // /* Disable validate: classpath can contain CP variables and container
2052         // that need to be resolved
2053         // if (classpath != INVALID_CLASSPATH
2054         // && !JavaConventions.validateClasspath(this, classpath,
2055         // outputLocation).isOK()) {
2056         // classpath = INVALID_CLASSPATH;
2057         // }
2058         // */
2059         // perProjectInfo.classpath = classpath;
2060         // perProjectInfo.outputLocation = outputLocation;
2061         // return classpath;
2062         // }
2063         /**
2064          * @see IJavaProject
2065          */
2066         public IClasspathEntry[] getRawClasspath() throws JavaModelException {
2067                 // Do not create marker but log problems while getting raw classpath
2068                 return getRawClasspath(false, true);
2069         }
2070
2071         /*
2072          * Internal variant allowing to parameterize problem creation/logging
2073          */
2074         public IClasspathEntry[] getRawClasspath(boolean createMarkers,
2075                         boolean logProblems) throws JavaModelException {
2076
2077                 JavaModelManager.PerProjectInfo perProjectInfo = null;
2078                 IClasspathEntry[] classpath;
2079                 if (createMarkers) {
2080                         this.flushClasspathProblemMarkers(false/* cycle */, true/* format */);
2081                         classpath = this.readClasspathFile(createMarkers, logProblems);
2082                 } else {
2083                         perProjectInfo = getPerProjectInfo();
2084                         classpath = perProjectInfo.rawClasspath;
2085                         if (classpath != null)
2086                                 return classpath;
2087                         classpath = this.readClasspathFile(createMarkers, logProblems);
2088                 }
2089                 // extract out the output location
2090                 IPath outputLocation = null;
2091                 if (classpath != null && classpath.length > 0) {
2092                         IClasspathEntry entry = classpath[classpath.length - 1];
2093                         if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
2094                                 outputLocation = entry.getPath();
2095                                 IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1];
2096                                 System.arraycopy(classpath, 0, copy, 0, copy.length);
2097                                 classpath = copy;
2098                         }
2099                 }
2100                 if (classpath == null) {
2101                         return defaultClasspath();
2102                 }
2103                 /*
2104                  * Disable validate: classpath can contain CP variables and container
2105                  * that need to be resolved if (classpath != INVALID_CLASSPATH &&
2106                  * !JavaConventions.validateClasspath(this, classpath,
2107                  * outputLocation).isOK()) { classpath = INVALID_CLASSPATH; }
2108                  */
2109                 if (!createMarkers) {
2110                         perProjectInfo.rawClasspath = classpath;
2111                         perProjectInfo.outputLocation = outputLocation;
2112                 }
2113                 return classpath;
2114         }
2115
2116         /**
2117          * @see IJavaProject#getRequiredProjectNames
2118          */
2119         public String[] getRequiredProjectNames() throws JavaModelException {
2120
2121                 return this.projectPrerequisites(getResolvedClasspath(true));
2122         }
2123
2124         /**
2125          * @see IJavaProject
2126          */
2127         public IClasspathEntry[] getResolvedClasspath(boolean ignoreUnresolvedEntry)
2128                         throws JavaModelException {
2129
2130                 return this.getResolvedClasspath(ignoreUnresolvedEntry, false); // generateMarkerOnError
2131         }
2132
2133         /**
2134          * Internal variant which can create marker on project for invalid entries
2135          * and caches the resolved classpath on perProjectInfo
2136          */
2137         public IClasspathEntry[] getResolvedClasspath(
2138                         boolean ignoreUnresolvedEntry, boolean generateMarkerOnError)
2139                         throws JavaModelException {
2140                 return getResolvedClasspath(ignoreUnresolvedEntry,
2141                                 generateMarkerOnError, true // returnResolutionInProgress
2142                 );
2143                 // JavaModelManager manager = JavaModelManager.getJavaModelManager();
2144                 // JavaModelManager.PerProjectInfo perProjectInfo =
2145                 // manager.getPerProjectInfoCheckExistence(project);
2146                 //              
2147                 // // reuse cache if not needing to refresh markers or checking bound
2148                 // variables
2149                 // if (ignoreUnresolvedEntry && !generateMarkerOnError && perProjectInfo
2150                 // != null){
2151                 // // resolved path is cached on its info
2152                 // IClasspathEntry[] infoPath = perProjectInfo.lastResolvedClasspath;
2153                 // if (infoPath != null) return infoPath;
2154                 // }
2155                 // Map reverseMap = perProjectInfo == null ? null : new HashMap(5);
2156                 // IClasspathEntry[] resolvedPath = getResolvedClasspath(
2157                 // getRawClasspath(),
2158                 // generateMarkerOnError ? getOutputLocation() : null,
2159                 // ignoreUnresolvedEntry,
2160                 // generateMarkerOnError,
2161                 // reverseMap);
2162                 //
2163                 // if (perProjectInfo != null){
2164                 // if (perProjectInfo.classpath == null // .classpath file could not be
2165                 // read
2166                 // && generateMarkerOnError
2167                 // && JavaProject.hasJavaNature(project)) {
2168                 // this.createClasspathProblemMarker(new JavaModelStatus(
2169                 // IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
2170                 // Util.bind("classpath.cannotReadClasspathFile",
2171                 // this.getElementName()))); //$NON-NLS-1$
2172                 // }
2173                 //
2174                 // perProjectInfo.lastResolvedClasspath = resolvedPath;
2175                 // perProjectInfo.resolvedPathToRawEntries = reverseMap;
2176                 // }
2177                 // return resolvedPath;
2178         }
2179
2180         /*
2181          * Internal variant which can create marker on project for invalid entries
2182          * and caches the resolved classpath on perProjectInfo. If requested, return
2183          * a special classpath (RESOLUTION_IN_PROGRESS) if the classpath is being
2184          * resolved.
2185          */
2186         public IClasspathEntry[] getResolvedClasspath(
2187                         boolean ignoreUnresolvedEntry, boolean generateMarkerOnError,
2188                         boolean returnResolutionInProgress) throws JavaModelException {
2189
2190                 JavaModelManager manager = JavaModelManager.getJavaModelManager();
2191                 JavaModelManager.PerProjectInfo perProjectInfo = null;
2192                 if (ignoreUnresolvedEntry && !generateMarkerOnError) {
2193                         perProjectInfo = getPerProjectInfo();
2194                         if (perProjectInfo != null) {
2195                                 // resolved path is cached on its info
2196                                 IClasspathEntry[] infoPath = perProjectInfo.resolvedClasspath;
2197                                 if (infoPath != null) {
2198                                         return infoPath;
2199                                 } else if (returnResolutionInProgress
2200                                                 && manager.isClasspathBeingResolved(this)) {
2201                                         if (JavaModelManager.CP_RESOLVE_VERBOSE) {
2202                                                 Util
2203                                                                 .verbose("CPResolution: reentering raw classpath resolution, will use empty classpath instead" + //$NON-NLS-1$
2204                                                                                 "       project: " + getElementName() + '\n' + //$NON-NLS-1$
2205                                                                                 "       invocation stack trace:"); //$NON-NLS-1$
2206                                                 new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
2207                                         }
2208                                         return RESOLUTION_IN_PROGRESS;
2209                                 }
2210                         }
2211                 }
2212                 Map reverseMap = perProjectInfo == null ? null : new HashMap(5);
2213                 IClasspathEntry[] resolvedPath = null;
2214                 boolean nullOldResolvedCP = perProjectInfo != null
2215                                 && perProjectInfo.resolvedClasspath == null;
2216                 try {
2217                         // protect against misbehaving clients (see
2218                         // https://bugs.eclipse.org/bugs/show_bug.cgi?id=61040)
2219                         if (nullOldResolvedCP)
2220                                 manager.setClasspathBeingResolved(this, true);
2221                         resolvedPath = getResolvedClasspath(getRawClasspath(
2222                                         generateMarkerOnError, !generateMarkerOnError),
2223                                         generateMarkerOnError ? getOutputLocation() : null,
2224                                         ignoreUnresolvedEntry, generateMarkerOnError, reverseMap);
2225                 } finally {
2226                         if (nullOldResolvedCP)
2227                                 perProjectInfo.resolvedClasspath = null;
2228                 }
2229
2230                 if (perProjectInfo != null) {
2231                         if (perProjectInfo.rawClasspath == null // .classpath file could not
2232                                                                                                         // be read
2233                                         && generateMarkerOnError
2234                                         && JavaProject.hasJavaNature(this.project)) {
2235                                 // flush .classpath format markers (bug 39877), but only when
2236                                 // file cannot be read (bug 42366)
2237                                 this.flushClasspathProblemMarkers(false, true);
2238                                 this
2239                                                 .createClasspathProblemMarker(new JavaModelStatus(
2240                                                                 IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
2241                                                                 Util
2242                                                                                 .bind(
2243                                                                                                 "classpath.cannotReadClasspathFile", this.getElementName()))); //$NON-NLS-1$
2244                         }
2245
2246                         perProjectInfo.resolvedClasspath = resolvedPath;
2247                         perProjectInfo.resolvedPathToRawEntries = reverseMap;
2248                         manager.setClasspathBeingResolved(this, false);
2249                 }
2250                 return resolvedPath;
2251         }
2252
2253         /**
2254          * Internal variant which can process any arbitrary classpath
2255          */
2256         public IClasspathEntry[] getResolvedClasspath(
2257                         IClasspathEntry[] classpathEntries, IPath projectOutputLocation, // only
2258                                                                                                                                                                 // set
2259                                                                                                                                                                 // if
2260                                                                                                                                                                 // needing
2261                                                                                                                                                                 // full
2262                                                                                                                                                                 // classpath
2263                                                                                                                                                                 // validation
2264                                                                                                                                                                 // (and
2265                                                                                                                                                                 // markers)
2266                         boolean ignoreUnresolvedEntry, // if unresolved entries are met,
2267                                                                                         // should it trigger initializations
2268                         boolean generateMarkerOnError, Map reverseMap) // can be null if
2269                                                                                                                         // not interested in
2270                                                                                                                         // reverse mapping
2271                         throws JavaModelException {
2272
2273                 IJavaModelStatus status;
2274                 if (generateMarkerOnError) {
2275                         flushClasspathProblemMarkers(false, false);
2276                 }
2277
2278                 int length = classpathEntries.length;
2279                 ArrayList resolvedEntries = new ArrayList();
2280
2281                 for (int i = 0; i < length; i++) {
2282
2283                         IClasspathEntry rawEntry = classpathEntries[i];
2284                         IPath resolvedPath;
2285                         status = null;
2286
2287                         /* validation if needed */
2288                         // if (generateMarkerOnError || !ignoreUnresolvedEntry) {
2289                         // status = JavaConventions.validateClasspathEntry(this, rawEntry,
2290                         // false);
2291                         // if (generateMarkerOnError && !status.isOK())
2292                         // createClasspathProblemMarker(status);
2293                         // }
2294                         switch (rawEntry.getEntryKind()) {
2295
2296                         case IClasspathEntry.CPE_VARIABLE:
2297
2298                                 IClasspathEntry resolvedEntry = JavaCore
2299                                                 .getResolvedClasspathEntry(rawEntry);
2300                                 if (resolvedEntry == null) {
2301                                         if (!ignoreUnresolvedEntry)
2302                                                 throw new JavaModelException(status);
2303                                 } else {
2304                                         if (reverseMap != null
2305                                                         && reverseMap.get(resolvedPath = resolvedEntry
2306                                                                         .getPath()) == null)
2307                                                 reverseMap.put(resolvedPath, rawEntry);
2308                                         resolvedEntries.add(resolvedEntry);
2309                                 }
2310                                 break;
2311
2312                         // case IClasspathEntry.CPE_CONTAINER :
2313                         //                              
2314                         // IClasspathContainer container =
2315                         // PHPCore.getClasspathContainer(rawEntry.getPath(), this);
2316                         // if (container == null){
2317                         // if (!ignoreUnresolvedEntry) throw new JavaModelException(status);
2318                         // break;
2319                         // }
2320                         //
2321                         // IClasspathEntry[] containerEntries =
2322                         // container.getClasspathEntries();
2323                         // if (containerEntries == null) break;
2324                         //
2325                         // // container was bound
2326                         // for (int j = 0, containerLength = containerEntries.length; j <
2327                         // containerLength; j++){
2328                         // IClasspathEntry cEntry = containerEntries[j];
2329                         //                                              
2330                         // if (generateMarkerOnError) {
2331                         // IJavaModelStatus containerStatus =
2332                         // JavaConventions.validateClasspathEntry(this, cEntry, false);
2333                         // if (!containerStatus.isOK())
2334                         // createClasspathProblemMarker(containerStatus);
2335                         // }
2336                         // // if container is exported, then its nested entries must in turn
2337                         // be exported (21749)
2338                         // if (rawEntry.isExported()){
2339                         // cEntry = new ClasspathEntry(cEntry.getContentKind(),
2340                         // cEntry.getEntryKind(), cEntry.getPath(),
2341                         // cEntry.getExclusionPatterns(), cEntry.getSourceAttachmentPath(),
2342                         // cEntry.getSourceAttachmentRootPath(), cEntry.getOutputLocation(),
2343                         // true); // duplicate container entry for tagging it as exported
2344                         // }
2345                         // if (reverseMap != null && reverseMap.get(resolvedPath =
2346                         // cEntry.getPath()) == null) reverseMap.put(resolvedPath,
2347                         // rawEntry);
2348                         // resolvedEntries.add(cEntry);
2349                         // }
2350                         // break;
2351
2352                         default:
2353
2354                                 if (reverseMap != null
2355                                                 && reverseMap.get(resolvedPath = rawEntry.getPath()) == null)
2356                                         reverseMap.put(resolvedPath, rawEntry);
2357                                 resolvedEntries.add(rawEntry);
2358
2359                         }
2360                 }
2361
2362                 IClasspathEntry[] resolvedPath = new IClasspathEntry[resolvedEntries
2363                                 .size()];
2364                 resolvedEntries.toArray(resolvedPath);
2365
2366                 // if (generateMarkerOnError && projectOutputLocation != null) {
2367                 // status = JavaConventions.validateClasspath(this, resolvedPath,
2368                 // projectOutputLocation);
2369                 // if (!status.isOK()) createClasspathProblemMarker(status);
2370                 // }
2371                 return resolvedPath;
2372         }
2373
2374         /*
2375          * @see IJavaElement
2376          */
2377         public IResource getResource() {
2378                 return this.getProject();
2379         }
2380
2381         /**
2382          * @see IJavaProject
2383          */
2384         public ISearchableNameEnvironment getSearchableNameEnvironment()
2385                         throws JavaModelException {
2386
2387                 // JavaProjectElementInfo info = getJavaProjectElementInfo();
2388                 // if (info.getSearchableEnvironment() == null) {
2389                 // info.setSearchableEnvironment(new SearchableEnvironment(this));
2390                 // }
2391                 // return info.getSearchableEnvironment();
2392                 return null;
2393         }
2394
2395         /**
2396          * Retrieve a shared property on a project. If the property is not defined,
2397          * answers null. Note that it is orthogonal to IResource persistent
2398          * properties, and client code has to decide which form of storage to use
2399          * appropriately. Shared properties produce real resource files which can be
2400          * shared through a VCM onto a server. Persistent properties are not
2401          * shareable.
2402          * 
2403          * @see JavaProject#setSharedProperty(String, String)
2404          */
2405         public String getSharedProperty(String key) throws CoreException {
2406
2407                 String property = null;
2408                 IFile rscFile = getProject().getFile(key);
2409                 if (rscFile.exists()) {
2410                         property = new String(Util.getResourceContentsAsByteArray(rscFile));
2411                 }
2412                 return property;
2413         }
2414
2415         /**
2416          * @see JavaElement
2417          */
2418         // public SourceMapper getSourceMapper() {
2419         //
2420         // return null;
2421         // }
2422         /**
2423          * @see IJavaElement
2424          */
2425         public IResource getUnderlyingResource() throws JavaModelException {
2426                 if (!exists())
2427                         throw newNotPresentException();
2428                 return getProject();
2429         }
2430
2431         /**
2432          * @see IJavaProject
2433          */
2434         public boolean hasBuildState() {
2435
2436                 return JavaModelManager.getJavaModelManager().getLastBuiltState(
2437                                 this.getProject(), null) != null;
2438         }
2439
2440         /**
2441          * @see IJavaProject
2442          */
2443         public boolean hasClasspathCycle(IClasspathEntry[] preferredClasspath) {
2444                 HashSet cycleParticipants = new HashSet();
2445                 updateCycleParticipants(preferredClasspath, new ArrayList(2),
2446                                 cycleParticipants, ResourcesPlugin.getWorkspace().getRoot(),
2447                                 new HashSet(2));
2448                 return !cycleParticipants.isEmpty();
2449         }
2450
2451         public boolean hasCycleMarker() {
2452                 return this.getCycleMarker() != null;
2453         }
2454
2455         public int hashCode() {
2456                 return project.hashCode();
2457         }
2458
2459         /**
2460          * Returns true if the given project is accessible and it has a java nature,
2461          * otherwise false.
2462          */
2463         public static boolean hasJavaNature(IProject project) {
2464                 try {
2465                         return project.hasNature(PHPeclipsePlugin.PHP_NATURE_ID);
2466                 } catch (CoreException e) {
2467                         // project does not exist or is not open
2468                 }
2469                 return false;
2470         }
2471
2472         /**
2473          * Answers true if the project potentially contains any source. A project
2474          * which has no source is immutable.
2475          */
2476         public boolean hasSource() {
2477
2478                 // look if any source folder on the classpath
2479                 // no need for resolved path given source folder cannot be abstracted
2480                 IClasspathEntry[] entries;
2481                 try {
2482                         entries = this.getRawClasspath();
2483                 } catch (JavaModelException e) {
2484                         return true; // unsure
2485                 }
2486                 for (int i = 0, max = entries.length; i < max; i++) {
2487                         if (entries[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) {
2488                                 return true;
2489                         }
2490                 }
2491                 return false;
2492         }
2493
2494         /**
2495          * Compare current classpath with given one to see if any different. Note
2496          * that the argument classpath contains its binary output.
2497          */
2498         public boolean isClasspathEqualsTo(IClasspathEntry[] newClasspath,
2499                         IPath newOutputLocation, IClasspathEntry[] otherClasspathWithOutput)
2500                         throws JavaModelException {
2501
2502                 if (otherClasspathWithOutput != null
2503                                 && otherClasspathWithOutput.length > 0) {
2504
2505                         int length = otherClasspathWithOutput.length;
2506                         if (length == newClasspath.length + 1) {
2507                                 // output is amongst file entries (last one)
2508
2509                                 // compare classpath entries
2510                                 for (int i = 0; i < length - 1; i++) {
2511                                         if (!otherClasspathWithOutput[i].equals(newClasspath[i]))
2512                                                 return false;
2513                                 }
2514                                 // compare binary outputs
2515                                 IClasspathEntry output = otherClasspathWithOutput[length - 1];
2516                                 if (output.getContentKind() == ClasspathEntry.K_OUTPUT
2517                                                 && output.getPath().equals(newOutputLocation))
2518                                         return true;
2519                         }
2520                 }
2521                 return false;
2522         }
2523
2524         /*
2525          * @see IJavaProject
2526          */
2527         public boolean isOnClasspath(IJavaElement element) {
2528                 IPath path = element.getPath();
2529                 switch (element.getElementType()) {
2530                 case IJavaElement.PACKAGE_FRAGMENT_ROOT:
2531                         if (!((IPackageFragmentRoot) element).isArchive()) {
2532                                 // ensure that folders are only excluded if all of their
2533                                 // children are excluded
2534                                 path = path.append("*"); //$NON-NLS-1$
2535                         }
2536                         break;
2537                 case IJavaElement.PACKAGE_FRAGMENT:
2538                         if (!((IPackageFragmentRoot) element.getParent()).isArchive()) {
2539                                 // ensure that folders are only excluded if all of their
2540                                 // children are excluded
2541                                 path = path.append("*"); //$NON-NLS-1$
2542                         }
2543                         break;
2544                 }
2545                 return this.isOnClasspath(path);
2546         }
2547
2548         private boolean isOnClasspath(IPath path) {
2549                 IClasspathEntry[] classpath;
2550                 try {
2551                         classpath = this
2552                                         .getResolvedClasspath(true/* ignore unresolved variable */);
2553                 } catch (JavaModelException e) {
2554                         return false; // not a Java project
2555                 }
2556                 for (int i = 0; i < classpath.length; i++) {
2557                         IClasspathEntry entry = classpath[i];
2558                         if (entry.getPath().isPrefixOf(path)
2559                                         && !Util.isExcluded(path, null, ((ClasspathEntry) entry)
2560                                                         .fullExclusionPatternChars(), true)) {
2561                                 return true;
2562                         }
2563                 }
2564                 return false;
2565         }
2566
2567         /*
2568          * @see IJavaProject
2569          */
2570         public boolean isOnClasspath(IResource resource) {
2571                 IPath path = resource.getFullPath();
2572
2573                 // ensure that folders are only excluded if all of their children are
2574                 // excluded
2575                 if (resource.getType() == IResource.FOLDER) {
2576                         path = path.append("*"); //$NON-NLS-1$
2577                 }
2578
2579                 return this.isOnClasspath(path);
2580         }
2581
2582         private IPath getPluginWorkingLocation() {
2583                 return this.project.getWorkingLocation(JavaCore.PLUGIN_ID);
2584         }
2585
2586         /*
2587          * load preferences from a shareable format (VCM-wise)
2588          */
2589         public Preferences loadPreferences() {
2590
2591                 Preferences preferences = new Preferences();
2592
2593                 // File prefFile =
2594                 // getProject().getLocation().append(PREF_FILENAME).toFile();
2595                 IPath projectMetaLocation = getPluginWorkingLocation();
2596                 if (projectMetaLocation != null) {
2597                         File prefFile = projectMetaLocation.append(PREF_FILENAME).toFile();
2598                         if (prefFile.exists()) { // load preferences from file
2599                                 InputStream in = null;
2600                                 try {
2601                                         in = new BufferedInputStream(new FileInputStream(prefFile));
2602                                         preferences.load(in);
2603                                         return preferences;
2604                                 } catch (IOException e) { // problems loading preference store
2605                                                                                         // - quietly ignore
2606                                 } finally {
2607                                         if (in != null) {
2608                                                 try {
2609                                                         in.close();
2610                                                 } catch (IOException e) { // ignore problems with
2611                                                                                                         // close
2612                                                 }
2613                                         }
2614                                 }
2615                         }
2616                 }
2617                 return null;
2618         }
2619
2620         /**
2621          * @see IJavaProject#newEvaluationContext
2622          */
2623         // public IEvaluationContext newEvaluationContext() {
2624         //
2625         // return new EvaluationContextWrapper(new EvaluationContext(), this);
2626         // }
2627         /**
2628          * @see IJavaProject
2629          */
2630         // public ITypeHierarchy newTypeHierarchy(
2631         // IRegion region,
2632         // IProgressMonitor monitor)
2633         // throws JavaModelException {
2634         //
2635         // if (region == null) {
2636         // throw new
2637         // IllegalArgumentException(ProjectPrefUtil.bind("hierarchy.nullRegion"));//$NON-NLS-1$
2638         // }
2639         // CreateTypeHierarchyOperation op =
2640         // new CreateTypeHierarchyOperation(null, region, this, true);
2641         // runOperation(op, monitor);
2642         // return op.getResult();
2643         // }
2644         /**
2645          * @see IJavaProject
2646          */
2647         // public ITypeHierarchy newTypeHierarchy(
2648         // IType type,
2649         // IRegion region,
2650         // IProgressMonitor monitor)
2651         // throws JavaModelException {
2652         //
2653         // if (type == null) {
2654         // throw new
2655         // IllegalArgumentException(ProjectPrefUtil.bind("hierarchy.nullFocusType"));//$NON-NLS-1$
2656         // }
2657         // if (region == null) {
2658         // throw new
2659         // IllegalArgumentException(ProjectPrefUtil.bind("hierarchy.nullRegion"));//$NON-NLS-1$
2660         // }
2661         // CreateTypeHierarchyOperation op =
2662         // new CreateTypeHierarchyOperation(type, region, this, true);
2663         // runOperation(op, monitor);
2664         // return op.getResult();
2665         // }
2666         // /**
2667         // * Open project if resource isn't closed
2668         // */
2669         // protected void openWhenClosed(IProgressMonitor pm) throws
2670         // JavaModelException {
2671         //
2672         // if (!this.fProject.isOpen()) {
2673         // throw newNotPresentException();
2674         // } else {
2675         // super.openWhenClosed(pm);
2676         // }
2677         // }
2678         public String[] projectPrerequisites(IClasspathEntry[] entries)
2679                         throws JavaModelException {
2680
2681                 ArrayList prerequisites = new ArrayList();
2682                 // need resolution
2683                 entries = getResolvedClasspath(entries, null, true, false, null/*
2684                                                                                                                                                  * no
2685                                                                                                                                                  * reverse
2686                                                                                                                                                  * map
2687                                                                                                                                                  */);
2688                 for (int i = 0, length = entries.length; i < length; i++) {
2689                         IClasspathEntry entry = entries[i];
2690                         if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
2691                                 prerequisites.add(entry.getPath().lastSegment());
2692                         }
2693                 }
2694                 int size = prerequisites.size();
2695                 if (size == 0) {
2696                         return NO_PREREQUISITES;
2697                 } else {
2698                         String[] result = new String[size];
2699                         prerequisites.toArray(result);
2700                         return result;
2701                 }
2702         }
2703
2704         /**
2705          * Reads the .classpath file from disk and returns the list of entries it
2706          * contains (including output location entry) Returns null if .classfile is
2707          * not present. Returns INVALID_CLASSPATH if it has a format problem.
2708          */
2709         protected IClasspathEntry[] readClasspathFile(boolean createMarker,
2710                         boolean logProblems) {
2711
2712                 try {
2713                         String xmlClasspath = getSharedProperty(CLASSPATH_FILENAME);
2714                         if (xmlClasspath == null)
2715                                 return null;
2716                         return decodeClasspath(xmlClasspath, createMarker, logProblems);
2717                 } catch (CoreException e) {
2718                         // file does not exist (or not accessible)
2719                         if (createMarker && this.getProject().isAccessible()) {
2720                                 this
2721                                                 .createClasspathProblemMarker(new JavaModelStatus(
2722                                                                 IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
2723                                                                 Util
2724                                                                                 .bind(
2725                                                                                                 "classpath.cannotReadClasspathFile", this.getElementName()))); //$NON-NLS-1$
2726                         }
2727                         if (logProblems) {
2728                                 Util.log(e, "Exception while retrieving " + this.getPath() //$NON-NLS-1$
2729                                                 + "/.classpath, will revert to default classpath"); //$NON-NLS-1$
2730                         }
2731                 }
2732                 return null;
2733         }
2734
2735         /**
2736          * Removes the given builder from the build spec for the given project.
2737          */
2738         protected void removeFromBuildSpec(String builderID) throws CoreException {
2739
2740                 IProjectDescription description = getProject().getDescription();
2741                 ICommand[] commands = description.getBuildSpec();
2742                 for (int i = 0; i < commands.length; ++i) {
2743                         if (commands[i].getBuilderName().equals(builderID)) {
2744                                 ICommand[] newCommands = new ICommand[commands.length - 1];
2745                                 System.arraycopy(commands, 0, newCommands, 0, i);
2746                                 System.arraycopy(commands, i + 1, newCommands, i,
2747                                                 commands.length - i - 1);
2748                                 description.setBuildSpec(newCommands);
2749                                 getProject().setDescription(description, null);
2750                                 return;
2751                         }
2752                 }
2753         }
2754
2755         /**
2756          * @see JavaElement#rootedAt(IJavaProject)
2757          */
2758         public IJavaElement rootedAt(IJavaProject project) {
2759                 return project;
2760
2761         }
2762
2763         /**
2764          * Answers an ID which is used to distinguish project/entries during package
2765          * fragment root computations
2766          */
2767         public String rootID() {
2768                 return "[PRJ]" + this.getProject().getFullPath(); //$NON-NLS-1$
2769         }
2770
2771         /**
2772          * Saves the classpath in a shareable format (VCM-wise) only when necessary,
2773          * that is, if it is semantically different from the existing one in file.
2774          * Will never write an identical one.
2775          * 
2776          * @return Return whether the .classpath file was modified.
2777          */
2778         public boolean saveClasspath(IClasspathEntry[] newClasspath,
2779                         IPath newOutputLocation) throws JavaModelException {
2780
2781                 if (!getProject().exists())
2782                         return false;
2783
2784                 IClasspathEntry[] fileEntries = readClasspathFile(
2785                                 false /* don't create markers */, false/* don't log problems */);
2786                 if (fileEntries != null
2787                                 && isClasspathEqualsTo(newClasspath, newOutputLocation,
2788                                                 fileEntries)) {
2789                         // no need to save it, it is the same
2790                         return false;
2791                 }
2792
2793                 // actual file saving
2794                 try {
2795                         setSharedProperty(CLASSPATH_FILENAME, encodeClasspath(newClasspath,
2796                                         newOutputLocation, true));
2797                         return true;
2798                 } catch (CoreException e) {
2799                         throw new JavaModelException(e);
2800                 }
2801         }
2802
2803         /**
2804          * Save project custom preferences to shareable file (.jprefs)
2805          */
2806         private void savePreferences(Preferences preferences) {
2807
2808                 if (!JavaProject.hasJavaNature(this.project))
2809                         return; // ignore
2810
2811                 if (preferences == null
2812                                 || (!preferences.needsSaving() && preferences.propertyNames().length != 0)) {
2813                         // nothing to save
2814                         return;
2815                 }
2816
2817                 // preferences need to be saved
2818                 // the preferences file is located in the plug-in's state area
2819                 // at a well-known name (.jprefs)
2820                 // File prefFile =
2821                 // this.project.getLocation().append(PREF_FILENAME).toFile();
2822                 File prefFile = getPluginWorkingLocation().append(PREF_FILENAME)
2823                                 .toFile();
2824                 if (preferences.propertyNames().length == 0) {
2825                         // there are no preference settings
2826                         // rather than write an empty file, just delete any existing file
2827                         if (prefFile.exists()) {
2828                                 prefFile.delete(); // don't worry if delete unsuccessful
2829                         }
2830                         return;
2831                 }
2832
2833                 // write file, overwriting an existing one
2834                 OutputStream out = null;
2835                 try {
2836                         // do it as carefully as we know how so that we don't lose/mangle
2837                         // the setting in times of stress
2838                         out = new BufferedOutputStream(new FileOutputStream(prefFile));
2839                         preferences.store(out, null);
2840                 } catch (IOException e) { // problems saving preference store -
2841                                                                         // quietly ignore
2842                 } finally {
2843                         if (out != null) {
2844                                 try {
2845                                         out.close();
2846                                 } catch (IOException e) { // ignore problems with close
2847                                 }
2848                         }
2849                 }
2850         }
2851
2852         /**
2853          * Update the Java command in the build spec (replace existing one if
2854          * present, add one first if none).
2855          */
2856         private void setJavaCommand(IProjectDescription description,
2857                         ICommand newCommand) throws CoreException {
2858
2859                 ICommand[] oldCommands = description.getBuildSpec();
2860                 ICommand oldJavaCommand = getJavaCommand(description);
2861                 ICommand[] newCommands;
2862
2863                 if (oldJavaCommand == null) {
2864                         // Add a Java build spec before other builders (1FWJK7I)
2865                         newCommands = new ICommand[oldCommands.length + 1];
2866                         System
2867                                         .arraycopy(oldCommands, 0, newCommands, 1,
2868                                                         oldCommands.length);
2869                         newCommands[0] = newCommand;
2870                 } else {
2871                         for (int i = 0, max = oldCommands.length; i < max; i++) {
2872                                 if (oldCommands[i] == oldJavaCommand) {
2873                                         oldCommands[i] = newCommand;
2874                                         break;
2875                                 }
2876                         }
2877                         newCommands = oldCommands;
2878                 }
2879
2880                 // Commit the spec change into the project
2881                 description.setBuildSpec(newCommands);
2882                 getProject().setDescription(description, null);
2883         }
2884
2885         /**
2886          * @see net.sourceforge.phpdt.core.IJavaProject#setOptions(Map)
2887          */
2888         public void setOptions(Map newOptions) {
2889
2890                 Preferences preferences;
2891                 setPreferences(preferences = new Preferences()); // always reset
2892                                                                                                                         // (26255)
2893                 if (newOptions != null) {
2894                         Iterator keys = newOptions.keySet().iterator();
2895                         while (keys.hasNext()) {
2896                                 String key = (String) keys.next();
2897                                 if (!JavaModelManager.OptionNames.contains(key))
2898                                         continue; // unrecognized option
2899                                 // no filtering for encoding (custom encoding for project is
2900                                 // allowed)
2901                                 String value = (String) newOptions.get(key);
2902                                 preferences.setDefault(key, CUSTOM_DEFAULT_OPTION_VALUE); // empty
2903                                                                                                                                                         // string
2904                                                                                                                                                         // isn't
2905                                                                                                                                                         // the
2906                                                                                                                                                         // default
2907                                                                                                                                                         // (26251)
2908                                 preferences.setValue(key, value);
2909                         }
2910                 }
2911
2912                 // persist options
2913                 savePreferences(preferences);
2914         }
2915
2916         /**
2917          * @see IJavaProject
2918          */
2919         public void setOutputLocation(IPath path, IProgressMonitor monitor)
2920                         throws JavaModelException {
2921
2922                 if (path == null) {
2923                         throw new IllegalArgumentException(Util.bind("path.nullpath")); //$NON-NLS-1$
2924                 }
2925                 if (path.equals(getOutputLocation())) {
2926                         return;
2927                 }
2928                 this.setRawClasspath(SetClasspathOperation.ReuseClasspath, path,
2929                                 monitor);
2930         }
2931
2932         /*
2933          * Set cached preferences, no preference file is saved, only info is updated
2934          */
2935         public void setPreferences(Preferences preferences) {
2936                 IProject project = getProject();
2937                 if (!JavaProject.hasJavaNature(project))
2938                         return; // ignore
2939                 JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager
2940                                 .getJavaModelManager().getPerProjectInfo(project, true);
2941                 perProjectInfo.preferences = preferences;
2942         }
2943
2944         /**
2945          * @see IJavaProject
2946          */
2947         public void setRawClasspath(IClasspathEntry[] entries,
2948                         IPath outputLocation, IProgressMonitor monitor)
2949                         throws JavaModelException {
2950
2951                 setRawClasspath(entries, outputLocation, monitor, true, // canChangeResource
2952                                                                                                                                 // (as per API
2953                                                                                                                                 // contract)
2954                                 getResolvedClasspath(true), // ignoreUnresolvedVariable
2955                                 true, // needValidation
2956                                 true); // need to save
2957         }
2958
2959         public void setRawClasspath(IClasspathEntry[] newEntries,
2960                         IPath newOutputLocation, IProgressMonitor monitor,
2961                         boolean canChangeResource, IClasspathEntry[] oldResolvedPath,
2962                         boolean needValidation, boolean needSave) throws JavaModelException {
2963
2964                 JavaModelManager manager = (JavaModelManager) JavaModelManager
2965                                 .getJavaModelManager();
2966                 try {
2967                         IClasspathEntry[] newRawPath = newEntries;
2968                         if (newRawPath == null) { // are we already with the default
2969                                                                                 // classpath
2970                                 newRawPath = defaultClasspath();
2971                         }
2972                         SetClasspathOperation op = new SetClasspathOperation(this,
2973                                         oldResolvedPath, newRawPath, newOutputLocation,
2974                                         canChangeResource, needValidation, needSave);
2975                         runOperation(op, monitor);
2976
2977                 } catch (JavaModelException e) {
2978                         manager.flush();
2979                         throw e;
2980                 }
2981         }
2982
2983         /**
2984          * @see IJavaProject
2985          */
2986         public void setRawClasspath(IClasspathEntry[] entries,
2987                         IProgressMonitor monitor) throws JavaModelException {
2988
2989                 setRawClasspath(entries, SetClasspathOperation.ReuseOutputLocation,
2990                                 monitor, true, // canChangeResource (as per API contract)
2991                                 getResolvedClasspath(true), // ignoreUnresolvedVariable
2992                                 true, // needValidation
2993                                 true); // need to save
2994         }
2995
2996         /**
2997          * NOTE: <code>null</code> specifies default classpath, and an empty array
2998          * specifies an empty classpath.
2999          * 
3000          * @exception NotPresentException
3001          *                if this project does not exist.
3002          */
3003         // protected void setRawClasspath0(IClasspathEntry[] rawEntries)
3004         // throws JavaModelException {
3005         //
3006         // JavaModelManager.PerProjectInfo info =
3007         // JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project);
3008         //      
3009         // synchronized (info) {
3010         // if (rawEntries != null) {
3011         // info.classpath = rawEntries;
3012         // }
3013         //                      
3014         // // clear cache of resolved classpath
3015         // info.lastResolvedClasspath = null;
3016         // info.resolvedPathToRawEntries = null;
3017         // }
3018         // }
3019         /**
3020          * Record a shared persistent property onto a project. Note that it is
3021          * orthogonal to IResource persistent properties, and client code has to
3022          * decide which form of storage to use appropriately. Shared properties
3023          * produce real resource files which can be shared through a VCM onto a
3024          * server. Persistent properties are not shareable.
3025          * 
3026          * shared properties end up in resource files, and thus cannot be modified
3027          * during delta notifications (a CoreException would then be thrown).
3028          * 
3029          * @see JavaProject#getSharedProperty(String key)
3030          */
3031         public void setSharedProperty(String key, String value)
3032                         throws CoreException {
3033
3034                 IFile rscFile = getProject().getFile(key);
3035                 InputStream inputStream = new ByteArrayInputStream(value.getBytes());
3036                 // update the resource content
3037                 if (rscFile.exists()) {
3038                         if (rscFile.isReadOnly()) {
3039                                 // provide opportunity to checkout read-only .classpath file
3040                                 // (23984)
3041                                 ResourcesPlugin.getWorkspace().validateEdit(
3042                                                 new IFile[] { rscFile }, null);
3043                         }
3044                         rscFile.setContents(inputStream, IResource.FORCE, null);
3045                 } else {
3046                         rscFile.create(inputStream, IResource.FORCE, null);
3047                 }
3048         }
3049
3050         /**
3051          * Update cycle markers for all java projects
3052          */
3053         public static void updateAllCycleMarkers() throws JavaModelException {
3054
3055                 // long start = System.currentTimeMillis();
3056
3057                 JavaModelManager manager = JavaModelManager.getJavaModelManager();
3058                 IJavaProject[] projects = manager.getJavaModel().getJavaProjects();
3059                 IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
3060
3061                 HashSet cycleParticipants = new HashSet();
3062                 HashSet traversed = new HashSet();
3063                 int length = projects.length;
3064
3065                 // compute cycle participants
3066                 ArrayList prereqChain = new ArrayList();
3067                 for (int i = 0; i < length; i++) {
3068                         JavaProject project = (JavaProject) projects[i];
3069                         if (!traversed.contains(project.getPath())) {
3070                                 prereqChain.clear();
3071                                 project.updateCycleParticipants(null, prereqChain,
3072                                                 cycleParticipants, workspaceRoot, traversed);
3073                         }
3074                 }
3075                 // System.out.println("updateAllCycleMarkers: " +
3076                 // (System.currentTimeMillis() - start) + " ms");
3077
3078                 for (int i = 0; i < length; i++) {
3079                         JavaProject project = (JavaProject) projects[i];
3080
3081                         if (cycleParticipants.contains(project.getPath())) {
3082                                 IMarker cycleMarker = project.getCycleMarker();
3083                                 String circularCPOption = project.getOption(
3084                                                 JavaCore.CORE_CIRCULAR_CLASSPATH, true);
3085                                 int circularCPSeverity = JavaCore.ERROR
3086                                                 .equals(circularCPOption) ? IMarker.SEVERITY_ERROR
3087                                                 : IMarker.SEVERITY_WARNING;
3088                                 if (cycleMarker != null) {
3089                                         // update existing cycle marker if needed
3090                                         try {
3091                                                 int existingSeverity = ((Integer) cycleMarker
3092                                                                 .getAttribute(IMarker.SEVERITY)).intValue();
3093                                                 if (existingSeverity != circularCPSeverity) {
3094                                                         cycleMarker.setAttribute(IMarker.SEVERITY,
3095                                                                         circularCPSeverity);
3096                                                 }
3097                                         } catch (CoreException e) {
3098                                                 throw new JavaModelException(e);
3099                                         }
3100                                 } else {
3101                                         // create new marker
3102                                         project
3103                                                         .createClasspathProblemMarker(new JavaModelStatus(
3104                                                                         IJavaModelStatusConstants.CLASSPATH_CYCLE,
3105                                                                         project));
3106                                 }
3107                         } else {
3108                                 project.flushClasspathProblemMarkers(true, false);
3109                         }
3110                 }
3111         }
3112
3113         /**
3114          * If a cycle is detected, then cycleParticipants contains all the paths of
3115          * projects involved in this cycle (directly and indirectly), no cycle if
3116          * the set is empty (and started empty)
3117          */
3118         public void updateCycleParticipants(IClasspathEntry[] preferredClasspath,
3119                         ArrayList prereqChain, HashSet cycleParticipants,
3120                         IWorkspaceRoot workspaceRoot, HashSet traversed) {
3121
3122                 IPath path = this.getPath();
3123                 prereqChain.add(path);
3124                 traversed.add(path);
3125                 try {
3126                         IClasspathEntry[] classpath = preferredClasspath == null ? getResolvedClasspath(true)
3127                                         : preferredClasspath;
3128                         for (int i = 0, length = classpath.length; i < length; i++) {
3129                                 IClasspathEntry entry = classpath[i];
3130
3131                                 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
3132                                         IPath prereqProjectPath = entry.getPath();
3133                                         int index = cycleParticipants.contains(prereqProjectPath) ? 0
3134                                                         : prereqChain.indexOf(prereqProjectPath);
3135                                         if (index >= 0) { // refer to cycle, or in cycle itself
3136                                                 for (int size = prereqChain.size(); index < size; index++) {
3137                                                         cycleParticipants.add(prereqChain.get(index));
3138                                                 }
3139                                         } else {
3140                                                 if (!traversed.contains(prereqProjectPath)) {
3141                                                         IResource member = workspaceRoot
3142                                                                         .findMember(prereqProjectPath);
3143                                                         if (member != null
3144                                                                         && member.getType() == IResource.PROJECT) {
3145                                                                 JavaProject project = (JavaProject) JavaCore
3146                                                                                 .create((IProject) member);
3147                                                                 project.updateCycleParticipants(null,
3148                                                                                 prereqChain, cycleParticipants,
3149                                                                                 workspaceRoot, traversed);
3150                                                         }
3151                                                 }
3152                                         }
3153                                 }
3154                         }
3155                 } catch (JavaModelException e) {
3156                 }
3157                 prereqChain.remove(path);
3158         }
3159
3160         /**
3161          * Reset the collection of package fragment roots (local ones) - only if
3162          * opened. Need to check *all* package fragment roots in order to reset
3163          * NameLookup
3164          */
3165         public void updatePackageFragmentRoots() {
3166
3167                 if (this.isOpen()) {
3168                         try {
3169                                 JavaProjectElementInfo info = getJavaProjectElementInfo();
3170
3171                                 IClasspathEntry[] classpath = getResolvedClasspath(true);
3172                                 // NameLookup lookup = info.getNameLookup();
3173                                 // if (lookup != null){
3174                                 // IPackageFragmentRoot[] oldRoots =
3175                                 // lookup.fPackageFragmentRoots;
3176                                 // IPackageFragmentRoot[] newRoots =
3177                                 // computePackageFragmentRoots(classpath, true);
3178                                 // checkIdentical: { // compare all pkg fragment root lists
3179                                 // if (oldRoots.length == newRoots.length){
3180                                 // for (int i = 0, length = oldRoots.length; i < length; i++){
3181                                 // if (!oldRoots[i].equals(newRoots[i])){
3182                                 // break checkIdentical;
3183                                 // }
3184                                 // }
3185                                 // return; // no need to update
3186                                 // }
3187                                 // }
3188                                 // info.setNameLookup(null); // discard name lookup (hold onto
3189                                 // roots)
3190                                 // }
3191                                 info.setNonJavaResources(null);
3192                                 info.setChildren(computePackageFragmentRoots(classpath, false));
3193
3194                         } catch (JavaModelException e) {
3195                                 try {
3196                                         close(); // could not do better
3197                                 } catch (JavaModelException ex) {
3198                                 }
3199                         }
3200                 }
3201         }
3202
3203         public void removeLoadPathEntry(IProject anotherPHPProject) {
3204                 Iterator entries = getLoadPathEntries().iterator();
3205                 while (entries.hasNext()) {
3206                         LoadPathEntry entry = (LoadPathEntry) entries.next();
3207                         if (entry.getType() == LoadPathEntry.TYPE_PROJECT
3208                                         && entry.getProject().getName().equals(
3209                                                         anotherPHPProject.getName())) {
3210                                 getLoadPathEntries().remove(entry);
3211                                 fScratched = true;
3212                                 break;
3213                         }
3214                 }
3215         }
3216
3217         public void save() throws CoreException {
3218                 if (fScratched) {
3219                         InputStream xmlPath = new ByteArrayInputStream(getLoadPathXML()
3220                                         .getBytes());
3221                         IFile loadPathsFile = getLoadPathEntriesFile();
3222                         if (!loadPathsFile.exists())
3223                                 loadPathsFile.create(xmlPath, true, null);
3224                         else
3225                                 loadPathsFile.setContents(xmlPath, true, false, null);
3226
3227                         fScratched = false;
3228                 }
3229         }
3230
3231 }