From 6252354506953777f5b921b8746a54e7d317475a Mon Sep 17 00:00:00 2001 From: Erik Hatcher Date: Sun, 3 Mar 2002 12:37:41 +0000 Subject: [PATCH] once again for Jose Alberto - think I got it right this time git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271710 13f79535-47bb-0310-9956-ffa450edef68 --- proposal/sandbox/antlib/build.xml | 46 +- .../main/org/apache/tools/ant/Project.java | 1539 +++++++++++------ .../org/apache/tools/ant/ProjectHelper.java | 156 +- .../org/apache/tools/ant/RoleAdapter.java | 5 + .../org/apache/tools/ant/SymbolTable.java | 646 ++++--- .../org/apache/tools/ant/TaskAdapter.java | 36 +- .../org/apache/tools/ant/taskdefs/Ant.java | 24 +- .../org/apache/tools/ant/taskdefs/Antjar.java | 14 +- .../org/apache/tools/ant/taskdefs/Antlib.java | 682 +++++--- .../tools/ant/types/DataTypeAdapterTask.java | 24 +- 10 files changed, 1971 insertions(+), 1201 deletions(-) diff --git a/proposal/sandbox/antlib/build.xml b/proposal/sandbox/antlib/build.xml index 10783034c..4961c04fa 100644 --- a/proposal/sandbox/antlib/build.xml +++ b/proposal/sandbox/antlib/build.xml @@ -6,21 +6,24 @@ + - - + + - - - + + + + + @@ -39,6 +42,32 @@ + + + + + + + + + + + + + + + + + + + @@ -48,6 +77,11 @@ optimize="${optimize}"> + + + + + @@ -56,7 +90,7 @@ - diff --git a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/Project.java b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/Project.java index 20f856f4b..118a2d59c 100644 --- a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/Project.java +++ b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/Project.java @@ -1,57 +1,56 @@ /* - * The Apache Software License, Version 1.1 + * The Apache Software License, Version 1.1 * - * Copyright (c) 2000-2002 The Apache Software Foundation. All rights - * reserved. + * Copyright (c) 2000-2002 The Apache Software Foundation. All rights + * reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. * - * 3. The end-user documentation included with the redistribution, if - * any, must include the following acknowlegement: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowlegement may appear in the software itself, - * if and wherever such third-party acknowlegements normally appear. + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. * - * 4. The names "The Jakarta Project", "Ant", and "Apache Software - * Foundation" must not be used to endorse or promote products derived - * from this software without prior written permission. For written - * permission, please contact apache@apache.org. + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. * - * 5. Products derived from this software may not be called "Apache" - * nor may "Apache" appear in their names without prior written - * permission of the Apache Group. + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * ==================================================================== + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . */ - package org.apache.tools.ant; import java.io.File; @@ -63,35 +62,67 @@ import java.util.Properties; import java.util.Enumeration; import java.util.Stack; import java.lang.reflect.Modifier; +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; - -import org.apache.tools.ant.types.DataTypeAdapterTask; -import org.apache.tools.ant.types.FilterSet; -import org.apache.tools.ant.types.FilterSetCollection; -import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.types.DataTypeAdapterTask; +import org.apache.tools.ant.types.FileSet; +import org.apache.tools.ant.types.FilterSet; +import org.apache.tools.ant.types.FilterSetCollection; +import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.taskdefs.Antlib; /** - * Central representation of an Ant project. This class defines a - * Ant project with all of it's targets and tasks. It also provides - * the mechanism to kick off a build using a particular target name. - *

- * This class also encapsulates methods which allow Files to be refered - * to using abstract path names which are translated to native system - * file paths at runtime as well as defining various project properties. + * Central representation of an Ant project. This class defines a Ant project + * with all of it's targets and tasks. It also provides the mechanism to kick + * off a build using a particular target name.

* - * @author duncan@x180.com + * This class also encapsulates methods which allow Files to be refered to + * using abstract path names which are translated to native system file paths + * at runtime as well as defining various project properties. + * + *@author duncan@x180.com + *@author j_a_fernandez@yahoo.com + *@created February 27, 2002 */ public class Project { + /** + * Description of the Field + */ public final static int MSG_ERR = 0; + /** + * Description of the Field + */ public final static int MSG_WARN = 1; + /** + * Description of the Field + */ public final static int MSG_INFO = 2; + /** + * Description of the Field + */ public final static int MSG_VERBOSE = 3; + /** + * Description of the Field + */ public final static int MSG_DEBUG = 4; + /** + * LoaderId for the CoreLoader. + */ + public final static String CORELOADER_ID = null; + + /** + * Description of the Field + */ public final static String TASK_ROLE = "task"; - public final static String DATATYPE_ROLE = "datatype"; + /** + * Description of the Field + */ + public final static String DATATYPE_ROLE = "data-type"; // private set of constants to represent the state // of a DFS of the Target dependencies @@ -100,15 +131,38 @@ public class Project { private static String javaVersion; + /** + * Description of the Field + */ public final static String JAVA_1_0 = "1.0"; + /** + * Description of the Field + */ public final static String JAVA_1_1 = "1.1"; + /** + * Description of the Field + */ public final static String JAVA_1_2 = "1.2"; + /** + * Description of the Field + */ public final static String JAVA_1_3 = "1.3"; + /** + * Description of the Field + */ public final static String JAVA_1_4 = "1.4"; + /** + * Description of the Field + */ public final static String TOKEN_START = FilterSet.DEFAULT_TOKEN_START; + /** + * Description of the Field + */ public final static String TOKEN_END = FilterSet.DEFAULT_TOKEN_END; + private final static String CORE_DEFINITIONS = "org/apache/tools/ant/antlib.xml"; + private String name; private String description; @@ -126,13 +180,19 @@ public class Project { private Vector listeners = new Vector(); - /** The Ant core classloader - may be null if using system loader */ + /** + * The Ant core classloader - may be null if using system loader + */ private ClassLoader coreLoader = null; - /** Records the latest task on a thread */ + /** + * Records the latest task on a thread + */ private Hashtable threadTasks = new Hashtable(); - /** Store symbol tables */ + /** + * Store symbol tables + */ private SymbolTable symbols; static { @@ -161,179 +221,289 @@ public class Project { private FileUtils fileUtils; + + /** + *

+ * + * Description: The only reason for this class is to make the + * LoadDefinition method visible in this package.

+ * + *@author jfernandez + *@created February 27, 2002 + */ + private class Corelib extends Antlib { + /** + * Constructor for the Corelib object + */ + Corelib() { + super(Project.this); + setLoaderid(CORELOADER_ID); + getOnerror().setValue("ignore"); + } + + + /** + * Description of the Method + */ + public void loadCoreDefinitions() { + getOnerror().setValue("report"); + super.loadDefinitions(CORE_DEFINITIONS); + } + } + + /** - * create a new ant project + * create a new ant project */ public Project() { fileUtils = FileUtils.newFileUtils(); - symbols = new SymbolTable(); - symbols.setProject(this); + symbols = new SymbolTable(); + symbols.setProject(this); } - + + /** - * create a new ant project that inherits from caler project - * @param p the calling project + * create a new ant project that inherits from caller project + * + *@param p the calling project */ - public Project(Project p) { + private Project(Project p) { fileUtils = FileUtils.newFileUtils(); - symbols = new SymbolTable(p); - symbols.setProject(this); + symbols = new SymbolTable(p.getSymbols()); + symbols.setProject(this); + setCoreLoader(p.getCoreLoader()); } - + + /** - * Initialise the project. - * - * This involves setting the default task definitions and loading the - * system properties. + * Loads the core definitions into the Root project. */ - public void init() throws BuildException { - setJavaVersionProperty(); - - // Initialize simbol table just in case - symbols.addRole("task", TaskContainer.class, TaskAdapter.class); - symbols.addRole("datatype", TaskContainer.class, - DataTypeAdapterTask.class); + private void loadDefinitions() { + // Initialize symbol table just in case + symbols.addRole(TASK_ROLE, TaskContainer.class, TaskAdapter.class); + symbols.addRole(DATATYPE_ROLE, TaskContainer.class, + DataTypeAdapterTask.class); - String defs = "/org/apache/tools/ant/taskdefs/defaults.properties"; + Corelib load = new Corelib(); + load.loadDefinitions(); - try { - Properties props = new Properties(); - InputStream in = this.getClass().getResourceAsStream(defs); - if (in == null) { - throw new BuildException("Can't load default task list"); - } - props.load(in); - in.close(); - - Enumeration enum = props.propertyNames(); - while (enum.hasMoreElements()) { - String key = (String) enum.nextElement(); - String value = props.getProperty(key); - try { - Class taskClass = Class.forName(value); - addTaskDefinition(key, taskClass); - } catch (NoClassDefFoundError ncdfe) { - log("Could not load a dependent class (" + - ncdfe.getMessage() + ") for task " + key, MSG_DEBUG); - } catch (ClassNotFoundException cnfe) { - log("Could not load class (" - + value + ") for task " + key, MSG_DEBUG); - } + // If the most basic of tasks, "property", is not defined + // then there was no antlib jars from where to load the descriptors + // we should be doing bootstrapping, or ant.jar is not an antlib. + if (!isDefinedOnRole(TASK_ROLE, "property")) { + load.loadCoreDefinitions(); + + if (!isDefinedOnRole(TASK_ROLE, "property")) { + throw new BuildException("Can't load core definitions"); } - } catch (IOException ioe) { - throw new BuildException("Can't load default task list"); } + autoLoadDefinitions(); + } - String dataDefs = "/org/apache/tools/ant/types/defaults.properties"; + private void autoLoadDefinitions() { + DirectoryScanner ds = new DirectoryScanner(); + ds.setBasedir(new File(getProperty("ant.home"),"autolib")); + ds.scan(); + String dirs[] = ds.getIncludedDirectories(); + for (int i = 0; i < dirs.length; i++) { + autoLoad(ds.getBasedir(), dirs[i]); + } + } - try{ - Properties props = new Properties(); - InputStream in = this.getClass().getResourceAsStream(dataDefs); - if (in == null) { - throw new BuildException("Can't load default datatype list"); - } - props.load(in); - in.close(); - - Enumeration enum = props.propertyNames(); - while (enum.hasMoreElements()) { - String key = (String) enum.nextElement(); - String value = props.getProperty(key); - try { - Class dataClass = Class.forName(value); - addDataTypeDefinition(key, dataClass); - } catch (NoClassDefFoundError ncdfe) { - // ignore... - } catch (ClassNotFoundException cnfe) { - // ignore... - } - } - } catch (IOException ioe) { - throw new BuildException("Can't load default datatype list"); + private void autoLoad(File base, String dir) { + FileSet fs = new FileSet(); + fs.setProject(this); + fs.setDir(new File(base, dir)); + fs.setIncludes("*.jar"); + + Path cp = new Path(this); + cp.addFileset(fs); + if (cp.size() == 0) { + return; } + Antlib.FailureAction fa = new Antlib.FailureAction(); + fa.setValue("ignore"); + + Antlib lib = new Antlib(this); + lib.setClasspath(cp); + lib.setLoaderid(dir); + lib.setOnerror(fa); + lib.loadDefinitions(); + } + + /** + * Creates a subproject of the current project. + * + *@return Description of the Return Value + */ + public Project createSubProject() { + return new Project(this); + } + + + /** + * Initialise the project. This involves setting the default task + * definitions and loading the system properties. + * + *@exception BuildException Description of the Exception + */ + public void init() throws BuildException { + setJavaVersionProperty(); setSystemProperties(); + if (!isRoleDefined(TASK_ROLE)) { + // Top project, need to load the core definitions + loadDefinitions(); + } } + + /** + * Sets the CoreLoader to the default of the Project object + */ + private void setDefaultCoreLoader() { + coreLoader = this.getClass().getClassLoader(); + if (coreLoader == null) { + // This should only happen if ANT is being + // loader by the Bootstrap classloader + // This may be the case in JDK 1.1 + coreLoader = ClassLoader.getSystemClassLoader(); + } + } + + + /** + * Sets the coreLoader attribute of the Project object + * + *@param coreLoader The new coreLoader value + */ public void setCoreLoader(ClassLoader coreLoader) { - this.coreLoader = coreLoader; + if (coreLoader == null) { + setDefaultCoreLoader(); + } + else this.coreLoader = coreLoader; } - + + + /** + * Gets the coreLoader attribute of the Project object + * + *@return The coreLoader value + */ public ClassLoader getCoreLoader() { + if (coreLoader == null) { + setDefaultCoreLoader(); + } return coreLoader; } - + + + /** + * Adds a feature to the BuildListener attribute of the Project object + * + *@param listener The feature to be added to the BuildListener attribute + */ public void addBuildListener(BuildListener listener) { listeners.addElement(listener); } + + /** + * Description of the Method + * + *@param listener Description of the Parameter + */ public void removeBuildListener(BuildListener listener) { listeners.removeElement(listener); } + + /** + * Gets the buildListeners attribute of the Project object + * + *@return The buildListeners value + */ public Vector getBuildListeners() { return listeners; } + /** - * Get the symbols associated with this project. + * Get the symbols associated with this project. + * + *@return The symbols value */ - public SymbolTable getSymbols() { - return symbols; + private SymbolTable getSymbols() { + // Package protected on purpose + return symbols; } + /** - * Output a message to the log with the default log level - * of MSG_INFO - * @param msg text to log + * Output a message to the log with the default log level of MSG_INFO + * + *@param msg text to log */ - + public void log(String msg) { log(msg, MSG_INFO); } + /** - * Output a message to the log with the given log level - * and an event scope of project - * @param msg text to log - * @param msgLevel level to log at + * Output a message to the log with the given log level and an event scope + * of project + * + *@param msg text to log + *@param msgLevel level to log at */ public void log(String msg, int msgLevel) { fireMessageLogged(this, msg, msgLevel); } + /** - * Output a message to the log with the given log level - * and an event scope of a task - * @param task task to use in the log - * @param msg text to log - * @param msgLevel level to log at + * Output a message to the log with the given log level and an event scope + * of a task + * + *@param task task to use in the log + *@param msg text to log + *@param msgLevel level to log at */ public void log(Task task, String msg, int msgLevel) { fireMessageLogged(task, msg, msgLevel); } + /** - * Output a message to the log with the given log level - * and an event scope of a target - * @param target target to use in the log - * @param msg text to log - * @param msgLevel level to log at + * Output a message to the log with the given log level and an event scope + * of a target + * + *@param target target to use in the log + *@param msg text to log + *@param msgLevel level to log at */ public void log(Target target, String msg, int msgLevel) { fireMessageLogged(target, msg, msgLevel); } - + + /** + * Gets the globalFilterSet attribute of the Project object + * + *@return The globalFilterSet value + */ public FilterSet getGlobalFilterSet() { return globalFilterSet; } - + + /** - * set a property. Any existing property of the same name - * is overwritten, unless it is a user property. - * @param name name of property - * @param value new value of the property + * set a property. Any existing property of the same name is overwritten, + * unless it is a user property. + * + *@param name name of property + *@param value new value of the property */ public void setProperty(String name, String value) { // command line properties take precedence @@ -343,21 +513,23 @@ public class Project { } if (null != properties.get(name)) { - log("Overriding previous definition of property " + name, - MSG_VERBOSE); + log("Overriding previous definition of property " + name, + MSG_VERBOSE); } log("Setting project property: " + name + " -> " + - value, MSG_DEBUG); + value, MSG_DEBUG); properties.put(name, value); } + /** - * set a property. An existing property of the same name - * will not be overwritten. - * @param name name of property - * @param value new value of the property - * @since 1.5 + * set a property. An existing property of the same name will not be + * overwritten. + * + *@param name name of property + *@param value new value of the property + *@since 1.5 */ public void setNewProperty(String name, String value) { if (null != properties.get(name)) { @@ -365,26 +537,34 @@ public class Project { return; } log("Setting project property: " + name + " -> " + - value, MSG_DEBUG); + value, MSG_DEBUG); properties.put(name, value); } + /** - * set a user property, which can not be overwritten by - * set/unset property calls - * @see #setProperty(String,String) + * set a user property, which can not be overwritten by set/unset property + * calls + * + *@param name The new userProperty value + *@param value The new userProperty value + *@see #setProperty(String,String) */ public void setUserProperty(String name, String value) { log("Setting ro project property: " + name + " -> " + - value, MSG_DEBUG); + value, MSG_DEBUG); userProperties.put(name, value); properties.put(name, value); } - + + /** - * Allows Project and subclasses to set a property unless its - * already defined as a user property. There are a few cases - * internally to Project that need to do this currently. + * Allows Project and subclasses to set a property unless its already + * defined as a user property. There are a few cases internally to Project + * that need to do this currently. + * + *@param name The new propertyInternal value + *@param value The new propertyInternal value */ private void setPropertyInternal(String name, String value) { if (null != userProperties.get(name)) { @@ -393,182 +573,226 @@ public class Project { properties.put(name, value); } + /** - * query a property. - * @param name the name of the property - * @return the property value, or null for no match + * query a property. + * + *@param name the name of the property + *@return the property value, or null for no match */ public String getProperty(String name) { if (name == null) { - return null; + return null; } String property = (String) properties.get(name); return property; } + /** - * Replace ${} style constructions in the given value with the - * string value of the corresponding data types. + * Replace ${} style constructions in the given value with the string value + * of the corresponding data types. * - * @param value the string to be scanned for property references. + *@param value the string to be scanned for property + * references. + *@return Description of the Return Value + *@exception BuildException Description of the Exception */ public String replaceProperties(String value) - throws BuildException { + throws BuildException { return ProjectHelper.replaceProperties(this, value, properties); } + /** - * query a user property. - * @param name the name of the property - * @return the property value, or null for no match + * query a user property. + * + *@param name the name of the property + *@return the property value, or null for no match */ public String getUserProperty(String name) { if (name == null) { - return null; + return null; } String property = (String) userProperties.get(name); return property; } + /** - * get a copy of the property hashtable - * @return the hashtable containing all properties, user included + * get a copy of the property hashtable + * + *@return the hashtable containing all properties, user included */ public Hashtable getProperties() { Hashtable propertiesCopy = new Hashtable(); - + Enumeration e = properties.keys(); while (e.hasMoreElements()) { Object name = e.nextElement(); Object value = properties.get(name); propertiesCopy.put(name, value); } - + return propertiesCopy; } + /** - * get a copy of the user property hashtable - * @return the hashtable user properties only + * get a copy of the user property hashtable + * + *@return the hashtable user properties only */ public Hashtable getUserProperties() { Hashtable propertiesCopy = new Hashtable(); - + Enumeration e = userProperties.keys(); while (e.hasMoreElements()) { Object name = e.nextElement(); Object value = properties.get(name); propertiesCopy.put(name, value); } - + return propertiesCopy; } + /** - * set the default target of the project - * @deprecated, use setDefault - * @see #setDefault(String) + * set the default target of the project + * + *@param defaultTarget The new defaultTarget value + *@deprecated, use setDefault + *@see #setDefault(String) */ public void setDefaultTarget(String defaultTarget) { this.defaultTarget = defaultTarget; } + /** - * get the default target of the project - * @return default target or null + * get the default target of the project + * + *@return default target or null */ public String getDefaultTarget() { return defaultTarget; } - + /** - * set the default target of the project - * XML attribute name. + * set the default target of the project XML attribute name. + * + *@param defaultTarget The new default value */ public void setDefault(String defaultTarget) { this.defaultTarget = defaultTarget; } + /** - * ant xml property. Set the project name as - * an attribute of this class, and of the property - * ant.project.name + * ant xml property. Set the project name as an attribute of this class, + * and of the property ant.project.name + * + *@param name The new name value */ public void setName(String name) { - setUserProperty("ant.project.name", name); + setUserProperty("ant.project.name", name); this.name = name; } - /** get the project name - * @return name string + + /** + * get the project name + * + *@return name string */ public String getName() { return name; } - /** set the project description - * @param description text + + /** + * set the project description + * + *@param description text */ public void setDescription(String description) { this.description = description; } - /** get the project description - * @return description or null if no description has been set + + /** + * get the project description + * + *@return description or null if no description has been set */ public String getDescription() { return description; } - /** @deprecated */ + + /** + *@param token The feature to be added to the Filter attribute + *@param value The feature to be added to the Filter attribute + *@deprecated + */ public void addFilter(String token, String value) { if (token == null) { return; } - + globalFilterSet.addFilter(new FilterSet.Filter(token, value)); } - /** @deprecated */ + + /** + *@return The filters value + *@deprecated + */ public Hashtable getFilters() { // we need to build the hashtable dynamically return globalFilterSet.getFilterHash(); } + /** - * match basedir attribute in xml - * @param baseD project base directory. - * @throws BuildException if the directory was invalid + * match basedir attribute in xml + * + *@param baseD project base directory. + *@throws BuildException if the directory was invalid */ public void setBasedir(String baseD) throws BuildException { setBaseDir(new File(baseD)); } + /** - * set the base directory; XML attribute. - * checks for the directory existing and being a directory type - * @param baseDir project base directory. - * @throws BuildException if the directory was invalid + * set the base directory; XML attribute. checks for the directory existing + * and being a directory type + * + *@param baseDir project base directory. + *@throws BuildException if the directory was invalid */ public void setBaseDir(File baseDir) throws BuildException { baseDir = fileUtils.normalize(baseDir.getAbsolutePath()); - if (!baseDir.exists()) { + if (!baseDir.exists()) { throw new BuildException("Basedir " + baseDir.getAbsolutePath() + " does not exist"); } - if (!baseDir.isDirectory()) { + if (!baseDir.isDirectory()) { throw new BuildException("Basedir " + baseDir.getAbsolutePath() + " is not a directory"); } this.baseDir = baseDir; - setPropertyInternal( "basedir", this.baseDir.getPath()); + setPropertyInternal("basedir", this.baseDir.getPath()); String msg = "Project base dir set to: " + this.baseDir; log(msg, MSG_VERBOSE); } + /** - * get the base directory of the project as a file object - * @return the base directory. If this is null, then the base - * dir is not valid + * get the base directory of the project as a file object + * + *@return the base directory. If this is null, then the base dir is not + * valid */ public File getBaseDir() { if (baseDir == null) { @@ -581,18 +805,22 @@ public class Project { return baseDir; } + /** - * static query of the java version - * @return something like "1.1" or "1.3" + * static query of the java version + * + *@return something like "1.1" or "1.3" */ public static String getJavaVersion() { return javaVersion; } + /** - * set the ant.java.version property, also tests for - * unsupported JVM versions, prints the verbose log messages - * @throws BuildException if this Java version is not supported + * set the ant.java.version property, also tests for unsupported JVM + * versions, prints the verbose log messages + * + *@throws BuildException if this Java version is not supported */ public void setJavaVersionProperty() throws BuildException { setPropertyInternal("ant.java.version", javaVersion); @@ -607,163 +835,202 @@ public class Project { log("Detected OS: " + System.getProperty("os.name"), MSG_VERBOSE); } + + /** + * turn all the system properties into ant properties. user properties + * still override these values + */ + public void setSystemProperties() { + Properties systemP = System.getProperties(); + Enumeration e = systemP.keys(); + while (e.hasMoreElements()) { + Object name = e.nextElement(); + String value = systemP.get(name).toString(); + this.setPropertyInternal(name.toString(), value); + } + } + + + /** + * Adds a feature to the ToLoader attribute of the Project object + * + *@param loader The feature to be added to the ToLoader attribute + *@param path The feature to be added to the ToLoader attribute + *@return Description of the Return Value + */ public ClassLoader addToLoader(String loader, Path path) { - return symbols.addToLoader(loader, path); + if (loader == CORELOADER_ID) { + // It is not possible to add more libraries to the CoreLoader + // Just return it as is. + return getCoreLoader(); + } + return symbols.addToLoader(loader, path); } - public boolean addRoleDefinition(String role, - Class roleClass, Class adapter) - { - return symbols.addRole(role, roleClass, adapter); + + /** + * Adds a feature to the RoleDefinition attribute of the Project object + * + *@param role The feature to be added to the RoleDefinition attribute + *@param roleClass The feature to be added to the RoleDefinition attribute + *@param adapter The feature to be added to the RoleDefinition attribute + *@return Description of the Return Value + */ + public boolean addRoleDefinition(String role, + Class roleClass, Class adapter) { + return symbols.addRole(role, roleClass, adapter); } + /** - * test for a role name being in use already + * test for a role name being in use already * - * @param name the name to test - * @return true if it is a task or a datatype + *@param name the name to test + *@return true if it is a task or a datatype */ public boolean isRoleDefined(String name) { - return (symbols.getRole(name) != null); + return (symbols.getRole(name) != null); } + + /** + * Adds a feature to the DefinitionOnRole attribute of the Project object + * + *@param role The feature to be added to the DefinitionOnRole attribute + *@param type The feature to be added to the DefinitionOnRole attribute + *@param clz The feature to be added to the DefinitionOnRole attribute + */ public void addDefinitionOnRole(String role, - String type, Class clz) - { - Class old = symbols.add(role, type, clz); - // Special management for Tasks + String type, Class clz) { + Class old = symbols.add(role, type, clz); + // Special management for Tasks if (TASK_ROLE.equals(role) && null != old && !old.equals(clz)) { - invalidateCreatedTasks(type); + invalidateCreatedTasks(type); } } + /** - * test for a name being in use already on this role + * test for a name being in use already on this role * - * @param name the name to test - * @return true if it is a task or a datatype + *@param name the name to test + *@param role Description of the Parameter + *@return true if it is a task or a datatype */ public boolean isDefinedOnRole(String role, String name) { - return (symbols.get(role, name) != null); - } - - /** - * turn all the system properties into ant properties. - * user properties still override these values - */ - public void setSystemProperties() { - Properties systemP = System.getProperties(); - Enumeration e = systemP.keys(); - while (e.hasMoreElements()) { - Object name = e.nextElement(); - String value = systemP.get(name).toString(); - this.setPropertyInternal(name.toString(), value); - } + return (symbols.get(role, name) != null); } + /** - * add a new task definition, complain if there is an overwrite attempt - * @param taskName name of the task - * @param taskClass full task classname - * @throws BuildException and logs as Project.MSG_ERR for - * conditions, that will cause the task execution to fail. + * add a new task definition, complain if there is an overwrite attempt + * + *@param taskName name of the task + *@param taskClass full task classname + *@throws BuildException and logs as Project.MSG_ERR for conditions, that + * will cause the task execution to fail. */ - public void addTaskDefinition(String taskName, Class taskClass) - throws BuildException { - Class old = symbols.add("task", taskName, taskClass); - if (null != old && !old.equals(taskClass)) { - invalidateCreatedTasks(taskName); - } - - String msg = - " +User task: " + taskName + " " + taskClass.getName(); - log(msg, MSG_DEBUG); - checkTaskClass(taskClass); + public void addTaskDefinition(String taskName, Class taskClass) + throws BuildException { + addDefinitionOnRole(TASK_ROLE, taskName, taskClass); } + /** - * Checks a class, whether it is suitable for serving as ant task. - * @throws BuildException and logs as Project.MSG_ERR for - * conditions, that will cause the task execution to fail. + * Checks a class, whether it is suitable for serving as ant task. + * + *@param taskClass Description of the Parameter + *@throws BuildException and logs as Project.MSG_ERR for conditions, that + * will cause the task execution to fail. + *@deprecated this is done now when added to SymbolTable */ public void checkTaskClass(final Class taskClass) throws BuildException { - if( !Task.class.isAssignableFrom(taskClass) ) { + if (!Task.class.isAssignableFrom(taskClass)) { TaskAdapter.checkTaskClass(taskClass, this); } } + /** - * get the current task definition hashtable + * get the current task definition hashtable + * + *@return The taskDefinitions value */ public Hashtable getTaskDefinitions() { - return symbols.getTaskDefinitions(); + return symbols.getDefinitions(TASK_ROLE); } + /** - * add a new datatype - * @param typeName name of the datatype - * @param typeClass full datatype classname + * add a new datatype + * + *@param typeName name of the datatype + *@param typeClass full datatype classname */ public void addDataTypeDefinition(String typeName, Class typeClass) { - symbols.add("datatype", typeName, typeClass); - - String msg = - " +User datatype: " + typeName + " " + typeClass.getName(); - log(msg, MSG_DEBUG); + addDefinitionOnRole(DATATYPE_ROLE, typeName, typeClass); } + /** - * get the current task definition hashtable + * get the current task definition hashtable + * + *@return The dataTypeDefinitions value */ public Hashtable getDataTypeDefinitions() { - return symbols.getDataTypeDefinitions(); + return symbols.getDefinitions(DATATYPE_ROLE); } + /** - * This call expects to add a new Target. - * @param target is the Target to be added to the current - * Project. - * @exception BuildException if the Target already exists - * in the project. - * @see Project#addOrReplaceTarget to replace existing Targets. + * This call expects to add a new Target. + * + *@param target is the Target to be added to the current + * Project. + *@see Project#addOrReplaceTarget to replace existing + * Targets. */ public void addTarget(Target target) { String name = target.getName(); if (targets.get(name) != null) { - throw new BuildException("Duplicate target: `"+name+"'"); + throw new BuildException("Duplicate target: `" + name + "'"); } addOrReplaceTarget(name, target); } + /** - * This call expects to add a new Target. - * @param target is the Target to be added to the current - * Project. - * @param targetName is the name to use for the Target - * @exception BuildException if the Target already exists - * in the project. - * @see Project#addOrReplaceTarget to replace existing Targets. - */ - public void addTarget(String targetName, Target target) - throws BuildException { - if (targets.get(targetName) != null) { - throw new BuildException("Duplicate target: `"+targetName+"'"); - } - addOrReplaceTarget(targetName, target); - } + * This call expects to add a new Target. + * + *@param target is the Target to be added to the current + * Project. + *@param targetName is the name to use for the Target + *@exception BuildException if the Target already exists in the project. + *@see Project#addOrReplaceTarget to replace existing + * Targets. + */ + public void addTarget(String targetName, Target target) + throws BuildException { + if (targets.get(targetName) != null) { + throw new BuildException("Duplicate target: `" + targetName + "'"); + } + addOrReplaceTarget(targetName, target); + } + /** - * @param target is the Target to be added or replaced in - * the current Project. + *@param target is the Target to be added or replaced in the current + * Project. */ public void addOrReplaceTarget(Target target) { addOrReplaceTarget(target.getName(), target); } + /** - * @param target is the Target to be added/replaced in - * the current Project. - * @param targetName is the name to use for the Target + *@param target is the Target to be added/replaced in the current + * Project. + *@param targetName is the name to use for the Target */ public void addOrReplaceTarget(String targetName, Target target) { String msg = " +Target: " + targetName; @@ -772,59 +1039,123 @@ public class Project { targets.put(targetName, target); } + /** - * get the target hashtable - * @return hashtable, the contents of which can be cast to Target + * get the target hashtable + * + *@return hashtable, the contents of which can be cast to Target */ public Hashtable getTargets() { return targets; } + /** - * create a new task instance - * @param taskType name of the task - * @throws BuildException when task creation goes bad - * @return null if the task name is unknown + * Create a new element instance on a Role + * + *@param role name of the role to use + *@param type name of the element to create + *@return null if element unknown on this role */ - public Task createTask(String taskType) throws BuildException { - Class c = symbols.get("task", taskType); - - if (c == null) { + public Object createForRole(String role, String type) { + SymbolTable.Factory f = symbols.get(role, type); + if (f == null) { return null; } - + try { - Object o = c.newInstance(); - Task task = null; - if( o instanceof Task ) { - task=(Task)o; - } else { - // "Generic" Bean - use the setter pattern - // and an Adapter - TaskAdapter taskA=new TaskAdapter(); - taskA.setProxy( o ); - task=taskA; + Object o = f.create(this); + // Do special book keeping for ProjectComponents + if (o instanceof ProjectComponent) { + ((ProjectComponent) o).setProject(this); + if (o instanceof Task) { + Task task = (Task) o; + task.setTaskType(type); + + // set default value, can be changed by the user + task.setTaskName(type); + addCreatedTask(type, task); + } } - task.setProject(this); - task.setTaskType(taskType); - - // set default value, can be changed by the user - task.setTaskName(taskType); - - String msg = " +Task: " + taskType; - log (msg, MSG_DEBUG); - addCreatedTask(taskType, task); - return task; + String msg = " +" + role + ": " + type; + log(msg, MSG_DEBUG); + return o; } catch (Throwable t) { - String msg = "Could not create task of type: " - + taskType + " due to " + t; + String msg = "Could not create " + role + " of type: " + + type + " due to " + t; throw new BuildException(msg, t); } } + + /** + *@param container Description of the Parameter + *@param type Description of the Parameter + *@return Description of the Return Value + */ + public Object createInRole(Object container, String type) { + Class clz = container.getClass(); + String roles[] = symbols.findRoles(clz); + Object theOne = null; + Method add = null; + + for (int i = 0; i < roles.length; i++) { + Object o = createForRole(roles[i], type); + if (o != null) { + if (theOne != null) { + String msg = "Element " + type + + " is ambiguous for container " + clz.getName(); + if (theOne instanceof RoleAdapter) { + theOne = ((RoleAdapter) theOne).getProxy(); + } + if (o instanceof RoleAdapter) { + o = ((RoleAdapter) o).getProxy(); + } + + log(msg, MSG_ERR); + log("cannot distinguish between " + + theOne.getClass().getName() + + " and " + o.getClass().getName(), MSG_ERR); + throw new BuildException(msg); + } + theOne = o; + add = symbols.getRole(roles[i]).getInterfaceMethod(); + } + } + if (theOne != null) { + try { + add.invoke(container, new Object[]{theOne}); + } catch (InvocationTargetException ite) { + if (ite.getTargetException() instanceof BuildException) { + throw (BuildException) ite.getTargetException(); + } + throw new BuildException(ite.getTargetException()); + } catch (Exception e) { + throw new BuildException(e); + } + } + return theOne; + } + + /** - * Keep a record of all tasks that have been created so that they - * can be invalidated if a taskdef overrides the definition. + * create a new task instance + * + *@param taskType name of the task + *@return null if the task name is unknown + *@throws BuildException when task creation goes bad + */ + public Task createTask(String taskType) throws BuildException { + return (Task) createForRole(TASK_ROLE, taskType); + } + + + /** + * Keep a record of all tasks that have been created so that they can be + * invalidated if a taskdef overrides the definition. + * + *@param type The feature to be added to the CreatedTask attribute + *@param task The feature to be added to the CreatedTask attribute */ private void addCreatedTask(String type, Task task) { synchronized (createdTasks) { @@ -837,9 +1168,12 @@ public class Project { } } + /** - * Mark tasks as invalid which no longer are of the correct type - * for a given taskname. + * Mark tasks as invalid which no longer are of the correct type for a + * given taskname. + * + *@param type Description of the Parameter */ private void invalidateCreatedTasks(String type) { synchronized (createdTasks) { @@ -856,88 +1190,63 @@ public class Project { } } + /** - * create a new DataType instance - * @param typeName name of the datatype - * @throws BuildException when datatype creation goes bad - * @return null if the datatype name is unknown + * create a new DataType instance + * + *@param typeName name of the datatype + *@return null if the datatype name is unknown + *@throws BuildException when datatype creation goes bad */ public Object createDataType(String typeName) throws BuildException { - Class c = symbols.get("datatype", typeName); - - if (c == null) { - return null; - } - - try { - java.lang.reflect.Constructor ctor = null; - boolean noArg = false; - // DataType can have a "no arg" constructor or take a single - // Project argument. - try { - ctor = c.getConstructor(new Class[0]); - noArg = true; - } catch (NoSuchMethodException nse) { - ctor = c.getConstructor(new Class[] {Project.class}); - noArg = false; - } - - Object o = null; - if (noArg) { - o = ctor.newInstance(new Object[0]); - } else { - o = ctor.newInstance(new Object[] {this}); - } - if (o instanceof ProjectComponent) { - ((ProjectComponent)o).setProject(this); - } - String msg = " +DataType: " + typeName; - log (msg, MSG_DEBUG); - return o; - } catch (java.lang.reflect.InvocationTargetException ite) { - Throwable t = ite.getTargetException(); - String msg = "Could not create datatype of type: " - + typeName + " due to " + t; - throw new BuildException(msg, t); - } catch (Throwable t) { - String msg = "Could not create datatype of type: " - + typeName + " due to " + t; - throw new BuildException(msg, t); - } + // This is to make the function backward compatible + // Since we know if it returning an adapter for it + DataTypeAdapterTask dt = + (DataTypeAdapterTask) createForRole(DATATYPE_ROLE, typeName); + return (dt != null ? dt.getProxy() : null); } + /** - * execute the sequence of targets, and the targets they depend on - * @param Vector a vector of target name strings - * @throws BuildException if the build failed + * execute the sequence of targets, and the targets they depend on + * + *@param targetNames Description of the Parameter + *@throws BuildException if the build failed */ public void executeTargets(Vector targetNames) throws BuildException { Throwable error = null; for (int i = 0; i < targetNames.size(); i++) { - executeTarget((String)targetNames.elementAt(i)); + executeTarget((String) targetNames.elementAt(i)); } } + + /** + * Description of the Method + * + *@param line Description of the Parameter + *@param isError Description of the Parameter + */ public void demuxOutput(String line, boolean isError) { - Task task = (Task)threadTasks.get(Thread.currentThread()); + Task task = (Task) threadTasks.get(Thread.currentThread()); if (task == null) { fireMessageLogged(this, line, isError ? MSG_ERR : MSG_INFO); - } - else { + } else { if (isError) { task.handleErrorOutput(line); - } - else { + } else { task.handleOutput(line); } } } - + + /** - * execute the targets and any targets it depends on - * @param targetName the target to execute - * @throws BuildException if the build failed + * execute the targets and any targets it depends on + * + *@param targetName the target to execute + *@throws BuildException if the build failed */ public void executeTarget(String targetName) throws BuildException { @@ -965,37 +1274,47 @@ public class Project { } while (!curtarget.getName().equals(targetName)); } + /** - * Return the canonical form of fileName as an absolute path. + * Return the canonical form of fileName as an absolute path.

* - *

If fileName is a relative file name, resolve it relative to - * rootDir.

+ * If fileName is a relative file name, resolve it relative to rootDir.

* - * @deprecated + *@param fileName Description of the Parameter + *@param rootDir Description of the Parameter + *@return Description of the Return Value + *@deprecated */ public File resolveFile(String fileName, File rootDir) { return fileUtils.resolveFile(rootDir, fileName); } + + /** + * Description of the Method + * + *@param fileName Description of the Parameter + *@return Description of the Return Value + */ public File resolveFile(String fileName) { return fileUtils.resolveFile(baseDir, fileName); } + /** - * Translate a path into its native (platform specific) format. - *

- * This method uses the PathTokenizer class to separate the input path - * into its components. This handles DOS style paths in a relatively - * sensible way. The file separators are then converted to their platform - * specific versions. + * Translate a path into its native (platform specific) format.

* - * @param to_process the path to be converted + * This method uses the PathTokenizer class to separate the input path into + * its components. This handles DOS style paths in a relatively sensible + * way. The file separators are then converted to their platform specific + * versions. * - * @return the native version of to_process or - * an empty string if to_process is null or empty + *@param to_process the path to be converted + *@return the native version of to_process or an empty string if + * to_process is null or empty */ public static String translatePath(String to_process) { - if ( to_process == null || to_process.length() == 0 ) { + if (to_process == null || to_process.length() == 0) { return ""; } @@ -1010,142 +1329,178 @@ public class Project { } path.append(pathComponent); } - + return path.toString(); } + /** - * Convienence method to copy a file from a source to a destination. - * No filtering is performed. + * Convienence method to copy a file from a source to a destination. No + * filtering is performed. * - * @throws IOException - * - * @deprecated + *@param sourceFile Description of the Parameter + *@param destFile Description of the Parameter + *@throws IOException + *@deprecated */ public void copyFile(String sourceFile, String destFile) throws IOException { fileUtils.copyFile(sourceFile, destFile); } + /** - * Convienence method to copy a file from a source to a destination - * specifying if token filtering must be used. + * Convienence method to copy a file from a source to a destination + * specifying if token filtering must be used. * - * @throws IOException - * - * @deprecated + *@param sourceFile Description of the Parameter + *@param destFile Description of the Parameter + *@param filtering Description of the Parameter + *@throws IOException + *@deprecated */ public void copyFile(String sourceFile, String destFile, boolean filtering) - throws IOException { + throws IOException { fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null); } + /** - * Convienence method to copy a file from a source to a - * destination specifying if token filtering must be used and if - * source files may overwrite newer destination files. - * - * @throws IOException + * Convienence method to copy a file from a source to a destination + * specifying if token filtering must be used and if source files may + * overwrite newer destination files. * - * @deprecated + *@param sourceFile Description of the Parameter + *@param destFile Description of the Parameter + *@param filtering Description of the Parameter + *@param overwrite Description of the Parameter + *@throws IOException + *@deprecated */ public void copyFile(String sourceFile, String destFile, boolean filtering, - boolean overwrite) throws IOException { + boolean overwrite) throws IOException { fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null, overwrite); } - /** - * Convienence method to copy a file from a source to a - * destination specifying if token filtering must be used, if - * source files may overwrite newer destination files and the - * last modified time of destFile file should be made equal - * to the last modified time of sourceFile. - * - * @throws IOException + + /** + * Convienence method to copy a file from a source to a destination + * specifying if token filtering must be used, if source files may + * overwrite newer destination files and the last modified time of destFile + * file should be made equal to the last modified time of sourceFile + * . * - * @deprecated + *@param sourceFile Description of the Parameter + *@param destFile Description of the Parameter + *@param filtering Description of the Parameter + *@param overwrite Description of the Parameter + *@param preserveLastModified Description of the Parameter + *@throws IOException + *@deprecated */ public void copyFile(String sourceFile, String destFile, boolean filtering, - boolean overwrite, boolean preserveLastModified) - throws IOException { - fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null, - overwrite, preserveLastModified); + boolean overwrite, boolean preserveLastModified) + throws IOException { + fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null, + overwrite, preserveLastModified); } + /** - * Convienence method to copy a file from a source to a destination. - * No filtering is performed. - * - * @throws IOException + * Convienence method to copy a file from a source to a destination. No + * filtering is performed. * - * @deprecated + *@param sourceFile Description of the Parameter + *@param destFile Description of the Parameter + *@throws IOException + *@deprecated */ public void copyFile(File sourceFile, File destFile) throws IOException { fileUtils.copyFile(sourceFile, destFile); } + /** - * Convienence method to copy a file from a source to a destination - * specifying if token filtering must be used. + * Convienence method to copy a file from a source to a destination + * specifying if token filtering must be used. * - * @throws IOException - * - * @deprecated + *@param sourceFile Description of the Parameter + *@param destFile Description of the Parameter + *@param filtering Description of the Parameter + *@throws IOException + *@deprecated */ public void copyFile(File sourceFile, File destFile, boolean filtering) - throws IOException { + throws IOException { fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null); } + /** - * Convienence method to copy a file from a source to a - * destination specifying if token filtering must be used and if - * source files may overwrite newer destination files. - * - * @throws IOException + * Convienence method to copy a file from a source to a destination + * specifying if token filtering must be used and if source files may + * overwrite newer destination files. * - * @deprecated + *@param sourceFile Description of the Parameter + *@param destFile Description of the Parameter + *@param filtering Description of the Parameter + *@param overwrite Description of the Parameter + *@throws IOException + *@deprecated */ public void copyFile(File sourceFile, File destFile, boolean filtering, - boolean overwrite) throws IOException { + boolean overwrite) throws IOException { fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null, overwrite); } + /** - * Convienence method to copy a file from a source to a - * destination specifying if token filtering must be used, if - * source files may overwrite newer destination files and the - * last modified time of destFile file should be made equal - * to the last modified time of sourceFile. - * - * @throws IOException + * Convienence method to copy a file from a source to a destination + * specifying if token filtering must be used, if source files may + * overwrite newer destination files and the last modified time of destFile + * file should be made equal to the last modified time of sourceFile + * . * - * @deprecated + *@param sourceFile Description of the Parameter + *@param destFile Description of the Parameter + *@param filtering Description of the Parameter + *@param overwrite Description of the Parameter + *@param preserveLastModified Description of the Parameter + *@throws IOException + *@deprecated */ public void copyFile(File sourceFile, File destFile, boolean filtering, - boolean overwrite, boolean preserveLastModified) - throws IOException { - fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null, - overwrite, preserveLastModified); + boolean overwrite, boolean preserveLastModified) + throws IOException { + fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null, + overwrite, preserveLastModified); } + /** - * Calls File.setLastModified(long time) in a Java 1.1 compatible way. + * Calls File.setLastModified(long time) in a Java 1.1 compatible way. * - * @deprecated + *@param file The new fileLastModified value + *@param time The new fileLastModified value + *@exception BuildException Description of the Exception + *@deprecated */ public void setFileLastModified(File file, long time) throws BuildException { if (getJavaVersion() == JAVA_1_1) { log("Cannot change the modification time of " + file - + " in JDK 1.1", Project.MSG_WARN); + + " in JDK 1.1", Project.MSG_WARN); return; } fileUtils.setFileLastModified(file, time); log("Setting modification time for " + file, MSG_VERBOSE); } + /** - * returns the boolean equivalent of a string, which is considered true - * if either "on", "true", or "yes" is found, ignoring case. + * returns the boolean equivalent of a string, which is considered true if + * either "on", "true", or "yes" is found, ignoring case. + * + *@param s Description of the Parameter + *@return Description of the Return Value */ public static boolean toBoolean(String s) { return (s.equalsIgnoreCase("on") || @@ -1153,19 +1508,22 @@ public class Project { s.equalsIgnoreCase("yes")); } + /** - * Topologically sort a set of Targets. - * @param root is the (String) name of the root Target. The sort is - * created in such a way that the sequence of Targets uptil the root - * target is the minimum possible such sequence. - * @param targets is a Hashtable representing a "name to Target" mapping - * @return a Vector of Strings with the names of the targets in - * sorted order. - * @exception BuildException if there is a cyclic dependency among the - * Targets, or if a Target does not exist. + * Topologically sort a set of Targets. + * + *@param root is the (String) name of the root Target. The + * sort is created in such a way that the sequence of Targets uptil the + * root target is the minimum possible such sequence. + *@param targets is a Hashtable representing a "name to Target" + * mapping + *@return a Vector of Strings with the names of the + * targets in sorted order. + *@exception BuildException if there is a cyclic dependency among the + * Targets, or if a Target does not exist. */ public final Vector topoSort(String root, Hashtable targets) - throws BuildException { + throws BuildException { Vector ret = new Vector(); Hashtable state = new Hashtable(); Stack visiting = new Stack(); @@ -1179,21 +1537,21 @@ public class Project { // build Target. tsort(root, targets, state, visiting, ret); - log("Build sequence for target `"+root+"' is "+ret, MSG_VERBOSE); - for (Enumeration en=targets.keys(); en.hasMoreElements();) { - String curTarget = (String)(en.nextElement()); + log("Build sequence for target `" + root + "' is " + ret, MSG_VERBOSE); + for (Enumeration en = targets.keys(); en.hasMoreElements(); ) { + String curTarget = (String) (en.nextElement()); String st = (String) state.get(curTarget); if (st == null) { tsort(curTarget, targets, state, visiting, ret); - } - else if (st == VISITING) { - throw new RuntimeException("Unexpected node in visiting state: "+curTarget); + } else if (st == VISITING) { + throw new RuntimeException("Unexpected node in visiting state: " + curTarget); } } - log("Complete build sequence is "+ret, MSG_VERBOSE); + log("Complete build sequence is " + ret, MSG_VERBOSE); return ret; } + // one step in a recursive DFS traversal of the Target dependency tree. // - The Hashtable "state" contains the state (VISITED or VISITING or null) // of all the target names. @@ -1211,14 +1569,24 @@ public class Project { // "ret" now contains the sorted sequence of Targets upto the current // Target. + /** + * Description of the Method + * + *@param root Description of the Parameter + *@param targets Description of the Parameter + *@param state Description of the Parameter + *@param visiting Description of the Parameter + *@param ret Description of the Parameter + *@exception BuildException Description of the Exception + */ private final void tsort(String root, Hashtable targets, - Hashtable state, Stack visiting, - Vector ret) - throws BuildException { + Hashtable state, Stack visiting, + Vector ret) + throws BuildException { state.put(root, VISITING); visiting.push(root); - Target target = (Target)(targets.get(root)); + Target target = (Target) (targets.get(root)); // Make sure we exist if (target == null) { @@ -1227,7 +1595,7 @@ public class Project { sb.append("' does not exist in this project. "); visiting.pop(); if (!visiting.empty()) { - String parent = (String)visiting.peek(); + String parent = (String) visiting.peek(); sb.append("It is used from target `"); sb.append(parent); sb.append("'."); @@ -1236,14 +1604,13 @@ public class Project { throw new BuildException(new String(sb)); } - for (Enumeration en=target.getDependencies(); en.hasMoreElements();) { + for (Enumeration en = target.getDependencies(); en.hasMoreElements(); ) { String cur = (String) en.nextElement(); - String m=(String)state.get(cur); + String m = (String) state.get(cur); if (m == null) { // Not been visited tsort(cur, targets, state, visiting, ret); - } - else if (m == VISITING) { + } else if (m == VISITING) { // Currently visiting this node, so have a cycle throw makeCircularException(cur, visiting); } @@ -1251,46 +1618,73 @@ public class Project { String p = (String) visiting.pop(); if (root != p) { - throw new RuntimeException("Unexpected internal error: expected to pop "+root+" but got "+p); + throw new RuntimeException("Unexpected internal error: expected to pop " + root + " but got " + p); } state.put(root, VISITED); ret.addElement(target); } + + /** + * Description of the Method + * + *@param end Description of the Parameter + *@param stk Description of the Parameter + *@return Description of the Return Value + */ private static BuildException makeCircularException(String end, Stack stk) { StringBuffer sb = new StringBuffer("Circular dependency: "); sb.append(end); String c; do { - c = (String)stk.pop(); + c = (String) stk.pop(); sb.append(" <- "); sb.append(c); - } while(!c.equals(end)); + } while (!c.equals(end)); return new BuildException(new String(sb)); } + + /** + * Adds a feature to the Reference attribute of the Project object + * + *@param name The feature to be added to the Reference attribute + *@param value The feature to be added to the Reference attribute + */ public void addReference(String name, Object value) { - if (null != references.get(name)) { - log("Overriding previous definition of reference to " + name, - MSG_WARN); + Object o = references.get(name); + if (null != o && o != value + && (!(o instanceof RoleAdapter) + || ((RoleAdapter) o).getProxy() != value)) { + log("Overriding previous definition of reference to " + name, + MSG_WARN); } log("Adding reference: " + name + " -> " + value, MSG_DEBUG); - references.put(name,value); + references.put(name, value); } + + /** + * Gets the references attribute of the Project object + * + *@return The references value + */ public Hashtable getReferences() { return references; } + /** - * @return The object with the "id" key. + *@param key Description of the Parameter + *@return The object with the "id" key. */ public Object getReference(String key) { return references.get(key); } + /** - * send build started event to the listeners + * send build started event to the listeners */ protected void fireBuildStarted() { BuildEvent event = new BuildEvent(this); @@ -1300,9 +1694,11 @@ public class Project { } } + /** - * send build finished event to the listeners - * @param exception exception which indicates failure if not null + * send build finished event to the listeners + * + *@param exception exception which indicates failure if not null */ protected void fireBuildFinished(Throwable exception) { BuildEvent event = new BuildEvent(this); @@ -1313,9 +1709,11 @@ public class Project { } } - + /** - * send target started event to the listeners + * send target started event to the listeners + * + *@param target Description of the Parameter */ protected void fireTargetStarted(Target target) { BuildEvent event = new BuildEvent(target); @@ -1325,9 +1723,12 @@ public class Project { } } + /** - * send build finished event to the listeners - * @param exception exception which indicates failure if not null + * send build finished event to the listeners + * + *@param exception exception which indicates failure if not null + *@param target Description of the Parameter */ protected void fireTargetFinished(Target target, Throwable exception) { BuildEvent event = new BuildEvent(target); @@ -1338,6 +1739,12 @@ public class Project { } } + + /** + * Description of the Method + * + *@param task Description of the Parameter + */ protected void fireTaskStarted(Task task) { // register this as the current task on the current thread. threadTasks.put(Thread.currentThread(), task); @@ -1348,6 +1755,13 @@ public class Project { } } + + /** + * Description of the Method + * + *@param task Description of the Parameter + *@param exception Description of the Parameter + */ protected void fireTaskFinished(Task task, Throwable exception) { threadTasks.remove(Thread.currentThread()); System.out.flush(); @@ -1360,6 +1774,14 @@ public class Project { } } + + /** + * Description of the Method + * + *@param event Description of the Parameter + *@param message Description of the Parameter + *@param priority Description of the Parameter + */ private void fireMessageLoggedEvent(BuildEvent event, String message, int priority) { event.setMessage(message, priority); for (int i = 0; i < listeners.size(); i++) { @@ -1368,18 +1790,43 @@ public class Project { } } + + /** + * Description of the Method + * + *@param project Description of the Parameter + *@param message Description of the Parameter + *@param priority Description of the Parameter + */ protected void fireMessageLogged(Project project, String message, int priority) { BuildEvent event = new BuildEvent(project); fireMessageLoggedEvent(event, message, priority); } + + /** + * Description of the Method + * + *@param target Description of the Parameter + *@param message Description of the Parameter + *@param priority Description of the Parameter + */ protected void fireMessageLogged(Target target, String message, int priority) { BuildEvent event = new BuildEvent(target); fireMessageLoggedEvent(event, message, priority); } + + /** + * Description of the Method + * + *@param task Description of the Parameter + *@param message Description of the Parameter + *@param priority Description of the Parameter + */ protected void fireMessageLogged(Task task, String message, int priority) { BuildEvent event = new BuildEvent(task); fireMessageLoggedEvent(event, message, priority); } + } diff --git a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/ProjectHelper.java b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/ProjectHelper.java index f832bce3e..fe832c3bb 100644 --- a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/ProjectHelper.java +++ b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/ProjectHelper.java @@ -114,7 +114,7 @@ public class ProjectHelper { private void parse() throws BuildException { FileInputStream inputStream = null; InputSource inputSource = null; - + try { SAXParser saxParser = getParserFactory().newSAXParser(); parser = saxParser.getParser(); @@ -123,7 +123,7 @@ public class ProjectHelper { for (int index = uri.indexOf('#'); index != -1; index = uri.indexOf('#')) { uri = uri.substring(0, index) + "%23" + uri.substring(index+1); } - + inputStream = new FileInputStream(buildFile); inputSource = new InputSource(inputStream); inputSource.setSystemId(uri); @@ -145,7 +145,7 @@ public class ProjectHelper { } throw be; } - + throw new BuildException(exc.getMessage(), t, location); } catch(SAXException exc) { @@ -231,20 +231,20 @@ public class ProjectHelper { */ public InputSource resolveEntity(String publicId, String systemId) { - + project.log("resolving systemId: " + systemId, Project.MSG_VERBOSE); - + if (systemId.startsWith("file:")) { String path = systemId.substring(5); int index = path.indexOf("file:"); - + // we only have to handle these for backward compatibility // since they are in the FAQ. while (index != -1) { path = path.substring(0, index) + path.substring(index + 5); index = path.indexOf("file:"); } - + String entitySystemId = path; index = path.indexOf("%23"); // convert these to # @@ -257,13 +257,13 @@ public class ProjectHelper { if (!file.isAbsolute()) { file = new File(buildFileParent, path); } - + try { InputSource inputSource = new InputSource(new FileInputStream(file)); inputSource.setSystemId("file:" + entitySystemId); return inputSource; } catch (FileNotFoundException fne) { - project.log(file.getAbsolutePath()+" could not be found", + project.log(file.getAbsolutePath()+" could not be found", Project.MSG_WARN); } } @@ -316,10 +316,10 @@ public class ProjectHelper { } if (def == null) { - throw new SAXParseException("The default attribute of project is required", + throw new SAXParseException("The default attribute of project is required", locator); } - + project.setDefaultTarget(def); @@ -360,6 +360,8 @@ public class ProjectHelper { handleTopTask(name, attrs); } else if (name.equals("target")) { handleTarget(name, attrs); + } else if (name.equals("description")) { + handleDescription(name, attrs); } else if (project.isDefinedOnRole(Project.DATATYPE_ROLE, name)) { handleTopTask(name, attrs); } else { @@ -367,9 +369,9 @@ public class ProjectHelper { } } - private void handleTopTask(String name, AttributeList attrs) - throws SAXParseException { - InmediateTarget target = new InmediateTarget(name); + private void handleTopTask(String name, AttributeList attrs) + throws SAXParseException { + InmediateTarget target = new InmediateTarget(name); (new TaskHandler(this, target, null, target)).init(name, attrs); } @@ -377,6 +379,10 @@ public class ProjectHelper { new TargetHandler(this).init(tag, attrs); } + private void handleDescription(String tag, AttributeList attrs) throws SAXParseException { + new DescriptionHandler(this).init(tag, attrs); + } + } /** @@ -441,8 +447,13 @@ public class ProjectHelper { } public void startElement(String name, AttributeList attrs) throws SAXParseException { - new TaskHandler(this, target, null, target).init(name, attrs); - } + if (name.equals("description")) { + new DescriptionHandler(this).init(name, attrs); + } + else { + new TaskHandler(this, target, null, target).init(name, attrs); + } + } } /** @@ -466,7 +477,7 @@ public class ProjectHelper { try { task = (Task)project.createInRole(container, tag); } catch (BuildException e) { - // swallow here, will be thrown again in + // swallow here, will be thrown again in // UnknownElement.maybeConfigure if the problem persists. } @@ -475,21 +486,21 @@ public class ProjectHelper { task.setProject(project); task.setTaskType(tag); task.setTaskName(tag); - container.addTask(task); + container.addTask(task); } - task.setLocation(new Location(buildFile.toString(), - locator.getLineNumber(), - locator.getColumnNumber())); + task.setLocation(new Location(buildFile.toString(), + locator.getLineNumber(), + locator.getColumnNumber())); configureId(task, attrs); - task.setOwningTarget(target); - task.init(); - wrapper = task.getRuntimeConfigurableWrapper(); - wrapper.setAttributes(attrs); - if (parentWrapper != null) { - parentWrapper.addChild(wrapper); - } + task.setOwningTarget(target); + task.init(); + wrapper = task.getRuntimeConfigurableWrapper(); + wrapper.setAttributes(attrs); + if (parentWrapper != null) { + parentWrapper.addChild(wrapper); + } } protected void finished() { @@ -531,7 +542,7 @@ public class ProjectHelper { private RuntimeConfigurable childWrapper = null; private Target target; - public NestedElementHandler(DocumentHandler parentHandler, + public NestedElementHandler(DocumentHandler parentHandler, Object parent, RuntimeConfigurable parentWrapper, Target target) { @@ -548,7 +559,7 @@ public class ProjectHelper { public void init(String propType, AttributeList attrs) throws SAXParseException { Class parentClass = parent.getClass(); - IntrospectionHelper ih = + IntrospectionHelper ih = IntrospectionHelper.getHelper(parentClass); try { @@ -557,9 +568,9 @@ public class ProjectHelper { UnknownElement uc = new UnknownElement(elementName); uc.setProject(project); ((UnknownElement) parent).addChild(uc); - // Set this parameters just in case is a Task - uc.setTaskType(elementName); - uc.setTaskName(elementName); + // Set this parameters just in case is a Task + uc.setTaskType(elementName); + uc.setTaskName(elementName); child = uc; } else { child = ih.createElement(project, parent, elementName); @@ -594,7 +605,7 @@ public class ProjectHelper { public void startElement(String name, AttributeList attrs) throws SAXParseException { if (child instanceof TaskContainer) { - // taskcontainer nested element can contain other tasks - no other + // taskcontainer nested element can contain other tasks - no other // nested elements possible new TaskHandler(this, (TaskContainer)child, childWrapper, target).init(name, attrs); } @@ -604,39 +615,64 @@ public class ProjectHelper { } } + /** + * Handler to perform appropriate semantics for the special + * element on tasks. + */ + private class DescriptionHandler extends AbstractHandler { + + public DescriptionHandler(DocumentHandler parent) { + super(parent); + } + + public void init(String tag, AttributeList attrs) throws SAXParseException { + if (attrs.getLength() > 0) { + throw new SAXParseException("No attributes allowed on " + tag, locator); + } + } + + public void characters(char[] buf, int start, int end) throws SAXParseException { + String desc = project.getDescription(); + if (desc == null) { + desc = ""; + } + project.setDescription(desc + new String(buf, start, end)); + } + } + /** * Special target type for top level Tasks and Datatypes. * This will allow eliminating special cases. */ private class InmediateTarget extends Target { - /** - * Create a target for a top level task or datatype. - * @param name the name of the task to be run on this target. - */ - InmediateTarget(String name) { - super(); - setProject(project); - setName("Top level " + name); - } + /** + * Create a target for a top level task or datatype. + * @param name the name of the task to be run on this target. + */ + InmediateTarget(String name) { + super(); + setProject(project); + setName("Top level " + name); + } } - public static void configure(Object target, AttributeList attrs, + public static void configure(Object target, AttributeList attrs, Project project) throws BuildException { if( target instanceof RoleAdapter ) { target=((RoleAdapter)target).getProxy(); } - IntrospectionHelper ih = + IntrospectionHelper ih = IntrospectionHelper.getHelper(target.getClass()); project.addBuildListener(ih); for (int i = 0; i < attrs.getLength(); i++) { // reflect these into the target - String value=replaceProperties(project, attrs.getValue(i), + String value=replaceProperties(project, attrs.getValue(i), project.getProperties() ); try { - ih.setAttribute(project, target, + ih.setAttribute(project, target, attrs.getName(i).toLowerCase(Locale.US), value); } catch (BuildException be) { @@ -674,7 +710,7 @@ public class ProjectHelper { } /** - * Stores a configured child element into its parent object + * Stores a configured child element into its parent object */ public static void storeChild(Project project, Object parent, Object child, String tag) { IntrospectionHelper ih = IntrospectionHelper.getHelper(parent.getClass()); @@ -719,23 +755,23 @@ public class ProjectHelper { if (!keys.containsKey(propertyName)) { project.log("Property ${" + propertyName + "} has not been set", Project.MSG_VERBOSE); } - fragment = (keys.containsKey(propertyName)) ? (String) keys.get(propertyName) - : "${" + propertyName + "}"; + fragment = (keys.containsKey(propertyName)) ? (String) keys.get(propertyName) + : "${" + propertyName + "}"; } sb.append(fragment); - } - + } + return sb.toString(); } /** - * This method will parse a string containing ${value} style + * This method will parse a string containing ${value} style * property values into two lists. The first list is a collection * of text fragments, while the other is a set of string property names * null entries in the first list indicate a property reference from the * second list. */ - public static void parsePropertyString(String value, Vector fragments, Vector propertyRefs) + public static void parsePropertyString(String value, Vector fragments, Vector propertyRefs) throws BuildException { int prev = 0; int pos; @@ -754,7 +790,7 @@ public class ProjectHelper { } else { int endName = value.indexOf('}', pos); if (endName < 0) { - throw new BuildException("Syntax error in property: " + throw new BuildException("Syntax error in property: " + value ); } String propertyName = value.substring(pos + 2, endName); @@ -779,17 +815,17 @@ public class ProjectHelper { /** * Scan AttributeList for the id attribute and maybe add a - * reference to project. + * reference to project. * *

Moved out of {@link #configure configure} to make it happen - * at parser time.

+ * at parser time.

*/ private void configureId(Object target, AttributeList attr) { String id = attr.getValue("id"); if (id != null) { - if( target instanceof RoleAdapter ) { - ((RoleAdapter)target).setId(id); - } + if( target instanceof RoleAdapter ) { + ((RoleAdapter)target).setId(id); + } project.addReference(id, target); } } diff --git a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/RoleAdapter.java b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/RoleAdapter.java index e028ebe92..57c1f62d9 100644 --- a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/RoleAdapter.java +++ b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/RoleAdapter.java @@ -55,6 +55,11 @@ package org.apache.tools.ant; public interface RoleAdapter { + /** + * Obtain the id in case it is needed. + */ + public void setId(String id); + /** * Set the object being adapted. * @param o the object being adapted diff --git a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/SymbolTable.java b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/SymbolTable.java index e6b8c843b..ecbb0984d 100644 --- a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/SymbolTable.java +++ b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/SymbolTable.java @@ -54,6 +54,7 @@ package org.apache.tools.ant; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; @@ -64,7 +65,7 @@ public class SymbolTable { /** Parent symbol table */ private SymbolTable parentTable; - + /** Project associated with this symbol table */ private Project project; @@ -82,8 +83,8 @@ public class SymbolTable { /** * Parameters for checking adapters. */ - private static final Class[] CHECK_ADAPTER_PARAMS = - new Class[]{Class.class, Project.class}; + private static final Class[] CHECK_ADAPTER_PARAMS = + new Class[]{Class.class, Project.class}; /** * Create a top level Symbol table. @@ -96,8 +97,8 @@ public class SymbolTable { * from that defined in the calling Project. * @param p the calling project */ - public SymbolTable(Project p) { - parentTable = p.getSymbols(); + public SymbolTable(SymbolTable st) { + parentTable = st; } /** @@ -105,7 +106,55 @@ public class SymbolTable { * @param p the project for this symbol table */ public void setProject(Project p) { - this.project = p; + this.project = p; + } + + /** + * Get the specified loader for the project. + * @param name the name of the loader + * @return the corresponding ANT classloader + */ + private AntClassLoader getLoader(String name) { + AntClassLoader cl = (AntClassLoader) loaders.get(name); + if (cl == null && parentTable != null) { + return parentTable.getLoader(name); + } + return cl; + } + + /** + * Add the specified class-path to a loader. + * If the loader is defined in an ancestor project then a new + * classloader inheritin from the one already existing + * will be created, otherwise the path willbe added to the existing + * ClassLoader. + * @param name the name of the loader to use. + * @param clspath the path to be added to the classloader + */ + public ClassLoader addToLoader(String name, Path clspath) { + // Find if the loader is already defined in the current project + AntClassLoader cl = (AntClassLoader) loaders.get(name); + if (cl == null) { + // Is it inherited from the calling project + if (parentTable != null) { + cl = parentTable.getLoader(name); + } + cl = new AntClassLoader(cl, project, clspath, true); + loaders.put(name, cl); + } + else { + // Add additional path to the existing definition + String[] pathElements = clspath.list(); + for (int i = 0; i < pathElements.length; ++i) { + try { + cl.addPathElement(pathElements[i]); + } + catch (BuildException e) { + // ignore path elements invalid relative to the project + } + } + } + return cl; } /** @@ -115,9 +164,9 @@ public class SymbolTable { * @return an array of roles supported by the class */ public String[] findRoles(final Class clz) { - Vector list = new Vector(); - findRoles(clz, list); - return (String[])list.toArray(new String[list.size()]); + Vector list = new Vector(); + findRoles(clz, list); + return (String[])list.toArray(new String[list.size()]); } /** @@ -126,27 +175,27 @@ public class SymbolTable { * @param list the roles collected up to this point */ private void findRoles(final Class clz, Vector list) { - for (Enumeration e = roles.keys(); e.hasMoreElements();) { - String role = (String) e.nextElement(); - - if (((Role) roles.get(role)).isImplementedBy(clz)) { - list.addElement(role); - } - } - if (parentTable != null) findRoles(clz, list); + for (Enumeration e = roles.keys(); e.hasMoreElements();) { + String role = (String) e.nextElement(); + + if (((Role) roles.get(role)).isImplementedBy(clz)) { + list.addElement(role); + } + } + if (parentTable != null) parentTable.findRoles(clz, list); } - + /** * Get the Role definition * @param role the name of the role - * @return the method used to support objects on this role + * @return the Role description */ public Role getRole(String role) { - Role r = (Role) roles.get(role); - if (r == null && parentTable != null) { - return parentTable.getRole(role); - } - return r; + Role r = (Role) roles.get(role); + if (r == null && parentTable != null) { + return parentTable.getRole(role); + } + return r; } /** @@ -157,126 +206,19 @@ public class SymbolTable { * @return whether the role replaced a different definition */ public boolean addRole(String role, Class rclz, Class aclz) { - // Check if role already declared - Role old = getRole(role); - if (old != null && old.isSameAsFor(rclz, aclz) - ) { - project.log("Ignoring override for role " + role - + ", it is already defined by the same definition.", - project.MSG_VERBOSE); - return false; - } - // Role interfaces should only contain one method - roles.put(role, new Role(rclz, aclz)); - return (old != null); - } - - /** - * Verify if the interface is valid. - * @param clz the interface to validate - * @return the method defined by the interface - */ - private Method validInterface(Class clz) { - Method m[] = clz.getDeclaredMethods(); - if (m.length == 1 - && java.lang.Void.TYPE.equals(m[0].getReturnType())) { - Class args[] = m[0].getParameterTypes(); - if (args.length == 1 - && !java.lang.String.class.equals(args[0]) - && !args[0].isArray() - && !args[0].isPrimitive()) { - return m[0]; - } - else { - throw new BuildException("Invalid role interface method in: " - + clz.getName()); - } - } - else { - throw new BuildException("More than one method on role interface"); - } - } - - /** - * Verify if the adapter is valid with respect to the interface. - * @param clz the class adapter to validate - * @param mtd the method whose only argument must match - * @return the static method to use for validating adaptees - */ - private Method validAdapter(Class clz, Method mtd) { - if (clz == null) return null; - - checkClass(clz); - if (!mtd.getParameterTypes()[0].isAssignableFrom(clz)) { - String msg = "Adapter " + clz.getName() + - " is incompatible with role interface " + - mtd.getDeclaringClass().getName(); - throw new BuildException(msg); - } - String msg = "Class " + clz.getName() + " is not an adapter: "; - if (!RoleAdapter.class.isAssignableFrom(clz)) { - throw new BuildException(msg + "does not implement RoleAdapter"); - } - try { - Method chk = clz.getMethod("checkClass", CHECK_ADAPTER_PARAMS); - if (!Modifier.isStatic(chk.getModifiers())) { - throw new BuildException(msg + "checkClass() is not static"); - } - return chk; - } - catch(NoSuchMethodException nme){ - throw new BuildException(msg + "checkClass() not found", nme); - } - } - - /** - * Get the specified loader for the project. - * @param name the name of the loader - * @return the corresponding ANT classloader - */ - private AntClassLoader getLoader(String name) { - AntClassLoader cl = (AntClassLoader) loaders.get(name); - if (cl == null && parentTable != null) { - return parentTable.getLoader(name); - } - return cl; + // Check if role already declared + Role old = getRole(role); + if (old != null && old.isSameAsFor(rclz, aclz)) { + project.log("Ignoring override for role " + role + + ", it is already defined by the same definition.", + project.MSG_VERBOSE); + return false; + } + // Role interfaces should only contain one method + roles.put(role, new Role(rclz, aclz)); + return (old != null); } - /** - * Add the specified class-path to a loader. - * If the loader is defined in an ancestor project then a new - * classloader inheritin from the one already existing - * will be created, otherwise the path willbe added to the existing - * ClassLoader. - * @param name the name of the loader to use. - * @param clspath the path to be added to the classloader - */ - public ClassLoader addToLoader(String name, Path clspath) { - // Find if the loader is already defined in the current project - AntClassLoader cl = (AntClassLoader) loaders.get(name); - if (cl == null) { - // Is it inherited from the calling project - if (parentTable != null) { - cl = parentTable.getLoader(name); - } - cl = new AntClassLoader(cl, project, clspath, true); - loaders.put(name, cl); - } - else { - // Add additional path to the existing definition - String[] pathElements = clspath.list(); - for (int i = 0; i < pathElements.length; ++i) { - try { - cl.addPathElement(pathElements[i]); - } - catch (BuildException e) { - // ignore path elements invalid relative to the project - } - } - } - return cl; - } - /** * Add a new type of element to a role. * @param role the role for this Class. @@ -285,46 +227,53 @@ public class SymbolTable { * @return the old definition */ public Class add(String role, String name, Class clz) { - // Find the role definition - Role r = getRole(role); - if (r == null) { - throw new BuildException("Unknown role: " + role); - } - // Check if it is already defined - Class old = get(role, name); - if (old != null) { - if (old.equals(clz)) { - project.log("Ignoring override for "+ role + " " + name - + ", it is already defined by the same class.", - project.MSG_VERBOSE); - return old; - } - else { + // Find the role definition + Role r = getRole(role); + if (r == null) { + throw new BuildException("Unknown role: " + role); + } + // Check if it is already defined + Factory old = get(role, name); + if (old != null) { + if (old.getOriginalClass().equals(clz)) { + project.log("Ignoring override for "+ role + " " + name + + ", it is already defined by the same class.", + project.MSG_VERBOSE); + return old.getOriginalClass(); + } + else { project.log("Trying to override old definition of " + - role + " " + name, - project.MSG_WARN); - } - } - checkClass(clz); - // Check that the Class is compatible with the role definition - r.verifyAdaptability(role, clz); - // Record the new type - Hashtable defTable = (Hashtable)defs.get(role); - if (defTable == null) { - defTable = new Hashtable(); - defs.put(role, defTable); - } - defTable.put(name, clz); - return old; + role + " " + name, + project.MSG_WARN); + } + } + Factory f = checkClass(clz); + // Check that the Class is compatible with the role definition + f = r.verifyAdaptability(role, f); + // Record the new type + Hashtable defTable = (Hashtable)defs.get(role); + if (defTable == null) { + defTable = new Hashtable(); + defs.put(role, defTable); + } + defTable.put(name, f); + + String msg = + " +User " + role + ": " + name + " " + clz.getName(); + project.log(msg, project.MSG_DEBUG); + return (old != null ? old.getOriginalClass() : null); } /** * Checks a class, whether it is suitable for serving in ANT. + * @return the factory to use when instantiating the class * @throws BuildException and logs as Project.MSG_ERR for * conditions, that will cause execution to fail. */ - void checkClass(final Class clz) - throws BuildException { + Factory checkClass(final Class clz) // Package on purpose + throws BuildException { + if (clz == null) return null; + if(!Modifier.isPublic(clz.getModifiers())) { final String message = clz + " is not public"; project.log(message, Project.MSG_ERR); @@ -336,21 +285,53 @@ public class SymbolTable { throw new BuildException(message); } try { - // Class can have a "no arg" constructor or take a single + // Class can have a "no arg" constructor or take a single // Project argument. // don't have to check for public, since // getConstructor finds public constructors only. try { clz.getConstructor(new Class[0]); + return new Factory(){ + public Object create(Project p) { + try { + return clz.newInstance(); + } + catch(Exception e) { + throw new BuildException(e); + } + } + + public Class getOriginalClass() { + return clz; + } + }; } catch (NoSuchMethodException nse) { - clz.getConstructor(new Class[] {Project.class}); + final Constructor c = + clz.getConstructor(new Class[] {Project.class}); + return new Factory(){ + public Object create(Project p) { + try { + return c.newInstance(new Object[]{p}); + } + catch(Exception e) { + throw new BuildException(e); + } + } + + public Class getOriginalClass() { + return clz; + } + }; } } catch(NoSuchMethodException e) { - final String message = - "No valid public constructor in " + clz; + final String message = "No valid public constructor in " + clz; project.log(message, Project.MSG_ERR); throw new BuildException(message); } + catch (NoClassDefFoundError ncdfe) { + final String msg = "Class cannot be loaded: " + ncdfe.getMessage(); + throw new BuildException(msg, ncdfe); + } } /** @@ -359,32 +340,25 @@ public class SymbolTable { * @param name the name of the element to sea * @return the Class implementation */ - public Class get(String role, String name) { - Hashtable defTable = (Hashtable)defs.get(role); - if (defTable != null) { - Class clz = (Class)defTable.get(name); - if (clz != null) return clz; - } - if (parentTable != null) { - return parentTable.get(role, name); - } - return null; - } - - /** - * Get a Hashtable that is usable for manipulating Tasks, - * @return a Hashtable that delegates to the Symbol table. - */ - public Hashtable getTaskDefinitions() { - return new SymbolHashtable("task"); + public Factory get(String role, String name) { + Hashtable defTable = (Hashtable)defs.get(role); + if (defTable != null) { + Factory f = (Factory)defTable.get(name); + if (f != null) return f; + } + if (parentTable != null) { + return parentTable.get(role, name); + } + return null; } /** - * Get a Hashtable that is usable for manipulating Datatypes, + * Get a Hashtable that is usable for manipulating elements on Role. + * @param role the role of the elements in the table * @return a Hashtable that delegates to the Symbol table. */ - public Hashtable getDataTypeDefinitions() { - return new SymbolHashtable("datatype"); + Hashtable getDefinitions(String role) { // package scope on purpose + return new SymbolHashtable(role); } /** @@ -392,100 +366,196 @@ public class SymbolTable { * the search operations to the Symbol table */ private class SymbolHashtable extends Hashtable { - final String role; - SymbolHashtable(String role) { - this.role = role; - } - - public synchronized Object put(Object key, Object value) { - return SymbolTable.this.add(role, (String) key, (Class) value); - } - - public synchronized Object get(Object key) { - return SymbolTable.this.get(role, (String)key); - } + final String role; + SymbolHashtable(String role) { + this.role = role; + } + + public synchronized Object put(Object key, Object value) { + return SymbolTable.this.add(role, (String) key, (Class) value); + } + + public synchronized Object get(Object key) { + Factory f = SymbolTable.this.get(role, (String)key); + return (f == null? null : f.getOriginalClass()); + } + } + + /** + * Factory for creating ANT objects. + * Class objects are not instanciated directly but through a Factory + * which is able to resolve issues such as proxys and such. + */ + public static interface Factory { + /** + * Creates an object for the Role + * @param the project in which it is created + * @return the instantiated object with a proxy if necessary + */ + public Object create(Project p); + + /** + * Creates an object for the Role, adapted if necessary + * for a particular interface. + */ +// public Object adaptFor(Class clz, Project p, Object o); + + /** + * The original class of the object without proxy. + */ + public Class getOriginalClass(); } /** * The definition of a role */ public class Role { - private Method interfaceMethod; - private Method adapterVerifier; - - /** - * Creates a new Role object - * @param roleClz the class that defines the role - * @param adapterClz the class for the adapter, or null if none - */ - Role(Class roleClz, Class adapterClz) { - interfaceMethod = validInterface(roleClz); - adapterVerifier = validAdapter(adapterClz, interfaceMethod); - } - - /** - * Get the method used to set on interface - */ - public Method getInterfaceMethod() { - return interfaceMethod; - } - - /** - * Instantiate a new adapter for this role. - */ - public RoleAdapter createAdapter() { - if (adapterVerifier == null) return null; - - try { - return (RoleAdapter) - adapterVerifier.getDeclaringClass().newInstance(); - } - catch(BuildException be) { - throw be; - } - catch(Exception e) { - throw new BuildException(e); - } - } - - /** - * Verify if the class can be adapted to use by the role - * @param role the name of the role to verify - * @param clz the class to verify - */ - public void verifyAdaptability(String role, Class clz) { - if (interfaceMethod.getParameterTypes()[0].isAssignableFrom(clz)) { - return; - } - if (adapterVerifier == null) { - String msg = "Class " + clz.getName() + - " incompatible with role: " + role; - throw new BuildException(msg); - } - try { - try { - adapterVerifier.invoke(null, - new Object[]{clz, project}); - } - catch (InvocationTargetException ite) { - throw ite.getTargetException(); - } - } - catch(BuildException be) { throw be; } - catch(Error err) {throw err; } - catch(Throwable t) { - throw new BuildException(t); - } - } - - public boolean isSameAsFor(Class clz, Class pclz) { - return interfaceMethod.getDeclaringClass().equals(clz) && - ((adapterVerifier == null && pclz == null) || - adapterVerifier.getDeclaringClass().equals(pclz)); - } - - public boolean isImplementedBy(Class clz) { - return interfaceMethod.getDeclaringClass().isAssignableFrom(clz); - } + private Method interfaceMethod; + private Method adapterVerifier; + private Factory adapterFactory; + + /** + * Creates a new Role object + * @param roleClz the class that defines the role + * @param adapterClz the class for the adapter, or null if none + */ + Role(Class roleClz, Class adapterClz) { + interfaceMethod = validInterface(roleClz); + adapterFactory = checkClass(adapterClz); + adapterVerifier = validAdapter(adapterClz, interfaceMethod); + } + + /** + * Get the method used to set on interface + */ + public Method getInterfaceMethod() { + return interfaceMethod; + } + + /** + * Instantiate a new adapter for this role. + */ + public RoleAdapter createAdapter(Project p) { + if (adapterFactory == null) return null; + + try { + return (RoleAdapter) adapterFactory.create(p); + } + catch(BuildException be) { + throw be; + } + catch(Exception e) { + throw new BuildException(e); + } + } + + /** + * Verify if the class can be adapted to use by the role + * @param role the name of the role to verify + * @param f the factory for the class to verify + */ + public Factory verifyAdaptability(String role, final Factory f) { + final Class clz = f.getOriginalClass(); + if (interfaceMethod.getParameterTypes()[0].isAssignableFrom(clz)) { + return f; + } + if (adapterVerifier == null) { + String msg = "Class " + clz.getName() + + " incompatible with role: " + role; + throw new BuildException(msg); + } + try { + try { + adapterVerifier.invoke(null, new Object[]{clz, project}); + return new Factory(){ + public Object create(Project p) { + RoleAdapter ra = createAdapter(p); + ra.setProxy(f.create(p)); + return ra; + } + + public Class getOriginalClass() { + return clz; + } + }; + } + catch (InvocationTargetException ite) { + throw ite.getTargetException(); + } + } + catch(BuildException be) { throw be; } + catch(Error err) {throw err; } + catch(Throwable t) { + throw new BuildException(t); + } + } + + public boolean isSameAsFor(Class clz, Class pclz) { + return interfaceMethod.getDeclaringClass().equals(clz) && + ((adapterVerifier == null && pclz == null) || + adapterVerifier.getDeclaringClass().equals(pclz)); + } + + public boolean isImplementedBy(Class clz) { + return interfaceMethod.getDeclaringClass().isAssignableFrom(clz); + } + + /** + * Verify if the interface is valid. + * @param clz the interface to validate + * @return the method defined by the interface + */ + private Method validInterface(Class clz) { + Method m[] = clz.getDeclaredMethods(); + if (m.length == 1 + && java.lang.Void.TYPE.equals(m[0].getReturnType())) { + Class args[] = m[0].getParameterTypes(); + if (args.length == 1 + && !java.lang.String.class.equals(args[0]) + && !args[0].isArray() + && !args[0].isPrimitive()) { + return m[0]; + } + else { + throw new BuildException("Invalid role interface method in: " + + clz.getName()); + } + } + else { + throw new BuildException("More than one method on role interface"); + } + } + + /** + * Verify if the adapter is valid with respect to the interface. + * @param clz the class adapter to validate + * @param mtd the method whose only argument must match + * @return the static method to use for validating adaptees + */ + private Method validAdapter(Class clz, Method mtd) { + if (clz == null) return null; + + if (!mtd.getParameterTypes()[0].isAssignableFrom(clz)) { + String msg = "Adapter " + clz.getName() + + " is incompatible with role interface " + + mtd.getDeclaringClass().getName(); + throw new BuildException(msg); + } + String msg = "Class " + clz.getName() + " is not an adapter: "; + if (!RoleAdapter.class.isAssignableFrom(clz)) { + throw new BuildException(msg + "does not implement RoleAdapter"); + } + try { + Method chk = clz.getMethod("checkClass", CHECK_ADAPTER_PARAMS); + if (!Modifier.isStatic(chk.getModifiers())) { + throw new BuildException(msg + "checkClass() is not static"); + } + return chk; + } + catch(NoSuchMethodException nme){ + throw new BuildException(msg + "checkClass() not found", nme); + } + } + } } diff --git a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/TaskAdapter.java b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/TaskAdapter.java index 213f4f014..077131c1b 100644 --- a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/TaskAdapter.java +++ b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/TaskAdapter.java @@ -1,7 +1,7 @@ /* * The Apache Software License, Version 1.1 * - * Copyright (c) 2000-2001 The Apache Software Foundation. All rights + * Copyright (c) 2000-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -9,7 +9,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * 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 @@ -17,15 +17,15 @@ * distribution. * * 3. The end-user documentation included with the redistribution, if - * any, must include the following acknowlegement: - * "This product includes software developed by the + * 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 + * 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" @@ -55,6 +55,7 @@ package org.apache.tools.ant; import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; @@ -68,7 +69,7 @@ import java.lang.reflect.Method; public class TaskAdapter extends Task implements RoleAdapter { Object proxy; - + /** * Checks a class, whether it is suitable to be adapted by TaskAdapter. * @@ -81,15 +82,15 @@ public class TaskAdapter extends Task implements RoleAdapter { * Logs other suspicious conditions with Project.MSG_WARN. */ public static void checkTaskClass(final Class taskClass, final Project project) { - // This code is for backward compatibility - checkClass(taskClass, project); + // This code is for backward compatibility + checkClass(taskClass, project); } /** * Checks a class, whether it is suitable to be adapted. * * Checks conditions only, which are additionally required for a tasks - * adapted by TaskAdapter. + * adapted by TaskAdapter. * * Throws a BuildException and logs as Project.MSG_ERR for * conditions, that will cause the task execution to fail. @@ -114,7 +115,7 @@ public class TaskAdapter extends Task implements RoleAdapter { throw new BuildException(message); } } - + /** * Do the execution. */ @@ -122,7 +123,7 @@ public class TaskAdapter extends Task implements RoleAdapter { Method setProjectM = null; try { Class c = proxy.getClass(); - setProjectM = + setProjectM = c.getMethod( "setProject", new Class[] {Project.class}); if(setProjectM != null) { setProjectM.invoke(proxy, new Object[] {project}); @@ -131,7 +132,7 @@ public class TaskAdapter extends Task implements RoleAdapter { // ignore this if the class being used as a task does not have // a set project method. } catch( Exception ex ) { - log("Error setting project in " + proxy.getClass(), + log("Error setting project in " + proxy.getClass(), Project.MSG_ERR); throw new BuildException( ex ); } @@ -146,14 +147,20 @@ public class TaskAdapter extends Task implements RoleAdapter { throw new BuildException("No public execute() in " + proxy.getClass()); } executeM.invoke(proxy, null); - return; + return; + } catch( InvocationTargetException ite ) { + Throwable t = ite.getTargetException(); + if (t instanceof BuildException) { + throw (BuildException) t; + } + throw new BuildException(t); } catch( Exception ex ) { log("Error in " + proxy.getClass(), Project.MSG_ERR); throw new BuildException( ex ); } } - + /** * Set the target object class */ @@ -165,4 +172,5 @@ public class TaskAdapter extends Task implements RoleAdapter { return this.proxy ; } + public void setId(String id) {} } diff --git a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Ant.java b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Ant.java index 13d42380d..5d6d8d699 100644 --- a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Ant.java +++ b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Ant.java @@ -138,10 +138,8 @@ public class Ant extends Task { } public void init() { - newProject = new Project(project); + newProject = project.createSubProject(); newProject.setJavaVersionProperty(); -// newProject.addTaskDefinition("property", -// (Class)project.getTaskDefinitions().get("property")); } private void reinit() { @@ -185,26 +183,6 @@ public class Ant extends Task { } } -// Hashtable taskdefs = project.getTaskDefinitions(); -// Enumeration et = taskdefs.keys(); -// while (et.hasMoreElements()) { -// String taskName = (String) et.nextElement(); -// if (taskName.equals("property")) { -// // we have already added this taskdef in #init -// continue; -// } -// Class taskClass = (Class) taskdefs.get(taskName); -// newProject.addTaskDefinition(taskName, taskClass); -// } - -// Hashtable typedefs = project.getDataTypeDefinitions(); -// Enumeration e = typedefs.keys(); -// while (e.hasMoreElements()) { -// String typeName = (String) e.nextElement(); -// Class typeClass = (Class) typedefs.get(typeName); -// newProject.addDataTypeDefinition(typeName, typeClass); -// } - // set user-defined or all properties from calling project Hashtable prop1; if (inheritAll) { diff --git a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antjar.java b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antjar.java index 16ef3ca7b..784e28926 100644 --- a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antjar.java +++ b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antjar.java @@ -104,7 +104,8 @@ public class Antjar extends Jar { public void setAntxml(File descriptor) { libraryDescriptor = descriptor; if (!libraryDescriptor.exists()) { - throw new BuildException("Deployment descriptor: " + libraryDescriptor + " does not exist."); + throw new BuildException("Deployment descriptor: " + + libraryDescriptor + " does not exist."); } // Create a ZipFileSet for this file, and pass it up. @@ -127,7 +128,8 @@ public class Antjar extends Jar { throws IOException, BuildException { // If no antxml file is specified, it's an error. if (libraryDescriptor == null) { - throw new BuildException("antxml attribute is required", location); + throw new BuildException("antxml attribute is required", + location); } super.initZipOutputStream(zOut); @@ -149,10 +151,12 @@ public class Antjar extends Jar { // meaning the same file is specified by the "antxml" attribute and in // a element. if (vPath.equalsIgnoreCase(Antlib.ANT_DESCRIPTOR)) { - if (libraryDescriptor == null || !libraryDescriptor.equals(file) || descriptorAdded) { + if (libraryDescriptor == null || + !libraryDescriptor.equals(file) || descriptorAdded) { log("Warning: selected " + archiveType + " files include a " + - Antlib.ANT_DESCRIPTOR + " which will be ignored " + - "(please use antxml attribute to " + archiveType + " task)", Project.MSG_WARN); + Antlib.ANT_DESCRIPTOR + " which will be ignored " + + "(please use antxml attribute to " + archiveType + + " task)", Project.MSG_WARN); } else { super.zipFile(file, zOut, vPath); diff --git a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antlib.java b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antlib.java index c084791c4..93a5c1982 100644 --- a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antlib.java +++ b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antlib.java @@ -55,12 +55,14 @@ package org.apache.tools.ant.taskdefs; import org.apache.tools.ant.*; import org.apache.tools.ant.types.*; +import org.apache.tools.ant.taskdefs.*; import org.xml.sax.*; import javax.xml.parsers.*; import java.util.*; import java.util.zip.*; import java.io.*; +import java.net.*; /** * Make available the tasks and types from an Ant library.
@@ -76,16 +78,18 @@ import java.io.*;
  * @since ant1.5
  */
 public class Antlib extends Task {
+
+    /**
+     * Location of descriptor in library
+     */
+    public static final String ANT_DESCRIPTOR = "META-INF/antlib.xml";
+
     /**
      * The named classloader to use.
      * Defaults to the default classLoader.
      */
     private String loaderId = "";
 
-    /**
-     * library attribute
-     */
-    private String library = null;
     /**
      * file attribute
      */
@@ -95,62 +99,200 @@ public class Antlib extends Task {
      */
     private boolean override = false;
     /**
-     * attribute to control classloader use
+     * attribute to control failure when loading
      */
-    private boolean useCurrentClassloader = false;
+    private FailureAction onerror = new FailureAction();
+
     /**
      * classpath to build up
      */
     private Path classpath = null;
 
+    /**
+     * the manufacture set of classes to load
+     */
+    private Path loaderPath = null;
+
     /**
      * our little xml parse
      */
     private SAXParserFactory saxFactory;
-    
+
     /**
      * table of aliases
      */
     private Vector aliases = new Vector();
 
     /**
-     * Location of descriptor in library
+     * Some internal constants.
      */
-    public static String ANT_DESCRIPTOR = "META-INF/antlib.xml";
+    private static final int FAIL = 0, REPORT = 1, IGNORE = 2;
 
     /**
-     * Prefix name for DTD of descriptor
-     */
-    public static String ANTLIB_DTD_URL =
-            "http://jakarta.apache.org/ant/";
-    /**
-     * prefix of the antlib
-     */
-    public static String ANTLIB_DTD_PREFIX = "Antlib-V";
-    
-    /**
-     * version counter 
+     * Posible actions when classes are not found
      */
-    public static String ANTLIB_DTD_VERSION = "1_0";
-    
-    /**
-     * dtd file extension
-     */
-    public static String ANTLIB_DTD_EXT = ".dtd";
+    public static class FailureAction extends EnumeratedAttribute {
+        public String[] getValues() {
+            return new String[]{"fail", "report", "ignore"};
+        }
+    }
 
+    private static class DescriptorEnumeration implements Enumeration {
+
+        /**
+         * The name of the resource being searched for.
+         */
+        private String resourceName;
+
+        /**
+         * The index of the next file to search.
+         */
+        private int index;
+
+        /**
+         * The list of files to search
+         */
+        private File files[];
+
+        /**
+         * The URL of the next resource to return in the enumeration. If this
+         * field is null then the enumeration has been completed,
+         * i.e., there are no more elements to return.
+         */
+        private URL nextDescriptor;
+
+        /**
+         * Construct a new enumeration of resources of the given name found
+         * within this class loader's classpath.
+         *
+         * @param name the name of the resource to search for.
+         */
+        DescriptorEnumeration(String fileNames[], String name) {
+            this.resourceName = name;
+            this.index = 0;
+            this.files = new File[fileNames.length];
+            for (int i = 0; i < files.length; i++) {
+                files[i] = new File(fileNames[i]);
+            }
+            findNextDescriptor();
+        }
+
+        /**
+         * Indicates whether there are more elements in the enumeration to
+         * return.
+         *
+         * @return true if there are more elements in the
+         *         enumeration; false otherwise.
+         */
+        public boolean hasMoreElements() {
+            return (this.nextDescriptor != null);
+        }
+
+        /**
+         * Returns the next resource in the enumeration.
+         *
+         * @return the next resource in the enumeration.
+         */
+        public Object nextElement() {
+            URL ret = this.nextDescriptor;
+            findNextDescriptor();
+            return ret;
+        }
+
+        /**
+         * Locates the next descriptor of the correct name in the files and
+         * sets nextDescriptor to the URL of that resource. If no
+         * more resources can be found, nextDescriptor is set to
+         * null.
+         */
+        private void findNextDescriptor() {
+            URL url = null;
+            while (index < files.length && url == null) {
+                try {
+                    url = getDescriptorURL(files[index], this.resourceName);
+                    index++;
+                }
+                catch (BuildException e) {
+                    // ignore path elements which are not valid relative to the
+                    // project
+                }
+            }
+            this.nextDescriptor = url;
+        }
+
+        /**
+         * Get an URL to a given resource in the given file which may
+         * either be a directory or a zip file.
+         *
+         * @param file the file (directory or jar) in which to search for
+         *             the resource. Must not be null.
+         * @param resourceName the name of the resource for which a URL
+         *                     is required. Must not be null.
+         *
+         * @return a URL to the required resource or null if the
+         *         resource cannot be found in the given file object
+         * @todo This code is extracted from AntClassLoader.getResourceURL
+         *       I hate when that happens but the code there is too tied to
+         *       the ClassLoader internals. Maybe we can find a nice place
+         *       to put it where both can use it.
+         */
+        private URL getDescriptorURL(File file, String resourceName) {
+            try {
+                if (!file.exists()) {
+                    return null;
+                }
+
+                if (file.isDirectory()) {
+                    File resource = new File(file, resourceName);
+
+                    if (resource.exists()) {
+                        try {
+                            return new URL("file:"+resource.toString());
+                        } catch (MalformedURLException ex) {
+                            return null;
+                        }
+                    }
+                }
+                else {
+                    ZipFile zipFile = new ZipFile(file);
+                    try {
+                        ZipEntry entry = zipFile.getEntry(resourceName);
+                        if (entry != null) {
+                            try {
+                                return new URL("jar:file:"+file.toString()+"!/"+entry);
+                            } catch (MalformedURLException ex) {
+                                return null;
+                            }
+                        }
+                    }
+                    finally {
+                        zipFile.close();
+                    }
+                }
+            }
+            catch (Exception e) {
+                e.printStackTrace();
+            }
+
+            return null;
+        }
+
+    }
 
     /**
      * constructor creates a validating sax parser
      */
     public Antlib() {
         super();
+        // Default error action
+        onerror.setValue("report");
         saxFactory = SAXParserFactory.newInstance();
-        saxFactory.setValidating(true);
+        saxFactory.setValidating(false);
     }
 
 
     /**
-     * constructor binds to a project as well as setting up internal state
+     * constructor binds to a project and sets ignore mode on errors
      *
      * @param p Description of Parameter
      */
@@ -161,12 +303,12 @@ public class Antlib extends Task {
 
 
     /**
-     * Set name of library to load. The library is located in $ANT_HOME/lib.
+     * Set name of library to load. The library is located in $ANT_HOME/antlib.
      *
-     * @param lib the name of library relative to $ANT_HOME/lib.
+     * @param lib the name of library relative to $ANT_HOME/antlib.
      */
     public void setLibrary(String lib) {
-        this.library = lib;
+        setFile(libraryFile("antlib", lib));
     }
 
 
@@ -180,13 +322,13 @@ public class Antlib extends Task {
     }
 
     /**
-     * Set the ClassLoader to use for this library.
+     * Set the ID of the ClassLoader to use for this library.
      *
-     * @param id the id for the ClassLoader to use, 
-     *           if other than the default.
+     * @param id the id for the ClassLoader to use,
+     *           null means use ANT's core classloader.
      */
     public void setLoaderid(String id) {
-	this.loaderId = id;
+        this.loaderId = id;
     }
 
     /**
@@ -200,15 +342,26 @@ public class Antlib extends Task {
 
 
     /**
-     * Set whether to use a new classloader or not. 
-     * Default is false.
+     * Get what to do if a definition cannot be loaded
+     * This method is mostly used by the core when loading core tasks.
+     *
+     * @return what to do if a definition cannot be loaded
+     */
+    final protected FailureAction getOnerror() {
+        return this.onerror;
+    }
+
+
+    /**
+     * Set whether to fail if a definition cannot be loaded
+     * Default is true.
      * This property is mostly used by the core when loading core tasks.
      *
-     * @param useCurrentClassloader if true the current classloader will
-     *      be used to load the definitions.
+     * @param failedonerror if true loading will stop if classes
+     *                      cannot be instantiated
      */
-    public void setUseCurrentClassloader(boolean useCurrentClassloader) {
-        this.useCurrentClassloader = useCurrentClassloader;
+    public void setOnerror(FailureAction onerror) {
+        this.onerror = onerror;
     }
 
 
@@ -262,78 +415,97 @@ public class Antlib extends Task {
     }
 
 
+    /**
+     * Obtain library file from ANT_HOME directory.
+     *
+     * @param lib the library name.
+     * @return the File instance of the library
+     */
+    private File libraryFile(String homeSubDir, String lib) {
+        // For the time being libraries live in $ANT_HOME/antlib.
+        // The idea being that not to load all the jars there anymore
+        String home = project.getProperty("ant.home");
+
+        if (home == null) {
+            throw new BuildException("ANT_HOME not set as required.");
+        }
+
+        return new File(new File(home, homeSubDir), lib);
+    }
+
     /**
      * actually do the work of loading the library
      *
      * @exception BuildException Description of Exception
-     * @todo maybe have failonerror support for missing file?
      */
     public void execute()
         throws BuildException {
-        File realFile = file;
-        if (library != null) {
-            if (file != null) {
-                String msg = "You cannot specify both file and library.";
-                throw new BuildException(msg, location);
-            }
-            // For the time being libraries live in $ANT_HOME/antlib.
-            // The idea being that we would not load all the jars there anymore
-            String home = project.getProperty("ant.home");
-
-            if (home == null) {
-                throw new BuildException("ANT_HOME not set as required.");
-            }
-
-            realFile = new File(new File(home, "antlib"), library);
-        }
-        else if (file == null) {
-            String msg = "Must specify either library or file attribute.";
+        if (file == null && classpath == null) {
+            String msg =
+                "Must specify either library or file attribute or classpath.";
             throw new BuildException(msg, location);
         }
-        if (!realFile.exists()) {
-            String msg = "Cannot find library: " + realFile;
+        if (file != null && !file.exists()) {
+            String msg = "Cannot find library: " + file;
             throw new BuildException(msg, location);
         }
 
-        //open the descriptor
-        InputStream is = getDescriptor(realFile);
-
-        if (is == null) {
-            String msg = "Missing descriptor on library: " + realFile;
-            throw new BuildException(msg, location);
-        }
+        loadDefinitions();
+    }
 
-        
-        ClassLoader classloader=null;
-        if (useCurrentClassloader && classpath != null) {
-            log("ignoring the useCurrentClassloader option as a classpath is defined",
-                    Project.MSG_WARN);
-            useCurrentClassloader=false;
-        }
-        if (!useCurrentClassloader) {
-            classloader = makeClassLoader(realFile);
-        }
 
-        //parse it and evaluate it.
-        evaluateDescriptor(classloader, processAliases(), is);
+    /**
+     * Load definitions in library and classpath
+     *
+     * @exception BuildException failure to access the resource
+     */
+    public boolean loadDefinitions() throws BuildException {
+        return loadDefinitions(ANT_DESCRIPTOR);
     }
 
-
     /**
-     * Load definitions directly from an external XML file.
+     * Load definitions from resource name in library and classpath
      *
-     * @param xmlfile XML file in the Antlib format.
-     * @exception BuildException failure to open the file
+     * @param res the name of the resources to load
+     * @exception BuildException failure to access the resource
      */
-    public void loadDefinitions(File xmlfile)
+    final protected boolean loadDefinitions(String res)
         throws BuildException {
+        Path path = makeLoaderClasspath();
+        ClassLoader cl = makeClassLoader(path);
+        boolean found = false;
         try {
-            InputStream is = new FileInputStream(xmlfile);
-            loadDefinitions(is);
+            for (Enumeration e = getDescriptors(path, res); e.hasMoreElements(); ) {
+                URL resURL = (URL)e.nextElement();
+                InputStream is = resURL.openStream();
+                loadDefinitions(cl, is);
+                found = true;
+            }
+            if (!found && onerror.getIndex() != IGNORE) {
+                String sPath = path.toString();
+                if ("".equals(sPath.trim())) {
+                    sPath = System.getProperty("java.classpath");
+                }
+                String msg = "Cannot find any " + res +
+                    " antlib descriptors in: " + sPath;
+                switch (onerror.getIndex()) {
+                case FAIL:
+                    throw new BuildException(msg);
+                case REPORT:
+                    log(msg, project.MSG_WARN);
+                }
+            }
         }
         catch (IOException io) {
-            throw new BuildException("Cannot read file: " + file, io);
+            String msg = "Cannot load definitions from: " + res;
+            switch (onerror.getIndex()) {
+            case FAIL:
+                throw new BuildException(msg, io);
+            case REPORT:
+                log(io.getMessage(), project.MSG_WARN);
+            }
         }
+        return found;
     }
 
 
@@ -343,46 +515,29 @@ public class Antlib extends Task {
      * @param is InputStream for the Antlib descriptor.
      * @exception BuildException trouble
      */
-    public void loadDefinitions(InputStream is)
+    private void loadDefinitions(ClassLoader cl, InputStream is)
         throws BuildException {
-        evaluateDescriptor(null, processAliases(), is);
+        evaluateDescriptor(cl, processAliases(), is);
     }
 
 
     /**
-     * get a descriptor from the library file
+     * get an Enumeration of URLs for all resouces corresponding to the
+     * descriptor name.
      *
-     * @param file jarfile to open
-     * @return input stream to the Descriptor 
+     * @param res the name of the resource to collect
+     * @return input stream to the Descriptor or null if none existent
      * @exception BuildException io trouble, or it isnt a zipfile
      */
-    private InputStream getDescriptor(File file)
-        throws BuildException {
-        try {
-            final ZipFile zipfile = new ZipFile(file);
-            ZipEntry entry = zipfile.getEntry(ANT_DESCRIPTOR);
-
-            if (entry == null) {
-                return null;
-            }
-
-            // Guarantee that when Entry is closed so does the zipfile instance.
-            return
-                new FilterInputStream(zipfile.getInputStream(entry)) {
-                    public void close()
-                        throws IOException {
-                        super.close();
-                        zipfile.close();
-                    }
-                };
-        }
-        catch (ZipException ze) {
-            throw new BuildException("Not a library file.", ze, location);
-        }
-        catch (IOException ioe) {
-            throw new BuildException("Cannot read library content.",
-                    ioe, location);
+    private Enumeration getDescriptors(Path path, final String res)
+        throws BuildException, IOException {
+        if (loaderId == null) {
+            // Path cannot be added to the CoreLoader so simply
+            // ask for all instances of the resource descriptors
+            return project.getCoreLoader().getResources(res);
         }
+
+        return new DescriptorEnumeration(path.list(), res);
     }
 
 
@@ -410,18 +565,34 @@ public class Antlib extends Task {
      * @return classloader using te
      * @exception BuildException trouble creating the classloader
      */
-    protected ClassLoader makeClassLoader(File file)
+    protected ClassLoader makeClassLoader(Path clspath)
         throws BuildException {
+        if (loaderId == null) {
+            log("Loading definitions from CORE,  ignored",
+                project.MSG_VERBOSE);
+            return project.getCoreLoader();
+        }
+
+        log("Using ClassLoader '" + loaderId + "' to load path: " + clspath,
+            project.MSG_VERBOSE);
+        return project.addToLoader(loaderId, clspath);
+    }
+
+
+    /**
+     * Constructs the Path to add to the ClassLoader
+     */
+    private Path makeLoaderClasspath()
+    {
         Path clspath = new Path(project);
-        clspath.setLocation(file);
+        if (file != null) clspath.setLocation(file);
         //append any build supplied classpath
         if (classpath != null) {
             clspath.append(classpath);
         }
-	return project.getSymbols().addToLoader(loaderId, clspath);
+        return clspath;
     }
 
-
     /**
      * parse the antlib descriptor
      *
@@ -431,8 +602,8 @@ public class Antlib extends Task {
      * @exception BuildException trouble
      */
     protected void evaluateDescriptor(ClassLoader cl,
-            Properties als, InputStream is)
-            throws BuildException {
+                                      Properties als, InputStream is)
+        throws BuildException {
         try {
             SAXParser saxParser = saxFactory.newSAXParser();
             Parser parser = saxParser.getParser();
@@ -440,7 +611,7 @@ public class Antlib extends Task {
             InputSource inputSource = new InputSource(is);
             //inputSource.setSystemId(uri); //URI is nasty for jar entries
             project.log("parsing descriptor for library: " + file,
-                    Project.MSG_VERBOSE);
+                        Project.MSG_VERBOSE);
             saxParser.parse(inputSource, new AntLibraryHandler(cl, als));
         }
         catch (ParserConfigurationException exc) {
@@ -485,8 +656,8 @@ public class Antlib extends Task {
 
 
     /**
-     * Parses the document describing the content of the 
-     * library. An inner class for access to Project.log 
+     * Parses the document describing the content of the
+     * library. An inner class for access to Project.log
      */
     private class AntLibraryHandler extends HandlerBase {
 
@@ -503,13 +674,11 @@ public class Antlib extends Task {
          */
         private Locator locator = null;
 
-	private int level = 0;
-
-	private SymbolTable symbols = null;
+        private int level = 0;
 
-	private String name = null;
-	private String className = null;
-	private String adapter = null;
+        private String name = null;
+        private String className = null;
+        private String adapter = null;
 
         /**
          * Constructor for the AntLibraryHandler object
@@ -520,7 +689,6 @@ public class Antlib extends Task {
         AntLibraryHandler(ClassLoader classloader, Properties als) {
             this.classloader = classloader;
             this.aliasMap = als;
-	    this.symbols = project.getSymbols();
         }
 
         /**
@@ -533,35 +701,35 @@ public class Antlib extends Task {
             this.locator = locator;
         }
 
-	private void parseAttributes(String tag, AttributeList attrs) 
-	    throws SAXParseException {
-	    name = null;
-	    className = null;
-	    adapter = null;
-	    
-	    for (int i = 0, last = attrs.getLength(); i < last; i++) {
-		String key = attrs.getName(i);
-		String value = attrs.getValue(i);
-		
-		if (key.equals("name")) {
-		    name = value;
-		}
-		else if (key.equals("class")) {
-		    className = value;
-		}
-		else if ("role".equals(tag) && key.equals("adapter")) {
-		    adapter = value;
-		}
-		else {
-		    throw new SAXParseException("Unexpected attribute \""
-						+ key + "\"", locator);
-		}
-	    }
-	    if (name == null || className == null) {
-		String msg = "Underspecified " + tag + " declaration.";
-		throw new SAXParseException(msg, locator);
-	    }
-	}
+        private void parseAttributes(String tag, AttributeList attrs)
+            throws SAXParseException {
+            name = null;
+            className = null;
+            adapter = null;
+
+            for (int i = 0, last = attrs.getLength(); i < last; i++) {
+                String key = attrs.getName(i);
+                String value = attrs.getValue(i);
+
+                if (key.equals("name")) {
+                    name = value;
+                }
+                else if (key.equals("class")) {
+                    className = value;
+                }
+                else if ("role".equals(tag) && key.equals("adapter")) {
+                    adapter = value;
+                }
+                else {
+                    throw new SAXParseException("Unexpected attribute \""
+                                                + key + "\"", locator);
+                }
+            }
+            if (name == null || className == null) {
+                String msg = "Underspecified " + tag + " declaration.";
+                throw new SAXParseException(msg, locator);
+            }
+        }
 
         /**
          * SAX callback handler
@@ -572,103 +740,105 @@ public class Antlib extends Task {
          */
         public void startElement(String tag, AttributeList attrs)
             throws SAXParseException {
-	    level ++;
+            level ++;
             if ("antlib".equals(tag)) {
-		if (level > 1) {
-		    throw new SAXParseException("Unexpected element: " + tag,
-						locator);
-		}
+                if (level > 1) {
+                    throw new SAXParseException("Unexpected element: " + tag,
+                                                locator);
+                }
                 // No attributes to worry about
                 return;
             }
-	    if (level == 1) {
-		throw new SAXParseException("Missing antlib root element",
-					    locator);
-	    }
-
-	    // Must have the two attributes declared
-	    parseAttributes(tag, attrs);
-
-	    try {
-		if ("role".equals(tag)) {
-		    if (isRoleInUse(name)) {
-			String msg = "Cannot override role: " + name;
-			log(msg, Project.MSG_WARN);
-			return;			
-		    }
-		    // Defining a new role
-		    symbols.addRole(name, loadClass(className),
-				    (adapter == null? 
-				     null : loadClass(adapter))); 
-		    return;
-		}
-
-		// Defining a new element kind
-		//check for name alias
-		String alias = aliasMap.getProperty(name);
-		if (alias != null) {
-		    name = alias;
-		}
-		//catch an attempted override of an existing name
-		if (!override && isInUse(tag, name)) {
-		    String msg = "Cannot override " + tag + ": " + name;
-		    log(msg, Project.MSG_WARN);
-		    return;
-		}
-		symbols.add(tag, name, loadClass(className));
-	    }
-	    catch(BuildException be) {
-		throw new SAXParseException(be.getMessage(), locator, be);
-	    }
-        }
-
-	public void endElement(String tag) {
-	    level--;
-	}
-
-	private Class loadClass(String className)
-	    throws SAXParseException {
-	    try {
-		//load the named class
-		Class cls;
-		if(classloader==null) {
-		    cls=Class.forName(className);
-		}
-		else {
-		    cls=classloader.loadClass(className);
-		}
-		return cls;
-	    }
-	    catch (ClassNotFoundException cnfe) {
-		String msg = "Class " + className +
-		    " cannot be found";
-		throw new SAXParseException(msg, locator, cnfe);
-	    }
-	    catch (NoClassDefFoundError ncdfe) {
-		String msg = "Class " + className +
-		    " cannot be found";
-		throw new SAXParseException(msg, locator);
-	    }
-	}
+            if (level == 1) {
+                throw new SAXParseException("Missing antlib root element",
+                                            locator);
+            }
 
-        /**
-         * test for a name being in use already on this role
-         *
-         * @param name the name to test
-         * @return true if it is a task or a datatype
-         */
-        private boolean isInUse(String role, String name) {
-            return (symbols.get(role, name) != null);
+            // Must have the two attributes declared
+            parseAttributes(tag, attrs);
+
+            try {
+                if ("role".equals(tag)) {
+                    if (project.isRoleDefined(name)) {
+                        String msg = "Cannot override role: " + name;
+                        log(msg, Project.MSG_WARN);
+                        return;
+                    }
+                    // Defining a new role
+                    Class clz = loadClass(className);
+                    if (clz != null) {
+                        project.addRoleDefinition(name, clz,
+                                                  (adapter == null? null :
+                                                   loadClass(adapter)));
+                    }
+                    return;
+                }
+
+                // Defining a new element kind
+                //check for name alias
+                String alias = aliasMap.getProperty(name);
+                if (alias != null) {
+                    name = alias;
+                }
+                //catch an attempted override of an existing name
+                if (!override && project.isDefinedOnRole(tag, name)) {
+                    String msg = "Cannot override " + tag + ": " + name;
+                    log(msg, Project.MSG_WARN);
+                    return;
+                }
+                Class clz = loadClass(className);
+                if (clz != null)
+                    project.addDefinitionOnRole(tag, name, clz);
+            }
+            catch(BuildException be) {
+                switch (onerror.getIndex()) {
+                case FAIL:
+                    throw new SAXParseException(be.getMessage(), locator, be);
+                case REPORT:
+                    project.log(be.getMessage(), project.MSG_WARN);
+                    break;
+                default:
+                    project.log(be.getMessage(), project.MSG_DEBUG);
+                }
+            }
         }
 
-        /**
-         * test for a role name being in use already
-         *
-         * @param name the name to test
-         * @return true if it is a task or a datatype
-         */
-        private boolean isRoleInUse(String name) {
-            return (symbols.getRole(name) != null);
+        public void endElement(String tag) {
+            level--;
+        }
+
+        private Class loadClass(String className)
+            throws SAXParseException {
+            String msg = null;
+            try {
+                //load the named class
+                Class cls;
+                if(classloader==null) {
+                    cls=Class.forName(className);
+                }
+                else {
+                    cls=classloader.loadClass(className);
+                }
+                return cls;
+            }
+            catch (ClassNotFoundException cnfe) {
+                msg = "Class " + className + " cannot be found";
+                if (onerror.getIndex() == FAIL)
+                    throw new SAXParseException(msg, locator, cnfe);
+            }
+            catch (NoClassDefFoundError ncdfe) {
+                msg = "Class " + className + " cannot be loaded";
+                if (onerror.getIndex() == FAIL)
+                    throw new SAXParseException(msg, locator);
+            }
+
+            if (onerror.getIndex() == REPORT) {
+                project.log(msg, project.MSG_WARN);
+            }
+            else {
+                project.log(msg, project.MSG_DEBUG);
+            }
+            return null;
         }
 
     //end inner class AntLibraryHandler
@@ -712,7 +882,7 @@ public class Antlib extends Task {
         }
     //end inner class alias
     }
-    
+
 //end class Antlib
 }
 
diff --git a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/types/DataTypeAdapterTask.java b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/types/DataTypeAdapterTask.java
index 18dc7c542..4669a0789 100644
--- a/proposal/sandbox/antlib/src/main/org/apache/tools/ant/types/DataTypeAdapterTask.java
+++ b/proposal/sandbox/antlib/src/main/org/apache/tools/ant/types/DataTypeAdapterTask.java
@@ -66,6 +66,7 @@ import org.apache.tools.ant.*;
 public class DataTypeAdapterTask extends Task implements RoleAdapter {
 
     Object proxy;
+    String id = null;
     
     /**
      * Checks a class, whether it is suitable to be adapted.
@@ -83,14 +84,27 @@ public class DataTypeAdapterTask extends Task implements RoleAdapter {
      * Do the execution.
      */
     public void execute() throws BuildException {
+	if (id != null) {
+	    // Need to re-register this reference
+	    // The container has register the Adapter instead
+            project.addReference(id, proxy);	    
+	}
+    }
+
+    /**
+     * Propagate configuration of Project
+     */
+    public void setProject(Project p) {
+	super.setProject(p);
+
 	// Check to see if the DataType has a setProject method to set
 	if (proxy instanceof ProjectComponent) {
-	    ((ProjectComponent)proxy).setProject(project);
+	    ((ProjectComponent)proxy).setProject(p);
 	    return;
 	}
 
 	// This may not be needed
-	// We are trying to set project even it is was not declared
+	// We are trying to set project even if is was not declared
 	// just like TaskAdapter does for beans, this is not done
 	// by the original code
         Method setProjectM = null;
@@ -99,7 +113,7 @@ public class DataTypeAdapterTask extends Task implements RoleAdapter {
             setProjectM = 
                 c.getMethod( "setProject", new Class[] {Project.class});
             if(setProjectM != null) {
-                setProjectM.invoke(proxy, new Object[] {project});
+                setProjectM.invoke(proxy, new Object[] {p});
             }
         } catch (NoSuchMethodException e) {
             // ignore this if the class being used as a task does not have
@@ -122,4 +136,8 @@ public class DataTypeAdapterTask extends Task implements RoleAdapter {
         return this.proxy ;
     }
 
+    public void setId(String id) {
+	log("Setting adapter id to: " + id, Project.MSG_DEBUG);
+	this.id = id;
+    }
 }