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