blob: 6295a15a31dafcb13af26c0185026761dbf59d11 [file] [log] [blame]
package org.eclipse.jdt.internal.core;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.resources.*;
import org.eclipse.jdt.internal.codeassist.ISearchableNameEnvironment;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.eval.IEvaluationContext;
import org.eclipse.jdt.internal.compiler.util.ObjectVector;
import org.eclipse.jdt.internal.core.builder.JavaBuilder;
import org.eclipse.jdt.internal.core.eval.EvaluationContextWrapper;
import org.eclipse.jdt.internal.core.search.indexing.*;
import org.eclipse.jdt.internal.core.util.*;
import org.eclipse.jdt.internal.eval.EvaluationContext;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.StringTokenizer;
import javax.xml.parsers.*;
import org.apache.xerces.dom.*;
import org.apache.xml.serialize.*;
import org.w3c.dom.*;
import org.xml.sax.*;
/**
* Handle for a Java Project.
*
* <p>A Java Project internally maintains a devpath that corresponds
* to the project's classpath. The classpath may include source folders
* from the current project; jars in the current project, other projects,
* and the local file system; and binary folders (output location) of other
* projects. The Java Model presents source elements corresponding to output
* .class files in other projects, and thus uses the devpath rather than
* the classpath (which is really a compilation path). The devpath mimics
* the classpath, except has source folder entries in place of output
* locations in external projects.
*
* <p>Each JavaProject has a NameLookup facility that locates elements
* on by name, based on the devpath.
*
* @see IJavaProject
*/
public class JavaProject
extends Openable
implements IJavaProject, IProjectNature {
/**
* Whether the underlying file system is case sensitive.
*/
protected static final boolean IS_CASE_SENSITIVE = !new File("Temp").equals(new File("temp")); //$NON-NLS-1$ //$NON-NLS-2$
/**
* An empty array of strings indicating that a project doesn't have any prerequesite projects.
*/
protected static final String[] NO_PREREQUISITES = new String[0];
/**
* The platform project this <code>IJavaProject</code> is based on
*/
protected IProject fProject;
/**
* Returns a canonicalized path from the given external path.
* Note that the return path contains the same number of segments
* and it contains a device only if the given path contained one.
* @see java.io.File for the definition of a canonicalized path
*/
public static IPath canonicalizedPath(IPath externalPath) {
if (externalPath == null)
return null;
// if (JavaModelManager.VERBOSE) {
// System.out.println("JAVA MODEL - Canonicalizing " + externalPath.toString()); //$NON-NLS-1$
// }
if (IS_CASE_SENSITIVE) {
// if (JavaModelManager.VERBOSE) {
// System.out.println("JAVA MODEL - Canonical path is original path (file system is case sensitive)"); //$NON-NLS-1$
// }
return externalPath;
}
// if not external path, return original path
if (ResourcesPlugin.getWorkspace().getRoot().findMember(externalPath) != null) {
// if (JavaModelManager.VERBOSE) {
// System.out.println("JAVA MODEL - Canonical path is original path (member of workspace)"); //$NON-NLS-1$
// }
return externalPath;
}
IPath canonicalPath = null;
try {
canonicalPath =
new Path(new File(externalPath.toOSString()).getCanonicalPath());
} catch (IOException e) {
// default to original path
// if (JavaModelManager.VERBOSE) {
// System.out.println("JAVA MODEL - Canonical path is original path (IOException)"); //$NON-NLS-1$
// }
return externalPath;
}
IPath result;
int canonicalLength = canonicalPath.segmentCount();
if (canonicalLength == 0) {
// the java.io.File canonicalization failed
// if (JavaModelManager.VERBOSE) {
// System.out.println("JAVA MODEL - Canonical path is original path (canonical path is empty)"); //$NON-NLS-1$
// }
return externalPath;
} else if (externalPath.isAbsolute()) {
result = canonicalPath;
} else {
// if path is relative, remove the first segments that were added by the java.io.File canonicalization
// e.g. 'lib/classes.zip' was converted to 'd:/myfolder/lib/classes.zip'
int externalLength = externalPath.segmentCount();
if (canonicalLength >= externalLength) {
result = canonicalPath.removeFirstSegments(canonicalLength - externalLength);
} else {
// if (JavaModelManager.VERBOSE) {
// System.out.println("JAVA MODEL - Canonical path is original path (canonical path is " + canonicalPath.toString() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
// }
return externalPath;
}
}
// keep device only if it was specified (this is because File.getCanonicalPath() converts '/lib/classed.zip' to 'd:/lib/classes/zip')
if (externalPath.getDevice() == null) {
result = result.setDevice(null);
}
// if (JavaModelManager.VERBOSE) {
// System.out.println("JAVA MODEL - Canonical path is " + result.toString()); //$NON-NLS-1$
// }
return result;
}
/**
* Returns the XML String encoding of the class path.
*/
protected static Element getEntryAsXMLElement(
Document document,
IClasspathEntry entry,
IPath prefixPath)
throws JavaModelException {
Element element = document.createElement("classpathentry"); //$NON-NLS-1$
element.setAttribute("kind", kindToString(entry.getEntryKind())); //$NON-NLS-1$
IPath path = entry.getPath();
if (entry.getEntryKind() != IClasspathEntry.CPE_VARIABLE && entry.getEntryKind() != IClasspathEntry.CPE_CONTAINER) {
// translate to project relative from absolute (unless a device path)
if (path.isAbsolute()) {
if (prefixPath != null && prefixPath.isPrefixOf(path)) {
if (path.segment(0).equals(prefixPath.segment(0))) {
path = path.removeFirstSegments(1);
path = path.makeRelative();
} else {
path = path.makeAbsolute();
}
}
}
}
element.setAttribute("path", path.toString()); //$NON-NLS-1$
if (entry.getSourceAttachmentPath() != null) {
element.setAttribute("sourcepath", entry.getSourceAttachmentPath().toString()); //$NON-NLS-1$
}
if (entry.getSourceAttachmentRootPath() != null) {
element.setAttribute(
"rootpath", //$NON-NLS-1$
entry.getSourceAttachmentRootPath().toString());
}
if (entry.isExported()) {
element.setAttribute("exported", "true"); //$NON-NLS-1$ //$NON-NLS-2$
}
return element;
}
/**
* Returns the kind of a <code>PackageFragmentRoot</code> from its <code>String</code> form.
*/
static int kindFromString(String kindStr) {
if (kindStr.equalsIgnoreCase("prj")) //$NON-NLS-1$
return IClasspathEntry.CPE_PROJECT;
if (kindStr.equalsIgnoreCase("var")) //$NON-NLS-1$
return IClasspathEntry.CPE_VARIABLE;
if (kindStr.equalsIgnoreCase("con")) //$NON-NLS-1$
return IClasspathEntry.CPE_CONTAINER;
if (kindStr.equalsIgnoreCase("src")) //$NON-NLS-1$
return IClasspathEntry.CPE_SOURCE;
if (kindStr.equalsIgnoreCase("lib")) //$NON-NLS-1$
return IClasspathEntry.CPE_LIBRARY;
if (kindStr.equalsIgnoreCase("output")) //$NON-NLS-1$
return ClasspathEntry.K_OUTPUT;
return -1;
}
/**
* Returns a <code>String</code> for the kind of a class path entry.
*/
static String kindToString(int kind) {
switch (kind) {
case IClasspathEntry.CPE_PROJECT :
return "src"; // backward compatibility //$NON-NLS-1$
case IClasspathEntry.CPE_SOURCE :
return "src"; //$NON-NLS-1$
case IClasspathEntry.CPE_LIBRARY :
return "lib"; //$NON-NLS-1$
case IClasspathEntry.CPE_VARIABLE :
return "var"; //$NON-NLS-1$
case IClasspathEntry.CPE_CONTAINER :
return "con"; //$NON-NLS-1$
case ClasspathEntry.K_OUTPUT :
return "output"; //$NON-NLS-1$
default :
return "unknown"; //$NON-NLS-1$
}
}
/**
* Constructor needed for <code>IProject.getNature()</code> and <code>IProject.addNature()</code>.
*
* @see #setProject
*/
public JavaProject() {
super(JAVA_PROJECT, null, null);
}
public JavaProject(IProject project, IJavaElement parent) {
super(JAVA_PROJECT, parent, project.getName());
fProject = project;
}
/**
* Adds a builder to the build spec for the given project.
*/
protected void addToBuildSpec(String builderID) throws CoreException {
IProjectDescription description = getProject().getDescription();
ICommand javaCommand = getJavaCommand(description);
if (javaCommand == null) {
// Add a Java command to the build spec
ICommand command = description.newCommand();
command.setBuilderName(builderID);
setJavaCommand(description, command);
}
}
protected void closing(Object info) throws JavaModelException {
// forget source attachment recommendations
IPackageFragmentRoot[] roots = this.getPackageFragmentRoots();
for (int i = 0; i < roots.length; i++) {
if (roots[i] instanceof JarPackageFragmentRoot){
((JarPackageFragmentRoot) roots[i]).setSourceAttachmentProperty(null);
}
}
super.closing(info);
}
/**
* Internal computation of an expanded classpath. It will eliminate duplicates, and produce copies
* of exported classpath entries to avoid possible side-effects ever after.
*/
private void computeExpandedClasspath(
JavaProject initialProject,
boolean ignoreUnresolvedVariable,
boolean generateMarkerOnError,
HashSet visitedProjects,
ObjectVector accumulatedEntries) throws JavaModelException {
if (visitedProjects.contains(this)){
return; // break cycles if any
}
visitedProjects.add(this);
if (generateMarkerOnError && !this.equals(initialProject)){
generateMarkerOnError = false;
}
IClasspathEntry[] immediateClasspath =
getResolvedClasspath(ignoreUnresolvedVariable, generateMarkerOnError);
IWorkspaceRoot workspaceRoot = this.getWorkspace().getRoot();
for (int i = 0, length = immediateClasspath.length; i < length; i++){
IClasspathEntry entry = immediateClasspath[i];
boolean isInitialProject = this.equals(initialProject);
if (isInitialProject || entry.isExported()){
accumulatedEntries.add(entry);
// recurse in project to get all its indirect exports (only consider exported entries from there on)
if (entry.getEntryKind() == ClasspathEntry.CPE_PROJECT) {
IProject projRsc = (IProject) workspaceRoot.findMember(entry.getPath());
if (projRsc != null && projRsc.isOpen()) {
JavaProject project = (JavaProject) JavaCore.create(projRsc);
project.computeExpandedClasspath(
initialProject,
ignoreUnresolvedVariable,
generateMarkerOnError,
visitedProjects,
accumulatedEntries);
}
}
}
}
}
/**
* Returns (local/all) the package fragment roots identified by the given project's classpath.
* Note: this follows project classpath references to find required project contributions,
* eliminating duplicates silently.
*/
public IPackageFragmentRoot[] computePackageFragmentRoots(IClasspathEntry[] classpath, boolean retrieveExportedRoots) throws JavaModelException {
ObjectVector accumulatedRoots = new ObjectVector();
computePackageFragmentRoots(classpath, accumulatedRoots, new HashSet(5), true, true, retrieveExportedRoots);
IPackageFragmentRoot[] rootArray = new IPackageFragmentRoot[accumulatedRoots.size()];
accumulatedRoots.copyInto(rootArray);
return rootArray;
}
/**
* Returns the package fragment roots identified by the given entry. In case it refers to
* a project, it will follow its classpath so as to find exported roots as well.
*/
public void computePackageFragmentRoots(
IClasspathEntry entry,
ObjectVector accumulatedRoots,
HashSet rootIDs,
boolean insideOriginalProject,
boolean checkExistency,
boolean retrieveExportedRoots) throws JavaModelException {
String rootID = ((ClasspathEntry)entry).rootID();
if (rootIDs.contains(rootID)) return;
IPath projectPath = getProject().getFullPath();
IPath entryPath = entry.getPath();
IWorkspaceRoot workspaceRoot = getWorkspace().getRoot();
switch(entry.getEntryKind()){
// source folder
case IClasspathEntry.CPE_SOURCE :
if (projectPath.isPrefixOf(entryPath)){
Object target = JavaModel.getTarget(workspaceRoot, entryPath, checkExistency);
if (target == null) return;
if (target instanceof IFolder || target instanceof IProject){
accumulatedRoots.add(
new PackageFragmentRoot((IResource)target, this));
rootIDs.add(rootID);
}
}
break;
// internal/external JAR or folder
case IClasspathEntry.CPE_LIBRARY :
if (!insideOriginalProject && !entry.isExported()) return;
String extension = entryPath.getFileExtension();
Object target = JavaModel.getTarget(workspaceRoot, entryPath, checkExistency);
if (target == null) return;
if (target instanceof IResource){
// internal target
IResource resource = (IResource) target;
switch (resource.getType()){
case IResource.FOLDER :
accumulatedRoots.add(
new PackageFragmentRoot(resource, this));
rootIDs.add(rootID);
break;
case IResource.FILE :
if ("jar".equalsIgnoreCase(extension) //$NON-NLS-1$
|| "zip".equalsIgnoreCase(extension)) { //$NON-NLS-1$
accumulatedRoots.add(
new JarPackageFragmentRoot(resource, this));
}
rootIDs.add(rootID);
break;
}
} else {
// external target - only JARs allowed
if (((java.io.File)target).isFile()
&& ("jar".equalsIgnoreCase(extension) //$NON-NLS-1$
|| "zip".equalsIgnoreCase(extension))) { //$NON-NLS-1$
accumulatedRoots.add(
new JarPackageFragmentRoot(entryPath.toOSString(), this));
rootIDs.add(rootID);
}
}
break;
// recurse into required project
case IClasspathEntry.CPE_PROJECT :
if (!retrieveExportedRoots) return;
if (!insideOriginalProject && !entry.isExported()) return;
JavaProject requiredProject = (JavaProject)getJavaModel().getJavaProject(entryPath.segment(0));
IProject requiredProjectRsc = requiredProject.getProject();
if (requiredProjectRsc.exists() && requiredProjectRsc.isOpen()){ // special builder binary output
rootIDs.add(rootID);
requiredProject.computePackageFragmentRoots(
requiredProject.getResolvedClasspath(true),
accumulatedRoots,
rootIDs,
false,
checkExistency,
retrieveExportedRoots);
}
break;
}
}
/**
* Returns (local/all) the package fragment roots identified by the given project's classpath.
* Note: this follows project classpath references to find required project contributions,
* eliminating duplicates silently.
*/
public void computePackageFragmentRoots(
IClasspathEntry[] classpath,
ObjectVector accumulatedRoots,
HashSet rootIDs,
boolean insideOriginalProject,
boolean checkExistency,
boolean retrieveExportedRoots) throws JavaModelException {
if (insideOriginalProject){
rootIDs.add(rootID());
}
for (int i = 0, length = classpath.length; i < length; i++){
computePackageFragmentRoots(
classpath[i],
accumulatedRoots,
rootIDs,
insideOriginalProject,
checkExistency,
retrieveExportedRoots);
}
}
/**
* Compute the file name to use for a given shared property
*/
public String computeSharedPropertyFileName(QualifiedName qName) {
return '.' + qName.getLocalName();
}
/**
* Configure the project with Java nature.
*/
public void configure() throws CoreException {
// register Java builder
addToBuildSpec(JavaCore.BUILDER_ID);
}
/**
* Record a new marker denoting a classpath problem
*/
void createClasspathProblemMarker(
String message,
int severity,
boolean isCycleProblem) {
try {
IMarker marker = getProject().createMarker(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER);
marker.setAttributes(
new String[] {
IMarker.MESSAGE,
IMarker.SEVERITY,
IMarker.LOCATION,
IJavaModelMarker.CYCLE_DETECTED },
new Object[] {
message,
new Integer(severity),
Util.bind("classpath.buildPath"),//$NON-NLS-1$
isCycleProblem ? "true" : "false"});//$NON-NLS-1$ //$NON-NLS-2$
} catch (CoreException e) {
}
}
/**
* Returns a new element info for this element.
*/
protected OpenableElementInfo createElementInfo() {
return new JavaProjectElementInfo();
}
/**
/**
* Removes the Java nature from the project.
*/
public void deconfigure() throws CoreException {
// deregister Java builder
removeFromBuildSpec(JavaCore.BUILDER_ID);
}
/**
* Returns a default class path.
* This is the root of the project
*/
protected IClasspathEntry[] defaultClasspath() throws JavaModelException {
return new IClasspathEntry[] {
JavaCore.newSourceEntry(getProject().getFullPath())};
}
/**
* Returns a default output location.
* This is the project bin folder
*/
protected IPath defaultOutputLocation() throws JavaModelException {
return getProject().getFullPath().append("bin"); //$NON-NLS-1$
}
/**
* Returns true if this handle represents the same Java project
* as the given handle. Two handles represent the same
* project if they are identical or if they represent a project with
* the same underlying resource and occurrence counts.
*
* @see JavaElement#equals
*/
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof JavaProject))
return false;
JavaProject other = (JavaProject) o;
return getProject().equals(other.getProject())
&& fOccurrenceCount == other.fOccurrenceCount;
}
/**
* @see IJavaProject
*/
public IJavaElement findElement(IPath path) throws JavaModelException {
if (path == null || path.isAbsolute()) {
throw new JavaModelException(
new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, path));
}
try {
String extension = path.getFileExtension();
if (extension == null) {
String packageName = path.toString().replace(IPath.SEPARATOR, '.');
IPackageFragment[] pkgFragments =
getNameLookup().findPackageFragments(packageName, false);
if (pkgFragments == null) {
return null;
} else {
// try to return one that is a child of this project
for (int i = 0, length = pkgFragments.length; i < length; i++) {
IPackageFragment pkgFragment = pkgFragments[i];
if (this.equals(pkgFragment.getParent().getParent())) {
return pkgFragment;
}
}
// default to the first one
return pkgFragments[0];
}
} else if (
extension.equalsIgnoreCase("java") //$NON-NLS-1$
|| extension.equalsIgnoreCase("class")) { //$NON-NLS-1$
IPath packagePath = path.removeLastSegments(1);
String packageName = packagePath.toString().replace(IPath.SEPARATOR, '.');
String typeName = path.lastSegment();
typeName = typeName.substring(0, typeName.length() - extension.length() - 1);
String qualifiedName = null;
if (packageName.length() > 0) {
qualifiedName = packageName + "." + typeName; //$NON-NLS-1$
} else {
qualifiedName = typeName;
}
IType type =
getNameLookup().findType(
qualifiedName,
false,
NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
if (type != null) {
return type.getParent();
} else {
return null;
}
} else {
// unsupported extension
return null;
}
} catch (JavaModelException e) {
if (e.getStatus().getCode()
== IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST) {
return null;
} else {
throw e;
}
}
}
/**
* @see IJavaProject
*/
public IPackageFragment findPackageFragment(IPath path)
throws JavaModelException {
return findPackageFragment0(this.canonicalizedPath(path));
}
/**
* non path canonicalizing version
*/
public IPackageFragment findPackageFragment0(IPath path)
throws JavaModelException {
return getNameLookup().findPackageFragment(path);
}
/**
* @see IJavaProject
*/
public IPackageFragmentRoot findPackageFragmentRoot(IPath path)
throws JavaModelException {
return findPackageFragmentRoot0(this.canonicalizedPath(path));
}
/**
* no path canonicalization
*/
public IPackageFragmentRoot findPackageFragmentRoot0(IPath path)
throws JavaModelException {
IPackageFragmentRoot[] allRoots = this.getAllPackageFragmentRoots();
if (!path.isAbsolute()) {
throw new IllegalArgumentException(Util.bind("path.mustBeAbsolute")); //$NON-NLS-1$
}
for (int i= 0; i < allRoots.length; i++) {
IPackageFragmentRoot classpathRoot= allRoots[i];
if (classpathRoot.getPath().equals(path)) {
return classpathRoot;
}
}
return null;
}
/**
* @see IJavaProject#findType(String)
*/
public IType findType(String fullyQualifiedName) throws JavaModelException {
IType type =
this.getNameLookup().findType(
fullyQualifiedName,
false,
NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
if (type == null) {
// try to find enclosing type
int lastDot = fullyQualifiedName.lastIndexOf('.');
if (lastDot == -1) return null;
type = this.findType(fullyQualifiedName.substring(0, lastDot));
if (type != null) {
type = type.getType(fullyQualifiedName.substring(lastDot+1));
if (!type.exists()) {
return null;
}
}
}
return type;
}
/**
* @see IJavaProject#findType(String, String)
*/
public IType findType(String packageName, String typeQualifiedName) throws JavaModelException {
return
this.getNameLookup().findType(
typeQualifiedName,
packageName,
false,
NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
}
/**
* Remove all markers denoting classpath problems
*/
protected void flushClasspathProblemMarkers(boolean flushCycleMarkers) {
try {
IProject project = getProject();
if (project.exists()) {
IMarker[] markers = project.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ONE);
for (int i = 0, length = markers.length; i < length; i++) {
IMarker marker = markers[i];
String cycleAttr = (String)marker.getAttribute(IJavaModelMarker.CYCLE_DETECTED);
if (flushCycleMarkers == (cycleAttr != null && cycleAttr.equals("true"))){ //$NON-NLS-1$
marker.delete();
}
}
}
} catch (CoreException e) {
}
}
/**
* @see Openable
*/
protected boolean generateInfos(
OpenableElementInfo info,
IProgressMonitor pm,
Map newElements,
IResource underlyingResource) throws JavaModelException {
boolean validInfo = false;
try {
if (((IProject) getUnderlyingResource()).isOpen()) {
// put the info now, because setting the classpath requires it
fgJavaModelManager.putInfo(this, info);
// read classpath property (contains actual classpath and output location settings)
IPath outputLocation = null;
IClasspathEntry[] classpath = null;
// read from file
String sharedClasspath = loadClasspath();
if (sharedClasspath != null) {
try {
classpath = readPaths(sharedClasspath);
} catch (IOException e) {
} catch (RuntimeException e) {
}
// extract out the output location
if (classpath != null && classpath.length > 0) {
IClasspathEntry entry = classpath[classpath.length - 1];
if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
outputLocation = entry.getPath();
IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1];
System.arraycopy(classpath, 0, copy, 0, copy.length);
classpath = copy;
}
}
}
// restore output location
if (outputLocation == null) {
outputLocation = defaultOutputLocation();
}
((JavaProjectElementInfo)info).setOutputLocation(outputLocation);
// restore classpath
if (classpath == null) {
classpath = defaultClasspath();
}
setRawClasspath0(classpath);
// only valid if reaches here
validInfo = true;
}
} catch (JavaModelException e) {
} finally {
if (!validInfo)
fgJavaModelManager.removeInfo(this);
}
return validInfo;
}
/**
* @see IJavaProject
*/
public IPackageFragmentRoot[] getAllPackageFragmentRoots()
throws JavaModelException {
return computePackageFragmentRoots(getResolvedClasspath(true), true);
}
/**
* @see IJavaProject#getClasspath()
* @deprecated - use JavaCore API instead
*/
public IClasspathEntry[] getClasspath() throws JavaModelException {
return this.getRawClasspath();
}
/**
* Returns the XML String encoding of the class path.
*/
protected String getClasspathAsXMLString(
IClasspathEntry[] classpath,
IPath outputLocation)
throws JavaModelException {
Document doc = new DocumentImpl();
Element cpElement = doc.createElement("classpath"); //$NON-NLS-1$
doc.appendChild(cpElement);
for (int i = 0; i < classpath.length; ++i) {
Element cpeElement =
getEntryAsXMLElement(doc, classpath[i], getProject().getFullPath());
cpElement.appendChild(cpeElement);
}
if (outputLocation != null) {
outputLocation = outputLocation.removeFirstSegments(1);
outputLocation = outputLocation.makeRelative();
Element oElement = doc.createElement("classpathentry"); //$NON-NLS-1$
oElement.setAttribute("kind", kindToString(ClasspathEntry.K_OUTPUT)); //$NON-NLS-1$
oElement.setAttribute("path", outputLocation.toOSString()); //$NON-NLS-1$
cpElement.appendChild(oElement);
}
// produce a String output
StringWriter writer = new StringWriter();
try {
OutputFormat format = new OutputFormat();
format.setIndenting(true);
Serializer serializer =
SerializerFactory.getSerializerFactory(Method.XML).makeSerializer(
writer,
format);
serializer.asDOMSerializer().serialize(doc);
} catch (IOException e) {
throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
}
return writer.toString();
}
/**
* Returns the classpath entry that refers to the given path
* or <code>null</code> if there is no reference to the path.
*/
public IClasspathEntry getClasspathEntryFor(IPath path)
throws JavaModelException {
IClasspathEntry[] entries = getExpandedClasspath(true);
for (int i = 0; i < entries.length; i++) {
if (entries[i].getPath().equals(path)) {
return entries[i];
}
}
return null;
}
/**
* Returns the qualified name for the classpath server property
* of this project
*/
public QualifiedName getClasspathPropertyName() {
return new QualifiedName(JavaCore.PLUGIN_ID, "classpath"); //$NON-NLS-1$
}
/**
* This is a helper method returning the expanded classpath for the project, as a list of classpath entries,
* where all classpath variable entries have been resolved and substituted with their final target entries.
* All project exports have been appended to project entries.
*/
public IClasspathEntry[] getExpandedClasspath(boolean ignoreUnresolvedVariable) throws JavaModelException {
return getExpandedClasspath(ignoreUnresolvedVariable, false);
}
/**
* Internal variant which can create marker on project for invalid entries,
* it will also perform classpath expansion in presence of project prerequisites
* exporting their entries.
*/
public IClasspathEntry[] getExpandedClasspath(
boolean ignoreUnresolvedVariable,
boolean generateMarkerOnError) throws JavaModelException {
ObjectVector accumulatedEntries = new ObjectVector();
computeExpandedClasspath(this, ignoreUnresolvedVariable, generateMarkerOnError, new HashSet(5), accumulatedEntries);
IClasspathEntry[] expandedPath = new IClasspathEntry[accumulatedEntries.size()];
accumulatedEntries.copyInto(expandedPath);
return expandedPath;
}
/**
* Returns the <code>char</code> that marks the start of this handles
* contribution to a memento.
*/
protected char getHandleMementoDelimiter() {
return JEM_JAVAPROJECT;
}
/**
* Find the specific Java command amongst the build spec of a given description
*/
private ICommand getJavaCommand(IProjectDescription description)
throws CoreException {
ICommand[] commands = description.getBuildSpec();
for (int i = 0; i < commands.length; ++i) {
if (commands[i].getBuilderName().equals(JavaCore.BUILDER_ID)) {
return commands[i];
}
}
return null;
}
/**
* @see IJavaElement
*/
public IJavaProject getJavaProject() {
return this;
}
/**
* Convenience method that returns the specific type of info for a Java project.
*/
protected JavaProjectElementInfo getJavaProjectElementInfo()
throws JavaModelException {
return (JavaProjectElementInfo) getElementInfo();
}
/**
* @see IJavaProject
*/
public NameLookup getNameLookup() throws JavaModelException {
JavaProjectElementInfo info = getJavaProjectElementInfo();
if (info.getNameLookup() == null) {
info.setNameLookup(new NameLookup(this));
}
return info.getNameLookup();
}
/**
* Returns an array of non-java resources contained in the receiver.
*/
public Object[] getNonJavaResources() throws JavaModelException {
return ((JavaProjectElementInfo) getElementInfo()).getNonJavaResources(this);
}
/**
* @see IJavaProject
*/
public IPath getOutputLocation() throws JavaModelException {
IPath outputLocation = null;
if (this.isOpen()) {
JavaProjectElementInfo info = getJavaProjectElementInfo();
outputLocation = info.getOutputLocation();
if (outputLocation != null) {
return outputLocation;
}
return defaultOutputLocation();
}
// if not already opened, then read from file (avoid populating the model for CP question)
String sharedClasspath = loadClasspath();
IClasspathEntry[] classpath = null;
if (sharedClasspath != null) {
try {
classpath = readPaths(sharedClasspath);
} catch (IOException e) {
} catch (RuntimeException e) {
}
// extract out the output location
if (classpath != null && classpath.length > 0) {
IClasspathEntry entry = classpath[classpath.length - 1];
if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
outputLocation = entry.getPath();
}
}
}
if (outputLocation != null) {
return outputLocation;
}
return defaultOutputLocation();
}
/**
* @return A handle to the package fragment root identified by the given path.
* This method is handle-only and the element may or may not exist. Returns
* <code>null</code> if unable to generate a handle from the path (for example,
* an absolute path that has less than 2 segments. The path may be relative or
* absolute.
*/
public IPackageFragmentRoot getPackageFragmentRoot(IPath path) {
Object target = JavaModel.getTarget(getProject().getWorkspace().getRoot(), path, false);
if (target == null) {
if (path.segmentCount() > 0) {
String ext = path.getFileExtension();
if (ext == null) {
return getPackageFragmentRoot(getProject().getFolder(path));
} else {
// resource jar
return getPackageFragmentRoot(getProject().getFile(path));
}
} else {
// default root
return getPackageFragmentRoot(getProject());
}
} else {
if (target instanceof IResource) {
return this.getPackageFragmentRoot((IResource)target);
} else {
String ext = path.getFileExtension();
if (((java.io.File)target).isFile()
&& ("jar".equalsIgnoreCase(ext) //$NON-NLS-1$
|| "zip".equalsIgnoreCase(ext))) { //$NON-NLS-1$
// external jar
return getPackageFragmentRoot0(path.toOSString());
} else {
// unknown path
return null;
}
}
}
}
/**
* @see IJavaProject
*/
public IPackageFragmentRoot getPackageFragmentRoot(IResource resource) {
String name = resource.getName();
if (resource.getType() == IResource.FILE
&& (Util.endsWithIgnoreCase(name, ".jar") //$NON-NLS-1$
|| Util.endsWithIgnoreCase(name, ".zip"))) { //$NON-NLS-1$
return new JarPackageFragmentRoot(resource, this);
} else {
return new PackageFragmentRoot(resource, this);
}
}
/**
* @see IJavaProject
*/
public IPackageFragmentRoot getPackageFragmentRoot(String jarPath) {
return getPackageFragmentRoot0(this.canonicalizedPath(new Path(jarPath)).toString());
}
/**
* no path canonicalization
*/
public IPackageFragmentRoot getPackageFragmentRoot0(String jarPath) {
return new JarPackageFragmentRoot(jarPath, this);
}
/**
* @see IJavaProject
*/
public IPackageFragmentRoot[] getPackageFragmentRoots()
throws JavaModelException {
Object[] children;
int length;
IPackageFragmentRoot[] roots;
System.arraycopy(
children = getChildren(),
0,
roots = new IPackageFragmentRoot[length = children.length],
0,
length);
return roots;
}
/**
* Returns the package fragment roots identified by the given entry.
*/
public IPackageFragmentRoot[] getPackageFragmentRoots(IClasspathEntry entry) {
try {
IClasspathEntry[] correspondingEntries = this.getResolvedClasspath(new IClasspathEntry[]{entry}, true, false);
return computePackageFragmentRoots(correspondingEntries, false);
} catch (JavaModelException e) {
return new IPackageFragmentRoot[] {};
}
}
/**
* Returns the package fragment root prefixed by the given path, or
* an empty collection if there are no such elements in the model.
*/
protected IPackageFragmentRoot[] getPackageFragmentRoots(IPath path)
throws JavaModelException {
IPackageFragmentRoot[] roots = getAllPackageFragmentRoots();
ArrayList matches = new ArrayList();
for (int i = 0; i < roots.length; ++i) {
if (path.isPrefixOf(roots[i].getPath())) {
matches.add(roots[i]);
}
}
IPackageFragmentRoot[] copy = new IPackageFragmentRoot[matches.size()];
matches.toArray(copy);
return copy;
}
/**
* @see IJavaProject
*/
public IPackageFragment[] getPackageFragments() throws JavaModelException {
IPackageFragmentRoot[] roots = getPackageFragmentRoots();
return getPackageFragmentsInRoots(roots);
}
/**
* Returns all the package fragments found in the specified
* package fragment roots.
*/
public IPackageFragment[] getPackageFragmentsInRoots(IPackageFragmentRoot[] roots) {
ArrayList frags = new ArrayList();
for (int i = 0; i < roots.length; i++) {
IPackageFragmentRoot root = roots[i];
try {
IJavaElement[] rootFragments = root.getChildren();
for (int j = 0; j < rootFragments.length; j++) {
frags.add(rootFragments[j]);
}
} catch (JavaModelException e) {
// do nothing
}
}
IPackageFragment[] fragments = new IPackageFragment[frags.size()];
frags.toArray(fragments);
return fragments;
}
/*
* @see IJavaElement
*/
public IPath getPath() {
return this.getProject().getFullPath();
}
/**
* @see IJavaProject
*/
public IProject getProject() {
return fProject;
}
/**
* @see IJavaProject
*/
public IClasspathEntry[] getRawClasspath() throws JavaModelException {
IClasspathEntry[] classpath = null;
if (this.isOpen()) {
JavaProjectElementInfo info = getJavaProjectElementInfo();
classpath = info.getRawClasspath();
if (classpath != null) {
return classpath;
}
return defaultClasspath();
}
// if not already opened, then read from file (avoid populating the model for CP question)
String sharedClasspath = loadClasspath();
if (sharedClasspath != null) {
try {
classpath = readPaths(sharedClasspath);
} catch (IOException e) {
} catch (RuntimeException e) {
}
// extract out the output location
if (classpath != null && classpath.length > 0) {
IClasspathEntry entry = classpath[classpath.length - 1];
if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1];
System.arraycopy(classpath, 0, copy, 0, copy.length);
classpath = copy;
}
}
}
if (classpath != null) {
return classpath;
}
return defaultClasspath();
}
/**
* @see IJavaProject#getRequiredProjectNames
*/
public String[] getRequiredProjectNames() throws JavaModelException {
return this.projectPrerequisites(getResolvedClasspath(true));
}
/**
* @see IJavaProject
*/
public IClasspathEntry[] getResolvedClasspath(boolean ignoreUnresolvedVariable)
throws JavaModelException {
return
this.getResolvedClasspath(
ignoreUnresolvedVariable,
false); // generateMarkerOnError
}
/**
* Internal variant which can create marker on project for invalid entries
*/
public IClasspathEntry[] getResolvedClasspath(
boolean ignoreUnresolvedEntry,
boolean generateMarkerOnError)
throws JavaModelException {
JavaProjectElementInfo projectInfo;
if (this.isOpen()){
projectInfo = getJavaProjectElementInfo();
} else {
// avoid populating the model for only retrieving the resolved classpath (13395)
projectInfo = null;
}
// reuse cache if not needing to refresh markers or checking bound variables
if (ignoreUnresolvedEntry && !generateMarkerOnError && projectInfo != null){
// resolved path is cached on its info
IClasspathEntry[] infoPath = projectInfo.lastResolvedClasspath;
if (infoPath != null) return infoPath;
}
IClasspathEntry[] resolvedPath = getResolvedClasspath(getRawClasspath(), ignoreUnresolvedEntry, generateMarkerOnError);
if (projectInfo != null){
projectInfo.lastResolvedClasspath = resolvedPath;
}
return resolvedPath;
}
/**
* Internal variant which can process any arbitrary classpath
*/
public IClasspathEntry[] getResolvedClasspath(
IClasspathEntry[] classpathEntries,
boolean ignoreUnresolvedEntry,
boolean generateMarkerOnError)
throws JavaModelException {
if (generateMarkerOnError){
flushClasspathProblemMarkers(false);
}
int length = classpathEntries.length;
int index = 0;
ArrayList resolvedEntries = new ArrayList();
for (int i = 0; i < length; i++) {
IClasspathEntry rawEntry = classpathEntries[i];
/* validation if needed */
if (generateMarkerOnError) {
IJavaModelStatus status =
JavaConventions.validateClasspathEntry(this, rawEntry, false);
if (!status.isOK())
createClasspathProblemMarker(
status.getMessage(),
IMarker.SEVERITY_ERROR,
false);
}
switch (rawEntry.getEntryKind()){
case IClasspathEntry.CPE_VARIABLE :
IClasspathEntry resolvedEntry = JavaCore.getResolvedClasspathEntry(rawEntry);
if (resolvedEntry == null) {
if (!ignoreUnresolvedEntry) {
throw new JavaModelException(
new JavaModelStatus(
IJavaModelStatusConstants.CP_VARIABLE_PATH_UNBOUND,
rawEntry.getPath().toString()));
}
} else {
resolvedEntries.add(resolvedEntry);
}
break;
case IClasspathEntry.CPE_CONTAINER :
IClasspathContainer container = JavaCore.getClasspathContainer(rawEntry.getPath(), this);
if (container == null){
// unbound container
if (!ignoreUnresolvedEntry) {
throw new JavaModelException(
new JavaModelStatus(
IJavaModelStatusConstants.CP_CONTAINER_PATH_UNBOUND,
rawEntry.getPath().toString()));
}
break;
}
IClasspathEntry[] containerEntries = container.getClasspathEntries();
if (containerEntries == null) break;
// container was bound, container entries could be variables
for (int j = 0, containerLength = containerEntries.length; j < containerLength; j++){
IClasspathEntry containerRawEntry = containerEntries[j];
if (generateMarkerOnError) {
IJavaModelStatus status =
JavaConventions.validateClasspathEntry(this, containerRawEntry, false);
if (!status.isOK())
createClasspathProblemMarker(
status.getMessage(),
IMarker.SEVERITY_ERROR,
false);
}
// container entry is variable ?
if (containerRawEntry.getEntryKind() == IClasspathEntry.CPE_VARIABLE){
resolvedEntry = JavaCore.getResolvedClasspathEntry(containerRawEntry);
if (resolvedEntry == null) {
if (!ignoreUnresolvedEntry) {
throw new JavaModelException(
new JavaModelStatus(
IJavaModelStatusConstants.CP_VARIABLE_PATH_UNBOUND,
containerRawEntry.getPath().toString()));
}
} else {
resolvedEntries.add(resolvedEntry);
}
} else {
resolvedEntries.add(containerRawEntry);
}
}
break;
default :
resolvedEntries.add(rawEntry);
}
}
IClasspathEntry[] resolvedPath = new IClasspathEntry[resolvedEntries.size()];
resolvedEntries.toArray(resolvedPath);
return resolvedPath;
}
/*
* @see IJavaElement
*/
public IResource getResource() {
return this.getProject();
}
/**
* @see IJavaProject
*/
public ISearchableNameEnvironment getSearchableNameEnvironment()
throws JavaModelException {
JavaProjectElementInfo info = getJavaProjectElementInfo();
if (info.getSearchableEnvironment() == null) {
info.setSearchableEnvironment(new SearchableEnvironment(this));
}
return info.getSearchableEnvironment();
}
/**
* Retrieve a shared property on a project. If the property is not defined, answers null.
* Note that it is orthogonal to IResource persistent properties, and client code has to decide
* which form of storage to use appropriately. Shared properties produce real resource files which
* can be shared through a VCM onto a server. Persistent properties are not shareable.
*
* @see JavaProject#setSharedProperty(QualifiedName, String)
*/
public String getSharedProperty(QualifiedName key) throws CoreException {
String property = null;
String propertyFileName = computeSharedPropertyFileName(key);
IFile rscFile = getProject().getFile(propertyFileName);
if (rscFile.exists()) {
property = new String(Util.getResourceContentsAsByteArray(rscFile));
}
return property;
}
/**
* @see JavaElement
*/
public SourceMapper getSourceMapper() {
return null;
}
/**
* @see IJavaElement
*/
public IResource getUnderlyingResource() throws JavaModelException {
return getProject();
}
/**
* @see IJavaProject
*/
public boolean hasBuildState() {
return JavaModelManager.getJavaModelManager().getLastBuiltState(this.getProject(), null) != null;
}
/**
* @see IJavaProject
*/
public boolean hasClasspathCycle(IClasspathEntry[] entries) {
HashSet cycleParticipants = new HashSet();
updateCycleParticipants(entries, new ArrayList(), cycleParticipants, getWorkspace().getRoot());
return !cycleParticipants.isEmpty();
}
public boolean hasCycleMarker(){
try {
IProject project = getProject();
if (project.exists()) {
IMarker[] markers = project.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ONE);
for (int i = 0, length = markers.length; i < length; i++) {
IMarker marker = markers[i];
String cycleAttr = (String)marker.getAttribute(IJavaModelMarker.CYCLE_DETECTED);
if (cycleAttr != null && cycleAttr.equals("true")){ //$NON-NLS-1$
return true;
}
}
}
} catch (CoreException e) {
}
return false;
}
public int hashCode() {
return fProject.hashCode();
}
/**
* Answers true if the project potentially contains any source. A project which has no source is immutable.
*/
public boolean hasSource() {
// look if any source folder on the classpath
// no need for resolved path given source folder cannot be abstracted
IClasspathEntry[] entries;
try {
entries = this.getRawClasspath();
} catch (JavaModelException e) {
return true; // unsure
}
for (int i = 0, max = entries.length; i < max; i++) {
if (entries[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) {
return true;
}
}
return false;
}
/**
* Compare current classpath with given one to see if any different.
* Note that the argument classpath contains its binary output.
*/
public boolean isClasspathEqualsTo(IClasspathEntry[] newClasspath, IPath newOutputLocation, IClasspathEntry[] otherClasspathWithOutput)
throws JavaModelException {
if (otherClasspathWithOutput != null && otherClasspathWithOutput.length > 0) {
int length = otherClasspathWithOutput.length;
if (length == newClasspath.length + 1) {
// output is amongst file entries (last one)
// compare classpath entries
for (int i = 0; i < length - 1; i++) {
if (!otherClasspathWithOutput[i].equals(newClasspath[i]))
return false;
}
// compare binary outputs
if (otherClasspathWithOutput[length - 1].getContentKind()
== ClasspathEntry.K_OUTPUT
&& otherClasspathWithOutput[length - 1].getPath().equals(newOutputLocation))
return true;
}
}
return false;
}
/*
* @see IJavaProject
*/
public boolean isOnClasspath(IJavaElement element) throws JavaModelException {
IPath rootPath;
if (element.getElementType() == IJavaElement.JAVA_PROJECT) {
rootPath = ((IJavaProject)element).getProject().getFullPath();
} else {
IPackageFragmentRoot root = (IPackageFragmentRoot)element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
if (root == null) {
return false;
}
rootPath = root.getPath();
}
return this.findPackageFragmentRoot0(rootPath) != null;
}
/**
* load the classpath from a shareable format (VCM-wise)
*/
public String loadClasspath() throws JavaModelException {
try {
return getSharedProperty(getClasspathPropertyName());
} catch (CoreException e) {
throw new JavaModelException(e);
}
}
/**
* @see IJavaProject#newEvaluationContext
*/
public IEvaluationContext newEvaluationContext() {
return new EvaluationContextWrapper(new EvaluationContext(), this);
}
/**
* @see IJavaProject#newLibraryEntry(IPath)
* @deprecated - use JavaCore API instead
*/
public IClasspathEntry newLibraryEntry(IPath path) {
return JavaCore.newLibraryEntry(path, null, null, false);
}
/**
* @see IJavaProject#newProjectEntry(IPath)
* @deprecated - use JavaCore API instead
*/
public IClasspathEntry newProjectEntry(IPath path) {
return JavaCore.newProjectEntry(path, false);
}
/**
* @see IJavaProject#newSourceEntry(IPath)
* @deprecated - use JavaCore API instead
*/
public IClasspathEntry newSourceEntry(IPath path) {
return JavaCore.newSourceEntry(path);
}
/**
* @see IJavaProject
*/
public ITypeHierarchy newTypeHierarchy(
IRegion region,
IProgressMonitor monitor)
throws JavaModelException {
if (region == null) {
throw new IllegalArgumentException(Util.bind("hierarchy.nullRegion"));//$NON-NLS-1$
}
CreateTypeHierarchyOperation op =
new CreateTypeHierarchyOperation(null, region, this, true);
runOperation(op, monitor);
return op.getResult();
}
/**
* @see IJavaProject
*/
public ITypeHierarchy newTypeHierarchy(
IType type,
IRegion region,
IProgressMonitor monitor)
throws JavaModelException {
if (type == null) {
throw new IllegalArgumentException(Util.bind("hierarchy.nullFocusType"));//$NON-NLS-1$
}
if (region == null) {
throw new IllegalArgumentException(Util.bind("hierarchy.nullRegion"));//$NON-NLS-1$
}
CreateTypeHierarchyOperation op =
new CreateTypeHierarchyOperation(type, region, this, true);
runOperation(op, monitor);
return op.getResult();
}
/**
* Ensures that this project is not currently being deleted before
* opening.
*
* fix for 1FW67PA
*/
protected void openWhenClosed(IProgressMonitor pm) throws JavaModelException {
JavaModelManager manager =
(JavaModelManager) JavaModelManager.getJavaModelManager();
if (manager.isBeingDeleted(fProject) || !this.fProject.isOpen()) {
throw newNotPresentException();
} else {
super.openWhenClosed(pm);
}
}
public String[] projectPrerequisites(IClasspathEntry[] entries)
throws JavaModelException {
ArrayList prerequisites = new ArrayList();
// need resolution
entries = getResolvedClasspath(entries, true, false);
for (int i = 0, length = entries.length; i < length; i++) {
IClasspathEntry entry = entries[i];
if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
prerequisites.add(entry.getPath().lastSegment());
}
}
int size = prerequisites.size();
if (size == 0) {
return NO_PREREQUISITES;
} else {
String[] result = new String[size];
prerequisites.toArray(result);
return result;
}
}
/**
* Returns a collection of <code>IClasspathEntry</code>s from the given
* classpath string in XML format.
*
* @exception IOException if the stream cannot be read
*/
protected IClasspathEntry[] readPaths(String xmlClasspath) throws IOException {
IPath projectPath = getProject().getFullPath();
StringReader reader = new StringReader(xmlClasspath);
Element cpElement;
try {
DocumentBuilder parser =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
cpElement = parser.parse(new InputSource(reader)).getDocumentElement();
} catch (SAXException e) {
throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$
} catch (ParserConfigurationException e) {
reader.close();
throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$
} finally {
reader.close();
}
if (!cpElement.getNodeName().equalsIgnoreCase("classpath")) { //$NON-NLS-1$
throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$
}
NodeList list = cpElement.getChildNodes();
ArrayList paths = new ArrayList();
int length = list.getLength();
for (int i = 0; i < length; ++i) {
Node node = list.item(i);
short type = node.getNodeType();
if (type == Node.ELEMENT_NODE) {
Element cpeElement = (Element) node;
if (cpeElement.getNodeName().equalsIgnoreCase("classpathentry")) { //$NON-NLS-1$
String cpeElementKind = cpeElement.getAttribute("kind"); //$NON-NLS-1$
String pathStr = cpeElement.getAttribute("path"); //$NON-NLS-1$
// ensure path is absolute
IPath path = new Path(pathStr);
int kind = kindFromString(cpeElementKind);
if (kind != IClasspathEntry.CPE_VARIABLE && kind != IClasspathEntry.CPE_CONTAINER && !path.isAbsolute()) {
path = projectPath.append(path);
}
// source attachment info (optional)
String sourceAttachmentPathStr = cpeElement.getAttribute("sourcepath"); //$NON-NLS-1$
IPath sourceAttachmentPath =
sourceAttachmentPathStr.equals("") ? null : new Path(sourceAttachmentPathStr); //$NON-NLS-1$
String sourceAttachmentRootPathStr = cpeElement.getAttribute("rootpath"); //$NON-NLS-1$
IPath sourceAttachmentRootPath =
sourceAttachmentRootPathStr.equals("") //$NON-NLS-1$
? null
: new Path(sourceAttachmentRootPathStr);
// exported flag
boolean isExported = cpeElement.getAttribute("exported").equals("true"); //$NON-NLS-1$ //$NON-NLS-2$
// recreate the CP entry
switch (kind) {
case IClasspathEntry.CPE_PROJECT :
if (!path.isAbsolute()) return null;
paths.add(JavaCore.newProjectEntry(path, isExported));
break;
case IClasspathEntry.CPE_LIBRARY :
if (!path.isAbsolute()) return null;
paths.add(JavaCore.newLibraryEntry(
path,
sourceAttachmentPath,
sourceAttachmentRootPath,
isExported));
break;
case IClasspathEntry.CPE_SOURCE :
if (!path.isAbsolute()) return null;
// must be an entry in this project or specify another project
String projSegment = path.segment(0);
if (projSegment != null && projSegment.equals(getElementName())) {
// this project
paths.add(JavaCore.newSourceEntry(path));
} else {
// another project
paths.add(JavaCore.newProjectEntry(path, isExported));
}
break;
case IClasspathEntry.CPE_VARIABLE :
paths.add(JavaCore.newVariableEntry(
path,
sourceAttachmentPath,
sourceAttachmentRootPath,
isExported));
break;
case IClasspathEntry.CPE_CONTAINER :
paths.add(JavaCore.newContainerEntry(
path,
isExported));
break;
case ClasspathEntry.K_OUTPUT :
if (!path.isAbsolute()) return null;
paths.add(new ClasspathEntry(
ClasspathEntry.K_OUTPUT,
IClasspathEntry.CPE_LIBRARY,
path,
null,
null,
false));
break;
}
}
}
}
if (paths.size() > 0) {
IClasspathEntry[] ips = new IClasspathEntry[paths.size()];
paths.toArray(ips);
return ips;
} else {
return null;
}
}
/**
* Removes the given builder from the build spec for the given project.
*/
protected void removeFromBuildSpec(String builderID) throws CoreException {
IProjectDescription description = getProject().getDescription();
ICommand[] commands = description.getBuildSpec();
for (int i = 0; i < commands.length; ++i) {
if (commands[i].getBuilderName().equals(builderID)) {
ICommand[] newCommands = new ICommand[commands.length - 1];
System.arraycopy(commands, 0, newCommands, 0, i);
System.arraycopy(commands, i + 1, newCommands, i, commands.length - i - 1);
description.setBuildSpec(newCommands);
getProject().setDescription(description, null);
return;
}
}
}
/**
* @see JavaElement#rootedAt(IJavaProject)
*/
public IJavaElement rootedAt(IJavaProject project) {
return project;
}
/**
* Answers an ID which is used to distinguish project/entries during package
* fragment root computations
*/
public String rootID(){
return "[PRJ]"+this.getProject().getFullPath(); //$NON-NLS-1$
}
/**
* Saves the classpath in a shareable format (VCM-wise) if necessary (i.e.&nbsp;semantically different).
* Will never write an identical one.
* Returns whether the .classpath file was modified.
*/
public boolean saveClasspath(IClasspathEntry[] newClasspath, IPath newOutputLocation) throws JavaModelException {
if (!getProject().exists()) return false;
QualifiedName classpathProp = getClasspathPropertyName();
try {
// attempt to prove the classpath has not change
String fileClasspathString = getSharedProperty(classpathProp);
if (fileClasspathString != null) {
IClasspathEntry[] fileEntries = readPaths(fileClasspathString);
if (isClasspathEqualsTo(newClasspath, newOutputLocation, fileEntries)) {
// no need to save it, it is the same
return false;
}
}
} catch (IOException e) {
} catch (RuntimeException e) {
} catch (CoreException e) {
}
// actual file saving
try {
setSharedProperty(
classpathProp,
getClasspathAsXMLString(newClasspath, newOutputLocation));
return true;
} catch (CoreException e) {
throw new JavaModelException(e);
}
}
/**
* @see IJavaProject#setClasspath(IClasspathEntry[], IProgressMonitor)
* @deprecated - use #setRawClasspath instead
*/
public void setClasspath(IClasspathEntry[] entries, IProgressMonitor monitor)
throws JavaModelException {
this.setRawClasspath(entries, monitor);
}
/**
* Update the Java command in the build spec (replace existing one if present,
* add one first if none).
*/
private void setJavaCommand(
IProjectDescription description,
ICommand newCommand)
throws CoreException {
ICommand[] oldCommands = description.getBuildSpec();
ICommand oldJavaCommand = getJavaCommand(description);
ICommand[] newCommands;
if (oldJavaCommand == null) {
// Add a Java build spec before other builders (1FWJK7I)
newCommands = new ICommand[oldCommands.length + 1];
System.arraycopy(oldCommands, 0, newCommands, 1, oldCommands.length);
newCommands[0] = newCommand;
} else {
for (int i = 0, max = oldCommands.length; i < max; i++) {
if (oldCommands[i] == oldJavaCommand) {
oldCommands[i] = newCommand;
break;
}
}
newCommands = oldCommands;
}
// Commit the spec change into the project
description.setBuildSpec(newCommands);
getProject().setDescription(description, null);
}
/**
* @see IJavaProject
*/
public void setOutputLocation(IPath outputLocation, IProgressMonitor monitor)
throws JavaModelException {
if (outputLocation == null) {
throw new IllegalArgumentException(Util.bind("path.nullpath")); //$NON-NLS-1$
}
if (outputLocation.equals(getOutputLocation())) {
return;
}
this.setRawClasspath(SetClasspathOperation.ReuseClasspath, outputLocation, monitor);
}
/**
* Sets the underlying kernel project of this Java project,
* and fills in its parent and name.
* Called by IProject.getNature().
*
* @see IProjectNature#setProject
*/
public void setProject(IProject project) {
fProject = project;
fParent = JavaModelManager.getJavaModelManager().getJavaModel();
fName = project.getName();
}
/**
* @see IJavaProject
*/
public void setRawClasspath(
IClasspathEntry[] entries,
IPath outputLocation,
IProgressMonitor monitor)
throws JavaModelException {
setRawClasspath(
entries,
outputLocation,
monitor,
true, // canChangeResource
true, // forceSave
getResolvedClasspath(true), // ignoreUnresolvedVariable
true); // needCycleCheck
}
public void setRawClasspath(
IClasspathEntry[] newEntries,
IPath newOutputLocation,
IProgressMonitor monitor,
boolean canChangeResource,
boolean forceSave,
IClasspathEntry[] oldResolvedPath,
boolean needCycleCheck)
throws JavaModelException {
JavaModelManager manager =
(JavaModelManager) JavaModelManager.getJavaModelManager();
try {
IClasspathEntry[] newRawPath = newEntries;
if (newRawPath == null) { //are we already with the default classpath
newRawPath = defaultClasspath();
}
SetClasspathOperation op =
new SetClasspathOperation(
this,
oldResolvedPath,
newRawPath,
newOutputLocation,
canChangeResource,
forceSave,
needCycleCheck);
runOperation(op, monitor);
} catch (JavaModelException e) {
manager.flush();
throw e;
}
}
/**
* @see IJavaProject
*/
public void setRawClasspath(
IClasspathEntry[] entries,
IProgressMonitor monitor)
throws JavaModelException {
setRawClasspath(
entries,
SetClasspathOperation.ReuseOutputLocation,
monitor,
true, // canChangeResource
true, // forceSave
getResolvedClasspath(true), // ignoreUnresolvedVariable
true); // needCycleCheck
}
/**
* NOTE: <code>null</code> specifies default classpath, and an empty
* array specifies an empty classpath.
*
* @exception NotPresentException if this project does not exist.
*/
protected void setRawClasspath0(IClasspathEntry[] rawEntries)
throws JavaModelException {
// if not open, will cause opening with default path
JavaProjectElementInfo info = getJavaProjectElementInfo();
synchronized (info) {
if (rawEntries == null) {
rawEntries = defaultClasspath();
}
// clear cache of resolved classpath
info.lastResolvedClasspath = null;
info.setRawClasspath(rawEntries);
// compute the new roots
updatePackageFragmentRoots();
}
}
/**
* Record a shared persistent property onto a project.
* Note that it is orthogonal to IResource persistent properties, and client code has to decide
* which form of storage to use appropriately. Shared properties produce real resource files which
* can be shared through a VCM onto a server. Persistent properties are not shareable.
*
* shared properties end up in resource files, and thus cannot be modified during
* delta notifications (a CoreException would then be thrown).
*
* @see JavaProject#getSharedProperty(QualifiedName key)
*/
public void setSharedProperty(QualifiedName key, String value)
throws CoreException {
String propertyName = computeSharedPropertyFileName(key);
IFile rscFile = getProject().getFile(propertyName);
InputStream input = new ByteArrayInputStream(value.getBytes());
// update the resource content
if (rscFile.exists()) {
rscFile.setContents(input, true, false, null);
} else {
rscFile.create(input, true, null);
}
}
/**
* Update cycle markers for all java projects
*/
public static void updateAllCycleMarkers() throws JavaModelException {
JavaModelManager manager = JavaModelManager.getJavaModelManager();
IJavaProject[] projects = manager.getJavaModel().getJavaProjects();
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
HashSet cycleParticipants = new HashSet();
ArrayList visited = new ArrayList();
int length = projects.length;
for (int i = 0; i < length; i++){
JavaProject project = (JavaProject)projects[i];
if (!cycleParticipants.contains(project)){
visited.clear();
project.updateCycleParticipants(null, visited, cycleParticipants, workspaceRoot);
}
}
for (int i = 0; i < length; i++){
JavaProject project = (JavaProject)projects[i];
if (cycleParticipants.contains(project)){
if (!project.hasCycleMarker()){
project.createClasspathProblemMarker(
Util.bind("classpath.cycle"), //$NON-NLS-1$
IMarker.SEVERITY_ERROR,
true);
}
} else {
project.flushClasspathProblemMarkers(true);
}
}
}
/**
* If a cycle is detected, then cycleParticipants contains all the project involved in this cycle (directly),
* no cycle if the set is empty (and started empty)
*/
public void updateCycleParticipants(IClasspathEntry[] preferredClasspath, ArrayList visited, HashSet cycleParticipants, IWorkspaceRoot workspaceRoot){
int index = visited.indexOf(this);
if (index >= 0){
// only consider direct participants inside the cycle
for (int i = index, size = visited.size(); i < size; i++){
cycleParticipants.add(visited.get(i));
}
return;
} else {
visited.add(this);
}
try {
IClasspathEntry[] classpath;
if (preferredClasspath == null) {
classpath = getResolvedClasspath(true);
} else {
classpath = preferredClasspath;
}
for (int i = 0, length = classpath.length; i < length; i++) {
IClasspathEntry entry = classpath[i];
if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT){
String projectName = entry.getPath().lastSegment();
JavaProject project = (JavaProject)JavaCore.create(workspaceRoot.getProject(projectName));
project.updateCycleParticipants(null, visited, cycleParticipants, workspaceRoot);
}
}
} catch(JavaModelException e){
}
visited.remove(this);
}
/**
* Reset the collection of package fragment roots (local ones) - only if opened.
* Need to check *all* package fragment roots in order to reset NameLookup
*/
public void updatePackageFragmentRoots(){
if (this.isOpen()) {
try {
JavaProjectElementInfo info = getJavaProjectElementInfo();
IClasspathEntry[] classpath = getResolvedClasspath(true);
NameLookup lookup = info.getNameLookup();
if (lookup != null){
IPackageFragmentRoot[] oldRoots = lookup.fPackageFragmentRoots;
IPackageFragmentRoot[] newRoots = computePackageFragmentRoots(classpath, true);
checkIdentical: { // compare all pkg fragment root lists
if (oldRoots.length == newRoots.length){
for (int i = 0, length = oldRoots.length; i < length; i++){
if (!oldRoots[i].equals(newRoots[i])){
break checkIdentical;
}
}
return; // no need to update
}
}
info.setNameLookup(null); // discard name lookup (hold onto roots)
}
info.setNonJavaResources(null);
info.setChildren(
computePackageFragmentRoots(classpath, false));
} catch(JavaModelException e){
try {
close(); // could not do better
} catch(JavaModelException ex){
}
}
}
}
}