| /******************************************************************************* |
| * Copyright (c) 2004, 2011 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.core.IAntCoreConstants; |
| 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() + IAntCoreConstants.EMPTY_STRING, |
| 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 = IAntCoreConstants.EMPTY_STRING; |
| 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, IAntCoreConstants.EMPTY_STRING); |
| } |
| 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; |
| } |
| |
| } |
| } |