/**********************************************************************
* Copyright (c) 2005-2009 ant4eclipse project team.
*
* 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:
* Nils Hartmann, Daniel Kasmeroglu, Gerd Wuetherich
**********************************************************************/
package org.ant4eclipse.ant.jdt;
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.ant4eclipse.ant.platform.core.MacroExecutionValues;
import org.ant4eclipse.ant.platform.core.ScopedMacroDefinition;
import org.ant4eclipse.ant.platform.core.delegate.ConditionalMacroDef;
import org.ant4eclipse.ant.platform.core.delegate.MacroExecutionValuesProvider;
import org.ant4eclipse.lib.core.Assure;
import org.ant4eclipse.lib.core.util.StringMap;
import org.ant4eclipse.lib.core.util.Utilities;
import org.ant4eclipse.lib.jdt.model.project.JavaProjectRole;
import org.ant4eclipse.lib.jdt.tools.JdtResolver;
import org.ant4eclipse.lib.jdt.tools.ResolvedClasspath;
import org.ant4eclipse.lib.platform.model.resource.EclipseProject;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.taskdefs.MacroDef;
import org.apache.tools.ant.types.FileSet;
/**
* <p>
* </p>
*
* @author Gerd Wütherich (gerd@gerd-wuetherich.de)
*/
public class ExecuteJdtProjectTask extends AbstractExecuteJdtProjectTask implements JdtExecutorValues {
/** the constant for SCOPE_PROJECT_ELEMENT_NAME */
private static final String SCOPE_PROJECT_ELEMENT_NAME = "ForProject";
/** the constant for SCOPE_TARGET_DIRECTORY_ELEMENT_NAME */
private static final String SCOPE_TARGET_DIRECTORY_ELEMENT_NAME = "ForEachOutputDirectory";
/** the constant for SCOPE_SOURCE_DIRECTORY_ELEMENT_NAME */
private static final String SCOPE_SOURCE_DIRECTORY_ELEMENT_NAME = "ForEachSourceDirectory";
private static final String SCOPE_FOR_EACH_RUNTIME_CLASSPATH_ELEMENT_NAME = "ForEachRuntimeClasspathEntry";
/** the constant for SCOPE_SOURCE_DIRECTORY */
public static final String SCOPE_SOURCE_DIRECTORY = "SCOPE_SOURCE_DIRECTORY";
/** the constant for SCOPE_TARGET_DIRECTORY */
public static final String SCOPE_TARGET_DIRECTORY = "SCOPE_TARGET_DIRECTORY";
/** the constant for SCOPE_PROJECT */
public static final String SCOPE_PROJECT = "SCOPE_PROJECT";
public static final String SCOPE_FOR_EACH_RUNTIME_CLASSPATH = "SCOPE_FOR_EACH_RUNTIME_CLASSPATH";
/** - */
public static final String CLASSPATH_ABSOLUTE_COMPILETIME = "absolute.compiletime";
/** - */
public static final String CLASSPATH_ABSOLUTE_RUNTIME = "absolute.runtime";
/** - */
public static final String CLASSPATH_RELATIVE_COMPILETIME = "relative.compiletime";
/** - */
public static final String CLASSPATH_RELATIVE_RUNTIME = "relative.runtime";
/** - */
private static final Set<String> CLASSPATH_POSSIBLE_VALUES = Collections
.unmodifiableSet(new HashSet<String>(
Arrays
.asList(
CLASSPATH_ABSOLUTE_COMPILETIME,
CLASSPATH_ABSOLUTE_RUNTIME,
CLASSPATH_RELATIVE_COMPILETIME,
CLASSPATH_RELATIVE_RUNTIME)));
/** - */
private Set<String> _resolvedClassPaths = CLASSPATH_POSSIBLE_VALUES;
/**
* <p>
* Creates a new instance of type {@link ExecuteJdtProjectTask}.
* </p>
*/
public ExecuteJdtProjectTask() {
super("executeJdtProject");
}
/**
* <p>
* Creates a new instance of type {@link ExecuteJdtProjectTask}.
* </p>
*
* @param prefix
* the prefix
*/
protected ExecuteJdtProjectTask(String prefix) {
super(prefix);
}
/**
* @param resolvedClassPaths
*/
public void setResolvedClassPaths(String resolvedClassPaths) {
//
this._resolvedClassPaths = new HashSet<String>();
//
if (resolvedClassPaths == null) {
return;
}
//
String[] paths = resolvedClassPaths.split(",");
//
for (String path : paths) {
String trimmedPath = path.trim().toLowerCase();
// Make sure argument is valid
if (!CLASSPATH_POSSIBLE_VALUES.contains(trimmedPath)) {
throw new BuildException(String.format(
"Invalid value for Parameter 'resolvedClassPaths' specified: '%s'. Allowed values are: '%s'", path,
CLASSPATH_POSSIBLE_VALUES));
}
// add value
this._resolvedClassPaths.add(trimmedPath);
}
}
/**
* {@inheritDoc}
*/
public final Object createDynamicElement(String name) throws BuildException {
// handle SCOPE_SOURCE_DIRECTORY
if (SCOPE_SOURCE_DIRECTORY_ELEMENT_NAME.equalsIgnoreCase(name)) {
return createScopedMacroDefinition(SCOPE_SOURCE_DIRECTORY);
}
// handle SCOPE_TARGET_DIRECTORY
else if (SCOPE_TARGET_DIRECTORY_ELEMENT_NAME.equalsIgnoreCase(name)) {
return createScopedMacroDefinition(SCOPE_TARGET_DIRECTORY);
}
// handle SCOPE_PROJECT
else if (SCOPE_PROJECT_ELEMENT_NAME.equalsIgnoreCase(name)) {
return createScopedMacroDefinition(SCOPE_PROJECT);
}
// handle SCOPE_FOR_EACH_RUNTIME_CLASSPATH
else if (SCOPE_FOR_EACH_RUNTIME_CLASSPATH_ELEMENT_NAME.equalsIgnoreCase(name)) {
return createScopedMacroDefinition(SCOPE_FOR_EACH_RUNTIME_CLASSPATH);
}
// delegate to template method
return onCreateDynamicElement(name);
}
/**
* <p>
* Override this method to provide support for additional sub-elements defined in an ant build file.
* </p>
*
* @param name
* the name of the sub element
* @return
*/
protected Object onCreateDynamicElement(String name) {
// default implementation returns null
return null;
}
/**
* <p>
* </p>
*
* @param scopedMacroDefinition
* @return
*/
protected boolean onExecuteScopeMacroDefintion(ScopedMacroDefinition<String> scopedMacroDefinition) {
// default implementation returns false
return false;
}
/**
* <p>
* </p>
*
* @param executionValues
*/
protected void addAdditionalExecutionValues(MacroExecutionValues executionValues) {
// adds additional execution values
}
/**
* {@inheritDoc}
*/
@Override
protected void doExecute() {
// check require fields
requireWorkspaceAndProjectNameSet();
// execute scoped macro definitions
for (ScopedMacroDefinition<String> scopedMacroDefinition : getScopedMacroDefinitions()) {
MacroDef macroDef = scopedMacroDefinition.getMacroDef();
// execute SCOPE_SOURCE_DIRECTORY
if (SCOPE_SOURCE_DIRECTORY.equals(scopedMacroDefinition.getScope())) {
executeSourceDirectoryScopedMacroDef(macroDef);
}
// execute SCOPE_TARGET_DIRECTORY
else if (SCOPE_TARGET_DIRECTORY.equals(scopedMacroDefinition.getScope())) {
executeOutputDirectoryScopedMacroDef(macroDef);
}
// execute SCOPE_PROJECT
else if (SCOPE_PROJECT.equals(scopedMacroDefinition.getScope())) {
executeProjectScopedMacroDef(macroDef);
}
// execute SCOPE_PROJECT
else if (SCOPE_FOR_EACH_RUNTIME_CLASSPATH.equals(scopedMacroDefinition.getScope())) {
executeForEachRuntimeClasspathScopedMacroDef(macroDef);
}
// delegate to template method
else {
if (!onExecuteScopeMacroDefintion(scopedMacroDefinition)) {
// TODO: NLS
throw new RuntimeException("Unknown Scope '" + scopedMacroDefinition.getScope() + "'");
}
}
}
}
/**
* @param macroDef
* @param javaProjectRole
* @param classpathes
*/
private void executeSourceDirectoryScopedMacroDef(MacroDef macroDef) {
for (final String sourceFolder : getJavaProjectRole().getSourceFolders()) {
// execute macro
executeMacroInstance(macroDef, new MacroExecutionValuesProvider() {
public MacroExecutionValues provideMacroExecutionValues(MacroExecutionValues values) {
getExecutorValuesProvider().provideExecutorValues(getJavaProjectRole(), getJdtClasspathContainerArguments(),
values, ExecuteJdtProjectTask.this._resolvedClassPaths);
// add source and output directory
values.getProperties().put(SOURCE_DIRECTORY_NAME, sourceFolder);
values.getProperties().put(SOURCE_DIRECTORY, convertToString(getEclipseProject().getChild(sourceFolder)));
values.getProperties().put(SOURCE_DIRECTORY_INCLUDES,
getJavaProjectRole().getIncludePatternsForSourceFolder(sourceFolder));
values.getProperties().put(SOURCE_DIRECTORY_EXCLUDES,
getJavaProjectRole().getExcludePatternsForSourceFolder(sourceFolder));
values.getProperties().put(OUTPUT_DIRECTORY_NAME, sourceFolder);
values.getProperties().put(
OUTPUT_DIRECTORY,
convertToString(getEclipseProject().getChild(
getJavaProjectRole().getOutputFolderForSourceFolder(sourceFolder))));
// refs
values.getReferences().put(SOURCE_DIRECTORY_PATH, convertToPath(getEclipseProject().getChild(sourceFolder)));
values.getReferences().put(
OUTPUT_DIRECTORY_PATH,
convertToPath(getEclipseProject().getChild(
getJavaProjectRole().getOutputFolderForSourceFolder(sourceFolder))));
// add additional execution values if necessary
addAdditionalExecutionValues(values);
// return the values
return values;
}
});
}
}
/**
* <p>
* </p>
*
* @param macroDef
*/
private void executeOutputDirectoryScopedMacroDef(MacroDef macroDef) {
// iterate over all output folders
for (final String outFolder : getJavaProjectRole().getAllOutputFolders()) {
// execute macro
executeMacroInstance(macroDef, new MacroExecutionValuesProvider() {
public MacroExecutionValues provideMacroExecutionValues(MacroExecutionValues values) {
// get the default jdt executor values
getExecutorValuesProvider().provideExecutorValues(getJavaProjectRole(), getJdtClasspathContainerArguments(),
values, ExecuteJdtProjectTask.this._resolvedClassPaths);
// add output directory
values.getProperties().put(OUTPUT_DIRECTORY_NAME, outFolder);
values.getProperties().put(OUTPUT_DIRECTORY, convertToString(getEclipseProject().getChild(outFolder)));
values.getReferences().put(OUTPUT_DIRECTORY_PATH, convertToPath(getEclipseProject().getChild(outFolder)));
// call template method
addAdditionalExecutionValues(values);
// return the values
return values;
}
});
}
}
/**
* <p>
* Executed the given MacroDef for each (resolved) runtime classpath entry of the Eclipse project
* </p>
*
* @param macroDef
*/
private void executeForEachRuntimeClasspathScopedMacroDef(MacroDef macroDef) {
Assure.instanceOf("macroDef", macroDef, ConditionalMacroDef.class);
// Get the ConditionalMacroDef to access the macros attributes
ConditionalMacroDef conditionalMacroDef = (ConditionalMacroDef) macroDef;
// Read the 'reverse' attribute
final boolean reverse = Boolean.parseBoolean(conditionalMacroDef.getAttribute("reverse", "false"));
final JavaProjectRole javaProjectRole = getJavaProjectRole();
final EclipseProject project = javaProjectRole.getEclipseProject();
// Resolve the absolute and relative classpaths
ResolvedClasspath cpAbsoluteRuntime = JdtResolver.resolveProjectClasspath(project, false, true,
getJdtClasspathContainerArguments());
// ResolvedClasspath cpRelativeRuntime = JdtResolver.resolveProjectClasspath(javaProjectRole.getEclipseProject(),
// true, true, getJdtClasspathContainerArguments());
// get the entries
final File[] absoluteClasspathFiles = cpAbsoluteRuntime.getClasspathFiles();
// final File[] relativeClasspathFiles = cpRelativeRuntime.getClasspathFiles();
// // TODO NLS
// throw new RuntimeException("number of absolute classpath entries (" + absoluteClasspathFiles.length + ")"
// + "must match number of relative classpath entries (" + relativeClasspathFiles.length + ")");
// }
// reverse the classpath order if requested
if (reverse) {
Utilities.reverse(absoluteClasspathFiles);
// Utilities.reverse(relativeClasspathFiles);
}
// invoke callback template for each classpath entry
for (int i = 0; i < absoluteClasspathFiles.length; i++) {
final int index = i;
executeMacroInstance(macroDef, new MacroExecutionValuesProvider() {
public MacroExecutionValues provideMacroExecutionValues(MacroExecutionValues values) {
getExecutorValuesProvider().provideExecutorValues(getJavaProjectRole(), getJdtClasspathContainerArguments(),
values, ExecuteJdtProjectTask.this._resolvedClassPaths);
final StringMap properties = values.getProperties();
// add absolute path
properties.put("classpathEntry.absolute", absoluteClasspathFiles[index].getAbsolutePath());
// // add relative path
// properties.put("classpathEntry.relative", relativeClasspathFiles[index].getPath());
// add name (last part of the path)
properties.put("classpathEntry.name", absoluteClasspathFiles[index].getName());
// add informations about file system resource
properties.put("classpathEntry.isExisting", Boolean.toString(absoluteClasspathFiles[index].exists()));
properties.put("classpathEntry.isFile", Boolean.toString(absoluteClasspathFiles[index].isFile()));
properties.put("classpathEntry.isFolder", Boolean.toString(absoluteClasspathFiles[index].isDirectory()));
String relative = Utilities.calcRelative(project.getFolder(), absoluteClasspathFiles[index]);
if ((relative == null) || (relative.indexOf("..") != -1)) {
// the calculation of a diff path failed or the relative path "moves" outside of the
// projects directory
properties.put("classpathEntry.isProjectRelative", "false");
} else {
// we've got a project relative classpath entry
properties.put("classpathEntry.isProjectRelative", "true");
}
// create a FileSet for the entry describing it's content
FileSet fileSet = new FileSet();
fileSet.setProject(getProject());
if (absoluteClasspathFiles[index].isFile()) {
fileSet.setFile(absoluteClasspathFiles[index]);
} else if (absoluteClasspathFiles[index].isDirectory()) {
fileSet.setDir(absoluteClasspathFiles[index]);
}
// add the FileSet as reference
values.getReferences().put("classpathEntry.fileSet", fileSet);
return values;
}
});
}
}
/**
* <p>
* </p>
*
* @param macroDef
*/
private void executeProjectScopedMacroDef(MacroDef macroDef) {
// execute macro
executeMacroInstance(macroDef, new MacroExecutionValuesProvider() {
public MacroExecutionValues provideMacroExecutionValues(final MacroExecutionValues values) {
// get the default jdt executor values
getExecutorValuesProvider().provideExecutorValues(getJavaProjectRole(), getJdtClasspathContainerArguments(),
values, ExecuteJdtProjectTask.this._resolvedClassPaths);
// add additional execution values if necessary
addAdditionalExecutionValues(values);
// return the values
return values;
}
});
}
}