blob: 6de3a07f0edcc93e9306e9107f33525b8c0d09e6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2005 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
* IBM Corporation - nlsing and incorporating into Eclipse
*******************************************************************************/
package org.eclipse.ant.internal.ui.datatransfer;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.eclipse.ant.internal.ui.AntUIPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
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.IVMInstall;
import org.eclipse.jdt.launching.JavaRuntime;
/**
* Class to store classpath settings of an Eclipse project.
*
* <p>NOTE: The constructed classpath does not contain items of the subprojects.
* Instead create an object of this class for each project returned by
* {@link eclipse2ant.util.EclipseUtil#getClasspathProjectsRecursive(IJavaProject)}.
*/
public class EclipseClasspath
{
public List srcDirs = new ArrayList();
public List classDirs = new ArrayList();
public List inclusionLists = new ArrayList();
public List exclusionLists = new ArrayList();
public Map class2sourcesMap = new TreeMap();
public Map class2includesMap = new TreeMap();
public Map class2excludesMap = new TreeMap();
public Map variable2valueMap = new TreeMap();
public List rawClassPathEntries = new ArrayList();
public List rawClassPathEntriesAbsolute = new ArrayList();
private IJavaProject project;
private String newProjectRoot;
private String jreLocation;
public EclipseClasspath(IJavaProject project) throws JavaModelException
{
this(project, null);
}
/**
* @param newProjectRoot replace project root, e.g. with a variable ${project.location}
*/
public EclipseClasspath(IJavaProject project, String newProjectRoot) throws JavaModelException
{
this.project = project;
jreLocation = getJRELocation();
this.newProjectRoot = newProjectRoot;
IClasspathEntry entries[] = project.getRawClasspath();
for (int i = 0; i < entries.length; i++)
{
handleSources(entries[i]);
handleVariables(entries[i]);
handleJars(entries[i]);
handleUserLibraries(entries[i]);
}
addClasses();
initClassMaps();
}
private String getJRELocation() {
try {
IVMInstall install= JavaRuntime.getVMInstall(project);
if (install != null) {
File installLocation= install.getInstallLocation();
if (installLocation != null) {
return new Path(installLocation.toString()).toString();
}
}
} catch (CoreException e) {
AntUIPlugin.log(e);
}
return ""; //$NON-NLS-1$
}
/**
* Get class directories without duplicates.
*/
public List getClassDirsUnique()
{
return removeDuplicates(classDirs);
}
private void handleSources(IClasspathEntry entry) throws JavaModelException
{
String projectRoot = ExportUtil.getProjectRoot(project);
String defaultClassDir = project.getOutputLocation().toString();
if (entry.getContentKind() == IPackageFragmentRoot.K_SOURCE &&
entry.getEntryKind() == IClasspathEntry.CPE_SOURCE)
{
// found source path
IPath srcDirPath = entry.getPath();
IPath classDirPath = entry.getOutputLocation();
String srcDir = 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);
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);
}
}
/**
* Convert sources/classes directories and inclusion/exclusion filters to map representation.
* As several source directories may compile to same class directory this is a useful conversion
* of the result of {@link #handleSources}.
*/
private void initClassMaps()
{
for (int i = 0; i < srcDirs.size(); i++)
{
String srcDir = (String) srcDirs.get(i);
String classDir = (String) classDirs.get(i);
List includeList = (List) inclusionLists.get(i);
List excludeList = (List) exclusionLists.get(i);
Set sources = (Set) class2sourcesMap.get(classDir);
if (sources == null)
{
sources = new TreeSet();
}
sources.add(srcDir);
class2sourcesMap.put(classDir, sources);
Set includes = (Set) class2includesMap.get(classDir);
if (includes == null)
{
includes = new TreeSet();
}
includes.addAll(includeList);
class2includesMap.put(classDir, includes);
Set excludes = (Set) class2excludesMap.get(classDir);
if (excludes == null)
{
excludes = new TreeSet();
}
excludes.addAll(excludeList);
class2excludesMap.put(classDir, excludes);
}
}
private void handleJars(IClasspathEntry entry)
{
if (entry.getContentKind() == IPackageFragmentRoot.K_BINARY &&
entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY)
{
String jarFile = entry.getPath().toString();
// ignore JRE libraries
if (jarFile.startsWith(jreLocation))
{
return;
}
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;
if (newProjectRoot == null)
{
jarFile = ExportUtil.removeProjectRoot(jarFile, project.getProject());
}
else
{
jarFile = ExportUtil.replaceProjectRoot(jarFile, project.getProject(), newProjectRoot);
}
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 varibale 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); //$NON-NLS-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$
variable2valueMap.put(location, ExportUtil.getProjectRoot(javaproject));
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);
}
String value = JavaCore.getClasspathVariable(variable).toString();
variable2valueMap.put(variable, value);
rawClassPathEntriesAbsolute.add(value + path);
rawClassPathEntries.add("${" + variable + "}" + path); //$NON-NLS-1$ //$NON-NLS-2$
}
}
private void handleUserLibraries(IClasspathEntry entry) throws JavaModelException
{
if (entry.getContentKind() == IPackageFragmentRoot.K_SOURCE &&
entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER)
{
// found (user) library
// String e = entry.getPath().toString(); // org.eclipse.jdt.USER_LIBRARY/MyLib
//JavaCore.USER_LIBRARY_CONTAINER_ID
IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), project);
IClasspathEntry entries[] = container.getClasspathEntries();
for (int i = 0; i < entries.length; i++)
{
handleJars(entries[i]);
}
}
}
/**
* Add classDirs in front of classpath.
*/
private void addClasses()
{
for (Iterator iter = classDirs.iterator(); iter.hasNext();)
{
String classDir = (String) iter.next();
if (newProjectRoot != null)
{
classDir = newProjectRoot + '/' + classDir;
}
rawClassPathEntries.add(0, classDir);
rawClassPathEntriesAbsolute.add(0, classDir);
}
}
/**
* Get classpath for given project.
*/
public static String getClasspath(IJavaProject project) throws JavaModelException
{
List items = EclipseClasspath.getClasspathList(project);
return toString(items, File.pathSeparator);
}
/**
* Get classpath for given project.
*/
public static String getClasspath(IJavaProject project, boolean includeSubProjects) throws JavaModelException
{
List items = EclipseClasspath.getClasspathList(project, includeSubProjects);
return toString(items, File.pathSeparator);
}
/**
* Get classpath for given project.
*/
public static List getClasspathList(IJavaProject project) throws JavaModelException
{
EclipseClasspath instance = new EclipseClasspath(project, ExportUtil.getProjectRoot(project));
return instance.removeDuplicates(instance.rawClassPathEntriesAbsolute);
}
/**
* Get classpath for given project.
*/
public static List getClasspathList(IJavaProject project, boolean includeSubProjects) throws JavaModelException
{
EclipseClasspath instance = new EclipseClasspath(project, ExportUtil.getProjectRoot(project));
List classpath = instance.rawClassPathEntriesAbsolute;
if (!includeSubProjects)
{
return instance.removeDuplicates(classpath);
}
Set subprojects = ExportUtil.getClasspathProjectsRecursive(project);
for (Iterator iter = subprojects.iterator(); iter.hasNext();)
{
IJavaProject subproject = (IJavaProject) iter.next();
instance = new EclipseClasspath(subproject, ExportUtil.getProjectRoot(subproject));
classpath.addAll(instance.rawClassPathEntriesAbsolute);
}
return instance.removeDuplicates(classpath);
}
public static String toString(Collection c, String separator)
{
StringBuffer b = new StringBuffer();
for (Iterator iter = c.iterator(); iter.hasNext();)
{
b.append((String) iter.next());
b.append(separator);
}
if (c.size() > 0) {
b.delete(b.length() - separator.length(), b.length());
}
return b.toString();
}
/**
* Remove duplicates preserving original order.
* @param l list to remove duplicates from
* @return new list without duplicates
*/
protected List removeDuplicates(List l)
{
List res = new ArrayList();
for (Iterator iter = l.iterator(); iter.hasNext();)
{
Object element = iter.next();
if (!res.contains(element))
{
res.add(element);
}
}
return res;
}
}