Sorry, in my previous email the attachment did not contain the patches for Antlib and Antjar.
 
In order to keep the antlib proposal of Jose-Alberto Fernandez compatible with the current head revision of ant, I have prepared a patch.
The patch addresses mainly changes in :
   - Project.java
   - Zip.java (to make the Antjar task still work)
It does not affect the proposal "semantically"
Please submit quickly if you can to allow work on this proposal to resume.
 
Yours
 
Antoine
 
Index: proposal/sandbox/antlib/src/main/org/apache/tools/ant/Project.java
===================================================================
RCS file: 
/home/cvspublic/ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/Project.java,v
retrieving revision 1.4
diff -u -r1.4 Project.java
--- proposal/sandbox/antlib/src/main/org/apache/tools/ant/Project.java  3 Mar 
2002 12:37:13 -0000       1.4
+++ proposal/sandbox/antlib/src/main/org/apache/tools/ant/Project.java  1 Apr 
2003 11:26:28 -0000
@@ -61,7 +61,6 @@
 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;
 
@@ -70,8 +69,10 @@
 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.util.LazyHashtable;
 import org.apache.tools.ant.types.Path;
 import org.apache.tools.ant.taskdefs.Antlib;
+import org.apache.tools.ant.input.InputHandler;
 
 /**
  *  Central representation of an Ant project. This class defines a Ant project
@@ -165,13 +166,16 @@
 
     private String name;
     private String description;
+    /** Map of references within the project (paths etc) (String to Object). */
 
     private Hashtable properties = new Hashtable();
     private Hashtable userProperties = new Hashtable();
-    private Hashtable references = new Hashtable();
+    private Hashtable references = new AntRefTable(this);
     private String defaultTarget;
-    //    private Hashtable dataClassDefinitions = new Hashtable();
-    //    private Hashtable taskClassDefinitions = new Hashtable();
+    /** Map from data type names to implementing classes (String to Class). */
+    private Hashtable dataClassDefinitions = new AntTaskTable(this, false);
+    /** Map from task names to implementing classes (String to Class). */
+    private Hashtable taskClassDefinitions = new AntTaskTable(this, true);
     private Hashtable createdTasks = new Hashtable();
     private Hashtable targets = new Hashtable();
     private FilterSet globalFilterSet = new FilterSet();
@@ -185,11 +189,13 @@
      */
     private ClassLoader coreLoader = null;
 
-    /**
-     *  Records the latest task on a thread
-     */
+    /** Records the latest task to be executed on a thread (Thread to Task). */
     private Hashtable threadTasks = new Hashtable();
 
+    /** Records the latest task to be executed on a thread Group. */
+    private Hashtable threadGroupTasks = new Hashtable();
+
+
     /**
      *  Store symbol tables
      */
@@ -219,6 +225,48 @@
         }
     }
 
+    /**
+     * Called to handle any input requests.
+     */
+    private InputHandler inputHandler = null;
+
+    /**
+     * The default input stream used to read any input
+     */
+    private InputStream defaultInputStream = null;
+
+    /**
+     * Sets the input handler
+     *
+     * @param handler the InputHandler instance to use for gathering input.
+     */
+    public void setInputHandler(InputHandler handler) {
+        inputHandler = handler;
+    }
+
+    /**
+     * Set the default System input stream. Normally this stream is set to
+     * System.in. This inputStream is used when no task inptu redirection is
+     * being performed.
+     *
+     * @param defaultInputStream the default input stream to use when input
+     *        is reuested.
+     * @since Ant 1.6
+     */
+    public void setDefaultInputStream(InputStream defaultInputStream) {
+        this.defaultInputStream = defaultInputStream;
+    }
+
+    /**
+     * Retrieves the current input handler.
+     *
+     * @return the InputHandler instance currently in place for the project
+     *         instance.
+     */
+    public InputHandler getInputHandler() {
+        return inputHandler;
+    }
+
     private FileUtils fileUtils;
 
 
@@ -302,12 +350,17 @@
 
     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 {
+            File autolib=new File(getProperty("ant.home"),"autolib");
+            log("scanning the autolib directory 
"+autolib.toString(),MSG_DEBUG);
+            ds.setBasedir(autolib);
+            ds.scan();
+            String dirs[] = ds.getIncludedDirectories();
+            for (int i = 0; i < dirs.length; i++) {
+                autoLoad(ds.getBasedir(), dirs[i]);
+            }
+        } catch (Exception e) {}
+
     }
 
     private void autoLoad(File base, String dir) {
@@ -343,21 +396,59 @@
 
 
     /**
-     *  Initialise the project. This involves setting the default task
-     *  definitions and loading the system properties.
+     * Initialises the project.
      *
-     [EMAIL PROTECTED]  BuildException  Description of the Exception
+     * This involves setting the default task definitions and loading the
+     * system properties.
+     *
+     * @exception BuildException if the default task list cannot be loaded
      */
     public void init() throws BuildException {
         setJavaVersionProperty();
-        setSystemProperties();
         if (!isRoleDefined(TASK_ROLE)) {
             // Top project, need to load the core definitions
             loadDefinitions();
         }
+        String defs = "/org/apache/tools/ant/taskdefs/defaults.properties";
+
+        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();
+            ((AntTaskTable) taskClassDefinitions).addDefinitions(props);
+
+
+        } catch (IOException ioe) {
+            throw new BuildException("Can't load default task list");
+        }
+
+        String dataDefs = "/org/apache/tools/ant/types/defaults.properties";
+
+        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();
+
+            ((AntTaskTable) dataClassDefinitions).addDefinitions(props);
+
+
+        } catch (IOException ioe) {
+            throw new BuildException("Can't load default datatype list");
+        }
+
+        setSystemProperties();
     }
 
 
+
     /**
      *  Sets the CoreLoader to the default of the Project object
      */
@@ -1223,13 +1314,16 @@
 
 
     /**
-     *  Description of the Method
-     *
-     [EMAIL PROTECTED]  line     Description of the Parameter
-     [EMAIL PROTECTED]  isError  Description of the Parameter
+     * Demultiplexes output so that each task receives the appropriate
+     * messages. If the current thread is not currently executing a task,
+     * the message is logged directly.
+     *
+     * @param line Message to handle. Should not be <code>null</code>.
+     * @param isError Whether the text represents an error (<code>true</code>)
+     *        or information (<code>false</code>).
      */
     public void demuxOutput(String line, boolean isError) {
-        Task task = (Task) threadTasks.get(Thread.currentThread());
+        Task task = getThreadTask(Thread.currentThread());
         if (task == null) {
             fireMessageLogged(this, line, isError ? MSG_ERR : MSG_INFO);
         } else {
@@ -1241,6 +1335,75 @@
         }
     }
 
+    /**
+     * Read data from the default input stream. If no default has been
+     * specified, System.in is used.
+     *
+     * @param buffer the buffer into which data is to be read.
+     * @param offset the offset into the buffer at which data is stored.
+     * @param length the amount of data to read
+     *
+     * @return the number of bytes read
+     *
+     * @exception IOException if the data cannot be read
+     * @since Ant 1.6
+     */
+    public int defaultInput(byte[] buffer, int offset, int length)
+        throws IOException {
+        if (defaultInputStream != null) {
+            return defaultInputStream.read(buffer, offset, length);
+        } else {
+            return System.in.read(buffer, offset, length);
+        }
+    }
+
+    /**
+     * Demux an input request to the correct task.
+     *
+     * @param buffer the buffer into which data is to be read.
+     * @param offset the offset into the buffer at which data is stored.
+     * @param length the amount of data to read
+     *
+     * @return the number of bytes read
+     *
+     * @exception IOException if the data cannot be read
+     * @since Ant 1.6
+     */
+    public int demuxInput(byte[] buffer, int offset, int length)
+        throws IOException {
+        Task task = getThreadTask(Thread.currentThread());
+        if (task == null) {
+            return defaultInput(buffer, offset, length);
+        } else {
+            return task.handleInput(buffer, offset, length);
+        }
+    }
+
+    /**
+     * Demultiplexes flush operation so that each task receives the appropriate
+     * messages. If the current thread is not currently executing a task,
+     * the message is logged directly.
+     *
+     * @since Ant 1.5.2
+     *
+     * @param line Message to handle. Should not be <code>null</code>.
+     * @param isError Whether the text represents an error (<code>true</code>)
+     *        or information (<code>false</code>).
+     */
+    public void demuxFlush(String line, boolean isError) {
+        Task task = getThreadTask(Thread.currentThread());
+        if (task == null) {
+            fireMessageLogged(this, line, isError ? MSG_ERR : MSG_INFO);
+        } else {
+            if (isError) {
+                task.handleErrorFlush(line);
+            } else {
+                task.handleFlush(line);
+            }
+        }
+    }
+
+
 
     /**
      *  execute the targets and any targets it depends on
@@ -1646,21 +1809,35 @@
 
 
     /**
-     *  Adds a feature to the Reference attribute of the Project object
+     * Adds a reference to the project.
      *
-     [EMAIL PROTECTED]  name   The feature to be added to the Reference 
attribute
-     [EMAIL PROTECTED]  value  The feature to be added to the Reference 
attribute
+     * @param name The name of the reference. Must not be <code>null</code>.
+     * @param value The value of the reference. Must not be <code>null</code>.
      */
     public void addReference(String name, Object value) {
-        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,
+        synchronized (references) {
+            Object old = ((AntRefTable) references).getReal(name);
+            if (old == value) {
+                // no warning, this is not changing anything
+                return;
+            }
+            if (old != null && !(old instanceof UnknownElement)) {
+                log("Overriding previous definition of reference to " + name,
                     MSG_WARN);
+            }
+
+            String valueAsString = "";
+            try {
+                valueAsString = value.toString();
+            } catch (Throwable t) {
+                log("Caught exception (" + t.getClass().getName() + ")"
+                    + " while expanding " + name + ": " + t.getMessage(),
+                    MSG_WARN);
+            }
+            log("Adding reference: " + name + " -> " + valueAsString,
+                MSG_DEBUG);
+            references.put(name, value);
         }
-        log("Adding reference: " + name + " -> " + value, MSG_DEBUG);
-        references.put(name, value);
     }
 
 
@@ -1684,6 +1861,45 @@
 
 
     /**
+     * Returns a description of the type of the given element, with
+     * special handling for instances of tasks and data types.
+     * <p>
+     * This is useful for logging purposes.
+     *
+     * @param element The element to describe.
+     *                Must not be <code>null</code>.
+     *
+     * @return a description of the element type
+     *
+     * @since 1.95, Ant 1.5
+     */
+    public String getElementName(Object element) {
+        Hashtable elements = taskClassDefinitions;
+        Class elementClass = element.getClass();
+        String typeName = "task";
+        if (!elements.contains(elementClass)) {
+            elements = dataClassDefinitions;
+            typeName = "data type";
+            if (!elements.contains(elementClass)) {
+                elements = null;
+            }
+        }
+
+        if (elements != null) {
+            Enumeration e = elements.keys();
+            while (e.hasMoreElements()) {
+                String name = (String) e.nextElement();
+                Class clazz = (Class) elements.get(name);
+                if (elementClass.equals(clazz)) {
+                    return "The <" + name + "> " + typeName;
+                }
+            }
+        }
+
+        return "Class " + elementClass.getName();
+    }
+
+    /**
      *  send build started event to the listeners
      */
     protected void fireBuildStarted() {
@@ -1827,6 +2043,166 @@
     protected void fireMessageLogged(Task task, String message, int priority) {
         BuildEvent event = new BuildEvent(task);
         fireMessageLoggedEvent(event, message, priority);
+    }
+    /**
+     * Register a task as the current task for a thread.
+     * If the task is null, the thread's entry is removed.
+     *
+     * @param thread the thread on which the task is registered.
+     * @param task the task to be registered.
+     * @since Ant 1.5
+     */
+    public synchronized void registerThreadTask(Thread thread, Task task) {
+        if (task != null) {
+            threadTasks.put(thread, task);
+            threadGroupTasks.put(thread.getThreadGroup(), task);
+        } else {
+            threadTasks.remove(thread);
+            threadGroupTasks.remove(thread.getThreadGroup());
+        }
+    }
+
+    /**
+     * Get the current task assopciated with a thread, if any
+     *
+     * @param thread the thread for which the task is required.
+     * @return the task which is currently registered for the given thread or
+     *         null if no task is registered.
+     */
+    public Task getThreadTask(Thread thread) {
+        Task task = (Task) threadTasks.get(thread);
+        if (task == null) {
+            ThreadGroup group = thread.getThreadGroup();
+            while (task == null && group != null) {
+                task = (Task) threadGroupTasks.get(group);
+                group = group.getParent();
+            }
+        }
+        return task;
+    }
+
+
+    // Should move to a separate public class - and have API to add
+    // listeners, etc.
+    private static class AntRefTable extends Hashtable {
+        Project project;
+        public AntRefTable(Project project) {
+            super();
+            this.project = project;
+        }
+
+        /** Returns the unmodified original object.
+         * This method should be called internally to
+         * get the 'real' object.
+         * The normal get method will do the replacement
+         * of UnknownElement ( this is similar with the JDNI
+         * refs behavior )
+         */
+        public Object getReal(Object key) {
+            return super.get(key);
+        }
+
+        /** Get method for the reference table.
+         *  It can be used to hook dynamic references and to modify
+         * some references on the fly - for example for delayed
+         * evaluation.
+         *
+         * It is important to make sure that the processing that is
+         * done inside is not calling get indirectly.
+         *
+         * @param key
+         * @return
+         */
+        public Object get(Object key) {
+            //System.out.println("AntRefTable.get " + key);
+            Object o = super.get(key);
+            if (o instanceof UnknownElement) {
+                // Make sure that
+                ((UnknownElement) o).maybeConfigure();
+                o = ((UnknownElement) o).getTask();
+            }
+            return o;
+        }
+    }
+
+    private static class AntTaskTable extends LazyHashtable {
+        Project project;
+        Properties props;
+        boolean tasks = false;
+
+        public AntTaskTable(Project p, boolean tasks) {
+            this.project = p;
+            this.tasks = tasks;
+        }
+
+        public void addDefinitions(Properties props) {
+            this.props = props;
+        }
+
+        protected void initAll() {
+            if (initAllDone ) return;
+            project.log("InitAll", Project.MSG_DEBUG);
+            if (props==null ) return;
+            Enumeration enum = props.propertyNames();
+            while (enum.hasMoreElements()) {
+                String key = (String) enum.nextElement();
+                Class taskClass=getTask( key );
+                if (taskClass!=null ) {
+                    // This will call a get() and a put()
+                    if (tasks )
+                        project.addTaskDefinition(key, taskClass);
+                    else
+                        project.addDataTypeDefinition(key, taskClass );
+                }
+            }
+            initAllDone=true;
+        }
+
+        protected Class getTask(String key) {
+            if (props==null ) return null; // for tasks loaded before init()
+            String value=props.getProperty(key);
+            if (value==null) {
+                //project.log( "No class name for " + key, Project.MSG_VERBOSE 
);
+                return null;
+            }
+            try {
+                Class taskClass=null;
+                if (project.getCoreLoader() != null &&
+                    
!("only".equals(project.getProperty("build.sysclasspath")))) {
+                    try {
+                        taskClass=project.getCoreLoader().loadClass(value);
+                        if (taskClass != null ) return taskClass;
+                    } catch( Exception ex ) {
+                    }
+                }
+                taskClass = Class.forName(value);
+                return taskClass;
+            } catch (NoClassDefFoundError ncdfe) {
+                project.log("Could not load a dependent class ("
+                        + ncdfe.getMessage() + ") for task " + key, 
Project.MSG_DEBUG);
+            } catch (ClassNotFoundException cnfe) {
+                project.log("Could not load class (" + value
+                        + ") for task " + key, Project.MSG_DEBUG);
+            }
+            return null;
+        }
+
+        // Hashtable implementation
+        public Object get( Object key ) {
+            Object orig=super.get( key );
+            if (orig!= null ) return orig;
+            if (! (key instanceof String) ) return null;
+            project.log("Get task " + key, Project.MSG_DEBUG );
+            Object taskClass=getTask( (String) key);
+            if (taskClass != null)
+                super.put( key, taskClass );
+            return taskClass;
+        }
+
+        public boolean containsKey(Object key) {
+            return get(key) != null;
+        }
+
     }
 
 }
Index: 
proposal/sandbox/antlib/src/main/org/apache/tools/ant/IntrospectionHelper.java
===================================================================
RCS file: 
/home/cvspublic/ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/IntrospectionHelper.java,v
retrieving revision 1.3
diff -u -r1.3 IntrospectionHelper.java
--- 
proposal/sandbox/antlib/src/main/org/apache/tools/ant/IntrospectionHelper.java  
    7 Mar 2003 11:22:58 -0000       1.3
+++ 
proposal/sandbox/antlib/src/main/org/apache/tools/ant/IntrospectionHelper.java  
    1 Apr 2003 11:26:33 -0000
@@ -1,7 +1,7 @@
 /*
  * The Apache Software License, Version 1.1
  *
- * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
+ * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
  * reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,7 +23,7 @@
  *    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
+ * 4. The names "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 [EMAIL PROTECTED]
@@ -54,16 +54,15 @@
 
 package org.apache.tools.ant;
 
-import org.apache.tools.ant.types.Path;
-import org.apache.tools.ant.types.EnumeratedAttribute;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Constructor;
 import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.Locale;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.Path;
 
 /**
  * Helper class that collects the methods a task or nested element
@@ -75,45 +74,125 @@
 public class IntrospectionHelper implements BuildListener {
 
     /**
-     * holds the types of the attributes that could be set.
+     * Map from attribute names to attribute types 
+     * (String to Class).
      */
     private Hashtable attributeTypes;
 
     /**
-     * holds the attribute setter methods.
+     * Map from attribute names to attribute setter methods 
+     * (String to AttributeSetter).
      */
     private Hashtable attributeSetters;
 
     /**
-     * Holds the types of nested elements that could be created.
+     * Map from attribute names to nested types 
+     * (String to Class).
      */
     private Hashtable nestedTypes;
 
     /**
-     * Holds methods to create nested elements.
+     * Map from attribute names to methods to create nested types 
+     * (String to NestedCreator).
      */
     private Hashtable nestedCreators;
 
     /**
-     * Holds methods to store configured nested elements.
+     * Map from attribute names to methods to store configured nested types 
+     * (String to NestedStorer).
      */
     private Hashtable nestedStorers;
 
     /**
-     * The method to add PCDATA stuff.
+     * The method to invoke to add PCDATA.
      */
     private Method addText = null;
 
     /**
-     * The Class that's been introspected.
+     * The class introspected by this instance.
      */
     private Class bean;
 
     /**
-     * instances we've already created
+     * Helper instances we've already created (Class to IntrospectionHelper).
      */
     private static Hashtable helpers = new Hashtable();
 
+    /** 
+     * Map from primitive types to wrapper classes for use in 
+     * createAttributeSetter (Class to Class). Note that char 
+     * and boolean are in here even though they get special treatment
+     * - this way we only need to test for the wrapper class.
+     */
+    private static final Hashtable PRIMITIVE_TYPE_MAP = new Hashtable(8);
+
+    // Set up PRIMITIVE_TYPE_MAP
+    static {
+        Class[] primitives = {Boolean.TYPE, Byte.TYPE, Character.TYPE, 
+                              Short.TYPE, Integer.TYPE, Long.TYPE, 
+                              Float.TYPE, Double.TYPE};
+        Class[] wrappers = {Boolean.class, Byte.class, Character.class, 
+                            Short.class, Integer.class, Long.class, 
+                            Float.class, Double.class};
+        for (int i = 0; i < primitives.length; i++) {
+            PRIMITIVE_TYPE_MAP.put (primitives[i], wrappers[i]);
+        }
+    }
+
+    // XXX: (Jon Skeet) The documentation below doesn't draw a clear 
+    // distinction between addConfigured and add. It's obvious what the
+    // code *here* does (addConfigured sets both a creator method which
+    // calls a no-arg constructor and a storer method which calls the
+    // method we're looking at, whlie add just sets a creator method
+    // which calls the method we're looking at) but it's not at all
+    // obvious what the difference in actual *effect* will be later
+    // on. I can't see any mention of addConfiguredXXX in "Developing
+    // with Ant" (at least in the version on the web site). Someone
+    // who understands should update this documentation 
+    // (and preferably the manual too) at some stage.
+    /**
+     * Sole constructor, which is private to ensure that all 
+     * IntrospectionHelpers are created via [EMAIL PROTECTED] 
#getHelper(Class) getHelper}.
+     * Introspects the given class for bean-like methods.
+     * Each method is examined in turn, and the following rules are applied:
+     * <p>
+     * <ul>
+     * <li>If the method is <code>Task.setLocation(Location)</code>, 
+     * <code>Task.setTaskType(String)</code>
+     * or <code>TaskContainer.addTask(Task)</code>, it is ignored. These 
+     * methods are handled differently elsewhere.
+     * <li><code>void addText(String)</code> is recognised as the method for
+     * adding PCDATA to a bean.
+     * <li><code>void setFoo(Bar)</code> is recognised as a method for 
+     * setting the value of attribute <code>foo</code>, so long as 
+     * <code>Bar</code> is non-void and is not an array type. Non-String 
+     * parameter types always overload String parameter types, but that is
+     * the only guarantee made in terms of priority.
+     * <li><code>Foo createBar()</code> is recognised as a method for
+     * creating a nested element called <code>bar</code> of type 
+     * <code>Foo</code>, so long as <code>Foo</code> is not a primitive or
+     * array type.
+     * <li><code>void addConfiguredFoo(Bar)</code> is recognised as a
+     * method for storing a pre-configured element called 
+     * <code>foo</code> and of type <code>Bar</code>, so long as
+     * <code>Bar</code> is not an array, primitive or String type. 
+     * <code>Bar</code> must have an accessible constructor taking no 
+     * arguments.
+     * <li><code>void addFoo(Bar)</code> is recognised as a
+     * method for storing an element called <code>foobar</code> 
+     * and of type <code>Baz</code>, so long as
+     * <code>Baz</code> is not an array, primitive or String type. 
+     * <code>Baz</code> must have an accessible constructor taking no 
+     * arguments.
+     * </ul>
+     * Note that only one method is retained to create/set/addConfigured/add 
+     * any element or attribute.
+     * 
+     * @param bean The bean type to introspect. 
+     *             Must not be <code>null</code>.
+     * 
+     * @see #getHelper(Class)
+     */
     private IntrospectionHelper(final Class bean) {
         attributeTypes = new Hashtable();
         attributeSetters = new Hashtable();
@@ -124,7 +203,7 @@
         this.bean = bean;
 
         Method[] methods = bean.getMethods();
-        for (int i=0; i<methods.length; i++) {
+        for (int i = 0; i < methods.length; i++) {
             final Method m = methods[i];
             final String name = m.getName();
             Class returnType = m.getReturnType();
@@ -132,23 +211,16 @@
 
             // not really user settable properties on tasks
             if (org.apache.tools.ant.Task.class.isAssignableFrom(bean)
-                && args.length == 1 &&
-                (
-                 (
-                  "setLocation".equals(name) && 
org.apache.tools.ant.Location.class.equals(args[0])
-                  ) || (
-                   "setTaskType".equals(name) && 
java.lang.String.class.equals(args[0])
-                  )
-                 )) {
+                 && args.length == 1 && isHiddenSetMethod(name, args[0])) {
                 continue;
             }
 
             // hide addTask for TaskContainers
-//              if 
(org.apache.tools.ant.TaskContainer.class.isAssignableFrom(bean)
-//                  && args.length == 1 && "addTask".equals(name)
-//                  && org.apache.tools.ant.Task.class.equals(args[0])) {
-//                  continue;
-//              }
+            if (org.apache.tools.ant.TaskContainer.class.isAssignableFrom(bean)
+                && args.length == 1 && "addTask".equals(name)
+                && org.apache.tools.ant.Task.class.equals(args[0])) {
+                continue;
+            }
 
 
             if ("addText".equals(name)
@@ -185,7 +257,7 @@
                         particular order.
                     */
                 }
-                AttributeSetter as = createAttributeSetter(m, args[0]);
+                AttributeSetter as = createAttributeSetter(m, args[0], 
propName);
                 if (as != null) {
                     attributeTypes.put(propName, args[0]);
                     attributeSetters.put(propName, as);
@@ -225,9 +297,7 @@
                     nestedCreators.put(propName, new NestedCreator() {
 
                             public Object create(Object parent)
-                                throws InvocationTargetException, 
-                                      IllegalAccessException, 
-                                      InstantiationException {
+                                throws InvocationTargetException, 
IllegalAccessException, InstantiationException {
 
                                 Object o = c.newInstance(new Object[] {});
                                 return o;
@@ -237,9 +307,7 @@
                     nestedStorers.put(propName, new NestedStorer() {
 
                             public void store(Object parent, Object child)
-                                throws InvocationTargetException, 
-                                      IllegalAccessException, 
-                                      InstantiationException {
+                                throws InvocationTargetException, 
IllegalAccessException, InstantiationException {
 
                                 m.invoke(parent, new Object[] {child});
                             }
@@ -262,9 +330,7 @@
                     nestedCreators.put(propName, new NestedCreator() {
 
                             public Object create(Object parent)
-                                throws InvocationTargetException, 
-                                      IllegalAccessException, 
-                                      InstantiationException {
+                                throws InvocationTargetException, 
IllegalAccessException, InstantiationException {
 
                                 Object o = c.newInstance(new Object[] {});
                                 m.invoke(parent, new Object[] {o});
@@ -279,8 +345,36 @@
         }
     }
 
-    /**
-     * Factory method for helper objects.
+    /** 
+     * Certain set methods are part of the Ant core interface to tasks and 
+     * therefore not to be considered for introspection
+     *
+     * @param name the name of the set method
+     * @param type the type of the set method's parameter 
+     * @return true if the given set method is to be hidden.
+     */
+    private boolean isHiddenSetMethod(String name, Class type) {
+        if ("setLocation".equals(name) 
+             && org.apache.tools.ant.Location.class.equals(type)) {
+            return true;
+        }
+        
+        if  ("setTaskType".equals(name) 
+             && java.lang.String.class.equals(type)) {
+            return true;
+        }
+        
+        return false;
+    }
+    
+    /**
+     * Returns a helper for the given class, either from the cache
+     * or by creating a new instance.
+     * 
+     * @param c The class for which a helper is required.
+     *          Must not be <code>null</code>.
+     * 
+     * @return a helper for the specified class
      */
     public static synchronized IntrospectionHelper getHelper(Class c) {
         IntrospectionHelper ih = (IntrospectionHelper) helpers.get(c);
@@ -292,17 +386,63 @@
     }
 
     /**
-     * Sets the named attribute.
+     * Returns a helper for the given class, either from the cache
+     * or by creating a new instance.
+     *
+     * The method will make sure the helper will be cleaned up at the end of
+     * the project, and only one instance will be created for each class.
+     *
+     * @param c The class for which a helper is required.
+     *          Must not be <code>null</code>.
+     *
+     * @return a helper for the specified class
+     */
+    public static synchronized IntrospectionHelper getHelper(Project p, Class 
c)
+    {
+        IntrospectionHelper ih = (IntrospectionHelper) helpers.get(c);
+        if (ih == null) {
+            ih = new IntrospectionHelper(c);
+            helpers.put(c, ih);
+            // Cleanup at end of project
+            p.addBuildListener(ih);
+        }
+        return ih;
+    }
+
+    /**
+     * Sets the named attribute in the given element, which is part of the 
+     * given project.
+     * 
+     * @param p The project containing the element. This is used when files 
+     *          need to be resolved. Must not be <code>null</code>.
+     * @param element The element to set the attribute in. Must not be 
+     *                <code>null</code>.
+     * @param attributeName The name of the attribute to set. Must not be
+     *                      <code>null</code>.
+     * @param value The value to set the attribute to. This may be interpreted
+     *              or converted to the necessary type if the setter method
+     *              doesn't just take a string. Must not be <code>null</code>.
+     * 
+     * @exception BuildException if the introspected class doesn't support 
+     *                           the given attribute, or if the setting 
+     *                           method fails.
      */
     public void setAttribute(Project p, Object element, String attributeName,
-                             String value)
-        throws BuildException {
-        AttributeSetter as = (AttributeSetter) 
attributeSetters.get(attributeName);
+                             String value) throws BuildException {
+        AttributeSetter as
+            = (AttributeSetter) attributeSetters.get(attributeName);
         if (as == null) {
-            String msg = getElementName(p, element) +
-            //String msg = "Class " + element.getClass().getName() +
-                " doesn't support the \"" + attributeName + "\" attribute.";
-            throw new BuildException(msg);
+            if (element instanceof DynamicConfigurator) {
+                DynamicConfigurator dc = (DynamicConfigurator) element;
+                dc.setDynamicAttribute(attributeName, value);
+                return;
+            }
+            else {
+                String msg = getElementName(p, element) +
+                    " doesn't support the \"" + attributeName +
+                    "\" attribute.";
+                throw new BuildException(msg);
+            }
         }
         try {
             as.set(p, element, value);
@@ -319,18 +459,32 @@
     }
 
     /**
-     * Adds PCDATA areas.
+     * Adds PCDATA to an element, using the element's 
+     * <code>void addText(String)</code> method, if it has one. If no
+     * such method is present, a BuildException is thrown if the 
+     * given text contains non-whitespace.
+     * 
+     * @param project The project which the element is part of. 
+     *                Must not be <code>null</code>.
+     * @param element The element to add the text to. 
+     *                Must not be <code>null</code>.
+     * @param text    The text to add.
+     *                Must not be <code>null</code>.
+     * 
+     * @exception BuildException if non-whitespace text is provided and no
+     *                           method is available to handle it, or if
+     *                           the handling method fails.
      */
-    public void addText(Project project, Object element, String text) {
+    public void addText(Project project, Object element, String text) 
+        throws BuildException {
         if (addText == null) {
             // Element doesn't handle text content
-            if ( text.trim().length() == 0 ) {
+            if (text.trim().length() == 0) {
                 // Only whitespace - ignore
                 return;
-            }
-            else {
+            } else {
                 // Not whitespace - fail
-                String msg = getElementName(project, element) +
+                String msg = project.getElementName(element) +
                     " doesn't support nested text data.";
                 throw new BuildException(msg);
             }
@@ -350,25 +504,46 @@
     }
 
     /**
-     * Creates a named nested element.
-     */
-    public Object createElement(Project project, Object element, String 
elementName)
-        throws BuildException {
-       
+     * Creates a named nested element. Depending on the results of the
+     * initial introspection, either a method in the given parent instance
+     * or a simple no-arg constructor is used to create an instance of the
+     * specified element type.
+     * 
+     * @param project Project to which the parent object belongs.
+     *                Must not be <code>null</code>. If the resulting
+     *                object is an instance of ProjectComponent, its
+     *                Project reference is set to this parameter value.
+     * @param parent  Parent object used to create the instance.
+     *                Must not be <code>null</code>.
+     * @param elementName Name of the element to create an instance of.
+     *                    Must not be <code>null</code>.
+     * 
+     * @return an instance of the specified element type
+     * 
+     * @exception BuildException if no method is available to create the
+     *                           element instance, or if the creating method
+     *                           fails.
+     */
+    public Object createElement(Project project, Object parent, 
+        String elementName) throws BuildException {
+        NestedCreator nc = (NestedCreator) nestedCreators.get(elementName);
+        if (nc == null && parent instanceof DynamicConfigurator) {
+            DynamicConfigurator dc = (DynamicConfigurator) parent;
+            Object nestedElement = dc.createDynamicElement(elementName);
+            if (nestedElement != null) {
+                if (nestedElement instanceof ProjectComponent) {
+                    ((ProjectComponent) nestedElement).setProject(project);
+                }
+                return nestedElement;
+            }
+        }
+        if (nc == null) {
+            String msg = project.getElementName(parent) +
+                " doesn't support the nested \"" + elementName + "\" element.";
+            throw new BuildException(msg);
+        }
         try {
-           // First check if there are any roles supported by this class
-           Object nestedElement = project.createInRole(element, elementName);
-           if (nestedElement == null) {
-               NestedCreator nc = 
-                   (NestedCreator) nestedCreators.get(elementName);
-               if (nc == null) {
-                   String msg = getElementName(project, element) +
-                       " doesn't support the nested \"" + elementName + 
-                       "\" element.";
-                   throw new BuildException(msg);
-               }
-               nestedElement = nc.create(element);
-           }
+            Object nestedElement = nc.create(parent);
             if (nestedElement instanceof ProjectComponent) {
                 ((ProjectComponent) nestedElement).setProject(project);
             }
@@ -389,19 +564,48 @@
     }
 
     /**
-     * Creates a named nested element.
+     * Indicate if this element supports a nested element of the 
+     * given name.
+     *
+     * @param elementName the name of the nested element being checked
+     *
+     * @return true if the given nested element is supported
+     */
+    public boolean supportsNestedElement(String elementName) {
+        return nestedCreators.containsKey(elementName);
+    }
+    
+    /**
+     * Stores a named nested element using a storage method determined
+     * by the initial introspection. If no appropriate storage method
+     * is available, this method returns immediately.
+     * 
+     * @param project Ignored in this implementation. 
+     *                May be <code>null</code>.
+     * 
+     * @param parent  Parent instance to store the child in. 
+     *                Must not be <code>null</code>.
+     * 
+     * @param child   Child instance to store in the parent.
+     *                Should not be <code>null</code>.
+     * 
+     * @param elementName  Name of the child element to store. 
+     *                     May be <code>null</code>, in which case
+     *                     this method returns immediately.
+     * 
+     * @exception BuildException if the storage method fails.
      */
-    public void storeElement(Project project, Object element, Object child, 
String elementName)
-        throws BuildException {
+    public void storeElement(Project project, Object parent, Object child, 
+        String elementName) throws BuildException {
         if (elementName == null) {
             return;
         }
-        NestedStorer ns = (NestedStorer)nestedStorers.get(elementName);
+        NestedStorer ns = (NestedStorer) nestedStorers.get(elementName);
         if (ns == null) {
             return;
         }
         try {
-            ns.store(element, child);
+            ns.store(parent, child);
         } catch (IllegalAccessException ie) {
             // impossible as getMethods should only return public methods
             throw new BuildException(ie);
@@ -418,7 +622,16 @@
     }
 
     /**
-     * returns the type of a named nested element.
+     * Returns the type of a named nested element.
+     * 
+     * @param elementName The name of the element to find the type of.
+     *                    Must not be <code>null</code>.
+     * 
+     * @return the type of the nested element with the specified name.
+     *         This will never be <code>null</code>.
+     * 
+     * @exception BuildException if the introspected class does not
+     *                           support the named nested element.
      */
     public Class getElementType(String elementName)
         throws BuildException {
@@ -432,7 +645,16 @@
     }
 
     /**
-     * returns the type of a named attribute.
+     * Returns the type of a named attribute.
+     * 
+     * @param attributeName The name of the attribute to find the type of.
+     *                      Must not be <code>null</code>.
+     * 
+     * @return the type of the attribute with the specified name.
+     *         This will never be <code>null</code>.
+     * 
+     * @exception BuildException if the introspected class does not
+     *                           support the named attribute.
      */
     public Class getAttributeType(String attributeName)
         throws BuildException {
@@ -446,35 +668,77 @@
     }
 
     /**
-     * Does the introspected class support PCDATA?
+     * Returns whether or not the introspected class supports PCDATA.
+     * 
+     * @return whether or not the introspected class supports PCDATA.
      */
     public boolean supportsCharacters() {
         return addText != null;
     }
 
     /**
-     * Return all attribues supported by the introspected class.
+     * Returns an enumeration of the names of the attributes supported 
+     * by the introspected class.
+     * 
+     * @return an enumeration of the names of the attributes supported
+     *         by the introspected class.
      */
     public Enumeration getAttributes() {
         return attributeSetters.keys();
     }
 
     /**
-     * Return all nested elements supported by the introspected class.
+     * Returns an enumeration of the names of the nested elements supported 
+     * by the introspected class.
+     * 
+     * @return an enumeration of the names of the nested elements supported
+     *         by the introspected class.
      */
     public Enumeration getNestedElements() {
         return nestedTypes.keys();
     }
 
     /**
-     * Create a proper implementation of AttributeSetter for the given
-     * attribute type.
+     * Creates an implementation of AttributeSetter for the given
+     * attribute type. Conversions (where necessary) are automatically
+     * made for the following types:
+     * <ul>
+     * <li>String (left as it is)
+     * <li>Character/char (first character is used)
+     * <li>Boolean/boolean 
+     * ([EMAIL PROTECTED] Project#toBoolean(String) Project.toBoolean(String)} 
is used)
+     * <li>Class (Class.forName is used)
+     * <li>File (resolved relative to the appropriate project)
+     * <li>Path (resolve relative to the appropriate project)
+     * <li>EnumeratedAttribute (uses its own 
+     * [EMAIL PROTECTED] EnumeratedAttribute#setValue(String) setValue} method)
+     * <li>Other primitive types (wrapper classes are used with constructors 
+     * taking String)
+     * </ul>
+     * 
+     * If none of the above covers the given parameters, a constructor for the 
+     * appropriate class taking a String parameter is used if it is available.
+     * 
+     * @param m The method to invoke on the bean when the setter is invoked.
+     *          Must not be <code>null</code>.
+     * @param arg The type of the single argument of the bean's method.
+     *            Must not be <code>null</code>.
+     * @param attrName the name of the attribute for which the setter is being
+     *                 created.
+     * 
+     * @return an appropriate AttributeSetter instance, or <code>null</code>
+     *         if no appropriate conversion is available.
      */
     private AttributeSetter createAttributeSetter(final Method m,
-                                                  final Class arg) {
+                                                  Class arg, 
+                                                  final String attrName) {
+        // use wrappers for primitive classes, e.g. int and 
+        // Integer are treated identically
+        final Class reflectedArg = PRIMITIVE_TYPE_MAP.containsKey (arg) 
+            ? (Class) PRIMITIVE_TYPE_MAP.get(arg) : arg;
 
         // simplest case - setAttribute expects String
-        if (java.lang.String.class.equals(arg)) {
+        if (java.lang.String.class.equals(reflectedArg)) {
             return new AttributeSetter() {
                     public void set(Project p, Object parent, String value)
                         throws InvocationTargetException, 
IllegalAccessException {
@@ -482,69 +746,23 @@
                     }
                 };
 
-        // now for the primitive types, use their wrappers
-        } else if (java.lang.Character.class.equals(arg)
-                   || java.lang.Character.TYPE.equals(arg)) {
+        // char and Character get special treatment - take the first character
+        } else if (java.lang.Character.class.equals(reflectedArg)) {
             return new AttributeSetter() {
                     public void set(Project p, Object parent, String value)
                         throws InvocationTargetException, 
IllegalAccessException {
+                        if (value.length() == 0) {
+                            throw new BuildException("The value \"\" is not a 
" 
+                                + "legal value for attribute \"" 
+                                + attrName + "\"");
+                        }
                         m.invoke(parent, new Character[] {new 
Character(value.charAt(0))});
                     }
 
                 };
-        } else if (java.lang.Byte.TYPE.equals(arg)) {
-            return new AttributeSetter() {
-                    public void set(Project p, Object parent, String value)
-                        throws InvocationTargetException, 
IllegalAccessException {
-                        m.invoke(parent, new Byte[] {new Byte(value)});
-                    }
-
-                };
-        } else if (java.lang.Short.TYPE.equals(arg)) {
-            return new AttributeSetter() {
-                    public void set(Project p, Object parent, String value)
-                        throws InvocationTargetException, 
IllegalAccessException {
-                        m.invoke(parent, new Short[] {new Short(value)});
-                    }
-
-                };
-        } else if (java.lang.Integer.TYPE.equals(arg)) {
-            return new AttributeSetter() {
-                    public void set(Project p, Object parent, String value)
-                        throws InvocationTargetException, 
IllegalAccessException {
-                        m.invoke(parent, new Integer[] {new Integer(value)});
-                    }
-
-                };
-        } else if (java.lang.Long.TYPE.equals(arg)) {
-            return new AttributeSetter() {
-                    public void set(Project p, Object parent, String value)
-                        throws InvocationTargetException, 
IllegalAccessException {
-                        m.invoke(parent, new Long[] {new Long(value)});
-                    }
-
-                };
-        } else if (java.lang.Float.TYPE.equals(arg)) {
-            return new AttributeSetter() {
-                    public void set(Project p, Object parent, String value)
-                        throws InvocationTargetException, 
IllegalAccessException {
-                        m.invoke(parent, new Float[] {new Float(value)});
-                    }
-
-                };
-        } else if (java.lang.Double.TYPE.equals(arg)) {
-            return new AttributeSetter() {
-                    public void set(Project p, Object parent, String value)
-                        throws InvocationTargetException, 
IllegalAccessException {
-                        m.invoke(parent, new Double[] {new Double(value)});
-                    }
-
-                };
-
-        // boolean gets an extra treatment, because we have a nice method
-        // in Project
-        } else if (java.lang.Boolean.class.equals(arg)
-                   || java.lang.Boolean.TYPE.equals(arg)) {
+        // boolean and Boolean get special treatment because we 
+        // have a nice method in Project
+        } else if (java.lang.Boolean.class.equals(reflectedArg)) {
             return new AttributeSetter() {
                     public void set(Project p, Object parent, String value)
                         throws InvocationTargetException, 
IllegalAccessException {
@@ -555,7 +773,7 @@
                 };
 
         // Class doesn't have a String constructor but a decent factory method
-        } else if (java.lang.Class.class.equals(arg)) {
+        } else if (java.lang.Class.class.equals(reflectedArg)) {
             return new AttributeSetter() {
                     public void set(Project p, Object parent, String value)
                         throws InvocationTargetException, 
IllegalAccessException, BuildException {
@@ -568,7 +786,7 @@
                 };
 
         // resolve relative paths through Project
-        } else if (java.io.File.class.equals(arg)) {
+        } else if (java.io.File.class.equals(reflectedArg)) {
             return new AttributeSetter() {
                     public void set(Project p, Object parent, String value)
                         throws InvocationTargetException, 
IllegalAccessException {
@@ -578,7 +796,7 @@
                 };
 
         // resolve relative paths through Project
-        } else if (org.apache.tools.ant.types.Path.class.equals(arg)) {
+        } else if (org.apache.tools.ant.types.Path.class.equals(reflectedArg)) 
{
             return new AttributeSetter() {
                     public void set(Project p, Object parent, String value)
                         throws InvocationTargetException, 
IllegalAccessException {
@@ -588,12 +806,13 @@
                 };
 
         // EnumeratedAttributes have their own helper class
-        } else if 
(org.apache.tools.ant.types.EnumeratedAttribute.class.isAssignableFrom(arg)) {
+        } else if 
(org.apache.tools.ant.types.EnumeratedAttribute.class.isAssignableFrom(reflectedArg))
 {
             return new AttributeSetter() {
                     public void set(Project p, Object parent, String value)
                         throws InvocationTargetException, 
IllegalAccessException, BuildException {
                         try {
-                            org.apache.tools.ant.types.EnumeratedAttribute ea 
= (org.apache.tools.ant.types.EnumeratedAttribute)arg.newInstance();
+                            org.apache.tools.ant.types.EnumeratedAttribute ea 
= 
+                                
(org.apache.tools.ant.types.EnumeratedAttribute) reflectedArg.newInstance();
                             ea.setValue(value);
                             m.invoke(parent, new EnumeratedAttribute[] {ea});
                         } catch (InstantiationException ie) {
@@ -603,11 +822,13 @@
                 };
 
         // worst case. look for a public String constructor and use it
+        // This is used (deliberately) for all primitives/wrappers other than 
+        // char and boolean
         } else {
 
             try {
                 final Constructor c =
-                    arg.getConstructor(new Class[] {java.lang.String.class});
+                    reflectedArg.getConstructor(new Class[] 
{java.lang.String.class});
 
                 return new AttributeSetter() {
                         public void set(Project p, Object parent,
@@ -632,63 +853,76 @@
         return null;
     }
 
-    protected String getElementName(Project project, Object element)
-    {
-        Hashtable elements = project.getTaskDefinitions();
-        String typeName = "task";
-        if (!elements.contains( element.getClass() ))
-        {
-            elements = project.getDataTypeDefinitions();
-            typeName = "data type";
-            if (!elements.contains( element.getClass() ))
-            {
-                elements = null;
-            }
-        }
-
-        if (elements != null)
-        {
-            Enumeration e = elements.keys();
-            while (e.hasMoreElements())
-            {
-                String elementName = (String) e.nextElement();
-                Class elementClass = (Class) elements.get( elementName );
-                if ( element.getClass().equals( elementClass ) )
-                {
-                    return "The <" + elementName + "> " + typeName;
-                }
-            }
-        }
-
-        return "Class " + element.getClass().getName();
+    /**
+     * Returns a description of the type of the given element in
+     * relation to a given project. This is used for logging purposes
+     * when the element is asked to cope with some data it has no
+     * way of handling.
+     * 
+     * @param project The project the element is defined in. 
+     *                Must not be <code>null</code>.
+     * 
+     * @param element The element to describe.
+     *                Must not be <code>null</code>.
+     * 
+     * @return a description of the element type
+     */
+    protected String getElementName(Project project, Object element) {
+        return project.getElementName(element);
     }
 
     /**
-     * extract the name of a property from a method name - subtracting
-     * a given prefix.
+     * Extracts the name of a property from a method name by subtracting
+     * a given prefix and converting into lower case. It is up to calling
+     * code to make sure the method name does actually begin with the
+     * specified prefix - no checking is done in this method.
+     * 
+     * @param methodName The name of the method in question.
+     *                   Must not be <code>null</code>.
+     * @param prefix     The prefix to remove.
+     *                   Must not be <code>null</code>.
+     * 
+     * @return the lower-cased method name with the prefix removed.
      */
     private String getPropertyName(String methodName, String prefix) {
         int start = prefix.length();
         return methodName.substring(start).toLowerCase(Locale.US);
     }
 
+    /**
+     * Internal interface used to create nested elements. Not documented 
+     * in detail for reasons of source code readability.
+     */
     private interface NestedCreator {
         Object create(Object parent)
             throws InvocationTargetException, IllegalAccessException, 
InstantiationException;
     }
 
+    /**
+     * Internal interface used to storing nested elements. Not documented 
+     * in detail for reasons of source code readability.
+     */
     private interface NestedStorer {
         void store(Object parent, Object child)
             throws InvocationTargetException, IllegalAccessException, 
InstantiationException;
     }
 
+    /**
+     * Internal interface used to setting element attributes. Not documented 
+     * in detail for reasons of source code readability.
+     */
     private interface AttributeSetter {
         void set(Project p, Object parent, String value)
             throws InvocationTargetException, IllegalAccessException,
                    BuildException;
     }
 
-    public void buildStarted(BuildEvent event) {}
+    /**
+     * Clears all storage used by this class, including the static cache of 
+     * helpers.
+     * 
+     * @param event Ignored in this implementation.
+     */
     public void buildFinished(BuildEvent event) {
         attributeTypes.clear();
         attributeSetters.clear();
@@ -698,9 +932,44 @@
         helpers.clear();
     }
 
+    /**
+     * Empty implementation to satisfy the BuildListener interface.
+     * @param event Ignored in this implementation.
+     */
+    public void buildStarted(BuildEvent event) {}
+    
+    /**
+     * Empty implementation to satisfy the BuildListener interface.
+     *
+     * @param event Ignored in this implementation.
+     */
     public void targetStarted(BuildEvent event) {}
+    
+    /**
+     * Empty implementation to satisfy the BuildListener interface.
+     *
+     * @param event Ignored in this implementation.
+     */
     public void targetFinished(BuildEvent event) {}
+    
+    /**
+     * Empty implementation to satisfy the BuildListener interface.
+     *
+     * @param event Ignored in this implementation.
+     */
     public void taskStarted(BuildEvent event) {}
+    
+    /**
+     * Empty implementation to satisfy the BuildListener interface.
+     *
+     * @param event Ignored in this implementation.
+     */
     public void taskFinished(BuildEvent event) {}
+    
+    /**
+     * Empty implementation to satisfy the BuildListener interface.
+     *
+     * @param event Ignored in this implementation.
+     */
     public void messageLogged(BuildEvent event) {}
 }
Index: 
proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antjar.java
===================================================================
RCS file: 
/home/cvspublic/ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antjar.java,v
retrieving revision 1.4
diff -u -r1.4 Antjar.java
--- proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antjar.java  
7 Mar 2003 11:22:59 -0000       1.4
+++ proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antjar.java  
1 Apr 2003 11:26:39 -0000
@@ -53,15 +53,12 @@
  */
 package org.apache.tools.ant.taskdefs;
 
-import org.xml.sax.*;
-import javax.xml.parsers.*;
 
 import org.apache.tools.ant.*;
 import org.apache.tools.ant.types.ZipFileSet;
 import org.apache.tools.zip.*;
 
 import java.io.*;
-import java.util.*;
 
 /**
  * Creates a ANTLIB archive. Code is similar to the War class, but with
@@ -129,7 +126,7 @@
         // If no antxml file is specified, it's an error.
         if (libraryDescriptor == null) {
             throw new BuildException("antxml attribute is required", 
-                                    location);
+                                    getLocation());
         }
 
         super.initZipOutputStream(zOut);
@@ -142,9 +139,10 @@
      * @param file file to add
      * @param zOut stream to add to 
      * @param vPath the path to add it to in the zipfile
+     * @param mode the Unix permissions to set.
      * @exception IOException io trouble
      */
-    protected void zipFile(File file, ZipOutputStream zOut, String vPath)
+    protected void zipFile(File file, ZipOutputStream zOut, String vPath, int 
mode)
         throws IOException {
         // If the file being added is META-INF/antlib.xml, we warn if it's not 
the
         // one specified in the "antxml" attribute - or if it's being added 
twice,
@@ -159,12 +157,12 @@
                    " task)", Project.MSG_WARN);
             }
             else {
-                super.zipFile(file, zOut, vPath);
+                super.zipFile(file, zOut, vPath, mode);
                 descriptorAdded = true;
             }
         }
         else {
-            super.zipFile(file, zOut, vPath);
+            super.zipFile(file, zOut, vPath, mode);
         }
     }
 
Index: 
proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antlib.java
===================================================================
RCS file: 
/home/cvspublic/ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antlib.java,v
retrieving revision 1.5
diff -u -r1.5 Antlib.java
--- proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antlib.java  
3 Mar 2002 12:37:41 -0000       1.5
+++ proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antlib.java  
1 Apr 2003 11:26:42 -0000
@@ -55,7 +55,6 @@
 
 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.*;
 
@@ -108,10 +107,6 @@
      */
     private Path classpath = null;
 
-    /**
-     * the manufacture set of classes to load
-     */
-    private Path loaderPath = null;
 
     /**
      * our little xml parse
@@ -357,7 +352,7 @@
      * Default is <code>true</code>.
      * This property is mostly used by the core when loading core tasks.
      *
-     * @param failedonerror if true loading will stop if classes
+     * @param onerror if true loading will stop if classes
      *                      cannot be instantiated
      */
     public void setOnerror(FailureAction onerror) {
@@ -399,7 +394,7 @@
      */
     public Path createClasspath() {
         if (classpath == null) {
-            classpath = new Path(project);
+            classpath = new Path(getProject());
         }
         return classpath.createPath();
     }
@@ -424,7 +419,7 @@
     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");
+        String home = getProject().getProperty("ant.home");
 
         if (home == null) {
             throw new BuildException("ANT_HOME not set as required.");
@@ -443,11 +438,11 @@
         if (file == null && classpath == null) {
             String msg =
                 "Must specify either library or file attribute or classpath.";
-            throw new BuildException(msg, location);
+            throw new BuildException(msg, getLocation());
         }
         if (file != null && !file.exists()) {
             String msg = "Cannot find library: " + file;
-            throw new BuildException(msg, location);
+            throw new BuildException(msg, getLocation());
         }
 
         loadDefinitions();
@@ -492,7 +487,7 @@
                 case FAIL:
                     throw new BuildException(msg);
                 case REPORT:
-                    log(msg, project.MSG_WARN);
+                    log(msg, Project.MSG_WARN);
                 }
             }
         }
@@ -502,7 +497,7 @@
             case FAIL:
                 throw new BuildException(msg, io);
             case REPORT:
-                log(io.getMessage(), project.MSG_WARN);
+                log(io.getMessage(), Project.MSG_WARN);
             }
         }
         return found;
@@ -534,7 +529,7 @@
         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 getProject().getCoreLoader().getResources(res);
         }
 
         return new DescriptorEnumeration(path.list(), res);
@@ -561,7 +556,7 @@
      * create the classpath for this library from the file passed in and
      * any classpath parameters
      *
-     * @param file library file to use
+     * @param clspath library file to use
      * @return classloader using te
      * @exception BuildException trouble creating the classloader
      */
@@ -569,13 +564,13 @@
         throws BuildException {
         if (loaderId == null) {
             log("Loading definitions from CORE, <classpath> ignored",
-                project.MSG_VERBOSE);
-            return project.getCoreLoader();
+                Project.MSG_VERBOSE);
+            return getProject().getCoreLoader();
         }
 
         log("Using ClassLoader '" + loaderId + "' to load path: " + clspath,
-            project.MSG_VERBOSE);
-        return project.addToLoader(loaderId, clspath);
+            Project.MSG_VERBOSE);
+        return getProject().addToLoader(loaderId, clspath);
     }
 
 
@@ -584,7 +579,7 @@
      */
     private Path makeLoaderClasspath()
     {
-        Path clspath = new Path(project);
+        Path clspath = new Path(getProject());
         if (file != null) clspath.setLocation(file);
         //append any build supplied classpath
         if (classpath != null) {
@@ -606,11 +601,10 @@
         throws BuildException {
         try {
             SAXParser saxParser = saxFactory.newSAXParser();
-            Parser parser = saxParser.getParser();
 
             InputSource inputSource = new InputSource(is);
             //inputSource.setSystemId(uri); //URI is nasty for jar entries
-            project.log("parsing descriptor for library: " + file,
+            getProject().log("parsing descriptor for library: " + file,
                         Project.MSG_VERBOSE);
             saxParser.parse(inputSource, new AntLibraryHandler(cl, als));
         }
@@ -683,7 +677,7 @@
         /**
          * Constructor for the AntLibraryHandler object
          *
-         * @param cl optional classloader
+         * @param classloader optional classloader
          * @param als alias list
          */
         AntLibraryHandler(ClassLoader classloader, Properties als) {
@@ -759,7 +753,7 @@
 
             try {
                 if ("role".equals(tag)) {
-                    if (project.isRoleDefined(name)) {
+                    if (getProject().isRoleDefined(name)) {
                         String msg = "Cannot override role: " + name;
                         log(msg, Project.MSG_WARN);
                         return;
@@ -767,7 +761,7 @@
                     // Defining a new role
                     Class clz = loadClass(className);
                     if (clz != null) {
-                        project.addRoleDefinition(name, clz,
+                        getProject().addRoleDefinition(name, clz,
                                                   (adapter == null? null :
                                                    loadClass(adapter)));
                     }
@@ -781,24 +775,24 @@
                     name = alias;
                 }
                 //catch an attempted override of an existing name
-                if (!override && project.isDefinedOnRole(tag, name)) {
+                if (!override && getProject().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);
+                    getProject().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);
+                    getProject().log(be.getMessage(), Project.MSG_WARN);
                     break;
                 default:
-                    project.log(be.getMessage(), project.MSG_DEBUG);
+                    getProject().log(be.getMessage(), Project.MSG_DEBUG);
                 }
             }
         }
@@ -833,10 +827,10 @@
             }
 
             if (onerror.getIndex() == REPORT) {
-                project.log(msg, project.MSG_WARN);
+                getProject().log(msg, Project.MSG_WARN);
             }
             else {
-                project.log(msg, project.MSG_DEBUG);
+                getProject().log(msg, Project.MSG_DEBUG);
             }
             return null;
         }

Reply via email to