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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
13 import java.io.BufferedInputStream;
14 import java.io.BufferedOutputStream;
15 import java.io.ByteArrayInputStream;
16 import java.io.ByteArrayOutputStream;
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;
33 import javax.xml.parsers.DocumentBuilder;
34 import javax.xml.parsers.DocumentBuilderFactory;
35 import javax.xml.parsers.ParserConfigurationException;
36 import javax.xml.parsers.SAXParserFactory;
38 import net.sourceforge.phpdt.core.IClasspathEntry;
39 import net.sourceforge.phpdt.core.IJavaElement;
40 import net.sourceforge.phpdt.core.IJavaModelMarker;
41 import net.sourceforge.phpdt.core.IJavaModelStatus;
42 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
43 import net.sourceforge.phpdt.core.IJavaProject;
44 import net.sourceforge.phpdt.core.IPackageFragment;
45 import net.sourceforge.phpdt.core.IPackageFragmentRoot;
46 import net.sourceforge.phpdt.core.JavaModelException;
47 import net.sourceforge.phpdt.core.JavaCore;
48 import net.sourceforge.phpdt.internal.codeassist.ISearchableNameEnvironment;
49 import net.sourceforge.phpdt.internal.compiler.util.ObjectVector;
50 import net.sourceforge.phpdt.internal.corext.Assert;
51 import net.sourceforge.phpeclipse.LoadPathEntry;
52 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
54 import org.apache.xerces.dom.DocumentImpl;
55 import org.apache.xml.serialize.Method;
56 import org.apache.xml.serialize.OutputFormat;
57 import org.apache.xml.serialize.Serializer;
58 import org.apache.xml.serialize.SerializerFactory;
59 import org.eclipse.core.resources.ICommand;
60 import org.eclipse.core.resources.IFile;
61 import org.eclipse.core.resources.IFolder;
62 import org.eclipse.core.resources.IMarker;
63 import org.eclipse.core.resources.IProject;
64 import org.eclipse.core.resources.IProjectDescription;
65 import org.eclipse.core.resources.IProjectNature;
66 import org.eclipse.core.resources.IResource;
67 import org.eclipse.core.resources.IWorkspace;
68 import org.eclipse.core.resources.IWorkspaceRoot;
69 import org.eclipse.core.resources.ResourcesPlugin;
70 import org.eclipse.core.runtime.CoreException;
71 import org.eclipse.core.runtime.IPath;
72 import org.eclipse.core.runtime.IProgressMonitor;
73 import org.eclipse.core.runtime.Path;
74 import org.eclipse.core.runtime.Preferences;
75 import org.eclipse.core.runtime.QualifiedName;
76 import org.w3c.dom.Document;
77 import org.w3c.dom.Element;
78 import org.w3c.dom.Node;
79 import org.w3c.dom.NodeList;
80 import org.xml.sax.Attributes;
81 import org.xml.sax.ContentHandler;
82 import org.xml.sax.InputSource;
83 import org.xml.sax.Locator;
84 import org.xml.sax.SAXException;
85 import org.xml.sax.XMLReader;
88 * Handle for a Java Project.
90 * <p>A Java Project internally maintains a devpath that corresponds
91 * to the project's classpath. The classpath may include source folders
92 * from the current project; jars in the current project, other projects,
93 * and the local file system; and binary folders (output location) of other
94 * projects. The Java Model presents source elements corresponding to output
95 * .class files in other projects, and thus uses the devpath rather than
96 * the classpath (which is really a compilation path). The devpath mimics
97 * the classpath, except has source folder entries in place of output
98 * locations in external projects.
100 * <p>Each JavaProject has a NameLookup facility that locates elements
101 * on by name, based on the devpath.
105 public class JavaProject
107 implements IJavaProject , IProjectNature {
110 * Whether the underlying file system is case sensitive.
112 protected static final boolean IS_CASE_SENSITIVE = !new File("Temp").equals(new File("temp")); //$NON-NLS-1$ //$NON-NLS-2$
115 * An empty array of strings indicating that a project doesn't have any prerequesite projects.
117 protected static final String[] NO_PREREQUISITES = new String[0];
120 * The platform project this <code>IJavaProject</code> is based on
122 protected IProject fProject;
123 protected List fLoadPathEntries;
124 protected boolean fScratched;
127 * Name of file containing project classpath
129 public static final String CLASSPATH_FILENAME = ".classpath"; //$NON-NLS-1$
132 * Name of file containing custom project preferences
134 public static final String PREF_FILENAME = ".jprefs"; //$NON-NLS-1$
137 * Value of the project's raw classpath if the .classpath file contains invalid entries.
139 public static final IClasspathEntry[] INVALID_CLASSPATH = new IClasspathEntry[0];
141 private static final String CUSTOM_DEFAULT_OPTION_VALUE = "#\r\n\r#custom-non-empty-default-value#\r\n\r#"; //$NON-NLS-1$
144 * Returns a canonicalized path from the given external path.
145 * Note that the return path contains the same number of segments
146 * and it contains a device only if the given path contained one.
147 * @see java.io.File for the definition of a canonicalized path
149 public static IPath canonicalizedPath(IPath externalPath) {
151 if (externalPath == null)
154 if (JavaModelManager.VERBOSE) {
155 System.out.println("JAVA MODEL - Canonicalizing " + externalPath.toString()); //$NON-NLS-1$
158 if (IS_CASE_SENSITIVE) {
159 if (JavaModelManager.VERBOSE) {
160 System.out.println("JAVA MODEL - Canonical path is original path (file system is case sensitive)"); //$NON-NLS-1$
165 // if not external path, return original path
166 IWorkspace workspace = ResourcesPlugin.getWorkspace();
167 if (workspace == null) return externalPath; // protection during shutdown (30487)
168 if (workspace.getRoot().findMember(externalPath) != null) {
169 if (JavaModelManager.VERBOSE) {
170 System.out.println("JAVA MODEL - Canonical path is original path (member of workspace)"); //$NON-NLS-1$
175 IPath canonicalPath = null;
178 new Path(new File(externalPath.toOSString()).getCanonicalPath());
179 } catch (IOException e) {
180 // default to original path
181 if (JavaModelManager.VERBOSE) {
182 System.out.println("JAVA MODEL - Canonical path is original path (IOException)"); //$NON-NLS-1$
188 int canonicalLength = canonicalPath.segmentCount();
189 if (canonicalLength == 0) {
190 // the java.io.File canonicalization failed
191 if (JavaModelManager.VERBOSE) {
192 System.out.println("JAVA MODEL - Canonical path is original path (canonical path is empty)"); //$NON-NLS-1$
195 } else if (externalPath.isAbsolute()) {
196 result = canonicalPath;
198 // if path is relative, remove the first segments that were added by the java.io.File canonicalization
199 // e.g. 'lib/classes.zip' was converted to 'd:/myfolder/lib/classes.zip'
200 int externalLength = externalPath.segmentCount();
201 if (canonicalLength >= externalLength) {
202 result = canonicalPath.removeFirstSegments(canonicalLength - externalLength);
204 if (JavaModelManager.VERBOSE) {
205 System.out.println("JAVA MODEL - Canonical path is original path (canonical path is " + canonicalPath.toString() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
211 // keep device only if it was specified (this is because File.getCanonicalPath() converts '/lib/classed.zip' to 'd:/lib/classes/zip')
212 if (externalPath.getDevice() == null) {
213 result = result.setDevice(null);
215 if (JavaModelManager.VERBOSE) {
216 System.out.println("JAVA MODEL - Canonical path is " + result.toString()); //$NON-NLS-1$
222 * Constructor needed for <code>IProject.getNature()</code> and <code>IProject.addNature()</code>.
226 public JavaProject() {
227 super(JAVA_PROJECT, null, null);
230 public JavaProject(IProject project, IJavaElement parent) {
231 super(JAVA_PROJECT, parent, project.getName());
234 public void addLoadPathEntry(IProject anotherPHPProject) {
237 LoadPathEntry newEntry = new LoadPathEntry(anotherPHPProject);
238 getLoadPathEntries().add(newEntry);
241 public void configure() throws CoreException {
242 // get project description and then the associated build commands
243 IProjectDescription desc = fProject.getDescription();
244 ICommand[] commands = desc.getBuildSpec();
246 // determine if builder already associated
247 boolean found = false;
248 for (int i = 0; i < commands.length; ++i) {
249 if (commands[i].getBuilderName().equals(PHPeclipsePlugin.BUILDER_PARSER_ID)) {
255 // add builder if not already in project
257 ICommand command = desc.newCommand();
258 command.setBuilderName(PHPeclipsePlugin.BUILDER_PARSER_ID);
259 ICommand[] newCommands = new ICommand[commands.length + 1];
261 // Add it before other builders.
262 System.arraycopy(commands, 0, newCommands, 1, commands.length);
263 newCommands[0] = command;
264 desc.setBuildSpec(newCommands);
265 fProject.setDescription(desc, null);
269 protected void loadLoadPathEntries() {
270 fLoadPathEntries = new ArrayList();
272 IFile loadPathsFile = getLoadPathEntriesFile();
274 XMLReader reader = null;
276 reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
277 reader.setContentHandler(getLoadPathEntriesContentHandler());
278 reader.parse(new InputSource(loadPathsFile.getContents()));
279 } catch (Exception e) {
280 //the file is nonextant or unreadable
284 public List getLoadPathEntries() {
285 if (fLoadPathEntries == null) {
286 loadLoadPathEntries();
289 return fLoadPathEntries;
292 protected ContentHandler getLoadPathEntriesContentHandler() {
293 return new ContentHandler() {
294 public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
297 public void endDocument() throws SAXException {
300 public void endElement(String arg0, String arg1, String arg2) throws SAXException {
303 public void endPrefixMapping(String arg0) throws SAXException {
306 public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {
309 public void processingInstruction(String arg0, String arg1) throws SAXException {
312 public void setDocumentLocator(Locator arg0) {
315 public void skippedEntity(String arg0) throws SAXException {
318 public void startDocument() throws SAXException {
321 public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
322 if ("pathentry".equals(qName))
323 if ("project".equals(atts.getValue("type"))) {
324 IPath referencedProjectPath = new Path(atts.getValue("path"));
325 IProject referencedProject = getProject(referencedProjectPath.lastSegment());
326 fLoadPathEntries.add(new LoadPathEntry(referencedProject));
330 public void startPrefixMapping(String arg0, String arg1) throws SAXException {
335 protected IFile getLoadPathEntriesFile() {
336 return fProject.getFile(".loadpath");
339 protected String getLoadPathXML() {
340 StringBuffer buffer = new StringBuffer();
341 buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><loadpath>");
343 Iterator pathEntriesIterator = fLoadPathEntries.iterator();
345 while (pathEntriesIterator.hasNext()) {
346 LoadPathEntry entry = (LoadPathEntry) pathEntriesIterator.next();
347 buffer.append(entry.toXML());
350 buffer.append("</loadpath>");
351 return buffer.toString();
354 * Adds a builder to the build spec for the given project.
356 protected void addToBuildSpec(String builderID) throws CoreException {
358 IProjectDescription description = getProject().getDescription();
359 ICommand javaCommand = getJavaCommand(description);
361 if (javaCommand == null) {
363 // Add a Java command to the build spec
364 ICommand command = description.newCommand();
365 command.setBuilderName(builderID);
366 setJavaCommand(description, command);
370 protected void closing(Object info) throws JavaModelException {
372 // forget source attachment recommendations
373 IPackageFragmentRoot[] roots = this.getPackageFragmentRoots();
374 // for (int i = 0; i < roots.length; i++) {
375 // if (roots[i] instanceof JarPackageFragmentRoot){
376 // ((JarPackageFragmentRoot) roots[i]).setSourceAttachmentProperty(null);
386 * Internal computation of an expanded classpath. It will eliminate duplicates, and produce copies
387 * of exported classpath entries to avoid possible side-effects ever after.
389 private void computeExpandedClasspath(
390 JavaProject initialProject,
391 boolean ignoreUnresolvedVariable,
392 boolean generateMarkerOnError,
393 HashSet visitedProjects,
394 ObjectVector accumulatedEntries) throws JavaModelException {
396 if (visitedProjects.contains(this)){
397 return; // break cycles if any
399 visitedProjects.add(this);
401 if (generateMarkerOnError && !this.equals(initialProject)){
402 generateMarkerOnError = false;
404 IClasspathEntry[] immediateClasspath =
405 getResolvedClasspath(ignoreUnresolvedVariable, generateMarkerOnError);
407 IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
408 for (int i = 0, length = immediateClasspath.length; i < length; i++){
409 IClasspathEntry entry = immediateClasspath[i];
411 boolean isInitialProject = this.equals(initialProject);
412 if (isInitialProject || entry.isExported()){
414 accumulatedEntries.add(entry);
416 // recurse in project to get all its indirect exports (only consider exported entries from there on)
417 if (entry.getEntryKind() == ClasspathEntry.CPE_PROJECT) {
418 IResource member = workspaceRoot.findMember(entry.getPath());
419 if (member != null && member.getType() == IResource.PROJECT){ // double check if bound to project (23977)
420 IProject projRsc = (IProject) member;
421 if (JavaProject.hasJavaNature(projRsc)) {
422 JavaProject project = (JavaProject) JavaCore.create(projRsc);
423 project.computeExpandedClasspath(
425 ignoreUnresolvedVariable,
426 generateMarkerOnError,
437 * Returns (local/all) the package fragment roots identified by the given project's classpath.
438 * Note: this follows project classpath references to find required project contributions,
439 * eliminating duplicates silently.
440 * Only works with resolved entries
442 public IPackageFragmentRoot[] computePackageFragmentRoots(IClasspathEntry[] resolvedClasspath, boolean retrieveExportedRoots) throws JavaModelException {
444 ObjectVector accumulatedRoots = new ObjectVector();
445 computePackageFragmentRoots(
448 new HashSet(5), // rootIDs
449 true, // inside original project
450 true, // check existency
451 retrieveExportedRoots);
452 IPackageFragmentRoot[] rootArray = new IPackageFragmentRoot[accumulatedRoots.size()];
453 accumulatedRoots.copyInto(rootArray);
458 * Computes the package fragment roots identified by the given entry.
459 * Only works with resolved entry
461 public IPackageFragmentRoot[] computePackageFragmentRoots(IClasspathEntry resolvedEntry) {
464 computePackageFragmentRoots(
465 new IClasspathEntry[]{ resolvedEntry },
466 false // don't retrieve exported roots
468 } catch (JavaModelException e) {
469 return new IPackageFragmentRoot[] {};
474 * Returns the package fragment roots identified by the given entry. In case it refers to
475 * a project, it will follow its classpath so as to find exported roots as well.
476 * Only works with resolved entry
478 public void computePackageFragmentRoots(
479 IClasspathEntry resolvedEntry,
480 ObjectVector accumulatedRoots,
482 boolean insideOriginalProject,
483 boolean checkExistency,
484 boolean retrieveExportedRoots) throws JavaModelException {
486 String rootID = ((ClasspathEntry)resolvedEntry).rootID();
487 if (rootIDs.contains(rootID)) return;
489 IPath projectPath = getProject().getFullPath();
490 IPath entryPath = resolvedEntry.getPath();
491 IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
493 switch(resolvedEntry.getEntryKind()){
496 case IClasspathEntry.CPE_SOURCE :
498 if (projectPath.isPrefixOf(entryPath)){
499 if (checkExistency) {
500 Object target = JavaModel.getTarget(workspaceRoot, entryPath, checkExistency);
501 if (target == null) return;
503 if (target instanceof IFolder || target instanceof IProject){
504 accumulatedRoots.add(
505 getPackageFragmentRoot((IResource)target));
509 IPackageFragmentRoot root = getFolderPackageFragmentRoot(entryPath);
511 accumulatedRoots.add(root);
518 // internal/external JAR or folder
519 case IClasspathEntry.CPE_LIBRARY :
521 if (!insideOriginalProject && !resolvedEntry.isExported()) return;
523 if (checkExistency) {
524 Object target = JavaModel.getTarget(workspaceRoot, entryPath, checkExistency);
525 if (target == null) return;
527 if (target instanceof IResource){
529 IResource resource = (IResource) target;
530 IPackageFragmentRoot root = getPackageFragmentRoot(resource);
532 accumulatedRoots.add(root);
536 // external target - only JARs allowed
537 // if (((java.io.File)target).isFile() && (Util.isArchiveFileName(entryPath.lastSegment()))) {
538 // accumulatedRoots.add(
539 // new JarPackageFragmentRoot(entryPath, this));
540 // rootIDs.add(rootID);
544 IPackageFragmentRoot root = getPackageFragmentRoot(entryPath);
546 accumulatedRoots.add(root);
552 // recurse into required project
553 case IClasspathEntry.CPE_PROJECT :
555 if (!retrieveExportedRoots) return;
556 if (!insideOriginalProject && !resolvedEntry.isExported()) return;
558 IResource member = workspaceRoot.findMember(entryPath);
559 if (member != null && member.getType() == IResource.PROJECT){// double check if bound to project (23977)
560 IProject requiredProjectRsc = (IProject) member;
561 if (JavaProject.hasJavaNature(requiredProjectRsc)){ // special builder binary output
563 JavaProject requiredProject = (JavaProject)JavaCore.create(requiredProjectRsc);
564 requiredProject.computePackageFragmentRoots(
565 requiredProject.getResolvedClasspath(true),
570 retrieveExportedRoots);
578 * Returns (local/all) the package fragment roots identified by the given project's classpath.
579 * Note: this follows project classpath references to find required project contributions,
580 * eliminating duplicates silently.
581 * Only works with resolved entries
583 public void computePackageFragmentRoots(
584 IClasspathEntry[] resolvedClasspath,
585 ObjectVector accumulatedRoots,
587 boolean insideOriginalProject,
588 boolean checkExistency,
589 boolean retrieveExportedRoots) throws JavaModelException {
591 if (insideOriginalProject){
592 rootIDs.add(rootID());
594 for (int i = 0, length = resolvedClasspath.length; i < length; i++){
595 computePackageFragmentRoots(
596 resolvedClasspath[i],
599 insideOriginalProject,
601 retrieveExportedRoots);
606 * Compute the file name to use for a given shared property
608 public String computeSharedPropertyFileName(QualifiedName qName) {
610 return '.' + qName.getLocalName();
614 * Returns whether the given resource is accessible through the children or the non-Java resources of this project.
615 * Returns true if the resource is not in the project.
616 * Assumes that the resource is a folder or a file.
618 public boolean contains(IResource resource) {
620 IClasspathEntry[] classpath;
623 classpath = getResolvedClasspath(true);
624 output = getOutputLocation();
625 } catch (JavaModelException e) {
629 IPath fullPath = resource.getFullPath();
630 IPath innerMostOutput = output.isPrefixOf(fullPath) ? output : null;
631 IClasspathEntry innerMostEntry = null;
632 for (int j = 0, cpLength = classpath.length; j < cpLength; j++) {
633 IClasspathEntry entry = classpath[j];
635 IPath entryPath = entry.getPath();
636 if ((innerMostEntry == null || innerMostEntry.getPath().isPrefixOf(entryPath))
637 && entryPath.isPrefixOf(fullPath)) {
638 innerMostEntry = entry;
640 IPath entryOutput = classpath[j].getOutputLocation();
641 if (entryOutput != null && entryOutput.isPrefixOf(fullPath)) {
642 innerMostOutput = entryOutput;
645 if (innerMostEntry != null) {
646 // special case prj==src and nested output location
647 if (innerMostOutput != null && innerMostOutput.segmentCount() > 1 // output isn't project
648 && innerMostEntry.getPath().segmentCount() == 1) { // 1 segment must be project name
651 if (resource instanceof IFolder) {
652 // folders are always included in src/lib entries
655 switch (innerMostEntry.getEntryKind()) {
656 case IClasspathEntry.CPE_SOURCE:
657 // .class files are not visible in source folders
658 return true; //!Util.isClassFileName(fullPath.lastSegment());
659 case IClasspathEntry.CPE_LIBRARY:
660 // .java files are not visible in library folders
661 return !Util.isJavaFileName(fullPath.lastSegment());
664 if (innerMostOutput != null) {
671 * Record a new marker denoting a classpath problem
673 IMarker createClasspathProblemMarker(IJavaModelStatus status) {
675 IMarker marker = null;
677 String[] arguments = new String[0];
678 boolean isCycleProblem = false, isClasspathFileFormatProblem = false;
679 switch (status.getCode()) {
681 case IJavaModelStatusConstants.CLASSPATH_CYCLE :
682 isCycleProblem = true;
683 if (JavaCore.ERROR.equals(getOption(JavaCore.CORE_CIRCULAR_CLASSPATH, true))) {
684 severity = IMarker.SEVERITY_ERROR;
686 severity = IMarker.SEVERITY_WARNING;
690 case IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT :
691 isClasspathFileFormatProblem = true;
692 severity = IMarker.SEVERITY_ERROR;
696 IPath path = status.getPath();
697 if (path != null) arguments = new String[] { path.toString() };
698 if (JavaCore.ERROR.equals(getOption(JavaCore.CORE_INCOMPLETE_CLASSPATH, true))) {
699 severity = IMarker.SEVERITY_ERROR;
701 severity = IMarker.SEVERITY_WARNING;
707 marker = getProject().createMarker(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER);
708 marker.setAttributes(
713 IJavaModelMarker.CYCLE_DETECTED,
714 IJavaModelMarker.CLASSPATH_FILE_FORMAT,
716 IJavaModelMarker.ARGUMENTS ,
720 new Integer(severity),
721 Util.bind("classpath.buildPath"),//$NON-NLS-1$
722 isCycleProblem ? "true" : "false",//$NON-NLS-1$ //$NON-NLS-2$
723 isClasspathFileFormatProblem ? "true" : "false",//$NON-NLS-1$ //$NON-NLS-2$
724 new Integer(status.getCode()),
725 Util.getProblemArgumentsForMarker(arguments) ,
728 } catch (CoreException e) {
734 * Returns a new element info for this element.
736 protected OpenableElementInfo createElementInfo() {
738 return new JavaProjectElementInfo();
742 * Reads and decode an XML classpath string
744 protected IClasspathEntry[] decodeClasspath(String xmlClasspath, boolean createMarker, boolean logProblems) {
746 ArrayList paths = new ArrayList();
747 IClasspathEntry defaultOutput = null;
749 if (xmlClasspath == null) return null;
750 StringReader reader = new StringReader(xmlClasspath);
754 DocumentBuilder parser =
755 DocumentBuilderFactory.newInstance().newDocumentBuilder();
756 cpElement = parser.parse(new InputSource(reader)).getDocumentElement();
757 } catch (SAXException e) {
758 throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$
759 } catch (ParserConfigurationException e) {
760 throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$
765 if (!cpElement.getNodeName().equalsIgnoreCase("classpath")) { //$NON-NLS-1$
766 throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$
768 NodeList list = cpElement.getElementsByTagName("classpathentry"); //$NON-NLS-1$
769 int length = list.getLength();
771 for (int i = 0; i < length; ++i) {
772 Node node = list.item(i);
773 if (node.getNodeType() == Node.ELEMENT_NODE) {
774 IClasspathEntry entry = ClasspathEntry.elementDecode((Element)node, this);
776 if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
777 defaultOutput = entry; // separate output
784 } catch (IOException e) {
786 if (createMarker && this.getProject().isAccessible()) {
787 this.createClasspathProblemMarker(new JavaModelStatus(
788 IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
789 Util.bind("classpath.xmlFormatError", this.getElementName(), e.getMessage()))); //$NON-NLS-1$
793 "Exception while retrieving "+ this.getPath() //$NON-NLS-1$
794 +"/.classpath, will mark classpath as invalid"); //$NON-NLS-1$
796 return INVALID_CLASSPATH;
797 } catch (Assert.AssertionFailedException e) {
798 // failed creating CP entries from file
799 if (createMarker && this.getProject().isAccessible()) {
800 this.createClasspathProblemMarker(new JavaModelStatus(
801 IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
802 Util.bind("classpath.illegalEntryInClasspathFile", this.getElementName(), e.getMessage()))); //$NON-NLS-1$
806 "Exception while retrieving "+ this.getPath() //$NON-NLS-1$
807 +"/.classpath, will mark classpath as invalid"); //$NON-NLS-1$
809 return INVALID_CLASSPATH;
811 int pathSize = paths.size();
812 if (pathSize > 0 || defaultOutput != null) {
813 IClasspathEntry[] entries = new IClasspathEntry[pathSize + (defaultOutput == null ? 0 : 1)];
814 paths.toArray(entries);
815 if (defaultOutput != null) entries[pathSize] = defaultOutput; // ensure output is last item
824 * Removes the Java nature from the project.
826 public void deconfigure() throws CoreException {
828 // deregister Java builder
829 removeFromBuildSpec(PHPeclipsePlugin.BUILDER_PARSER_ID);
833 * Returns a default class path.
834 * This is the root of the project
836 protected IClasspathEntry[] defaultClasspath() throws JavaModelException {
838 return new IClasspathEntry[] {
839 JavaCore.newSourceEntry(getProject().getFullPath())};
843 * Returns a default output location.
844 * This is the project bin folder
846 protected IPath defaultOutputLocation() throws JavaModelException {
847 return getProject().getFullPath().append("bin"); //$NON-NLS-1$
851 * Returns the XML String encoding of the class path.
853 protected String encodeClasspath(IClasspathEntry[] classpath, IPath outputLocation, boolean useLineSeparator) throws JavaModelException {
855 Document document = new DocumentImpl();
856 Element cpElement = document.createElement("classpath"); //$NON-NLS-1$
857 document.appendChild(cpElement);
859 for (int i = 0; i < classpath.length; ++i) {
860 cpElement.appendChild(((ClasspathEntry)classpath[i]).elementEncode(document, getProject().getFullPath()));
863 if (outputLocation != null) {
864 outputLocation = outputLocation.removeFirstSegments(1);
865 outputLocation = outputLocation.makeRelative();
866 Element oElement = document.createElement("classpathentry"); //$NON-NLS-1$
867 oElement.setAttribute("kind", ClasspathEntry.kindToString(ClasspathEntry.K_OUTPUT)); //$NON-NLS-1$
868 oElement.setAttribute("path", outputLocation.toString()); //$NON-NLS-1$
869 cpElement.appendChild(oElement);
872 // produce a String output
874 ByteArrayOutputStream s = new ByteArrayOutputStream();
875 OutputFormat format = new OutputFormat();
876 if (useLineSeparator) {
877 format.setIndenting(true);
878 format.setLineSeparator(System.getProperty("line.separator")); //$NON-NLS-1$
880 format.setPreserveSpace(true);
882 Serializer serializer =
883 SerializerFactory.getSerializerFactory(Method.XML).makeSerializer(
884 new OutputStreamWriter(s, "UTF8"), //$NON-NLS-1$
886 serializer.asDOMSerializer().serialize(document);
887 return s.toString("UTF8"); //$NON-NLS-1$
888 } catch (IOException e) {
889 throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
894 * Returns true if this handle represents the same Java project
895 * as the given handle. Two handles represent the same
896 * project if they are identical or if they represent a project with
897 * the same underlying resource and occurrence counts.
899 * @see JavaElement#equals
901 public boolean equals(Object o) {
906 if (!(o instanceof JavaProject))
909 JavaProject other = (JavaProject) o;
910 return getProject().equals(other.getProject())
911 && fOccurrenceCount == other.fOccurrenceCount;
914 public boolean exists() {
915 if (!hasJavaNature(fProject)) return false;
916 return super.exists();
922 public IJavaElement findElement(IPath path) throws JavaModelException {
924 if (path == null || path.isAbsolute()) {
925 throw new JavaModelException(
926 new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, path));
930 String extension = path.getFileExtension();
931 if (extension == null) {
932 String packageName = path.toString().replace(IPath.SEPARATOR, '.');
934 // IPackageFragment[] pkgFragments =
935 // getNameLookup().findPackageFragments(packageName, false);
936 // if (pkgFragments == null) {
940 // // try to return one that is a child of this project
941 // for (int i = 0, length = pkgFragments.length; i < length; i++) {
943 // IPackageFragment pkgFragment = pkgFragments[i];
944 // if (this.equals(pkgFragment.getParent().getParent())) {
945 // return pkgFragment;
948 // // default to the first one
949 // return pkgFragments[0];
952 extension.equalsIgnoreCase("java") //$NON-NLS-1$
953 || extension.equalsIgnoreCase("class")) { //$NON-NLS-1$
954 IPath packagePath = path.removeLastSegments(1);
955 String packageName = packagePath.toString().replace(IPath.SEPARATOR, '.');
956 String typeName = path.lastSegment();
957 typeName = typeName.substring(0, typeName.length() - extension.length() - 1);
958 String qualifiedName = null;
959 if (packageName.length() > 0) {
960 qualifiedName = packageName + "." + typeName; //$NON-NLS-1$
962 qualifiedName = typeName;
965 // getNameLookup().findType(
968 // NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
969 // if (type != null) {
970 // return type.getParent();
975 // unsupported extension
978 // } catch (JavaModelException e) {
979 // if (e.getStatus().getCode()
980 // == IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST) {
991 // public IPackageFragment findPackageFragment(IPath path)
992 // throws JavaModelException {
994 // return findPackageFragment0(JavaProject.canonicalizedPath(path));
998 // * non path canonicalizing version
1000 // public IPackageFragment findPackageFragment0(IPath path)
1001 // throws JavaModelException {
1003 // return getNameLookup().findPackageFragment(path);
1009 public IPackageFragmentRoot findPackageFragmentRoot(IPath path)
1010 throws JavaModelException {
1012 return findPackageFragmentRoot0(JavaProject.canonicalizedPath(path));
1016 * no path canonicalization
1018 public IPackageFragmentRoot findPackageFragmentRoot0(IPath path)
1019 throws JavaModelException {
1021 IPackageFragmentRoot[] allRoots = this.getAllPackageFragmentRoots();
1022 if (!path.isAbsolute()) {
1023 throw new IllegalArgumentException(Util.bind("path.mustBeAbsolute")); //$NON-NLS-1$
1025 for (int i= 0; i < allRoots.length; i++) {
1026 IPackageFragmentRoot classpathRoot= allRoots[i];
1027 if (classpathRoot.getPath().equals(path)) {
1028 return classpathRoot;
1036 public IPackageFragmentRoot[] findPackageFragmentRoots(IClasspathEntry entry) {
1038 IClasspathEntry[] classpath = this.getRawClasspath();
1039 for (int i = 0, length = classpath.length; i < length; i++) {
1040 if (classpath[i].equals(entry)) { // entry may need to be resolved
1042 computePackageFragmentRoots(
1043 getResolvedClasspath(new IClasspathEntry[] {entry}, null, true, false, null/*no reverse map*/),
1044 false); // don't retrieve exported roots
1047 } catch (JavaModelException e) {
1049 return new IPackageFragmentRoot[] {};
1053 * @see IJavaProject#findType(String)
1055 // public IType findType(String fullyQualifiedName) throws JavaModelException {
1057 // this.getNameLookup().findType(
1058 // fullyQualifiedName,
1060 // NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
1061 // if (type == null) {
1062 // // try to find enclosing type
1063 // int lastDot = fullyQualifiedName.lastIndexOf('.');
1064 // if (lastDot == -1) return null;
1065 // type = this.findType(fullyQualifiedName.substring(0, lastDot));
1066 // if (type != null) {
1067 // type = type.getType(fullyQualifiedName.substring(lastDot+1));
1068 // if (!type.exists()) {
1077 * @see IJavaProject#findType(String, String)
1079 // public IType findType(String packageName, String typeQualifiedName) throws JavaModelException {
1081 // this.getNameLookup().findType(
1082 // typeQualifiedName,
1085 // NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
1089 * Remove all markers denoting classpath problems
1091 protected void flushClasspathProblemMarkers(boolean flushCycleMarkers, boolean flushClasspathFormatMarkers) {
1093 IProject project = getProject();
1094 if (project.exists()) {
1095 IMarker[] markers = project.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
1096 for (int i = 0, length = markers.length; i < length; i++) {
1097 IMarker marker = markers[i];
1098 if (flushCycleMarkers && flushClasspathFormatMarkers) {
1101 String cycleAttr = (String)marker.getAttribute(IJavaModelMarker.CYCLE_DETECTED);
1102 String classpathFileFormatAttr = (String)marker.getAttribute(IJavaModelMarker.CLASSPATH_FILE_FORMAT);
1103 if ((flushCycleMarkers == (cycleAttr != null && cycleAttr.equals("true"))) //$NON-NLS-1$
1104 && (flushClasspathFormatMarkers == (classpathFileFormatAttr != null && classpathFileFormatAttr.equals("true")))){ //$NON-NLS-1$
1110 } catch (CoreException e) {
1117 protected boolean generateInfos(
1118 OpenableElementInfo info,
1119 IProgressMonitor pm,
1121 IResource underlyingResource) throws JavaModelException {
1123 boolean validInfo = false;
1125 if (getProject().isOpen()) {
1126 // put the info now, because computing the roots requires it
1127 JavaModelManager.getJavaModelManager().putInfo(this, info);
1129 // compute the pkg fragment roots
1130 updatePackageFragmentRoots();
1132 // remember the timestamps of external libraries the first time they are looked up
1133 IClasspathEntry[] resolvedClasspath = getResolvedClasspath(true/*ignore unresolved variable*/);
1134 for (int i = 0, length = resolvedClasspath.length; i < length; i++) {
1135 IClasspathEntry entry = resolvedClasspath[i];
1136 if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
1137 IPath path = entry.getPath();
1138 Object target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), path, true);
1139 if (target instanceof java.io.File) {
1140 Map externalTimeStamps = JavaModelManager.getJavaModelManager().deltaProcessor.externalTimeStamps;
1141 if (externalTimeStamps.get(path) == null) {
1142 long timestamp = DeltaProcessor.getTimeStamp((java.io.File)target);
1143 externalTimeStamps.put(path, new Long(timestamp));
1149 // only valid if reaches here
1154 JavaModelManager.getJavaModelManager().removeInfo(this);
1162 public IPackageFragmentRoot[] getAllPackageFragmentRoots()
1163 throws JavaModelException {
1165 return computePackageFragmentRoots(getResolvedClasspath(true), true);
1169 * Returns the classpath entry that refers to the given path
1170 * or <code>null</code> if there is no reference to the path.
1172 public IClasspathEntry getClasspathEntryFor(IPath path)
1173 throws JavaModelException {
1175 IClasspathEntry[] entries = getExpandedClasspath(true);
1176 for (int i = 0; i < entries.length; i++) {
1177 if (entries[i].getPath().equals(path)) {
1185 * Returns the cycle marker associated with this project or null if none.
1187 public IMarker getCycleMarker(){
1189 IProject project = getProject();
1190 if (project.exists()) {
1191 IMarker[] markers = project.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
1192 for (int i = 0, length = markers.length; i < length; i++) {
1193 IMarker marker = markers[i];
1194 String cycleAttr = (String)marker.getAttribute(IJavaModelMarker.CYCLE_DETECTED);
1195 if (cycleAttr != null && cycleAttr.equals("true")){ //$NON-NLS-1$
1200 } catch (CoreException e) {
1206 * This is a helper method returning the expanded classpath for the project, as a list of classpath entries,
1207 * where all classpath variable entries have been resolved and substituted with their final target entries.
1208 * All project exports have been appended to project entries.
1210 public IClasspathEntry[] getExpandedClasspath(boolean ignoreUnresolvedVariable) throws JavaModelException {
1212 return getExpandedClasspath(ignoreUnresolvedVariable, false);
1216 * Internal variant which can create marker on project for invalid entries,
1217 * it will also perform classpath expansion in presence of project prerequisites
1218 * exporting their entries.
1220 public IClasspathEntry[] getExpandedClasspath(
1221 boolean ignoreUnresolvedVariable,
1222 boolean generateMarkerOnError) throws JavaModelException {
1224 ObjectVector accumulatedEntries = new ObjectVector();
1225 computeExpandedClasspath(this, ignoreUnresolvedVariable, generateMarkerOnError, new HashSet(5), accumulatedEntries);
1227 IClasspathEntry[] expandedPath = new IClasspathEntry[accumulatedEntries.size()];
1228 accumulatedEntries.copyInto(expandedPath);
1230 return expandedPath;
1234 * Returns the <code>char</code> that marks the start of this handles
1235 * contribution to a memento.
1237 protected char getHandleMementoDelimiter() {
1239 return JEM_JAVAPROJECT;
1243 * Find the specific Java command amongst the build spec of a given description
1245 private ICommand getJavaCommand(IProjectDescription description)
1246 throws CoreException {
1248 ICommand[] commands = description.getBuildSpec();
1249 for (int i = 0; i < commands.length; ++i) {
1250 if (commands[i].getBuilderName().equals(PHPeclipsePlugin.BUILDER_PARSER_ID)) {
1258 * Convenience method that returns the specific type of info for a Java project.
1260 protected JavaProjectElementInfo getJavaProjectElementInfo()
1261 throws JavaModelException {
1263 return (JavaProjectElementInfo) getElementInfo();
1269 public NameLookup getNameLookup() throws JavaModelException {
1271 JavaProjectElementInfo info = getJavaProjectElementInfo();
1272 // lock on the project info to avoid race condition
1274 NameLookup nameLookup;
1275 if ((nameLookup = info.getNameLookup()) == null){
1276 info.setNameLookup(nameLookup = new NameLookup(this));
1283 // * Returns an array of non-java resources contained in the receiver.
1285 // public Object[] getNonJavaResources() throws JavaModelException {
1287 // return ((JavaProjectElementInfo) getElementInfo()).getNonJavaResources(this);
1291 * @see org.eclipse.jdt.core.IJavaProject#getOption(String, boolean)
1293 public String getOption(String optionName, boolean inheritJavaCoreOptions) {
1295 if (JavaModelManager.OptionNames.contains(optionName)){
1297 Preferences preferences = getPreferences();
1298 if (preferences == null || preferences.isDefault(optionName)) {
1299 return inheritJavaCoreOptions ? JavaCore.getOption(optionName) : null;
1301 return preferences.getString(optionName).trim();
1307 * @see org.eclipse.jdt.core.IJavaProject#getOptions(boolean)
1309 public Map getOptions(boolean inheritJavaCoreOptions) {
1311 // initialize to the defaults from JavaCore options pool
1312 Map options = inheritJavaCoreOptions ? JavaCore.getOptions() : new Hashtable(5);
1314 Preferences preferences = getPreferences();
1315 if (preferences == null) return options; // cannot do better (non-Java project)
1316 HashSet optionNames = JavaModelManager.OptionNames;
1318 // get preferences set to their default
1319 if (inheritJavaCoreOptions){
1320 String[] defaultPropertyNames = preferences.defaultPropertyNames();
1321 for (int i = 0; i < defaultPropertyNames.length; i++){
1322 String propertyName = defaultPropertyNames[i];
1323 if (optionNames.contains(propertyName)){
1324 options.put(propertyName, preferences.getDefaultString(propertyName).trim());
1328 // get custom preferences not set to their default
1329 String[] propertyNames = preferences.propertyNames();
1330 for (int i = 0; i < propertyNames.length; i++){
1331 String propertyName = propertyNames[i];
1332 if (optionNames.contains(propertyName)){
1333 options.put(propertyName, preferences.getString(propertyName).trim());
1342 public IPath getOutputLocation() throws JavaModelException {
1344 JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(fProject);
1345 IPath outputLocation = perProjectInfo.outputLocation;
1346 if (outputLocation != null) return outputLocation;
1348 // force to read classpath - will position output location as well
1349 this.getRawClasspath();
1350 outputLocation = perProjectInfo.outputLocation;
1351 if (outputLocation == null) {
1352 return defaultOutputLocation();
1354 return outputLocation;
1358 * @return A handle to the package fragment root identified by the given path.
1359 * This method is handle-only and the element may or may not exist. Returns
1360 * <code>null</code> if unable to generate a handle from the path (for example,
1361 * an absolute path that has less than 1 segment. The path may be relative or
1364 public IPackageFragmentRoot getPackageFragmentRoot(IPath path) {
1365 if (!path.isAbsolute()) {
1366 path = getPath().append(path);
1368 int segmentCount = path.segmentCount();
1369 switch (segmentCount) {
1374 return getPackageFragmentRoot(getProject());
1376 // a path ending with .jar/.zip is still ambiguous and could still resolve to a source/lib folder
1377 // thus will try to guess based on existing resource
1378 // if (Util.isArchiveFileName(path.lastSegment())) {
1379 // IResource resource = getProject().getWorkspace().getRoot().findMember(path);
1380 // if (resource != null && resource.getType() == IResource.FOLDER){
1381 // return getPackageFragmentRoot(resource);
1383 // return getPackageFragmentRoot0(path);
1385 return getPackageFragmentRoot(getProject().getWorkspace().getRoot().getFolder(path));
1391 * The path is known to match a source/library folder entry.
1393 public IPackageFragmentRoot getFolderPackageFragmentRoot(IPath path) {
1394 if (path.segmentCount() == 1) { // default project root
1395 return getPackageFragmentRoot(getProject());
1397 return getPackageFragmentRoot(getProject().getWorkspace().getRoot().getFolder(path));
1403 public IPackageFragmentRoot getPackageFragmentRoot(IResource resource) {
1405 switch (resource.getType()) {
1406 case IResource.FILE:
1407 // if (Util.isArchiveFileName(resource.getName())) {
1408 // return new JarPackageFragmentRoot(resource, this);
1412 case IResource.FOLDER:
1413 return new PackageFragmentRoot(resource, this, resource.getName());
1414 case IResource.PROJECT:
1415 return new PackageFragmentRoot(resource, this, ""); //$NON-NLS-1$
1424 // public IPackageFragmentRoot getPackageFragmentRoot(String jarPath) {
1426 // return getPackageFragmentRoot0(JavaProject.canonicalizedPath(new Path(jarPath)));
1430 // * no path canonicalization
1432 // public IPackageFragmentRoot getPackageFragmentRoot0(IPath jarPath) {
1434 // return new JarPackageFragmentRoot(jarPath, this);
1440 public IPackageFragmentRoot[] getPackageFragmentRoots()
1441 throws JavaModelException {
1445 IPackageFragmentRoot[] roots;
1448 children = getChildren(),
1450 roots = new IPackageFragmentRoot[length = children.length],
1461 public IPackageFragmentRoot[] getPackageFragmentRoots(IClasspathEntry entry) {
1462 return findPackageFragmentRoots(entry);
1466 * Returns the package fragment root prefixed by the given path, or
1467 * an empty collection if there are no such elements in the model.
1469 protected IPackageFragmentRoot[] getPackageFragmentRoots(IPath path)
1471 throws JavaModelException {
1472 IPackageFragmentRoot[] roots = getAllPackageFragmentRoots();
1473 ArrayList matches = new ArrayList();
1475 for (int i = 0; i < roots.length; ++i) {
1476 if (path.isPrefixOf(roots[i].getPath())) {
1477 matches.add(roots[i]);
1480 IPackageFragmentRoot[] copy = new IPackageFragmentRoot[matches.size()];
1481 matches.toArray(copy);
1488 public IPackageFragment[] getPackageFragments() throws JavaModelException {
1490 IPackageFragmentRoot[] roots = getPackageFragmentRoots();
1491 return getPackageFragmentsInRoots(roots);
1495 * Returns all the package fragments found in the specified
1496 * package fragment roots.
1498 public IPackageFragment[] getPackageFragmentsInRoots(IPackageFragmentRoot[] roots) {
1500 ArrayList frags = new ArrayList();
1501 for (int i = 0; i < roots.length; i++) {
1502 IPackageFragmentRoot root = roots[i];
1504 IJavaElement[] rootFragments = root.getChildren();
1505 for (int j = 0; j < rootFragments.length; j++) {
1506 frags.add(rootFragments[j]);
1508 } catch (JavaModelException e) {
1512 IPackageFragment[] fragments = new IPackageFragment[frags.size()];
1513 frags.toArray(fragments);
1520 public IPath getPath() {
1521 return this.getProject().getFullPath();
1527 public IProject getProject() {
1532 protected IProject getProject(String name) {
1533 return PHPeclipsePlugin.getWorkspace().getRoot().getProject(name);
1536 public List getReferencedProjects() {
1537 List referencedProjects = new ArrayList();
1539 Iterator iterator = getLoadPathEntries().iterator();
1540 while (iterator.hasNext()) {
1541 LoadPathEntry pathEntry = (LoadPathEntry) iterator.next();
1542 if (pathEntry.getType() == LoadPathEntry.TYPE_PROJECT)
1543 referencedProjects.add(pathEntry.getProject());
1546 return referencedProjects;
1550 * Returns the project custom preference pool.
1551 * Project preferences may include custom encoding.
1553 public Preferences getPreferences(){
1554 IProject project = getProject();
1555 if (!JavaProject.hasJavaNature(project)) return null;
1556 JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfo(project, true);
1557 Preferences preferences = perProjectInfo.preferences;
1558 if (preferences != null) return preferences;
1559 preferences = loadPreferences();
1560 if (preferences == null) preferences = new Preferences();
1561 perProjectInfo.preferences = preferences;
1568 public IClasspathEntry[] getRawClasspath() throws JavaModelException {
1570 JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(fProject);
1571 IClasspathEntry[] classpath = perProjectInfo.classpath;
1572 if (classpath != null) return classpath;
1573 classpath = this.readClasspathFile(false/*don't create markers*/, true/*log problems*/);
1575 // extract out the output location
1576 IPath outputLocation = null;
1577 if (classpath != null && classpath.length > 0) {
1578 IClasspathEntry entry = classpath[classpath.length - 1];
1579 if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
1580 outputLocation = entry.getPath();
1581 IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1];
1582 System.arraycopy(classpath, 0, copy, 0, copy.length);
1586 if (classpath == null) {
1587 return defaultClasspath();
1589 /* Disable validate: classpath can contain CP variables and container that need to be resolved
1590 if (classpath != INVALID_CLASSPATH
1591 && !JavaConventions.validateClasspath(this, classpath, outputLocation).isOK()) {
1592 classpath = INVALID_CLASSPATH;
1595 perProjectInfo.classpath = classpath;
1596 perProjectInfo.outputLocation = outputLocation;
1601 * @see IJavaProject#getRequiredProjectNames
1603 public String[] getRequiredProjectNames() throws JavaModelException {
1605 return this.projectPrerequisites(getResolvedClasspath(true));
1611 public IClasspathEntry[] getResolvedClasspath(boolean ignoreUnresolvedEntry)
1612 throws JavaModelException {
1615 this.getResolvedClasspath(
1616 ignoreUnresolvedEntry,
1617 false); // generateMarkerOnError
1621 * Internal variant which can create marker on project for invalid entries
1622 * and caches the resolved classpath on perProjectInfo
1624 public IClasspathEntry[] getResolvedClasspath(
1625 boolean ignoreUnresolvedEntry,
1626 boolean generateMarkerOnError)
1627 throws JavaModelException {
1629 JavaModelManager manager = JavaModelManager.getJavaModelManager();
1630 JavaModelManager.PerProjectInfo perProjectInfo = manager.getPerProjectInfoCheckExistence(fProject);
1632 // reuse cache if not needing to refresh markers or checking bound variables
1633 if (ignoreUnresolvedEntry && !generateMarkerOnError && perProjectInfo != null){
1634 // resolved path is cached on its info
1635 IClasspathEntry[] infoPath = perProjectInfo.lastResolvedClasspath;
1636 if (infoPath != null) return infoPath;
1638 Map reverseMap = perProjectInfo == null ? null : new HashMap(5);
1639 IClasspathEntry[] resolvedPath = getResolvedClasspath(
1641 generateMarkerOnError ? getOutputLocation() : null,
1642 ignoreUnresolvedEntry,
1643 generateMarkerOnError,
1646 if (perProjectInfo != null){
1647 if (perProjectInfo.classpath == null // .classpath file could not be read
1648 && generateMarkerOnError
1649 && JavaProject.hasJavaNature(fProject)) {
1650 this.createClasspathProblemMarker(new JavaModelStatus(
1651 IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
1652 Util.bind("classpath.cannotReadClasspathFile", this.getElementName()))); //$NON-NLS-1$
1655 perProjectInfo.lastResolvedClasspath = resolvedPath;
1656 perProjectInfo.resolvedPathToRawEntries = reverseMap;
1658 return resolvedPath;
1662 * Internal variant which can process any arbitrary classpath
1664 public IClasspathEntry[] getResolvedClasspath(
1665 IClasspathEntry[] classpathEntries,
1666 IPath projectOutputLocation, // only set if needing full classpath validation (and markers)
1667 boolean ignoreUnresolvedEntry, // if unresolved entries are met, should it trigger initializations
1668 boolean generateMarkerOnError,
1669 Map reverseMap) // can be null if not interested in reverse mapping
1670 throws JavaModelException {
1672 IJavaModelStatus status;
1673 if (generateMarkerOnError){
1674 flushClasspathProblemMarkers(false, false);
1677 int length = classpathEntries.length;
1678 ArrayList resolvedEntries = new ArrayList();
1680 for (int i = 0; i < length; i++) {
1682 IClasspathEntry rawEntry = classpathEntries[i];
1686 /* validation if needed */
1687 // if (generateMarkerOnError || !ignoreUnresolvedEntry) {
1688 // status = JavaConventions.validateClasspathEntry(this, rawEntry, false);
1689 // if (generateMarkerOnError && !status.isOK()) createClasspathProblemMarker(status);
1692 switch (rawEntry.getEntryKind()){
1694 case IClasspathEntry.CPE_VARIABLE :
1696 IClasspathEntry resolvedEntry = JavaCore.getResolvedClasspathEntry(rawEntry);
1697 if (resolvedEntry == null) {
1698 if (!ignoreUnresolvedEntry) throw new JavaModelException(status);
1700 if (reverseMap != null && reverseMap.get(resolvedPath = resolvedEntry.getPath()) == null) reverseMap.put(resolvedPath , rawEntry);
1701 resolvedEntries.add(resolvedEntry);
1705 // case IClasspathEntry.CPE_CONTAINER :
1707 // IClasspathContainer container = PHPCore.getClasspathContainer(rawEntry.getPath(), this);
1708 // if (container == null){
1709 // if (!ignoreUnresolvedEntry) throw new JavaModelException(status);
1713 // IClasspathEntry[] containerEntries = container.getClasspathEntries();
1714 // if (containerEntries == null) break;
1716 // // container was bound
1717 // for (int j = 0, containerLength = containerEntries.length; j < containerLength; j++){
1718 // IClasspathEntry cEntry = containerEntries[j];
1720 // if (generateMarkerOnError) {
1721 // IJavaModelStatus containerStatus = JavaConventions.validateClasspathEntry(this, cEntry, false);
1722 // if (!containerStatus.isOK()) createClasspathProblemMarker(containerStatus);
1724 // // if container is exported, then its nested entries must in turn be exported (21749)
1725 // if (rawEntry.isExported()){
1726 // cEntry = new ClasspathEntry(cEntry.getContentKind(),
1727 // cEntry.getEntryKind(), cEntry.getPath(),
1728 // cEntry.getExclusionPatterns(), cEntry.getSourceAttachmentPath(),
1729 // cEntry.getSourceAttachmentRootPath(), cEntry.getOutputLocation(),
1730 // true); // duplicate container entry for tagging it as exported
1732 // if (reverseMap != null && reverseMap.get(resolvedPath = cEntry.getPath()) == null) reverseMap.put(resolvedPath, rawEntry);
1733 // resolvedEntries.add(cEntry);
1739 if (reverseMap != null && reverseMap.get(resolvedPath = rawEntry.getPath()) == null) reverseMap.put(resolvedPath, rawEntry);
1740 resolvedEntries.add(rawEntry);
1745 IClasspathEntry[] resolvedPath = new IClasspathEntry[resolvedEntries.size()];
1746 resolvedEntries.toArray(resolvedPath);
1748 // if (generateMarkerOnError && projectOutputLocation != null) {
1749 // status = JavaConventions.validateClasspath(this, resolvedPath, projectOutputLocation);
1750 // if (!status.isOK()) createClasspathProblemMarker(status);
1752 return resolvedPath;
1758 public IResource getResource() {
1759 return this.getProject();
1765 public ISearchableNameEnvironment getSearchableNameEnvironment()
1766 throws JavaModelException {
1768 JavaProjectElementInfo info = getJavaProjectElementInfo();
1769 if (info.getSearchableEnvironment() == null) {
1770 info.setSearchableEnvironment(new SearchableEnvironment(this));
1772 return info.getSearchableEnvironment();
1776 * Retrieve a shared property on a project. If the property is not defined, answers null.
1777 * Note that it is orthogonal to IResource persistent properties, and client code has to decide
1778 * which form of storage to use appropriately. Shared properties produce real resource files which
1779 * can be shared through a VCM onto a server. Persistent properties are not shareable.
1781 * @see JavaProject#setSharedProperty(String, String)
1783 public String getSharedProperty(String key) throws CoreException {
1785 String property = null;
1786 IFile rscFile = getProject().getFile(key);
1787 if (rscFile.exists()) {
1788 property = new String(Util.getResourceContentsAsByteArray(rscFile));
1796 // public SourceMapper getSourceMapper() {
1804 public IResource getUnderlyingResource() throws JavaModelException {
1805 if (!exists()) throw newNotPresentException();
1806 return getProject();
1812 public boolean hasBuildState() {
1814 return JavaModelManager.getJavaModelManager().getLastBuiltState(this.getProject(), null) != null;
1820 public boolean hasClasspathCycle(IClasspathEntry[] preferredClasspath) {
1821 HashSet cycleParticipants = new HashSet();
1822 updateCycleParticipants(preferredClasspath, new ArrayList(2), cycleParticipants, ResourcesPlugin.getWorkspace().getRoot(), new HashSet(2));
1823 return !cycleParticipants.isEmpty();
1826 public boolean hasCycleMarker(){
1827 return this.getCycleMarker() != null;
1830 public int hashCode() {
1831 return fProject.hashCode();
1835 * Returns true if the given project is accessible and it has
1836 * a java nature, otherwise false.
1838 public static boolean hasJavaNature(IProject project) {
1840 return project.hasNature(PHPeclipsePlugin.PHP_NATURE_ID);
1841 } catch (CoreException e) {
1842 // project does not exist or is not open
1848 * Answers true if the project potentially contains any source. A project which has no source is immutable.
1850 public boolean hasSource() {
1852 // look if any source folder on the classpath
1853 // no need for resolved path given source folder cannot be abstracted
1854 IClasspathEntry[] entries;
1856 entries = this.getRawClasspath();
1857 } catch (JavaModelException e) {
1858 return true; // unsure
1860 for (int i = 0, max = entries.length; i < max; i++) {
1861 if (entries[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) {
1869 * Compare current classpath with given one to see if any different.
1870 * Note that the argument classpath contains its binary output.
1872 public boolean isClasspathEqualsTo(IClasspathEntry[] newClasspath, IPath newOutputLocation, IClasspathEntry[] otherClasspathWithOutput)
1873 throws JavaModelException {
1875 if (otherClasspathWithOutput != null && otherClasspathWithOutput.length > 0) {
1877 int length = otherClasspathWithOutput.length;
1878 if (length == newClasspath.length + 1) {
1879 // output is amongst file entries (last one)
1881 // compare classpath entries
1882 for (int i = 0; i < length - 1; i++) {
1883 if (!otherClasspathWithOutput[i].equals(newClasspath[i]))
1886 // compare binary outputs
1887 IClasspathEntry output = otherClasspathWithOutput[length - 1];
1888 if (output.getContentKind() == ClasspathEntry.K_OUTPUT
1889 && output.getPath().equals(newOutputLocation))
1901 public boolean isOnClasspath(IJavaElement element) {
1902 IPath path = element.getPath();
1903 switch (element.getElementType()) {
1904 case IJavaElement.PACKAGE_FRAGMENT_ROOT:
1905 if (!((IPackageFragmentRoot)element).isArchive()) {
1906 // ensure that folders are only excluded if all of their children are excluded
1907 path = path.append("*"); //$NON-NLS-1$
1910 case IJavaElement.PACKAGE_FRAGMENT:
1911 if (!((IPackageFragmentRoot)element.getParent()).isArchive()) {
1912 // ensure that folders are only excluded if all of their children are excluded
1913 path = path.append("*"); //$NON-NLS-1$
1917 return this.isOnClasspath(path);
1919 private boolean isOnClasspath(IPath path) {
1920 IClasspathEntry[] classpath;
1922 classpath = this.getResolvedClasspath(true/*ignore unresolved variable*/);
1923 } catch(JavaModelException e){
1924 return false; // not a Java project
1926 for (int i = 0; i < classpath.length; i++) {
1927 IClasspathEntry entry = classpath[i];
1928 if (entry.getPath().isPrefixOf(path)
1929 && !Util.isExcluded(path, ((ClasspathEntry)entry).fullExclusionPatternChars())) {
1938 public boolean isOnClasspath(IResource resource) {
1939 IPath path = resource.getFullPath();
1941 // ensure that folders are only excluded if all of their children are excluded
1942 if (resource.getType() == IResource.FOLDER) {
1943 path = path.append("*"); //$NON-NLS-1$
1946 return this.isOnClasspath(path);
1951 * load preferences from a shareable format (VCM-wise)
1953 public Preferences loadPreferences() {
1955 Preferences preferences = new Preferences();
1957 // File prefFile = getProject().getLocation().append(PREF_FILENAME).toFile();
1958 IPath projectMetaLocation = getProject().getPluginWorkingLocation(JavaCore.getPlugin().getDescriptor());
1959 if (projectMetaLocation != null) {
1960 File prefFile = projectMetaLocation.append(PREF_FILENAME).toFile();
1961 if (prefFile.exists()) { // load preferences from file
1962 InputStream in = null;
1964 in = new BufferedInputStream(new FileInputStream(prefFile));
1965 preferences.load(in);
1967 } catch (IOException e) { // problems loading preference store - quietly ignore
1972 } catch (IOException e) { // ignore problems with close
1982 * @see IJavaProject#newEvaluationContext
1984 // public IEvaluationContext newEvaluationContext() {
1986 // return new EvaluationContextWrapper(new EvaluationContext(), this);
1992 // public ITypeHierarchy newTypeHierarchy(
1994 // IProgressMonitor monitor)
1995 // throws JavaModelException {
1997 // if (region == null) {
1998 // throw new IllegalArgumentException(Util.bind("hierarchy.nullRegion"));//$NON-NLS-1$
2000 // CreateTypeHierarchyOperation op =
2001 // new CreateTypeHierarchyOperation(null, region, this, true);
2002 // runOperation(op, monitor);
2003 // return op.getResult();
2009 // public ITypeHierarchy newTypeHierarchy(
2012 // IProgressMonitor monitor)
2013 // throws JavaModelException {
2015 // if (type == null) {
2016 // throw new IllegalArgumentException(Util.bind("hierarchy.nullFocusType"));//$NON-NLS-1$
2018 // if (region == null) {
2019 // throw new IllegalArgumentException(Util.bind("hierarchy.nullRegion"));//$NON-NLS-1$
2021 // CreateTypeHierarchyOperation op =
2022 // new CreateTypeHierarchyOperation(type, region, this, true);
2023 // runOperation(op, monitor);
2024 // return op.getResult();
2028 * Open project if resource isn't closed
2030 protected void openWhenClosed(IProgressMonitor pm) throws JavaModelException {
2032 if (!this.fProject.isOpen()) {
2033 throw newNotPresentException();
2035 super.openWhenClosed(pm);
2039 public String[] projectPrerequisites(IClasspathEntry[] entries)
2040 throws JavaModelException {
2042 ArrayList prerequisites = new ArrayList();
2044 entries = getResolvedClasspath(entries, null, true, false, null/*no reverse map*/);
2045 for (int i = 0, length = entries.length; i < length; i++) {
2046 IClasspathEntry entry = entries[i];
2047 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
2048 prerequisites.add(entry.getPath().lastSegment());
2051 int size = prerequisites.size();
2053 return NO_PREREQUISITES;
2055 String[] result = new String[size];
2056 prerequisites.toArray(result);
2063 * Reads the .classpath file from disk and returns the list of entries it contains (including output location entry)
2064 * Returns null if .classfile is not present.
2065 * Returns INVALID_CLASSPATH if it has a format problem.
2067 protected IClasspathEntry[] readClasspathFile(boolean createMarker, boolean logProblems) {
2070 String xmlClasspath = getSharedProperty(CLASSPATH_FILENAME);
2071 if (xmlClasspath == null) return null;
2072 return decodeClasspath(xmlClasspath, createMarker, logProblems);
2073 } catch(CoreException e) {
2074 // file does not exist (or not accessible)
2075 if (createMarker && this.getProject().isAccessible()) {
2076 this.createClasspathProblemMarker(new JavaModelStatus(
2077 IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
2078 Util.bind("classpath.cannotReadClasspathFile", this.getElementName()))); //$NON-NLS-1$
2082 "Exception while retrieving "+ this.getPath() //$NON-NLS-1$
2083 +"/.classpath, will revert to default classpath"); //$NON-NLS-1$
2090 * Removes the given builder from the build spec for the given project.
2092 protected void removeFromBuildSpec(String builderID) throws CoreException {
2094 IProjectDescription description = getProject().getDescription();
2095 ICommand[] commands = description.getBuildSpec();
2096 for (int i = 0; i < commands.length; ++i) {
2097 if (commands[i].getBuilderName().equals(builderID)) {
2098 ICommand[] newCommands = new ICommand[commands.length - 1];
2099 System.arraycopy(commands, 0, newCommands, 0, i);
2100 System.arraycopy(commands, i + 1, newCommands, i, commands.length - i - 1);
2101 description.setBuildSpec(newCommands);
2102 getProject().setDescription(description, null);
2110 * @see JavaElement#rootedAt(IJavaProject)
2112 public IJavaElement rootedAt(IJavaProject project) {
2118 * Answers an ID which is used to distinguish project/entries during package
2119 * fragment root computations
2121 public String rootID(){
2122 return "[PRJ]"+this.getProject().getFullPath(); //$NON-NLS-1$
2126 * Saves the classpath in a shareable format (VCM-wise) only when necessary, that is, if it is semantically different
2127 * from the existing one in file. Will never write an identical one.
2129 * @return Return whether the .classpath file was modified.
2131 public boolean saveClasspath(IClasspathEntry[] newClasspath, IPath newOutputLocation) throws JavaModelException {
2133 if (!getProject().exists()) return false;
2135 IClasspathEntry[] fileEntries = readClasspathFile(false /*don't create markers*/, false/*don't log problems*/);
2136 if (fileEntries != null && isClasspathEqualsTo(newClasspath, newOutputLocation, fileEntries)) {
2137 // no need to save it, it is the same
2141 // actual file saving
2143 setSharedProperty(CLASSPATH_FILENAME, encodeClasspath(newClasspath, newOutputLocation, true));
2145 } catch (CoreException e) {
2146 throw new JavaModelException(e);
2151 * Save project custom preferences to shareable file (.jprefs)
2153 private void savePreferences(Preferences preferences) {
2155 IProject project = getProject();
2156 if (!JavaProject.hasJavaNature(project)) return; // ignore
2158 if (preferences == null || (!preferences.needsSaving() && preferences.propertyNames().length != 0)) {
2163 // preferences need to be saved
2164 // the preferences file is located in the plug-in's state area
2165 // at a well-known name (.jprefs)
2166 // File prefFile = getProject().getLocation().append(PREF_FILENAME).toFile();
2167 File prefFile = project.getPluginWorkingLocation(JavaCore.getPlugin().getDescriptor()).append(PREF_FILENAME).toFile();
2168 if (preferences.propertyNames().length == 0) {
2169 // there are no preference settings
2170 // rather than write an empty file, just delete any existing file
2171 if (prefFile.exists()) {
2172 prefFile.delete(); // don't worry if delete unsuccessful
2177 // write file, overwriting an existing one
2178 OutputStream out = null;
2180 // do it as carefully as we know how so that we don't lose/mangle
2181 // the setting in times of stress
2182 out = new BufferedOutputStream(new FileOutputStream(prefFile));
2183 preferences.store(out, null);
2184 } catch (IOException e) { // problems saving preference store - quietly ignore
2189 } catch (IOException e) { // ignore problems with close
2196 * Update the Java command in the build spec (replace existing one if present,
2197 * add one first if none).
2199 private void setJavaCommand(
2200 IProjectDescription description,
2201 ICommand newCommand)
2202 throws CoreException {
2204 ICommand[] oldCommands = description.getBuildSpec();
2205 ICommand oldJavaCommand = getJavaCommand(description);
2206 ICommand[] newCommands;
2208 if (oldJavaCommand == null) {
2209 // Add a Java build spec before other builders (1FWJK7I)
2210 newCommands = new ICommand[oldCommands.length + 1];
2211 System.arraycopy(oldCommands, 0, newCommands, 1, oldCommands.length);
2212 newCommands[0] = newCommand;
2214 for (int i = 0, max = oldCommands.length; i < max; i++) {
2215 if (oldCommands[i] == oldJavaCommand) {
2216 oldCommands[i] = newCommand;
2220 newCommands = oldCommands;
2223 // Commit the spec change into the project
2224 description.setBuildSpec(newCommands);
2225 getProject().setDescription(description, null);
2229 * @see org.eclipse.jdt.core.IJavaProject#setOptions(Map)
2231 public void setOptions(Map newOptions) {
2233 Preferences preferences;
2234 setPreferences(preferences = new Preferences()); // always reset (26255)
2235 if (newOptions != null){
2236 Iterator keys = newOptions.keySet().iterator();
2237 while (keys.hasNext()){
2238 String key = (String)keys.next();
2239 if (!JavaModelManager.OptionNames.contains(key)) continue; // unrecognized option
2240 // no filtering for encoding (custom encoding for project is allowed)
2241 String value = (String)newOptions.get(key);
2242 preferences.setDefault(key, CUSTOM_DEFAULT_OPTION_VALUE); // empty string isn't the default (26251)
2243 preferences.setValue(key, value);
2248 savePreferences(preferences);
2254 public void setOutputLocation(IPath path, IProgressMonitor monitor)
2255 throws JavaModelException {
2258 throw new IllegalArgumentException(Util.bind("path.nullpath")); //$NON-NLS-1$
2260 if (path.equals(getOutputLocation())) {
2263 this.setRawClasspath(SetClasspathOperation.ReuseClasspath, path, monitor);
2267 * Set cached preferences, no preference file is saved, only info is updated
2269 public void setPreferences(Preferences preferences) {
2270 IProject project = getProject();
2271 if (!JavaProject.hasJavaNature(project)) return; // ignore
2272 JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfo(project, true);
2273 perProjectInfo.preferences = preferences;
2277 * Sets the underlying kernel project of this Java project,
2278 * and fills in its parent and name.
2279 * Called by IProject.getNature().
2281 * @see IProjectNature#setProject
2283 public void setProject(IProject project) {
2286 fParent = JavaModelManager.getJavaModelManager().getJavaModel();
2287 fName = project.getName();
2293 public void setRawClasspath(
2294 IClasspathEntry[] entries,
2295 IPath outputLocation,
2296 IProgressMonitor monitor)
2297 throws JavaModelException {
2303 true, // canChangeResource (as per API contract)
2304 getResolvedClasspath(true), // ignoreUnresolvedVariable
2305 true, // needValidation
2306 true); // need to save
2309 public void setRawClasspath(
2310 IClasspathEntry[] newEntries,
2311 IPath newOutputLocation,
2312 IProgressMonitor monitor,
2313 boolean canChangeResource,
2314 IClasspathEntry[] oldResolvedPath,
2315 boolean needValidation,
2317 throws JavaModelException {
2319 JavaModelManager manager =
2320 (JavaModelManager) JavaModelManager.getJavaModelManager();
2322 IClasspathEntry[] newRawPath = newEntries;
2323 if (newRawPath == null) { //are we already with the default classpath
2324 newRawPath = defaultClasspath();
2326 SetClasspathOperation op =
2327 new SetClasspathOperation(
2335 runOperation(op, monitor);
2337 } catch (JavaModelException e) {
2346 public void setRawClasspath(
2347 IClasspathEntry[] entries,
2348 IProgressMonitor monitor)
2349 throws JavaModelException {
2353 SetClasspathOperation.ReuseOutputLocation,
2355 true, // canChangeResource (as per API contract)
2356 getResolvedClasspath(true), // ignoreUnresolvedVariable
2357 true, // needValidation
2358 true); // need to save
2362 * NOTE: <code>null</code> specifies default classpath, and an empty
2363 * array specifies an empty classpath.
2365 * @exception NotPresentException if this project does not exist.
2367 protected void setRawClasspath0(IClasspathEntry[] rawEntries)
2368 throws JavaModelException {
2370 JavaModelManager.PerProjectInfo info = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(fProject);
2372 synchronized (info) {
2373 if (rawEntries != null) {
2374 info.classpath = rawEntries;
2377 // clear cache of resolved classpath
2378 info.lastResolvedClasspath = null;
2379 info.resolvedPathToRawEntries = null;
2384 * Record a shared persistent property onto a project.
2385 * Note that it is orthogonal to IResource persistent properties, and client code has to decide
2386 * which form of storage to use appropriately. Shared properties produce real resource files which
2387 * can be shared through a VCM onto a server. Persistent properties are not shareable.
2389 * shared properties end up in resource files, and thus cannot be modified during
2390 * delta notifications (a CoreException would then be thrown).
2392 * @see JavaProject#getSharedProperty(String key)
2394 public void setSharedProperty(String key, String value) throws CoreException {
2396 IFile rscFile = getProject().getFile(key);
2397 InputStream inputStream = new ByteArrayInputStream(value.getBytes());
2398 // update the resource content
2399 if (rscFile.exists()) {
2400 if (rscFile.isReadOnly()) {
2401 // provide opportunity to checkout read-only .classpath file (23984)
2402 ResourcesPlugin.getWorkspace().validateEdit(new IFile[]{rscFile}, null);
2404 rscFile.setContents(inputStream, IResource.FORCE, null);
2406 rscFile.create(inputStream, IResource.FORCE, null);
2411 * Update cycle markers for all java projects
2413 public static void updateAllCycleMarkers() throws JavaModelException {
2415 //long start = System.currentTimeMillis();
2417 JavaModelManager manager = JavaModelManager.getJavaModelManager();
2418 IJavaProject[] projects = manager.getJavaModel().getJavaProjects();
2419 IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
2421 HashSet cycleParticipants = new HashSet();
2422 HashSet traversed = new HashSet();
2423 int length = projects.length;
2425 // compute cycle participants
2426 ArrayList prereqChain = new ArrayList();
2427 for (int i = 0; i < length; i++){
2428 JavaProject project = (JavaProject)projects[i];
2429 if (!traversed.contains(project.getPath())){
2430 prereqChain.clear();
2431 project.updateCycleParticipants(null, prereqChain, cycleParticipants, workspaceRoot, traversed);
2434 //System.out.println("updateAllCycleMarkers: " + (System.currentTimeMillis() - start) + " ms");
2436 for (int i = 0; i < length; i++){
2437 JavaProject project = (JavaProject)projects[i];
2439 if (cycleParticipants.contains(project.getPath())){
2440 IMarker cycleMarker = project.getCycleMarker();
2441 String circularCPOption = project.getOption(JavaCore.CORE_CIRCULAR_CLASSPATH, true);
2442 int circularCPSeverity = JavaCore.ERROR.equals(circularCPOption) ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING;
2443 if (cycleMarker != null) {
2444 // update existing cycle marker if needed
2446 int existingSeverity = ((Integer)cycleMarker.getAttribute(IMarker.SEVERITY)).intValue();
2447 if (existingSeverity != circularCPSeverity) {
2448 cycleMarker.setAttribute(IMarker.SEVERITY, circularCPSeverity);
2450 } catch (CoreException e) {
2451 throw new JavaModelException(e);
2454 // create new marker
2455 project.createClasspathProblemMarker(
2456 new JavaModelStatus(IJavaModelStatusConstants.CLASSPATH_CYCLE, project));
2459 project.flushClasspathProblemMarkers(true, false);
2465 * If a cycle is detected, then cycleParticipants contains all the paths of projects involved in this cycle (directly and indirectly),
2466 * no cycle if the set is empty (and started empty)
2468 public void updateCycleParticipants(
2469 IClasspathEntry[] preferredClasspath,
2470 ArrayList prereqChain,
2471 HashSet cycleParticipants,
2472 IWorkspaceRoot workspaceRoot,
2475 IPath path = this.getPath();
2476 prereqChain.add(path);
2477 traversed.add(path);
2479 IClasspathEntry[] classpath = preferredClasspath == null ? getResolvedClasspath(true) : preferredClasspath;
2480 for (int i = 0, length = classpath.length; i < length; i++) {
2481 IClasspathEntry entry = classpath[i];
2483 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT){
2484 IPath prereqProjectPath = entry.getPath();
2485 int index = cycleParticipants.contains(prereqProjectPath) ? 0 : prereqChain.indexOf(prereqProjectPath);
2486 if (index >= 0) { // refer to cycle, or in cycle itself
2487 for (int size = prereqChain.size(); index < size; index++) {
2488 cycleParticipants.add(prereqChain.get(index));
2491 if (!traversed.contains(prereqProjectPath)) {
2492 IResource member = workspaceRoot.findMember(prereqProjectPath);
2493 if (member != null && member.getType() == IResource.PROJECT){
2494 JavaProject project = (JavaProject)JavaCore.create((IProject)member);
2495 project.updateCycleParticipants(null, prereqChain, cycleParticipants, workspaceRoot, traversed);
2501 } catch(JavaModelException e){
2503 prereqChain.remove(path);
2506 * Reset the collection of package fragment roots (local ones) - only if opened.
2507 * Need to check *all* package fragment roots in order to reset NameLookup
2509 public void updatePackageFragmentRoots(){
2511 if (this.isOpen()) {
2513 JavaProjectElementInfo info = getJavaProjectElementInfo();
2515 IClasspathEntry[] classpath = getResolvedClasspath(true);
2516 // NameLookup lookup = info.getNameLookup();
2517 // if (lookup != null){
2518 // IPackageFragmentRoot[] oldRoots = lookup.fPackageFragmentRoots;
2519 // IPackageFragmentRoot[] newRoots = computePackageFragmentRoots(classpath, true);
2520 // checkIdentical: { // compare all pkg fragment root lists
2521 // if (oldRoots.length == newRoots.length){
2522 // for (int i = 0, length = oldRoots.length; i < length; i++){
2523 // if (!oldRoots[i].equals(newRoots[i])){
2524 // break checkIdentical;
2527 // return; // no need to update
2530 // info.setNameLookup(null); // discard name lookup (hold onto roots)
2532 info.setNonJavaResources(null);
2534 computePackageFragmentRoots(classpath, false));
2536 } catch(JavaModelException e){
2538 close(); // could not do better
2539 } catch(JavaModelException ex){
2545 public void removeLoadPathEntry(IProject anotherPHPProject) {
2546 Iterator entries = getLoadPathEntries().iterator();
2547 while (entries.hasNext()) {
2548 LoadPathEntry entry = (LoadPathEntry) entries.next();
2549 if (entry.getType() == LoadPathEntry.TYPE_PROJECT && entry.getProject().getName().equals(anotherPHPProject.getName())) {
2550 getLoadPathEntries().remove(entry);
2557 public void save() throws CoreException {
2559 InputStream xmlPath = new ByteArrayInputStream(getLoadPathXML().getBytes());
2560 IFile loadPathsFile = getLoadPathEntriesFile();
2561 if (!loadPathsFile.exists())
2562 loadPathsFile.create(xmlPath, true, null);
2564 loadPathsFile.setContents(xmlPath, true, false, null);