diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ExecutionManager.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ExecutionManager.java index 979a6a32b..24e96fbd6 100755 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ExecutionManager.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ExecutionManager.java @@ -222,7 +222,11 @@ public class ExecutionManager implements DemuxOutputReceiver { * @param isErr true if this content is from the thread's error stream. */ public void threadOutput(String line, boolean isErr) { - eventSupport.threadOutput(line, isErr); + if (mainFrame == null) { + eventSupport.threadOutput(line, isErr); + } else { + mainFrame.threadOutput(line, isErr); + } } } diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/Frame.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/Frame.java index bc422eca8..51f11dc1f 100644 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/Frame.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/Frame.java @@ -1,55 +1,55 @@ /* - * The Apache Software License, Version 1.1 + * The Apache Software License, Version 1.1 * - * Copyright (c) 2002 The Apache Software Foundation. All rights - * reserved. + * Copyright (c) 2002 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: + * 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. + * 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. + * 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. + * 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. + * 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. + * 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 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 - * . + * 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 + * . */ package org.apache.ant.antcore.execution; import java.io.File; @@ -84,10 +84,10 @@ import org.apache.ant.init.InitConfig; * contains the data values set by Ant tasks as they are executed, including * task definitions, property values, etc. * - * @author Conor MacNeill - * @created 14 January 2002 + * @author Conor MacNeill + * @created 14 January 2002 */ -public class Frame { +public class Frame implements DemuxOutputReceiver { /** the base dir of the project */ private File baseDir; @@ -98,20 +98,20 @@ public class Frame { private Map referencedFrames = new HashMap(); /** - * The context of this execution. This contains all data object's - * created by tasks that have been executed + * The context of this execution. This contains all data object's created + * by tasks that have been executed */ private Map dataValues = new HashMap(); /** - * Ant's initialization configuration with information on the location - * of Ant and its libraries. + * Ant's initialization configuration with information on the location of + * Ant and its libraries. */ private InitConfig initConfig; /** - * These are the standard libraries from which taskdefs, typedefs, etc - * may be imported. + * These are the standard libraries from which taskdefs, typedefs, etc may + * be imported. */ private Map standardLibs; @@ -144,17 +144,19 @@ public class Frame { */ private ComponentManager componentManager; - /** The core's execution Service */ + /** The core's execution Service */ private CoreExecService execService; + /** * Create an Execution Frame for the given project * - * @param standardLibs The libraries of tasks and types available to - * this frame - * @param config the user config to use for this execution of Ant - * @param initConfig Ant's initialisation config - * @exception ExecutionException if a component of the library cannot be + * @param standardLibs The libraries of tasks and types + * available to this frame + * @param config the user config to use for this + * execution of Ant + * @param initConfig Ant's initialisation config + * @exception ExecutionException if a component of the library cannot be * imported */ protected Frame(Map standardLibs, InitConfig initConfig, @@ -164,23 +166,27 @@ public class Frame { this.initConfig = initConfig; } + /** * Replace ${} style constructions in the given value with the string * value of the corresponding data values in the frame * - * @param value the string to be scanned for property references. - * @return the string with all property references replaced - * @exception ExecutionException if any of the properties do not exist + * @param value the string to be scanned for property + * references. + * @return the string with all property references + * replaced + * @exception ExecutionException if any of the properties do not exist */ public String replacePropertyRefs(String value) throws ExecutionException { return dataService.replacePropertyRefs(value); } + /** * Sets the Project of the Frame * - * @param project The new Project value - * @exception ExecutionException if any required sub-frames cannot be + * @param project The new Project value + * @exception ExecutionException if any required sub-frames cannot be * created and configured */ protected void setProject(Project project) throws ExecutionException { @@ -192,6 +198,7 @@ public class Frame { Project referencedProject = project.getReferencedProject(referenceName); Frame referencedFrame = createFrame(referencedProject); + referencedFrames.put(referenceName, referencedFrame); } @@ -200,10 +207,11 @@ public class Frame { setMagicProperties(); } + /** * get the name of the project associated with this frame. * - * @return the project's name + * @return the project's name */ public String getProjectName() { if (project != null) { @@ -211,18 +219,20 @@ public class Frame { } return null; } - + + /** * Set a value in this frame or any of its imported frames. * - * @param name the name of the value - * @param value the actual value - * @param mutable if true, existing values can be changed - * @exception ExecutionException if the value name is invalid + * @param name the name of the value + * @param value the actual value + * @param mutable if true, existing values can be changed + * @exception ExecutionException if the value name is invalid */ protected void setDataValue(String name, Object value, boolean mutable) throws ExecutionException { Frame frame = getContainingFrame(name); + if (frame == null) { throw new ExecutionException("There is no project corresponding " + "to the name \"" + name + "\""); @@ -239,12 +249,13 @@ public class Frame { } } + /** * Set the initial properties to be used when the frame starts execution * - * @param properties a Map of named properties which may in fact be any - * object - * @exception ExecutionException if the properties cannot be set + * @param properties a Map of named properties which may in + * fact be any object + * @exception ExecutionException if the properties cannot be set */ protected void setInitialProperties(Map properties) throws ExecutionException { @@ -256,16 +267,19 @@ public class Frame { addProperties(System.getProperties()); } + /** * Set the values of various magic properties * - * @exception ExecutionException if the properties cannot be set + * @exception ExecutionException if the properties cannot be set */ protected void setMagicProperties() throws ExecutionException { URL antHomeURL = initConfig.getAntHome(); String antHomeString = null; + if (antHomeURL.getProtocol().equals("file")) { File antHome = new File(antHomeURL.getFile()); + antHomeString = antHome.getAbsolutePath(); } else { antHomeString = antHomeURL.toString(); @@ -273,20 +287,22 @@ public class Frame { setDataValue(MagicProperties.ANT_HOME, antHomeString, true); } + /** * Get a definition from a referenced frame * - * @param definitionName the name of the definition relative to this - * frame - * @return the appropriate import info object from the referenced - * frame's imports - * @exception ExecutionException if the referenced definition cannot be + * @param definitionName the name of the definition relative to + * this frame + * @return the appropriate import info object from + * the referenced frame's imports + * @exception ExecutionException if the referenced definition cannot be * found */ protected ImportInfo getReferencedDefinition(String definitionName) throws ExecutionException { Frame containingFrame = getContainingFrame(definitionName); String localName = getNameInFrame(definitionName); + if (containingFrame == null) { throw new ExecutionException("There is no project corresponding " + "to the name \"" + definitionName + "\""); @@ -298,10 +314,11 @@ public class Frame { } } + /** * Gets the project model this frame is working with * - * @return the project model + * @return the project model */ protected Project getProject() { return project; @@ -313,20 +330,23 @@ public class Frame { * is an expensive operation since it must clone all of the property * stores in all frames * - * @return a Map containing the frames properties indexed by their full + * @return a Map containing the frames properties indexed by their full * name. */ protected Map getAllProperties() { Map allProperties = new HashMap(dataValues); Iterator i = referencedFrames.keySet().iterator(); + while (i.hasNext()) { String refName = (String) i.next(); Frame refFrame = getReferencedFrame(refName); Map refProperties = refFrame.getAllProperties(); Iterator j = refProperties.keySet().iterator(); + while (j.hasNext()) { String name = (String) j.next(); Object value = refProperties.get(name); + allProperties.put(refName + Project.REF_DELIMITER + name, value); } @@ -335,10 +355,11 @@ public class Frame { return allProperties; } + /** * Get the Ant initialization configuration for this frame. * - * @return Ant's initialization configuration + * @return Ant's initialization configuration */ protected InitConfig getInitConfig() { return initConfig; @@ -348,24 +369,27 @@ public class Frame { /** * Get the config instance being used by this frame. * - * @return the config associated with this frame. + * @return the config associated with this frame. */ protected AntConfig getConfig() { return config; } + /** * Get the core's implementation of the given service interface. * - * @param serviceInterfaceClass the service interface for which an + * @param serviceInterfaceClass the service interface for which an * implementation is require - * @return the core's implementation of the service interface - * @exception ExecutionException if the core does not provide an + * @return the core's implementation of the service + * interface + * @exception ExecutionException if the core does not provide an * implementatin of the requested interface */ protected Object getCoreService(Class serviceInterfaceClass) throws ExecutionException { Object service = services.get(serviceInterfaceClass); + if (service == null) { throw new ExecutionException("No service of interface class " + serviceInterfaceClass); @@ -373,69 +397,78 @@ public class Frame { return service; } + /** * Get the EventSupport instance for this frame. This tracks the build * listeners on this frame * - * @return the EventSupport instance + * @return the EventSupport instance */ protected BuildEventSupport getEventSupport() { return eventSupport; } + /** * Gets the baseDir of the Frame * - * @return the baseDir value + * @return the baseDir value */ protected File getBaseDir() { return baseDir; } + /** * Get a referenced frame by its reference name * - * @param referenceName the name under which the frame was imported. - * @return the Frame asscociated with the given reference name or null - * if there is no such project. + * @param referenceName the name under which the frame was imported. + * @return the Frame asscociated with the given reference + * name or null if there is no such project. */ protected Frame getReferencedFrame(String referenceName) { return (Frame) referencedFrames.get(referenceName); } + /** * Get the frames representing referenced projects. * - * @return an iterator which returns the referenced ExeuctionFrames.. + * @return an iterator which returns the referenced ExeuctionFrames.. */ protected Iterator getReferencedFrames() { return referencedFrames.values().iterator(); } + /** * Get the name of an object in its frame * - * @param fullname The name of the object - * @return the name of the object within its containing frame + * @param fullname The name of the object + * @return the name of the object within its containing frame */ protected String getNameInFrame(String fullname) { int index = fullname.lastIndexOf(Project.REF_DELIMITER); + if (index == -1) { return fullname; } return fullname.substring(index + Project.REF_DELIMITER.length()); } + /** * Get a value from this frame or any imported frame * - * @param name the name of the data value - may contain reference - * delimiters - * @return the data value fetched from the appropriate frame - * @exception ExecutionException if the value is not defined + * @param name the name of the data value - may contain + * reference delimiters + * @return the data value fetched from the + * appropriate frame + * @exception ExecutionException if the value is not defined */ protected Object getDataValue(String name) throws ExecutionException { Frame frame = getContainingFrame(name); + if (frame == null) { throw new ExecutionException("There is no project corresponding " + "to the name \"" + name + "\""); @@ -447,17 +480,19 @@ public class Frame { } } + /** * Indicate if a data value has been set * - * @param name the name of the data value - may contain reference - * delimiters - * @return true if the value exists - * @exception ExecutionException if the containing frame for the value + * @param name the name of the data value - may contain + * reference delimiters + * @return true if the value exists + * @exception ExecutionException if the containing frame for the value * does not exist */ protected boolean isDataValueSet(String name) throws ExecutionException { Frame frame = getContainingFrame(name); + if (frame == null) { throw new ExecutionException("There is no project corresponding " + "to the name \"" + name + "\""); @@ -474,12 +509,13 @@ public class Frame { * Get the execution frame which contains, directly, the named element * where the name is relative to this frame * - * @param elementName The name of the element - * @return the execution frame for the project that contains the given - * target + * @param elementName The name of the element + * @return the execution frame for the project that contains + * the given target */ protected Frame getContainingFrame(String elementName) { int index = elementName.lastIndexOf(Project.REF_DELIMITER); + if (index == -1) { return this; } @@ -488,8 +524,10 @@ public class Frame { String relativeName = elementName.substring(0, index); StringTokenizer tokenizer = new StringTokenizer(relativeName, Project.REF_DELIMITER); + while (tokenizer.hasMoreTokens()) { String refName = tokenizer.nextToken(); + currentFrame = currentFrame.getReferencedFrame(refName); if (currentFrame == null) { return null; @@ -499,81 +537,94 @@ public class Frame { return currentFrame; } + /** * Add a collection of properties to this frame * - * @param properties the collection of property values, indexed by their - * names - * @exception ExecutionException if the frame cannot be created. + * @param properties the collection of property values, + * indexed by their names + * @exception ExecutionException if the frame cannot be created. */ protected void addProperties(Map properties) throws ExecutionException { for (Iterator i = properties.keySet().iterator(); i.hasNext();) { String name = (String) i.next(); Object value = properties.get(name); + setDataValue(name, value, false); } } + /** * Create a new frame for a given project * - * @param project the project model the frame will deal with - * @return an Frame ready to build the project - * @exception ExecutionException if the frame cannot be created. + * @param project the project model the frame will deal + * with + * @return an Frame ready to build the project + * @exception ExecutionException if the frame cannot be created. */ protected Frame createFrame(Project project) throws ExecutionException { Frame newFrame = new Frame(standardLibs, initConfig, config); + newFrame.setProject(project); for (Iterator j = eventSupport.getListeners(); j.hasNext();) { BuildListener listener = (BuildListener) j.next(); + newFrame.addBuildListener(listener); } return newFrame; } + /** * Log a message as a build event * - * @param message the message to be logged - * @param level the priority level of the message + * @param message the message to be logged + * @param level the priority level of the message */ protected void log(String message, int level) { eventSupport.fireMessageLogged(project, message, level); } + /** * Add a build listener to this execution frame * - * @param listener the listener to be added to the frame + * @param listener the listener to be added to the frame */ protected void addBuildListener(BuildListener listener) { for (Iterator i = getReferencedFrames(); i.hasNext();) { Frame referencedFrame = (Frame) i.next(); + referencedFrame.addBuildListener(listener); } eventSupport.addBuildListener(listener); } + /** * Remove a build listener from the execution * - * @param listener the listener to be removed + * @param listener the listener to be removed */ protected void removeBuildListener(BuildListener listener) { for (Iterator i = getReferencedFrames(); i.hasNext();) { Frame subFrame = (Frame) i.next(); + subFrame.removeBuildListener(listener); } eventSupport.removeBuildListener(listener); } + /** * Run the given list of targets * - * @param targets a list of target names which are to be evaluated - * @exception ExecutionException if there is a problem in the build + * @param targets a list of target names which are to be + * evaluated + * @exception ExecutionException if there is a problem in the build */ protected void runBuild(List targets) throws ExecutionException { determineBaseDirs(); @@ -582,6 +633,7 @@ public class Frame { if (targets.isEmpty()) { // we just execute the default target if any String defaultTarget = project.getDefaultTarget(); + if (defaultTarget != null) { log("Executing default target: " + defaultTarget, MessageLevel.MSG_DEBUG); @@ -590,18 +642,20 @@ public class Frame { } else { for (Iterator i = targets.iterator(); i.hasNext();) { String targetName = (String) i.next(); + log("Executing target: " + targetName, MessageLevel.MSG_DEBUG); executeTarget(targetName); } } } + /** * Execute the tasks of a target in this frame with the given name * - * @param targetName the name of the target whose tasks will be - * evaluated - * @exception ExecutionException if there is a problem executing the + * @param targetName the name of the target whose tasks will + * be evaluated + * @exception ExecutionException if there is a problem executing the * tasks of the target */ protected void executeTarget(String targetName) throws ExecutionException { @@ -611,10 +665,12 @@ public class Frame { try { // firstly build a list of fully qualified target names to execute. List dependencyOrder = project.getTargetDependencies(targetName); + for (Iterator i = dependencyOrder.iterator(); i.hasNext();) { String fullTargetName = (String) i.next(); Frame frame = getContainingFrame(fullTargetName); String localTargetName = getNameInFrame(fullTargetName); + frame.executeTargetTasks(localTargetName); } } catch (ConfigException e) { @@ -622,25 +678,29 @@ public class Frame { } } + /** * Run the tasks returned by the given iterator * - * @param taskIterator the iterator giving the tasks to execute - * @exception ExecutionException if there is execution problem while + * @param taskIterator the iterator giving the tasks to execute + * @exception ExecutionException if there is execution problem while * executing tasks */ protected void executeTasks(Iterator taskIterator) throws ExecutionException { while (taskIterator.hasNext()) { BuildElement model = (BuildElement) taskIterator.next(); + // what sort of element is this. try { Object component = componentManager.createComponent(model); + if (component instanceof Task) { execService.executeTask((Task) component); } else { String typeId = model.getAspectValue(Constants.ANT_ASPECT, "id"); + if (typeId != null) { setDataValue(typeId, component, true); } @@ -648,25 +708,28 @@ public class Frame { } catch (AntException te) { ExecutionException e = new ExecutionException(te, te.getLocation()); + e.setLocation(model.getLocation(), false); throw e; } catch (RuntimeException e) { ExecutionException ee = new ExecutionException(e.getClass().getName() + ": " + e.getMessage(), e, model.getLocation()); + throw ee; } } } + /** * Execute the given target's tasks. The target must be local to this * frame's project * - * @param targetName the name of the target within this frame that is to - * be executed. - * @exception ExecutionException if there is a problem executing tasks + * @param targetName the name of the target within this frame + * that is to be executed. + * @exception ExecutionException if there is a problem executing tasks */ protected void executeTargetTasks(String targetName) throws ExecutionException { @@ -692,6 +755,7 @@ public class Frame { try { Iterator taskIterator = target.getTasks(); + eventSupport.fireTargetStarted(target); executeTasks(taskIterator); } catch (ExecutionException e) { @@ -702,6 +766,7 @@ public class Frame { ExecutionException ee = new ExecutionException(e.getClass().getName() + ": " + e.getMessage(), e, target.getLocation()); + failureCause = ee; throw ee; } finally { @@ -713,22 +778,26 @@ public class Frame { /** * Initialize the frame by executing the project level tasks if any * - * @exception ExecutionException if the top level tasks of the frame + * @exception ExecutionException if the top level tasks of the frame * failed */ protected void initialize() throws ExecutionException { for (Iterator i = getReferencedFrames(); i.hasNext();) { Frame referencedFrame = (Frame) i.next(); + referencedFrame.initialize(); } + Iterator taskIterator = project.getTasks(); + executeTasks(taskIterator); } + /** * Determine the base directory for each frame in the frame hierarchy * - * @exception ExecutionException if the base directories cannot be + * @exception ExecutionException if the base directories cannot be * determined */ private void determineBaseDirs() throws ExecutionException { @@ -737,14 +806,17 @@ public class Frame { = new File(getDataValue(MagicProperties.BASEDIR).toString()); } else { URL projectURL = project.getSourceURL(); + if (projectURL.getProtocol().equals("file")) { File projectFile = new File(projectURL.getFile()); File projectFileParent = projectFile.getParentFile(); String base = project.getBase(); + if (base == null) { baseDir = projectFileParent; } else { FileUtils fileUtils = FileUtils.newFileUtils(); + baseDir = fileUtils.resolveFile(projectFileParent, base); } } else { @@ -755,10 +827,12 @@ public class Frame { for (Iterator i = getReferencedFrames(); i.hasNext();) { Frame refFrame = (Frame) i.next(); + refFrame.determineBaseDirs(); } } + /** * Configure the services that the frame makes available to its library * components @@ -778,5 +852,19 @@ public class Frame { services.put(EventService.class, new CoreEventService(this)); services.put(ExecService.class, execService); } + + + /** + * Handle the content from a single thread. This method will be called by + * the thread producing the content. The content is broken up into + * separate lines + * + * @param line the content produce by the current thread. + * @param isErr true if this content is from the thread's error stream. + */ + public void threadOutput(String line, boolean isErr) { + eventSupport.threadOutput(line, isErr); + } } +