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