blob: c3b890234a38a0cfcede96bcefb2a57b850adafc [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.resources.*;
import org.eclipse.jdt.internal.codeassist.ISearchableNameEnvironment;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.eval.IEvaluationContext;
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.Hashtable;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Vector;
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 an INameLookup facility that locates elements
* on by name, based on the devpath.
*
* @see IJavaProject
*/
public class JavaProject extends Openable implements IJavaProject, IProjectNature {
/**
* 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;
/**
* 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);
}
}
/**
* 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 not external path, return original path
if (ResourcesPlugin.getWorkspace().getRoot().findMember(externalPath) != null) {
return externalPath;
}
IPath canonicalPath = null;
try {
canonicalPath = new Path(new File(externalPath.toOSString()).getCanonicalPath());
} catch (IOException e) {
// default to original path
return externalPath;
}
// keep only segments that were in original path and device if it was there
IPath result = canonicalPath.removeFirstSegments(canonicalPath.segmentCount() - externalPath.segmentCount());
if (externalPath.getDevice() == null) {
return result.setDevice(null);
} else {
return result;
}
}
/**
* Compute the file name to use for a given shared property
*/
public String computeSharedPropertyFileName(QualifiedName qName){
return /*'.' + qName.getQualifier() + */ '.' + qName.getLocalName();
}
/**
* Configure the project with Java nature.
*/
public void configure() throws CoreException {
// register Java builder
addToBuildSpec(JavaCore.BUILDER_ID);
// notify Java delta (Java project added)
JavaModelManager manager = (JavaModelManager) JavaModelManager.getJavaModelManager();
JavaModel model = (JavaModel) getJavaModel();
JavaElementDelta projectDelta = new JavaElementDelta(model);
projectDelta.added(this);
JavaElementInfo jmi= model.getElementInfo();
jmi.addChild(this);
manager.registerResourceDelta(projectDelta);
manager.fire();
}
/**
* Create's a classpath entry of the specified kind.
*
* Returns null if unable to create a valid entry.
*/
protected IClasspathEntry createClasspathEntry(IPath path, int kind, IPath sourceAttachmentPath, IPath sourceAttachmentRootPath) {
switch(kind){
case IClasspathEntry.CPE_PROJECT :
if (!path.isAbsolute()) return null;
return JavaCore.newProjectEntry(path);
case IClasspathEntry.CPE_LIBRARY :
if (!path.isAbsolute()) return null;
return JavaCore.newLibraryEntry(path, sourceAttachmentPath, sourceAttachmentRootPath);
case IClasspathEntry.CPE_SOURCE :
if (!path.isAbsolute()) return null;
// must be an entry in this project or specify another project
// change zrh
String projSegment= path.segment(0);
if (projSegment != null && projSegment.equals(getElementName())) {
// this project
return JavaCore.newSourceEntry(path);
} else {
// another project
return JavaCore.newProjectEntry(path);
}
case IClasspathEntry.CPE_VARIABLE :
return JavaCore.newVariableEntry(path, sourceAttachmentPath, sourceAttachmentRootPath);
case ClasspathEntry.K_OUTPUT :
if (!path.isAbsolute()) return null;
return new ClasspathEntry(ClasspathEntry.K_OUTPUT, IClasspathEntry.CPE_LIBRARY, path, null, null);
default:
return null;
}
}
/**
* 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") || extension.equalsIgnoreCase("class")) { //$NON-NLS-1$ //$NON-NLS-2$
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, INameLookup.ACCEPT_CLASSES | INameLookup.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 INameLookup
*/
public IPackageFragment findPackageFragment(IPath path) throws JavaModelException {
return getNameLookup().findPackageFragment(this.canonicalizedPath(path));
}
/**
* @see INameLookup
*/
public IPackageFragmentRoot findPackageFragmentRoot(IPath path) throws JavaModelException {
return getNameLookup().findPackageFragmentRoot(this.canonicalizedPath(path));
}
/**
* @see Openable
*/
protected boolean generateInfos(OpenableElementInfo info, IProgressMonitor pm, Hashtable 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)
boolean needToSaveClasspath = false;
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();
needToSaveClasspath = true;
}
setOutputLocation0(outputLocation);
// restore classpath
if (classpath == null) {
classpath= defaultClasspath();
needToSaveClasspath = true;
}
setRawClasspath0(classpath);
// need to commit classpath ?
//if (needToSaveClasspath) saveClasspath();
// 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 {
IJavaElement[] tempChildren= getElementInfo().getChildren();
IPackageFragmentRoot[] children= new IPackageFragmentRoot[tempChildren.length];
for (int i= 0; i < tempChildren.length; i++) {
children[i]= (IPackageFragmentRoot) tempChildren[i];
}
return children;
}
/**
* Returns all package fragments from all of the package fragment roots
* on the classpath.
*/
public IPackageFragment[] getAllPackageFragments() throws JavaModelException {
IPackageFragmentRoot[] roots= getAllPackageFragmentRoots();
return getPackageFragmentsInRoots(roots);
}
/**
* Returns all the <code>IPackageFragmentRoot</code>s the builder needs to
* know about in order to build this project. This includes:
* <ul>
* <li>the source roots for the current project
* <li>the binary roots (output locations) for the required projects
* <li>the binary roots for any jar/lib used by this project
* </li>
*/
public IPackageFragmentRoot[] getBuilderRoots(IResourceDelta delta) throws JavaModelException {
Vector builderRoots= new Vector();
IClasspathEntry[] classpath;
classpath= getResolvedClasspath(true);
IResource res;
IJavaProject project;
for (int i= 0; i < classpath.length; i++) {
IClasspathEntry entry= classpath[i];
switch (entry.getEntryKind()) {
case IClasspathEntry.CPE_LIBRARY :
IPackageFragmentRoot[] roots= this.getPackageFragmentRoots(entry);
if (roots.length > 0)
builderRoots.addElement(roots[0]);
break;
case IClasspathEntry.CPE_PROJECT :
// other project contributions are restrained to their binary output
res= retrieveResource(entry.getPath(), delta);
if (res != null) {
project= (IJavaProject) JavaCore.create(res);
if (project.isOpen()){
res= retrieveResource(project.getOutputLocation(), delta);
if (res != null) {
PackageFragmentRoot root= (PackageFragmentRoot) project.getPackageFragmentRoot(res);
root.setOccurrenceCount(root.getOccurrenceCount() + 1);
((PackageFragmentRootInfo) root.getElementInfo()).setRootKind(IPackageFragmentRoot.K_BINARY);
root.refreshChildren();
builderRoots.addElement(root);
}
}
}
break;
case IClasspathEntry.CPE_SOURCE :
if (getCorrespondingResource().getFullPath().isPrefixOf(entry.getPath())) {
res= retrieveResource(entry.getPath(), delta);
if (res != null)
builderRoots.addElement(getPackageFragmentRoot(res));
} else {
IProject proj= (IProject) getWorkspace().getRoot().findMember(entry.getPath());
project= (IJavaProject) JavaCore.create(proj);
if (proj.isOpen()){
res= retrieveResource(project.getOutputLocation(), delta);
PackageFragmentRoot root= (PackageFragmentRoot) project.getPackageFragmentRoot(res);
root.setOccurrenceCount(root.getOccurrenceCount() + 1);
((PackageFragmentRootInfo) root.getElementInfo()).setRootKind(IPackageFragmentRoot.K_BINARY);
root.refreshChildren();
builderRoots.addElement(root);
}
}
break;
}
}
IPackageFragmentRoot[] result= new IPackageFragmentRoot[builderRoots.size()];
builderRoots.copyInto(result);
return result;
}
/**
* @see IParent
*/
public IJavaElement[] getChildren() throws JavaModelException {
return getPackageFragmentRoots();
}
/**
* 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= getResolvedClasspath(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$
}
/**
* 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){
// 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", entry.getSourceAttachmentRootPath().toString()); //$NON-NLS-1$
}
return element;
}
/**
* 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 INameLookup 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 path = getJavaProjectElementInfo().getOutputLocation();
if (path == null) {
return this.defaultOutputLocation();
} else {
return path;
}
}
/**
* @see IJavaProject
*/
public IPackageFragmentRoot getPackageFragmentRoot(String jarPath) {
jarPath = this.canonicalizedPath(new Path(jarPath)).toString();
return new JarPackageFragmentRoot(jarPath, this);
}
/**
* @see IJavaProject
*/
public IPackageFragmentRoot getPackageFragmentRoot(IResource resource) {
String name= resource.getName();
if (Util.endsWithIgnoreCase(name,".jar") || Util.endsWithIgnoreCase(name,".zip")) { //$NON-NLS-2$ //$NON-NLS-1$
return new JarPackageFragmentRoot(resource, this);
} else {
return new PackageFragmentRoot(resource, this);
}
}
/**
* Returns 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.
*
* @private
*/
public IPackageFragmentRoot getPackageFragmentRoot(IPath path) {
IResource resource = null;
if (!path.isAbsolute() || (resource = getProject().getWorkspace().getRoot().findMember(path)) != null) {
if (resource != null){
return getPackageFragmentRoot(resource);
}
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 {
return getPackageFragmentRoot(path.toString()); // external jar
}
}
/**
* @see IJavaProject
*/
public IPackageFragmentRoot[] getPackageFragmentRoots() throws JavaModelException {
IPackageFragmentRoot[] children= getAllPackageFragmentRoots();
Vector directChildren= new Vector(children.length);
for (int i= 0; i < children.length; i++) {
IPackageFragmentRoot root= children[i];
IJavaProject proj= root.getJavaProject();
if (proj != null && proj.equals(this)) {
directChildren.addElement(root);
}
}
children= new IPackageFragmentRoot[directChildren.size()];
directChildren.copyInto(children);
return children;
}
/**
* 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();
Vector matches= new Vector();
for (int i= 0; i < roots.length; ++i) {
if (path.isPrefixOf(roots[i].getPath())) {
matches.addElement(roots[i]);
}
}
IPackageFragmentRoot[] copy= new IPackageFragmentRoot[matches.size()];
matches.copyInto(copy);
return copy;
}
/**
* Returns the package fragment roots identified by the given entry.
*/
public IPackageFragmentRoot[] getPackageFragmentRoots(IClasspathEntry entry) {
entry = JavaCore.getResolvedClasspathEntry(entry);
if (entry == null){
return new IPackageFragmentRoot[] {}; // variable not found
}
IPath path= entry.getPath();
IWorkspaceRoot workspaceRoot = getWorkspace().getRoot();
if (entry.getContentKind() == IPackageFragmentRoot.K_BINARY) {
String ext= path.getFileExtension();
IPackageFragmentRoot root= null;
if (ext != null && (ext.equalsIgnoreCase("zip") || ext.equalsIgnoreCase("jar"))) { //$NON-NLS-1$ //$NON-NLS-2$
// jar
// removeFirstSegment removes the part relative to the project which is retrieve
// through workspace.getDefaultContentLocation
if (path.isAbsolute() && getWorkspace().getRoot().findMember(path) == null) {
// file system jar
root= new JarPackageFragmentRoot(path.toOSString(), this);
} else {
// resource jar
root= new JarPackageFragmentRoot(workspaceRoot.getFile(path), this);
}
return new IPackageFragmentRoot[] {root};
}
}
IPath projectPath= getProject().getFullPath();
if (projectPath.isPrefixOf(path)) {
// local to this project
IResource resource= null;
// change zrh
if (path.segmentCount() > 1) {
resource= workspaceRoot.getFolder(path);
} else {
resource= workspaceRoot.findMember(path);
}
if (resource == null) return new IPackageFragmentRoot[]{};
IPackageFragmentRoot root= new PackageFragmentRoot(resource, this);
return new IPackageFragmentRoot[] {root};
} else {
// another project
// change zrh
if (path.segmentCount() != 1)
return new IPackageFragmentRoot[] {}; // invalid path for a project
String project= path.segment(0);
IJavaProject javaProject= getJavaModel().getJavaProject(project);
Vector sourceRoots= new Vector();
IPackageFragmentRoot[] roots= null;
try {
roots= javaProject.getPackageFragmentRoots();
} catch (JavaModelException e) {
return new IPackageFragmentRoot[]{};
}
for (int i= 0; i < roots.length; i++) {
try {
if (roots[i].getKind() == IPackageFragmentRoot.K_SOURCE) {
sourceRoots.addElement(roots[i]);
}
} catch (JavaModelException e) {
// do nothing if the root does not exist
}
}
IPackageFragmentRoot[] copy= new IPackageFragmentRoot[sourceRoots.size()];
sourceRoots.copyInto(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.
*/
protected IPackageFragment[] getPackageFragmentsInRoots(IPackageFragmentRoot[] roots) {
Vector frags= new Vector();
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.addElement(rootFragments[j]);
}
} catch (JavaModelException e) {
// do nothing
}
}
IPackageFragment[] fragments= new IPackageFragment[frags.size()];
frags.copyInto(fragments);
return fragments;
}
/**
* @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);
}
/**
* @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(...)
*/
public String getSharedProperty(QualifiedName key) throws CoreException {
String property = null;
try {
String propertyFileName= computeSharedPropertyFileName(key);
IFile rscFile = getProject().getFile(propertyFileName);
if (rscFile.exists()){
InputStream input = rscFile.getContents(true);
property = new String(Util.readContentsAsBytes(input));
}
} catch (IOException e) {
}
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) {
StringHashtableOfInt depthTable= new StringHashtableOfInt();
try {
String projectName= this.getElementName();
depthTable.put(projectName, -2); // mark this project as being visited
String[] prerequisites= this.projectPrerequisites(entries);
for (int i= 0, length= prerequisites.length; i < length; i++) {
((JavaModel) this.getJavaModel()).computeDepth(prerequisites[i], depthTable, projectName, false);
}
} catch (JavaModelException e) {
return e.getStatus().getCode() == IJavaModelStatusConstants.NAME_COLLISION;
}
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[] otherClasspathWithOutput) throws JavaModelException {
if (otherClasspathWithOutput != null && otherClasspathWithOutput.length > 0) {
IClasspathEntry[] classpath = getRawClasspath();
int length = otherClasspathWithOutput.length;
if (length == classpath.length+1){ // output is amongst file entries (last one)
// compare classpath entries
for (int i = 0; i < length-1; i++){
if (!otherClasspathWithOutput[i].equals(classpath[i])) return false;
}
// compare binary outputs
if (otherClasspathWithOutput[length-1].getContentKind() == ClasspathEntry.K_OUTPUT
&& otherClasspathWithOutput[length-1].getPath().equals(getOutputLocation())) return true;
}
}
return false;
}
/**
* 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("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 ClasspathEntry.K_OUTPUT :
return "output"; //$NON-NLS-1$
default :
return "unknown"; //$NON-NLS-1$
}
}
/**
* 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
*/
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
*/
public void open(IProgressMonitor pm) throws JavaModelException {
JavaModelManager manager= (JavaModelManager) JavaModelManager.getJavaModelManager();
if (manager.isBeingDeleted(fProject)) {
throw newNotPresentException();
} else {
super.open(pm);
}
}
/**
* 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);
}
}
private String[] projectPrerequisites(IClasspathEntry[] entries) throws JavaModelException {
Vector prerequisites= new Vector();
for (int i= 0, length= entries.length; i < length; i++) {
IClasspathEntry entry= entries[i];
entry = JavaCore.getResolvedClasspathEntry(entry);
if (entry == null) continue; // ignore unbound variable
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.copyInto(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();
Vector paths= new Vector();
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 && !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("") ? null : new Path(sourceAttachmentRootPathStr); //$NON-NLS-1$
IClasspathEntry entry= createClasspathEntry(path, kind, sourceAttachmentPath, sourceAttachmentRootPath);
if (entry == null) return null;
paths.addElement(entry);
}
}
}
if (paths.size() > 0) {
IClasspathEntry[] ips= new IClasspathEntry[paths.size()];
paths.copyInto(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;
}
}
}
/**
* Reset the non-java resources collection for package fragment roots of the
* receiver
*/
protected void resetNonJavaResourcesForPackageFragmentRoots() throws JavaModelException {
IPackageFragmentRoot[] roots = getAllPackageFragmentRoots();
if (roots == null) return;
for (int i = 0, max = roots.length; i < max; i++) {
IPackageFragmentRoot root = roots[i];
try {
IResource res = root.getUnderlyingResource();
if (res != null) {
((PackageFragmentRoot)root).resetNonJavaResources();
}
} catch(JavaModelException e) {
// ignore if the resource cannot be retrieved anymore.
}
}
}
/**
* Returns the <code>IResource</code> that correspond to the specified path.
* null if none.
*/
private IResource retrieveResource(IPath path, IResourceDelta delta) throws JavaModelException {
IWorkspaceRoot workspaceRoot = getWorkspace().getRoot();
IResource res= workspaceRoot.findMember(path);
if (delta == null)
return res;
if (res == null) {
// the resource has been removed or renamed
// look for a possible delta that might help to retrieve the new resource if case of renamed
IResourceDelta[] deltas= delta.getAffectedChildren();
for (int i= 0, max= deltas.length; i < max; i++) {
IResourceDelta currentDelta= deltas[i];
if (currentDelta.getKind() == IResourceDelta.REMOVED) {
IPath moveToPath= currentDelta.getMovedToPath();
if (moveToPath != null) {
res= workspaceRoot.findMember(moveToPath);
if (res == null) {
throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, moveToPath));
}
break;
} else {
break;
}
}
}
}
return res;
}
/**
* Save the classpath in a shareable format (VCM-wise) if necessary (i.e. semantically different)
*/
public void saveClasspath() throws JavaModelException {
this.saveClasspath(false);
}
/**
* Save the classpath in a shareable format (VCM-wise) if necessary (i.e. semantically different)
*/
public void saveClasspath(boolean force) throws JavaModelException {
if (!getProject().exists()) return;
if (!isOpen()) return; // no update for closed projects ???
QualifiedName classpathProp = getClasspathPropertyName();
try {
// attempt to prove the classpath has not change
String fileClasspathString = getSharedProperty(classpathProp);
if (fileClasspathString != null){
IClasspathEntry[] fileEntries = readPaths(fileClasspathString);
if (!force && isClasspathEqualsTo(fileEntries)) {
// no need to save it, it is already the same
return;
}
}
} catch (IOException e){
} catch (RuntimeException e){
} catch(CoreException e){
}
// actual file saving
try {
setSharedProperty(
classpathProp,
getClasspathAsXMLString(getRawClasspath(), getOutputLocation()));
} catch(CoreException e){
throw new JavaModelException(e);
}
}
/**
* 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;
}
SetOutputLocationOperation op= new SetOutputLocationOperation(this, outputLocation);
runOperation(op, monitor);
}
/**
* @private - for use by <code>SetOutputLocationOperation</code> only.<br>
* Set the path to the location where the builder writes .class files
*
* @exception JavaModelException if an error occurs setting the output location
* or if this project is not present
*/
protected void setOutputLocation0(IPath outputLocation) throws JavaModelException {
//getting the element info (if it is generated) has the side effect of setting the
//output location to that specified in the classpath file (or the default output location
//if none is specified in the classpath file).
JavaProjectElementInfo info= getJavaProjectElementInfo();
info.setOutputLocation(outputLocation);
}
/**
* 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.getJavaModel(project.getWorkspace());
fName= project.getName();
}
/**
* @see IJavaProject
*/
public void setRawClasspath(IClasspathEntry[] entries, IProgressMonitor monitor) throws JavaModelException {
setRawClasspath(entries, monitor, true, getResolvedClasspath(true));
}
/**
* @see IJavaProject
*/
public void setRawClasspath(IClasspathEntry[] entries, IProgressMonitor monitor, boolean saveClasspath) throws JavaModelException {
setRawClasspath(entries, monitor, saveClasspath, getResolvedClasspath(true));
}
/**
* @see IJavaProject
*/
public void setRawClasspath(IClasspathEntry[] newEntries, IProgressMonitor monitor, boolean saveClasspath, IClasspathEntry[] oldResolvedPath) throws JavaModelException {
JavaModelManager manager= (JavaModelManager) JavaModelManager.getJavaModelManager();
try {
IJavaModelStatus status= verifyClasspath(newEntries);
if (!status.isOK()) {
throw new JavaModelException(status);
}
JavaProjectElementInfo info = getJavaProjectElementInfo();
IClasspathEntry[] newRawPath = newEntries;
if (newRawPath == null) { //are we already with the default classpath
newRawPath = defaultClasspath();
}
SetClasspathOperation op= new SetClasspathOperation(this, oldResolvedPath, newRawPath, saveClasspath);
runOperation(op, monitor);
} catch (JavaModelException e) {
manager.flush();
throw e;
}
}
/**
* 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[] entries) throws JavaModelException {
JavaProjectElementInfo info= getJavaProjectElementInfo();
synchronized(info){
if (entries == null) {
entries= defaultClasspath();
}
// clear the existing children
info.setChildren(new IPackageFragmentRoot[] {});
info.setRawClasspath(entries);
IndexManager indexManager = ((JavaModelManager)JavaModelManager.getJavaModelManager()).getIndexManager();
// determine the new children
for (int i= 0; i < entries.length; i++) {
IClasspathEntry entry= entries[i];
IPackageFragmentRoot[] roots= getPackageFragmentRoots(entry);
for (int j= 0; j < roots.length; j++) {
PackageFragmentRoot root= (PackageFragmentRoot)roots[j];
if (root.exists0()){
if (root.isArchive()){
if (indexManager != null) indexManager.indexJarFile(root.getPath(), getUnderlyingResource().getName());
}
info.addChild(roots[j]);
}
}
}
// flush namelookup (holds onto caches)
info.setNameLookup(null);
// See PR 1G8BFWS: ITPJUI:WINNT - internal jar appearing twice in packages view
resetNonJavaResourcesForPackageFragmentRoots();
((JavaProjectElementInfo) getElementInfo()).setNonJavaResources(null);
}
}
/**
* 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(...)
*/
public void setSharedProperty(QualifiedName key, String value) throws CoreException {
IProject project = getProject();
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);
}
}
public void updateClassPath() throws JavaModelException {
setRawClasspath(getRawClasspath(), null, false);
}
/**
* Possible failures: <ul>
* <li>NAME_COLLISION - two entries specify the same path.
* <li>INVALID_PATH - a CPE_PROJECT entry has been specified referring to this project
* </ul>
*/
protected IJavaModelStatus verifyClasspath(IClasspathEntry[] classpath) {
if (classpath != null) {
int entryCount= classpath.length;
for (int i= 0; i < entryCount; i++) {
IClasspathEntry entry= classpath[i];
inner : for (int j= 0; j < entryCount; j++) {
if (i == j) {
continue inner;
}
if (JavaConventions.isOverlappingRoots(entry.getPath(), classpath[j].getPath())) {
return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION);
}
}
if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT && entry.getPath().equals(getProject().getFullPath())) {
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH);
}
}
}
return JavaModelStatus.VERIFIED_OK;
}
/**
* Record a new marker denoting a classpath problem for a given entry
*/
private void createClasspathProblemMarker(IClasspathEntry entry, String message){
try {
IMarker marker = getProject().createMarker(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER);
marker.setAttributes(
new String[]{ IMarker.MESSAGE, IMarker.SEVERITY, IMarker.LOCATION},
new Object[]{message, new Integer(IMarker.SEVERITY_WARNING), Util.bind("classpath.buildPath")}); //$NON-NLS-1$
} catch (CoreException e) {
}
}
/**
* Remove all markers denoting classpath problems
*/
protected void flushClasspathProblemMarkers(){
try {
IProject project = getProject();
if (project.exists()){
project.deleteMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ONE);
}
} catch (CoreException e) {
}
}
/**
* Internal variant which can create marker on project for invalid entries
*/
public IClasspathEntry[] getResolvedClasspath(boolean ignoreUnresolvedVariable, boolean generateMarkerOnError) throws JavaModelException {
IClasspathEntry[] classpath = getRawClasspath();
IClasspathEntry[] resolvedPath = classpath; // clone only if necessary
int length = classpath.length;
int index = 0;
for (int i = 0; i < length; i++){
IClasspathEntry entry = classpath[i];
/* validation if needed */
if (generateMarkerOnError){
IJavaModelStatus status = JavaConventions.validateClasspathEntry(this, entry, false);
if (!status.isOK()) createClasspathProblemMarker(entry, status.getMessage());
}
/* resolve variables if any, unresolved ones are ignored */
if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE){
// clone original path
if (resolvedPath == classpath){
System.arraycopy(classpath, 0, resolvedPath = new IClasspathEntry[length], 0, i);
}
// resolve current variable (handling variable->variable->variable->entry
IPath variablePath = entry.getPath(); // for error reporting
entry = JavaCore.getResolvedClasspathEntry(entry);
if (entry == null){
if (!ignoreUnresolvedVariable){
throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.CP_VARIABLE_PATH_UNBOUND, variablePath.toString()));
}
}
}
if (entry != null){
resolvedPath[index++] = entry;
}
}
// resize resolved classpath in case some variable entries could not be resolved
if (index != length){
System.arraycopy(resolvedPath, 0, resolvedPath = new IClasspathEntry[index], 0, index);
}
return resolvedPath;
}
}