You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by co...@apache.org on 2002/03/06 17:36:12 UTC

cvs commit: jakarta-ant/src/main/org/apache/tools/ant ProjectHelper.java

costin      02/03/06 08:36:12

  Modified:    src/main/org/apache/tools/ant ProjectHelper.java
  Log:
  Since nobody objects, this is the 'project helper modularization' commit.
  
  The default is ProjectHelperImpl, which have the original ( SAX1 ) implementation.
  
  Most of the XML-related code has been removed, the only remaining problem
  is the AttributeList that is passed to the introspection helper ( which is
  XML and SAX1 specific ). It's easy to pass this by using a AttributeListImpl,
  and hopefully the introspection helper will be made less SAX1-specific someday.
  
  Revision  Changes    Path
  1.77      +140 -1045 jakarta-ant/src/main/org/apache/tools/ant/ProjectHelper.java
  
  Index: ProjectHelper.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/ProjectHelper.java,v
  retrieving revision 1.76
  retrieving revision 1.77
  diff -u -r1.76 -r1.77
  --- ProjectHelper.java	28 Feb 2002 15:23:38 -0000	1.76
  +++ ProjectHelper.java	6 Mar 2002 16:36:12 -0000	1.77
  @@ -58,59 +58,40 @@
   import java.io.FileInputStream;
   import java.io.FileNotFoundException;
   import java.io.IOException;
  +import java.io.InputStream;
  +import java.io.BufferedReader;
  +import java.io.InputStreamReader;
   import java.util.Hashtable;
   import java.util.Vector;
   import java.util.Enumeration;
   import java.util.Locale;
  -import org.xml.sax.Locator;
  -import org.xml.sax.InputSource;
  -import org.xml.sax.HandlerBase;
  -import org.xml.sax.SAXParseException;
  -import org.xml.sax.SAXException;
  -import org.xml.sax.DocumentHandler;
  -import org.xml.sax.AttributeList;
  -import org.xml.sax.helpers.XMLReaderAdapter;
  +import java.lang.reflect.InvocationTargetException;
  +import java.lang.reflect.Method;
   
  -import javax.xml.parsers.SAXParserFactory;
  -import javax.xml.parsers.SAXParser;
  -import javax.xml.parsers.ParserConfigurationException;
  +import org.xml.sax.AttributeList;
  +import org.apache.tools.ant.helper.ProjectHelperImpl;
   
   /**
  - * Configures a project (complete with targets and tasks) based on
  - * an XML build file.
  + * Configures a Project (complete with Targets and Tasks) based on
  + * a XML build file. It'll rely on a plugin to do the actual processing
  + * of the xml file.
  + *
  + * This class also provide static wrappers for common introspection.
  + *
  + * All helper plugins must provide backward compatiblity with the
  + * original ant patterns, unless a different behavior is explicitely
  + * specified. For example, if namespace is used on the <project> tag
  + * the helper can expect the entire build file to be namespace-enabled.
  + * Namespaces or helper-specific tags can provide meta-information to
  + * the helper, allowing it to use new ( or different policies ).
  + *
  + * However, if no namespace is used the behavior should be exactly
  + * identical with the default helper.
    *
    * @author duncan@x180.com
    */
  -
   public class ProjectHelper {
   
  -    /** 
  -     * Parser factory to use to create parsers.
  -     * @see #getParserFactory
  -     */
  -    private static SAXParserFactory parserFactory = null;
  -
  -    /**
  -     * SAX 1 style parser used to parse the given file. This may 
  -     * in fact be a SAX 2 XMLReader wrapped in an XMLReaderAdapter.
  -     */
  -    private org.xml.sax.Parser parser;
  -    
  -    /** The project to configure. */
  -    private Project project;
  -    /** The configuration file to parse. */
  -    private File buildFile;
  -    /** 
  -     * Parent directory of the build file. Used for resolving entities
  -     * and setting the project's base directory.
  -     */
  -    private File buildFileParent;
  -    /** 
  -     * Locator for the configuration file parser. 
  -     * Used for giving locations of errors etc.
  -     */
  -    private Locator locator;
  -
       /**
        * Configures the project with the contents of the specified XML file.
        * 
  @@ -122,1020 +103,166 @@
        *                           be read
        */
       public static void configureProject(Project project, File buildFile) throws BuildException {
  -        new ProjectHelper(project, buildFile).parse();
  +        ProjectHelper helper=ProjectHelper.getProjectHelper();
  +        helper.parse(project, buildFile);
       }
   
  -    /**
  -     * Constructs a new helper for the specified project and XML file.
  -     * 
  -     * @param project The project for the resulting ProjectHelper to configure. 
  -     *                Must not be <code>null</code>.
  -     * @param buildFile An XML file giving the project's configuration.
  -     *                  Must not be <code>null</code>.
  -     */
  -    private ProjectHelper(Project project, File buildFile) {
  -        this.project = project;
  -        this.buildFile = new File(buildFile.getAbsolutePath());
  -        buildFileParent = new File(this.buildFile.getParent());
  +    public ProjectHelper() {
       }
   
       /**
        * Parses the project file, configuring the project as it goes.
  -     * 
  +     *
  +     * @param project The project for the resulting ProjectHelper to configure. 
  +     *                Must not be <code>null</code>.
  +     * @param source The source for XML configuration. A helper must support
  +     *               at least File, for backward compatibility. Helpers may
  +     *               support URL, InputStream, etc or specialized types.
  +     *
  +     * @since Ant1.5
        * @exception BuildException if the configuration is invalid or cannot 
        *                           be read
        */
  -    private void parse() throws BuildException {
  -        FileInputStream inputStream = null;
  -        InputSource inputSource = null;
  -        
  -        try {
  -            SAXParser saxParser = getParserFactory().newSAXParser();
  -            try {
  -                parser = saxParser.getParser();
  -            } catch (SAXException exc) {
  -                parser = new XMLReaderAdapter(saxParser.getXMLReader());
  -            }
  -
  -            String uri = "file:" + buildFile.getAbsolutePath().replace('\\', '/');
  -            for (int index = uri.indexOf('#'); index != -1; index = uri.indexOf('#')) {
  -                uri = uri.substring(0, index) + "%23" + uri.substring(index+1);
  -            }
  -            
  -            inputStream = new FileInputStream(buildFile);
  -            inputSource = new InputSource(inputStream);
  -            inputSource.setSystemId(uri);
  -            project.log("parsing buildfile " + buildFile + " with URI = " + uri, Project.MSG_VERBOSE);
  -            HandlerBase hb = new RootHandler();
  -            parser.setDocumentHandler(hb);
  -            parser.setEntityResolver(hb);
  -            parser.setErrorHandler(hb);
  -            parser.setDTDHandler(hb);
  -            parser.parse(inputSource);
  -        }
  -        catch(ParserConfigurationException exc) {
  -            throw new BuildException("Parser has not been configured correctly", exc);
  -        }
  -        catch(SAXParseException exc) {
  -            Location location =
  -                new Location(buildFile.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(FileNotFoundException exc) {
  -            throw new BuildException(exc);
  -        }
  -        catch(IOException exc) {
  -            throw new BuildException("Error reading project file", exc);
  -        }
  -        finally {
  -            if (inputStream != null) {
  -                try {
  -                    inputStream.close();
  -                }
  -                catch (IOException ioe) {
  -                    // ignore this
  -                }
  -            }
  -        }
  +    public void parse(Project project, Object source) throws BuildException {
  +        throw new BuildException("ProjectHelper.parse() must be implemented in a helper plugin "
  +                                 + this.getClass().getName());
       }
   
  -    /**
  -     * The common superclass for all SAX event handlers used to parse
  -     * the configuration file. Each method just throws an exception, 
  -     * so subclasses should override what they can handle.
  -     *
  -     * Each type of XML element (task, target, etc.) in Ant has
  -     * a specific subclass.
  -     *
  -     * In the constructor, this class takes over the handling of SAX
  -     * events from the parent handler and returns
  -     * control back to the parent in the endElement method.
  -     */
  -    private class AbstractHandler extends HandlerBase {
  -        
  -        /** 
  -         * Previous handler for the document. 
  -         * When the next element is finished, control returns
  -         * to this handler.
  -         */
  -        protected DocumentHandler parentHandler;
  -        
  -        /**
  -         * Creates a handler and sets the parser to use it
  -         * for the current element.
  -         * 
  -         * @param parentHandler The handler which should be restored to the 
  -         *                      parser at the end of the element. 
  -         *                      Must not be <code>null</code>.
  -         */
  -        public AbstractHandler(DocumentHandler parentHandler) {
  -            this.parentHandler = parentHandler;
  +    /* -------------------- Helper discovery -------------------- */
  +    public static final String HELPER_PROPERTY =
  +        "org.apache.tools.ant.ProjectHelper";
  +    
  +    public static final String SERVICE_ID =
  +        "/META-INF/services/org.apache.tools.ant.ProjectHelper";
   
  -            // Start handling SAX events
  -            parser.setDocumentHandler(this);
  -        }
  +    
  +    /** Discover a project helper instance. Uses the same patterns
  +     *  as JAXP, commons-logging, etc: a system property, a JDK1.3
  +     *  service discovery, default.
  +     */
  +    public static ProjectHelper getProjectHelper()
  +        throws BuildException
  +    {
  +        // Identify the class loader we will be using. Ant may be
  +        // in a webapp or embeded in a different app
  +        ProjectHelper helper=null;
           
  -        /**
  -         * Handles the start of an element. This base implementation just
  -         * throws an exception.
  -         * 
  -         * @param tag The name of the element being started. 
  -         *            Will not be <code>null</code>.
  -         * @param attrs Attributes of the element being started.
  -         *              Will not be <code>null</code>.
  -         * 
  -         * @exception SAXParseException if this method is not overridden, or in
  -         *                              case of error in an overridden version
  -         */
  -        public void startElement(String tag, AttributeList attrs) throws SAXParseException {
  -            throw new SAXParseException("Unexpected element \"" + tag + "\"", locator);
  -        }
  -
  -        /**
  -         * Handles text within an element. This base implementation just
  -         * throws an exception.
  -         * 
  -         * @param buf A character array of the text within the element.
  -         *            Will not be <code>null</code>.
  -         * @param start The start element in the array.
  -         * @param count The number of characters to read from the array.
  -         * 
  -         * @exception SAXParseException if this method is not overridden, or in
  -         *                              case of error in an overridden version
  -         */
  -        public void characters(char[] buf, int start, int count) throws SAXParseException {
  -            String s = new String(buf, start, count).trim();
  -
  -            if (s.length() > 0) {
  -                throw new SAXParseException("Unexpected text \"" + s + "\"", locator);
  -            }
  -        }
  -
  -        /**
  -         * Called when this element and all elements nested into it have been
  -         * handled.
  -         */
  -        protected void finished() {}
  -
  -        /**
  -         * Handles the end of an element. Any required clean-up is performed
  -         * by the finished() method and then the original handler is restored to
  -         * the parser.
  -         * 
  -         * @param name The name of the element which is ending.
  -         *             Will not be <code>null</code>.
  -         * 
  -         * @exception SAXException in case of error (not thrown in 
  -         *                         this implementation)
  -         * 
  -         * @see #finished()
  -         */
  -        public void endElement(String name) throws SAXException {
  -
  -            finished();
  -            // Let parent resume handling SAX events
  -            parser.setDocumentHandler(parentHandler);
  +        // First, try the system property
  +        try {
  +            String helperClass = System.getProperty(HELPER_PROPERTY);
  +            if (helperClass != null) {
  +                helper = newHelper(helperClass);
  +            }
  +        } catch (SecurityException e) {
  +            // It's ok, we'll try next option
  +            ;
           }
  -    }
   
  -    /**
  -     * Handler for the root element. Its only child must be the "project" element.
  -     */
  -    private class RootHandler extends HandlerBase {
  -
  -        /**
  -         * Resolves file: URIs relative to the build file.
  -         * 
  -         * @param publicId The public identifer, or <code>null</code>
  -         *                 if none is available. Ignored in this 
  -         *                 implementation.
  -         * @param systemId The system identifier provided in the XML 
  -         *                 document. Will not be <code>null</code>.
  -         */
  -        public InputSource resolveEntity(String publicId,
  -                                         String systemId) {
  -        
  -            project.log("resolving systemId: " + systemId, Project.MSG_VERBOSE);
  -        
  -            if (systemId.startsWith("file:")) {
  -                String path = systemId.substring(5);
  -                int index = path.indexOf("file:");
  -                
  -                // we only have to handle these for backward compatibility
  -                // since they are in the FAQ.
  -                while (index != -1) {
  -                    path = path.substring(0, index) + path.substring(index + 5);
  -                    index = path.indexOf("file:");
  +        // A JDK1.3 'service' ( like in JAXP ). That will plug a helper
  +        // automatically if in CLASSPATH, with the right META-INF/services.
  +        if( helper==null ) {
  +            try {
  +                ClassLoader classLoader=getContextClassLoader();
  +                InputStream is=null;
  +                if (classLoader != null) {
  +                    is=classLoader.getResourceAsStream( SERVICE_ID );
                   }
  -                
  -                String entitySystemId = path;
  -                index = path.indexOf("%23");
  -                // convert these to #
  -                while (index != -1) {
  -                    path = path.substring(0, index) + "#" + path.substring(index + 3);
  -                    index = path.indexOf("%23");
  -                }
  -
  -                File file = new File(path);
  -                if (!file.isAbsolute()) {
  -                    file = new File(buildFileParent, path);
  +                if( is==null ) {
  +                    is=ClassLoader.getSystemResourceAsStream( SERVICE_ID );
                   }
                   
  -                try {
  -                    InputSource inputSource = new InputSource(new FileInputStream(file));
  -                    inputSource.setSystemId("file:" + entitySystemId);
  -                    return inputSource;
  -                } catch (FileNotFoundException fne) {
  -                    project.log(file.getAbsolutePath()+" could not be found", 
  -                                Project.MSG_WARN);
  -                }
  -            }
  -            // use default if not file or file not found
  -            return null;
  -        }
  -
  -        /**
  -         * Handles the start of a project element. A project handler is created
  -         * and initialised with the element name and attributes.
  -         * 
  -         * @param tag The name of the element being started. 
  -         *            Will not be <code>null</code>.
  -         * @param attrs Attributes of the element being started.
  -         *              Will not be <code>null</code>.
  -         * 
  -         * @exception SAXParseException if the tag given is not 
  -         *                              <code>"project"</code>
  -         */
  -        public void startElement(String tag, AttributeList attrs) throws SAXParseException {
  -            if (tag.equals("project")) {
  -                new ProjectHandler(this).init(tag, attrs);
  -            } else {
  -                throw new SAXParseException("Config file is not of expected XML type", locator);
  -            }
  -        }
  -
  -        /**
  -         * Sets the locator in the project helper for future reference.
  -         * 
  -         * @param locator The locator used by the parser.
  -         *                Will not be <code>null</code>.
  -         */
  -        public void setDocumentLocator(Locator locator) {
  -            ProjectHelper.this.locator = locator;
  -        }
  -    }
  -
  -    /**
  -     * Handler for the top level "project" element.
  -     */
  -    private class ProjectHandler extends AbstractHandler {
  -        
  -        /**
  -         * Constructor which just delegates to the superconstructor.
  -         * 
  -         * @param parentHandler The handler which should be restored to the 
  -         *                      parser at the end of the element. 
  -         *                      Must not be <code>null</code>.
  -         */
  -        public ProjectHandler(DocumentHandler parentHandler) {
  -            super(parentHandler);
  -        }
  -        
  -        /**
  -         * Initialisation routine called after handler creation
  -         * with the element name and attributes. The attributes which
  -         * this handler can deal with are: <code>"default"</code>,
  -         * <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
  -         * 
  -         * @param tag Name of the element which caused this handler
  -         *            to be created. Should not be <code>null</code>.
  -         *            Ignored in this implementation.
  -         * @param attrs Attributes of the element which caused this
  -         *              handler to be created. Must not be <code>null</code>.
  -         * 
  -         * @exception SAXParseException if an unexpected attribute is 
  -         *            encountered or if the <code>"default"</code> attribute
  -         *            is missing.
  -         */
  -        public void init(String tag, AttributeList attrs) throws SAXParseException {
  -            String def = null;
  -            String name = null;
  -            String id = null;
  -            String baseDir = null;
  -
  -            for (int i = 0; i < attrs.getLength(); i++) {
  -                String key = attrs.getName(i);
  -                String value = attrs.getValue(i);
  -
  -                if (key.equals("default")) {
  -                    def = value;
  -                } else if (key.equals("name")) {
  -                    name = value;
  -                } else if (key.equals("id")) {
  -                    id = value;
  -                } else if (key.equals("basedir")) {
  -                    baseDir = value;
  -                } else {
  -                    throw new SAXParseException("Unexpected attribute \"" + attrs.getName(i) + "\"", locator);
  -                }
  -            }
  -
  -            if (def == null) {
  -                throw new SAXParseException("The default attribute of project is required", 
  -                                            locator);
  -            }
  -            
  -
  -            project.setDefaultTarget(def);
  -
  -            if (name != null) {
  -                project.setName(name);
  -                project.addReference(name, project);
  -            }
  -
  -            if (id != null) {
  -              project.addReference(id, project);
  -            }
  -
  -            if (project.getProperty("basedir") != null) {
  -                project.setBasedir(project.getProperty("basedir"));
  -            } else {
  -                if (baseDir == null) {
  -                    project.setBasedir(buildFileParent.getAbsolutePath());
  -                } else {
  -                    // check whether the user has specified an absolute path
  -                    if ((new File(baseDir)).isAbsolute()) {
  -                        project.setBasedir(baseDir);
  -                    } else {
  -                        project.setBaseDir(project.resolveFile(baseDir, buildFileParent));
  +                if( is != null ) {
  +                    // This code is needed by EBCDIC and other strange systems.
  +                    // It's a fix for bugs reported in xerces
  +                    BufferedReader rd;
  +                    try {
  +                        rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
  +                    } catch (java.io.UnsupportedEncodingException e) {
  +                        rd = new BufferedReader(new InputStreamReader(is));
  +                    }
  +                    
  +                    String helperClassName = rd.readLine();
  +                    rd.close();
  +                    
  +                    if (helperClassName != null &&
  +                        ! "".equals(helperClassName)) {
  +                        
  +                        helper= newHelper( helperClassName );
                       }
                   }
  -            }
  -
  -        }
  -
  -        /**
  -         * Handles the start of a top-level element within the project. An
  -         * appropriate handler is created and initialised with the details
  -         * of the element.
  -         * 
  -         * @param tag The name of the element being started. 
  -         *            Will not be <code>null</code>.
  -         * @param attrs Attributes of the element being started.
  -         *              Will not be <code>null</code>.
  -         * 
  -         * @exception SAXParseException if the tag given is not 
  -         *            <code>"taskdef"</code>, <code>"typedef"</code>,
  -         *            <code>"property"</code>, <code>"target"</code>
  -         *            or a data type definition
  -         */
  -        public void startElement(String name, AttributeList attrs) throws SAXParseException {
  -            if (name.equals("taskdef")) {
  -                handleTaskdef(name, attrs);
  -            } else if (name.equals("typedef")) {
  -                handleTypedef(name, attrs);
  -            } else if (name.equals("property")) {
  -                handleProperty(name, attrs);
  -            } else if (name.equals("target")) {
  -                handleTarget(name, attrs);
  -            } else if (project.getDataTypeDefinitions().get(name) != null) {
  -                handleDataType(name, attrs);
  -            } else {
  -                throw new SAXParseException("Unexpected element \"" + name + "\"", locator);
  -            }
  -        }
  -        
  -        /**
  -         * Handles a task defintion element by creating a task handler
  -         * and initialising is with the details of the element.
  -         * 
  -         * @param tag The name of the element to be handled.
  -         *            Will not be <code>null</code>.
  -         * @param attrs Attributes of the element to be handled.
  -         *              Will not be <code>null</code>.
  -         * 
  -         * @exception SAXParseException if an error occurs when initialising 
  -         *                              the task handler
  -         *                          
  -         */
  -        private void handleTaskdef(String name, AttributeList attrs) throws SAXParseException {
  -            (new TaskHandler(this, null, null, null)).init(name, attrs);
  -        }
  -
  -        /**
  -         * Handles a type defintion element by creating a task handler
  -         * and initialising is with the details of the element.
  -         * 
  -         * @param tag The name of the element to be handled.
  -         *            Will not be <code>null</code>.
  -         * @param attrs Attributes of the element to be handled.
  -         *              Will not be <code>null</code>.
  -         * 
  -         * @exception SAXParseException if an error occurs initialising the 
  -         *                              handler
  -         */
  -        private void handleTypedef(String name, AttributeList attrs) throws SAXParseException {
  -            (new TaskHandler(this, null, null, null)).init(name, attrs);
  -        }
  -
  -        /**
  -         * Handles a property defintion element by creating a task handler
  -         * and initialising is with the details of the element.
  -         * 
  -         * @param tag The name of the element to be handled.
  -         *            Will not be <code>null</code>.
  -         * @param attrs Attributes of the element to be handled.
  -         *              Will not be <code>null</code>.
  -         * 
  -         * @exception SAXParseException if an error occurs initialising 
  -         *                              the handler
  -         */
  -        private void handleProperty(String name, AttributeList attrs) throws SAXParseException {
  -            (new TaskHandler(this, null, null, null)).init(name, attrs);
  -        }
  -
  -        /**
  -         * Handles a target defintion element by creating a target handler
  -         * and initialising is with the details of the element.
  -         * 
  -         * @param tag The name of the element to be handled.
  -         *            Will not be <code>null</code>.
  -         * @param attrs Attributes of the element to be handled.
  -         *              Will not be <code>null</code>.
  -         * 
  -         * @exception SAXParseException if an error occurs initialising 
  -         *                              the handler
  -         */
  -        private void handleTarget(String tag, AttributeList attrs) throws SAXParseException {
  -            new TargetHandler(this).init(tag, attrs);
  -        }
  -        /**
  -         * Handles a data type defintion element by creating a data type 
  -         * handler and initialising is with the details of the element.
  -         * 
  -         * @param tag The name of the element to be handled.
  -         *            Will not be <code>null</code>.
  -         * @param attrs Attributes of the element to be handled.
  -         *              Will not be <code>null</code>.
  -         * 
  -         * @exception SAXParseException if an error occurs initialising 
  -         *                              the handler
  -         */
  -        private void handleDataType(String name, AttributeList attrs) throws SAXParseException {
  -            new DataTypeHandler(this).init(name, attrs);
  -        }
  -
  -    }
  -
  -    /**
  -     * Handler for "target" elements.
  -     */
  -    private class TargetHandler extends AbstractHandler {
  -        private Target target;
  -
  -        /**
  -         * Constructor which just delegates to the superconstructor.
  -         * 
  -         * @param parentHandler The handler which should be restored to the 
  -         *                      parser at the end of the element. 
  -         *                      Must not be <code>null</code>.
  -         */
  -        public TargetHandler(DocumentHandler parentHandler) {
  -            super(parentHandler);
  -        }
  -
  -        /**
  -         * Initialisation routine called after handler creation
  -         * with the element name and attributes. The attributes which
  -         * this handler can deal with are: <code>"name"</code>,
  -         * <code>"depends"</code>, <code>"if"</code>,
  -         * <code>"unless"</code>, <code>"id"</code> and 
  -         * <code>"description"</code>.
  -         * 
  -         * @param tag Name of the element which caused this handler
  -         *            to be created. Should not be <code>null</code>.
  -         *            Ignored in this implementation.
  -         * @param attrs Attributes of the element which caused this
  -         *              handler to be created. Must not be <code>null</code>.
  -         * 
  -         * @exception SAXParseException if an unexpected attribute is encountered
  -         *            or if the <code>"name"</code> attribute is missing.
  -         */
  -        public void init(String tag, AttributeList attrs) throws SAXParseException {
  -            String name = null;
  -            String depends = "";
  -            String ifCond = null;
  -            String unlessCond = null;
  -            String id = null;
  -            String description = null;
  -
  -            for (int i = 0; i < attrs.getLength(); i++) {
  -                String key = attrs.getName(i);
  -                String value = attrs.getValue(i);
  -
  -                if (key.equals("name")) {
  -                    name = value;
  -                } else if (key.equals("depends")) {
  -                    depends = value;
  -                } else if (key.equals("if")) {
  -                    ifCond = value;
  -                } else if (key.equals("unless")) {
  -                    unlessCond = value;
  -                } else if (key.equals("id")) {
  -                    id = value;
  -                } else if (key.equals("description")) {
  -                    description = value;
  -                } else {
  -                    throw new SAXParseException("Unexpected attribute \"" + key + "\"", locator);
  -                }
  -            }
  -
  -            if (name == null) {
  -                throw new SAXParseException("target element appears without a name attribute", locator);
  -            }
  -
  -            target = new Target();
  -            target.setName(name);
  -            target.setIf(ifCond);
  -            target.setUnless(unlessCond);
  -            target.setDescription(description);
  -            project.addTarget(name, target);
  -
  -            if (id != null && !id.equals("")) {
  -                project.addReference(id, target);
  -            }
  -
  -            // take care of dependencies
  -
  -            if (depends.length() > 0) {
  -                target.setDepends(depends);
  +            } catch( Exception ex ) {
  +                ;
               }
           }
   
  -        /**
  -         * Handles the start of an element within a target.
  -         * 
  -         * @param tag The name of the element being started. 
  -         *            Will not be <code>null</code>.
  -         * @param attrs Attributes of the element being started.
  -         *              Will not be <code>null</code>.
  -         * 
  -         * @exception SAXParseException if an error occurs when initialising
  -         *                              the appropriate child handler
  -         */
  -        public void startElement(String name, AttributeList attrs) throws SAXParseException {
  -            if (project.getDataTypeDefinitions().get(name) != null) {
  -                new DataTypeHandler(this, target).init(name, attrs);
  -            } else {
  -                new TaskHandler(this, target, null, target).init(name, attrs);
  -            }
  +        if( helper!=null ) {
  +            return helper;
  +        } else {
  +            // Default
  +            return new ProjectHelperImpl();
           }
       }
   
  -    /**
  -     * Handler for all task elements.
  +    /** Create a new helper. It'll first try the thread class loader,
  +     *  then Class.forName() will load from the same loader that
  +     *  loaded this class.
        */
  -    private class TaskHandler extends AbstractHandler {
  -        /** Containing target, if any. */
  -        private Target target;
  -        /** 
  -         * Container for the task, if any. If target is 
  -         * non-<code>null</code>, this must be too.
  -         */
  -        private TaskContainer container;
  -        /**
  -         * Task created by this handler.
  -         */
  -        private Task task;
  -        /**
  -         * Wrapper for the parent element, if any. The wrapper for this 
  -         * element will be added to this wrapper as a child.
  -         */
  -        private RuntimeConfigurable parentWrapper;
  -        /**
  -         * Wrapper for this element which takes care of actually configuring
  -         * the element, if this element is contained within a target. 
  -         * Otherwise the configuration is performed with the configure method.
  -         * @see ProjectHelper#configure(Object,AttributeList,Project)
  -         */
  -        private RuntimeConfigurable wrapper = null;
  -        
  -        /**
  -         * Constructor.
  -         * 
  -         * @param parentHandler The handler which should be restored to the 
  -         *                      parser at the end of the element. 
  -         *                      Must not be <code>null</code>.
  -         * 
  -         * @param container     Container for the element. 
  -         *                      May be <code>null</code> if the target is 
  -         *                      <code>null</code> as well. If the
  -         *                      target is <code>null</code>, this parameter
  -         *                      is effectively ignored.
  -         * 
  -         * @param parentWrapper Wrapper for the parent element, if any.
  -         *                      May be <code>null</code>. If the
  -         *                      target is <code>null</code>, this parameter
  -         *                      is effectively ignored.
  -         * 
  -         * @param target        Target this element is part of.
  -         *                      May be <code>null</code>.
  -         */
  -        public TaskHandler(DocumentHandler parentHandler, TaskContainer container, RuntimeConfigurable parentWrapper, Target target) {
  -            super(parentHandler);
  -            this.container = container;
  -            this.parentWrapper = parentWrapper;
  -            this.target = target;
  -        }
  -
  -        /**
  -         * Initialisation routine called after handler creation
  -         * with the element name and attributes. This configures
  -         * the element with its attributes and sets it up with
  -         * its parent container (if any). Nested elements are then
  -         * added later as the parser encounters them.
  -         * 
  -         * @param tag Name of the element which caused this handler
  -         *            to be created. Must not be <code>null</code>.
  -         *            
  -         * @param attrs Attributes of the element which caused this
  -         *              handler to be created. Must not be <code>null</code>.
  -         * 
  -         * @exception SAXParseException in case of error (not thrown in
  -         *                              this implementation)
  -         */
  -        public void init(String tag, AttributeList attrs) throws SAXParseException {
  -            try {
  -                task = project.createTask(tag);
  -            } catch (BuildException e) {
  -                // swallow here, will be thrown again in 
  -                // UnknownElement.maybeConfigure if the problem persists.
  -            }
  -
  -            if (task == null) {
  -                task = new UnknownElement(tag);
  -                task.setProject(project);
  -                task.setTaskType(tag);
  -                task.setTaskName(tag);
  -            }
  -
  -            task.setLocation(new Location(buildFile.toString(), locator.getLineNumber(), locator.getColumnNumber()));
  -            configureId(task, attrs);
  -
  -            // Top level tasks don't have associated targets
  -            if (target != null) {
  -                task.setOwningTarget(target);
  -                container.addTask(task);
  -                task.init();
  -                wrapper = task.getRuntimeConfigurableWrapper();
  -                wrapper.setAttributes(attrs);
  -                if (parentWrapper != null) {
  -                    parentWrapper.addChild(wrapper);
  -                }
  -            } else {
  -                task.init();
  -                configure(task, attrs, project);
  -            }
  -        }
  -
  -        /**
  -         * Executes the task if it is a top-level one.
  -         */
  -        protected void finished() {
  -            if (task != null && target == null) {
  -                task.execute();
  -            }
  -        }
  -
  -        /**
  -         * Adds text to the task, using the wrapper if one is
  -         * available (in other words if the task is within a target) 
  -         * or using addText otherwise.
  -         * 
  -         * @param buf A character array of the text within the element.
  -         *            Will not be <code>null</code>.
  -         * @param start The start element in the array.
  -         * @param count The number of characters to read from the array.
  -         * 
  -         * @exception SAXParseException if the element doesn't support text
  -         * 
  -         * @see ProjectHelper#addText(Project,Object,char[],int,int)
  -         */
  -        public void characters(char[] buf, int start, int count) throws SAXParseException {
  -            if (wrapper == null) {
  +    private static ProjectHelper newHelper(String helperClass)
  +        throws BuildException
  +    {
  +        ClassLoader classLoader = getContextClassLoader();
  +        try {
  +            Class clazz = null;
  +            if (classLoader != null) {
                   try {
  -                    addText(project, task, buf, start, count);
  -                } catch (BuildException exc) {
  -                    throw new SAXParseException(exc.getMessage(), locator, exc);
  +                    clazz = classLoader.loadClass(helperClass);
  +                } catch( ClassNotFoundException ex ) {
  +                    // try next method
                   }
  -            } else {
  -                wrapper.addText(buf, start, count);
  -            }
  -        }
  -        
  -        /**
  -         * Handles the start of an element within a target. Task containers
  -         * will always use another task handler, and all other tasks
  -         * will always use a nested element handler.
  -         * 
  -         * @param tag The name of the element being started. 
  -         *            Will not be <code>null</code>.
  -         * @param attrs Attributes of the element being started.
  -         *              Will not be <code>null</code>.
  -         * 
  -         * @exception SAXParseException if an error occurs when initialising
  -         *                              the appropriate child handler
  -         */
  -        public void startElement(String name, AttributeList attrs) throws SAXParseException {
  -            if (task instanceof TaskContainer) {
  -                // task can contain other tasks - no other nested elements possible
  -                new TaskHandler(this, (TaskContainer)task, wrapper, target).init(name, attrs);
               }
  -            else {
  -                new NestedElementHandler(this, task, wrapper, target).init(name, attrs);
  +            if( clazz==null ) {
  +                clazz = Class.forName(helperClass);
               }
  +            return ((ProjectHelper) clazz.newInstance());
  +        } catch (Exception e) {
  +            throw new BuildException(e);
           }
       }
   
       /**
  -     * Handler for all nested properties.
  +     *  JDK1.1 compatible access to the context class loader.
  +     *  Cut&paste from Jaxp.
        */
  -    private class NestedElementHandler extends AbstractHandler {
  -        /** Parent object (task/data type/etc). */
  -        private Object parent;
  -        /** The nested element itself. */
  -        private Object child;
  -        /**
  -         * Wrapper for the parent element, if any. The wrapper for this 
  -         * element will be added to this wrapper as a child.
  -         */
  -        private RuntimeConfigurable parentWrapper;
  -        /**
  -         * Wrapper for this element which takes care of actually configuring
  -         * the element, if a parent wrapper is provided.
  -         * Otherwise the configuration is performed with the configure method.
  -         * @see ProjectHelper#configure(Object,AttributeList,Project)
  -         */
  -        private RuntimeConfigurable childWrapper = null;
  -        /** Target this element is part of, if any. */
  -        private Target target;
  -
  -        /**
  -         * Constructor.
  -         * 
  -         * @param parentHandler The handler which should be restored to the 
  -         *                      parser at the end of the element. 
  -         *                      Must not be <code>null</code>.
  -         * 
  -         * @param parent        Parent of this element (task/data type/etc).
  -         *                      Must not be <code>null</code>.
  -         * 
  -         * @param parentWrapper Wrapper for the parent element, if any.
  -         *                      May be <code>null</code>.
  -         * 
  -         * @param target        Target this element is part of.
  -         *                      May be <code>null</code>.
  -         */
  -        public NestedElementHandler(DocumentHandler parentHandler, 
  -                                    Object parent,
  -                                    RuntimeConfigurable parentWrapper,
  -                                    Target target) {
  -            super(parentHandler);
  -
  -            if (parent instanceof TaskAdapter) {
  -                this.parent = ((TaskAdapter) parent).getProxy();
  -            } else {
  -                this.parent = parent;
  -            }
  -            this.parentWrapper = parentWrapper;
  -            this.target = target;
  -        }
  -
  -        /**
  -         * Initialisation routine called after handler creation
  -         * with the element name and attributes. This configures
  -         * the element with its attributes and sets it up with
  -         * its parent container (if any). Nested elements are then
  -         * added later as the parser encounters them.
  -         * 
  -         * @param tag Name of the element which caused this handler
  -         *            to be created. Must not be <code>null</code>.
  -         *            
  -         * @param attrs Attributes of the element which caused this
  -         *              handler to be created. Must not be <code>null</code>.
  -         * 
  -         * @exception SAXParseException in case of error, such as a 
  -         *            BuildException being thrown during configuration.
  -         */
  -        public void init(String propType, AttributeList attrs) throws SAXParseException {
  -            Class parentClass = parent.getClass();
  -            IntrospectionHelper ih = 
  -                IntrospectionHelper.getHelper(parentClass);
  -
  -            try {
  -                String elementName = propType.toLowerCase(Locale.US);
  -                if (parent instanceof UnknownElement) {
  -                    UnknownElement uc = new UnknownElement(elementName);
  -                    uc.setProject(project);
  -                    ((UnknownElement) parent).addChild(uc);
  -                    child = uc;
  -                } else {
  -                    child = ih.createElement(project, parent, elementName);
  -                }
  -
  -                configureId(child, attrs);
  -
  -                if (parentWrapper != null) {
  -                    childWrapper = new RuntimeConfigurable(child, propType);
  -                    childWrapper.setAttributes(attrs);
  -                    parentWrapper.addChild(childWrapper);
  -                } else {
  -                    configure(child, attrs, project);
  -                    ih.storeElement(project, parent, child, elementName);
  -                }
  -            } catch (BuildException exc) {
  -                throw new SAXParseException(exc.getMessage(), locator, exc);
  -            }
  +    public static ClassLoader getContextClassLoader()
  +        throws BuildException
  +    {
  +        // Are we running on a JDK 1.2 or later system?
  +        Method method = null;
  +        try {
  +            method = Thread.class.getMethod("getContextClassLoader", null);
  +        } catch (NoSuchMethodException e) {
  +            // we are running on JDK 1.1
  +            return null; 
           }
   
  -        /**
  -         * Adds text to the element, using the wrapper if one is
  -         * available or using addText otherwise.
  -         * 
  -         * @param buf A character array of the text within the element.
  -         *            Will not be <code>null</code>.
  -         * @param start The start element in the array.
  -         * @param count The number of characters to read from the array.
  -         * 
  -         * @exception SAXParseException if the element doesn't support text
  -         * 
  -         * @see ProjectHelper#addText(Project,Object,char[],int,int)
  -         */
  -        public void characters(char[] buf, int start, int count) throws SAXParseException {
  -            if (parentWrapper == null) {
  -                try {
  -                    addText(project, child, buf, start, count);
  -                } catch (BuildException exc) {
  -                    throw new SAXParseException(exc.getMessage(), locator, exc);
  -                }
  -            } else {
  -                childWrapper.addText(buf, start, count);
  -            }
  +        // Get the thread context class loader (if there is one)
  +        ClassLoader classLoader = null;
  +        try {
  +            classLoader = (ClassLoader)
  +                method.invoke(Thread.currentThread(), null);
  +        } catch (IllegalAccessException e) {
  +            throw new BuildException
  +                ("Unexpected IllegalAccessException", e);
  +        } catch (InvocationTargetException e) {
  +            throw new BuildException
  +                ("Unexpected InvocationTargetException", e);
           }
   
  -        /**
  -         * Handles the start of an element within this one. Task containers
  -         * will always use a task handler, and all other elements
  -         * will always use another nested element handler.
  -         * 
  -         * @param tag The name of the element being started. 
  -         *            Will not be <code>null</code>.
  -         * @param attrs Attributes of the element being started.
  -         *              Will not be <code>null</code>.
  -         * 
  -         * @exception SAXParseException if an error occurs when initialising
  -         *                              the appropriate child handler
  -         */
  -        public void startElement(String name, AttributeList attrs) throws SAXParseException {
  -            if (child instanceof TaskContainer) {
  -                // taskcontainer nested element can contain other tasks - no other 
  -                // nested elements possible
  -                new TaskHandler(this, (TaskContainer)child, childWrapper, target).init(name, attrs);
  -            }
  -            else {
  -                new NestedElementHandler(this, child, childWrapper, target).init(name, attrs);
  -            }
  -        }
  +        // Return the selected class loader
  +        return (classLoader);
       }
   
  -    /**
  -     * Handler for all data types directly subordinate to project or target.
  -     */
  -    private class DataTypeHandler extends AbstractHandler {
  -        /** Parent target, if any. */
  -        private Target target;
  -        /** The element being configured. */
  -        private Object element;
  -        /** Wrapper for this element, if it's part of a target. */
  -        private RuntimeConfigurable wrapper = null;
  -        
  -        /**
  -         * Constructor with no target specified.
  -         * 
  -         * @param parentHandler The handler which should be restored to the 
  -         *                      parser at the end of the element. 
  -         *                      Must not be <code>null</code>.
  -         */
  -        public DataTypeHandler(DocumentHandler parentHandler) {
  -            this(parentHandler, null);
  -        }
  -
  -        /**
  -         * Constructor with a target specified.
  -         * 
  -         * @param parentHandler The handler which should be restored to the 
  -         *                      parser at the end of the element. 
  -         *                      Must not be <code>null</code>.
  -         * 
  -         * @param target The parent target of this element.
  -         *               May be <code>null</code>.
  -         */
  -        public DataTypeHandler(DocumentHandler parentHandler, Target target) {
  -            super(parentHandler);
  -            this.target = target;
  -        }
  -
  -        /**
  -         * Initialisation routine called after handler creation
  -         * with the element name and attributes. This configures
  -         * the element with its attributes and sets it up with
  -         * its parent container (if any). Nested elements are then
  -         * added later as the parser encounters them.
  -         * 
  -         * @param tag Name of the element which caused this handler
  -         *            to be created. Must not be <code>null</code>.
  -         *            
  -         * @param attrs Attributes of the element which caused this
  -         *              handler to be created. Must not be <code>null</code>.
  -         * 
  -         * @exception SAXParseException in case of error, such as a 
  -         *            BuildException being thrown during configuration.
  -         */
  -        public void init(String propType, AttributeList attrs) throws SAXParseException {
  -            try {
  -                element = project.createDataType(propType);
  -                if (element == null) {
  -                    throw new BuildException("Unknown data type "+propType);
  -                }
  -                
  -                if (target != null) {
  -                    wrapper = new RuntimeConfigurable(element, propType);
  -                    wrapper.setAttributes(attrs);
  -                    target.addDataType(wrapper);
  -                } else {
  -                    configure(element, attrs, project);
  -                    configureId(element, attrs);
  -                }
  -            } catch (BuildException exc) {
  -                throw new SAXParseException(exc.getMessage(), locator, exc);
  -            }
  -        }
  -
  -        // XXX: (Jon Skeet) Any reason why this doesn't use the wrapper
  -        // if one is available, whereas NestedElementHandler.characters does?
  -        /**
  -         * Adds text to the element.
  -         * 
  -         * @param buf A character array of the text within the element.
  -         *            Will not be <code>null</code>.
  -         * @param start The start element in the array.
  -         * @param count The number of characters to read from the array.
  -         * 
  -         * @exception SAXParseException if the element doesn't support text
  -         * 
  -         * @see ProjectHelper#addText(Project,Object,char[],int,int)
  -         */
  -        public void characters(char[] buf, int start, int count) throws SAXParseException {
  -            try {
  -                addText(project, element, buf, start, count);
  -            } catch (BuildException exc) {
  -                throw new SAXParseException(exc.getMessage(), locator, exc);
  -            }
  -        }
  -
  -        /**
  -         * Handles the start of an element within this one.
  -         * This will always use a nested element handler.
  -         * 
  -         * @param tag The name of the element being started. 
  -         *            Will not be <code>null</code>.
  -         * @param attrs Attributes of the element being started.
  -         *              Will not be <code>null</code>.
  -         * 
  -         * @exception SAXParseException if an error occurs when initialising
  -         *                              the child handler
  -         */
  -        public void startElement(String name, AttributeList attrs) throws SAXParseException {
  -            new NestedElementHandler(this, element, wrapper, target).init(name, attrs);
  -        }
  -    }
  +    // -------------------- Static utils, used by most helpers -------------------- 
   
       /**
        * Configures an object using an introspection handler.
  @@ -1357,38 +484,6 @@
   
           if (prev < value.length()) {
               fragments.addElement(value.substring(prev));
  -        }
  -    }
  -
  -    /**
  -     * Returns the parser factory to use. Only one parser
  -     * factory is ever created by this method (multi-threading 
  -     * issues aside) and is then cached for future use.
  -     * 
  -     * @return a SAXParserFactory to use within this class
  -     */
  -    private static SAXParserFactory getParserFactory() {
  -        if (parserFactory == null) {
  -            parserFactory = SAXParserFactory.newInstance();
  -        }
  -
  -        return parserFactory;
  -    }
  -
  -    /**
  -     * Scans an attribute list for the <code>id</code> attribute and 
  -     * stores a reference to the target object in the project if an
  -     * id is found.
  -     * <p>
  -     * This method was moved out of the configure method to allow
  -     * it to be executed at parse time.
  -     * 
  -     * @see #configure(Object,AttributeList,Project)
  -     */
  -    private void configureId(Object target, AttributeList attr) {
  -        String id = attr.getValue("id");
  -        if (id != null) {
  -            project.addReference(id, target);
           }
       }
   }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>