|
|
@@ -1,920 +0,0 @@ |
|
|
|
/* |
|
|
|
* The Apache Software License, Version 1.1 |
|
|
|
* |
|
|
|
* Copyright (c) 2001 The Apache Software Foundation. All rights |
|
|
|
* reserved. |
|
|
|
* |
|
|
|
* Redistribution and use in source and binary forms, with or without |
|
|
|
* modification, are permitted provided that the following conditions |
|
|
|
* are met: |
|
|
|
* |
|
|
|
* 1. Redistributions of source code must retain the above copyright |
|
|
|
* notice, this list of conditions and the following disclaimer. |
|
|
|
* |
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
|
|
* notice, this list of conditions and the following disclaimer in |
|
|
|
* the documentation and/or other materials provided with the |
|
|
|
* distribution. |
|
|
|
* |
|
|
|
* 3. The end-user documentation included with the redistribution, if |
|
|
|
* any, must include the following acknowlegement: |
|
|
|
* "This product includes software developed by the |
|
|
|
* Apache Software Foundation (http://www.apache.org/)." |
|
|
|
* Alternately, this acknowlegement may appear in the software itself, |
|
|
|
* if and wherever such third-party acknowlegements normally appear. |
|
|
|
* |
|
|
|
* 4. The names "The Jakarta Project", "Ant", and "Apache Software |
|
|
|
* Foundation" must not be used to endorse or promote products derived |
|
|
|
* from this software without prior written permission. For written |
|
|
|
* permission, please contact apache@apache.org. |
|
|
|
* |
|
|
|
* 5. Products derived from this software may not be called "Apache" |
|
|
|
* nor may "Apache" appear in their names without prior written |
|
|
|
* permission of the Apache Group. |
|
|
|
* |
|
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
|
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
|
|
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
|
|
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
|
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
|
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
|
|
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
|
|
* SUCH DAMAGE. |
|
|
|
* ==================================================================== |
|
|
|
* |
|
|
|
* This software consists of voluntary contributions made by many |
|
|
|
* individuals on behalf of the Apache Software Foundation. For more |
|
|
|
* information on the Apache Software Foundation, please see |
|
|
|
* <http://www.apache.org/>. |
|
|
|
*/ |
|
|
|
package org.apache.ant.core.execution; |
|
|
|
|
|
|
|
import org.apache.ant.core.model.*; |
|
|
|
import org.apache.ant.core.support.*; |
|
|
|
import org.apache.ant.core.types.*; |
|
|
|
|
|
|
|
import java.util.*; |
|
|
|
import java.net.*; |
|
|
|
|
|
|
|
/** |
|
|
|
* An ExecutionFrame is the state of a project during an execution. |
|
|
|
* The ExecutionFrame contains the data values set by Ant tasks as |
|
|
|
* they are executed, including task definitions, property values, etc. |
|
|
|
* |
|
|
|
* @author <a href="mailto:conor@apache.org">Conor MacNeill</a> |
|
|
|
*/ |
|
|
|
public class ExecutionFrame { |
|
|
|
/** State used in dependency analysis when a target's dependencies are being |
|
|
|
examined. */ |
|
|
|
private static final String VISITING = "VISITING"; |
|
|
|
|
|
|
|
/** State used in dependency analysis to indicate a target has been examined */ |
|
|
|
private static final String VISITED = "VISITED"; |
|
|
|
|
|
|
|
/** The Project that this execiton frame is processing */ |
|
|
|
private Project project = null; |
|
|
|
|
|
|
|
/** The base URL for this frame. This is derived from the |
|
|
|
Project's source URL and it's base attribute. */ |
|
|
|
private URL baseURL = null; |
|
|
|
|
|
|
|
/** The imported frames of this frame. For each project imported by this frame's |
|
|
|
project, a corresponding ExecutionFrame is created. */ |
|
|
|
private Map importedFrames = new HashMap(); |
|
|
|
|
|
|
|
/** BuildEvent support used to fire events and manage listeners */ |
|
|
|
private BuildEventSupport eventSupport = new BuildEventSupport(); |
|
|
|
|
|
|
|
/** The context of this execution. This contains all data object's |
|
|
|
created by tasks that have been executed */ |
|
|
|
private Map dataValues = new HashMap(); |
|
|
|
|
|
|
|
/** Introspector objects used to configure Tasks from the Task models.*/ |
|
|
|
private Map introspectors = new HashMap(); |
|
|
|
|
|
|
|
/** The task defs that this frame will use to process tasks */ |
|
|
|
private Map taskDefs = new HashMap(); |
|
|
|
|
|
|
|
/** Type converters for this executionFrame. Converters are used when configuring |
|
|
|
Tasks to handle special type conversions. */ |
|
|
|
private Map converters = new HashMap(); |
|
|
|
|
|
|
|
/** The aspect handler active in this frame */ |
|
|
|
private Map aspectHandlers = new HashMap(); |
|
|
|
|
|
|
|
/** The namespace under which this execution frame lives in the hierarchical |
|
|
|
project namespace - null for the root namespace */ |
|
|
|
private String namespace; |
|
|
|
|
|
|
|
/** |
|
|
|
* Construct an execution frame to process the given project model with |
|
|
|
* the configuration represented by the libraries. |
|
|
|
* |
|
|
|
* @param project the model of the project to be built. |
|
|
|
* @param libraries an Array of AntLibrary objects containing the |
|
|
|
* configuration of Ant for this build. |
|
|
|
* |
|
|
|
* @throws ConfigException when the project cannot be setup with the |
|
|
|
* given configuration |
|
|
|
*/ |
|
|
|
public ExecutionFrame(Project project, AntLibrary[] libraries) |
|
|
|
throws ConfigException { |
|
|
|
|
|
|
|
this.namespace = null; |
|
|
|
setupFrame(project, libraries); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Construct a subframe for managing a project imported into the main project. |
|
|
|
* @param project the model of the project to be built. |
|
|
|
* @param libraries an Array of AntLibrary objects containing the |
|
|
|
* configuration of Ant for this build. |
|
|
|
* @param namespace the location of this project within the overall import |
|
|
|
* namespace. |
|
|
|
* |
|
|
|
* @throws ConfigException when the project cannot be setup with the |
|
|
|
* given configuration |
|
|
|
*/ |
|
|
|
private ExecutionFrame(Project project, AntLibrary[] libraries, String namespace) |
|
|
|
throws ConfigException { |
|
|
|
|
|
|
|
this.namespace = namespace; |
|
|
|
setupFrame(project, libraries); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Set up the execution frame. |
|
|
|
* |
|
|
|
* This method examines the project model and constructs the required |
|
|
|
* subframes to handle imported projects. |
|
|
|
* @param project the model of the project to be built. |
|
|
|
* @param libraries an Array of AntLibrary objects containing the |
|
|
|
* configuration of Ant for this build. |
|
|
|
* |
|
|
|
* @throws ConfigException when the project cannot be setup with the |
|
|
|
* given configuration |
|
|
|
*/ |
|
|
|
private void setupFrame(Project project, AntLibrary[] libraries) |
|
|
|
throws ConfigException { |
|
|
|
|
|
|
|
this.project = project; |
|
|
|
for (int i = 0; i < libraries.length; ++i) { |
|
|
|
addLibrary(libraries[i]); |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
String base = project.getBase(); |
|
|
|
if (base == null) { |
|
|
|
baseURL = project.getSourceURL(); |
|
|
|
} |
|
|
|
else { |
|
|
|
base = base.trim(); |
|
|
|
if (!base.endsWith("/")) { |
|
|
|
base += "/"; |
|
|
|
} |
|
|
|
baseURL = new URL(project.getSourceURL(), base); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (MalformedURLException e) { |
|
|
|
throw new ConfigException("Project's base value \"" + project.getBase() |
|
|
|
+ "\" is not valid", e, project.getLocation()); |
|
|
|
} |
|
|
|
|
|
|
|
for (Iterator i = project.getImportedProjectNames(); i.hasNext();) { |
|
|
|
String importName = (String)i.next(); |
|
|
|
Project importedProject = project.getImportedProject(importName); |
|
|
|
String importNamespace |
|
|
|
= namespace == null ? importName : namespace + ":" + importName; |
|
|
|
ExecutionFrame importedFrame |
|
|
|
= new ExecutionFrame(importedProject, libraries, importNamespace); |
|
|
|
importedFrames.put(importName, importedFrame); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Add a configuration library to this execution frame. The library |
|
|
|
* will contain task definitions, converters, apsect handler definitions, |
|
|
|
* etc. |
|
|
|
* |
|
|
|
* @param library the configuration library to add to this frame. |
|
|
|
* |
|
|
|
* @throws ConfigException if the items in the library cannot be configured. |
|
|
|
*/ |
|
|
|
public void addLibrary(AntLibrary library) throws ConfigException { |
|
|
|
for (Iterator i = library.getTaskDefinitions(); i.hasNext(); ) { |
|
|
|
TaskDefinition taskDefinition = (TaskDefinition)i.next(); |
|
|
|
addTaskDefinition(taskDefinition); |
|
|
|
} |
|
|
|
for (Iterator i = library.getConverterDefinitions(); i.hasNext(); ) { |
|
|
|
ConverterDefinition converterDef = (ConverterDefinition)i.next(); |
|
|
|
addConverterDefinition(converterDef); |
|
|
|
} |
|
|
|
for (Iterator i = library.getAspectDefinitions(); i.hasNext(); ) { |
|
|
|
AspectDefinition aspectDef = (AspectDefinition)i.next(); |
|
|
|
addAspectHandler(aspectDef); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Add a task definition to this execution frame |
|
|
|
* |
|
|
|
* @param taskDefinition the TaskDefinition to be added to the project. |
|
|
|
*/ |
|
|
|
public void addTaskDefinition(TaskDefinition taskDefinition) { |
|
|
|
String taskName = taskDefinition.getName(); |
|
|
|
taskDefs.put(taskName, taskDefinition); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Add a aspect handler definition to this execution frame |
|
|
|
* |
|
|
|
* @param taskDefinition the TaskDefinition to be added to the project. |
|
|
|
* |
|
|
|
* @throws ConfigException if the aspect handler cannot be created or configured. |
|
|
|
*/ |
|
|
|
public void addAspectHandler(AspectDefinition aspectDefinition) |
|
|
|
throws ConfigException { |
|
|
|
String aspectPrefix = aspectDefinition.getAspectPrefix(); |
|
|
|
try { |
|
|
|
Class aspectHandlerClass = aspectDefinition.getAspectHandlerClass(); |
|
|
|
aspectHandlers.put(aspectPrefix, aspectHandlerClass); |
|
|
|
} |
|
|
|
catch (ClassNotFoundException e) { |
|
|
|
throw new ConfigException("Unable to load aspect handler class for " |
|
|
|
+ aspectDefinition.getAspectHandlerClassName() |
|
|
|
+ " in converter from " + aspectDefinition.getLibraryURL(), |
|
|
|
e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Add a converter definition to this library. |
|
|
|
* |
|
|
|
* The converter is created immediately to handle conversions |
|
|
|
* when items are being configured. If the converter is an instance of |
|
|
|
* an AntConverter, the converter is configured with this execution |
|
|
|
* frame giving it the context it needs to resolve items relative to the |
|
|
|
* project's base, etc. |
|
|
|
* |
|
|
|
* @param converterDef the converter definition to load |
|
|
|
* |
|
|
|
* @throws ConfigException if the converter cannot be created or configured. |
|
|
|
*/ |
|
|
|
public void addConverterDefinition(ConverterDefinition converterDef) throws ConfigException { |
|
|
|
boolean targetLoaded = false; |
|
|
|
try { |
|
|
|
Class targetClass = converterDef.getTargetClass(); |
|
|
|
targetLoaded = false; |
|
|
|
Class converterClass = converterDef.getConverterClass(); |
|
|
|
Converter converter = (AntConverter)converterClass.newInstance(); |
|
|
|
if (converter instanceof AntConverter) { |
|
|
|
((AntConverter)converter).init(this); |
|
|
|
} |
|
|
|
converters.put(targetClass, converter); |
|
|
|
} |
|
|
|
catch (ClassNotFoundException e) { |
|
|
|
if (targetLoaded) { |
|
|
|
throw new ConfigException("Unable to load converter class for " |
|
|
|
+ converterDef.getConverterClassName() |
|
|
|
+ " in converter from " + converterDef.getLibraryURL(), |
|
|
|
e); |
|
|
|
} |
|
|
|
else { |
|
|
|
throw new ConfigException("Unable to load target class " |
|
|
|
+ converterDef.getTargetClassName() |
|
|
|
+ " in converter from " + converterDef.getLibraryURL(), |
|
|
|
e); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (InstantiationException e) { |
|
|
|
throw new ConfigException("Unable to instantiate converter class " |
|
|
|
+ converterDef.getTargetClassName() |
|
|
|
+ " in converter from " + converterDef.getLibraryURL(), |
|
|
|
e); |
|
|
|
} |
|
|
|
catch (IllegalAccessException e) { |
|
|
|
throw new ConfigException("Unable to access converter class " |
|
|
|
+ converterDef.getTargetClassName() |
|
|
|
+ " in converter from " + converterDef.getLibraryURL(), |
|
|
|
e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Get the bae URL of this frame. This will either be specified by the project's |
|
|
|
* base attribute or be derived implicitly from the project's location. |
|
|
|
*/ |
|
|
|
public URL getBaseURL() { |
|
|
|
return baseURL; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void addBuildListener(BuildListener listener) { |
|
|
|
for (Iterator i = getImportedFrames(); i.hasNext(); ) { |
|
|
|
ExecutionFrame subFrame = (ExecutionFrame)i.next(); |
|
|
|
subFrame.addBuildListener(listener); |
|
|
|
} |
|
|
|
eventSupport.addBuildListener(listener); |
|
|
|
} |
|
|
|
|
|
|
|
public void removeBuildListener(BuildListener listener) { |
|
|
|
for (Iterator i = getImportedFrames(); i.hasNext(); ) { |
|
|
|
ExecutionFrame subFrame = (ExecutionFrame)i.next(); |
|
|
|
subFrame.removeBuildListener(listener); |
|
|
|
} |
|
|
|
eventSupport.removeBuildListener(listener); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Get the project associated with this execution frame. |
|
|
|
* |
|
|
|
* @return the project associated iwth this execution frame. |
|
|
|
*/ |
|
|
|
public Project getProject() { |
|
|
|
return project; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Get the names of the frames representing imported projects. |
|
|
|
* |
|
|
|
* @return an iterator which returns the names of the imported frames. |
|
|
|
*/ |
|
|
|
public Iterator getImportedFrameNames() { |
|
|
|
return importedFrames.keySet().iterator(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Get the frames representing imported projects. |
|
|
|
* |
|
|
|
* @return an iterator which returns the imported ExeuctionFrames.. |
|
|
|
*/ |
|
|
|
public Iterator getImportedFrames() { |
|
|
|
return importedFrames.values().iterator(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Get an imported frame by name |
|
|
|
* |
|
|
|
* @param importName the name under which the frame was imported. |
|
|
|
* |
|
|
|
* @return the ExecutionFrame asscociated with the given import name or null |
|
|
|
* if there is no such project. |
|
|
|
*/ |
|
|
|
public ExecutionFrame getImportedFrame(String importName) { |
|
|
|
return (ExecutionFrame)importedFrames.get(importName); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Get the location of this frame in the namespace hierarchy |
|
|
|
* |
|
|
|
* @return the location of this frame within the project import |
|
|
|
* namespace hierarchy. |
|
|
|
*/ |
|
|
|
public String getNamespace() { |
|
|
|
return namespace; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Get the fully qualified name of something with respect to this |
|
|
|
* execution frame. |
|
|
|
* |
|
|
|
* @param name the unqualified name. |
|
|
|
* |
|
|
|
* @return the fully qualified version of the given name |
|
|
|
*/ |
|
|
|
public String getQualifiedName(String name) { |
|
|
|
return namespace == null ? name : namespace + ":" + name; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Execute the given target's tasks |
|
|
|
* |
|
|
|
* @param the name of the target within this frame that is to be executed. |
|
|
|
*/ |
|
|
|
public void executeTargetTasks(String targetName) throws ExecutionException, ConfigException { |
|
|
|
Target target = project.getTarget(targetName); |
|
|
|
try { |
|
|
|
Iterator taskIterator = target.getTasks(); |
|
|
|
eventSupport.fireTargetStarted(this, target); |
|
|
|
executeTasks(taskIterator); |
|
|
|
eventSupport.fireTargetFinished(this, target, null); |
|
|
|
} |
|
|
|
catch (RuntimeException e) { |
|
|
|
eventSupport.fireTargetFinished(this, target, e); |
|
|
|
throw e; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Initialize the frame by executing the project level tasks if any |
|
|
|
*/ |
|
|
|
public void initialize() throws ExecutionException, ConfigException { |
|
|
|
for (Iterator i = getImportedFrames(); i.hasNext(); ) { |
|
|
|
ExecutionFrame subFrame = (ExecutionFrame)i.next(); |
|
|
|
subFrame.initialize(); |
|
|
|
} |
|
|
|
Iterator taskIterator = project.getTasks(); |
|
|
|
executeTasks(taskIterator); |
|
|
|
} |
|
|
|
|
|
|
|
public void fillinDependencyOrder(String targetName, List dependencyOrder, |
|
|
|
Map state, Stack visiting) throws ConfigException { |
|
|
|
String fullTargetName = getQualifiedName(targetName); |
|
|
|
if (state.get(fullTargetName) == VISITED) { |
|
|
|
return; |
|
|
|
} |
|
|
|
Target target = getProject().getTarget(targetName); |
|
|
|
if (target == null) { |
|
|
|
StringBuffer sb = new StringBuffer("Target `"); |
|
|
|
sb.append(targetName); |
|
|
|
sb.append("' does not exist in this project. "); |
|
|
|
if (!visiting.empty()) { |
|
|
|
String parent = (String)visiting.peek(); |
|
|
|
sb.append("It is used from target `"); |
|
|
|
sb.append(parent); |
|
|
|
sb.append("'."); |
|
|
|
} |
|
|
|
|
|
|
|
throw new ConfigException(new String(sb), getProject().getLocation()); |
|
|
|
} |
|
|
|
|
|
|
|
state.put(fullTargetName, VISITING); |
|
|
|
visiting.push(fullTargetName); |
|
|
|
for (Iterator i = target.getDependencies(); i.hasNext(); ) { |
|
|
|
String dependency = (String)i.next(); |
|
|
|
try { |
|
|
|
ExecutionFrame dependencyFrame = getRelativeFrame(dependency); |
|
|
|
if (dependencyFrame == null) { |
|
|
|
StringBuffer sb = new StringBuffer("Target `"); |
|
|
|
sb.append(dependency); |
|
|
|
sb.append("' does not exist in this project. "); |
|
|
|
throw new ConfigException(new String(sb), target.getLocation()); |
|
|
|
} |
|
|
|
|
|
|
|
String fullyQualifiedName = getQualifiedName(dependency); |
|
|
|
String dependencyState = (String)state.get(fullyQualifiedName); |
|
|
|
if (dependencyState == null) { |
|
|
|
dependencyFrame.fillinDependencyOrder(getNameInFrame(dependency), dependencyOrder, |
|
|
|
state, visiting); |
|
|
|
} |
|
|
|
else if (dependencyState == VISITING) { |
|
|
|
String circleDescription |
|
|
|
= getCircularDesc(dependency, visiting); |
|
|
|
throw new ConfigException(circleDescription, target.getLocation()); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (ExecutionException e) { |
|
|
|
throw new ConfigException(e.getMessage(), e, target.getLocation()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
state.put(fullTargetName, VISITED); |
|
|
|
String poppedNode = (String)visiting.pop(); |
|
|
|
if (poppedNode != fullTargetName) { |
|
|
|
throw new ConfigException("Problem determining dependencies " + |
|
|
|
" - expecting '" + fullTargetName + |
|
|
|
"' but got '" + poppedNode + "'"); |
|
|
|
} |
|
|
|
dependencyOrder.add(fullTargetName); |
|
|
|
} |
|
|
|
|
|
|
|
private String getCircularDesc(String end, Stack visitingNodes) { |
|
|
|
StringBuffer sb = new StringBuffer("Circular dependency: "); |
|
|
|
sb.append(end); |
|
|
|
String c; |
|
|
|
do { |
|
|
|
c = (String)visitingNodes.pop(); |
|
|
|
sb.append(" <- "); |
|
|
|
sb.append(c); |
|
|
|
} while(!c.equals(end)); |
|
|
|
return new String(sb); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Check whether the targets in this frame and its subframes are OK |
|
|
|
*/ |
|
|
|
public void checkTargets(List dependencyOrder, Map state, Stack visiting) |
|
|
|
throws ConfigException { |
|
|
|
// get the targets and just iterate through them. |
|
|
|
for (Iterator i = getProject().getTargets(); i.hasNext();) { |
|
|
|
Target target = (Target)i.next(); |
|
|
|
fillinDependencyOrder(target.getName(), |
|
|
|
dependencyOrder, state, visiting); |
|
|
|
} |
|
|
|
|
|
|
|
// Now do the subframes. |
|
|
|
for (Iterator i = getImportedFrames(); i.hasNext();) { |
|
|
|
ExecutionFrame importedFrame = (ExecutionFrame)i.next(); |
|
|
|
importedFrame.checkTargets(dependencyOrder, state, visiting); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Create a Task and configure it according to the given model. |
|
|
|
*/ |
|
|
|
private Task configureTask(TaskElement model) |
|
|
|
throws ConfigException, ExecutionException { |
|
|
|
|
|
|
|
String taskType = model.getType(); |
|
|
|
TaskDefinition taskDefinition = (TaskDefinition)taskDefs.get(taskType); |
|
|
|
if (taskDefinition == null) { |
|
|
|
throw new ConfigException("There is no defintion for tasks of type <" |
|
|
|
+ taskType + ">", model.getLocation()); |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
Class elementClass = taskDefinition.getExecutionTaskClass(); |
|
|
|
Object element = elementClass.newInstance(); |
|
|
|
Task task = null; |
|
|
|
if (element instanceof Task) { |
|
|
|
// create a Task context for the Task |
|
|
|
task = (Task)element; |
|
|
|
} |
|
|
|
else { |
|
|
|
task = new TaskAdapter(taskType, element); |
|
|
|
} |
|
|
|
|
|
|
|
configureElement(element, model); |
|
|
|
|
|
|
|
return task; |
|
|
|
} |
|
|
|
catch (ClassNotFoundException e) { |
|
|
|
throw new ConfigException("Execution class " + taskDefinition.getTaskClassName() |
|
|
|
+ " was not found", e, model.getLocation()); |
|
|
|
} |
|
|
|
catch (InstantiationException e) { |
|
|
|
throw new ConfigException("Unable to instantiate execution class " |
|
|
|
+ taskDefinition.getTaskClassName(), |
|
|
|
e, model.getLocation()); |
|
|
|
} |
|
|
|
catch (IllegalAccessException e) { |
|
|
|
throw new ConfigException("Unable to access execution class " |
|
|
|
+ taskDefinition.getTaskClassName(), |
|
|
|
e, model.getLocation()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private List getActiveAspects(BuildElement model) |
|
|
|
throws ConfigException, ExecutionException, |
|
|
|
ClassIntrospectionException, ConversionException { |
|
|
|
List activeAspects = new ArrayList(); |
|
|
|
for (Iterator i = model.getAspectNames(); i.hasNext();) { |
|
|
|
String aspectPrefix = (String)i.next(); |
|
|
|
Class aspectHandlerClass = (Class)aspectHandlers.get(aspectPrefix); |
|
|
|
if (aspectHandlerClass != null) { |
|
|
|
try { |
|
|
|
AspectHandler aspectHandler |
|
|
|
= (AspectHandler)aspectHandlerClass.newInstance(); |
|
|
|
ClassIntrospector introspector = getIntrospector(aspectHandlerClass); |
|
|
|
|
|
|
|
ExecutionContext context = new ExecutionContext(this, eventSupport, model); |
|
|
|
aspectHandler.setAspectContext(context); |
|
|
|
|
|
|
|
Map aspectAttributes = model.getAspectAttributes(aspectPrefix); |
|
|
|
for (Iterator j = aspectAttributes.keySet().iterator(); j.hasNext();) { |
|
|
|
String attributeName = (String)j.next(); |
|
|
|
String attributeValue = (String)aspectAttributes.get(attributeName); |
|
|
|
introspector.setAttribute(aspectHandler, attributeName, |
|
|
|
replacePropertyRefs(attributeValue)); |
|
|
|
} |
|
|
|
activeAspects.add(aspectHandler); |
|
|
|
} |
|
|
|
catch (InstantiationException e) { |
|
|
|
throw new ConfigException("Unable to instantiate aspect handler class " |
|
|
|
+ aspectHandlerClass, |
|
|
|
e); |
|
|
|
} |
|
|
|
catch (IllegalAccessException e) { |
|
|
|
throw new ConfigException("Unable to access aspect handler class " |
|
|
|
+ aspectHandlerClass, |
|
|
|
e); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return activeAspects; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Configure an element according to the given model. |
|
|
|
*/ |
|
|
|
private void configureElement(Object element, TaskElement model) |
|
|
|
throws ExecutionException, ConfigException { |
|
|
|
|
|
|
|
if (element instanceof Task) { |
|
|
|
Task task = (Task)element; |
|
|
|
ExecutionContext context = new ExecutionContext(this, eventSupport, model); |
|
|
|
task.setTaskContext(context); |
|
|
|
} |
|
|
|
try { |
|
|
|
ClassIntrospector introspector = getIntrospector(element.getClass()); |
|
|
|
|
|
|
|
List aspects = getActiveAspects(model); |
|
|
|
for (Iterator i = aspects.iterator(); i.hasNext(); ) { |
|
|
|
AspectHandler aspectHandler = (AspectHandler)i.next(); |
|
|
|
aspectHandler.beforeConfigElement(element); |
|
|
|
} |
|
|
|
|
|
|
|
// start by setting the attributes of this element |
|
|
|
for (Iterator i = model.getAttributeNames(); i.hasNext();) { |
|
|
|
String attributeName = (String)i.next(); |
|
|
|
String attributeValue = model.getAttributeValue(attributeName); |
|
|
|
introspector.setAttribute(element, attributeName, |
|
|
|
replacePropertyRefs(attributeValue)); |
|
|
|
} |
|
|
|
|
|
|
|
String modelText = model.getText().trim(); |
|
|
|
if (modelText.length() != 0) { |
|
|
|
introspector.addText(element, replacePropertyRefs(modelText)); |
|
|
|
} |
|
|
|
|
|
|
|
// now do the nested elements |
|
|
|
for (Iterator i = model.getNestedElements(); i.hasNext();) { |
|
|
|
TaskElement nestedElementModel = (TaskElement)i.next(); |
|
|
|
if (element instanceof TaskContainer && |
|
|
|
!introspector.supportsNestedElement(nestedElementModel.getType())) { |
|
|
|
|
|
|
|
Task nestedTask = configureTask(nestedElementModel); |
|
|
|
TaskContainer container = (TaskContainer)element; |
|
|
|
container.addTask(nestedTask); |
|
|
|
} |
|
|
|
else { |
|
|
|
Object nestedElement |
|
|
|
= introspector.createElement(element, nestedElementModel.getType()); |
|
|
|
configureElement(nestedElement, nestedElementModel); |
|
|
|
} |
|
|
|
} |
|
|
|
for (Iterator i = aspects.iterator(); i.hasNext(); ) { |
|
|
|
AspectHandler aspectHandler = (AspectHandler)i.next(); |
|
|
|
aspectHandler.afterConfigElement(element); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (ClassIntrospectionException e) { |
|
|
|
throw new ExecutionException(e, model.getLocation()); |
|
|
|
} |
|
|
|
catch (ConversionException e) { |
|
|
|
throw new ExecutionException(e, model.getLocation()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Run the tasks returned by the give iterator |
|
|
|
* |
|
|
|
* @param taskIterator the iterator giving the tasks to execute |
|
|
|
*/ |
|
|
|
public void executeTasks(Iterator taskIterator) throws ExecutionException, ConfigException { |
|
|
|
TaskElement task = null; |
|
|
|
try { |
|
|
|
while (taskIterator.hasNext()) { |
|
|
|
task = (TaskElement)taskIterator.next(); |
|
|
|
try { |
|
|
|
Task configuredTask = configureTask(task); |
|
|
|
eventSupport.fireTaskStarted(this, task); |
|
|
|
configuredTask.execute(); |
|
|
|
} |
|
|
|
catch (ExecutionException e) { |
|
|
|
if (e.getLocation() == null || e.getLocation() == Location.UNKNOWN_LOCATION) { |
|
|
|
e.setLocation(task.getLocation()); |
|
|
|
} |
|
|
|
throw e; |
|
|
|
} |
|
|
|
catch (ConfigException e) { |
|
|
|
if (e.getLocation() == null || e.getLocation() == Location.UNKNOWN_LOCATION) { |
|
|
|
e.setLocation(task.getLocation()); |
|
|
|
} |
|
|
|
throw e; |
|
|
|
} |
|
|
|
eventSupport.fireTaskFinished(this, task, null); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (RuntimeException e) { |
|
|
|
eventSupport.fireTaskFinished(this, task, e); |
|
|
|
throw e; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private ClassIntrospector getIntrospector(Class c) { |
|
|
|
if (introspectors.containsKey(c)) { |
|
|
|
return (ClassIntrospector)introspectors.get(c); |
|
|
|
} |
|
|
|
ClassIntrospector introspector = new ClassIntrospector(c, converters); |
|
|
|
introspectors.put(c, introspector); |
|
|
|
return introspector; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Replace ${} style constructions in the given value with the string value of |
|
|
|
* the corresponding data types. |
|
|
|
* |
|
|
|
* @param value the string to be scanned for property references. |
|
|
|
*/ |
|
|
|
public String replacePropertyRefs(String value) throws ExecutionException { |
|
|
|
if (value == null) { |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
List fragments = new ArrayList(); |
|
|
|
List propertyRefs = new ArrayList(); |
|
|
|
parsePropertyString(value, fragments, propertyRefs); |
|
|
|
|
|
|
|
StringBuffer sb = new StringBuffer(); |
|
|
|
Iterator i = fragments.iterator(); |
|
|
|
Iterator j = propertyRefs.iterator(); |
|
|
|
while (i.hasNext()) { |
|
|
|
String fragment = (String)i.next(); |
|
|
|
if (fragment == null) { |
|
|
|
String propertyName = (String)j.next(); |
|
|
|
if (!isDataValueSet(propertyName)) { |
|
|
|
throw new ExecutionException("Property " + propertyName + " has not been set"); |
|
|
|
} |
|
|
|
fragment = getDataValue(propertyName).toString(); |
|
|
|
} |
|
|
|
sb.append(fragment); |
|
|
|
} |
|
|
|
|
|
|
|
return sb.toString(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* This method will parse a string containing ${value} style |
|
|
|
* property values into two list. The first list is a collection |
|
|
|
* of text fragments, while the other is a set of string property names |
|
|
|
* null entries in the first list indicate a property reference from the |
|
|
|
* second list. |
|
|
|
*/ |
|
|
|
static public void parsePropertyString(String value, List fragments, List propertyRefs) |
|
|
|
throws ExecutionException { |
|
|
|
int prev = 0; |
|
|
|
int pos; |
|
|
|
while ((pos = value.indexOf("$", prev)) >= 0) { |
|
|
|
if (pos > 0) { |
|
|
|
fragments.add(value.substring(prev, pos)); |
|
|
|
} |
|
|
|
|
|
|
|
if( pos == (value.length() - 1)) { |
|
|
|
fragments.add("$"); |
|
|
|
prev = pos + 1; |
|
|
|
} |
|
|
|
else if (value.charAt(pos + 1) != '{' ) { |
|
|
|
fragments.add(value.substring(pos + 1, pos + 2)); |
|
|
|
prev = pos + 2; |
|
|
|
} else { |
|
|
|
int endName = value.indexOf('}', pos); |
|
|
|
if (endName < 0) { |
|
|
|
throw new ExecutionException("Syntax error in property: " |
|
|
|
+ value ); |
|
|
|
} |
|
|
|
String propertyName = value.substring(pos + 2, endName); |
|
|
|
fragments.add(null); |
|
|
|
propertyRefs.add(propertyName); |
|
|
|
prev = endName + 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (prev < value.length()) { |
|
|
|
fragments.add(value.substring(prev)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Given a name of an object, get the frame relative from this frame that |
|
|
|
* contains that object. |
|
|
|
*/ |
|
|
|
public ExecutionFrame getRelativeFrame(String name) throws ExecutionException { |
|
|
|
int index = name.lastIndexOf(":"); |
|
|
|
if (index == -1) { |
|
|
|
return this; |
|
|
|
} |
|
|
|
|
|
|
|
ExecutionFrame currentFrame = this; |
|
|
|
String relativeFrameName = name.substring(0, index); |
|
|
|
StringTokenizer tokenizer = new StringTokenizer(relativeFrameName, ":"); |
|
|
|
while (tokenizer.hasMoreTokens()) { |
|
|
|
String frameName = tokenizer.nextToken(); |
|
|
|
currentFrame = currentFrame.getImportedFrame(frameName); |
|
|
|
if (currentFrame == null) { |
|
|
|
throw new ExecutionException("The project " + frameName + " in " |
|
|
|
+ name + " was not found"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return currentFrame; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Get the name of an object in its frame |
|
|
|
*/ |
|
|
|
public String getNameInFrame(String name) { |
|
|
|
int index = name.lastIndexOf(":"); |
|
|
|
if (index == -1) { |
|
|
|
return name; |
|
|
|
} |
|
|
|
return name.substring(index+1); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Set a value in this frame or any of its imported frames |
|
|
|
*/ |
|
|
|
public void setDataValue(String name, Object value) throws ExecutionException { |
|
|
|
ExecutionFrame frame = getRelativeFrame(name); |
|
|
|
frame.setDirectDataValue(getNameInFrame(name), value); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Get a value from this frame or any imported frame |
|
|
|
*/ |
|
|
|
public Object getDataValue(String name) throws ExecutionException { |
|
|
|
ExecutionFrame frame = getRelativeFrame(name); |
|
|
|
return frame.getDirectDataValue(getNameInFrame(name)); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Set a value in this frame only |
|
|
|
*/ |
|
|
|
private void setDirectDataValue(String name, Object value) { |
|
|
|
dataValues.put(name, value); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Get a value from this frame |
|
|
|
*/ |
|
|
|
private Object getDirectDataValue(String name) { |
|
|
|
return dataValues.get(name); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Indicate if a data value has been set |
|
|
|
*/ |
|
|
|
public boolean isDataValueSet(String name) throws ExecutionException { |
|
|
|
ExecutionFrame frame = getRelativeFrame(name); |
|
|
|
return frame.isDirectDataValueSet(getNameInFrame(name)); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Indicate if a data value has been set in this frame |
|
|
|
*/ |
|
|
|
private boolean isDirectDataValueSet(String name) { |
|
|
|
return dataValues.containsKey(name); |
|
|
|
} |
|
|
|
|
|
|
|
public void runBuild(List targetNames) throws AntException { |
|
|
|
Throwable buildFailureCause = null; |
|
|
|
try { |
|
|
|
eventSupport.fireBuildStarted(this, project); |
|
|
|
initialize(); |
|
|
|
|
|
|
|
if (targetNames.isEmpty()) { |
|
|
|
// we just execute the default target if any |
|
|
|
String defaultTarget = project.getDefaultTarget(); |
|
|
|
if (defaultTarget != null) { |
|
|
|
executeTarget(defaultTarget); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
for (Iterator i = targetNames.iterator(); i.hasNext();) { |
|
|
|
executeTarget((String)i.next()); |
|
|
|
} |
|
|
|
} |
|
|
|
eventSupport.fireBuildFinished(this, project, null); |
|
|
|
} |
|
|
|
catch (RuntimeException e) { |
|
|
|
buildFailureCause = e; |
|
|
|
throw e; |
|
|
|
} |
|
|
|
catch (AntException e) { |
|
|
|
buildFailureCause = e; |
|
|
|
throw e; |
|
|
|
} |
|
|
|
finally { |
|
|
|
eventSupport.fireBuildFinished(this, project, buildFailureCause); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void executeTarget(String targetName) throws ExecutionException, ConfigException { |
|
|
|
// to execute a target we must determine its dependencies and |
|
|
|
// execute them in order. |
|
|
|
Map state = new HashMap(); |
|
|
|
Stack visiting = new Stack(); |
|
|
|
List dependencyOrder = new ArrayList(); |
|
|
|
ExecutionFrame startingFrame = getRelativeFrame(targetName); |
|
|
|
startingFrame.fillinDependencyOrder(getNameInFrame(targetName), |
|
|
|
dependencyOrder, state, visiting); |
|
|
|
|
|
|
|
// Now tell each frame to execute the targets required |
|
|
|
for (Iterator i = dependencyOrder.iterator(); i.hasNext();) { |
|
|
|
String fullTargetName = (String)i.next(); |
|
|
|
ExecutionFrame frame = getRelativeFrame(fullTargetName); |
|
|
|
frame.executeTargetTasks(getNameInFrame(fullTargetName)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |