blob: 8de43fc3714f6fcf0f6cbf0cf795ce076a9702a0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2008 Richard Hoefter and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Richard Hoefter (richard.hoefter@web.de) - initial API and implementation, bug 95298, bug 192726, bug 201180
* IBM Corporation - nlsing and incorporating into Eclipse, bug 108276
*******************************************************************************/
package org.eclipse.ant.internal.ui.datatransfer;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.ant.internal.ui.AntUIPlugin;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.launching.IRuntimeClasspathEntry;
import org.eclipse.jdt.launching.JavaRuntime;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Class to inspect classpath of an Eclipse project.
*/
public class EclipseClasspath
{
protected List srcDirs = new ArrayList();
protected List classDirs = new ArrayList();
protected List inclusionLists = new ArrayList();
protected List exclusionLists = new ArrayList();
protected Map variable2valueMap = new LinkedHashMap();
protected List rawClassPathEntries = new ArrayList();
protected List rawClassPathEntriesAbsolute = new ArrayList();
private IJavaProject project;
private static Map userLibraryCache = new HashMap();
/**
* Initialize object with classpath of given project.
*/
public EclipseClasspath(IJavaProject project) throws JavaModelException
{
this.project = project;
handle(project.getRawClasspath());
}
/**
* Initialize object with runtime classpath of given launch configuration.
* @param project project that contains given launch configuration conf
* @param conf launch configuration
* @param bootstrap if true only bootstrap entries are added, if false only
* non-bootstrap entries are added
*/
public EclipseClasspath(IJavaProject project, ILaunchConfiguration conf, boolean bootstrap)
throws CoreException
{
this.project = project;
// convert IRuntimeClasspathEntry to IClasspathEntry
IRuntimeClasspathEntry[] runtimeEntries;
// see AbstractJavaLaunchConfigurationDelegate
runtimeEntries = JavaRuntime.computeUnresolvedRuntimeClasspath(conf);
List classpathEntries = new ArrayList(runtimeEntries.length);
for (int i = 0; i < runtimeEntries.length; i++)
{
IRuntimeClasspathEntry entry = runtimeEntries[i];
if ( bootstrap && (entry.getClasspathProperty() == IRuntimeClasspathEntry.BOOTSTRAP_CLASSES) ||
! bootstrap && (entry.getClasspathProperty() != IRuntimeClasspathEntry.BOOTSTRAP_CLASSES))
{
// NOTE: See AbstractJavaLaunchConfigurationDelegate.getBootpathExt()
// for an alternate bootclasspath detection
if (entry.getClass().getName().equals("org.eclipse.jdt.internal.launching.VariableClasspathEntry")) //$NON-NLS-1$
{
IClasspathEntry e = convertVariableClasspathEntry(entry);
if (e != null)
{
classpathEntries.add(e);
}
}
else if (entry.getClass().getName().equals("org.eclipse.jdt.internal.launching.DefaultProjectClasspathEntry")) //$NON-NLS-1$
{
IClasspathEntry e = JavaCore.newProjectEntry(entry.getPath());
classpathEntries.add(e);
}
else if (entry.getClasspathEntry() != null)
{
classpathEntries.add(entry.getClasspathEntry());
}
}
else if (bootstrap && entry.toString().startsWith(JavaRuntime.JRE_CONTAINER))
{
classpathEntries.add(entry.getClasspathEntry());
}
else if (bootstrap && entry.toString().startsWith(JavaCore.USER_LIBRARY_CONTAINER_ID))
{
classpathEntries.add(entry.getClasspathEntry());
}
}
IClasspathEntry[] entries =
(IClasspathEntry[]) classpathEntries.toArray(new IClasspathEntry[classpathEntries.size()]);
handle(entries);
}
private void handle(IClasspathEntry[] entries) throws JavaModelException
{
for (int i = 0; i < entries.length; i++)
{
handleSources(entries[i]);
handleVariables(entries[i]);
handleJars(entries[i]);
handleLibraries(entries[i]);
handleProjects(entries[i]);
}
}
private void handleSources(IClasspathEntry entry) throws JavaModelException
{
String projectRoot = ExportUtil.getProjectRoot(project);
String defaultClassDir = project.getOutputLocation().toString();
String defaultClassDirAbsolute = ExportUtil.resolve(project.getOutputLocation());
if (entry.getContentKind() == IPackageFragmentRoot.K_SOURCE &&
entry.getEntryKind() == IClasspathEntry.CPE_SOURCE)
{
// found source path
IPath srcDirPath = entry.getPath();
IPath classDirPath = entry.getOutputLocation();
String srcDir = handleLinkedResource(srcDirPath);
ExportUtil.removeProjectRoot((srcDirPath != null) ? srcDirPath.toString() : projectRoot, project.getProject());
String classDir = ExportUtil.removeProjectRoot((classDirPath != null) ? classDirPath.toString() : defaultClassDir, project.getProject());
srcDirs.add(srcDir);
classDirs.add(classDir);
String classDirAbsolute = (classDirPath != null) ? ExportUtil.resolve(classDirPath) : defaultClassDirAbsolute;
rawClassPathEntries.add(classDir);
rawClassPathEntriesAbsolute.add(classDirAbsolute);
IPath[] inclusions = entry.getInclusionPatterns();
List inclusionList = new ArrayList();
for (int j = 0; j < inclusions.length; j++)
{
if (inclusions[j] != null)
{
inclusionList.add(ExportUtil.removeProjectRoot(inclusions[j].toString(), project.getProject()));
}
}
inclusionLists.add(inclusionList);
IPath[] exclusions = entry.getExclusionPatterns();
List exclusionList = new ArrayList();
for (int j = 0; j < exclusions.length; j++)
{
if (exclusions[j] != null)
{
exclusionList.add(ExportUtil.removeProjectRoot(exclusions[j].toString(), project.getProject()));
}
}
exclusionLists.add(exclusionList);
}
}
/**
* Check if given source path is a linked resource. Add values to
* {@link #variable2valueMap} accordingly.
* @param srcDirPath source dir as IPath
* @return source directory with reference, e.g. ${MYPATH}/src, if it is no
* link, orginal source dir is returned
*/
private String handleLinkedResource(IPath srcDirPath)
{
String projectRoot = ExportUtil.getProjectRoot(project);
String srcDir = ExportUtil.removeProjectRoot((srcDirPath != null) ? srcDirPath.toString() : projectRoot, project.getProject());
if (srcDirPath == null)
{
return srcDir;
}
IFile file;
try
{
file = ResourcesPlugin.getWorkspace().getRoot().getFile(srcDirPath);
}
catch (IllegalArgumentException e)
{
return srcDir;
}
if (file.isLinked())
{
String pathVariable = file.getRawLocation().segment(0).toString();
IPath pathVariableValue = file.getWorkspace().getPathVariableManager().getValue(pathVariable);
if (pathVariableValue != null)
{
// path variable was used
String pathVariableExtension = file.getRawLocation().removeFirstSegments(1).toString(); // Bug 192726
String relativePath = ExportUtil.getRelativePath(pathVariableValue.toString(),
projectRoot);
variable2valueMap.put(pathVariable + ".pathvariable", relativePath); //$NON-NLS-1$
variable2valueMap.put(srcDir + ".link", //$NON-NLS-1$
"${" + pathVariable + ".pathvariable}/" + pathVariableExtension); //$NON-NLS-1$ //$NON-NLS-2$
}
else
{
String relativePath = ExportUtil.getRelativePath(file.getLocation() + "", //$NON-NLS-1$
projectRoot);
variable2valueMap.put(srcDir + ".link", relativePath); //$NON-NLS-1$
}
srcDir = "${" + srcDir + ".link}"; //$NON-NLS-1$ //$NON-NLS-2$
}
return srcDir;
}
private void handleJars(IClasspathEntry entry)
{
if (entry.getContentKind() == IPackageFragmentRoot.K_BINARY &&
entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY)
{
String jarFile = entry.getPath().toString();
StringBuffer jarFileBuffer = new StringBuffer();
StringBuffer jarFileAbsoluteBuffer = new StringBuffer();
String jarFileAbsolute = ExportUtil.resolve(entry.getPath());
if (jarFileAbsolute == null)
{
jarFileAbsolute = jarFile; // jarFile was already absolute
if (handleSubProjectClassesDirectory(jarFile, jarFileBuffer, jarFileAbsoluteBuffer))
{
jarFile = jarFileBuffer.toString();
jarFileAbsolute = jarFileAbsoluteBuffer.toString();
}
}
String jarFileOld = jarFile;
jarFile = ExportUtil.removeProjectRoot(jarFile, project.getProject());
if (jarFile.equals(jarFileOld))
{
if (handleSubProjectClassesDirectory(jarFile, jarFileBuffer, jarFileAbsoluteBuffer))
{
jarFile = jarFileBuffer.toString();
jarFileAbsolute = jarFileAbsoluteBuffer.toString();
}
}
rawClassPathEntries.add(jarFile);
rawClassPathEntriesAbsolute.add(jarFileAbsolute);
}
}
/**
* Checks if file is a class directory of a subproject and fills string buffers with resolved values.
* @param file file to check
* @param jarFile filled with file location with variable reference ${project.location},
* which is also added to variable2valueMap
* @param jarFileAbsolute filled with absolute file location
* @return true if file is a classes directory
*/
private boolean handleSubProjectClassesDirectory(String file, StringBuffer jarFile, StringBuffer jarFileAbsolute)
{
// class directory of a subproject?
if (file != null && file.indexOf('/') == 0)
{
int i = file.indexOf('/', 1);
i = (i != -1) ? i : file.length();
String subproject = file.substring(1, i);
IJavaProject javaproject = ExportUtil.getJavaProjectByName(subproject);
if (javaproject != null)
{
jarFile.setLength(0);
jarFileAbsolute.setLength(0);
String location = javaproject.getProject().getName() + ".location"; //$NON-NLS-1$
jarFileAbsolute.append(ExportUtil.replaceProjectRoot(file, javaproject.getProject(), ExportUtil.getProjectRoot(javaproject)));
jarFile.append(ExportUtil.replaceProjectRoot(file, javaproject.getProject(), "${" + location + "}")); //$NON-NLS-1$ //$NON-NLS-2$
String projectRoot= ExportUtil.getProjectRoot(project);
String relativePath = ExportUtil.getRelativePath(ExportUtil.getProjectRoot(javaproject),
projectRoot);
variable2valueMap.put(location, relativePath);
return true;
}
}
return false;
}
private void handleVariables(IClasspathEntry entry)
{
if (entry.getContentKind() == IPackageFragmentRoot.K_SOURCE &&
entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE)
{
// found variable
String e = entry.getPath().toString();
int index = e.indexOf('/');
if (index == -1)
{
index = e.indexOf('\\');
}
String variable = e;
String path = ""; //$NON-NLS-1$
if (index != -1)
{
variable = e.substring(0, index);
path = e.substring(index);
}
IPath value = JavaCore.getClasspathVariable(variable);
if (value != null)
{
String projectRoot = ExportUtil.getProjectRoot(project);
String relativePath = ExportUtil.getRelativePath(value.toString(),
projectRoot);
variable2valueMap.put(variable, relativePath);
}
else if (variable2valueMap.get(variable) == null)
{
// only add empty value, if variable is new
variable2valueMap.put(variable, ""); //$NON-NLS-1$
}
rawClassPathEntriesAbsolute.add(value + path);
rawClassPathEntries.add("${" + variable + "}" + path); //$NON-NLS-1$ //$NON-NLS-2$
}
}
private void handleLibraries(IClasspathEntry entry) throws JavaModelException
{
if (entry.getContentKind() == IPackageFragmentRoot.K_SOURCE &&
entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER)
{
// found library
IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), project);
if (container == null) {
// jar missing (project not compile clean)
return;
}
String jar = entry.getPath().toString();
String refName;
if (jar.startsWith(JavaRuntime.JRE_CONTAINER))
{
// JRE System Library
refName = "${jre.container}"; //$NON-NLS-1$
}
else if (jar.startsWith(JavaCore.USER_LIBRARY_CONTAINER_ID))
{
// User Library
String libraryName = container.getDescription();
refName = "${" + libraryName + ".userclasspath}"; //$NON-NLS-1$ //$NON-NLS-2$
if (container.getKind() == IClasspathContainer.K_SYSTEM)
{
refName = "${" + libraryName + ".bootclasspath}"; //$NON-NLS-1$ //$NON-NLS-2$
}
}
else
{
// Library dependencies: e.g. Plug-in Dependencies
String libraryName = container.getDescription();
refName = "${" + libraryName + ".libraryclasspath}"; //$NON-NLS-1$ //$NON-NLS-2$
}
userLibraryCache.put(refName, container);
srcDirs.add(refName);
classDirs.add(refName);
rawClassPathEntries.add(refName);
rawClassPathEntriesAbsolute.add(refName);
inclusionLists.add(new ArrayList());
exclusionLists.add(new ArrayList());
}
}
private void handleProjects(IClasspathEntry entry)
{
if (entry.getContentKind() == IPackageFragmentRoot.K_SOURCE &&
entry.getEntryKind() == IClasspathEntry.CPE_PROJECT)
{
// found required project on build path
String subProjectRoot = entry.getPath().toString();
IJavaProject subProject = ExportUtil.getJavaProject(subProjectRoot);
if (subProject == null)
{
// project was not loaded in workspace
AntUIPlugin.log("project is not loaded in workspace: " + subProjectRoot, null); //$NON-NLS-1$
return;
}
// only add an indicator that this is a project reference
String classpathRef = "${" + subProject.getProject().getName() + ".classpath}"; //$NON-NLS-1$ //$NON-NLS-2$
srcDirs.add(classpathRef);
classDirs.add(classpathRef);
rawClassPathEntries.add(classpathRef);
rawClassPathEntriesAbsolute.add(classpathRef);
inclusionLists.add(new ArrayList());
exclusionLists.add(new ArrayList());
}
}
/**
* Get runtime classpath items for given project separated with path separator.
*/
public static String getClasspath(IJavaProject project) throws CoreException
{
List items = getClasspathList(project);
return ExportUtil.toString(items, File.pathSeparator);
}
/**
* Get runtime classpath items for given project.
*/
public static List getClasspathList(IJavaProject project) throws CoreException
{
String[] classpath = JavaRuntime.computeDefaultRuntimeClassPath(project);
return Arrays.asList(classpath);
}
/**
* Check if given string is a reference.
*/
public static boolean isReference(String s)
{
return isProjectReference(s) || isUserLibraryReference(s) ||
isUserSystemLibraryReference(s) || isLibraryReference(s) ||
isJreReference(s);
// NOTE: A linked resource is no reference
}
/**
* Check if given string is a project reference.
*/
public static boolean isProjectReference(String s)
{
return s.startsWith("${") && s.endsWith(".classpath}"); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Resolves given project reference to a project.
* @return <code>null</code> if project is not resolvable
*/
public static IJavaProject resolveProjectReference(String s)
{
String name = ExportUtil.removePrefixAndSuffix(s, "${", ".classpath}"); //$NON-NLS-1$ //$NON-NLS-2$
return ExportUtil.getJavaProjectByName(name);
}
/**
* Check if given string is a user library reference.
*/
public static boolean isUserLibraryReference(String s)
{
return s.startsWith("${") && s.endsWith(".userclasspath}"); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Check if given string is a user system library reference.
* This library is added to the compiler boot classpath.
*/
public static boolean isUserSystemLibraryReference(String s)
{
return s.startsWith("${") && s.endsWith(".bootclasspath}"); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Check if given string is a library reference. e.g. Plug-in dependencies
* are library references.
*
*/
public static boolean isLibraryReference(String s)
{
return s.startsWith("${") && s.endsWith(".libraryclasspath}"); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Check if given string is a JRE reference.
*/
public static boolean isJreReference(String s)
{
return s.equals("${jre.container}"); //$NON-NLS-1$
}
/**
* Resolves given user (system) library or plugin reference to its container.
*
* <p>NOTE: The library can only be resolved if an EclipseClasspath object
* was created which had a reference to this library. The class holds an
* internal cache to circumvent that UserLibraryManager is an internal
* class.
*
* @return null if library is not resolvable
*/
public static IClasspathContainer resolveUserLibraryReference(String s)
{
return (IClasspathContainer) userLibraryCache.get(s);
}
/**
* Check if given string is a linked resource.
*
*/
public static boolean isLinkedResource(String s)
{
return s.startsWith("${") && s.endsWith(".link}"); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Get source folder name of a linked resource.
*
* @see #isLinkedResource(String)
*/
public static String getLinkedResourceName(String s)
{
return ExportUtil.removePrefixAndSuffix(s, "${", ".link}"); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Resolves given linked resource to an absolute file location.
*/
public String resolveLinkedResource(String s)
{
String name = ExportUtil.removePrefixAndSuffix(s, "${", "}"); //$NON-NLS-1$ //$NON-NLS-2$
String value = (String) variable2valueMap.get(name);
String suffix = ".pathvariable}"; //$NON-NLS-1$
int i = value.indexOf(suffix);
if (i != -1)
{
// path variable
String pathVariable = value.substring(0, i + suffix.length() - 1);
pathVariable = ExportUtil.removePrefix(pathVariable, "${"); //$NON-NLS-1$
return (String) variable2valueMap.get(pathVariable) + value.substring(i + suffix.length());
}
return value;
}
/**
* Convert a VariableClasspathEntry to a IClasspathEntry.
*
* <p>This is a workaround as entry.getClasspathEntry() returns null.
*/
private IClasspathEntry convertVariableClasspathEntry(IRuntimeClasspathEntry entry)
{
try
{
Document doc = ExportUtil.parseXmlString(entry.getMemento());
Element element = (Element) doc.getElementsByTagName("memento").item(0); //$NON-NLS-1$
String variableString = element.getAttribute("variableString"); //$NON-NLS-1$
ExportUtil.addVariable(variable2valueMap, variableString, ExportUtil.getProjectRoot(project));
// remove ${...} from string to be conform for handleVariables()
variableString = ExportUtil.removePrefix(variableString, "${");//$NON-NLS-1$
int i = variableString.indexOf('}');
if (i != -1)
{
variableString = variableString.substring(0, i)
+ variableString.substring(i + 1);
}
IPath path = new Path(variableString);
return JavaCore.newVariableEntry(path, null, null);
}
catch (Exception e)
{
AntUIPlugin.log(e);
return null;
}
}
}