diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/antlib/AntLibHandler.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/antlib/AntLibHandler.java index 705930f5d..4a63541fb 100755 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/antlib/AntLibHandler.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/antlib/AntLibHandler.java @@ -144,12 +144,17 @@ public class AntLibHandler extends ElementHandler { antLibrarySpec.addDefinition(defnHandler.getDefinitionType(), defnHandler.getName(), defnHandler.getClassName()); } else if (qualifiedName.equals("converter")) { - ClassNameHandler converterHandler - = new ClassNameHandler(); + ClassNameHandler converterHandler = new ClassNameHandler(); converterHandler.start(getParseContext(), getXMLReader(), this, getLocator(), attributes, getElementSource(), qualifiedName); antLibrarySpec.addConverter(converterHandler.getClassName()); + } else if (qualifiedName.equals("aspect")) { + ClassNameHandler aspectHandler = new ClassNameHandler(); + aspectHandler.start(getParseContext(), getXMLReader(), + this, getLocator(), attributes, getElementSource(), + qualifiedName); + antLibrarySpec.addAspect(aspectHandler.getClassName()); } else if (qualifiedName.equals("factory")) { ClassNameHandler factoryHandler = new ClassNameHandler(); diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/antlib/AntLibManager.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/antlib/AntLibManager.java index bb8f131ef..da6880e8e 100644 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/antlib/AntLibManager.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/antlib/AntLibManager.java @@ -60,6 +60,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.HashMap; import org.apache.ant.antcore.xml.ParseContext; import org.apache.ant.antcore.xml.XMLParseException; import org.apache.ant.common.util.CircularDependencyChecker; @@ -153,10 +154,11 @@ public class AntLibManager { * @param initConfig the Ant initialization configuration * @param libraries the collection of libraries already configured * @param libPathsMap a map of lists of library paths for each library + * @return A map of the newly configured libraries * @exception ExecutionException if a library cannot be configured from * the given specification */ - public void configLibraries(InitConfig initConfig, Map librarySpecs, + public Map configLibraries(InitConfig initConfig, Map librarySpecs, Map libraries, Map libPathsMap) throws ExecutionException { @@ -180,15 +182,18 @@ public class AntLibManager { } } + Map newLibraries = new HashMap(); CircularDependencyChecker configuring = new CircularDependencyChecker("configuring Ant libraries"); for (Iterator i = librarySpecs.keySet().iterator(); i.hasNext();) { String libraryId = (String) i.next(); if (!libraries.containsKey(libraryId)) { configLibrary(initConfig, librarySpecs, libraryId, - configuring, libraries, libPathsMap); + configuring, libraries, newLibraries, libPathsMap); } } + + return newLibraries; } /** @@ -267,13 +272,14 @@ public class AntLibManager { * dependencies. * @param libraries the collection of libraries which have already been * configured + * @param newLibraries the new libraries being configured. * @param libPathsMap a map of lists of library patsh fro each library * @exception ExecutionException if the library cannot be configured. */ private void configLibrary(InitConfig initConfig, Map librarySpecs, String libraryId, CircularDependencyChecker configuring, - Map libraries, Map libPathsMap) + Map libraries, Map newLibraries, Map libPathsMap) throws ExecutionException { try { @@ -283,14 +289,15 @@ public class AntLibManager { = (AntLibrarySpec) librarySpecs.get(libraryId); String extendsId = librarySpec.getExtendsLibraryId(); if (extendsId != null) { - if (!libraries.containsKey(extendsId)) { + if (!libraries.containsKey(extendsId) && + !newLibraries.containsKey(extendsId)) { if (!librarySpecs.containsKey(extendsId)) { throw new ExecutionException("Could not find library, " + extendsId + ", upon which library " + libraryId + " depends"); } configLibrary(initConfig, librarySpecs, extendsId, - configuring, libraries, libPathsMap); + configuring, libraries, newLibraries, libPathsMap); } } @@ -323,10 +330,14 @@ public class AntLibManager { if (extendsId != null) { AntLibrary extendsLibrary = (AntLibrary) libraries.get(extendsId); + if (extendsLibrary == null) { + extendsLibrary = (AntLibrary) newLibraries.get(extendsId); + } + antLibrary.setExtendsLibrary(extendsLibrary); } antLibrary.setParentLoader(initConfig.getCommonLoader()); - libraries.put(libraryId, antLibrary); + newLibraries.put(libraryId, antLibrary); if (libPathsMap != null) { List libPaths = (List) libPathsMap.get(libraryId); diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/antlib/AntLibrary.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/antlib/AntLibrary.java index 234dccf11..a0d186072 100755 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/antlib/AntLibrary.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/antlib/AntLibrary.java @@ -88,6 +88,9 @@ public class AntLibrary implements ComponentLibrary { /** The list of converter classnames defined in this library */ private List converterClassNames = new ArrayList(); + /** The list of aspect classnames defined in this library */ + private List aspectClassNames = new ArrayList(); + /** The class name of this library's factory class, if any */ private String factoryClassName; @@ -116,6 +119,7 @@ public class AntLibrary implements ComponentLibrary { this.definitions = spec.getDefinitions(); this.isolated = spec.isIsolated(); this.converterClassNames.addAll(spec.getConverters()); + this.aspectClassNames.addAll(spec.getAspects()); this.factoryClassName = spec.getFactory(); this.definitionURL = spec.getLibraryURL(); } @@ -182,7 +186,7 @@ public class AntLibrary implements ComponentLibrary { } /** - * Gets an the converter class names of the AntLibrary + * Gets the converter class names of the AntLibrary * * @return an iterator over a list of String class names */ @@ -190,6 +194,15 @@ public class AntLibrary implements ComponentLibrary { return converterClassNames.iterator(); } + /** + * Gets the aspect class names of the AntLibrary + * + * @return an iterator over a list of String class names + */ + public Iterator getAspectClassNames() { + return aspectClassNames.iterator(); + } + /** * Get the URL to where the library was loaded from * @@ -251,6 +264,15 @@ public class AntLibrary implements ComponentLibrary { return !converterClassNames.isEmpty(); } + /** + * Indicate whether this library has any aspects defined + * + * @return true if any aspects have been defined + */ + public boolean hasAspects() { + return !aspectClassNames.isEmpty(); + } + /** * Add a library to path to this AntLibrary definition * diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/antlib/AntLibrarySpec.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/antlib/AntLibrarySpec.java index 130e2a451..3550eeb17 100755 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/antlib/AntLibrarySpec.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/antlib/AntLibrarySpec.java @@ -85,6 +85,9 @@ public class AntLibrarySpec { /** The list of converter classnames defined in this library */ private List converterClassNames = new ArrayList(); + /** The list of aspect classnames defined in this library */ + private List aspectClassNames = new ArrayList(); + /** The name of the factory class for this library */ private String factoryClassName; @@ -196,6 +199,16 @@ public class AntLibrarySpec { return converterClassNames; } + + /** + * Get the list of aspect classnames defined in this library spec + * + * @return the aspect classnames list + */ + public List getAspects() { + return aspectClassNames; + } + /** * Gets the factory classname of the AntLibrarySpec * @@ -262,7 +275,7 @@ public class AntLibrarySpec { } /** - * Add a converter to this library sec + * Add a converter to this library spec * * @param className the name of the converter class */ @@ -270,6 +283,15 @@ public class AntLibrarySpec { converterClassNames.add(className); } + /** + * Add an aspect to this the library spec + * + * @param className the name of the aspect class + */ + public void addAspect(String className) { + aspectClassNames.add(className); + } + /** * Indicates if this library requires Ant's XML parser * 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 eff357c63..96297897b 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 @@ -66,7 +66,9 @@ import org.apache.ant.antcore.antlib.AntLibManager; import org.apache.ant.antcore.antlib.AntLibrary; import org.apache.ant.antcore.antlib.ComponentLibrary; import org.apache.ant.antcore.antlib.DynamicLibrary; +import org.apache.ant.antcore.config.AntConfig; import org.apache.ant.common.antlib.AntLibFactory; +import org.apache.ant.common.antlib.Aspect; import org.apache.ant.common.antlib.Converter; import org.apache.ant.common.antlib.DeferredTask; import org.apache.ant.common.antlib.ExecutionComponent; @@ -79,16 +81,21 @@ import org.apache.ant.common.service.ComponentService; import org.apache.ant.common.util.ExecutionException; import org.apache.ant.common.util.Location; import org.apache.ant.init.LoaderUtils; -import org.apache.ant.antcore.config.AntConfig; /** - * The instance of the ComponentServices made available by the core to the - * ant libraries. + * The instance of the ComponentServices made available by the core to the ant + * libraries. * * @author Conor MacNeill * @created 27 January 2002 */ public class ComponentManager implements ComponentService { + + /** + * These are AntLibraries which have been loaded into this component + * manager + */ + private static Map antLibraries = new HashMap(); /** * Type converters for this frame. Converters are used when configuring * Tasks to handle special type conversions. @@ -98,6 +105,9 @@ public class ComponentManager implements ComponentService { /** This is the set of libraries whose converters have been loaded */ private Set loadedConverters = new HashSet(); + /** This is the set of libraries whose aspects have been loaded */ + private Set loadedAspects = new HashSet(); + /** The factory objects for each library, indexed by the library Id */ private Map libFactories = new HashMap(); @@ -108,20 +118,20 @@ public class ComponentManager implements ComponentService { private AntLibManager libManager; /** - * These are AntLibraries which have been loaded into this component - * manager + * This is the list of aspects which have been loaded from the various Ant + * libraries */ - private static Map antLibraries = new HashMap(); + private List aspects = new ArrayList(); /** dynamic libraries which have been defined */ private Map dynamicLibraries; /** The definitions which have been imported into this frame. */ - private Map definitions = new HashMap(); + private Map imports = new HashMap(); /** - * This map stores a list of additional paths for each library indexed - * by the libraryId + * This map stores a list of additional paths for each library indexed by + * the libraryId */ private Map libPathsMap = new HashMap(); @@ -133,8 +143,11 @@ public class ComponentManager implements ComponentService { * Constructor * * @param frame the frame containing this context + * + * @exception ExecutionException if the loaded libraries could not be + * imported. */ - protected ComponentManager(Frame frame) { + protected ComponentManager(Frame frame) throws ExecutionException { this.frame = frame; AntConfig config = frame.getConfig(); libManager = new AntLibManager(config.isRemoteLibAllowed()); @@ -150,7 +163,7 @@ public class ComponentManager implements ComponentService { * @param importAll if true all tasks are imported as the library is * loaded * @param autoImport true if libraries in the Ant namespace should be - * automatically imported. + * automatically imported. * @exception ExecutionException if the library cannot be loaded */ public void loadLib(String libLocation, boolean importAll, @@ -159,17 +172,19 @@ public class ComponentManager implements ComponentService { try { Map librarySpecs = new HashMap(); libManager.loadLibs(librarySpecs, libLocation); - libManager.configLibraries(frame.getInitConfig(), librarySpecs, - antLibraries, libPathsMap); + Map newLibraries = libManager.configLibraries(frame.getInitConfig(), + librarySpecs, antLibraries, libPathsMap); - Iterator i = librarySpecs.keySet().iterator(); + antLibraries.putAll(newLibraries); + Iterator i = antLibraries.keySet().iterator(); while (i.hasNext()) { String libraryId = (String) i.next(); - boolean doAuto = autoImport - && libraryId.startsWith(Constants.ANT_LIB_PREFIX); + boolean doAuto = autoImport + && libraryId.startsWith(Constants.ANT_LIB_PREFIX); if (importAll || doAuto) { importLibrary(libraryId); } + addAspects((AntLibrary) antLibraries.get(libraryId)); } } catch (MalformedURLException e) { throw new ExecutionException("Unable to load libraries from " @@ -181,8 +196,7 @@ public class ComponentManager implements ComponentService { * Experimental - define a new task * * @param taskName the name by which this task will be referred - * @param factory the library factory object to create the task - * instances + * @param factory the library factory object to create the task instances * @param loader the class loader to use to create the particular tasks * @param className the name of the class implementing the task * @exception ExecutionException if the task cannot be defined @@ -198,8 +212,7 @@ public class ComponentManager implements ComponentService { * Experimental - define a new type * * @param typeName the name by which this type will be referred - * @param factory the library factory object to create the type - * instances + * @param factory the library factory object to create the type instances * @param loader the class loader to use to create the particular types * @param className the name of the class implementing the type * @exception ExecutionException if the type cannot be defined @@ -251,15 +264,15 @@ public class ComponentManager implements ComponentService { String defName = (String) i.next(); importLibraryDef(library, defName, null); } - addLibraryConverters(library); + addConverters(library); } /** * Import a single component from a library, optionally aliasing it to a * new name * - * @param libraryId the unique id of the library from which the - * component is being imported + * @param libraryId the unique id of the library from which the component + * is being imported * @param defName the name of the component within its library * @param alias the name under which this component will be used in the * build scripts. If this is null, the components default name is @@ -274,11 +287,11 @@ public class ComponentManager implements ComponentService { + "library \"" + libraryId + "\" as it has not been loaded"); } importLibraryDef(library, defName, alias); - addLibraryConverters(library); + addConverters(library); } /** - * Imports a component defined in a nother frame. + * Imports a component defined in another frame. * * @param relativeName the qualified name of the component relative to * this execution frame @@ -306,7 +319,7 @@ public class ComponentManager implements ComponentService { + "> as <" + label + "> from library \"" + definition.getComponentLibrary().getLibraryId() + "\", class: " + definition.getClassName(), MessageLevel.MSG_DEBUG); - definitions.put(label, definition); + imports.put(label, definition); } /** @@ -321,30 +334,36 @@ public class ComponentManager implements ComponentService { */ public Object createComponent(String componentName) throws ExecutionException { - return createComponent(componentName, null); + return createComponent(componentName, (BuildElement) null); } /** - * Create a component given its class. The component will have a context - * but will not be configured. It should be configured using the - * appropriate set methods and then validated before being used. + * Create a component given its libraryId and local name within the + * library. This method is unambiguous in the face of imports, aliases and + * taskdefs performed in the build. * - * @param componentClass the component's class - * @param factory the factory to create the component - * @param loader the classloader associated with the component - * @param addTaskAdapter whenther the returned component should be a - * task, potentially being wrapped in an adapter - * @param componentName the name of the component type + * @param libraryId the component's library identifier. + * @param localName the name component within the library. * @return the created component. The return type of this method depends * on the component type. * @exception ExecutionException if the component cannot be created */ - public Object createComponent(AntLibFactory factory, ClassLoader loader, - Class componentClass, boolean addTaskAdapter, - String componentName) + public Object createComponent(String libraryId, String localName) throws ExecutionException { - return createComponent(loader, factory, componentClass, - componentName, componentName, addTaskAdapter, null); + AntLibrary library + = (AntLibrary) antLibraries.get(libraryId); + if (library == null) { + throw new ExecutionException("No library with libraryId \"" + + libraryId + "\" is available"); + } + + AntLibDefinition libDefinition = library.getDefinition(localName); + if (libDefinition == null) { + throw new ExecutionException("No component with name \"" + + localName + "\" was found in library with libraryId \"" + + libraryId + "\""); + } + return createComponentFromDef(localName, library, libDefinition, null); } /** @@ -361,8 +380,8 @@ public class ComponentManager implements ComponentService { * Get the collection of Ant Libraries defined for this frame Gets the * factory object for the given library * - * @param componentLibrary the compnent library for which a factory - * objetc is required + * @param componentLibrary the compnent library for which a factory objetc + * is required * @return the library's factory object * @exception ExecutionException if the factory cannot be created */ @@ -386,11 +405,11 @@ public class ComponentManager implements ComponentService { * Get an imported definition from the component manager * * @param name the name under which the component has been imported - * @return the ImportInfo object detailing the import's library and - * other details + * @return the ImportInfo object detailing the import's library and other + * details */ - protected ImportInfo getDefinition(String name) { - return (ImportInfo) definitions.get(name); + protected ImportInfo getImport(String name) { + return (ImportInfo) imports.get(name); } /** @@ -409,10 +428,11 @@ public class ComponentManager implements ComponentService { } /** - * Create a component. + * Create a component. This method creates a component and then configures + * it from the given build model. * - * @param componentName the name of the component which is used to - * select the object type to be created + * @param componentName the name of the component which is used to select + * the object type to be created * @param model the build model of the component. If this is null, the * component is created but not configured. * @return the configured component @@ -422,38 +442,119 @@ public class ComponentManager implements ComponentService { protected Object createComponent(String componentName, BuildElement model) throws ExecutionException { - Location location = Location.UNKNOWN_LOCATION; - if (model != null) { - location = model.getLocation(); - } - ImportInfo definition = getDefinition(componentName); - if (definition == null) { + ImportInfo importInfo = getImport(componentName); + if (importInfo == null) { throw new ExecutionException("There is no definition of the <" + componentName + "> component"); } - String className = definition.getClassName(); + String className = importInfo.getClassName(); ComponentLibrary componentLibrary - = definition.getComponentLibrary(); - boolean isTask = definition.getDefinitionType() == AntLibrary.TASKDEF; - String localName = definition.getLocalName(); + = importInfo.getComponentLibrary(); + + return createComponentFromDef(componentName, componentLibrary, + importInfo.getDefinition(), model); + } + + /** + * Create a component from its library definition. + * + * @param componentName The component's name in the global context + * @param componentLibrary the library which provides the deifnition of + * the component + * @param libDefinition the component's definition + * @param model the BuildElement model of the component's configuration. + * @return the required component potentially wrapped in a wrapper object. + * @exception ExecutionException if the component cannot be created + */ + private Object createComponentFromDef(String componentName, + ComponentLibrary componentLibrary, + AntLibDefinition libDefinition, + BuildElement model) + throws ExecutionException { + + Location location = Location.UNKNOWN_LOCATION; + if (model != null) { + location = model.getLocation(); + } + + boolean isTask + = libDefinition.getDefinitionType() == AntLibrary.TASKDEF; + String localName = libDefinition.getDefinitionName(); + String className = libDefinition.getClassName(); try { ClassLoader componentLoader = componentLibrary.getClassLoader(); Class componentClass = Class.forName(className, true, componentLoader); AntLibFactory libFactory = getLibFactory(componentLibrary); - return createComponent(componentLoader, libFactory, componentClass, - componentName, localName, isTask, model); + // create the component using the factory + Object component + = libFactory.createComponent(componentClass, localName); + + // wrap the component in an adapter if required. + ExecutionComponent execComponent = null; + if (isTask) { + 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(componentLoader); + + // 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(componentLoader); + 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(libFactory, 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 (ClassNotFoundException e) { throw new ExecutionException("Class " + className + " for component <" + componentName + "> was not found", e, location); } catch (NoClassDefFoundError e) { throw new ExecutionException("Could not load a dependent class (" - + e.getMessage() + ") for component " + componentName, - e, location); + + e.getMessage() + ") for component " + componentName, e, + location); + } catch (InstantiationException e) { + throw new ExecutionException("Unable to instantiate component " + + "class " + className + " for component <" + + componentName + ">", e, location); + } catch (IllegalAccessException e) { + throw new ExecutionException("Unable to access task class " + + className + " for component <" + + componentName + ">", e, location); } catch (ExecutionException e) { - e.setLocation(model.getLocation(), false); + e.setLocation(location, false); throw e; } } @@ -477,7 +578,7 @@ public class ComponentManager implements ComponentService { frame.log("Adding component <" + defName + "> as <" + label + "> from library \"" + library.getLibraryId() + "\", class: " + libDef.getClassName(), MessageLevel.MSG_DEBUG); - definitions.put(label, new ImportInfo(library, libDef)); + imports.put(label, new ImportInfo(library, libDef)); } /** @@ -514,8 +615,7 @@ public class ComponentManager implements ComponentService { * @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. + * @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, @@ -616,8 +716,8 @@ public class ComponentManager implements ComponentService { = libFactory.createComponent(typeClass, localName); if (typeInstance instanceof ExecutionComponent) { - ExecutionComponent component - = (ExecutionComponent) typeInstance; + ExecutionComponent component + = (ExecutionComponent) typeInstance; ExecutionContext context = new ExecutionContext(frame, component, model.getLocation()); component.init(context, localName); @@ -650,8 +750,8 @@ public class ComponentManager implements ComponentService { * @param element the container element in which the nested element will * be created * @param model the model of the nested element - * @param factory Ant Library factory associated with the element to - * which the attribute is to be added. + * @param factory Ant Library factory associated with the element to which + * the attribute is to be added. * @exception ExecutionException if the nested element cannot be created */ private void addNestedElement(AntLibFactory factory, Setter setter, @@ -734,10 +834,9 @@ public class ComponentManager implements ComponentService { * @param element the container object for which a nested element is * required. * @param model the build model for the nestd element - * @param factory Ant Library factory associated with the element - * creating the nested element - * @exception ExecutionException if the nested element cannot be - * created. + * @param factory Ant Library factory associated with the element creating + * the nested element + * @exception ExecutionException if the nested element cannot be created. */ private void createNestedElement(AntLibFactory factory, Setter setter, Object element, BuildElement model) @@ -807,7 +906,7 @@ public class ComponentManager implements ComponentService { for (Iterator i = model.getNestedElements(); i.hasNext();) { BuildElement nestedElementModel = (BuildElement) i.next(); String nestedElementName = nestedElementModel.getType(); - ImportInfo info = getDefinition(nestedElementName); + ImportInfo info = getImport(nestedElementName); if (element instanceof TaskContainer && info != null && info.getDefinitionType() == AntLibrary.TASKDEF @@ -858,6 +957,63 @@ public class ComponentManager implements ComponentService { } + /** + * Load any apsects from the given library. + * + * @param library the library from which the aspects are to be loaded. + * + * @exception ExecutionException if an aspect cannot be loaded. + */ + private void addAspects(AntLibrary library) throws ExecutionException { + if (!library.hasAspects() + || loadedAspects.contains(library.getLibraryId())) { + return; + } + + String className = null; + try { + AntLibFactory libFactory = getLibFactory(library); + ClassLoader aspectLoader = library.getClassLoader(); + for (Iterator i = library.getAspectClassNames(); i.hasNext();) { + className = (String) i.next(); + Class aspectClass + = Class.forName(className, true, aspectLoader); + if (!Aspect.class.isAssignableFrom(aspectClass)) { + throw new ExecutionException("In Ant library \"" + + library.getLibraryId() + "\" the aspect class " + + aspectClass.getName() + + " does not implement the Aspect interface"); + } + Aspect aspect = (Aspect) libFactory.createInstance(aspectClass); + ExecutionContext context = new ExecutionContext(frame, + null, Location.UNKNOWN_LOCATION); + aspect.init(context); + aspects.add(aspect); + } + loadedAspects.add(library.getLibraryId()); + } catch (ClassNotFoundException e) { + throw new ExecutionException("In Ant library \"" + + library.getLibraryId() + "\" aspect class " + + className + " was not found", e); + } catch (NoClassDefFoundError e) { + throw new ExecutionException("In Ant library \"" + + library.getLibraryId() + + "\" could not load a dependent class (" + + e.getMessage() + ") for aspect " + className); + } catch (InstantiationException e) { + throw new ExecutionException("In Ant library \"" + + library.getLibraryId() + + "\" unable to instantiate aspect class " + + className, e); + } catch (IllegalAccessException e) { + throw new ExecutionException("In Ant library \"" + + library.getLibraryId() + + "\" unable to access aspect class " + + className, e); + } + } + + /** * Add the converters from the given library to those managed by this * frame. @@ -866,7 +1022,7 @@ public class ComponentManager implements ComponentService { * @exception ExecutionException if a converter defined in the library * cannot be instantiated */ - private void addLibraryConverters(AntLibrary library) + private void addConverters(AntLibrary library) throws ExecutionException { if (!library.hasConverters() || loadedConverters.contains(library.getLibraryId())) { @@ -888,7 +1044,7 @@ public class ComponentManager implements ComponentService { + " does not implement the Converter interface"); } Converter converter - = libFactory.createConverter(converterClass); + = (Converter) libFactory.createInstance(converterClass); ExecutionContext context = new ExecutionContext(frame, null, Location.UNKNOWN_LOCATION); converter.init(context); @@ -919,5 +1075,14 @@ public class ComponentManager implements ComponentService { + className, e); } } + + /** + * Get the aspects which have been registered from ant libraries. + * + * @return the list of Aspect instances currently defined. + */ + protected List getAspects() { + return aspects; + } } 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 a12ffc767..889624e00 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 @@ -59,13 +59,11 @@ import java.util.List; import java.util.Map; import org.apache.ant.antcore.modelparser.XMLProjectParser; import org.apache.ant.antcore.xml.XMLParseException; -import org.apache.ant.common.antlib.AntContext; import org.apache.ant.common.antlib.Task; import org.apache.ant.common.model.Project; import org.apache.ant.common.service.ExecService; import org.apache.ant.common.util.ExecutionException; import org.apache.ant.init.InitUtils; -import org.apache.ant.init.LoaderUtils; /** * This is the core's implementation of the Execution Service. @@ -100,36 +98,7 @@ public class CoreExecService implements ExecService { * @exception ExecutionException if there is an execution problem */ public void executeTask(Task task) throws ExecutionException { - AntContext context = task.getAntContext(); - - if (!(context instanceof ExecutionContext)) { - throw new ExecutionException("The Task was not configured with an" - + " appropriate context"); - } - ExecutionContext execContext = (ExecutionContext) context; - - frame.getEventSupport().fireTaskStarted(task); - - Throwable failureCause = null; - - try { - ClassLoader currentLoader - = LoaderUtils.setContextLoader(execContext.getClassLoader()); - - task.execute(); - LoaderUtils.setContextLoader(currentLoader); - } catch (ExecutionException e) { - failureCause = e; - throw e; - } catch (Throwable e) { - ExecutionException ee = - new ExecutionException(e); - - failureCause = ee; - throw ee; - } finally { - frame.getEventSupport().fireTaskFinished(task, failureCause); - } + frame.executeTask(task); } 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 2965147e1..d5112be95 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 @@ -148,9 +148,11 @@ public class ExecutionManager implements DemuxOutputReceiver { } catch (RuntimeException e) { buildFailureCause = e; throw e; - } catch (AntException e) { + } catch (ExecutionException e) { + ExecutionException ee = e instanceof ExecutionException + ? e : new ExecutionException(e); buildFailureCause = e; - throw e; + throw ee; } finally { eventSupport.fireBuildFinished(project, buildFailureCause); } 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 fe59c5465..b963d8d2a 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 @@ -61,8 +61,11 @@ import java.util.Map; import java.util.StringTokenizer; import java.util.List; import java.util.ArrayList; +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; @@ -79,6 +82,7 @@ import org.apache.ant.common.util.DemuxOutputReceiver; import org.apache.ant.common.util.ExecutionException; import org.apache.ant.common.util.FileUtils; import org.apache.ant.init.InitConfig; +import org.apache.ant.init.LoaderUtils; /** * An Frame maintains the state of a project during an execution. The Frame @@ -98,6 +102,13 @@ public class Frame implements DemuxOutputReceiver { /** The referenced frames corresponding to the referenced projects */ private Map referencedFrames = new HashMap(); + /** + * This is a Map of Maps. This map is keyed on an executing task. + * Each entry is itself a Map of Aspects to their context for the + * particular task. + */ + private Map aspectContextsMap = new HashMap(); + /** * The property overrides for the referenced frames. This map is indexed * by the reference names of the frame. Each entry is another Map of @@ -390,7 +401,7 @@ public class Frame implements DemuxOutputReceiver { + "to the name \"" + definitionName + "\""); } if (containingFrame == this) { - return componentManager.getDefinition(localName); + return componentManager.getImport(localName); } else { return containingFrame.getReferencedDefinition(localName); } @@ -656,8 +667,6 @@ public class Frame implements DemuxOutputReceiver { referencedFrame.setInitialProperties(initialProperties); overrides.remove(name); } - - referencedFrames.put(name, referencedFrame); referencedFrame.initialize(); @@ -850,6 +859,68 @@ public class Frame implements DemuxOutputReceiver { } } + /** + * Execute a task notifiying all registered aspects of the fact + * + * @param task the Task instance to execute. + * + * @exception ExecutionException if the task has a problem. + */ + protected void executeTask(Task task) 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); + } + 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; + + try { + ClassLoader currentLoader + = LoaderUtils.setContextLoader(execContext.getClassLoader()); + + task.execute(); + LoaderUtils.setContextLoader(currentLoader); + } catch (Throwable e) { + failureCause = e; + } + + // Now call back the aspects that registered interest + Set activeAspects = aspectContexts.keySet(); + for (Iterator i = activeAspects.iterator(); i.hasNext();) { + Aspect aspect = (Aspect) i.next(); + Object aspectContext = aspectContexts.get(aspect); + failureCause + = aspect.postExecuteTask(aspectContext, failureCause); + } + eventSupport.fireTaskFinished(task, failureCause); + if (aspectContexts.size() != 0) { + aspectContextsMap.remove(task); + } + + if (failureCause != null) { + if (failureCause instanceof ExecutionException) { + throw (ExecutionException) failureCause; + } + throw new ExecutionException(failureCause); + } + } + /** * Run the tasks returned by the given iterator @@ -860,23 +931,26 @@ public class Frame implements DemuxOutputReceiver { */ protected void executeTasks(Iterator taskIterator) throws ExecutionException { + while (taskIterator.hasNext()) { BuildElement model = (BuildElement) taskIterator.next(); // what sort of element is this. + List aspects = componentManager.getAspects(); 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); + for (Iterator i = aspects.iterator(); i.hasNext();) { + Aspect aspect = (Aspect) i.next(); + Object replacement + = aspect.postCreateComponent(component, model); + if (replacement != null) { + component = replacement; } } + + if (component instanceof Task) { + executeTask((Task) component); + } } catch (ExecutionException e) { e.setLocation(model.getLocation(), false); throw e; @@ -1009,8 +1083,11 @@ public class Frame implements DemuxOutputReceiver { /** * Configure the services that the frame makes available to its library * components + * + * @exception ExecutionException if the services required by the core + * could not be configured. */ - private void configureServices() { + private void configureServices() throws ExecutionException { // create services and make them available in our services map fileService = new CoreFileService(this); componentManager = new ComponentManager(this); diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ImportInfo.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ImportInfo.java index 8c38ee83e..0539d829e 100644 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ImportInfo.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ImportInfo.java @@ -116,5 +116,13 @@ public class ImportInfo { return libDefinition.getDefinitionName(); } + /** + * Get the definition of the imported component. + * + * @return the component's library definition. + */ + public AntLibDefinition getDefinition() { + return libDefinition; + } } diff --git a/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/Ant1Factory.java b/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/Ant1Factory.java index 47102c3a8..56def0204 100644 --- a/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/Ant1Factory.java +++ b/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/Ant1Factory.java @@ -53,7 +53,6 @@ */ package org.apache.tools.ant; import org.apache.ant.common.antlib.AntContext; -import org.apache.ant.common.antlib.Converter; import org.apache.ant.common.antlib.StandardLibFactory; import org.apache.ant.common.service.EventService; import org.apache.ant.common.util.ExecutionException; @@ -145,40 +144,41 @@ public class Ant1Factory extends StandardLibFactory { } /** - * Create a converter. + * Create an instance of the given class * - * @param converterClass the class of the converter. - * @return an instance of the requested converter class - * @exception InstantiationException if the converter cannot be - * instantiated - * @exception IllegalAccessException if the converter cannot be accessed - * @exception ExecutionException if the converter cannot be created + * @param requiredClass the class for which an instance is + * required + * @return a instance of the required class + * @exception InstantiationException if the class cannot be instantiated + * @exception IllegalAccessException if the instance cannot be accessed + * @exception ExecutionException if there is a problem creating the + * converter */ - public Converter createConverter(Class converterClass) + public Object createInstance(Class requiredClass) throws InstantiationException, IllegalAccessException, ExecutionException { java.lang.reflect.Constructor c = null; - Converter converter = null; + Object instance = null; try { try { - c = converterClass.getConstructor(new Class[0]); - converter = (Converter) c.newInstance(new Object[0]); + c = requiredClass.getConstructor(new Class[0]); + instance = c.newInstance(new Object[0]); } catch (NoSuchMethodException nse) { - c = converterClass.getConstructor(new Class[]{Project.class}); - converter = (Converter) c.newInstance(new Object[]{project}); + c = requiredClass.getConstructor(new Class[]{Project.class}); + instance = c.newInstance(new Object[]{project}); } - return converter; + return instance; } catch (java.lang.reflect.InvocationTargetException ite) { Throwable t = ite.getTargetException(); - String msg = "Could not create converter of type: " - + converterClass.getName() + " due to " + t; + String msg = "Could not create instance of type: " + + requiredClass.getName() + " due to " + t; throw new ExecutionException(msg, t); } catch (NoSuchMethodException e) { throw new ExecutionException("Unable to find an appropriate " - + "constructor for converter " + converterClass.getName(), e); + + "constructor for class " + requiredClass.getName(), e); } } diff --git a/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/Project.java b/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/Project.java index 37e00d568..31f33d5a6 100644 --- a/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/Project.java +++ b/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/Project.java @@ -1058,8 +1058,7 @@ public class Project implements org.apache.ant.common.event.BuildListener { } try { - Object taskObject = componentService.createComponent(factory, - context.getClassLoader(), taskClass, false, taskType); + Object taskObject = componentService.createComponent(taskType); if (taskObject instanceof Task) { task = (Task) taskObject; } else { @@ -1093,9 +1092,7 @@ public class Project implements org.apache.ant.common.event.BuildListener { } try { - Object dataInstance = componentService.createComponent(factory, - context.getClassLoader(), typeClass, false, typeName); - return dataInstance; + return componentService.createComponent(typeName); } catch (Throwable e) { throw new BuildException(e); } diff --git a/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/taskdefs/Ant.java b/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/taskdefs/Ant.java index bd0481bfa..00016ef14 100644 --- a/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/taskdefs/Ant.java +++ b/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/taskdefs/Ant.java @@ -146,9 +146,7 @@ public class Ant extends Task { ComponentService componentService = getComponentService(); AntLibFactory factory = getProject().getFactory(); realAnt = (org.apache.ant.antlib.system.Ant) - componentService.createComponent(factory, - context.getClassLoader(), - org.apache.ant.antlib.system.Ant.class, false, "antcall"); + componentService.createComponent("ant.system", "ant"); } catch (ExecutionException e) { throw new BuildException(e); } diff --git a/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/taskdefs/CallTarget.java b/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/taskdefs/CallTarget.java index bfc3f42c2..e09156e07 100644 --- a/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/taskdefs/CallTarget.java +++ b/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/taskdefs/CallTarget.java @@ -102,8 +102,8 @@ public class CallTarget extends Task { try { ComponentService componentService = getComponentService(); AntLibFactory factory = getProject().getFactory(); - antCall = (AntCall) componentService.createComponent(factory, - context.getClassLoader(), AntCall.class, false, "antcall"); + antCall = (AntCall) componentService.createComponent("ant.system", + "antcall"); } catch (ExecutionException e) { throw new BuildException(e); } diff --git a/proposal/mutant/src/java/antlibs/system/antlib.xml b/proposal/mutant/src/java/antlibs/system/antlib.xml index 21424666e..dc9282b53 100644 --- a/proposal/mutant/src/java/antlibs/system/antlib.xml +++ b/proposal/mutant/src/java/antlibs/system/antlib.xml @@ -15,5 +15,7 @@ - + + + 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 new file mode 100644 index 000000000..0cefe5c10 --- /dev/null +++ b/proposal/mutant/src/java/antlibs/system/org/apache/ant/antlib/system/AntAspect.java @@ -0,0 +1,107 @@ +/* + * 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; +import org.apache.ant.common.antlib.AbstractAspect; +import org.apache.ant.common.antlib.AntContext; +import org.apache.ant.common.service.DataService; +import org.apache.ant.common.util.ExecutionException; +import org.apache.ant.common.model.BuildElement; + +/** + * The Ant aspect - handles all ant aspects + * + * @author Conor MacNeill + */ +public class AntAspect extends AbstractAspect { + /** The Ant aspect used to identify Ant metadata */ + public static final String ANT_ASPECT = "ant"; + + /** The core's data service implementation */ + private DataService dataService = null; + + /** + * Initialise the aspect with a context. + * + * @param context the aspect's context + * @exception ExecutionException if the aspect cannot be initialised + */ + public void init(AntContext context) throws ExecutionException { + super.init(context); + dataService = (DataService) context.getCoreService(DataService.class); + } + + /** + * This join point is activated after a component has been created and + * configured. If the aspect wishes, an object can be returned in place + * of the one created by Ant. + * + * @param component the component that has been created. + * @param model the Build model used to create the component. + * + * @return a replacement for the component if desired. If null is returned + * the current component is used. + * @exception ExecutionException if the component cannot be processed. + */ + public Object postCreateComponent(Object component, BuildElement model) + throws ExecutionException { + String typeId = model.getAspectValue(ANT_ASPECT, "id"); + + if (typeId != null) { + dataService.setMutableDataValue(typeId, component); + } + + return null; + } +} + 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 new file mode 100644 index 000000000..a762ca8c2 --- /dev/null +++ b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/AbstractAspect.java @@ -0,0 +1,162 @@ +/* + * 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.antlib; + +import org.apache.ant.common.util.ExecutionException; +import org.apache.ant.common.model.BuildElement; + +/** + * An implementation of the Aspect interface providing default behaviour. + * + * @author Conor MacNeill + */ +public class AbstractAspect implements Aspect { + /** + * The Ant context for this aspect which can be used to access core + * services. + */ + private AntContext context; + + /** + * Initialise the aspect with a context. + * + * @param context the aspect's context + * @exception ExecutionException if the aspect cannot be initialised + */ + public void init(AntContext context) throws ExecutionException { + this.context = context; + } + + /** + * Get this aspect's context + * + * @return the aspect context + */ + protected AntContext getAntContext() { + return context; + } + + + /** + * This join point is activated after a component has been created and + * configured. If the aspect wishes, an object can be returned in place + * of the one created by Ant. + * + * @param component the component that has been created. + * @param model the Build model used to create the component. + * + * @return a replacement for the component if desired. If null is returned + * the current component is used. + * @exception ExecutionException if the aspect cannot process the component. + */ + public Object postCreateComponent(Object component, BuildElement model) + throws ExecutionException { + return null; + } + + /** + * 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 + * 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 { + 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) { + return failureCause; + } + + /** + * This point is activated when the task is to receive output that has + * been sent to output stream and redirected into the task. + * + * @param context the context the aspect provided in preExecuteTask. + * @param line the content sent to the output stream. + * + * @return the line to be forwarded onto the task. + */ + public String taskOutput(Object context, String line) { + return line; + } + + /** + * This point is activated when the task is to receive error content that + * has been sent to error stream and redirected into the task. + * + * @param context the context the aspect provided in preExecuteTask. + * @param line the content sent to the error stream. + * + * @return the line to be forwarded onto the task. + */ + public String taskError(Object context, String line) { + return line; + } +} + diff --git a/proposal/mutant/src/java/common/org/apache/ant/common/antlib/AntLibFactory.java b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/AntLibFactory.java index 4d0fe43a5..aa51713ad 100644 --- a/proposal/mutant/src/java/common/org/apache/ant/common/antlib/AntLibFactory.java +++ b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/AntLibFactory.java @@ -88,17 +88,17 @@ public interface AntLibFactory { ExecutionException; /** - * Create an instance of the given converter class + * Create an instance of the given class * - * @param converterClass the converter class for which an instance is + * @param requiredClass the class for which an instance is * required - * @return a converter instance + * @return a instance of the required class * @exception InstantiationException if the class cannot be instantiated * @exception IllegalAccessException if the instance cannot be accessed * @exception ExecutionException if there is a problem creating the * converter */ - Converter createConverter(Class converterClass) + Object createInstance(Class requiredClass) throws InstantiationException, IllegalAccessException, ExecutionException; 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 new file mode 100644 index 000000000..bf07fe3ff --- /dev/null +++ b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/Aspect.java @@ -0,0 +1,138 @@ +/* + * 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.antlib; + +import org.apache.ant.common.util.ExecutionException; +import org.apache.ant.common.model.BuildElement; + +/** + * An aspect is a component which is activated across all task and + * component operations. It allows a single implmentation to be applied + * to a number of tasks without requiring changes to the task implementations. + * + * @author Conor MacNeill + */ +public interface Aspect { + /** + * Initialise the aspect with a context. + * + * @param context the aspect's context + * @exception ExecutionException if the aspect cannot be initialised + */ + void init(AntContext context) + throws ExecutionException; + + + /** + * This join point is activated after a component has been created and + * configured. If the aspect wishes, an object can be returned in place + * of the one created by Ant. + * + * @param component the component that has been created. + * @param model the Build model used to create the component. + * + * @return a replacement for the component if desired. If null is returned + * the current component is used. + * @exception ExecutionException if the aspect cannot process the component. + */ + Object postCreateComponent(Object component, BuildElement model) + throws ExecutionException; + + /** + * 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 + * 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; + + /** + * 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. + */ + Throwable postExecuteTask(Object context, Throwable failureCause); + + /** + * This point is activated when the task is to receive output that has + * been sent to output stream and redirected into the task. + * + * @param context the context the aspect provided in preExecuteTask. + * @param line the content sent to the output stream. + * + * @return the line to be forwarded onto the task. + */ + String taskOutput(Object context, String line); + + /** + * This point is activated when the task is to receive error content that + * has been sent to error stream and redirected into the task. + * + * @param context the context the aspect provided in preExecuteTask. + * @param line the content sent to the error stream. + * + * @return the line to be forwarded onto the task. + */ + String taskError(Object context, String line); +} + diff --git a/proposal/mutant/src/java/common/org/apache/ant/common/antlib/ExecutionComponent.java b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/ExecutionComponent.java index 4240c35dc..066c5bfee 100644 --- a/proposal/mutant/src/java/common/org/apache/ant/common/antlib/ExecutionComponent.java +++ b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/ExecutionComponent.java @@ -63,10 +63,10 @@ import org.apache.ant.common.util.ExecutionException; */ public interface ExecutionComponent { /** - * Initialise the task. The task may use the AntContext to request + * Initialise the component. The component may use the AntContext to request * services from the Ant core. * - * @param context the Task's context + * @param context the Component's context * @param componentType the type of the component * @exception ExecutionException if the component cannot be initialised */ diff --git a/proposal/mutant/src/java/common/org/apache/ant/common/antlib/StandardLibFactory.java b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/StandardLibFactory.java index 81b5f5589..633091c87 100644 --- a/proposal/mutant/src/java/common/org/apache/ant/common/antlib/StandardLibFactory.java +++ b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/StandardLibFactory.java @@ -93,20 +93,20 @@ public class StandardLibFactory implements AntLibFactory { } /** - * Create an instance of the given converter class + * Create an instance of the given class * - * @param converterClass the converter class for which an instance is + * @param requiredClass the class for which an instance is * required - * @return a converter instance + * @return a instance of the required class * @exception InstantiationException if the class cannot be instantiated * @exception IllegalAccessException if the instance cannot be accessed * @exception ExecutionException if there is a problem creating the * converter */ - public Converter createConverter(Class converterClass) + public Object createInstance(Class requiredClass) throws InstantiationException, IllegalAccessException, ExecutionException { - return (Converter) converterClass.newInstance(); + return requiredClass.newInstance(); } /** 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 9a1a6afaa..d4b8f66a7 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 @@ -174,22 +174,17 @@ public interface ComponentService { Object createComponent(String componentName) throws ExecutionException; /** - * Create a component given its class. The component will have a context - * but will not be configured. It should be configured using the - * appropriate set methods and then validated before being used. + * Create a component given its libraryId and local name within the + * library. This method is unambiguous in the face of imports, aliases and + * taskdefs performed in the build. * - * @param componentClass the component's class - * @param factory the factory to create the component - * @param loader the classloader associated with the component - * @param addTaskAdapter whenther the returned component should be a - * task, potentially being wrapped in an adapter - * @param componentName the name of the component type + * @param libraryId the component's library identifier. + * @param localName the name component within the library. * @return the created component. The return type of this method depends * on the component type. * @exception ExecutionException if the component cannot be created */ - Object createComponent(AntLibFactory factory, ClassLoader loader, - Class componentClass, boolean addTaskAdapter, - String componentName) throws ExecutionException; + Object createComponent(String libraryId, String localName) + throws ExecutionException; }