ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ehatc...@apache.org
Subject cvs commit: jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant Project.java RoleAdapter.java SymbolTable.java TaskAdapter.java
Date Mon, 11 Feb 2002 03:39:01 GMT
ehatcher    02/02/10 19:39:00

  Modified:    proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs
                        Antjar.java Antlib.java
               proposal/sandbox/antlib/docs/manual/CoreTasks antjar.html
                        antlib.html
  Added:       proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs
                        Ant.java
               proposal/sandbox/antlib build.xml
               proposal/sandbox/antlib/src/main/org/apache/tools/ant
                        Project.java RoleAdapter.java SymbolTable.java
                        TaskAdapter.java
  Log:
  upon Jose Alberto's request, updates to antlib
  
  Revision  Changes    Path
  1.2       +1 -140    jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antjar.java
  
  Index: Antjar.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antjar.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Antjar.java	27 Nov 2001 06:53:22 -0000	1.1
  +++ Antjar.java	11 Feb 2002 03:39:00 -0000	1.2
  @@ -107,9 +107,6 @@
               throw new BuildException("Deployment descriptor: " + libraryDescriptor + " does not exist.");
           }
   
  -        //check 
  -        validateDescriptor();
  -
           // Create a ZipFileSet for this file, and pass it up.
           ZipFileSet fs = new ZipFileSet();
           fs.setDir(new File(libraryDescriptor.getParent()));
  @@ -130,7 +127,7 @@
           throws IOException, BuildException {
           // If no antxml file is specified, it's an error.
           if (libraryDescriptor == null) {
  -            throw new BuildException("webxml attribute is required", location);
  +            throw new BuildException("antxml attribute is required", location);
           }
   
           super.initZipOutputStream(zOut);
  @@ -177,140 +174,4 @@
           super.cleanUp();
       }
   
  -
  -    /**
  -     * validate the descriptor against the DTD
  -     *
  -     * @exception BuildException failure to validate
  -     */
  -    protected void validateDescriptor()
  -        throws BuildException {
  -        SAXParserFactory saxFactory = SAXParserFactory.newInstance();
  -        saxFactory.setValidating(true);
  -        InputStream is = null;
  -        try {
  -            SAXParser saxParser = saxFactory.newSAXParser();
  -            Parser parser = saxParser.getParser();
  -            is = new FileInputStream(libraryDescriptor);
  -            InputSource inputSource = new InputSource(is);
  -            inputSource.setSystemId("file:" + libraryDescriptor);
  -            project.log("Validating library descriptor: " + libraryDescriptor,
  -                    Project.MSG_VERBOSE);
  -            saxParser.parse(inputSource, new AntLibraryValidator());
  -        }
  -        catch (ParserConfigurationException exc) {
  -            throw new BuildException("Parser has not been configured correctly", exc);
  -        }
  -        catch (SAXParseException exc) {
  -            Location location =
  -                    new Location(libraryDescriptor.toString(),
  -                    exc.getLineNumber(), exc.getColumnNumber());
  -
  -            Throwable t = exc.getException();
  -            if (t instanceof BuildException) {
  -                BuildException be = (BuildException) t;
  -                if (be.getLocation() == Location.UNKNOWN_LOCATION) {
  -                    be.setLocation(location);
  -                }
  -                throw be;
  -            }
  -
  -            throw new BuildException(exc.getMessage(), t, location);
  -        }
  -        catch (SAXException exc) {
  -            Throwable t = exc.getException();
  -            if (t instanceof BuildException) {
  -                throw (BuildException) t;
  -            }
  -            throw new BuildException(exc.getMessage(), t);
  -        }
  -        catch (IOException exc) {
  -            throw new BuildException("Error reading library descriptor", exc);
  -        }
  -        finally {
  -            if (is != null) {
  -                try {
  -                    is.close();
  -                }
  -                catch (IOException ioe) {
  -                    // ignore this
  -                }
  -            }
  -        }
  -    }
  -
  -
  -    /**
  -     * Parses the document describing the content of the library.
  -     */
  -    private class AntLibraryValidator extends HandlerBase {
  -
  -        /**
  -         * flag to track whether the DOCTYPE was hit in the prolog
  -         */
  -        private boolean doctypePresent = false;
  -
  -        /**
  -         * doc locator
  -         */
  -        private Locator locator = null;
  -
  -        /**
  -         * Sets the DocumentLocator attribute of the AntLibraryValidator
  -         * object
  -         *
  -         * @param locator The new DocumentLocator value
  -         */
  -        public void setDocumentLocator(Locator locator) {
  -            this.locator = locator;
  -        }
  -
  -        /**
  -         * SAX callback handler
  -         *
  -         * @param tag XML tag
  -         * @param attrs attributes
  -         * @exception SAXParseException parse trouble
  -         */
  -        public void startElement(String tag, AttributeList attrs)
  -            throws SAXParseException {
  -            // By the time an element is found
  -            // the DOCTYPE should have been found.
  -            if (!doctypePresent) {
  -                String msg = "Missing DOCTYPE declaration or wrong SYSTEM ID";
  -                throw new SAXParseException(msg, locator);
  -            }
  -        }
  -
  -        /**
  -         * Recognizes the DTD declaration for antlib and returns the corresponding
  -         * DTD definition from a resource. <P>
  -         *
  -         * To allow for future versions of the DTD format it will search
  -         * for any DTDs of the form "Antlib-V.*\.dtd".
  -         *
  -         * @param publicId public ID (ignored)
  -         * @param systemId system ID (matched against)
  -         * @return local DTD instance 
  -         */
  -        public InputSource resolveEntity(String publicId,
  -                String systemId) {
  -
  -            log("Looking for entity with PublicID=" + publicId +
  -                    " and SystemId=" + systemId, Project.MSG_VERBOSE);
  -            if (Antlib.matchDtdId(systemId)) {
  -                String resId =
  -                        systemId.substring(Antlib.ANTLIB_DTD_URL.length());
  -                InputSource is =
  -                        new InputSource(this.getClass().getResourceAsStream(resId));
  -
  -                is.setSystemId(systemId);
  -                doctypePresent = true;
  -                return is;
  -            }
  -            return null;
  -        }
  -    //end inner class AntLibraryValidator
  -    }
   }
  -
  
  
  
  1.2       +140 -132  jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antlib.java
  
  Index: Antlib.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antlib.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Antlib.java	27 Nov 2001 06:53:22 -0000	1.1
  +++ Antlib.java	11 Feb 2002 03:39:00 -0000	1.2
  @@ -76,9 +76,11 @@
    * @since ant1.5
    */
   public class Antlib extends Task {
  -    /*
  -     *  implements DeclaringTask
  +    /**
  +     * The named classloader to use.
  +     * Defaults to the default classLoader.
        */
  +    private String loaderId = "";
   
       /**
        * library attribute
  @@ -177,6 +179,15 @@
           this.file = file;
       }
   
  +    /**
  +     * Set the ClassLoader to use for this library.
  +     *
  +     * @param id the id for the ClassLoader to use, 
  +     *           if other than the default.
  +     */
  +    public void setLoaderid(String id) {
  +	this.loaderId = id;
  +    }
   
       /**
        * Set whether to override any existing definitions.
  @@ -189,8 +200,9 @@
   
   
       /**
  -     * Set whether to use a new classloader or not. Default is <code>false</code>
  -     * . This property is mostly used by the core when loading core tasks.
  +     * Set whether to use a new classloader or not. 
  +     * Default is <code>false</code>.
  +     * 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.
  @@ -264,7 +276,7 @@
                   String msg = "You cannot specify both file and library.";
                   throw new BuildException(msg, location);
               }
  -            // For the time being libraries live in $ANT_HOME/lib.
  +            // 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");
   
  @@ -272,7 +284,7 @@
                   throw new BuildException("ANT_HOME not set as required.");
               }
   
  -            realFile = new File(new File(home, "lib"), library);
  +            realFile = new File(new File(home, "antlib"), library);
           }
           else if (file == null) {
               String msg = "Must specify either library or file attribute.";
  @@ -406,8 +418,7 @@
           if (classpath != null) {
               clspath.append(classpath);
           }
  -        AntClassLoader al = new AntClassLoader(project, clspath, true);
  -        return al;
  +	return project.getSymbols().addToLoader(loaderId, clspath);
       }
   
   
  @@ -474,30 +485,6 @@
   
   
       /**
  -     * get a DTD URI from url, prefix and extension
  -     *
  -     * @return URI for this dtd version
  -     */
  -    public static String dtdVersion() {
  -        return ANTLIB_DTD_URL + ANTLIB_DTD_PREFIX +
  -                ANTLIB_DTD_VERSION + ANTLIB_DTD_EXT;
  -    }
  -
  -
  -    /**
  -     * compare system ID with the dtd string
  -     * -ignoring any version number
  -     * @param systemId Description of Parameter
  -     * @return true if this is a an ant library descriptor
  -     */
  -    public static boolean matchDtdId(String systemId) {
  -        return (systemId != null &&
  -                systemId.startsWith(ANTLIB_DTD_URL + ANTLIB_DTD_PREFIX) &&
  -                systemId.endsWith(ANTLIB_DTD_EXT));
  -    }
  -
  -
  -    /**
        * Parses the document describing the content of the 
        * library. An inner class for access to Project.log 
        */
  @@ -516,6 +503,14 @@
            */
           private Locator locator = null;
   
  +	private int level = 0;
  +
  +	private SymbolTable symbols = null;
  +
  +	private String name = null;
  +	private String className = null;
  +	private String adapter = null;
  +
           /**
            * Constructor for the AntLibraryHandler object
            *
  @@ -525,9 +520,9 @@
           AntLibraryHandler(ClassLoader classloader, Properties als) {
               this.classloader = classloader;
               this.aliasMap = als;
  +	    this.symbols = project.getSymbols();
           }
   
  -
           /**
            * Sets the DocumentLocator attribute of the AntLibraryHandler
            * object
  @@ -538,6 +533,35 @@
               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);
  +	    }
  +	}
   
           /**
            * SAX callback handler
  @@ -548,121 +572,105 @@
            */
           public void startElement(String tag, AttributeList attrs)
               throws SAXParseException {
  +	    level ++;
               if ("antlib".equals(tag)) {
  +		if (level > 1) {
  +		    throw new SAXParseException("Unexpected element: " + tag,
  +						locator);
  +		}
                   // No attributes to worry about
                   return;
               }
  -            if ("task".equals(tag) || "type".equals(tag)) {
  -                String name = null;
  -                String className = 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 {
  -                        throw new SAXParseException("Unexpected attribute \""
  -                                 + key + "\"", locator);
  -                    }
  -                }
  -                if (name == null || className == null) {
  -                    String msg = "Underspecified " + tag + " declaration.";
  -                    throw new SAXParseException(msg, locator);
  -                }
  -
  -                try {
  -                    //check for name alias
  -                    String alias = aliasMap.getProperty(name);
  -                    if (alias != null) {
  -                        name = alias;
  -                    }
  -                    //catch an attempted override of an existing name
  -                    if (!override && inUse(name)) {
  -                        String msg = "Cannot override " + tag + ": " + name;
  -                        log(msg, Project.MSG_WARN);
  -                        return;
  -                    }
  -
  -                    //load the named class
  -                    Class cls;
  -                    if(classloader==null) {
  -                        cls=Class.forName(className);
  -                    }
  -                    else {
  -                        cls=classloader.loadClass(className);
  -                    }
  -
  -                    //register it as a task or a datatype
  -                    if (tag.equals("task")) {
  -                        project.addTaskDefinition(name, cls);
  -                    }
  -                    else {
  -                        project.addDataTypeDefinition(name, 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);
  -                }
  -            }
  -            else {
  -                throw new SAXParseException("Unexpected element \"" +
  -                        tag + "\"",
  -                        locator);
  -            }
  -        }
  -
  +	    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);
  +	    }
  +	}
   
           /**
  -         * test for a name being in use already
  +         * 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 inUse(String name) {
  -            return (project.getTaskDefinitions().get(name) != null ||
  -                    project.getDataTypeDefinitions().get(name) != null);
  +        private boolean isInUse(String role, String name) {
  +            return (symbols.get(role, name) != null);
           }
   
  -
           /**
  -         * Recognizes the DTD declaration for antlib and returns the corresponding
  -         * DTD definition from a resource. <P>
  -         *
  -         * To allow for future versions of the DTD format it will search
  -         * for any DTDs of the form "Antlib-V.*\.dtd".
  +         * test for a role name being in use already
            *
  -         * @param publicId public ID (ignored)
  -         * @param systemId system ID (matched against)
  -         * @return local DTD instance 
  +         * @param name the name to test
  +         * @return true if it is a task or a datatype
            */
  -        public InputSource resolveEntity(String publicId,
  -                String systemId) {
  -
  -            log("Looking for entiry with PublicID=" + publicId +
  -                    " and SystemId=" + systemId, Project.MSG_VERBOSE);
  -            if (matchDtdId(systemId)) {
  -                String resId = systemId.substring(ANTLIB_DTD_URL.length());
  -                InputSource is =
  -                        new InputSource(this.getClass().getResourceAsStream(resId));
  -
  -                is.setSystemId(systemId);
  -                return is;
  -            }
  -            return null;
  +        private boolean isRoleInUse(String name) {
  +            return (symbols.getRole(name) != null);
           }
  +
       //end inner class AntLibraryHandler
       }
   
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Ant.java
  
  Index: Ant.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * 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:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.tools.ant.taskdefs;
  
  import org.apache.tools.ant.Task;
  import org.apache.tools.ant.Project;
  import org.apache.tools.ant.ProjectComponent;
  import org.apache.tools.ant.BuildListener;
  import org.apache.tools.ant.DefaultLogger;
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.ProjectHelper;
  import org.apache.tools.ant.util.FileUtils;
  import java.io.File;
  import java.io.PrintStream;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.lang.reflect.Method;
  import java.util.Vector;
  import java.util.Hashtable;
  import java.util.Enumeration;
  
  /**
   * Call Ant in a sub-project
   *
   *  <pre>
   *  &lt;target name=&quot;foo&quot; depends=&quot;init&quot;&gt;
   *    &lt;ant antfile=&quot;build.xml&quot; target=&quot;bar&quot; &gt;
   *      &lt;property name=&quot;property1&quot; value=&quot;aaaaa&quot; /&gt;
   *      &lt;property name=&quot;foo&quot; value=&quot;baz&quot; /&gt;
   *    &lt;/ant&gt;</SPAN>
   *  &lt;/target&gt;</SPAN>
   *
   *  &lt;target name=&quot;bar&quot; depends=&quot;init&quot;&gt;
   *    &lt;echo message=&quot;prop is ${property1} ${foo}&quot; /&gt;
   *  &lt;/target&gt;
   * </pre>
   *
   *
   * @author costin@dnt.ro
   */
  public class Ant extends Task {
  
      /** the basedir where is executed the build file */
      private File dir = null;
      
      /** the build.xml file (can be absolute) in this case dir will be ignored */
      private String antFile = null;
      
      /** the target to call if any */
      private String target = null;
      
      /** the output */
      private String output = null;
      
      /** should we inherit properties from the parent ? */
      private boolean inheritAll = true;
      
      /** should we inherit references from the parent ? */
      private boolean inheritRefs = false;
      
      /** the properties to pass to the new project */
      private Vector properties = new Vector();
      
      /** the references to pass to the new project */
      private Vector references = new Vector();
  
      /** the temporary project created to run the build file */
      private Project newProject;
  
      /**
       * If true, inherit all properties from parent Project
       * If false, inherit only userProperties and those defined
       * inside the ant call itself
       */
      public void setInheritAll(boolean value) {
         inheritAll = value;
      }
  
      /**
       * If true, inherit all references from parent Project
       * If false, inherit only those defined
       * inside the ant call itself
       */
      public void setInheritRefs(boolean value) {
         inheritRefs = value;
      }
  
      public void init() {
          newProject = new Project(project);
          newProject.setJavaVersionProperty();
  //          newProject.addTaskDefinition("property", 
  //                               (Class)project.getTaskDefinitions().get("property"));
      }
  
      private void reinit() {
          init();
          final int count = properties.size();
          for (int i = 0; i < count; i++) {
              Property p = (Property) properties.elementAt(i);
              Property newP = (Property) newProject.createTask("property");
              newP.setName(p.getName());
              if (p.getValue() != null) {
                  newP.setValue(p.getValue());
              }
              if (p.getFile() != null) {
                  newP.setFile(p.getFile());
              } 
              if (p.getResource() != null) {
                  newP.setResource(p.getResource());
              }
              properties.setElementAt(newP, i);
          }
      }
  
      private void initializeProject() {
          Vector listeners = project.getBuildListeners();
          final int count = listeners.size();
          for (int i = 0; i < count; i++) {
              newProject.addBuildListener((BuildListener)listeners.elementAt(i));
          }
  
          if (output != null) {
              try {
                  PrintStream out = new PrintStream(new FileOutputStream(output));
                  DefaultLogger logger = new DefaultLogger();
                  logger.setMessageOutputLevel(Project.MSG_INFO);
                  logger.setOutputPrintStream(out);
                  logger.setErrorPrintStream(out);
                  newProject.addBuildListener(logger);
              }
              catch( IOException ex ) {
                  log( "Ant: Can't set output to " + output );
              }
          }
  
  //          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) {
             prop1 = project.getProperties();
          } else {
             prop1 = project.getUserProperties();
  
             // set Java built-in properties separately,
             // b/c we won't inherit them.
             newProject.setSystemProperties();
          }
          
          Enumeration e = prop1.keys();
          while (e.hasMoreElements()) {
              String arg = (String) e.nextElement();
              if ("basedir".equals(arg) || "ant.file".equals(arg)) {
                  // basedir and ant.file get special treatment in execute()
                  continue;
              }
              
              String value = (String) prop1.get(arg);
              if (inheritAll){
                 newProject.setProperty(arg, value);
              } else {
                 newProject.setUserProperty(arg, value);
              }
          }
      }
  
      protected void handleOutput(String line) {
          if (newProject != null) {
              newProject.demuxOutput(line, false);
          } else {
              super.handleOutput(line);
          }
      }
      
      protected void handleErrorOutput(String line) {
          if (newProject != null) {
              newProject.demuxOutput(line, true);
          } else {
              super.handleErrorOutput(line);
          }
      }
      
      /**
       * Do the execution.
       */
      public void execute() throws BuildException {
          try {
              if (newProject == null) {
                  reinit();
              }
          
              if ( (dir == null) && (inheritAll) ) {
                  dir = project.getBaseDir();
              }
  
              initializeProject();
  
              if (dir != null) {
                  newProject.setBaseDir(dir);
                  newProject.setUserProperty("basedir" , dir.getAbsolutePath());
              } else {
                  dir = project.getBaseDir();
              }
  
              overrideProperties();
  
              if (antFile == null) {
                  antFile = "build.xml";
              }
  
              File file = FileUtils.newFileUtils().resolveFile(dir, antFile);
              antFile = file.getAbsolutePath();
  
              newProject.setUserProperty( "ant.file" , antFile );
              ProjectHelper.configureProject(newProject, new File(antFile));
              
              if (target == null) {
                  target = newProject.getDefaultTarget();
              }
  
              addReferences();
  
              // Are we trying to call the target in which we are defined?
              if (newProject.getBaseDir().equals(project.getBaseDir()) &&
                  newProject.getProperty("ant.file").equals(project.getProperty("ant.file")) &&
                  getOwningTarget() != null &&
                  target.equals(this.getOwningTarget().getName())) { 
  
                  throw new BuildException("ant task calling its own parent target");
              }
  
              newProject.executeTarget(target);
          } finally {
              // help the gc
              newProject = null;
          }
      }
  
      /**
       * Override the properties in the new project with the one
       * explicitly defined as nested elements here.
       */
      private void overrideProperties() throws BuildException {
          Enumeration e = properties.elements();
          while (e.hasMoreElements()) {
              Property p = (Property) e.nextElement();
              p.setProject(newProject);
              p.execute();
          }
      }
  
      /**
       * Add the references explicitly defined as nested elements to the
       * new project.  Also copy over all references that don't override
       * existing references in the new project if inheritall has been
       * requested.
       */
      private void addReferences() throws BuildException {
          Hashtable thisReferences = (Hashtable) project.getReferences().clone();
          Hashtable newReferences = newProject.getReferences();
          Enumeration e;
          if (references.size() > 0) {
              for(e = references.elements(); e.hasMoreElements();) {
                  Reference ref = (Reference)e.nextElement();
                  String refid = ref.getRefId();
                  if (refid == null) {
                      throw new BuildException("the refid attribute is required for reference elements");
                  }
                  if (!thisReferences.containsKey(refid)) {
                      log("Parent project doesn't contain any reference '"
                          + refid + "'", 
                          Project.MSG_WARN);
                      continue;
                  }
  
                  thisReferences.remove(refid);
                  String toRefid = ref.getToRefid();
                  if (toRefid == null) {
                      toRefid = refid;
                  }
                  copyReference(refid, toRefid);
              }
          }
  
          // Now add all references that are not defined in the
          // subproject, if inheritRefs is true
          if (inheritRefs) {
              for(e = thisReferences.keys(); e.hasMoreElements();) {
                  String key = (String)e.nextElement();
                  if (newReferences.containsKey(key)) {
                      continue;
                  }
                  copyReference(key, key);
              }
          }
      }
  
      /**
       * Try to clone and reconfigure the object referenced by oldkey in
       * the parent project and add it to the new project with the key
       * newkey.
       *
       * <p>If we cannot clone it, copy the referenced object itself and
       * keep our fingers crossed.</p>
       */
      private void copyReference(String oldKey, String newKey) {
          Object orig = project.getReference(oldKey);
          Class c = orig.getClass();
          Object copy = orig;
          try {
              Method cloneM = c.getMethod("clone", new Class[0]);
              if (cloneM != null) {
                  copy = cloneM.invoke(orig, new Object[0]);
              }
          } catch (Exception e) {
              // not Clonable
          }
          
  
          if (copy instanceof ProjectComponent) {
              ((ProjectComponent) copy).setProject(newProject);
          } else {
              try {
                  Method setProjectM = 
                      c.getMethod( "setProject", new Class[] {Project.class});
                  if(setProjectM != null) {
                      setProjectM.invoke(copy, new Object[] {newProject});
                  }
              } catch (NoSuchMethodException e) {
                  // ignore this if the class being referenced does not have
                  // a set project method.
              } catch(Exception e2) {
                  String msg = "Error setting new project instance for reference with id "
                      + oldKey; 
                  throw new BuildException(msg, e2, location);
              }
          }
          newProject.addReference(newKey, copy);
      }
  
      /**
       * ...
       */
      public void setDir(File d) {
          this.dir = d;
      }
  
      /**
       * set the build file, it can be either absolute or relative.
       * If it is absolute, <tt>dir</tt> will be ignored, if it is
       * relative it will be resolved relative to <tt>dir</tt>.
       */
      public void setAntfile(String s) {
          // @note: it is a string and not a file to handle relative/absolute
          // otherwise a relative file will be resolved based on the current
          // basedir.
          this.antFile = s;
      }
  
      /**
       * set the target to execute. If none is defined it will
       * execute the default target of the build file
       */
      public void setTarget(String s) {
          this.target = s;
      }
  
      public void setOutput(String s) {
          this.output = s;
      }
  
      /** create a property to pass to the new project as a 'user property' */
      public Property createProperty() {
          if (newProject == null) {
              reinit();
          }
          Property p = new Property(true);
          p.setProject(newProject);
          p.setTaskName("property");
          properties.addElement( p );
          return p;
      }
  
      /** 
       * create a reference element that identifies a data type that
       * should be carried over to the new project.
       */
      public void addReference(Reference r) {
          references.addElement(r);
      }
  
      /**
       * Helper class that implements the nested &lt;reference&gt;
       * element of &lt;ant&gt; and &lt;antcall&gt;.
       */
      public static class Reference 
          extends org.apache.tools.ant.types.Reference {
  
          public Reference() {super();}
          
          private String targetid=null;
          public void setToRefid(String targetid) { this.targetid=targetid; }
          public String getToRefid() { return targetid; }
      }
  }
  
  
  
  1.2       +30 -22    jakarta-ant/proposal/sandbox/antlib/docs/manual/CoreTasks/antjar.html
  
  Index: antjar.html
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/sandbox/antlib/docs/manual/CoreTasks/antjar.html,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- antjar.html	27 Nov 2001 06:53:22 -0000	1.1
  +++ antjar.html	11 Feb 2002 03:39:00 -0000	1.2
  @@ -12,41 +12,50 @@
   <p>An extension of the <a href="jar.html">Jar</a> task with special
   treatment for the library descriptor file that should end up in the
   <code>META-INF</code> directory of the Ant Archive.</p>
  -<p>This task validates the provided library descriptor making certain
  -it specifies the following SYSTEM ID: 
  -<b>&quot;http://jakarta.apache.org/ant/AntlibV1_0.dtd&quot;</b>. 
  -This DTD is defined as follows:</p>
  +<p>
  +Descriptors must follow the following rules, although there is no fix DTD
  +for them:
   <pre>
  -&lt;?xml version='1.0' encoding="UTF8" ?&gt;
  -
  -&lt;!-- 
  -This file defines the XML format for ANT library descriptors.
  -Descriptors must especify a DOCTYPE of 
  -"http://jakarta.apache.org/ant/Antlib-V1_0.dtd"
  -as the SystemId for the document.
  ---&gt;
   
   &lt;!-- Root element for the Antlib descriptor.                 --&gt;
  -&lt;!ELEMENT antlib (task | type)* &gt;
  -&lt;!ATTLIST antlib
  -          version  CDATA #IMPLIED
  -&gt;
  +&lt;!ELEMENT antlib (role | <i>rolename</i>)* &gt;
   
  -&lt;!-- Declaration of tasks contained in the library.          --&gt;
  -&lt;!ELEMENT task EMPTY&gt;
  -&lt;!ATTLIST task 
  +&lt;!-- Declaration of roles contained in the library.          --&gt;
  +&lt;!ELEMENT role EMPTY&gt;
  +&lt;!ATTLIST role 
             name     CDATA #REQUIRED
             class    CDATA #REQUIRED
  +          proxy    CDATA #IMPLIED
   &gt;
   
   &lt;!-- Declaration of datatypes contained in the library       --&gt;
  -&lt;!ELEMENT type EMPTY&gt;
  -&lt;!ATTLIST type 
  +&lt;!ELEMENT <i>rolename</i> EMPTY&gt;
  +&lt;!ATTLIST <i>rolename</i> 
             name     CDATA #REQUIRED
             class    CDATA #REQUIRED
   &gt;
   
   </pre>
  +There are two predefined roles: <i><b>task</b></i> and <i><b>datatype</b></i>.
  +<p>
  +<h4>Role definition</h4>
  +The <b>name</b> of the role. This name is used when specifying 
  +elements for this role.
  +<p>
  +The <b>class</b> defining a role must be an interface containing a 
  +unique void method with only one argument whose type is the that of 
  +elements declared on the role.
  +<p>
  +The <b>proxy</b> defined in a role specifies a class that can be used 
  +to bridge between the type expected by the role and the type of 
  +elements declared for that role.
  +<h4>Element definition</h4>
  +Any element whose name is that of a role declares an element for that role.
  +<p>
  +The <b>name</b> defined the name of the element to use in the buildfile 
  +to specify the element being declared.
  +<p>
  +The <b>class</b> the class defining the element.
   <h3>Parameters</h3>
   <table border="1" cellpadding="2" cellspacing="0">
     <tr>
  @@ -78,7 +87,6 @@
   <p>Here is a sample <code>META-INF/antlib.xml</code>:</p>
   <pre>
   &lt;?xml version="1.0" encoding="UTF8" ?&gt;
  -&lt;!DOCTYPE antlib  SYSTEM "http://jakarta.apache.org/ant/Antlib-V1_0.dtd" &gt;
   
   &lt;antlib version="1.0" &gt;
     &lt;task name="case" class="org.apache.ant.contrib.Case" /&gt;
  
  
  
  1.2       +39 -8     jakarta-ant/proposal/sandbox/antlib/docs/manual/CoreTasks/antlib.html
  
  Index: antlib.html
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/sandbox/antlib/docs/manual/CoreTasks/antlib.html,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- antlib.html	27 Nov 2001 06:53:22 -0000	1.1
  +++ antlib.html	11 Feb 2002 03:39:00 -0000	1.2
  @@ -9,16 +9,38 @@
   
   <h2><a name="antlib">AntLib</a></h2>
   <h3>Description</h3>
  -<p>Defines and loads any tasks and datatypes contained in an ANT library.</p>
  +<p>Defines and loads elements contained in an ANT library.</p>
   <p>It also allows the aliasing of the names being defined in order to avoid 
   collisions and provides means to override definitions with the ones defined
   in the library.</p>
  -Ant libraries can be loaded in the current classloader, which is more efficient,
  +Ant libraries are associated with ClassLoaders identified by the
  +<tt>loaderid</tt> attribute. If no loader is specified a default loader
  +will be used. Ant libraries specifying the same loader are loaded by the
  +same ClassLoader as long as the libraries are defined on the same project.
  +Classloaders with the same ID in a subproject have the corresponding 
  +classloader in the parent project as their parent classloader.
  +<p>
  +Ant libraries can be loaded in the current classloader, 
  +which is more efficient,
   but requires the tasks to be in the path already (such as in the ant lib 
   directory) - set <tt>useCurrentClassloader</tt> to true to enable this.
   It is also possible to add more libraries to the path, such as any 
   libraries the task is dependent on. 
  -  
  +<p>
  +Ant libraries define objects of several types:
  +<ol>
  +<li> <b>Roles</b>: Define an interface to be implemented by elements
  +(usually tasks) that accept subelements of the specified role.
  +Roles may also define a proxy class which may be applied to an element
  +in order to make it compatible with the role.
  +</li>
  +<li> <b>Tasks</b>: define elements that belong to the predefined 
  +role "task".
  +<li> <b>Data types</b>: define elements that belong to the predefined role
  +"datatype".
  +<li> <b>Other role elements</b>: declare elements for other roles that 
  +have been previously defined.
  +</ol>  
   <h3>Parameters</h3>
   <table border="1" cellpadding="2" cellspacing="0">
     <tr>
  @@ -33,11 +55,13 @@
     </tr>
     <tr>
       <td valign="top">library</td>
  -    <td valign="top">The name of a library relative to ${ant.home}/lib.</td>
  +    <td valign="top">The name of a library relative to ${ant.home}/antlib.</td>
     </tr>
     <tr>
       <td valign="top">override</td>
  -    <td valign="top">Replace any existing definition with the same name. (&quot;true&quot;/&quot;false&quot;). When &quot;false&quot; already defined tasks
  +    <td valign="top">Replace any existing definition with the same name. 
  +    (&quot;true&quot;/&quot;false&quot;). 
  +    When &quot;false&quot; already defined tasks
            and datatytes take precedence over those in the library.
   	 Default is &quot;false&quot; when omitted.</td>
       <td align="center" valign="top">No</td>
  @@ -59,12 +83,20 @@
       </td>
       <td valign="top" align="center">No</td>
     </tr>  
  +  <tr>
  +    <td valign="top">loaderid</td>
  +    <td valign="top">The ID of the ClassLoader to use to load the classes
  +    defined in this library. If omitted a default per project ClassLoader 
  +    will be used.
  +    </td>
  +    <td valign="top" align="center">No</td>
  +  </tr>
   </table>
   <h3><a name="nested">Parameters specified as nested elements</a></h3>
   
   <h4>alias</h4>
   <p>Specifies the usage of a different name from that defined in the library
  -descriptor.</p>
  +descriptor. Applies only to element definitions (not role declarations).</p>
   <table border="1" cellpadding="2" cellspacing="0">
     <tr>
       <td valign="top"><b>Attribute</b></td>
  @@ -86,9 +118,8 @@
   descriptor. This is used to deal with name clashes </p>
   
   <h4>classpath</h4>
  -<h4>classpath</h4>
   
  -A classpath of extra libraries to import to support this task. 
  +A classpath of extra libraries to import to support this library. 
   
   <h4>classpathref</h4>
   A reference to an existing classpath. 
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/antlib/build.xml
  
  Index: build.xml
  ===================================================================
  <?xml version='1.0' ?>
  <project name="antlib" default="all">
    <property name='orig' location='../../..' />
    <property name='orig-build' location='${orig}/build' />
    <property name='orig-classes' location='${orig-build}/classes' />
    <property name='build' location='build' />
    <property name='dist' location='dist' />
    <property name='classes' location='${build}/classes' />
  
    <property name="debug" value="true" />
    <property name="deprecation" value="false" />
    <property name="optimize" value="true" />
    
    
    <target name='init'>
      <ant target='build' dir='${orig}' inheritAll='false' />
      <mkdir dir='${classes}' />
      <copy toDir='${classes}' preservelastmodified='true' >
        <fileset dir='${orig-classes}'>
          <include name='**' />
  	<exclude name='org/apache/tools/ant/Project.class' />
  	<exclude name='org/apache/tools/ant/TaskAdapter.class' />
  	<exclude name='org/apache/tools/ant/taskdefs/Ant.class' />
        </fileset>
      </copy>
    </target>
  
    <target name='all' depends='init, build' />
  
    <target name='fullbuild' depends='init, compile'>
      <ant target='internal_dist' dir='${orig}'>
        <property name="build.dir" value="${build}"/>
        <property name="dist.dir" value="${dist}"/>
      </ant>
    </target>
  
    <target name='build' depends='init, compile'>
      <ant target='dist-lite' dir='${orig}'>
        <property name="build.dir" value="${build}"/>
        <property name="dist.dir" value="${dist}"/>
      </ant>
    </target>
  
    <target name='compile'>
      <javac srcdir='src/main' destdir='${classes}'
             debug="${debug}"
             deprecation="${deprecation}"
             optimize="${optimize}">
        <include name='**/*.java'/>
      </javac>
    </target>
  
    <target name='clean'>
      <delete dir='${build}' />
    </target>
  
    <target name='cleanall' depends='clean'>
      <delete dir='${dist}' />
    </target>
  </project>
  
  
  1.1                  jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/Project.java
  
  Index: Project.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * 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:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.tools.ant;
  
  import java.io.File;
  import java.io.InputStream;
  import java.io.IOException;
  import java.util.Hashtable;
  import java.util.Vector;
  import java.util.Properties;
  import java.util.Enumeration;
  import java.util.Stack;
  import java.lang.reflect.Modifier;
  
  
  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; 
  
  /**
   * 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.
   * <p>
   * 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
   */
  
  public class Project {
  
      public final static int MSG_ERR = 0;
      public final static int MSG_WARN = 1;
      public final static int MSG_INFO = 2;
      public final static int MSG_VERBOSE = 3;
      public final static int MSG_DEBUG = 4;
  
      // private set of constants to represent the state
      // of a DFS of the Target dependencies
      private final static String VISITING = "VISITING";
      private final static String VISITED = "VISITED";
  
      private static String javaVersion;
  
      public final static String JAVA_1_0 = "1.0";
      public final static String JAVA_1_1 = "1.1";
      public final static String JAVA_1_2 = "1.2";
      public final static String JAVA_1_3 = "1.3";
      public final static String JAVA_1_4 = "1.4";
  
      public final static String TOKEN_START = FilterSet.DEFAULT_TOKEN_START;
      public final static String TOKEN_END = FilterSet.DEFAULT_TOKEN_END;
  
      private String name;
      private String description;
  
      private Hashtable properties = new Hashtable();
      private Hashtable userProperties = new Hashtable();
      private Hashtable references = new Hashtable();
      private String defaultTarget;
      //    private Hashtable dataClassDefinitions = new Hashtable();
      //    private Hashtable taskClassDefinitions = new Hashtable();
      private Hashtable createdTasks = new Hashtable();
      private Hashtable targets = new Hashtable();
      private FilterSet globalFilterSet = new FilterSet();
      private FilterSetCollection globalFilters = new FilterSetCollection(globalFilterSet);
      private File baseDir;
  
      private Vector listeners = new Vector();
  
      /** The Ant core classloader - may be null if using system loader */    
      private ClassLoader coreLoader = null;
  
      /** Records the latest task on a thread */ 
      private Hashtable threadTasks = new Hashtable();
  
      /** Store symbol tables */
      private SymbolTable symbols;
  
      static {
  
          // Determine the Java version by looking at available classes
          // java.lang.StrictMath was introduced in JDK 1.3
          // java.lang.ThreadLocal was introduced in JDK 1.2
          // java.lang.Void was introduced in JDK 1.1
          // Count up version until a NoClassDefFoundError ends the try
  
          try {
              javaVersion = JAVA_1_0;
              Class.forName("java.lang.Void");
              javaVersion = JAVA_1_1;
              Class.forName("java.lang.ThreadLocal");
              javaVersion = JAVA_1_2;
              Class.forName("java.lang.StrictMath");
              javaVersion = JAVA_1_3;
              Class.forName("java.lang.CharSequence");
              javaVersion = JAVA_1_4;
          } catch (ClassNotFoundException cnfe) {
              // swallow as we've hit the max class version that
              // we have
          }
      }
  
      private FileUtils fileUtils;
  
      /**
       * create a new ant project
       */
      public Project() {
          fileUtils = FileUtils.newFileUtils();
  	symbols = new SymbolTable();
  	symbols.setProject(this);
      }
      
      /**
       * create a new ant project that inherits from caler project
       * @param p the calling project
       */
      public Project(Project p) {
          fileUtils = FileUtils.newFileUtils();
  	symbols = new SymbolTable(p);
  	symbols.setProject(this);
      }
      
      /**
       * Initialise the project.
       *
       * This involves setting the default task definitions and loading the
       * system properties.
       */
      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);
  
          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();
  
              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); 
                  }
              }
          } 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();
  
              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");
          }
  
          setSystemProperties();
      }
  
      public void setCoreLoader(ClassLoader coreLoader) {
          this.coreLoader = coreLoader;
      }
      
      public ClassLoader getCoreLoader() {
          return coreLoader;
      }
      
      public void addBuildListener(BuildListener listener) {
          listeners.addElement(listener);
      }
  
      public void removeBuildListener(BuildListener listener) {
          listeners.removeElement(listener);
      }
  
      public Vector getBuildListeners() {
          return listeners;
      }
  
      /**
       * Get the symbols associated with this project.
       */
      public SymbolTable getSymbols() {
  	return symbols;
      }
  
      /**
       * 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 
       */
      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 
       */
      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 
       */
      public void log(Target target, String msg, int msgLevel) {
          fireMessageLogged(target, msg, msgLevel);
      }
  
    
      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
       */
      public void setProperty(String name, String value) {
          // command line properties take precedence
          if (null != userProperties.get(name)) {
              log("Override ignored for user property " + name, MSG_VERBOSE);
              return;
          }
  
          if (null != properties.get(name)) {
              log("Overriding previous definition of property " + name, 
                  MSG_VERBOSE);
          }
  
          log("Setting project property: " + name + " -> " +
               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
       */
      public void setNewProperty(String name, String value) {
          if (null != properties.get(name)) {
              log("Override ignored for property " + name, MSG_VERBOSE);
              return;
          }
          log("Setting project property: " + name + " -> " +
              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)
       */
      public void setUserProperty(String name, String value) {
          log("Setting ro project property: " + name + " -> " +
              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.
       */
      private void setPropertyInternal(String name, String value) {
          if (null != userProperties.get(name)) {
              return;
          }
          properties.put(name, value);
      }
  
      /**
       * 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;
          }
          String property = (String) properties.get(name);
          return property;
      }
  
      /**
       * 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.
       */
      public String replaceProperties(String value)
          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
       */
      public String getUserProperty(String name) {
          if (name == 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
       */
      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
       */
      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)
       */
      public void setDefaultTarget(String defaultTarget) {
          this.defaultTarget = defaultTarget;
      }
  
      /**
       * 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.
       */
      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
       */
      public void setName(String name) {
          setUserProperty("ant.project.name",  name);
          this.name = name;
      }
  
      /** get the project name
       * @return name string
       */
      public String getName() {
          return name;
      }
  
      /** 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
       */
      public String getDescription() {
          return description;
      }
  
      /** @deprecated */
      public void addFilter(String token, String value) {
          if (token == null) {
              return;
          }
          
          globalFilterSet.addFilter(new FilterSet.Filter(token, 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
       */
      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
       */
      public void setBaseDir(File baseDir) throws BuildException {
          baseDir = fileUtils.normalize(baseDir.getAbsolutePath());
          if (!baseDir.exists()) { 
              throw new BuildException("Basedir " + baseDir.getAbsolutePath() + " does not exist");
          }
          if (!baseDir.isDirectory()) { 
              throw new BuildException("Basedir " + baseDir.getAbsolutePath() + " is not a directory");
          }
          this.baseDir = baseDir;
          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
       */
      public File getBaseDir() {
          if (baseDir == null) {
              try {
                  setBasedir(".");
              } catch (BuildException ex) {
                  ex.printStackTrace();
              }
          }
          return baseDir;
      }
  
      /**
       * 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
       */
      public void setJavaVersionProperty() throws BuildException {
          setPropertyInternal("ant.java.version", javaVersion);
  
          // sanity check
          if (javaVersion == JAVA_1_0) {
              throw new BuildException("Ant cannot work on Java 1.0");
          }
  
          log("Detected Java version: " + javaVersion + " in: " + System.getProperty("java.home"), MSG_VERBOSE);
  
          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);
          }
      }
  
      /**
       * 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); 
      }
  
      /**
       * 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.
       */
      public void checkTaskClass(final Class taskClass) throws BuildException {
          if( !Task.class.isAssignableFrom(taskClass) ) {
              TaskAdapter.checkTaskClass(taskClass, this);
          }
      }
  
      /**
       * get the current task definition hashtable
       */
      public Hashtable getTaskDefinitions() {
          return symbols.getTaskDefinitions();
      }
  
      /**
       * 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);
      }
  
      /**
       * get the current task definition hashtable
       */
      public Hashtable getDataTypeDefinitions() {
          return symbols.getDataTypeDefinitions();
      }
  
      /**
       * This call expects to add a <em>new</em> 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.
       */
      public void addTarget(Target target) {
          String name = target.getName();
          if (targets.get(name) != null) {
              throw new BuildException("Duplicate target: `"+name+"'");
          }
          addOrReplaceTarget(name, target);
      }
  
      /**
       * This call expects to add a <em>new</em> 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.
       */
      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
       */
      public void addOrReplaceTarget(String targetName, Target target) {
          String msg = " +Target: " + targetName;
          log(msg, MSG_DEBUG);
          target.setProject(this);
          targets.put(targetName, 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
       */
      public Task createTask(String taskType) throws BuildException {
          Class c = symbols.get("task", taskType);
  
          if (c == 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;
              }
              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;
          } catch (Throwable t) {
              String msg = "Could not create task of type: "
                   + taskType + " due to " + t;
              throw new BuildException(msg, t);
          }
      }
  
      /**
       * Keep a record of all tasks that have been created so that they
       * can be invalidated if a taskdef overrides the definition.
       */
      private void addCreatedTask(String type, Task task) {
          synchronized (createdTasks) {
              Vector v = (Vector) createdTasks.get(type);
              if (v == null) {
                  v = new Vector();
                  createdTasks.put(type, v);
              }
              v.addElement(task);
          }
      }
  
      /**
       * Mark tasks as invalid which no longer are of the correct type
       * for a given taskname.
       */
      private void invalidateCreatedTasks(String type) {
          synchronized (createdTasks) {
              Vector v = (Vector) createdTasks.get(type);
              if (v != null) {
                  Enumeration enum = v.elements();
                  while (enum.hasMoreElements()) {
                      Task t = (Task) enum.nextElement();
                      t.markInvalid();
                  }
                  v.removeAllElements();
                  createdTasks.remove(type);
              }
          }
      }
  
      /**
       * 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
       */
      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);
          }
      }
  
      /**
       * 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
       */
      public void executeTargets(Vector targetNames) throws BuildException {
          Throwable error = null;
  
          for (int i = 0; i < targetNames.size(); i++) {
              executeTarget((String)targetNames.elementAt(i));
          }
      }
  
      public void demuxOutput(String line, boolean isError) {
          Task task = (Task)threadTasks.get(Thread.currentThread());
          if (task == null) {
              fireMessageLogged(this, line, isError ? MSG_ERR : MSG_INFO);
          }
          else {
              if (isError) {
                  task.handleErrorOutput(line);
              }
              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
       */
      public void executeTarget(String targetName) throws BuildException {
  
          // sanity check ourselves, if we've been asked to build nothing
          // then we should complain
  
          if (targetName == null) {
              String msg = "No target specified";
              throw new BuildException(msg);
          }
  
          // Sort the dependency tree, and run everything from the
          // beginning until we hit our targetName.
          // Sorting checks if all the targets (and dependencies)
          // exist, and if there is any cycle in the dependency
          // graph.
          Vector sortedTargets = topoSort(targetName, targets);
  
          int curidx = 0;
          Target curtarget;
  
          do {
              curtarget = (Target) sortedTargets.elementAt(curidx++);
              curtarget.performTasks();
          } while (!curtarget.getName().equals(targetName));
      }
  
      /**
       * Return the canonical form of fileName as an absolute path.
       *
       * <p>If fileName is a relative file name, resolve it relative to
       * rootDir.</p>
       *
       * @deprecated
       */
      public File resolveFile(String fileName, File rootDir) {
          return fileUtils.resolveFile(rootDir, fileName);
      }
  
      public File resolveFile(String fileName) {
          return fileUtils.resolveFile(baseDir, fileName);
      }
  
      /**
       * Translate a path into its native (platform specific) format. 
       * <p>
       * 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.
       *
       * @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 ) {
              return "";
          }
  
          StringBuffer path = new StringBuffer(to_process.length() + 50);
          PathTokenizer tokenizer = new PathTokenizer(to_process);
          while (tokenizer.hasMoreTokens()) {
              String pathComponent = tokenizer.nextToken();
              pathComponent = pathComponent.replace('/', File.separatorChar);
              pathComponent = pathComponent.replace('\\', File.separatorChar);
              if (path.length() != 0) {
                  path.append(File.pathSeparatorChar);
              }
              path.append(pathComponent);
          }
          
          return path.toString();
      }
  
      /**
       * Convienence method to copy a file from a source to a destination.
       * No filtering is performed.
       *
       * @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.
       *
       * @throws IOException
       *
       * @deprecated
       */
      public void copyFile(String sourceFile, String destFile, boolean filtering)
          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 
       *
       * @deprecated
       */
      public void copyFile(String sourceFile, String destFile, boolean filtering,
                           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 <code>destFile</code> file should be made equal
       * to the last modified time of <code>sourceFile</code>.
       *
       * @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);
      }
  
      /**
       * Convienence method to copy a file from a source to a destination.
       * No filtering is performed.
       *
       * @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.
       *
       * @throws IOException
       *
       * @deprecated
       */
      public void copyFile(File sourceFile, File destFile, boolean filtering)
          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 
       *
       * @deprecated
       */
      public void copyFile(File sourceFile, File destFile, boolean filtering,
                           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 <code>destFile</code> file should be made equal
       * to the last modified time of <code>sourceFile</code>.
       *
       * @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);
      }
  
      /**
       * Calls File.setLastModified(long time) in a Java 1.1 compatible way.
       *
       * @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);
              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.
       */
      public static boolean toBoolean(String s) {
          return (s.equalsIgnoreCase("on") ||
                  s.equalsIgnoreCase("true") ||
                  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.
       */
      public final Vector topoSort(String root, Hashtable targets)
          throws BuildException {
          Vector ret = new Vector();
          Hashtable state = new Hashtable();
          Stack visiting = new Stack();
  
          // We first run a DFS based sort using the root as the starting node.
          // This creates the minimum sequence of Targets to the root node.
          // We then do a sort on any remaining unVISITED targets.
          // This is unnecessary for doing our build, but it catches
          // circular dependencies or missing Targets on the entire
          // dependency tree, not just on the Targets that depend on the
          // 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());
              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);
              }
          }
          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.
      // - The Stack "visiting" contains a stack of target names that are
      // currently on the DFS stack. (NB: the target names in "visiting" are
      // exactly the target names in "state" that are in the VISITING state.)
      // 1. Set the current target to the VISITING state, and push it onto
      // the "visiting" stack.
      // 2. Throw a BuildException if any child of the current node is
      // in the VISITING state (implies there is a cycle.) It uses the
      // "visiting" Stack to construct the cycle.
      // 3. If any children have not been VISITED, tsort() the child.
      // 4. Add the current target to the Vector "ret" after the children
      //   have been visited. Move the current target to the VISITED state.
      //   "ret" now contains the sorted sequence of Targets upto the current
      //   Target.
  
      private final void tsort(String root, Hashtable targets,
                               Hashtable state, Stack visiting,
                               Vector ret)
          throws BuildException {
          state.put(root, VISITING);
          visiting.push(root);
  
          Target target = (Target)(targets.get(root));
  
          // Make sure we exist
          if (target == null) {
              StringBuffer sb = new StringBuffer("Target `");
              sb.append(root);
              sb.append("' does not exist in this project. ");
              visiting.pop();
              if (!visiting.empty()) {
                  String parent = (String)visiting.peek();
                  sb.append("It is used from target `");
                  sb.append(parent);
                  sb.append("'.");
              }
  
              throw new BuildException(new String(sb));
          }
  
          for (Enumeration en=target.getDependencies(); en.hasMoreElements();) {
              String cur = (String) en.nextElement();
              String m=(String)state.get(cur);
              if (m == null) {
                  // Not been visited
                  tsort(cur, targets, state, visiting, ret);
              }
              else if (m == VISITING) {
                  // Currently visiting this node, so have a cycle
                  throw makeCircularException(cur, visiting);
              }
          }
  
          String p = (String) visiting.pop();
          if (root != p) {
              throw new RuntimeException("Unexpected internal error: expected to pop "+root+" but got "+p);
          }
          state.put(root, VISITED);
          ret.addElement(target);
      }
  
      private static BuildException makeCircularException(String end, Stack stk) {
          StringBuffer sb = new StringBuffer("Circular dependency: ");
          sb.append(end);
          String c;
          do {
              c = (String)stk.pop();
              sb.append(" <- ");
              sb.append(c);
          } while(!c.equals(end));
          return new BuildException(new String(sb));
      }
  
      public void addReference(String name, Object value) {
          if (null != references.get(name)) {
              log("Overriding previous definition of reference to " + name, 
                  MSG_WARN);
          }
          log("Adding reference: " + name + " -> " + value, MSG_DEBUG);
          references.put(name,value);
      }
  
      public Hashtable getReferences() {
          return references;
      }
  
      /**
       * @return The object with the "id" key.
       */
      public Object getReference(String key) {
          return references.get(key);
      }
  
      /**
       * send build started event to the listeners
       */
      protected void fireBuildStarted() {
          BuildEvent event = new BuildEvent(this);
          for (int i = 0; i < listeners.size(); i++) {
              BuildListener listener = (BuildListener) listeners.elementAt(i);
              listener.buildStarted(event);
          }
      }
  
      /**
       * 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);
          event.setException(exception);
          for (int i = 0; i < listeners.size(); i++) {
              BuildListener listener = (BuildListener) listeners.elementAt(i);
              listener.buildFinished(event);
          }
      }
  
      
      /**
       * send target started event to the listeners
       */
      protected void fireTargetStarted(Target target) {
          BuildEvent event = new BuildEvent(target);
          for (int i = 0; i < listeners.size(); i++) {
              BuildListener listener = (BuildListener) listeners.elementAt(i);
              listener.targetStarted(event);
          }
      }
  
      /**
       * send build finished event to the listeners
       * @param exception exception which indicates failure if not null
       */
      protected void fireTargetFinished(Target target, Throwable exception) {
          BuildEvent event = new BuildEvent(target);
          event.setException(exception);
          for (int i = 0; i < listeners.size(); i++) {
              BuildListener listener = (BuildListener) listeners.elementAt(i);
              listener.targetFinished(event);
          }
      }
  
      protected void fireTaskStarted(Task task) {
          // register this as the current task on the current thread.
          threadTasks.put(Thread.currentThread(), task);
          BuildEvent event = new BuildEvent(task);
          for (int i = 0; i < listeners.size(); i++) {
              BuildListener listener = (BuildListener) listeners.elementAt(i);
              listener.taskStarted(event);
          }
      }
  
      protected void fireTaskFinished(Task task, Throwable exception) {
          threadTasks.remove(Thread.currentThread());
          System.out.flush();
          System.err.flush();
          BuildEvent event = new BuildEvent(task);
          event.setException(exception);
          for (int i = 0; i < listeners.size(); i++) {
              BuildListener listener = (BuildListener) listeners.elementAt(i);
              listener.taskFinished(event);
          }
      }
  
      private void fireMessageLoggedEvent(BuildEvent event, String message, int priority) {
          event.setMessage(message, priority);
          for (int i = 0; i < listeners.size(); i++) {
              BuildListener listener = (BuildListener) listeners.elementAt(i);
              listener.messageLogged(event);
          }
      }
  
      protected void fireMessageLogged(Project project, String message, int priority) {
          BuildEvent event = new BuildEvent(project);
          fireMessageLoggedEvent(event, message, priority);
      }
  
      protected void fireMessageLogged(Target target, String message, int priority) {
          BuildEvent event = new BuildEvent(target);
          fireMessageLoggedEvent(event, message, priority);
      }
  
      protected void fireMessageLogged(Task task, String message, int priority) {
          BuildEvent event = new BuildEvent(task);
          fireMessageLoggedEvent(event, message, priority);
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/RoleAdapter.java
  
  Index: RoleAdapter.java
  ===================================================================
  /*
   *  The Apache Software License, Version 1.1
   *
   *  Copyright (c) 1999 The Apache Software Foundation.  All rights
   *  reserved.
   *
   *  Redistribution and use in source and binary forms, with or without
   *  modification, are permitted provided that the following conditions
   *  are met:
   *
   *  1. Redistributions of source code must retain the above copyright
   *  notice, this list of conditions and the following disclaimer.
   *
   *  2. Redistributions in binary form must reproduce the above copyright
   *  notice, this list of conditions and the following disclaimer in
   *  the documentation and/or other materials provided with the
   *  distribution.
   *
   *  3. The end-user documentation included with the redistribution, if
   *  any, must include the following acknowlegement:
   *  "This product includes software developed by the
   *  Apache Software Foundation (http://www.apache.org/)."
   *  Alternately, this acknowlegement may appear in the software itself,
   *  if and wherever such third-party acknowlegements normally appear.
   *
   *  4. The names "The Jakarta Project", "Ant", and "Apache Software
   *  Foundation" must not be used to endorse or promote products derived
   *  from this software without prior written permission. For written
   *  permission, please contact apache@apache.org.
   *
   *  5. Products derived from this software may not be called "Apache"
   *  nor may "Apache" appear in their names without prior written
   *  permission of the Apache Group.
   *
   *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   *  DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   *  ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   *  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   *  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   *  SUCH DAMAGE.
   *  ====================================================================
   *
   *  This software consists of voluntary contributions made by many
   *  individuals on behalf of the Apache Software Foundation.  For more
   *  information on the Apache Software Foundation, please see
   *  <http://www.apache.org/>.
   */
  package org.apache.tools.ant;
  
  public interface RoleAdapter {
  
      /**
       * Set the object being adapted.
       * @param o the object being adapted
       */
      public void setProxy(Object o);
      
      /**
       * Get the object adapted by this class.
       * @return the object being adapted, if any.
       */
      public Object getProxy();
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/SymbolTable.java
  
  Index: SymbolTable.java
  ===================================================================
  /*
   *  The Apache Software License, Version 1.1
   *
   *  Copyright (c) 1999 The Apache Software Foundation.  All rights
   *  reserved.
   *
   *  Redistribution and use in source and binary forms, with or without
   *  modification, are permitted provided that the following conditions
   *  are met:
   *
   *  1. Redistributions of source code must retain the above copyright
   *  notice, this list of conditions and the following disclaimer.
   *
   *  2. Redistributions in binary form must reproduce the above copyright
   *  notice, this list of conditions and the following disclaimer in
   *  the documentation and/or other materials provided with the
   *  distribution.
   *
   *  3. The end-user documentation included with the redistribution, if
   *  any, must include the following acknowlegement:
   *  "This product includes software developed by the
   *  Apache Software Foundation (http://www.apache.org/)."
   *  Alternately, this acknowlegement may appear in the software itself,
   *  if and wherever such third-party acknowlegements normally appear.
   *
   *  4. The names "The Jakarta Project", "Ant", and "Apache Software
   *  Foundation" must not be used to endorse or promote products derived
   *  from this software without prior written permission. For written
   *  permission, please contact apache@apache.org.
   *
   *  5. Products derived from this software may not be called "Apache"
   *  nor may "Apache" appear in their names without prior written
   *  permission of the Apache Group.
   *
   *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   *  DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   *  ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   *  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   *  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   *  SUCH DAMAGE.
   *  ====================================================================
   *
   *  This software consists of voluntary contributions made by many
   *  individuals on behalf of the Apache Software Foundation.  For more
   *  information on the Apache Software Foundation, please see
   *  <http://www.apache.org/>.
   */
  package org.apache.tools.ant;
  
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  import java.lang.reflect.Modifier;
  import java.util.*;
  
  import org.apache.tools.ant.types.Path;
  
  public class SymbolTable {
  
      /** Parent symbol table */
      private SymbolTable parentTable;
      
      /** Project associated with this symbol table */
      private Project project;
  
      /** The table of roles available to this Project */
      private Hashtable roles = new Hashtable();
  
      /** The table of loaders active on this Project */
      private Hashtable loaders = new Hashtable();
  
      /**
       * Table of per role definitions.
       */
      private Hashtable defs = new Hashtable();
  
      /**
       * Parameters for checking adapters.
       */
      private static final Class[] CHECK_ADAPTER_PARAMS = 
  	new Class[]{Class.class, Project.class};
  
      /**
       * Create a top level Symbol table.
       */
      public SymbolTable() {
      }
  
      /**
       * Create a symbol table inheriting the definitions
       * from that defined in the calling Project.
       * @param p the calling project
       */
      public SymbolTable(Project p) {
  	parentTable = p.getSymbols();
      }
  
      /**
       * Set the project associated with this symbol table.
       * @param p the project for this symbol table
       */
      public void setProject(Project p) {
  	this.project = p;
      }
  
      /**
       * Find all the roles supported by a Class
       * on this symbol table.
       * @param clz the class to analyze
       * @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()]);
      }
  
      /**
       * Collect the roles for the class
       * @param clz the class being inspected
       * @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);
      }
      
      /**
       * Get the Role definition
       * @param role the name of the role
       * @return the method used to support objects on this role
       */
      public Role getRole(String role) {
  	Role r = (Role) roles.get(role);
  	if (r == null && parentTable != null) {
  	    return parentTable.getRole(role);
  	}
  	return r;
      }
  
      /**
       * Add a new role definition to this project.
       * @param role the name of the role
       * @param rclz the interface used to specify support for the role.
       * @param aclz the optional adapter class
       * @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;
      }
  
      /**
       * 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.
       * @param name the name of the element for this Class
       * @param clz the Class being declared
       * @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 {
                  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;
      }
  
      /**
       * Checks a class, whether it is suitable for serving in ANT.
       * @throws BuildException and logs as Project.MSG_ERR for
       * conditions, that will cause execution to fail.
       */
      void checkClass(final Class clz) 
  	throws BuildException {
          if(!Modifier.isPublic(clz.getModifiers())) {
              final String message = clz + " is not public";
              project.log(message, Project.MSG_ERR);
              throw new BuildException(message);
          }
          if(Modifier.isAbstract(clz.getModifiers())) {
              final String message = clz + " is abstract";
              project.log(message, Project.MSG_ERR);
              throw new BuildException(message);
          }
          try {
              // 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]);
              } catch (NoSuchMethodException nse) {
                  clz.getConstructor(new Class[] {Project.class});
              }
          } catch(NoSuchMethodException e) {
              final String message = 
  		"No valid public constructor in " + clz;
              project.log(message, Project.MSG_ERR);
              throw new BuildException(message);
          }
      }
  
      /**
       * Get the class in the role identified with the element name.
       * @param role the role to look into.
       * @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");
      }
  
      /**
       * Get a Hashtable that is usable for manipulating Datatypes,
       * @return a Hashtable that delegates to the Symbol table.
       */
      public Hashtable getDataTypeDefinitions() {
  	return new SymbolHashtable("datatype");
      }
  
      /**
       * Hashtable implementation that delegates
       * 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);
  	}
      }
  
      /**
       * 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);
  	}
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/TaskAdapter.java
  
  Index: TaskAdapter.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.tools.ant;
  
  import java.lang.reflect.Method;
  
  
  
  /**
   *  Use introspection to "adapt" an arbitrary Bean ( not extending Task, but with similar
   *  patterns).
   *
   * @author costin@dnt.ro
   * @author j_a_fernandez@yahoo.com
   */
  public class TaskAdapter extends Task implements RoleAdapter {
  
      Object proxy;
      
      /**
       * Checks a class, whether it is suitable to be adapted by TaskAdapter.
       *
       * Checks conditions only, which are additionally required for a tasks
       * adapted by TaskAdapter. Thus, this method should be called by
       * {@link Project#checkTaskClass}.
       *
       * Throws a BuildException and logs as Project.MSG_ERR for
       * conditions, that will cause the task execution to fail.
       * 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);
      }
  
      /**
       * Checks a class, whether it is suitable to be adapted.
       *
       * Checks conditions only, which are additionally required for a tasks
       * adapted by TaskAdapter. 
       *
       * Throws a BuildException and logs as Project.MSG_ERR for
       * conditions, that will cause the task execution to fail.
       * Logs other suspicious conditions with Project.MSG_WARN.
       */
      public static void checkClass(final Class taskClass, final Project project) {
          // don't have to check for interface, since then
          // taskClass would be abstract too.
          try {
              final Method executeM = taskClass.getMethod( "execute", null );
              // don't have to check for public, since
              // getMethod finds public method only.
              // don't have to check for abstract, since then
              // taskClass would be abstract too.
              if(!Void.TYPE.equals(executeM.getReturnType())) {
                  final String message = "return type of execute() should be void but was \""+executeM.getReturnType()+"\" in " + taskClass;
                  project.log(message, Project.MSG_WARN);
              }
          } catch(NoSuchMethodException e) {
              final String message = "No public execute() in " + taskClass;
              project.log(message, Project.MSG_ERR);
              throw new BuildException(message);
          }
      }
      
      /**
       * Do the execution.
       */
      public void execute() throws BuildException {
          Method setProjectM = null;
          try {
              Class c = proxy.getClass();
              setProjectM = 
                  c.getMethod( "setProject", new Class[] {Project.class});
              if(setProjectM != null) {
                  setProjectM.invoke(proxy, new Object[] {project});
              }
          } catch (NoSuchMethodException e) {
              // 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(), 
                  Project.MSG_ERR);
              throw new BuildException( ex );
          }
  
  
          Method executeM=null;
          try {
              Class c=proxy.getClass();
              executeM=c.getMethod( "execute", new Class[0] );
              if( executeM == null ) {
                  log("No public execute() in " + proxy.getClass(), Project.MSG_ERR);
                  throw new BuildException("No public execute() in " + proxy.getClass());
              }
              executeM.invoke(proxy, null);
              return; 
          } catch( Exception ex ) {
              log("Error in " + proxy.getClass(), Project.MSG_ERR);
              throw new BuildException( ex );
          }
  
      }
      
      /**
       * Set the target object class
       */
      public void setProxy(Object o) {
          this.proxy = o;
      }
  
      public Object getProxy() {
          return this.proxy ;
      }
  
  }
  
  
  

--
To unsubscribe, e-mail:   <mailto:ant-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:ant-dev-help@jakarta.apache.org>


Mime
View raw message