blob: baa8a0d84b7b2a8dfa6b9428de5c620d19addcda [file] [log] [blame]
/*
* 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);
}
}
}