| /* |
| * 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 |
| * <http://www.apache.org/>. |
| */ |
| package org.apache.ant.antcore.execution; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import org.apache.ant.antcore.antlib.AntLibDefinition; |
| 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.common.antlib.AntLibFactory; |
| import org.apache.ant.common.antlib.Converter; |
| import org.apache.ant.common.antlib.DeferredTask; |
| import org.apache.ant.common.antlib.ExecutionComponent; |
| import org.apache.ant.common.antlib.StandardLibFactory; |
| import org.apache.ant.common.antlib.Task; |
| import org.apache.ant.common.antlib.TaskContainer; |
| import org.apache.ant.common.event.MessageLevel; |
| import org.apache.ant.common.model.BuildElement; |
| 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; |
| |
| /** |
| * The instance of the ComponentServices made available by the core to the |
| * ant libraries. |
| * |
| * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> |
| * @created 27 January 2002 |
| */ |
| public class ComponentManager implements ComponentService { |
| /** |
| * Type converters for this frame. Converters are used when configuring |
| * Tasks to handle special type conversions. |
| */ |
| private Map converters = new HashMap(); |
| |
| /** This is the set of libraries whose converters have been loaded */ |
| private Set loadedConverters = new HashSet(); |
| |
| /** The factory objects for each library, indexed by the library Id */ |
| private Map libFactories = new HashMap(); |
| |
| /** The Frame this service instance is working for */ |
| private Frame frame; |
| |
| /** The library manager instance used to configure libraries. */ |
| private AntLibManager libManager; |
| |
| /** |
| * These are AntLibraries which have been loaded into this component |
| * manager |
| */ |
| private Map antLibraries; |
| |
| /** dynamic libraries which have been defined */ |
| private Map dynamicLibraries; |
| |
| /** The definitions which have been imported into this frame. */ |
| private Map definitions = new HashMap(); |
| |
| /** |
| * This map stores a list of additional paths for each library indexed |
| * by the libraryId |
| */ |
| private Map libPathsMap; |
| |
| /** Reflector objects used to configure Tasks from the Task models. */ |
| private Map setters = new HashMap(); |
| |
| |
| /** |
| * Constructor |
| * |
| * @param frame the frame containing this context |
| * @param allowRemoteLibs true if remote libraries can be loaded though |
| * this service. |
| * @param configLibPaths the additional library paths specified in the |
| * configuration |
| */ |
| protected ComponentManager(Frame frame, boolean allowRemoteLibs, |
| Map configLibPaths) { |
| this.frame = frame; |
| libManager = new AntLibManager(allowRemoteLibs); |
| dynamicLibraries = new HashMap(); |
| libPathsMap = new HashMap(configLibPaths); |
| } |
| |
| /** |
| * Load a library or set of libraries from a location making them |
| * available for use |
| * |
| * @param libLocation the file or URL of the library location |
| * @param importAll if true all tasks are imported as the library is |
| * loaded |
| * @exception ExecutionException if the library cannot be loaded |
| */ |
| public void loadLib(String libLocation, boolean importAll) |
| throws ExecutionException { |
| try { |
| Map librarySpecs = new HashMap(); |
| libManager.loadLibs(librarySpecs, libLocation); |
| libManager.configLibraries(frame.getInitConfig(), librarySpecs, |
| antLibraries, libPathsMap); |
| |
| if (importAll) { |
| Iterator i = librarySpecs.keySet().iterator(); |
| while (i.hasNext()) { |
| String libraryId = (String)i.next(); |
| importLibrary(libraryId); |
| } |
| } |
| } catch (MalformedURLException e) { |
| throw new ExecutionException("Unable to load libraries from " |
| + libLocation, e); |
| } |
| } |
| |
| /** |
| * 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 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 |
| */ |
| public void taskdef(AntLibFactory factory, ClassLoader loader, |
| String taskName, String className) |
| throws ExecutionException { |
| defineComponent(factory, loader, ComponentLibrary.TASKDEF, |
| taskName, className); |
| } |
| |
| /** |
| * 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 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 |
| */ |
| public void typedef(AntLibFactory factory, ClassLoader loader, |
| String typeName, String className) |
| throws ExecutionException { |
| defineComponent(factory, loader, ComponentLibrary.TYPEDEF, |
| typeName, className); |
| } |
| |
| /** |
| * Add a library path for the given library |
| * |
| * @param libraryId the unique id of the library for which an additional |
| * path is being defined |
| * @param libPath the library path (usually a jar) |
| * @exception ExecutionException if the path cannot be specified |
| */ |
| public void addLibPath(String libraryId, URL libPath) |
| throws ExecutionException { |
| List libPaths = (List)libPathsMap.get(libraryId); |
| if (libPaths == null) { |
| libPaths = new ArrayList(); |
| libPathsMap.put(libraryId, libPaths); |
| } |
| libPaths.add(libPath); |
| |
| // If this library already exists give it the new path now |
| AntLibrary library = (AntLibrary)antLibraries.get(libraryId); |
| if (library != null) { |
| libManager.addLibPath(library, libPath); |
| } |
| } |
| |
| /** |
| * Import a complete library into the current execution frame |
| * |
| * @param libraryId The id of the library to be imported |
| * @exception ExecutionException if the library cannot be imported |
| */ |
| public void importLibrary(String libraryId) throws ExecutionException { |
| AntLibrary library = (AntLibrary)antLibraries.get(libraryId); |
| if (library == null) { |
| throw new ExecutionException("Unable to import library " + libraryId |
| + " as it has not been loaded"); |
| } |
| for (Iterator i = library.getDefinitionNames(); i.hasNext(); ) { |
| String defName = (String)i.next(); |
| importLibraryDef(library, defName, null); |
| } |
| addLibraryConverters(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 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 |
| * used. |
| * @exception ExecutionException if the component cannot be imported |
| */ |
| public void importComponent(String libraryId, String defName, |
| String alias) throws ExecutionException { |
| AntLibrary library = (AntLibrary)antLibraries.get(libraryId); |
| if (library == null) { |
| throw new ExecutionException("Unable to import component from " |
| + "library \"" + libraryId + "\" as it has not been loaded"); |
| } |
| importLibraryDef(library, defName, alias); |
| addLibraryConverters(library); |
| } |
| |
| /** |
| * Imports a component defined in a nother frame. |
| * |
| * @param relativeName the qualified name of the component relative to |
| * this execution frame |
| * @param alias the name under which this component will be used in the |
| * build scripts. If this is null, the components default name is |
| * used. |
| * @exception ExecutionException if the component cannot be imported |
| */ |
| public void importFrameComponent(String relativeName, String alias) |
| throws ExecutionException { |
| ImportInfo definition |
| = frame.getReferencedDefinition(relativeName); |
| |
| if (definition == null) { |
| throw new ExecutionException("The reference \"relativeName\" does" |
| + " not refer to a defined component"); |
| } |
| |
| String label = alias; |
| if (label == null) { |
| label = frame.getNameInFrame(relativeName); |
| } |
| |
| frame.log("Adding referenced component <" + definition.getLocalName() |
| + "> as <" + label + "> from library \"" |
| + definition.getComponentLibrary().getLibraryId() + "\", class: " |
| + definition.getClassName(), MessageLevel.MSG_DEBUG); |
| definitions.put(label, definition); |
| } |
| |
| /** |
| * Create a component. 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. |
| * |
| * @param componentName the name of the component |
| * @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(String componentName) |
| throws ExecutionException { |
| return createComponent(componentName, 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. |
| * |
| * @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 |
| * @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) |
| throws ExecutionException { |
| return createComponent(loader, factory, componentClass, |
| componentName, componentName, addTaskAdapter, null); |
| } |
| |
| /** |
| * Set the standard libraries (i.e. those which are independent of the |
| * build files) to be used in this component manager |
| * |
| * @param standardLibs A collection of AntLibrary objects indexed by |
| * their libraryId |
| * @exception ExecutionException if the components cannot be imported |
| * form the libraries fro which such importing is automatic. |
| */ |
| protected void setStandardLibraries(Map standardLibs) |
| throws ExecutionException { |
| |
| antLibraries = new HashMap(standardLibs); |
| |
| // go through the libraries and import all standard ant libraries |
| for (Iterator i = antLibraries.keySet().iterator(); i.hasNext(); ) { |
| String libraryId = (String)i.next(); |
| if (libraryId.startsWith(Constants.ANT_LIB_PREFIX)) { |
| // standard library - import whole library |
| importLibrary(libraryId); |
| } |
| } |
| } |
| |
| /** |
| * Get the collection ov converters currently configured |
| * |
| * @return A map of converter instances indexed on the class they can |
| * convert |
| */ |
| protected Map getConverters() { |
| return converters; |
| } |
| |
| /** |
| * 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 |
| * @return the library's factory object |
| * @exception ExecutionException if the factory cannot be created |
| */ |
| protected AntLibFactory getLibFactory(ComponentLibrary componentLibrary) |
| throws ExecutionException { |
| String libraryId = componentLibrary.getLibraryId(); |
| if (libFactories.containsKey(libraryId)) { |
| return (AntLibFactory)libFactories.get(libraryId); |
| } |
| ExecutionContext context |
| = new ExecutionContext(frame, null, Location.UNKNOWN_LOCATION); |
| AntLibFactory libFactory = componentLibrary.getFactory(context); |
| if (libFactory == null) { |
| libFactory = new StandardLibFactory(); |
| } |
| libFactories.put(libraryId, libFactory); |
| return libFactory; |
| } |
| |
| /** |
| * 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 |
| */ |
| protected ImportInfo getDefinition(String name) { |
| return (ImportInfo)definitions.get(name); |
| } |
| |
| /** |
| * Create a component from a build model |
| * |
| * @param model the build model representing the component and its |
| * configuration |
| * @return the configured component |
| * @exception ExecutionException if there is a problem creating or |
| * configuring the component |
| */ |
| protected Object createComponent(BuildElement model) |
| throws ExecutionException { |
| String componentName = model.getType(); |
| return createComponent(componentName, model); |
| } |
| |
| /** |
| * Create a component. |
| * |
| * @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 |
| * @exception ExecutionException if there is a problem creating or |
| * configuring the component |
| */ |
| 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) { |
| throw new ExecutionException("There is no definition of the <" |
| + componentName + "> component"); |
| } |
| String className = definition.getClassName(); |
| |
| ComponentLibrary componentLibrary |
| = definition.getComponentLibrary(); |
| boolean isTask = definition.getDefinitionType() == AntLibrary.TASKDEF; |
| String localName = definition.getLocalName(); |
| 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); |
| } 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); |
| } catch (ExecutionException e) { |
| e.setLocation(model.getLocation(), false); |
| throw e; |
| } |
| } |
| |
| /** |
| * Import a single component from the given library |
| * |
| * @param library the library which provides the component |
| * @param defName the name of the component in the library |
| * @param alias the name to be used for the component in build files. If |
| * this is null, the component's name within its library is used. |
| */ |
| protected void importLibraryDef(ComponentLibrary library, String defName, |
| String alias) { |
| String label = alias; |
| if (label == null) { |
| label = defName; |
| } |
| |
| AntLibDefinition libDef = library.getDefinition(defName); |
| frame.log("Adding component <" + defName + "> as <" + label |
| + "> from library \"" + library.getLibraryId() + "\", class: " |
| + libDef.getClassName(), MessageLevel.MSG_DEBUG); |
| definitions.put(label, new ImportInfo(library, libDef)); |
| } |
| |
| /** |
| * Gets the setter for the given class |
| * |
| * @param c the class for which the reflector is desired |
| * @return the reflector |
| */ |
| private Setter getSetter(Class c) { |
| if (setters.containsKey(c)) { |
| return (Setter)setters.get(c); |
| } |
| Setter setter = null; |
| if (DeferredTask.class.isAssignableFrom(c)) { |
| setter = new DeferredSetter(); |
| } else { |
| ClassIntrospector introspector |
| = new ClassIntrospector(c, getConverters()); |
| setter = introspector.getReflector(); |
| } |
| |
| setters.put(c, setter); |
| 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.getClass().getName() + ": " |
| + e.getMessage(), e, location); |
| } |
| } |
| |
| /** |
| * Create an instance of a type given its required class |
| * |
| * @param typeClass the class from which the instance should be created |
| * @param model the model describing the required configuration of the |
| * instance |
| * @param libFactory the factory object of the typeClass's Ant library |
| * @param localName the name of the type within its Ant library |
| * @return an instance of the given class appropriately configured |
| * @exception ExecutionException if there is a problem creating the type |
| * instance |
| */ |
| private Object createTypeInstance(Class typeClass, AntLibFactory libFactory, |
| BuildElement model, String localName) |
| throws ExecutionException { |
| try { |
| Object typeInstance |
| = libFactory.createComponent(typeClass, localName); |
| |
| if (typeInstance instanceof ExecutionComponent) { |
| ExecutionComponent component = (ExecutionComponent)typeInstance; |
| ExecutionContext context = new ExecutionContext(frame, |
| component, model.getLocation()); |
| component.init(context, localName); |
| configureElement(libFactory, typeInstance, model); |
| component.validateComponent(); |
| } else { |
| configureElement(libFactory, typeInstance, model); |
| } |
| return typeInstance; |
| } catch (InstantiationException e) { |
| throw new ExecutionException("Unable to instantiate type class " |
| + typeClass.getName() + " for type <" + model.getType() + ">", |
| e, model.getLocation()); |
| } catch (IllegalAccessException e) { |
| throw new ExecutionException("Unable to access type class " |
| + typeClass.getName() + " for type <" + model.getType() + ">", |
| e, model.getLocation()); |
| } catch (ExecutionException e) { |
| e.setLocation(model.getLocation(), false); |
| throw e; |
| } catch (RuntimeException e) { |
| throw new ExecutionException(e.getClass().getName() + ": " |
| + e.getMessage(), e, model.getLocation()); |
| } |
| } |
| |
| /** |
| * Create and add a nested element |
| * |
| * @param setter The Setter instance for the container element |
| * @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. |
| * @exception ExecutionException if the nested element cannot be created |
| */ |
| private void addNestedElement(AntLibFactory factory, Setter setter, |
| Object element, BuildElement model) |
| throws ExecutionException { |
| String nestedElementName = model.getType(); |
| 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"); |
| if (refId != null && typeName != null) { |
| throw new ExecutionException("Only one of " + Constants.ANT_ASPECT |
| + ":type and " + Constants.ANT_ASPECT |
| + ":refid may be specified at a time", model.getLocation()); |
| } |
| |
| Object typeInstance = null; |
| if (typeName != null) { |
| // the build file has specified the actual type of the element. |
| // we need to look up that type and use it |
| typeInstance = createComponent(typeName, model); |
| } else if (refId != null) { |
| // We have a reference to an existing instance. Need to check if |
| // it is compatible with the type expected by the nested element's |
| // adder method |
| typeInstance = frame.getDataValue(refId); |
| if (model.getAttributeNames().hasNext() || |
| model.getNestedElements().hasNext() || |
| model.getText().length() != 0) { |
| throw new ExecutionException("Element <" + nestedElementName |
| + "> is defined by reference and hence may not specify " |
| + "any attributes, nested elements or content", |
| model.getLocation()); |
| } |
| if (typeInstance == null) { |
| throw new ExecutionException("The given ant:refid value '" |
| + refId + "' is not defined", model.getLocation()); |
| } |
| } else if (nestedType != null) { |
| // We need to create an instance of the class expected by the nested |
| // element's adder method if that is possible |
| if (nestedType.isInterface()) { |
| throw new ExecutionException("No element can be created for " |
| + "nested element <" + nestedElementName + ">. Please " |
| + "provide a value by reference or specify the value type", |
| model.getLocation()); |
| } |
| typeInstance = createTypeInstance(nestedType, factory, model, null); |
| } else { |
| throw new ExecutionException("The type of the <" |
| + nestedElementName + "> nested element is not known. " |
| + "Please specify by the type using the \"ant:type\" " |
| + "attribute or provide a reference to an instance with " |
| + "the \"ant:id\" attribute"); |
| } |
| |
| // is the typeInstance compatible with the type expected |
| // by the element's add method |
| if (!nestedType.isInstance(typeInstance)) { |
| if (refId != null) { |
| throw new ExecutionException("The value specified by refId " |
| + refId + " is not compatible with the <" |
| + nestedElementName + "> nested element", |
| model.getLocation()); |
| } else if (typeName != null) { |
| throw new ExecutionException("The type " |
| + typeName + " is not compatible with the <" |
| + nestedElementName + "> nested element", |
| model.getLocation()); |
| } |
| } |
| setter.addElement(element, nestedElementName, typeInstance); |
| } |
| |
| /** |
| * Create a nested element for the given object according to the model. |
| * |
| * @param setter the Setter instance of the container object |
| * @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. |
| */ |
| private void createNestedElement(AntLibFactory factory, Setter setter, |
| Object element, BuildElement model) |
| throws ExecutionException { |
| String nestedElementName = model.getType(); |
| try { |
| Object nestedElement |
| = setter.createElement(element, nestedElementName); |
| factory.registerCreatedElement(nestedElement); |
| if (nestedElement instanceof ExecutionComponent) { |
| ExecutionComponent component |
| = (ExecutionComponent)nestedElement; |
| ExecutionContext context = new ExecutionContext(frame, |
| component, model.getLocation()); |
| component.init(context, nestedElementName); |
| configureElement(factory, nestedElement, model); |
| component.validateComponent(); |
| } else { |
| configureElement(factory, nestedElement, model); |
| } |
| } catch (ExecutionException e) { |
| e.setLocation(model.getLocation(), false); |
| throw e; |
| } catch (RuntimeException e) { |
| throw new ExecutionException(e.getClass().getName() + ": " |
| + e.getMessage(), e, model.getLocation()); |
| } |
| } |
| |
| |
| /** |
| * Configure an element according to the given model. |
| * |
| * @param element the object to be configured |
| * @param model the BuildElement describing the object in the build file |
| * @param factory Ant Library factory associated with the element being |
| * configured |
| * @exception ExecutionException if the element cannot be configured |
| */ |
| private void configureElement(AntLibFactory factory, Object element, |
| BuildElement model) |
| throws ExecutionException { |
| Setter setter = getSetter(element.getClass()); |
| // start by setting the attributes of this element |
| for (Iterator i = model.getAttributeNames(); i.hasNext(); ) { |
| String attributeName = (String)i.next(); |
| String attributeValue = model.getAttributeValue(attributeName); |
| if (!setter.supportsAttribute(attributeName)) { |
| throw new ExecutionException(model.getType() |
| + " does not support the \"" + attributeName |
| + "\" attribute", model.getLocation()); |
| } |
| setter.setAttribute(element, attributeName, |
| frame.replacePropertyRefs(attributeValue)); |
| } |
| |
| String modelText = model.getText().trim(); |
| if (modelText.length() != 0) { |
| if (!setter.supportsText()) { |
| throw new ExecutionException(model.getType() |
| + " does not support content", model.getLocation()); |
| } |
| setter.addText(element, |
| frame.replacePropertyRefs(modelText)); |
| } |
| |
| // now do the nested elements |
| for (Iterator i = model.getNestedElements(); i.hasNext(); ) { |
| BuildElement nestedElementModel = (BuildElement)i.next(); |
| String nestedElementName = nestedElementModel.getType(); |
| ImportInfo info = getDefinition(nestedElementName); |
| if (element instanceof TaskContainer |
| && info != null |
| && info.getDefinitionType() == AntLibrary.TASKDEF |
| && !setter.supportsNestedElement(nestedElementName)) { |
| // it is a nested task |
| Task nestedTask |
| = (Task)createComponent(nestedElementModel); |
| TaskContainer container = (TaskContainer)element; |
| container.addNestedTask(nestedTask); |
| } else { |
| if (setter.supportsNestedAdder(nestedElementName)) { |
| addNestedElement(factory, setter, element, |
| nestedElementModel); |
| } else if (setter.supportsNestedCreator(nestedElementName)) { |
| createNestedElement(factory, setter, element, |
| nestedElementModel); |
| } else { |
| throw new ExecutionException(model.getType() |
| + " does not support the \"" + nestedElementName |
| + "\" nested element", |
| nestedElementModel.getLocation()); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Define a new component |
| * |
| * @param componentName the name this component will take |
| * @param defType the type of component being defined |
| * @param factory the library factory object to create the component |
| * instances |
| * @param loader the class loader to use to create the particular |
| * components |
| * @param className the name of the class implementing the component |
| * @exception ExecutionException if the component cannot be defined |
| */ |
| private void defineComponent(AntLibFactory factory, ClassLoader loader, |
| int defType, String componentName, |
| String className) |
| throws ExecutionException { |
| DynamicLibrary dynamicLibrary |
| = new DynamicLibrary(factory, loader); |
| dynamicLibrary.addComponent(defType, componentName, className); |
| dynamicLibraries.put(dynamicLibrary.getLibraryId(), dynamicLibrary); |
| importLibraryDef(dynamicLibrary, componentName, null); |
| } |
| |
| |
| /** |
| * Add the converters from the given library to those managed by this |
| * frame. |
| * |
| * @param library the library from which the converters are required |
| * @exception ExecutionException if a converter defined in the library |
| * cannot be instantiated |
| */ |
| private void addLibraryConverters(AntLibrary library) |
| throws ExecutionException { |
| if (!library.hasConverters() |
| || loadedConverters.contains(library.getLibraryId())) { |
| return; |
| } |
| |
| String className = null; |
| try { |
| AntLibFactory libFactory = getLibFactory(library); |
| ClassLoader converterLoader = library.getClassLoader(); |
| for (Iterator i = library.getConverterClassNames(); i.hasNext(); ) { |
| className = (String)i.next(); |
| Class converterClass |
| = Class.forName(className, true, converterLoader); |
| if (!Converter.class.isAssignableFrom(converterClass)) { |
| throw new ExecutionException("In Ant library \"" |
| + library.getLibraryId() + "\" the converter class " |
| + converterClass.getName() |
| + " does not implement the Converter interface"); |
| } |
| Converter converter |
| = libFactory.createConverter(converterClass); |
| ExecutionContext context = new ExecutionContext(frame, |
| null, Location.UNKNOWN_LOCATION); |
| converter.init(context); |
| Class[] converterTypes = converter.getTypes(); |
| for (int j = 0; j < converterTypes.length; ++j) { |
| converters.put(converterTypes[j], converter); |
| } |
| } |
| loadedConverters.add(library.getLibraryId()); |
| } catch (ClassNotFoundException e) { |
| throw new ExecutionException("In Ant library \"" |
| + library.getLibraryId() + "\" converter 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 converter " + className); |
| } catch (InstantiationException e) { |
| throw new ExecutionException("In Ant library \"" |
| + library.getLibraryId() |
| + "\" unable to instantiate converter class " |
| + className, e); |
| } catch (IllegalAccessException e) { |
| throw new ExecutionException("In Ant library \"" |
| + library.getLibraryId() |
| + "\" unable to access converter class " |
| + className, e); |
| } |
| } |
| } |
| |