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