diff --git a/proposal/mutant/build.xml b/proposal/mutant/build.xml index b5af3e7ab..90f67cdd8 100644 --- a/proposal/mutant/build.xml +++ b/proposal/mutant/build.xml @@ -46,7 +46,7 @@ - + @@ -54,7 +54,7 @@ - + @@ -66,7 +66,7 @@ - + @@ -78,7 +78,7 @@ - + @@ -98,7 +98,7 @@ - + @@ -126,7 +126,7 @@ - + @@ -155,7 +155,7 @@ - + diff --git a/proposal/mutant/build/ant1compat.xml b/proposal/mutant/build/ant1compat.xml index 459456961..c7593bfc4 100644 --- a/proposal/mutant/build/ant1compat.xml +++ b/proposal/mutant/build/ant1compat.xml @@ -431,7 +431,8 @@ - + - + diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ComponentManager.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ComponentManager.java index 96297897b..4aee9573d 100644 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ComponentManager.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ComponentManager.java @@ -184,7 +184,6 @@ public class ComponentManager implements ComponentService { if (importAll || doAuto) { importLibrary(libraryId); } - addAspects((AntLibrary) antLibraries.get(libraryId)); } } catch (MalformedURLException e) { throw new ExecutionException("Unable to load libraries from " @@ -265,6 +264,7 @@ public class ComponentManager implements ComponentService { importLibraryDef(library, defName, null); } addConverters(library); + addAspects(library); } /** @@ -288,6 +288,7 @@ public class ComponentManager implements ComponentService { } importLibraryDef(library, defName, alias); addConverters(library); + addAspects(library); } /** @@ -392,7 +393,7 @@ public class ComponentManager implements ComponentService { return (AntLibFactory) libFactories.get(libraryId); } ExecutionContext context - = new ExecutionContext(frame, null, Location.UNKNOWN_LOCATION); + = new ExecutionContext(frame, null, null); AntLibFactory libFactory = componentLibrary.getFactory(context); if (libFactory == null) { libFactory = new StandardLibFactory(); @@ -511,7 +512,7 @@ public class ComponentManager implements ComponentService { // initialise the component with it. if (execComponent != null) { ExecutionContext context - = new ExecutionContext(frame, execComponent, location); + = new ExecutionContext(frame, execComponent, model); context.setClassLoader(componentLoader); execComponent.init(context, componentName); } @@ -604,98 +605,6 @@ public class ComponentManager implements ComponentService { return setter; } - /** - * Create a component - handles all the variations - * - * @param loader the component's classloader - * @param componentClass The class of the component. - * @param componentName The component's name in the global context - * @param addTaskAdapter whether the component should add a Task adapter - * to make this component a Task. - * @param localName The name of the component within its library - * @param model the BuildElement model of the component's configuration - * @param factory the facrtory object used to create the component - * @return the required component potentially wrapped in a wrapper object. - * @exception ExecutionException if the component cannot be created - */ - private Object createComponent(ClassLoader loader, AntLibFactory factory, - Class componentClass, String componentName, - String localName, boolean addTaskAdapter, - BuildElement model) - throws ExecutionException { - // set the location to unknown unless we have a build model to use - Location location = Location.UNKNOWN_LOCATION; - if (model != null) { - location = model.getLocation(); - } - - try { - // create the component using the factory - Object component - = factory.createComponent(componentClass, localName); - - // wrap the component in an adapter if required. - ExecutionComponent execComponent = null; - if (addTaskAdapter) { - if (component instanceof Task) { - execComponent = (Task) component; - } else { - execComponent = new TaskAdapter(componentName, component); - } - } else if (component instanceof ExecutionComponent) { - execComponent = (ExecutionComponent) component; - } - - // set the context loader to that for the component - ClassLoader currentLoader - = LoaderUtils.setContextLoader(loader); - - // if the component is an execution component create a context and - // initialise the component with it. - if (execComponent != null) { - ExecutionContext context - = new ExecutionContext(frame, execComponent, location); - context.setClassLoader(loader); - execComponent.init(context, componentName); - } - - // if we have a model, use it to configure the component. Otherwise - // the caller is expected to configure thre object - if (model != null) { - configureElement(factory, component, model); - // if the component is an execution component and we have a - // model, validate it - if (execComponent != null) { - execComponent.validateComponent(); - } - } - - // reset the loader - LoaderUtils.setContextLoader(currentLoader); - - // if we have an execution component, potentially a wrapper, - // return it otherwise the component directly - if (execComponent != null) { - return execComponent; - } else { - return component; - } - } catch (InstantiationException e) { - throw new ExecutionException("Unable to instantiate component " - + "class " + componentClass.getName() + " for component <" - + componentName + ">", e, location); - } catch (IllegalAccessException e) { - throw new ExecutionException("Unable to access task class " - + componentClass.getName() + " for component <" - + componentName + ">", e, location); - } catch (ExecutionException e) { - e.setLocation(location, false); - throw e; - } catch (RuntimeException e) { - throw new ExecutionException(e, location); - } - } - /** * Create an instance of a type given its required class * @@ -718,8 +627,8 @@ public class ComponentManager implements ComponentService { if (typeInstance instanceof ExecutionComponent) { ExecutionComponent component = (ExecutionComponent) typeInstance; - ExecutionContext context = new ExecutionContext(frame, - component, model.getLocation()); + ExecutionContext context + = new ExecutionContext(frame, component, model); component.init(context, localName); configureElement(libFactory, typeInstance, model); component.validateComponent(); @@ -761,8 +670,10 @@ public class ComponentManager implements ComponentService { Class nestedType = setter.getType(nestedElementName); // is there a polymorph indicator - look in Ant aspects - String typeName = model.getAspectValue(Constants.ANT_ASPECT, "type"); - String refId = model.getAspectValue(Constants.ANT_ASPECT, "refid"); + String typeName + = model.getAspectAttributeValue(Constants.ANT_ASPECT, "type"); + String refId + = model.getAspectAttributeValue(Constants.ANT_ASPECT, "refid"); if (refId != null && typeName != null) { throw new ExecutionException("Only one of " + Constants.ANT_ASPECT + ":type and " + Constants.ANT_ASPECT @@ -849,8 +760,8 @@ public class ComponentManager implements ComponentService { if (nestedElement instanceof ExecutionComponent) { ExecutionComponent component = (ExecutionComponent) nestedElement; - ExecutionContext context = new ExecutionContext(frame, - component, model.getLocation()); + ExecutionContext context + = new ExecutionContext(frame, component, model); component.init(context, nestedElementName); configureElement(factory, nestedElement, model); component.validateComponent(); @@ -865,6 +776,30 @@ public class ComponentManager implements ComponentService { } } + /** + * configure an object with attribtes from the given map + * + * @param object the object to be configured. + * @param attributeValues a map containing named attribute values. + * + * @exception ExecutionException if the object does not support an + * attribute in the map. + */ + public void configureAttributes(Object object, Map attributeValues) + throws ExecutionException { + Setter setter = getSetter(object.getClass()); + for (Iterator i = attributeValues.keySet().iterator(); i.hasNext();) { + String attributeName = (String) i.next(); + String attributeValue = (String) attributeValues.get(attributeName); + if (!setter.supportsAttribute(attributeName)) { + throw new ExecutionException(object.getClass().getName() + + " does not support the \"" + attributeName + + "\" attribute"); + } + setter.setAttribute(object, attributeName, + frame.replacePropertyRefs(attributeValue)); + } + } /** * Configure an element according to the given model. @@ -985,8 +920,8 @@ public class ComponentManager implements ComponentService { + " does not implement the Aspect interface"); } Aspect aspect = (Aspect) libFactory.createInstance(aspectClass); - ExecutionContext context = new ExecutionContext(frame, - null, Location.UNKNOWN_LOCATION); + ExecutionContext context + = new ExecutionContext(frame, null, null); aspect.init(context); aspects.add(aspect); } @@ -1045,8 +980,8 @@ public class ComponentManager implements ComponentService { } Converter converter = (Converter) libFactory.createInstance(converterClass); - ExecutionContext context = new ExecutionContext(frame, - null, Location.UNKNOWN_LOCATION); + ExecutionContext context + = new ExecutionContext(frame, null, null); converter.init(context); Class[] converterTypes = converter.getTypes(); for (int j = 0; j < converterTypes.length; ++j) { diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/CoreExecService.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/CoreExecService.java index 889624e00..2f17c4521 100644 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/CoreExecService.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/CoreExecService.java @@ -60,10 +60,13 @@ import java.util.Map; import org.apache.ant.antcore.modelparser.XMLProjectParser; import org.apache.ant.antcore.xml.XMLParseException; import org.apache.ant.common.antlib.Task; +import org.apache.ant.common.antlib.AntContext; import org.apache.ant.common.model.Project; +import org.apache.ant.common.model.BuildElement; import org.apache.ant.common.service.ExecService; import org.apache.ant.common.util.ExecutionException; import org.apache.ant.init.InitUtils; +import org.apache.ant.common.model.AspectValueCollection; /** * This is the core's implementation of the Execution Service. @@ -98,8 +101,54 @@ public class CoreExecService implements ExecService { * @exception ExecutionException if there is an execution problem */ public void executeTask(Task task) throws ExecutionException { - frame.executeTask(task); + ExecutionContext execContext = getTaskExecutionContext(task); + + BuildElement model = execContext.getModel(); + AspectValueCollection aspectValues = null; + if (model != null) { + aspectValues = model.getAspectAttributes(); + } + frame.executeTask(task, aspectValues); + } + + /** + * Retrieve the execution context from a task and verify that the context + * is valid. + * + * @param task the task. + * @return the task's execution context. + * + * @exception ExecutionException if the task's context is not valid. + */ + private ExecutionContext getTaskExecutionContext(Task task) + throws ExecutionException { + AntContext context = task.getAntContext(); + + if (!(context instanceof ExecutionContext)) { + throw new ExecutionException("The Task was not configured with an" + + " appropriate context"); + } + return (ExecutionContext) context; + } + + /** + * Execute a task with a set of aspect values. Normally aspect values come + * from a build model but not all tasks will be created from a build model. + * Some may be created dynamically and configured programatically. This + * method allows aspect values to provided for execution of such tasks since + * by their nature, aspect values are not part of the task configuration. + * + * @param task the task to be executed + * @param aspectValues the aspect attribute values. + * @exception ExecutionException if there is an execution problem + */ + public void executeTask(Task task, AspectValueCollection aspectValues) + throws ExecutionException { + ExecutionContext execContext = getTaskExecutionContext(task); + + frame.executeTask(task, aspectValues); } + /** diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ExecutionContext.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ExecutionContext.java index 2287a4ca7..c91539c7f 100755 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ExecutionContext.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ExecutionContext.java @@ -56,6 +56,7 @@ import org.apache.ant.common.antlib.AntContext; import org.apache.ant.common.antlib.ExecutionComponent; import org.apache.ant.common.util.ExecutionException; import org.apache.ant.common.util.Location; +import org.apache.ant.common.model.BuildElement; /** * This is the core's implementation of the AntContext for all core objects. @@ -71,8 +72,8 @@ public class ExecutionContext implements AntContext { /** the event support instance used to manage build events */ private BuildEventSupport eventSupport; - /** The location of the object associated with this context */ - private Location location; + /** The build model associated with this context. */ + private BuildElement model; /** the execution component associated with the context, if any */ private ExecutionComponent component; @@ -89,13 +90,13 @@ public class ExecutionContext implements AntContext { * * @param frame the frame containing this context * @param component the component associated with this context - may be null - * @param location the location associated with the component + * @param model the build model associated with this component if any. */ protected ExecutionContext(Frame frame, ExecutionComponent component, - Location location) { + BuildElement model) { this.frame = frame; this.eventSupport = frame.getEventSupport(); - this.location = location; + this.model = model; this.component = component; } @@ -120,7 +121,10 @@ public class ExecutionContext implements AntContext { * @return the location in the build model associated with this context. */ public Location getLocation() { - return location; + if (model == null) { + return Location.UNKNOWN_LOCATION; + } + return model.getLocation(); } /** @@ -166,5 +170,14 @@ public class ExecutionContext implements AntContext { protected ExecutionComponent getExecutionComponent() { return component; } + + /** + * Get the build model associated with this context. + * + * @return the build model or null if there is no build model. + */ + protected BuildElement getModel() { + return model; + } } 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 b963d8d2a..301009df6 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 @@ -65,12 +65,12 @@ import java.util.Set; import org.apache.ant.antcore.config.AntConfig; import org.apache.ant.common.antlib.Task; import org.apache.ant.common.antlib.Aspect; -import org.apache.ant.common.antlib.AntContext; import org.apache.ant.common.event.BuildListener; import org.apache.ant.common.event.MessageLevel; import org.apache.ant.common.model.BuildElement; import org.apache.ant.common.model.Project; import org.apache.ant.common.model.Target; +import org.apache.ant.common.model.AspectValueCollection; import org.apache.ant.common.service.ComponentService; import org.apache.ant.common.service.DataService; import org.apache.ant.common.service.EventService; @@ -860,36 +860,32 @@ public class Frame implements DemuxOutputReceiver { } /** - * Execute a task notifiying all registered aspects of the fact - * - * @param task the Task instance to execute. + * Execute a task with the given aspect values. * + * @param task the task to be executed. + * @param aspectValues the collection of aspect attribute values. * @exception ExecutionException if the task has a problem. */ - protected void executeTask(Task task) throws ExecutionException { + protected void executeTask(Task task, AspectValueCollection aspectValues) + throws ExecutionException { List aspects = componentManager.getAspects(); Map aspectContexts = new HashMap(); for (Iterator i = aspects.iterator(); i.hasNext();) { Aspect aspect = (Aspect) i.next(); - Object context = aspect.preExecuteTask(task); - aspectContexts.put(aspect, context); + Object aspectContext = aspect.preExecuteTask(task, aspectValues); + if (aspectContext != null) { + aspectContexts.put(aspect, aspectContext); + } } if (aspectContexts.size() != 0) { aspectContextsMap.put(task, aspectContexts); } - AntContext context = task.getAntContext(); - - if (!(context instanceof ExecutionContext)) { - throw new ExecutionException("The Task was not configured with an" - + " appropriate context"); - } - ExecutionContext execContext = (ExecutionContext) context; - eventSupport.fireTaskStarted(task); Throwable failureCause = null; + ExecutionContext execContext = (ExecutionContext) task.getAntContext(); try { ClassLoader currentLoader = LoaderUtils.setContextLoader(execContext.getClassLoader()); @@ -949,7 +945,7 @@ public class Frame implements DemuxOutputReceiver { } if (component instanceof Task) { - executeTask((Task) component); + execService.executeTask((Task) component); } } catch (ExecutionException e) { e.setLocation(model.getLocation(), false); diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/BuildElementHandler.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/BuildElementHandler.java index 7695ff754..df406840e 100644 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/BuildElementHandler.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/BuildElementHandler.java @@ -93,7 +93,7 @@ public class BuildElementHandler extends ModelElementHandler { buildElement.addAttribute(attributeName, getAttribute(attributeName)); } - buildElement.setAspects(getAspects()); + buildElement.addAspectAttributes(getAspectAttributes()); } diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/ProjectHandler.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/ProjectHandler.java index 7b37970a6..1d8db526b 100644 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/ProjectHandler.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/ProjectHandler.java @@ -133,7 +133,7 @@ public class ProjectHandler extends ModelElementHandler { project.setDefaultTarget(getAttribute(DEFAULT_ATTR)); project.setBase(getAttribute(BASEDIR_ATTR)); project.setName(getAttribute(NAME_ATTR)); - project.setAspects(getAspects()); + project.addAspectAttributes(getAspectAttributes()); } } diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/TargetHandler.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/TargetHandler.java index 2f98316c6..5469f3f25 100644 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/TargetHandler.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/TargetHandler.java @@ -105,7 +105,7 @@ public class TargetHandler extends ModelElementHandler { target = new Target(getLocation(), getAttribute(NAME_ATTR)); setModelElement(target); target.setDescription(getAttribute(DESC_ATTR)); - target.setAspects(getAspects()); + target.addAspectAttributes(getAspectAttributes()); String depends = getAttribute(DEPENDS_ATTR); if (depends != null) { diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/xml/ElementHandler.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/xml/ElementHandler.java index 189302a68..6e576eff3 100755 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/xml/ElementHandler.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/xml/ElementHandler.java @@ -101,7 +101,7 @@ public abstract class ElementHandler extends DefaultHandler { private Map elementAttributes; /** The aspect attributes read from the element definition */ - private Map aspects; + private Map aspectAttributes; /** The content of this element */ private String content; @@ -150,8 +150,8 @@ public abstract class ElementHandler extends DefaultHandler { * * @return The aspect attributes. */ - public Map getAspects() { - return aspects; + public Map getAspectAttributes() { + return aspectAttributes; } /** @@ -313,14 +313,14 @@ public abstract class ElementHandler extends DefaultHandler { */ protected final void processAttributes(Attributes attributes) throws SAXParseException { - aspects = new HashMap(); + aspectAttributes = new HashMap(); elementAttributes = new HashMap(); int length = attributes.getLength(); for (int i = 0; i < length; ++i) { String attributeName = attributes.getQName(i); String attributeValue = attributes.getValue(i); if (attributeName.indexOf(":") != -1) { - aspects.put(attributeName, attributeValue); + aspectAttributes.put(attributeName, attributeValue); } else { validateAttribute(attributeName, attributeValue); elementAttributes.put(attributeName, attributeValue); diff --git a/proposal/mutant/src/java/antlibs/system/org/apache/ant/antlib/system/AntAspect.java b/proposal/mutant/src/java/antlibs/system/org/apache/ant/antlib/system/AntAspect.java index 0cefe5c10..0a1eea592 100644 --- a/proposal/mutant/src/java/antlibs/system/org/apache/ant/antlib/system/AntAspect.java +++ b/proposal/mutant/src/java/antlibs/system/org/apache/ant/antlib/system/AntAspect.java @@ -52,11 +52,16 @@ * . */ package org.apache.ant.antlib.system; + +import java.util.Map; import org.apache.ant.common.antlib.AbstractAspect; import org.apache.ant.common.antlib.AntContext; +import org.apache.ant.common.antlib.Task; import org.apache.ant.common.service.DataService; +import org.apache.ant.common.service.ComponentService; import org.apache.ant.common.util.ExecutionException; import org.apache.ant.common.model.BuildElement; +import org.apache.ant.common.model.AspectValueCollection; /** * The Ant aspect - handles all ant aspects @@ -70,6 +75,9 @@ public class AntAspect extends AbstractAspect { /** The core's data service implementation */ private DataService dataService = null; + /** The core's component service */ + private ComponentService componentService = null; + /** * Initialise the aspect with a context. * @@ -79,6 +87,8 @@ public class AntAspect extends AbstractAspect { public void init(AntContext context) throws ExecutionException { super.init(context); dataService = (DataService) context.getCoreService(DataService.class); + componentService + = (ComponentService) context.getCoreService(ComponentService.class); } /** @@ -95,7 +105,7 @@ public class AntAspect extends AbstractAspect { */ public Object postCreateComponent(Object component, BuildElement model) throws ExecutionException { - String typeId = model.getAspectValue(ANT_ASPECT, "id"); + String typeId = model.getAspectAttributeValue(ANT_ASPECT, "id"); if (typeId != null) { dataService.setMutableDataValue(typeId, component); @@ -103,5 +113,51 @@ public class AntAspect extends AbstractAspect { return null; } + + /** + * This join point is activated just prior to task execution. + * + * @param task the task being executed. + * @param aspectValues a collection of aspect attribute values for use + * during the task execution. + * + * @return an objectwhich indicates that this aspect wishes to + * be notified after execution has been completed, in which case the obkect + * is returned to provide the aspect its context. If this returns null + * the aspect's postExecuteTask method will not be invoked. + * @exception ExecutionException if the aspect cannot process the task. + */ + public Object preExecuteTask(Task task, AspectValueCollection aspectValues) + throws ExecutionException { + AntAspectContext aspectContext = new AntAspectContext(); + Map antAspectValues = aspectValues.getAttributes(ANT_ASPECT); + if (antAspectValues == null) { + return null; + } + + componentService.configureAttributes(aspectContext, antAspectValues); + if (aspectContext.isRequired()) { + return aspectContext; + } + return null; + } + + /** + * This join point is activated after a task has executed. The aspect + * may override the task's failure cause by returning a new failure. + * + * @param context the context the aspect provided in preExecuteTask. + * @param failureCause the current failure reason for the task. + * + * @return a new failure reason or null if the task is not to fail. + */ + public Throwable postExecuteTask(Object context, Throwable failureCause) { + AntAspectContext aspectContext = (AntAspectContext) context; + if (!aspectContext.getFailOnError()) { + return null; + } + return super.postExecuteTask(context, failureCause); + } + } diff --git a/proposal/mutant/src/java/antlibs/system/org/apache/ant/antlib/system/AntAspectContext.java b/proposal/mutant/src/java/antlibs/system/org/apache/ant/antlib/system/AntAspectContext.java new file mode 100644 index 000000000..00ec71df4 --- /dev/null +++ b/proposal/mutant/src/java/antlibs/system/org/apache/ant/antlib/system/AntAspectContext.java @@ -0,0 +1,94 @@ +/* + * The Apache Software License, Version 1.1 + * + * 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: + * + * 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 + * . + */ +package org.apache.ant.antlib.system; + +/** + * The context for the Ant Aspect + * + * @author Conor MacNeill + */ +public class AntAspectContext { + /** Indicates if the task's execution should not fail */ + private boolean failOnError = true; + + /** + * Set the flag covering whether a task failure halts the build. + * + * @param failOnError false if the build should continue. + */ + public void setFailOnError(boolean failOnError) { + this.failOnError = failOnError; + } + + /** + * Indicate whether a task failure halts the build. + * + * @return true if a task error causes the build to fail. + */ + public boolean getFailOnError() { + return failOnError; + } + + /** + * Indicate if this aspect context is required - i.e. whether the + * aspect needs to be reactivated after task execution + * + * @return true if the context should be used and the aspect reactivated + * after task execution. + */ + public boolean isRequired() { + return failOnError != true; + } +} + diff --git a/proposal/mutant/src/java/common/org/apache/ant/common/antlib/AbstractAspect.java b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/AbstractAspect.java index a762ca8c2..01fdd1b0f 100644 --- a/proposal/mutant/src/java/common/org/apache/ant/common/antlib/AbstractAspect.java +++ b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/AbstractAspect.java @@ -55,6 +55,7 @@ package org.apache.ant.common.antlib; import org.apache.ant.common.util.ExecutionException; import org.apache.ant.common.model.BuildElement; +import org.apache.ant.common.model.AspectValueCollection; /** * An implementation of the Aspect interface providing default behaviour. @@ -109,14 +110,17 @@ public class AbstractAspect implements Aspect { * This join point is activated just prior to task execution. * * @param task the task being executed. + * @param aspectValues a collection of aspect attribute values for use + * during the task execution. * - * @return an objectwhich indicates that this aspect wishes to + * @return an object which indicates that this aspect wishes to * be notified after execution has been completed, in which case the obkect * is returned to provide the aspect its context. If this returns null * the aspect's postExecuteTask method will not be invoked. * @exception ExecutionException if the aspect cannot process the task. */ - public Object preExecuteTask(Task task) throws ExecutionException { + public Object preExecuteTask(Task task, AspectValueCollection aspectValues) + throws ExecutionException { return null; } diff --git a/proposal/mutant/src/java/common/org/apache/ant/common/antlib/AntContext.java b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/AntContext.java index 02770ce99..58946bcce 100644 --- a/proposal/mutant/src/java/common/org/apache/ant/common/antlib/AntContext.java +++ b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/AntContext.java @@ -88,15 +88,8 @@ public interface AntContext { /** * Gets the location associated with the AntContext * - * @return the location + * @return the location which may be the unknown location */ Location getLocation(); - - /** - * Get the classloader associated with this context - * - * @return a classloader instance. - */ - ClassLoader getClassLoader(); } diff --git a/proposal/mutant/src/java/common/org/apache/ant/common/antlib/Aspect.java b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/Aspect.java index bf07fe3ff..3e3efdbb4 100644 --- a/proposal/mutant/src/java/common/org/apache/ant/common/antlib/Aspect.java +++ b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/Aspect.java @@ -55,6 +55,7 @@ package org.apache.ant.common.antlib; import org.apache.ant.common.util.ExecutionException; import org.apache.ant.common.model.BuildElement; +import org.apache.ant.common.model.AspectValueCollection; /** * An aspect is a component which is activated across all task and @@ -93,14 +94,17 @@ public interface Aspect { * This join point is activated just prior to task execution. * * @param task the task being executed. - * - * @return an objectwhich indicates that this aspect wishes to + * @param aspectValues a collection of aspect attribute values for use + * during the task execution - may be null if no aspect values are + * provided. + * @return an object which indicates that this aspect wishes to * be notified after execution has been completed, in which case the obkect * is returned to provide the aspect its context. If this returns null * the aspect's postExecuteTask method will not be invoked. * @exception ExecutionException if the aspect cannot process the task. */ - Object preExecuteTask(Task task) throws ExecutionException; + Object preExecuteTask(Task task, AspectValueCollection aspectValues) + throws ExecutionException; /** * This join point is activated after a task has executed. The aspect diff --git a/proposal/mutant/src/java/common/org/apache/ant/common/model/AspectValueCollection.java b/proposal/mutant/src/java/common/org/apache/ant/common/model/AspectValueCollection.java new file mode 100644 index 000000000..3c0f6db46 --- /dev/null +++ b/proposal/mutant/src/java/common/org/apache/ant/common/model/AspectValueCollection.java @@ -0,0 +1,134 @@ +/* + * The Apache Software License, Version 1.1 + * + * 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: + * + * 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 + * . + */ +package org.apache.ant.common.model; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * The AspectValueCollection holds aspect values for a range of aspects. + * Values can be retrieved for a particular aspect attribute or all attributes + * of a given aspect. + * + * @author Conor MacNeill + * @created 11 January 2002 + */ +public class AspectValueCollection { + /** The aspects defined for this element. */ + private Map aspectMaps = new HashMap(); + + /** + * Set the aspect attribute values. + * + * The attributes are sorted into their various aspects + * + * @param attributes a Map of aspect attributes values. The keys are the + * aspect + */ + public void addAttributes(Map attributes) { + for (Iterator i = attributes.keySet().iterator(); i.hasNext();) { + String attributeName = (String) i.next(); + int separator = attributeName.indexOf(":"); + if (separator != -1) { + String aspectName = attributeName.substring(0, separator); + String name = attributeName.substring(separator + 1); + if (aspectName.length() != 0 && name.length() != 0) { + Map prefixMap = (Map) aspectMaps.get(aspectName); + if (prefixMap == null) { + prefixMap = new HashMap(); + aspectMaps.put(aspectName, prefixMap); + } + prefixMap.put(name, attributes.get(attributeName)); + } + } + } + } + + /** + * Get an iterator on the aspects which have been given values on this + * element + * + * @return an iterator of Strings , being the aspects which have been + * given values on this element. + */ + public Iterator getNames() { + return aspectMaps.keySet().iterator(); + } + + /** + * Get the set of attribute values related to the given aspect + * + * @param aspectName the aspect name + * @return a map of the attribute values for the given aspect. + */ + public Map getAttributes(String aspectName) { + return (Map) aspectMaps.get(aspectName); + } + + /** + * Get the value of a single aspect attribute + * + * @param aspectName the prefix which identifies the aspectr + * @param keyName the attribute name + * @return the aspect value + */ + public String getAttributeValue(String aspectName, String keyName) { + Map aspectAttributes = getAttributes(aspectName); + if (aspectAttributes == null) { + return null; + } + return (String) aspectAttributes.get(keyName); + } +} + diff --git a/proposal/mutant/src/java/common/org/apache/ant/common/model/ModelElement.java b/proposal/mutant/src/java/common/org/apache/ant/common/model/ModelElement.java index 4c84b12af..4bb9643d4 100644 --- a/proposal/mutant/src/java/common/org/apache/ant/common/model/ModelElement.java +++ b/proposal/mutant/src/java/common/org/apache/ant/common/model/ModelElement.java @@ -52,7 +52,7 @@ * . */ package org.apache.ant.common.model; -import java.util.HashMap; + import java.util.Iterator; import java.util.Map; @@ -67,8 +67,8 @@ import org.apache.ant.common.util.Location; * @created 11 January 2002 */ public abstract class ModelElement { - /** The aspects defined for this element. */ - private Map aspectMaps; + /** The aspectValues defined for this element. */ + private AspectValueCollection aspectValues = new AspectValueCollection(); /** The starting location of this element */ private Location location = Location.UNKNOWN_LOCATION; @@ -107,28 +107,13 @@ public abstract class ModelElement { } /** - * Set the aspects of this element + * Adds aspect related attributes of this element * - * @param aspects a Map of apects that relate to this model element. + * @param aspectAttributes a Map of aspect realted attributes that pertain + * to this model element. */ - public void setAspects(Map aspects) { - aspectMaps = new HashMap(); - for (Iterator i = aspects.keySet().iterator(); i.hasNext();) { - String aspectName = (String) i.next(); - int separator = aspectName.indexOf(":"); - if (separator != -1) { - String prefix = aspectName.substring(0, separator); - String name = aspectName.substring(separator + 1); - if (prefix.length() != 0 && name.length() != 0) { - Map prefixMap = (Map) aspectMaps.get(prefix); - if (prefixMap == null) { - prefixMap = new HashMap(); - aspectMaps.put(prefix, prefixMap); - } - prefixMap.put(name, aspects.get(aspectName)); - } - } - } + public void addAspectAttributes(Map aspectAttributes) { + aspectValues.addAttributes(aspectAttributes); } /** @@ -159,39 +144,44 @@ public abstract class ModelElement { } /** - * Get an iterator on the aspects which have been given values on this + * Get an iterator on the aspectValues which have been given values on this * element * - * @return an iterator of Strings , being the aspects which have been + * @return an iterator of Strings , being the aspectValues which have been * given values on this element. */ public Iterator getAspectNames() { - return aspectMaps.keySet().iterator(); + return aspectValues.getNames(); } /** * Get the set of attribute values related to the given aspect * - * @param aspectPrefix the aspect identifier + * @param aspectName the aspect identifier * @return a map of the attribute values for the given aspect. */ - public Map getAspectAttributes(String aspectPrefix) { - return (Map) aspectMaps.get(aspectPrefix); + public Map getAspectAttributes(String aspectName) { + return aspectValues.getAttributes(aspectName); } /** * Get the value of a single aspect attribute * - * @param aspectPrefix the prefix which identifies the aspectr + * @param aspectName the aspect name * @param keyName the attribute name * @return the aspect value */ - public String getAspectValue(String aspectPrefix, String keyName) { - Map aspectAttributes = getAspectAttributes(aspectPrefix); - if (aspectAttributes == null) { - return null; - } - return (String) aspectAttributes.get(keyName); + public String getAspectAttributeValue(String aspectName, String keyName) { + return aspectValues.getAttributeValue(aspectName, keyName); + } + + /** + * Get the complete collection of aspect attribute values. + * + * @return an AspectValueCollection instance. + */ + public AspectValueCollection getAspectAttributes() { + return aspectValues; } } diff --git a/proposal/mutant/src/java/common/org/apache/ant/common/service/ComponentService.java b/proposal/mutant/src/java/common/org/apache/ant/common/service/ComponentService.java index d4b8f66a7..885375adf 100644 --- a/proposal/mutant/src/java/common/org/apache/ant/common/service/ComponentService.java +++ b/proposal/mutant/src/java/common/org/apache/ant/common/service/ComponentService.java @@ -53,9 +53,11 @@ */ package org.apache.ant.common.service; import java.net.URL; +import java.util.Map; import org.apache.ant.common.antlib.AntLibFactory; import org.apache.ant.common.util.ExecutionException; + /** * The Component Service is used to manage the definitions that Ant uses at * runtime. It supports the following operations @@ -186,5 +188,17 @@ public interface ComponentService { */ Object createComponent(String libraryId, String localName) throws ExecutionException; + + /** + * Configure an object with attribtes from the given map + * + * @param object the object to be configured. + * @param attributeValues a map containing named attribute values. + * + * @exception ExecutionException if the object does not support an + * attribute in the map. + */ + void configureAttributes(Object object, Map attributeValues) + throws ExecutionException; } diff --git a/proposal/mutant/src/java/common/org/apache/ant/common/service/ExecService.java b/proposal/mutant/src/java/common/org/apache/ant/common/service/ExecService.java index 7f73f59aa..35f6bf99c 100644 --- a/proposal/mutant/src/java/common/org/apache/ant/common/service/ExecService.java +++ b/proposal/mutant/src/java/common/org/apache/ant/common/service/ExecService.java @@ -58,6 +58,7 @@ import java.util.Map; import org.apache.ant.common.antlib.Task; import org.apache.ant.common.model.Project; import org.apache.ant.common.util.ExecutionException; +import org.apache.ant.common.model.AspectValueCollection; /** * The ExecService provides executiuon services to tasks @@ -133,6 +134,21 @@ public interface ExecService { void executeTask(Task task) throws ExecutionException; + /** + * Execute a task with a set of aspect values. Normally aspect values come + * from a build model but not all tasks will be created from a build model. + * Some may be created dynamically and configured programatically. This + * method allows aspect values to provided for execution of such tasks since + * by their nature, aspect values are not part of the task configuration. + * + * @param task the task to be executed + * @param aspectValues the aspect attribute values. + * @exception ExecutionException if there is an execution problem + */ + void executeTask(Task task, AspectValueCollection aspectValues) + throws ExecutionException; + + /** * get the name of the project associated with this execution. *