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