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.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;
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;
86 * Handle for a Java Project.
88 * <p>A Java Project internally maintains a devpath that corresponds
89 * to the project's classpath. The classpath may include source folders
90 * from the current project; jars in the current project, other projects,
91 * and the local file system; and binary folders (output location) of other
92 * projects. The Java Model presents source elements corresponding to output
93 * .class files in other projects, and thus uses the devpath rather than
94 * the classpath (which is really a compilation path). The devpath mimics
95 * the classpath, except has source folder entries in place of output
96 * locations in external projects.
98 * <p>Each JavaProject has a NameLookup facility that locates elements
99 * on by name, based on the devpath.
103 public class JavaProject
105 implements IJavaProject , IProjectNature {
108 * Whether the underlying file system is case sensitive.
110 protected static final boolean IS_CASE_SENSITIVE = !new File("Temp").equals(new File("temp")); //$NON-NLS-1$ //$NON-NLS-2$
113 * An empty array of strings indicating that a project doesn't have any prerequesite projects.
115 protected static final String[] NO_PREREQUISITES = new String[0];
118 * The platform project this <code>IJavaProject</code> is based on
120 protected IProject project;
121 protected List fLoadPathEntries;
122 protected boolean fScratched;
125 * Name of file containing project classpath
127 public static final String CLASSPATH_FILENAME = ".classpath"; //$NON-NLS-1$
130 * Name of file containing custom project preferences
132 public static final String PREF_FILENAME = ".jprefs"; //$NON-NLS-1$
135 * Value of the project's raw classpath if the .classpath file contains invalid entries.
137 public static final IClasspathEntry[] INVALID_CLASSPATH = new IClasspathEntry[0];
139 private static final String CUSTOM_DEFAULT_OPTION_VALUE = "#\r\n\r#custom-non-empty-default-value#\r\n\r#"; //$NON-NLS-1$
141 * Value of project's resolved classpath while it is being resolved
143 private static final IClasspathEntry[] RESOLUTION_IN_PROGRESS = new IClasspathEntry[0];
146 * Returns a canonicalized path from the given external path.
147 * Note that the return path contains the same number of segments
148 * and it contains a device only if the given path contained one.
149 * @see java.io.File for the definition of a canonicalized path
151 public static IPath canonicalizedPath(IPath externalPath) {
153 if (externalPath == null)
156 if (JavaModelManager.VERBOSE) {
157 System.out.println("JAVA MODEL - Canonicalizing " + externalPath.toString()); //$NON-NLS-1$
160 if (IS_CASE_SENSITIVE) {
161 if (JavaModelManager.VERBOSE) {
162 System.out.println("JAVA MODEL - Canonical path is original path (file system is case sensitive)"); //$NON-NLS-1$
167 // if not external path, return original path
168 IWorkspace workspace = ResourcesPlugin.getWorkspace();
169 if (workspace == null) return externalPath; // protection during shutdown (30487)
170 if (workspace.getRoot().findMember(externalPath) != null) {
171 if (JavaModelManager.VERBOSE) {
172 System.out.println("JAVA MODEL - Canonical path is original path (member of workspace)"); //$NON-NLS-1$
177 IPath canonicalPath = null;
180 new Path(new File(externalPath.toOSString()).getCanonicalPath());
181 } catch (IOException e) {
182 // default to original path
183 if (JavaModelManager.VERBOSE) {
184 System.out.println("JAVA MODEL - Canonical path is original path (IOException)"); //$NON-NLS-1$
190 int canonicalLength = canonicalPath.segmentCount();
191 if (canonicalLength == 0) {
192 // the java.io.File canonicalization failed
193 if (JavaModelManager.VERBOSE) {
194 System.out.println("JAVA MODEL - Canonical path is original path (canonical path is empty)"); //$NON-NLS-1$
197 } else if (externalPath.isAbsolute()) {
198 result = canonicalPath;
200 // if path is relative, remove the first segments that were added by the java.io.File canonicalization
201 // e.g. 'lib/classes.zip' was converted to 'd:/myfolder/lib/classes.zip'
202 int externalLength = externalPath.segmentCount();
203 if (canonicalLength >= externalLength) {
204 result = canonicalPath.removeFirstSegments(canonicalLength - externalLength);
206 if (JavaModelManager.VERBOSE) {
207 System.out.println("JAVA MODEL - Canonical path is original path (canonical path is " + canonicalPath.toString() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
213 // keep device only if it was specified (this is because File.getCanonicalPath() converts '/lib/classed.zip' to 'd:/lib/classes/zip')
214 if (externalPath.getDevice() == null) {
215 result = result.setDevice(null);
217 if (JavaModelManager.VERBOSE) {
218 System.out.println("JAVA MODEL - Canonical path is " + result.toString()); //$NON-NLS-1$
224 * Constructor needed for <code>IProject.getNature()</code> and <code>IProject.addNature()</code>.
226 * @see #setProject(IProject)
228 public JavaProject() {
232 public JavaProject(IProject project, JavaElement parent) {
233 super(parent, project.getName());
234 this.project = project;
236 public void addLoadPathEntry(IProject anotherPHPProject) {
239 LoadPathEntry newEntry = new LoadPathEntry(anotherPHPProject);
240 getLoadPathEntries().add(newEntry);
243 public void configure() throws CoreException {
244 // get project description and then the associated build commands
245 IProjectDescription desc = project.getDescription();
246 ICommand[] commands = desc.getBuildSpec();
248 // determine if builder already associated
249 boolean found = false;
250 for (int i = 0; i < commands.length; ++i) {
251 if (commands[i].getBuilderName().equals(PHPeclipsePlugin.BUILDER_PARSER_ID)) {
257 // add builder if not already in project
259 ICommand command = desc.newCommand();
260 command.setBuilderName(PHPeclipsePlugin.BUILDER_PARSER_ID);
261 ICommand[] newCommands = new ICommand[commands.length + 1];
263 // Add it before other builders.
264 System.arraycopy(commands, 0, newCommands, 1, commands.length);
265 newCommands[0] = command;
266 desc.setBuildSpec(newCommands);
267 project.setDescription(desc, null);
271 protected void loadLoadPathEntries() {
272 fLoadPathEntries = new ArrayList();
274 IFile loadPathsFile = getLoadPathEntriesFile();
276 XMLReader reader = null;
278 reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
279 reader.setContentHandler(getLoadPathEntriesContentHandler());
280 reader.parse(new InputSource(loadPathsFile.getContents()));
281 } catch (Exception e) {
282 //the file is nonextant or unreadable
286 public List getLoadPathEntries() {
287 if (fLoadPathEntries == null) {
288 loadLoadPathEntries();
291 return fLoadPathEntries;
294 protected ContentHandler getLoadPathEntriesContentHandler() {
295 return new ContentHandler() {
296 public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
299 public void endDocument() throws SAXException {
302 public void endElement(String arg0, String arg1, String arg2) throws SAXException {
305 public void endPrefixMapping(String arg0) throws SAXException {
308 public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {
311 public void processingInstruction(String arg0, String arg1) throws SAXException {
314 public void setDocumentLocator(Locator arg0) {
317 public void skippedEntity(String arg0) throws SAXException {
320 public void startDocument() throws SAXException {
323 public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
324 if ("pathentry".equals(qName))
325 if ("project".equals(atts.getValue("type"))) {
326 IPath referencedProjectPath = new Path(atts.getValue("path"));
327 IProject referencedProject = getProject(referencedProjectPath.lastSegment());
328 fLoadPathEntries.add(new LoadPathEntry(referencedProject));
332 public void startPrefixMapping(String arg0, String arg1) throws SAXException {
337 protected IFile getLoadPathEntriesFile() {
338 return project.getFile(".loadpath");
341 protected String getLoadPathXML() {
342 StringBuffer buffer = new StringBuffer();
343 buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><loadpath>");
345 Iterator pathEntriesIterator = fLoadPathEntries.iterator();
347 while (pathEntriesIterator.hasNext()) {
348 LoadPathEntry entry = (LoadPathEntry) pathEntriesIterator.next();
349 buffer.append(entry.toXML());
352 buffer.append("</loadpath>");
353 return buffer.toString();
356 * Adds a builder to the build spec for the given project.
358 protected void addToBuildSpec(String builderID) throws CoreException {
360 IProjectDescription description = getProject().getDescription();
361 ICommand javaCommand = getJavaCommand(description);
363 if (javaCommand == null) {
365 // Add a Java command to the build spec
366 ICommand command = description.newCommand();
367 command.setBuilderName(builderID);
368 setJavaCommand(description, command);
374 protected boolean buildStructure(OpenableElementInfo info, IProgressMonitor pm, Map newElements, IResource underlyingResource) throws JavaModelException {
376 // check whether the java project can be opened
377 if (!underlyingResource.isAccessible()) {
378 throw newNotPresentException();
381 IWorkspace workspace = ResourcesPlugin.getWorkspace();
382 IWorkspaceRoot wRoot = workspace.getRoot();
383 // cannot refresh cp markers on opening (emulate cp check on startup) since can create deadlocks (see bug 37274)
384 // IClasspathEntry[] resolvedClasspath = getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
386 // // compute the pkg fragment roots
387 // info.setChildren(computePackageFragmentRoots(resolvedClasspath, false));
389 // // remember the timestamps of external libraries the first time they are looked up
390 // for (int i = 0, length = resolvedClasspath.length; i < length; i++) {
391 // IClasspathEntry entry = resolvedClasspath[i];
392 // if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
393 // IPath path = entry.getPath();
394 // Object target = JavaModel.getTarget(wRoot, path, true);
395 // if (target instanceof java.io.File) {
396 // Map externalTimeStamps = JavaModelManager.getJavaModelManager().deltaState.externalTimeStamps;
397 // if (externalTimeStamps.get(path) == null) {
398 // long timestamp = DeltaProcessor.getTimeStamp((java.io.File)target);
399 // externalTimeStamps.put(path, new Long(timestamp));
407 protected void closing(Object info) {
409 // // forget source attachment recommendations
410 // Object[] children = ((JavaElementInfo)info).children;
411 // for (int i = 0, length = children.length; i < length; i++) {
412 // Object child = children[i];
413 // if (child instanceof JarPackageFragmentRoot){
414 // ((JarPackageFragmentRoot)child).setSourceAttachmentProperty(null);
420 // protected void closing(Object info) throws JavaModelException {
422 // // forget source attachment recommendations
423 // IPackageFragmentRoot[] roots = this.getPackageFragmentRoots();
424 //// for (int i = 0; i < roots.length; i++) {
425 //// if (roots[i] instanceof JarPackageFragmentRoot){
426 //// ((JarPackageFragmentRoot) roots[i]).setSourceAttachmentProperty(null);
430 // super.closing(info);
435 * Internal computation of an expanded classpath. It will eliminate duplicates, and produce copies
436 * of exported classpath entries to avoid possible side-effects ever after.
438 private void computeExpandedClasspath(
439 JavaProject initialProject,
440 boolean ignoreUnresolvedVariable,
441 boolean generateMarkerOnError,
443 ObjectVector accumulatedEntries,
444 Map preferredClasspaths,
445 Map preferredOutputs) throws JavaModelException {
447 String projectRootId = this.rootID();
448 if (rootIDs.contains(projectRootId)){
449 return; // break cycles if any
451 rootIDs.add(projectRootId);
453 IClasspathEntry[] preferredClasspath = preferredClasspaths != null ? (IClasspathEntry[])preferredClasspaths.get(this) : null;
454 IPath preferredOutput = preferredOutputs != null ? (IPath)preferredOutputs.get(this) : null;
455 IClasspathEntry[] immediateClasspath =
456 preferredClasspath != null
457 ? getResolvedClasspath(preferredClasspath, preferredOutput, ignoreUnresolvedVariable, generateMarkerOnError, null)
458 : getResolvedClasspath(ignoreUnresolvedVariable, generateMarkerOnError, false/*don't returnResolutionInProgress*/);
460 IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
461 boolean isInitialProject = this.equals(initialProject);
462 for (int i = 0, length = immediateClasspath.length; i < length; i++){
463 ClasspathEntry entry = (ClasspathEntry) immediateClasspath[i];
464 if (isInitialProject || entry.isExported()){
465 String rootID = entry.rootID();
466 if (rootIDs.contains(rootID)) {
470 accumulatedEntries.add(entry);
472 // recurse in project to get all its indirect exports (only consider exported entries from there on)
473 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
474 IResource member = workspaceRoot.findMember(entry.getPath());
475 if (member != null && member.getType() == IResource.PROJECT){ // double check if bound to project (23977)
476 IProject projRsc = (IProject) member;
477 if (JavaProject.hasJavaNature(projRsc)) {
478 JavaProject javaProject = (JavaProject) JavaCore.create(projRsc);
479 javaProject.computeExpandedClasspath(
481 ignoreUnresolvedVariable,
482 false /* no marker when recursing in prereq*/,
496 * Internal computation of an expanded classpath. It will eliminate duplicates, and produce copies
497 * of exported classpath entries to avoid possible side-effects ever after.
499 // private void computeExpandedClasspath(
500 // JavaProject initialProject,
501 // boolean ignoreUnresolvedVariable,
502 // boolean generateMarkerOnError,
503 // HashSet visitedProjects,
504 // ObjectVector accumulatedEntries) throws JavaModelException {
506 // if (visitedProjects.contains(this)){
507 // return; // break cycles if any
509 // visitedProjects.add(this);
511 // if (generateMarkerOnError && !this.equals(initialProject)){
512 // generateMarkerOnError = false;
514 // IClasspathEntry[] immediateClasspath =
515 // getResolvedClasspath(ignoreUnresolvedVariable, generateMarkerOnError);
517 // IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
518 // for (int i = 0, length = immediateClasspath.length; i < length; i++){
519 // IClasspathEntry entry = immediateClasspath[i];
521 // boolean isInitialProject = this.equals(initialProject);
522 // if (isInitialProject || entry.isExported()){
524 // accumulatedEntries.add(entry);
526 // // recurse in project to get all its indirect exports (only consider exported entries from there on)
527 // if (entry.getEntryKind() == ClasspathEntry.CPE_PROJECT) {
528 // IResource member = workspaceRoot.findMember(entry.getPath());
529 // if (member != null && member.getType() == IResource.PROJECT){ // double check if bound to project (23977)
530 // IProject projRsc = (IProject) member;
531 // if (JavaProject.hasJavaNature(projRsc)) {
532 // JavaProject project = (JavaProject) JavaCore.create(projRsc);
533 // project.computeExpandedClasspath(
535 // ignoreUnresolvedVariable,
536 // generateMarkerOnError,
538 // accumulatedEntries);
547 * Returns (local/all) the package fragment roots identified by the given project's classpath.
548 * Note: this follows project classpath references to find required project contributions,
549 * eliminating duplicates silently.
550 * Only works with resolved entries
552 public IPackageFragmentRoot[] computePackageFragmentRoots(IClasspathEntry[] resolvedClasspath, boolean retrieveExportedRoots) throws JavaModelException {
554 ObjectVector accumulatedRoots = new ObjectVector();
555 computePackageFragmentRoots(
558 new HashSet(5), // rootIDs
559 true, // inside original project
560 true, // check existency
561 retrieveExportedRoots);
562 IPackageFragmentRoot[] rootArray = new IPackageFragmentRoot[accumulatedRoots.size()];
563 accumulatedRoots.copyInto(rootArray);
568 * Computes the package fragment roots identified by the given entry.
569 * Only works with resolved entry
571 public IPackageFragmentRoot[] computePackageFragmentRoots(IClasspathEntry resolvedEntry) {
574 computePackageFragmentRoots(
575 new IClasspathEntry[]{ resolvedEntry },
576 false // don't retrieve exported roots
578 } catch (JavaModelException e) {
579 return new IPackageFragmentRoot[] {};
584 * Returns the package fragment roots identified by the given entry. In case it refers to
585 * a project, it will follow its classpath so as to find exported roots as well.
586 * Only works with resolved entry
588 public void computePackageFragmentRoots(
589 IClasspathEntry resolvedEntry,
590 ObjectVector accumulatedRoots,
592 boolean insideOriginalProject,
593 boolean checkExistency,
594 boolean retrieveExportedRoots) throws JavaModelException {
596 String rootID = ((ClasspathEntry)resolvedEntry).rootID();
597 if (rootIDs.contains(rootID)) return;
599 IPath projectPath = getProject().getFullPath();
600 IPath entryPath = resolvedEntry.getPath();
601 IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
603 switch(resolvedEntry.getEntryKind()){
606 case IClasspathEntry.CPE_SOURCE :
608 if (projectPath.isPrefixOf(entryPath)){
609 if (checkExistency) {
610 Object target = JavaModel.getTarget(workspaceRoot, entryPath, checkExistency);
611 if (target == null) return;
613 if (target instanceof IFolder || target instanceof IProject){
614 accumulatedRoots.add(
615 getPackageFragmentRoot((IResource)target));
619 IPackageFragmentRoot root = getFolderPackageFragmentRoot(entryPath);
621 accumulatedRoots.add(root);
628 // internal/external JAR or folder
629 case IClasspathEntry.CPE_LIBRARY :
631 if (!insideOriginalProject && !resolvedEntry.isExported()) return;
633 if (checkExistency) {
634 Object target = JavaModel.getTarget(workspaceRoot, entryPath, checkExistency);
635 if (target == null) return;
637 if (target instanceof IResource){
639 IResource resource = (IResource) target;
640 IPackageFragmentRoot root = getPackageFragmentRoot(resource);
642 accumulatedRoots.add(root);
646 // external target - only JARs allowed
647 // if (((java.io.File)target).isFile() && (ProjectPrefUtil.isArchiveFileName(entryPath.lastSegment()))) {
648 // accumulatedRoots.add(
649 // new JarPackageFragmentRoot(entryPath, this));
650 // rootIDs.add(rootID);
654 IPackageFragmentRoot root = getPackageFragmentRoot(entryPath);
656 accumulatedRoots.add(root);
662 // recurse into required project
663 case IClasspathEntry.CPE_PROJECT :
665 if (!retrieveExportedRoots) return;
666 if (!insideOriginalProject && !resolvedEntry.isExported()) return;
668 IResource member = workspaceRoot.findMember(entryPath);
669 if (member != null && member.getType() == IResource.PROJECT){// double check if bound to project (23977)
670 IProject requiredProjectRsc = (IProject) member;
671 if (JavaProject.hasJavaNature(requiredProjectRsc)){ // special builder binary output
673 JavaProject requiredProject = (JavaProject)JavaCore.create(requiredProjectRsc);
674 requiredProject.computePackageFragmentRoots(
675 requiredProject.getResolvedClasspath(true),
680 retrieveExportedRoots);
688 * Returns (local/all) the package fragment roots identified by the given project's classpath.
689 * Note: this follows project classpath references to find required project contributions,
690 * eliminating duplicates silently.
691 * Only works with resolved entries
693 public void computePackageFragmentRoots(
694 IClasspathEntry[] resolvedClasspath,
695 ObjectVector accumulatedRoots,
697 boolean insideOriginalProject,
698 boolean checkExistency,
699 boolean retrieveExportedRoots) throws JavaModelException {
701 if (insideOriginalProject){
702 rootIDs.add(rootID());
704 for (int i = 0, length = resolvedClasspath.length; i < length; i++){
705 computePackageFragmentRoots(
706 resolvedClasspath[i],
709 insideOriginalProject,
711 retrieveExportedRoots);
716 * Compute the file name to use for a given shared property
718 public String computeSharedPropertyFileName(QualifiedName qName) {
720 return '.' + qName.getLocalName();
724 * Returns whether the given resource is accessible through the children or the non-Java resources of this project.
725 * Returns true if the resource is not in the project.
726 * Assumes that the resource is a folder or a file.
728 public boolean contains(IResource resource) {
730 IClasspathEntry[] classpath;
733 classpath = getResolvedClasspath(true);
734 output = getOutputLocation();
735 } catch (JavaModelException e) {
739 IPath fullPath = resource.getFullPath();
740 IPath innerMostOutput = output.isPrefixOf(fullPath) ? output : null;
741 IClasspathEntry innerMostEntry = null;
742 for (int j = 0, cpLength = classpath.length; j < cpLength; j++) {
743 IClasspathEntry entry = classpath[j];
745 IPath entryPath = entry.getPath();
746 if ((innerMostEntry == null || innerMostEntry.getPath().isPrefixOf(entryPath))
747 && entryPath.isPrefixOf(fullPath)) {
748 innerMostEntry = entry;
750 IPath entryOutput = classpath[j].getOutputLocation();
751 if (entryOutput != null && entryOutput.isPrefixOf(fullPath)) {
752 innerMostOutput = entryOutput;
755 if (innerMostEntry != null) {
756 // special case prj==src and nested output location
757 if (innerMostOutput != null && innerMostOutput.segmentCount() > 1 // output isn't project
758 && innerMostEntry.getPath().segmentCount() == 1) { // 1 segment must be project name
761 if (resource instanceof IFolder) {
762 // folders are always included in src/lib entries
765 switch (innerMostEntry.getEntryKind()) {
766 case IClasspathEntry.CPE_SOURCE:
767 // .class files are not visible in source folders
768 return true; //!net.sourceforge.phpdt.internal.compiler.util.ProjectPrefUtil.isClassFileName(fullPath.lastSegment());
769 case IClasspathEntry.CPE_LIBRARY:
770 // .java files are not visible in library folders
771 return !net.sourceforge.phpdt.internal.compiler.util.Util.isJavaFileName(fullPath.lastSegment());
774 if (innerMostOutput != null) {
781 * Record a new marker denoting a classpath problem
783 IMarker createClasspathProblemMarker(IJavaModelStatus status) {
785 IMarker marker = null;
787 String[] arguments = new String[0];
788 boolean isCycleProblem = false, isClasspathFileFormatProblem = false;
789 switch (status.getCode()) {
791 case IJavaModelStatusConstants.CLASSPATH_CYCLE :
792 isCycleProblem = true;
793 if (JavaCore.ERROR.equals(getOption(JavaCore.CORE_CIRCULAR_CLASSPATH, true))) {
794 severity = IMarker.SEVERITY_ERROR;
796 severity = IMarker.SEVERITY_WARNING;
800 case IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT :
801 isClasspathFileFormatProblem = true;
802 severity = IMarker.SEVERITY_ERROR;
806 IPath path = status.getPath();
807 if (path != null) arguments = new String[] { path.toString() };
808 if (JavaCore.ERROR.equals(getOption(JavaCore.CORE_INCOMPLETE_CLASSPATH, true))) {
809 severity = IMarker.SEVERITY_ERROR;
811 severity = IMarker.SEVERITY_WARNING;
817 marker = getProject().createMarker(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER);
818 marker.setAttributes(
823 IJavaModelMarker.CYCLE_DETECTED,
824 IJavaModelMarker.CLASSPATH_FILE_FORMAT,
826 IJavaModelMarker.ARGUMENTS ,
830 new Integer(severity),
831 Util.bind("classpath.buildPath"),//$NON-NLS-1$
832 isCycleProblem ? "true" : "false",//$NON-NLS-1$ //$NON-NLS-2$
833 isClasspathFileFormatProblem ? "true" : "false",//$NON-NLS-1$ //$NON-NLS-2$
834 new Integer(status.getCode()),
835 Util.getProblemArgumentsForMarker(arguments) ,
838 } catch (CoreException e) {
844 * Returns a new element info for this element.
846 protected Object createElementInfo() {
847 return new JavaProjectElementInfo();
852 * Returns a new search name environment for this project. This name environment first looks in the given working copies.
854 // public ISearchableNameEnvironment newSearchableNameEnvironment(ICompilationUnit[] workingCopies) throws JavaModelException {
855 // return new SearchableEnvironment(this, workingCopies);
859 * Returns a new search name environment for this project. This name environment first looks in the working copies
860 * of the given owner.
862 public ISearchableNameEnvironment newSearchableNameEnvironment(WorkingCopyOwner owner) throws JavaModelException {
863 return new SearchableEnvironment(this, owner);
866 * Reads and decode an XML classpath string
868 protected IClasspathEntry[] decodeClasspath(String xmlClasspath, boolean createMarker, boolean logProblems) {
870 ArrayList paths = new ArrayList();
871 IClasspathEntry defaultOutput = null;
873 if (xmlClasspath == null) return null;
874 StringReader reader = new StringReader(xmlClasspath);
878 DocumentBuilder parser =
879 DocumentBuilderFactory.newInstance().newDocumentBuilder();
880 cpElement = parser.parse(new InputSource(reader)).getDocumentElement();
881 } catch (SAXException e) {
882 throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$
883 } catch (ParserConfigurationException e) {
884 throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$
889 if (!cpElement.getNodeName().equalsIgnoreCase("classpath")) { //$NON-NLS-1$
890 throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$
892 NodeList list = cpElement.getElementsByTagName("classpathentry"); //$NON-NLS-1$
893 int length = list.getLength();
895 for (int i = 0; i < length; ++i) {
896 Node node = list.item(i);
897 if (node.getNodeType() == Node.ELEMENT_NODE) {
898 IClasspathEntry entry = ClasspathEntry.elementDecode((Element)node, this);
900 if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
901 defaultOutput = entry; // separate output
908 } catch (IOException e) {
910 if (createMarker && this.getProject().isAccessible()) {
911 this.createClasspathProblemMarker(new JavaModelStatus(
912 IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
913 Util.bind("classpath.xmlFormatError", this.getElementName(), e.getMessage()))); //$NON-NLS-1$
917 "Exception while retrieving "+ this.getPath() //$NON-NLS-1$
918 +"/.classpath, will mark classpath as invalid"); //$NON-NLS-1$
920 return INVALID_CLASSPATH;
921 } catch (Assert.AssertionFailedException e) {
922 // failed creating CP entries from file
923 if (createMarker && this.getProject().isAccessible()) {
924 this.createClasspathProblemMarker(new JavaModelStatus(
925 IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
926 Util.bind("classpath.illegalEntryInClasspathFile", this.getElementName(), e.getMessage()))); //$NON-NLS-1$
930 "Exception while retrieving "+ this.getPath() //$NON-NLS-1$
931 +"/.classpath, will mark classpath as invalid"); //$NON-NLS-1$
933 return INVALID_CLASSPATH;
935 int pathSize = paths.size();
936 if (pathSize > 0 || defaultOutput != null) {
937 IClasspathEntry[] entries = new IClasspathEntry[pathSize + (defaultOutput == null ? 0 : 1)];
938 paths.toArray(entries);
939 if (defaultOutput != null) entries[pathSize] = defaultOutput; // ensure output is last item
948 * Removes the Java nature from the project.
950 public void deconfigure() throws CoreException {
952 // deregister Java builder
953 removeFromBuildSpec(PHPeclipsePlugin.BUILDER_PARSER_ID);
957 * Returns a default class path.
958 * This is the root of the project
960 protected IClasspathEntry[] defaultClasspath() throws JavaModelException {
962 return new IClasspathEntry[] {
963 JavaCore.newSourceEntry(getProject().getFullPath())};
967 * Returns a default output location.
968 * This is the project bin folder
970 protected IPath defaultOutputLocation() throws JavaModelException {
971 return null; //getProject().getFullPath().append("bin"); //$NON-NLS-1$
975 * Returns the XML String encoding of the class path.
977 protected String encodeClasspath(IClasspathEntry[] classpath, IPath outputLocation, boolean indent) throws JavaModelException {
979 ByteArrayOutputStream s = new ByteArrayOutputStream();
980 OutputStreamWriter writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
981 XMLWriter xmlWriter = new XMLWriter(writer);
983 xmlWriter.startTag("classpath", indent); //$NON-NLS-1$
984 for (int i = 0; i < classpath.length; ++i) {
985 ((ClasspathEntry)classpath[i]).elementEncode(xmlWriter, this.project.getFullPath(), indent, true);
988 if (outputLocation != null) {
989 outputLocation = outputLocation.removeFirstSegments(1);
990 outputLocation = outputLocation.makeRelative();
991 HashMap parameters = new HashMap();
992 parameters.put("kind", ClasspathEntry.kindToString(ClasspathEntry.K_OUTPUT));//$NON-NLS-1$
993 parameters.put("path", String.valueOf(outputLocation));//$NON-NLS-1$
994 xmlWriter.printTag("classpathentry", parameters, indent, true, true);//$NON-NLS-1$
997 xmlWriter.endTag("classpath", indent);//$NON-NLS-1$
1000 return s.toString("UTF8");//$NON-NLS-1$
1001 } catch (IOException e) {
1002 throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
1006 * Returns the XML String encoding of the class path.
1008 // protected String encodeClasspath(IClasspathEntry[] classpath, IPath outputLocation, boolean useLineSeparator) throws JavaModelException {
1010 // Document document = new DocumentImpl();
1011 // Element cpElement = document.createElement("classpath"); //$NON-NLS-1$
1012 // document.appendChild(cpElement);
1014 // for (int i = 0; i < classpath.length; ++i) {
1015 // cpElement.appendChild(((ClasspathEntry)classpath[i]).elementEncode(document, getProject().getFullPath()));
1018 // if (outputLocation != null) {
1019 // outputLocation = outputLocation.removeFirstSegments(1);
1020 // outputLocation = outputLocation.makeRelative();
1021 // Element oElement = document.createElement("classpathentry"); //$NON-NLS-1$
1022 // oElement.setAttribute("kind", ClasspathEntry.kindToString(ClasspathEntry.K_OUTPUT)); //$NON-NLS-1$
1023 // oElement.setAttribute("path", outputLocation.toString()); //$NON-NLS-1$
1024 // cpElement.appendChild(oElement);
1027 // // produce a String output
1029 // ByteArrayOutputStream s = new ByteArrayOutputStream();
1030 // OutputFormat format = new OutputFormat();
1031 // if (useLineSeparator) {
1032 // format.setIndenting(true);
1033 // format.setLineSeparator(System.getProperty("line.separator")); //$NON-NLS-1$
1035 // format.setPreserveSpace(true);
1037 // Serializer serializer =
1038 // SerializerFactory.getSerializerFactory(Method.XML).makeSerializer(
1039 // new OutputStreamWriter(s, "UTF8"), //$NON-NLS-1$
1041 // serializer.asDOMSerializer().serialize(document);
1042 // return s.toString("UTF8"); //$NON-NLS-1$
1043 // } catch (IOException e) {
1044 // throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
1049 * Returns true if this handle represents the same Java project
1050 * as the given handle. Two handles represent the same
1051 * project if they are identical or if they represent a project with
1052 * the same underlying resource and occurrence counts.
1054 * @see JavaElement#equals
1056 public boolean equals(Object o) {
1061 if (!(o instanceof JavaProject))
1064 JavaProject other = (JavaProject) o;
1065 return getProject().equals(other.getProject())
1066 && occurrenceCount == other.occurrenceCount;
1069 public boolean exists() {
1070 if (!hasJavaNature(project)) return false;
1071 return super.exists();
1077 public IJavaElement findElement(IPath path) throws JavaModelException {
1079 if (path == null || path.isAbsolute()) {
1080 throw new JavaModelException(
1081 new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, path));
1085 String extension = path.getFileExtension();
1086 if (extension == null) {
1087 String packageName = path.toString().replace(IPath.SEPARATOR, '.');
1089 // IPackageFragment[] pkgFragments =
1090 // getNameLookup().findPackageFragments(packageName, false);
1091 // if (pkgFragments == null) {
1095 // // try to return one that is a child of this project
1096 // for (int i = 0, length = pkgFragments.length; i < length; i++) {
1098 // IPackageFragment pkgFragment = pkgFragments[i];
1099 // if (this.equals(pkgFragment.getParent().getParent())) {
1100 // return pkgFragment;
1103 // // default to the first one
1104 // return pkgFragments[0];
1107 extension.equalsIgnoreCase("java") //$NON-NLS-1$
1108 || extension.equalsIgnoreCase("class")) { //$NON-NLS-1$
1109 IPath packagePath = path.removeLastSegments(1);
1110 String packageName = packagePath.toString().replace(IPath.SEPARATOR, '.');
1111 String typeName = path.lastSegment();
1112 typeName = typeName.substring(0, typeName.length() - extension.length() - 1);
1113 String qualifiedName = null;
1114 if (packageName.length() > 0) {
1115 qualifiedName = packageName + "." + typeName; //$NON-NLS-1$
1117 qualifiedName = typeName;
1120 // getNameLookup().findType(
1123 // NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
1124 // if (type != null) {
1125 // return type.getParent();
1130 // unsupported extension
1133 // } catch (JavaModelException e) {
1134 // if (e.getStatus().getCode()
1135 // == IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST) {
1146 // public IPackageFragment findPackageFragment(IPath path)
1147 // throws JavaModelException {
1149 // return findPackageFragment0(JavaProject.canonicalizedPath(path));
1153 // * non path canonicalizing version
1155 // public IPackageFragment findPackageFragment0(IPath path)
1156 // throws JavaModelException {
1158 // return getNameLookup().findPackageFragment(path);
1164 public IPackageFragmentRoot findPackageFragmentRoot(IPath path)
1165 throws JavaModelException {
1167 return findPackageFragmentRoot0(JavaProject.canonicalizedPath(path));
1171 * no path canonicalization
1173 public IPackageFragmentRoot findPackageFragmentRoot0(IPath path)
1174 throws JavaModelException {
1176 IPackageFragmentRoot[] allRoots = this.getAllPackageFragmentRoots();
1177 if (!path.isAbsolute()) {
1178 throw new IllegalArgumentException(Util.bind("path.mustBeAbsolute")); //$NON-NLS-1$
1180 for (int i= 0; i < allRoots.length; i++) {
1181 IPackageFragmentRoot classpathRoot= allRoots[i];
1182 if (classpathRoot.getPath().equals(path)) {
1183 return classpathRoot;
1191 public IPackageFragmentRoot[] findPackageFragmentRoots(IClasspathEntry entry) {
1193 IClasspathEntry[] classpath = this.getRawClasspath();
1194 for (int i = 0, length = classpath.length; i < length; i++) {
1195 if (classpath[i].equals(entry)) { // entry may need to be resolved
1197 computePackageFragmentRoots(
1198 getResolvedClasspath(new IClasspathEntry[] {entry}, null, true, false, null/*no reverse map*/),
1199 false); // don't retrieve exported roots
1202 } catch (JavaModelException e) {
1204 return new IPackageFragmentRoot[] {};
1208 * @see IJavaProject#findType(String)
1210 // public IType findType(String fullyQualifiedName) throws JavaModelException {
1212 // this.getNameLookup().findType(
1213 // fullyQualifiedName,
1215 // NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
1216 // if (type == null) {
1217 // // try to find enclosing type
1218 // int lastDot = fullyQualifiedName.lastIndexOf('.');
1219 // if (lastDot == -1) return null;
1220 // type = this.findType(fullyQualifiedName.substring(0, lastDot));
1221 // if (type != null) {
1222 // type = type.getType(fullyQualifiedName.substring(lastDot+1));
1223 // if (!type.exists()) {
1232 * @see IJavaProject#findType(String, String)
1234 // public IType findType(String packageName, String typeQualifiedName) throws JavaModelException {
1236 // this.getNameLookup().findType(
1237 // typeQualifiedName,
1240 // NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
1244 * Remove all markers denoting classpath problems
1246 protected void flushClasspathProblemMarkers(boolean flushCycleMarkers, boolean flushClasspathFormatMarkers) {
1248 IProject project = getProject();
1249 if (project.exists()) {
1250 IMarker[] markers = project.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
1251 for (int i = 0, length = markers.length; i < length; i++) {
1252 IMarker marker = markers[i];
1253 if (flushCycleMarkers && flushClasspathFormatMarkers) {
1256 String cycleAttr = (String)marker.getAttribute(IJavaModelMarker.CYCLE_DETECTED);
1257 String classpathFileFormatAttr = (String)marker.getAttribute(IJavaModelMarker.CLASSPATH_FILE_FORMAT);
1258 if ((flushCycleMarkers == (cycleAttr != null && cycleAttr.equals("true"))) //$NON-NLS-1$
1259 && (flushClasspathFormatMarkers == (classpathFileFormatAttr != null && classpathFileFormatAttr.equals("true")))){ //$NON-NLS-1$
1265 } catch (CoreException e) {
1272 // protected boolean generateInfos(
1273 // OpenableElementInfo info,
1274 // IProgressMonitor pm,
1276 // IResource underlyingResource) throws JavaModelException {
1278 // boolean validInfo = false;
1280 // if (getProject().isOpen()) {
1281 // // put the info now, because computing the roots requires it
1282 // JavaModelManager.getJavaModelManager().putInfo(this, info);
1284 // // compute the pkg fragment roots
1285 // updatePackageFragmentRoots();
1287 // // remember the timestamps of external libraries the first time they are looked up
1288 // IClasspathEntry[] resolvedClasspath = getResolvedClasspath(true/*ignore unresolved variable*/);
1289 // for (int i = 0, length = resolvedClasspath.length; i < length; i++) {
1290 // IClasspathEntry entry = resolvedClasspath[i];
1291 // if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
1292 // IPath path = entry.getPath();
1293 // Object target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), path, true);
1294 // if (target instanceof java.io.File) {
1295 // Map externalTimeStamps = JavaModelManager.getJavaModelManager().deltaProcessor.externalTimeStamps;
1296 // if (externalTimeStamps.get(path) == null) {
1297 // long timestamp = DeltaProcessor.getTimeStamp((java.io.File)target);
1298 // externalTimeStamps.put(path, new Long(timestamp));
1304 // // only valid if reaches here
1305 // validInfo = true;
1309 // JavaModelManager.getJavaModelManager().removeInfo(this);
1311 // return validInfo;
1317 public IPackageFragmentRoot[] getAllPackageFragmentRoots()
1318 throws JavaModelException {
1320 return computePackageFragmentRoots(getResolvedClasspath(true), true);
1324 * Returns the classpath entry that refers to the given path
1325 * or <code>null</code> if there is no reference to the path.
1327 public IClasspathEntry getClasspathEntryFor(IPath path)
1328 throws JavaModelException {
1330 IClasspathEntry[] entries = getExpandedClasspath(true);
1331 for (int i = 0; i < entries.length; i++) {
1332 if (entries[i].getPath().equals(path)) {
1340 * Returns the cycle marker associated with this project or null if none.
1342 public IMarker getCycleMarker(){
1344 IProject project = getProject();
1345 if (project.exists()) {
1346 IMarker[] markers = project.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
1347 for (int i = 0, length = markers.length; i < length; i++) {
1348 IMarker marker = markers[i];
1349 String cycleAttr = (String)marker.getAttribute(IJavaModelMarker.CYCLE_DETECTED);
1350 if (cycleAttr != null && cycleAttr.equals("true")){ //$NON-NLS-1$
1355 } catch (CoreException e) {
1362 public int getElementType() {
1363 return JAVA_PROJECT;
1366 * This is a helper method returning the expanded classpath for the project, as a list of classpath entries,
1367 * where all classpath variable entries have been resolved and substituted with their final target entries.
1368 * All project exports have been appended to project entries.
1369 * @param ignoreUnresolvedVariable boolean
1370 * @return IClasspathEntry[]
1371 * @throws JavaModelException
1373 public IClasspathEntry[] getExpandedClasspath(boolean ignoreUnresolvedVariable) throws JavaModelException {
1375 return getExpandedClasspath(ignoreUnresolvedVariable, false/*don't create markers*/, null, null);
1381 public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner) {
1382 switch (token.charAt(0)) {
1384 return getHandleUpdatingCountFromMemento(memento, owner);
1385 case JEM_PACKAGEFRAGMENTROOT:
1386 String rootPath = IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH;
1388 while (memento.hasMoreTokens()) {
1389 token = memento.nextToken();
1390 char firstChar = token.charAt(0);
1391 if (firstChar != JEM_PACKAGEFRAGMENT && firstChar != JEM_COUNT) {
1397 JavaElement root = (JavaElement)getPackageFragmentRoot(new Path(rootPath));
1398 if (token != null && token.charAt(0) == JEM_PACKAGEFRAGMENT) {
1399 return root.getHandleFromMemento(token, memento, owner);
1401 return root.getHandleFromMemento(memento, owner);
1408 * Returns the <code>char</code> that marks the start of this handles
1409 * contribution to a memento.
1411 protected char getHandleMementoDelimiter() {
1413 return JEM_JAVAPROJECT;
1417 * Internal variant which can create marker on project for invalid entries,
1418 * it will also perform classpath expansion in presence of project prerequisites
1419 * exporting their entries.
1420 * @param ignoreUnresolvedVariable boolean
1421 * @param generateMarkerOnError boolean
1422 * @param preferredClasspaths Map
1423 * @param preferredOutputs Map
1424 * @return IClasspathEntry[]
1425 * @throws JavaModelException
1427 public IClasspathEntry[] getExpandedClasspath(
1428 boolean ignoreUnresolvedVariable,
1429 boolean generateMarkerOnError,
1430 Map preferredClasspaths,
1431 Map preferredOutputs) throws JavaModelException {
1433 ObjectVector accumulatedEntries = new ObjectVector();
1434 computeExpandedClasspath(this, ignoreUnresolvedVariable, generateMarkerOnError, new HashSet(5), accumulatedEntries, preferredClasspaths, preferredOutputs);
1436 IClasspathEntry[] expandedPath = new IClasspathEntry[accumulatedEntries.size()];
1437 accumulatedEntries.copyInto(expandedPath);
1439 return expandedPath;
1442 // * Internal variant which can create marker on project for invalid entries,
1443 // * it will also perform classpath expansion in presence of project prerequisites
1444 // * exporting their entries.
1446 // public IClasspathEntry[] getExpandedClasspath(
1447 // boolean ignoreUnresolvedVariable,
1448 // boolean generateMarkerOnError) throws JavaModelException {
1450 // ObjectVector accumulatedEntries = new ObjectVector();
1451 // computeExpandedClasspath(this, ignoreUnresolvedVariable, generateMarkerOnError, new HashSet(5), accumulatedEntries);
1453 // IClasspathEntry[] expandedPath = new IClasspathEntry[accumulatedEntries.size()];
1454 // accumulatedEntries.copyInto(expandedPath);
1456 // return expandedPath;
1460 * Find the specific Java command amongst the build spec of a given description
1462 private ICommand getJavaCommand(IProjectDescription description)
1463 throws CoreException {
1465 ICommand[] commands = description.getBuildSpec();
1466 for (int i = 0; i < commands.length; ++i) {
1467 if (commands[i].getBuilderName().equals(PHPeclipsePlugin.BUILDER_PARSER_ID)) {
1475 * Convenience method that returns the specific type of info for a Java project.
1477 protected JavaProjectElementInfo getJavaProjectElementInfo()
1478 throws JavaModelException {
1480 return (JavaProjectElementInfo) getElementInfo();
1486 public NameLookup getNameLookup() throws JavaModelException {
1488 JavaProjectElementInfo info = getJavaProjectElementInfo();
1489 // lock on the project info to avoid race condition
1491 NameLookup nameLookup;
1492 if ((nameLookup = info.getNameLookup()) == null){
1493 info.setNameLookup(nameLookup = new NameLookup(this));
1499 * Returns a new name lookup. This name lookup first looks in the given working copies.
1501 public NameLookup newNameLookup(ICompilationUnit[] workingCopies) throws JavaModelException {
1503 JavaProjectElementInfo info = getJavaProjectElementInfo();
1504 // lock on the project info to avoid race condition while computing the pkg fragment roots and package fragment caches
1505 // synchronized(info){
1506 // return new NameLookup(info.getAllPackageFragmentRoots(this), info.getAllPackageFragments(this), workingCopies);
1512 * Returns a new name lookup. This name lookup first looks in the working copies of the given owner.
1514 public NameLookup newNameLookup(WorkingCopyOwner owner) throws JavaModelException {
1516 JavaModelManager manager = JavaModelManager.getJavaModelManager();
1517 ICompilationUnit[] workingCopies = owner == null ? null : manager.getWorkingCopies(owner, true/*add primary WCs*/);
1518 return newNameLookup(workingCopies);
1522 // * Returns an array of non-java resources contained in the receiver.
1524 // public Object[] getNonJavaResources() throws JavaModelException {
1526 // return ((JavaProjectElementInfo) getElementInfo()).getNonJavaResources(this);
1530 * @see net.sourceforge.phpdt.core.IJavaProject#getOption(String, boolean)
1532 public String getOption(String optionName, boolean inheritJavaCoreOptions) {
1534 if (JavaModelManager.OptionNames.contains(optionName)){
1536 Preferences preferences = getPreferences();
1537 if (preferences == null || preferences.isDefault(optionName)) {
1538 return inheritJavaCoreOptions ? JavaCore.getOption(optionName) : null;
1540 return preferences.getString(optionName).trim();
1546 * @see net.sourceforge.phpdt.core.IJavaProject#getOptions(boolean)
1548 public Map getOptions(boolean inheritJavaCoreOptions) {
1550 // initialize to the defaults from JavaCore options pool
1551 Map options = inheritJavaCoreOptions ? JavaCore.getOptions() : new Hashtable(5);
1553 Preferences preferences = getPreferences();
1554 if (preferences == null) return options; // cannot do better (non-Java project)
1555 HashSet optionNames = JavaModelManager.OptionNames;
1557 // get preferences set to their default
1558 if (inheritJavaCoreOptions){
1559 String[] defaultPropertyNames = preferences.defaultPropertyNames();
1560 for (int i = 0; i < defaultPropertyNames.length; i++){
1561 String propertyName = defaultPropertyNames[i];
1562 if (optionNames.contains(propertyName)){
1563 options.put(propertyName, preferences.getDefaultString(propertyName).trim());
1567 // get custom preferences not set to their default
1568 String[] propertyNames = preferences.propertyNames();
1569 for (int i = 0; i < propertyNames.length; i++){
1570 String propertyName = propertyNames[i];
1571 if (optionNames.contains(propertyName)){
1572 options.put(propertyName, preferences.getString(propertyName).trim());
1581 // public IPath getOutputLocation() throws JavaModelException {
1583 // JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project);
1584 // IPath outputLocation = perProjectInfo.outputLocation;
1585 // if (outputLocation != null) return outputLocation;
1587 // // force to read classpath - will position output location as well
1588 // this.getRawClasspath();
1589 // outputLocation = perProjectInfo.outputLocation;
1590 // if (outputLocation == null) {
1591 // return defaultOutputLocation();
1593 // return outputLocation;
1598 public IPath getOutputLocation() throws JavaModelException {
1599 // Do not create marker but log problems while getting output location
1600 return this.getOutputLocation(false, true);
1604 * @param createMarkers boolean
1605 * @param logProblems boolean
1607 * @throws JavaModelException
1609 public IPath getOutputLocation(boolean createMarkers, boolean logProblems) throws JavaModelException {
1611 JavaModelManager.PerProjectInfo perProjectInfo = getPerProjectInfo();
1612 IPath outputLocation = perProjectInfo.outputLocation;
1613 if (outputLocation != null) return outputLocation;
1615 // force to read classpath - will position output location as well
1616 this.getRawClasspath(createMarkers, logProblems);
1617 outputLocation = perProjectInfo.outputLocation;
1618 if (outputLocation == null) {
1619 return defaultOutputLocation();
1621 return outputLocation;
1624 * @return A handle to the package fragment root identified by the given path.
1625 * This method is handle-only and the element may or may not exist. Returns
1626 * <code>null</code> if unable to generate a handle from the path (for example,
1627 * an absolute path that has less than 1 segment. The path may be relative or
1630 public IPackageFragmentRoot getPackageFragmentRoot(IPath path) {
1631 if (!path.isAbsolute()) {
1632 path = getPath().append(path);
1634 int segmentCount = path.segmentCount();
1635 switch (segmentCount) {
1640 return getPackageFragmentRoot(getProject());
1642 // a path ending with .jar/.zip is still ambiguous and could still resolve to a source/lib folder
1643 // thus will try to guess based on existing resource
1644 // if (ProjectPrefUtil.isArchiveFileName(path.lastSegment())) {
1645 // IResource resource = getProject().getWorkspace().getRoot().findMember(path);
1646 // if (resource != null && resource.getType() == IResource.FOLDER){
1647 // return getPackageFragmentRoot(resource);
1649 // return getPackageFragmentRoot0(path);
1651 return getPackageFragmentRoot(getProject().getWorkspace().getRoot().getFolder(path));
1657 * The path is known to match a source/library folder entry.
1659 public IPackageFragmentRoot getFolderPackageFragmentRoot(IPath path) {
1660 if (path.segmentCount() == 1) { // default project root
1661 return getPackageFragmentRoot(getProject());
1663 return getPackageFragmentRoot(getProject().getWorkspace().getRoot().getFolder(path));
1669 public IPackageFragmentRoot getPackageFragmentRoot(IResource resource) {
1671 switch (resource.getType()) {
1672 case IResource.FILE:
1673 // if (ProjectPrefUtil.isArchiveFileName(resource.getName())) {
1674 // return new JarPackageFragmentRoot(resource, this);
1678 case IResource.FOLDER:
1679 return new PackageFragmentRoot(resource, this, resource.getName());
1680 case IResource.PROJECT:
1681 return new PackageFragmentRoot(resource, this, ""); //$NON-NLS-1$
1690 // public IPackageFragmentRoot getPackageFragmentRoot(String jarPath) {
1692 // return getPackageFragmentRoot0(JavaProject.canonicalizedPath(new Path(jarPath)));
1696 // * no path canonicalization
1698 // public IPackageFragmentRoot getPackageFragmentRoot0(IPath jarPath) {
1700 // return new JarPackageFragmentRoot(jarPath, this);
1706 public IPackageFragmentRoot[] getPackageFragmentRoots()
1707 throws JavaModelException {
1711 IPackageFragmentRoot[] roots;
1714 children = getChildren(),
1716 roots = new IPackageFragmentRoot[length = children.length],
1727 public IPackageFragmentRoot[] getPackageFragmentRoots(IClasspathEntry entry) {
1728 return findPackageFragmentRoots(entry);
1732 * Returns the package fragment root prefixed by the given path, or
1733 * an empty collection if there are no such elements in the model.
1735 protected IPackageFragmentRoot[] getPackageFragmentRoots(IPath path)
1737 throws JavaModelException {
1738 IPackageFragmentRoot[] roots = getAllPackageFragmentRoots();
1739 ArrayList matches = new ArrayList();
1741 for (int i = 0; i < roots.length; ++i) {
1742 if (path.isPrefixOf(roots[i].getPath())) {
1743 matches.add(roots[i]);
1746 IPackageFragmentRoot[] copy = new IPackageFragmentRoot[matches.size()];
1747 matches.toArray(copy);
1754 public IPackageFragment[] getPackageFragments() throws JavaModelException {
1756 IPackageFragmentRoot[] roots = getPackageFragmentRoots();
1757 return getPackageFragmentsInRoots(roots);
1761 * Returns all the package fragments found in the specified
1762 * package fragment roots.
1764 public IPackageFragment[] getPackageFragmentsInRoots(IPackageFragmentRoot[] roots) {
1766 ArrayList frags = new ArrayList();
1767 for (int i = 0; i < roots.length; i++) {
1768 IPackageFragmentRoot root = roots[i];
1770 IJavaElement[] rootFragments = root.getChildren();
1771 for (int j = 0; j < rootFragments.length; j++) {
1772 frags.add(rootFragments[j]);
1774 } catch (JavaModelException e) {
1778 IPackageFragment[] fragments = new IPackageFragment[frags.size()];
1779 frags.toArray(fragments);
1786 public IPath getPath() {
1787 return this.getProject().getFullPath();
1790 public JavaModelManager.PerProjectInfo getPerProjectInfo() throws JavaModelException {
1791 return JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(this.project);
1797 public IProject getProject() {
1802 * Sets the underlying kernel project of this Java project,
1803 * and fills in its parent and name.
1804 * Called by IProject.getNature().
1806 * @see IProjectNature#setProject(IProject)
1808 public void setProject(IProject project) {
1810 this.project = project;
1811 this.parent = JavaModelManager.getJavaModelManager().getJavaModel();
1812 this.name = project.getName();
1814 protected IProject getProject(String name) {
1815 return PHPeclipsePlugin.getWorkspace().getRoot().getProject(name);
1818 public List getReferencedProjects() {
1819 List referencedProjects = new ArrayList();
1821 Iterator iterator = getLoadPathEntries().iterator();
1822 while (iterator.hasNext()) {
1823 LoadPathEntry pathEntry = (LoadPathEntry) iterator.next();
1824 if (pathEntry.getType() == LoadPathEntry.TYPE_PROJECT)
1825 referencedProjects.add(pathEntry.getProject());
1828 return referencedProjects;
1832 * Returns the project custom preference pool.
1833 * Project preferences may include custom encoding.
1835 public Preferences getPreferences(){
1836 IProject project = getProject();
1837 if (!JavaProject.hasJavaNature(project)) return null;
1838 JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfo(project, true);
1839 Preferences preferences = perProjectInfo.preferences;
1840 if (preferences != null) return preferences;
1841 preferences = loadPreferences();
1842 if (preferences == null) preferences = new Preferences();
1843 perProjectInfo.preferences = preferences;
1850 // public IClasspathEntry[] getRawClasspath() throws JavaModelException {
1852 // JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project);
1853 // IClasspathEntry[] classpath = perProjectInfo.classpath;
1854 // if (classpath != null) return classpath;
1855 // classpath = this.readClasspathFile(false/*don't create markers*/, true/*log problems*/);
1857 // // extract out the output location
1858 // IPath outputLocation = null;
1859 // if (classpath != null && classpath.length > 0) {
1860 // IClasspathEntry entry = classpath[classpath.length - 1];
1861 // if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
1862 // outputLocation = entry.getPath();
1863 // IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1];
1864 // System.arraycopy(classpath, 0, copy, 0, copy.length);
1865 // classpath = copy;
1868 // if (classpath == null) {
1869 // return defaultClasspath();
1871 // /* Disable validate: classpath can contain CP variables and container that need to be resolved
1872 // if (classpath != INVALID_CLASSPATH
1873 // && !JavaConventions.validateClasspath(this, classpath, outputLocation).isOK()) {
1874 // classpath = INVALID_CLASSPATH;
1877 // perProjectInfo.classpath = classpath;
1878 // perProjectInfo.outputLocation = outputLocation;
1879 // return classpath;
1884 public IClasspathEntry[] getRawClasspath() throws JavaModelException {
1885 // Do not create marker but log problems while getting raw classpath
1886 return getRawClasspath(false, true);
1890 * Internal variant allowing to parameterize problem creation/logging
1892 public IClasspathEntry[] getRawClasspath(boolean createMarkers, boolean logProblems) throws JavaModelException {
1894 JavaModelManager.PerProjectInfo perProjectInfo = null;
1895 IClasspathEntry[] classpath;
1896 if (createMarkers) {
1897 this.flushClasspathProblemMarkers(false/*cycle*/, true/*format*/);
1898 classpath = this.readClasspathFile(createMarkers, logProblems);
1900 perProjectInfo = getPerProjectInfo();
1901 classpath = perProjectInfo.rawClasspath;
1902 if (classpath != null) return classpath;
1903 classpath = this.readClasspathFile(createMarkers, logProblems);
1905 // extract out the output location
1906 IPath outputLocation = null;
1907 if (classpath != null && classpath.length > 0) {
1908 IClasspathEntry entry = classpath[classpath.length - 1];
1909 if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
1910 outputLocation = entry.getPath();
1911 IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1];
1912 System.arraycopy(classpath, 0, copy, 0, copy.length);
1916 if (classpath == null) {
1917 return defaultClasspath();
1919 /* Disable validate: classpath can contain CP variables and container that need to be resolved
1920 if (classpath != INVALID_CLASSPATH
1921 && !JavaConventions.validateClasspath(this, classpath, outputLocation).isOK()) {
1922 classpath = INVALID_CLASSPATH;
1925 if (!createMarkers) {
1926 perProjectInfo.rawClasspath = classpath;
1927 perProjectInfo.outputLocation = outputLocation;
1933 * @see IJavaProject#getRequiredProjectNames
1935 public String[] getRequiredProjectNames() throws JavaModelException {
1937 return this.projectPrerequisites(getResolvedClasspath(true));
1943 public IClasspathEntry[] getResolvedClasspath(boolean ignoreUnresolvedEntry)
1944 throws JavaModelException {
1947 this.getResolvedClasspath(
1948 ignoreUnresolvedEntry,
1949 false); // generateMarkerOnError
1953 * Internal variant which can create marker on project for invalid entries
1954 * and caches the resolved classpath on perProjectInfo
1956 public IClasspathEntry[] getResolvedClasspath(
1957 boolean ignoreUnresolvedEntry,
1958 boolean generateMarkerOnError)
1959 throws JavaModelException {
1961 getResolvedClasspath(
1962 ignoreUnresolvedEntry,
1963 generateMarkerOnError,
1964 true // returnResolutionInProgress
1966 // JavaModelManager manager = JavaModelManager.getJavaModelManager();
1967 // JavaModelManager.PerProjectInfo perProjectInfo = manager.getPerProjectInfoCheckExistence(project);
1969 // // reuse cache if not needing to refresh markers or checking bound variables
1970 // if (ignoreUnresolvedEntry && !generateMarkerOnError && perProjectInfo != null){
1971 // // resolved path is cached on its info
1972 // IClasspathEntry[] infoPath = perProjectInfo.lastResolvedClasspath;
1973 // if (infoPath != null) return infoPath;
1975 // Map reverseMap = perProjectInfo == null ? null : new HashMap(5);
1976 // IClasspathEntry[] resolvedPath = getResolvedClasspath(
1977 // getRawClasspath(),
1978 // generateMarkerOnError ? getOutputLocation() : null,
1979 // ignoreUnresolvedEntry,
1980 // generateMarkerOnError,
1983 // if (perProjectInfo != null){
1984 // if (perProjectInfo.classpath == null // .classpath file could not be read
1985 // && generateMarkerOnError
1986 // && JavaProject.hasJavaNature(project)) {
1987 // this.createClasspathProblemMarker(new JavaModelStatus(
1988 // IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
1989 // Util.bind("classpath.cannotReadClasspathFile", this.getElementName()))); //$NON-NLS-1$
1992 // perProjectInfo.lastResolvedClasspath = resolvedPath;
1993 // perProjectInfo.resolvedPathToRawEntries = reverseMap;
1995 // return resolvedPath;
1998 * Internal variant which can create marker on project for invalid entries
1999 * and caches the resolved classpath on perProjectInfo.
2000 * If requested, return a special classpath (RESOLUTION_IN_PROGRESS) if the classpath is being resolved.
2002 public IClasspathEntry[] getResolvedClasspath(
2003 boolean ignoreUnresolvedEntry,
2004 boolean generateMarkerOnError,
2005 boolean returnResolutionInProgress)
2006 throws JavaModelException {
2008 JavaModelManager manager = JavaModelManager.getJavaModelManager();
2009 JavaModelManager.PerProjectInfo perProjectInfo = null;
2010 if (ignoreUnresolvedEntry && !generateMarkerOnError) {
2011 perProjectInfo = getPerProjectInfo();
2012 if (perProjectInfo != null) {
2013 // resolved path is cached on its info
2014 IClasspathEntry[] infoPath = perProjectInfo.resolvedClasspath;
2015 if (infoPath != null) {
2017 } else if (returnResolutionInProgress && manager.isClasspathBeingResolved(this)) {
2018 if (JavaModelManager.CP_RESOLVE_VERBOSE) {
2020 "CPResolution: reentering raw classpath resolution, will use empty classpath instead" + //$NON-NLS-1$
2021 " project: " + getElementName() + '\n' + //$NON-NLS-1$
2022 " invocation stack trace:"); //$NON-NLS-1$
2023 new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
2025 return RESOLUTION_IN_PROGRESS;
2029 Map reverseMap = perProjectInfo == null ? null : new HashMap(5);
2030 IClasspathEntry[] resolvedPath = null;
2031 boolean nullOldResolvedCP = perProjectInfo != null && perProjectInfo.resolvedClasspath == null;
2033 // protect against misbehaving clients (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=61040)
2034 if (nullOldResolvedCP) manager.setClasspathBeingResolved(this, true);
2035 resolvedPath = getResolvedClasspath(
2036 getRawClasspath(generateMarkerOnError, !generateMarkerOnError),
2037 generateMarkerOnError ? getOutputLocation() : null,
2038 ignoreUnresolvedEntry,
2039 generateMarkerOnError,
2042 if (nullOldResolvedCP) perProjectInfo.resolvedClasspath = null;
2045 if (perProjectInfo != null){
2046 if (perProjectInfo.rawClasspath == null // .classpath file could not be read
2047 && generateMarkerOnError
2048 && JavaProject.hasJavaNature(this.project)) {
2049 // flush .classpath format markers (bug 39877), but only when file cannot be read (bug 42366)
2050 this.flushClasspathProblemMarkers(false, true);
2051 this.createClasspathProblemMarker(new JavaModelStatus(
2052 IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
2053 Util.bind("classpath.cannotReadClasspathFile", this.getElementName()))); //$NON-NLS-1$
2056 perProjectInfo.resolvedClasspath = resolvedPath;
2057 perProjectInfo.resolvedPathToRawEntries = reverseMap;
2058 manager.setClasspathBeingResolved(this, false);
2060 return resolvedPath;
2063 * Internal variant which can process any arbitrary classpath
2065 public IClasspathEntry[] getResolvedClasspath(
2066 IClasspathEntry[] classpathEntries,
2067 IPath projectOutputLocation, // only set if needing full classpath validation (and markers)
2068 boolean ignoreUnresolvedEntry, // if unresolved entries are met, should it trigger initializations
2069 boolean generateMarkerOnError,
2070 Map reverseMap) // can be null if not interested in reverse mapping
2071 throws JavaModelException {
2073 IJavaModelStatus status;
2074 if (generateMarkerOnError){
2075 flushClasspathProblemMarkers(false, false);
2078 int length = classpathEntries.length;
2079 ArrayList resolvedEntries = new ArrayList();
2081 for (int i = 0; i < length; i++) {
2083 IClasspathEntry rawEntry = classpathEntries[i];
2087 /* validation if needed */
2088 // if (generateMarkerOnError || !ignoreUnresolvedEntry) {
2089 // status = JavaConventions.validateClasspathEntry(this, rawEntry, false);
2090 // if (generateMarkerOnError && !status.isOK()) createClasspathProblemMarker(status);
2093 switch (rawEntry.getEntryKind()){
2095 case IClasspathEntry.CPE_VARIABLE :
2097 IClasspathEntry resolvedEntry = JavaCore.getResolvedClasspathEntry(rawEntry);
2098 if (resolvedEntry == null) {
2099 if (!ignoreUnresolvedEntry) throw new JavaModelException(status);
2101 if (reverseMap != null && reverseMap.get(resolvedPath = resolvedEntry.getPath()) == null) reverseMap.put(resolvedPath , rawEntry);
2102 resolvedEntries.add(resolvedEntry);
2106 // case IClasspathEntry.CPE_CONTAINER :
2108 // IClasspathContainer container = PHPCore.getClasspathContainer(rawEntry.getPath(), this);
2109 // if (container == null){
2110 // if (!ignoreUnresolvedEntry) throw new JavaModelException(status);
2114 // IClasspathEntry[] containerEntries = container.getClasspathEntries();
2115 // if (containerEntries == null) break;
2117 // // container was bound
2118 // for (int j = 0, containerLength = containerEntries.length; j < containerLength; j++){
2119 // IClasspathEntry cEntry = containerEntries[j];
2121 // if (generateMarkerOnError) {
2122 // IJavaModelStatus containerStatus = JavaConventions.validateClasspathEntry(this, cEntry, false);
2123 // if (!containerStatus.isOK()) createClasspathProblemMarker(containerStatus);
2125 // // if container is exported, then its nested entries must in turn be exported (21749)
2126 // if (rawEntry.isExported()){
2127 // cEntry = new ClasspathEntry(cEntry.getContentKind(),
2128 // cEntry.getEntryKind(), cEntry.getPath(),
2129 // cEntry.getExclusionPatterns(), cEntry.getSourceAttachmentPath(),
2130 // cEntry.getSourceAttachmentRootPath(), cEntry.getOutputLocation(),
2131 // true); // duplicate container entry for tagging it as exported
2133 // if (reverseMap != null && reverseMap.get(resolvedPath = cEntry.getPath()) == null) reverseMap.put(resolvedPath, rawEntry);
2134 // resolvedEntries.add(cEntry);
2140 if (reverseMap != null && reverseMap.get(resolvedPath = rawEntry.getPath()) == null) reverseMap.put(resolvedPath, rawEntry);
2141 resolvedEntries.add(rawEntry);
2146 IClasspathEntry[] resolvedPath = new IClasspathEntry[resolvedEntries.size()];
2147 resolvedEntries.toArray(resolvedPath);
2149 // if (generateMarkerOnError && projectOutputLocation != null) {
2150 // status = JavaConventions.validateClasspath(this, resolvedPath, projectOutputLocation);
2151 // if (!status.isOK()) createClasspathProblemMarker(status);
2153 return resolvedPath;
2159 public IResource getResource() {
2160 return this.getProject();
2166 public ISearchableNameEnvironment getSearchableNameEnvironment()
2167 throws JavaModelException {
2169 // JavaProjectElementInfo info = getJavaProjectElementInfo();
2170 // if (info.getSearchableEnvironment() == null) {
2171 // info.setSearchableEnvironment(new SearchableEnvironment(this));
2173 // return info.getSearchableEnvironment();
2178 * Retrieve a shared property on a project. If the property is not defined, answers null.
2179 * Note that it is orthogonal to IResource persistent properties, and client code has to decide
2180 * which form of storage to use appropriately. Shared properties produce real resource files which
2181 * can be shared through a VCM onto a server. Persistent properties are not shareable.
2183 * @see JavaProject#setSharedProperty(String, String)
2185 public String getSharedProperty(String key) throws CoreException {
2187 String property = null;
2188 IFile rscFile = getProject().getFile(key);
2189 if (rscFile.exists()) {
2190 property = new String(Util.getResourceContentsAsByteArray(rscFile));
2198 // public SourceMapper getSourceMapper() {
2206 public IResource getUnderlyingResource() throws JavaModelException {
2207 if (!exists()) throw newNotPresentException();
2208 return getProject();
2214 public boolean hasBuildState() {
2216 return JavaModelManager.getJavaModelManager().getLastBuiltState(this.getProject(), null) != null;
2222 public boolean hasClasspathCycle(IClasspathEntry[] preferredClasspath) {
2223 HashSet cycleParticipants = new HashSet();
2224 updateCycleParticipants(preferredClasspath, new ArrayList(2), cycleParticipants, ResourcesPlugin.getWorkspace().getRoot(), new HashSet(2));
2225 return !cycleParticipants.isEmpty();
2228 public boolean hasCycleMarker(){
2229 return this.getCycleMarker() != null;
2232 public int hashCode() {
2233 return project.hashCode();
2237 * Returns true if the given project is accessible and it has
2238 * a java nature, otherwise false.
2240 public static boolean hasJavaNature(IProject project) {
2242 return project.hasNature(PHPeclipsePlugin.PHP_NATURE_ID);
2243 } catch (CoreException e) {
2244 // project does not exist or is not open
2250 * Answers true if the project potentially contains any source. A project which has no source is immutable.
2252 public boolean hasSource() {
2254 // look if any source folder on the classpath
2255 // no need for resolved path given source folder cannot be abstracted
2256 IClasspathEntry[] entries;
2258 entries = this.getRawClasspath();
2259 } catch (JavaModelException e) {
2260 return true; // unsure
2262 for (int i = 0, max = entries.length; i < max; i++) {
2263 if (entries[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) {
2271 * Compare current classpath with given one to see if any different.
2272 * Note that the argument classpath contains its binary output.
2274 public boolean isClasspathEqualsTo(IClasspathEntry[] newClasspath, IPath newOutputLocation, IClasspathEntry[] otherClasspathWithOutput)
2275 throws JavaModelException {
2277 if (otherClasspathWithOutput != null && otherClasspathWithOutput.length > 0) {
2279 int length = otherClasspathWithOutput.length;
2280 if (length == newClasspath.length + 1) {
2281 // output is amongst file entries (last one)
2283 // compare classpath entries
2284 for (int i = 0; i < length - 1; i++) {
2285 if (!otherClasspathWithOutput[i].equals(newClasspath[i]))
2288 // compare binary outputs
2289 IClasspathEntry output = otherClasspathWithOutput[length - 1];
2290 if (output.getContentKind() == ClasspathEntry.K_OUTPUT
2291 && output.getPath().equals(newOutputLocation))
2303 public boolean isOnClasspath(IJavaElement element) {
2304 IPath path = element.getPath();
2305 switch (element.getElementType()) {
2306 case IJavaElement.PACKAGE_FRAGMENT_ROOT:
2307 if (!((IPackageFragmentRoot)element).isArchive()) {
2308 // ensure that folders are only excluded if all of their children are excluded
2309 path = path.append("*"); //$NON-NLS-1$
2312 case IJavaElement.PACKAGE_FRAGMENT:
2313 if (!((IPackageFragmentRoot)element.getParent()).isArchive()) {
2314 // ensure that folders are only excluded if all of their children are excluded
2315 path = path.append("*"); //$NON-NLS-1$
2319 return this.isOnClasspath(path);
2321 private boolean isOnClasspath(IPath path) {
2322 IClasspathEntry[] classpath;
2324 classpath = this.getResolvedClasspath(true/*ignore unresolved variable*/);
2325 } catch(JavaModelException e){
2326 return false; // not a Java project
2328 for (int i = 0; i < classpath.length; i++) {
2329 IClasspathEntry entry = classpath[i];
2330 if (entry.getPath().isPrefixOf(path)
2331 && !Util.isExcluded(path, null,((ClasspathEntry)entry).fullExclusionPatternChars(),true)) {
2340 public boolean isOnClasspath(IResource resource) {
2341 IPath path = resource.getFullPath();
2343 // ensure that folders are only excluded if all of their children are excluded
2344 if (resource.getType() == IResource.FOLDER) {
2345 path = path.append("*"); //$NON-NLS-1$
2348 return this.isOnClasspath(path);
2351 private IPath getPluginWorkingLocation() {
2352 return this.project.getWorkingLocation(JavaCore.PLUGIN_ID);
2355 * load preferences from a shareable format (VCM-wise)
2357 public Preferences loadPreferences() {
2359 Preferences preferences = new Preferences();
2361 // File prefFile = getProject().getLocation().append(PREF_FILENAME).toFile();
2362 IPath projectMetaLocation = getPluginWorkingLocation();
2363 if (projectMetaLocation != null) {
2364 File prefFile = projectMetaLocation.append(PREF_FILENAME).toFile();
2365 if (prefFile.exists()) { // load preferences from file
2366 InputStream in = null;
2368 in = new BufferedInputStream(new FileInputStream(prefFile));
2369 preferences.load(in);
2371 } catch (IOException e) { // problems loading preference store - quietly ignore
2376 } catch (IOException e) { // ignore problems with close
2386 * @see IJavaProject#newEvaluationContext
2388 // public IEvaluationContext newEvaluationContext() {
2390 // return new EvaluationContextWrapper(new EvaluationContext(), this);
2396 // public ITypeHierarchy newTypeHierarchy(
2398 // IProgressMonitor monitor)
2399 // throws JavaModelException {
2401 // if (region == null) {
2402 // throw new IllegalArgumentException(ProjectPrefUtil.bind("hierarchy.nullRegion"));//$NON-NLS-1$
2404 // CreateTypeHierarchyOperation op =
2405 // new CreateTypeHierarchyOperation(null, region, this, true);
2406 // runOperation(op, monitor);
2407 // return op.getResult();
2413 // public ITypeHierarchy newTypeHierarchy(
2416 // IProgressMonitor monitor)
2417 // throws JavaModelException {
2419 // if (type == null) {
2420 // throw new IllegalArgumentException(ProjectPrefUtil.bind("hierarchy.nullFocusType"));//$NON-NLS-1$
2422 // if (region == null) {
2423 // throw new IllegalArgumentException(ProjectPrefUtil.bind("hierarchy.nullRegion"));//$NON-NLS-1$
2425 // CreateTypeHierarchyOperation op =
2426 // new CreateTypeHierarchyOperation(type, region, this, true);
2427 // runOperation(op, monitor);
2428 // return op.getResult();
2432 // * Open project if resource isn't closed
2434 // protected void openWhenClosed(IProgressMonitor pm) throws JavaModelException {
2436 // if (!this.fProject.isOpen()) {
2437 // throw newNotPresentException();
2439 // super.openWhenClosed(pm);
2443 public String[] projectPrerequisites(IClasspathEntry[] entries)
2444 throws JavaModelException {
2446 ArrayList prerequisites = new ArrayList();
2448 entries = getResolvedClasspath(entries, null, true, false, null/*no reverse map*/);
2449 for (int i = 0, length = entries.length; i < length; i++) {
2450 IClasspathEntry entry = entries[i];
2451 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
2452 prerequisites.add(entry.getPath().lastSegment());
2455 int size = prerequisites.size();
2457 return NO_PREREQUISITES;
2459 String[] result = new String[size];
2460 prerequisites.toArray(result);
2467 * Reads the .classpath file from disk and returns the list of entries it contains (including output location entry)
2468 * Returns null if .classfile is not present.
2469 * Returns INVALID_CLASSPATH if it has a format problem.
2471 protected IClasspathEntry[] readClasspathFile(boolean createMarker, boolean logProblems) {
2474 String xmlClasspath = getSharedProperty(CLASSPATH_FILENAME);
2475 if (xmlClasspath == null) return null;
2476 return decodeClasspath(xmlClasspath, createMarker, logProblems);
2477 } catch(CoreException e) {
2478 // file does not exist (or not accessible)
2479 if (createMarker && this.getProject().isAccessible()) {
2480 this.createClasspathProblemMarker(new JavaModelStatus(
2481 IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
2482 Util.bind("classpath.cannotReadClasspathFile", this.getElementName()))); //$NON-NLS-1$
2486 "Exception while retrieving "+ this.getPath() //$NON-NLS-1$
2487 +"/.classpath, will revert to default classpath"); //$NON-NLS-1$
2494 * Removes the given builder from the build spec for the given project.
2496 protected void removeFromBuildSpec(String builderID) throws CoreException {
2498 IProjectDescription description = getProject().getDescription();
2499 ICommand[] commands = description.getBuildSpec();
2500 for (int i = 0; i < commands.length; ++i) {
2501 if (commands[i].getBuilderName().equals(builderID)) {
2502 ICommand[] newCommands = new ICommand[commands.length - 1];
2503 System.arraycopy(commands, 0, newCommands, 0, i);
2504 System.arraycopy(commands, i + 1, newCommands, i, commands.length - i - 1);
2505 description.setBuildSpec(newCommands);
2506 getProject().setDescription(description, null);
2514 * @see JavaElement#rootedAt(IJavaProject)
2516 public IJavaElement rootedAt(IJavaProject project) {
2522 * Answers an ID which is used to distinguish project/entries during package
2523 * fragment root computations
2525 public String rootID(){
2526 return "[PRJ]"+this.getProject().getFullPath(); //$NON-NLS-1$
2530 * Saves the classpath in a shareable format (VCM-wise) only when necessary, that is, if it is semantically different
2531 * from the existing one in file. Will never write an identical one.
2533 * @return Return whether the .classpath file was modified.
2535 public boolean saveClasspath(IClasspathEntry[] newClasspath, IPath newOutputLocation) throws JavaModelException {
2537 if (!getProject().exists()) return false;
2539 IClasspathEntry[] fileEntries = readClasspathFile(false /*don't create markers*/, false/*don't log problems*/);
2540 if (fileEntries != null && isClasspathEqualsTo(newClasspath, newOutputLocation, fileEntries)) {
2541 // no need to save it, it is the same
2545 // actual file saving
2547 setSharedProperty(CLASSPATH_FILENAME, encodeClasspath(newClasspath, newOutputLocation, true));
2549 } catch (CoreException e) {
2550 throw new JavaModelException(e);
2556 * Save project custom preferences to shareable file (.jprefs)
2558 private void savePreferences(Preferences preferences) {
2560 if (!JavaProject.hasJavaNature(this.project)) return; // ignore
2562 if (preferences == null || (!preferences.needsSaving() && preferences.propertyNames().length != 0)) {
2567 // preferences need to be saved
2568 // the preferences file is located in the plug-in's state area
2569 // at a well-known name (.jprefs)
2570 // File prefFile = this.project.getLocation().append(PREF_FILENAME).toFile();
2571 File prefFile = getPluginWorkingLocation().append(PREF_FILENAME).toFile();
2572 if (preferences.propertyNames().length == 0) {
2573 // there are no preference settings
2574 // rather than write an empty file, just delete any existing file
2575 if (prefFile.exists()) {
2576 prefFile.delete(); // don't worry if delete unsuccessful
2581 // write file, overwriting an existing one
2582 OutputStream out = null;
2584 // do it as carefully as we know how so that we don't lose/mangle
2585 // the setting in times of stress
2586 out = new BufferedOutputStream(new FileOutputStream(prefFile));
2587 preferences.store(out, null);
2588 } catch (IOException e) { // problems saving preference store - quietly ignore
2593 } catch (IOException e) { // ignore problems with close
2599 * Update the Java command in the build spec (replace existing one if present,
2600 * add one first if none).
2602 private void setJavaCommand(
2603 IProjectDescription description,
2604 ICommand newCommand)
2605 throws CoreException {
2607 ICommand[] oldCommands = description.getBuildSpec();
2608 ICommand oldJavaCommand = getJavaCommand(description);
2609 ICommand[] newCommands;
2611 if (oldJavaCommand == null) {
2612 // Add a Java build spec before other builders (1FWJK7I)
2613 newCommands = new ICommand[oldCommands.length + 1];
2614 System.arraycopy(oldCommands, 0, newCommands, 1, oldCommands.length);
2615 newCommands[0] = newCommand;
2617 for (int i = 0, max = oldCommands.length; i < max; i++) {
2618 if (oldCommands[i] == oldJavaCommand) {
2619 oldCommands[i] = newCommand;
2623 newCommands = oldCommands;
2626 // Commit the spec change into the project
2627 description.setBuildSpec(newCommands);
2628 getProject().setDescription(description, null);
2632 * @see net.sourceforge.phpdt.core.IJavaProject#setOptions(Map)
2634 public void setOptions(Map newOptions) {
2636 Preferences preferences;
2637 setPreferences(preferences = new Preferences()); // always reset (26255)
2638 if (newOptions != null){
2639 Iterator keys = newOptions.keySet().iterator();
2640 while (keys.hasNext()){
2641 String key = (String)keys.next();
2642 if (!JavaModelManager.OptionNames.contains(key)) continue; // unrecognized option
2643 // no filtering for encoding (custom encoding for project is allowed)
2644 String value = (String)newOptions.get(key);
2645 preferences.setDefault(key, CUSTOM_DEFAULT_OPTION_VALUE); // empty string isn't the default (26251)
2646 preferences.setValue(key, value);
2651 savePreferences(preferences);
2657 public void setOutputLocation(IPath path, IProgressMonitor monitor)
2658 throws JavaModelException {
2661 throw new IllegalArgumentException(Util.bind("path.nullpath")); //$NON-NLS-1$
2663 if (path.equals(getOutputLocation())) {
2666 this.setRawClasspath(SetClasspathOperation.ReuseClasspath, path, monitor);
2670 * Set cached preferences, no preference file is saved, only info is updated
2672 public void setPreferences(Preferences preferences) {
2673 IProject project = getProject();
2674 if (!JavaProject.hasJavaNature(project)) return; // ignore
2675 JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfo(project, true);
2676 perProjectInfo.preferences = preferences;
2682 public void setRawClasspath(
2683 IClasspathEntry[] entries,
2684 IPath outputLocation,
2685 IProgressMonitor monitor)
2686 throws JavaModelException {
2692 true, // canChangeResource (as per API contract)
2693 getResolvedClasspath(true), // ignoreUnresolvedVariable
2694 true, // needValidation
2695 true); // need to save
2698 public void setRawClasspath(
2699 IClasspathEntry[] newEntries,
2700 IPath newOutputLocation,
2701 IProgressMonitor monitor,
2702 boolean canChangeResource,
2703 IClasspathEntry[] oldResolvedPath,
2704 boolean needValidation,
2706 throws JavaModelException {
2708 JavaModelManager manager =
2709 (JavaModelManager) JavaModelManager.getJavaModelManager();
2711 IClasspathEntry[] newRawPath = newEntries;
2712 if (newRawPath == null) { //are we already with the default classpath
2713 newRawPath = defaultClasspath();
2715 SetClasspathOperation op =
2716 new SetClasspathOperation(
2724 runOperation(op, monitor);
2726 } catch (JavaModelException e) {
2735 public void setRawClasspath(
2736 IClasspathEntry[] entries,
2737 IProgressMonitor monitor)
2738 throws JavaModelException {
2742 SetClasspathOperation.ReuseOutputLocation,
2744 true, // canChangeResource (as per API contract)
2745 getResolvedClasspath(true), // ignoreUnresolvedVariable
2746 true, // needValidation
2747 true); // need to save
2751 * NOTE: <code>null</code> specifies default classpath, and an empty
2752 * array specifies an empty classpath.
2754 * @exception NotPresentException if this project does not exist.
2756 // protected void setRawClasspath0(IClasspathEntry[] rawEntries)
2757 // throws JavaModelException {
2759 // JavaModelManager.PerProjectInfo info = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project);
2761 // synchronized (info) {
2762 // if (rawEntries != null) {
2763 // info.classpath = rawEntries;
2766 // // clear cache of resolved classpath
2767 // info.lastResolvedClasspath = null;
2768 // info.resolvedPathToRawEntries = null;
2773 * Record a shared persistent property onto a project.
2774 * Note that it is orthogonal to IResource persistent properties, and client code has to decide
2775 * which form of storage to use appropriately. Shared properties produce real resource files which
2776 * can be shared through a VCM onto a server. Persistent properties are not shareable.
2778 * shared properties end up in resource files, and thus cannot be modified during
2779 * delta notifications (a CoreException would then be thrown).
2781 * @see JavaProject#getSharedProperty(String key)
2783 public void setSharedProperty(String key, String value) throws CoreException {
2785 IFile rscFile = getProject().getFile(key);
2786 InputStream inputStream = new ByteArrayInputStream(value.getBytes());
2787 // update the resource content
2788 if (rscFile.exists()) {
2789 if (rscFile.isReadOnly()) {
2790 // provide opportunity to checkout read-only .classpath file (23984)
2791 ResourcesPlugin.getWorkspace().validateEdit(new IFile[]{rscFile}, null);
2793 rscFile.setContents(inputStream, IResource.FORCE, null);
2795 rscFile.create(inputStream, IResource.FORCE, null);
2800 * Update cycle markers for all java projects
2802 public static void updateAllCycleMarkers() throws JavaModelException {
2804 //long start = System.currentTimeMillis();
2806 JavaModelManager manager = JavaModelManager.getJavaModelManager();
2807 IJavaProject[] projects = manager.getJavaModel().getJavaProjects();
2808 IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
2810 HashSet cycleParticipants = new HashSet();
2811 HashSet traversed = new HashSet();
2812 int length = projects.length;
2814 // compute cycle participants
2815 ArrayList prereqChain = new ArrayList();
2816 for (int i = 0; i < length; i++){
2817 JavaProject project = (JavaProject)projects[i];
2818 if (!traversed.contains(project.getPath())){
2819 prereqChain.clear();
2820 project.updateCycleParticipants(null, prereqChain, cycleParticipants, workspaceRoot, traversed);
2823 //System.out.println("updateAllCycleMarkers: " + (System.currentTimeMillis() - start) + " ms");
2825 for (int i = 0; i < length; i++){
2826 JavaProject project = (JavaProject)projects[i];
2828 if (cycleParticipants.contains(project.getPath())){
2829 IMarker cycleMarker = project.getCycleMarker();
2830 String circularCPOption = project.getOption(JavaCore.CORE_CIRCULAR_CLASSPATH, true);
2831 int circularCPSeverity = JavaCore.ERROR.equals(circularCPOption) ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING;
2832 if (cycleMarker != null) {
2833 // update existing cycle marker if needed
2835 int existingSeverity = ((Integer)cycleMarker.getAttribute(IMarker.SEVERITY)).intValue();
2836 if (existingSeverity != circularCPSeverity) {
2837 cycleMarker.setAttribute(IMarker.SEVERITY, circularCPSeverity);
2839 } catch (CoreException e) {
2840 throw new JavaModelException(e);
2843 // create new marker
2844 project.createClasspathProblemMarker(
2845 new JavaModelStatus(IJavaModelStatusConstants.CLASSPATH_CYCLE, project));
2848 project.flushClasspathProblemMarkers(true, false);
2854 * If a cycle is detected, then cycleParticipants contains all the paths of projects involved in this cycle (directly and indirectly),
2855 * no cycle if the set is empty (and started empty)
2857 public void updateCycleParticipants(
2858 IClasspathEntry[] preferredClasspath,
2859 ArrayList prereqChain,
2860 HashSet cycleParticipants,
2861 IWorkspaceRoot workspaceRoot,
2864 IPath path = this.getPath();
2865 prereqChain.add(path);
2866 traversed.add(path);
2868 IClasspathEntry[] classpath = preferredClasspath == null ? getResolvedClasspath(true) : preferredClasspath;
2869 for (int i = 0, length = classpath.length; i < length; i++) {
2870 IClasspathEntry entry = classpath[i];
2872 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT){
2873 IPath prereqProjectPath = entry.getPath();
2874 int index = cycleParticipants.contains(prereqProjectPath) ? 0 : prereqChain.indexOf(prereqProjectPath);
2875 if (index >= 0) { // refer to cycle, or in cycle itself
2876 for (int size = prereqChain.size(); index < size; index++) {
2877 cycleParticipants.add(prereqChain.get(index));
2880 if (!traversed.contains(prereqProjectPath)) {
2881 IResource member = workspaceRoot.findMember(prereqProjectPath);
2882 if (member != null && member.getType() == IResource.PROJECT){
2883 JavaProject project = (JavaProject)JavaCore.create((IProject)member);
2884 project.updateCycleParticipants(null, prereqChain, cycleParticipants, workspaceRoot, traversed);
2890 } catch(JavaModelException e){
2892 prereqChain.remove(path);
2895 * Reset the collection of package fragment roots (local ones) - only if opened.
2896 * Need to check *all* package fragment roots in order to reset NameLookup
2898 public void updatePackageFragmentRoots(){
2900 if (this.isOpen()) {
2902 JavaProjectElementInfo info = getJavaProjectElementInfo();
2904 IClasspathEntry[] classpath = getResolvedClasspath(true);
2905 // NameLookup lookup = info.getNameLookup();
2906 // if (lookup != null){
2907 // IPackageFragmentRoot[] oldRoots = lookup.fPackageFragmentRoots;
2908 // IPackageFragmentRoot[] newRoots = computePackageFragmentRoots(classpath, true);
2909 // checkIdentical: { // compare all pkg fragment root lists
2910 // if (oldRoots.length == newRoots.length){
2911 // for (int i = 0, length = oldRoots.length; i < length; i++){
2912 // if (!oldRoots[i].equals(newRoots[i])){
2913 // break checkIdentical;
2916 // return; // no need to update
2919 // info.setNameLookup(null); // discard name lookup (hold onto roots)
2921 info.setNonJavaResources(null);
2923 computePackageFragmentRoots(classpath, false));
2925 } catch(JavaModelException e){
2927 close(); // could not do better
2928 } catch(JavaModelException ex){
2934 public void removeLoadPathEntry(IProject anotherPHPProject) {
2935 Iterator entries = getLoadPathEntries().iterator();
2936 while (entries.hasNext()) {
2937 LoadPathEntry entry = (LoadPathEntry) entries.next();
2938 if (entry.getType() == LoadPathEntry.TYPE_PROJECT && entry.getProject().getName().equals(anotherPHPProject.getName())) {
2939 getLoadPathEntries().remove(entry);
2946 public void save() throws CoreException {
2948 InputStream xmlPath = new ByteArrayInputStream(getLoadPathXML().getBytes());
2949 IFile loadPathsFile = getLoadPathEntriesFile();
2950 if (!loadPathsFile.exists())
2951 loadPathsFile.create(xmlPath, true, null);
2953 loadPathsFile.setContents(xmlPath, true, false, null);