diff --git a/bootstrap.bat b/bootstrap.bat index 53be8e055..d2a70b7b0 100755 --- a/bootstrap.bat +++ b/bootstrap.bat @@ -17,7 +17,7 @@ if "" == "%JAVAC%" set JAVAC=%JAVA_HOME%\bin\javac echo. echo ... Bootstrapping Ant Distribution -set CLASSPATH=src\main;classes;lib\xml.jar +set CLASSPATH=src\main;classes;%CLASSPATH% if exist %JAVA_HOME%\lib\tools.jar set CLASSPATH=%CLASSPATH%;%JAVA_HOME%\lib\tools.jar echo JAVA_HOME=%JAVA_HOME% @@ -40,7 +40,6 @@ echo. echo ... Copying Required Files copy %TOOLS%\ant\taskdefs\*.properties classes\org\apache\tools\ant\taskdefs -copy %TOOLS%\ant\*.properties classes\org\apache\tools\ant echo. echo ... Building Ant Distribution diff --git a/bootstrap.sh b/bootstrap.sh index 0ea973ee7..1e70ebcc6 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -5,7 +5,7 @@ fi SRCDIR=src/main/org/apache/tools CLASSDIR=classes CLASSPATH=${CLASSPATH}:${JAVA_HOME}/lib/classes.zip:${JAVA_HOME}/lib/tools.jar -CLASSPATH=${CLASSPATH}:lib/xml.jar:src/main:${CLASSDIR} +CLASSPATH=${CLASSPATH}:src/main:${CLASSDIR} mkdir -p ${CLASSDIR} @@ -17,7 +17,6 @@ javac -d ${CLASSDIR} ${SRCDIR}/ant/*.java javac -d ${CLASSDIR} ${SRCDIR}/ant/taskdefs/*.java cp src/main/org/apache/tools/ant/taskdefs/defaults.properties ${CLASSDIR}/org/apache/tools/ant/taskdefs -cp src/main/org/apache/tools/ant/parser.properties ${CLASSDIR}/org/apache/tools/ant java org.apache.tools.ant.Main main java org.apache.tools.ant.Main clean diff --git a/build.bat b/build.bat index ebc5543db..614280239 100755 --- a/build.bat +++ b/build.bat @@ -1,3 +1,3 @@ @echo off REM convience bat file to build with -java -classpath "%CLASSPATH%;lib\ant.jar;lib\xml.jar" org.apache.tools.ant.Main %1 %2 %3 %4 %5 +java -classpath "%CLASSPATH%;lib\ant.jar" org.apache.tools.ant.Main %1 %2 %3 %4 %5 diff --git a/build.sh b/build.sh index 8b92bd3e8..8a6212b42 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,6 @@ #!/bin/sh -ADDL_CLASSPATH=./lib/ant.jar:./lib/xml.jar +ADDL_CLASSPATH=./lib/ant.jar if [ "$CLASSPATH" != "" ] ; then CLASSPATH=$CLASSPATH:$ADDL_CLASSPATH diff --git a/build.xml b/build.xml index e5c29bd88..f77d06f33 100644 --- a/build.xml +++ b/build.xml @@ -21,7 +21,7 @@ - + diff --git a/src/main/org/apache/tools/ant/ApacheParser.java b/src/main/org/apache/tools/ant/ApacheParser.java deleted file mode 100644 index 39d0dc67c..000000000 --- a/src/main/org/apache/tools/ant/ApacheParser.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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", "Tomcat", 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 - * . - */ - -package org.apache.tools.ant; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.lang.reflect.Method; -import org.w3c.dom.Document; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -/** - * Implementation of Parser using Apache Xerces-J. - * - * @author pier@apache.org - */ -public class ApacheParser extends Parser { - - Class DOMParser = null; - Method parse; - Method getDocument; - - /** - * Parse the specified file and return a DOM Document. - */ - public Document parse(File buildFile) - throws SAXException, IOException { - try { - if (DOMParser == null) { - DOMParser = Class.forName("org.apache.xerces.parsers.DOMParser"); - parse = DOMParser.getMethod("parse", new Class[]{String.class}); - getDocument = DOMParser.getMethod("getDocument", new Class[]{}); - } - - Object p=DOMParser.newInstance(); - URL url=new URL("file","",buildFile.getAbsolutePath()); - parse.invoke(p, new Object[]{url.toExternalForm()}); - return(org.w3c.dom.Document)getDocument.invoke(p, new Object[]{}); - } catch (Exception e) { - if (e instanceof IOException) throw (IOException)e; - if (e instanceof SAXException) throw (SAXException)e; - throw new IOException(e.toString()); - } - } -} diff --git a/src/main/org/apache/tools/ant/BuildException.java b/src/main/org/apache/tools/ant/BuildException.java index feebdf9f9..aa04cc609 100644 --- a/src/main/org/apache/tools/ant/BuildException.java +++ b/src/main/org/apache/tools/ant/BuildException.java @@ -1,7 +1,7 @@ /* * The Apache Software License, Version 1.1 * - * Copyright (c) 1999 The Apache Software Foundation. All rights + * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -9,7 +9,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in @@ -17,15 +17,15 @@ * distribution. * * 3. The end-user documentation included with the redistribution, if - * any, must include the following acknowlegement: - * "This product includes software developed by the + * any, must include the following acknowlegement: + * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products derived - * from this software without prior written permission. For written + * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" @@ -50,7 +50,7 @@ * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . - */ + */ package org.apache.tools.ant; @@ -65,10 +65,13 @@ public class BuildException extends RuntimeException { /** Exception that might have caused this one. */ private Exception cause; + /** Location in the build file where the exception occured */ + private Location location = Location.UNKNOWN_LOCATION; + /** * Constructs a build exception with no descriptive information. */ - + public BuildException() { super(); } @@ -77,7 +80,7 @@ public class BuildException extends RuntimeException { * Constructs an exception with the given descriptive message. * @param msg Description of or information about the exception. */ - + public BuildException(String msg) { super(msg); } @@ -93,14 +96,60 @@ public class BuildException extends RuntimeException { super(msg); this.cause = cause; } - + + /** + * Constructs an exception with the given message and exception as + * a root cause and a location in a file. + * @param msg Description of or information about the exception. + * @param cause Exception that might have cause this one. + * @param location Location in the project file where the error occured. + */ + + public BuildException(String msg, Exception cause, Location location) { + this(msg, cause); + this.location = location; + } + /** * Constructs an exception with the given exception as a root cause. * @param cause Exception that might have caused this one. */ - + public BuildException(Exception cause) { super(cause.toString()); this.cause = cause; } + + /** + * Constructs an exception with the given descriptive message and a location + * in a file. + * @param msg Description of or information about the exception. + * @param location Location in the project file where the error occured. + */ + + public BuildException(String msg, Location location) { + super(msg); + this.location = location; + } + + /** + * Returns the nested exception. + */ + public Exception getException() { + return cause; + } + + /** + * Returns the location of the error and the error message. + */ + public String toString() { + return location.toString() + getMessage(); + } + + /** + * Sets the file location where the error occured. + */ + public void setLocation(Location location) { + this.location = location; + } } diff --git a/src/main/org/apache/tools/ant/Main.java b/src/main/org/apache/tools/ant/Main.java index 55e39b0b3..42706bfda 100644 --- a/src/main/org/apache/tools/ant/Main.java +++ b/src/main/org/apache/tools/ant/Main.java @@ -141,7 +141,7 @@ public class Main { /* Interestingly enough, we get to here when a user * uses -Dname=value. However, in some cases, the JDK - * goes ahead * and parses this out to args + * goes ahead * and parses this out to args * {"-Dname", "value"} * so instead of parsing on "=", we just make the "-D" * characters go away and skip one argument forward. @@ -189,7 +189,7 @@ public class Main { // ok, so if we've made it here, let's run the damn build allready runBuild(); - + return; } @@ -216,15 +216,23 @@ public class Main { project.setUserProperty(arg, value); } project.setUserProperty( "ant.file" , buildFile.getAbsolutePath() ); - + // first use the ProjectHelper to create the project object // from the given build file. try { + try { + Class.forName("javax.xml.parsers.SAXParserFactory"); + } catch (ClassNotFoundException cnfe) { + throw new BuildException(cnfe); + } ProjectHelper.configureProject(project, buildFile); } catch (BuildException be) { - String msg = "BUILD CONFIG ERROR: "; - System.out.println(msg + be.getMessage()); - be.printStackTrace(); + System.out.println("\nBUILD CONFIG ERROR\n"); + if (be.getException() == null) { + System.out.println(be.toString()); + } else { + be.getException().printStackTrace(); + } System.exit(1); } @@ -240,8 +248,8 @@ public class Main { project.executeTarget((String) en.nextElement()); } } catch (BuildException be) { - String msg = "BUILD FATAL ERROR: "; - System.out.println(msg + be.getMessage()); + String msg = "\nBUILD FATAL ERROR\n\n"; + System.out.println(msg + be.toString()); if (msgOutputLevel > Project.MSG_INFO) { be.printStackTrace(); } diff --git a/src/main/org/apache/tools/ant/Parser.java b/src/main/org/apache/tools/ant/Parser.java deleted file mode 100644 index b25fbcd48..000000000 --- a/src/main/org/apache/tools/ant/Parser.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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", "Tomcat", 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 - * . - */ - -package org.apache.tools.ant; - -import java.io.File; -import java.io.InputStream; -import java.io.IOException; -import java.util.Properties; -import org.w3c.dom.Document; -import org.xml.sax.SAXException; - -/** - * Dummy parser abstraction class for ANT to be used until the Java API for - * XML Parsing are released. - * - * @author pier@apache.org - */ -public abstract class Parser { - // The properties file to be loaded - private static String properties="org/apache/tools/ant/parser.properties"; - - /** - * Create a working instance of a parser - */ - public static Parser getParser(Project project) - throws BuildException { - InputStream in=project.getClass().getResourceAsStream("parser.properties"); - if (in==null) throw new BuildException("Cannot find properties file"); - - String name; - try { - Properties prop=new Properties(); - prop.load(in); - name=prop.getProperty("parser"); - if (name==null) throw new BuildException("Parser name not found"); - } catch(IOException e) { - throw new BuildException("Cannot load properties file"); - } - try { - return((Parser)Class.forName(name).newInstance()); - } catch (ClassNotFoundException e) { - throw new BuildException("Class "+name+" cannot be found"); - } catch (InstantiationException e) { - throw new BuildException("Class "+name+" cannot be instantiated"); - } catch (IllegalAccessException e) { - throw new BuildException("Class "+name+" cannot be accessed"); - } catch (ClassCastException e) { - throw new BuildException("Class "+name+" doesn't extend Parser"); - } - } - - /** - * Parse the specified file and return a DOM Document. - */ - public abstract Document parse(File f) - throws SAXException, IOException; -} - - diff --git a/src/main/org/apache/tools/ant/ProjectHelper.java b/src/main/org/apache/tools/ant/ProjectHelper.java index 37dc264e3..6192ee897 100644 --- a/src/main/org/apache/tools/ant/ProjectHelper.java +++ b/src/main/org/apache/tools/ant/ProjectHelper.java @@ -55,13 +55,13 @@ package org.apache.tools.ant; import java.beans.*; -import java.io.File; -import java.io.IOException; +import java.io.*; import java.lang.reflect.*; import java.util.*; -import org.xml.sax.SAXException; +import org.xml.sax.*; import org.w3c.dom.*; import org.apache.tools.ant.taskdefs.*; +import javax.xml.parsers.*; /** * Configures a Project (complete with Targets and Tasks) based on @@ -72,228 +72,332 @@ import org.apache.tools.ant.taskdefs.*; public class ProjectHelper { - public static void configureProject(Project project, File buildFile) - throws BuildException - { + private static SAXParserFactory parserFactory = null; - // XXX - // need to get rid of the DOM layer and use SAX + private org.xml.sax.Parser parser; + private Project project; + private File buildFile; + private Locator locator; - Document doc; + /** + * Configures the Project with the contents of the specified XML file. + */ + public static void configureProject(Project project, File buildFile) throws BuildException { + new ProjectHelper(project, buildFile).parse(); + } + + /** + * Constructs a new Ant parser for the specified XML file. + */ + private ProjectHelper(Project project, File buildFile) { + this.project = project; + this.buildFile = buildFile; + } + /** + * Parses the project file. + */ + private void parse() throws BuildException { try { - doc=Parser.getParser(project).parse(buildFile); - } catch (IOException ioe) { - String msg = "Can't open config file: " + buildFile + - " due to: " + ioe; - throw new BuildException(msg); - } catch (SAXException se) { - String msg = "Can't open config file: " + buildFile + - " due to: " + se; - throw new BuildException(msg); + parser = getParserFactory().newSAXParser().getParser(); + parser.setDocumentHandler(new RootHandler()); + parser.parse(new InputSource(new FileReader(buildFile))); + } + 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()); + throw new BuildException(exc.getMessage(), exc.getException(), location); + } + catch(SAXException exc) { + throw new BuildException(exc.getMessage(), exc.getException()); } + catch(FileNotFoundException exc) { + throw new BuildException("File \"" + buildFile.toString() + "\" not found"); + } + catch(IOException exc) { + throw new BuildException("Error reading project file", exc); + } + } - Element root = doc.getDocumentElement(); + /** + * The common superclass for all sax event handlers in Ant. Basically + * throws an exception in each method, so subclasses should override + * what they can handle. + * + * Each type of xml element (task, target, etc) in ant will + * have its own subclass of AbstractHandler. + * + * 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 { + protected DocumentHandler parentHandler; - // sanity check, make sure that we have the right element - // as we aren't validating the input + public AbstractHandler(DocumentHandler parentHandler) { + this.parentHandler = parentHandler; - if (!root.getTagName().equals("project")) { - String msg = "Config file is not of expected XML type"; - throw new BuildException(msg); + // Start handling SAX events + parser.setDocumentHandler(this); + } + + public void startElement(String tag, AttributeList attrs) throws SAXParseException { + throw new SAXParseException("Unexpected element \"" + tag + "\"", locator); } - project.setDefaultTarget(root.getAttribute("default")); + public void characters(char[] buf, int start, int end) throws SAXParseException { + String s = new String(buf, start, end).trim(); - String name = root.getAttribute("name"); - project.setName(name); - if (name != null) project.addReference(name, project); + if (s.length() > 0) { + throw new SAXParseException("Unexpected text \"" + s + "\"", locator); + } + } - String id = root.getAttribute("id"); - if (id != null) project.addReference(id, project); + public void endElement(String name) throws SAXException { - String baseDir = project.getProperty("basedir"); - if (baseDir == null) { - baseDir = root.getAttribute("basedir"); - if (baseDir.equals("")) { - // Using clunky JDK1.1 methods here - baseDir = new File(buildFile.getAbsolutePath()).getParent(); + // Let parent resume handling SAX events + parser.setDocumentHandler(parentHandler); + } + } + + /** + * Handler for the root element. It's only child must be the "project" element. + */ + private class RootHandler extends HandlerBase { + 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); } } - project.setBasedir(baseDir); - // set up any properties that may be in the config file + public void setDocumentLocator(Locator locator) { + ProjectHelper.this.locator = locator; + } + } + + /** + * Handler for the top level "project" element. + */ + private class ProjectHandler extends AbstractHandler { + public ProjectHandler(DocumentHandler parentHandler) { + super(parentHandler); + } + + public void init(String tag, AttributeList attrs) throws SAXParseException { + String def = null; + String name = null; + String id = null; + String baseDir = new File(buildFile.getAbsolutePath()).getParent(); + + 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); + } + } + + project.setDefaultTarget(def); - // configureProperties(project, root); + project.setName(name); + if (name != null) project.addReference(name, project); - // set up any task defs that may be in the config file + if (id != null) project.addReference(id, project); - // configureTaskDefs(project, root); + if (project.getProperty("basedir") != null) { + project.setBasedir(project.getProperty("basedir")); + } else { + project.setBasedir(baseDir); + } - // set up the taskdefs, properties, and targets into the project - configureProject(project, root); + } + + public void startElement(String name, AttributeList attrs) throws SAXParseException { + if (name.equals("taskdef")) { + handleTaskdef(name, attrs); + } else if (name.equals("property")) { + handleProperty(name, attrs); + } else if (name.equals("target")) { + handleTarget(name, attrs); + } else { + throw new SAXParseException("Unexpected element \"" + name + "\"", locator); + } + } + + private void handleTaskdef(String name, AttributeList attrs) throws SAXParseException { + new TaskHandler(this, null).init(name, attrs); + } + + private void handleProperty(String name, AttributeList attrs) throws SAXParseException { + new TaskHandler(this, null).init(name, attrs); + } + + private void handleTarget(String tag, AttributeList attrs) throws SAXParseException { + new TargetHandler(this).init(tag, attrs); + } } - private static void configureProject(Project project, Element root) - throws BuildException - { - // configure taskdefs - NodeList list = root.getElementsByTagName("taskdef"); - for (int i = 0; i < list.getLength(); i++) { - Task taskdef = new Taskdef(); - configure(project, taskdef, (Element)list.item(i)); - taskdef.setProject(project); - taskdef.init(); - } - - // configure properties - list = root.getElementsByTagName("property"); - for (int i = 0; i < list.getLength(); i++) { - Task property = new Property(); - configure(project, property, (Element)list.item(i)); - property.setProject(project); - property.init(); - } - - // configure targets - list = root.getElementsByTagName("target"); - for (int i = 0; i < list.getLength(); i++) { - Element element = (Element)list.item(i); - String targetName = element.getAttribute("name"); - String targetDep = element.getAttribute("depends"); - String targetCond = element.getAttribute("if"); - String targetId = element.getAttribute("id"); - - // all targets must have a name - if (targetName.equals("")) { - String msg = "target element appears without a name attribute"; - throw new BuildException(msg); + /** + * Handler for "target" elements. + */ + private class TargetHandler extends AbstractHandler { + private Target target; + + public TargetHandler(DocumentHandler parentHandler) { + super(parentHandler); + } + + public void init(String tag, AttributeList attrs) throws SAXParseException { + String name = null; + String depends = ""; + String cond = null; + String id = 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")) { + cond = value; + } else if (key.equals("id")) { + id = value; + } else { + throw new SAXParseException("Unexpected attribute \"" + key + "\"", locator); + } } - Target target = new Target(); - target.setName(targetName); - target.setCondition(targetCond); - project.addTarget(targetName, target); + if (name == null) { + throw new SAXParseException("target element appears without a name attribute", locator); + } - if (targetId != null && !targetId.equals("")) - project.addReference(targetId,target); + target = new Target(); + target.setName(name); + target.setCondition(cond); + project.addTarget(name, target); + + if (id != null && !id.equals("")) + project.addReference(id, target); // take care of dependencies - if (targetDep.length() > 0) { - StringTokenizer tok = - new StringTokenizer(targetDep, ",", false); + if (depends.length() > 0) { + StringTokenizer tok = + new StringTokenizer(depends, ",", false); while (tok.hasMoreTokens()) { target.addDependency(tok.nextToken().trim()); } } + } - // populate target with tasks - - configureTasks(project, target, element); + public void startElement(String name, AttributeList attrs) throws SAXParseException { + new TaskHandler(this, target).init(name, attrs); } } - private static void configureTasks(Project project, - Target target, - Element targetElement) - throws BuildException - { - NodeList list = targetElement.getChildNodes(); - for (int i = 0; i < list.getLength(); i++) { - Node node = list.item(i); - - // right now, all we are interested in is element nodes - // not quite sure what to do with others except drop 'em - - if (node.getNodeType() == Node.ELEMENT_NODE) { - Element element = (Element)node; - String taskType = element.getTagName(); + /** + * Handler for all task elements. + */ + private class TaskHandler extends AbstractHandler { + private Target target; + private Task task; - // XXX - // put in some sanity checking + public TaskHandler(DocumentHandler parentHandler, Target target) { + super(parentHandler); - Task task = project.createTask(taskType); + this.target = target; + } - // get the attributes of this element and reflect them - // into the task + public void init(String tag, AttributeList attrs) throws SAXParseException { + task = project.createTask(tag); + configure(task, attrs); + task.setLocation(new Location(buildFile.toString(), locator.getLineNumber(), locator.getColumnNumber())); + task.init(); - configure(project, task, element); - task.init(); + // Top level tasks don't have associated targets + if (target != null) { task.setTarget(target); target.addTask(task); + } + } - processNestedProperties(project, task, element); + public void characters(char[] buf, int start, int end) throws SAXParseException { + String text = new String(buf, start, end).trim(); + if (text.length() == 0) return; + + try { + Method addProp = task.getClass().getMethod("addText", new Class[]{String.class}); + Object child = addProp.invoke(task, new Object[] {text}); + } catch(NoSuchMethodException exc) { + throw new SAXParseException(task.getClass() + " does not support nested text elements", locator); + } catch(InvocationTargetException exc) { + throw new SAXParseException("Error invoking \"addText\" method", locator, exc); + } catch(IllegalAccessException exc) { + throw new SAXParseException("Unable to access \"addText\" method", locator, exc); } } + + public void startElement(String name, AttributeList attrs) throws SAXParseException { + new NestedPropertyHandler(this, task).init(name, attrs); + } } - private static void processNestedProperties(Project project, - Object target, - Element targetElement) - throws BuildException - { - Class targetClass = target.getClass(); - NodeList list = targetElement.getChildNodes(); - - for (int i = 0; i < list.getLength(); i++) { - Node node = list.item(i); - - // right now, all we are interested in is element nodes - // not quite sure what to do with others except drop 'em - - if (node.getNodeType() == Node.TEXT_NODE) { - String text = ((Text)node).getData(); - try { - Method addProp = targetClass.getMethod( - "addText", new Class[]{"".getClass()}); - Object child = addProp.invoke(target, new Object[] {text}); - } catch (NoSuchMethodException nsme) { - if (text.trim().length() > 0) - throw new BuildException(targetClass + - " does not support nested text elements"); - } catch (InvocationTargetException ite) { - throw new BuildException(ite.getMessage()); - } catch (IllegalAccessException iae) { - throw new BuildException(iae.getMessage()); - } - } + /** + * Handler for all nested properties. + */ + private class NestedPropertyHandler extends AbstractHandler { + private DocumentHandler parentHandler; - if (node.getNodeType() == Node.ELEMENT_NODE) { - Element element = (Element)node; - String propType = element.getTagName(); - String methodName = "create" + - Character.toUpperCase(propType.charAt(0)) + - propType.substring(1); - - try { - Method addProp = - targetClass.getMethod(methodName, new Class[]{}); - Object child = addProp.invoke(target, new Object[] {}); - - configure(project, child, element); - - processNestedProperties(project, child, element); - } catch (NoSuchMethodException nsme) { - throw new BuildException(targetClass + - " does not support nested " + propType + " properties"); - } catch (InvocationTargetException ite) { - throw new BuildException(ite.getMessage()); - } catch (IllegalAccessException iae) { - throw new BuildException(iae.getMessage()); - } + private Object target; + private Object child; + + public NestedPropertyHandler(DocumentHandler parentHandler, Object target) { + super(parentHandler); + this.target = target; + } + + public void init(String propType, AttributeList attrs) throws SAXParseException { + Class targetClass = target.getClass(); + + String methodName = "create" + Character.toUpperCase(propType.charAt(0)) + propType.substring(1); + + try { + Method addProp = targetClass.getMethod(methodName, new Class[]{}); + child = addProp.invoke(target, new Object[] {}); + configure(child, attrs); + } catch(NoSuchMethodException exc) { + throw new SAXParseException(targetClass + " does not support nested " + propType + " properties", locator); + } catch(InvocationTargetException exc) { + throw new SAXParseException(exc.getMessage(), locator); + } catch(IllegalAccessException exc) { + throw new SAXParseException(exc.getMessage(), locator); } } - } - private static void configure(Project project, - Object target, - Element element) - throws BuildException - { - NamedNodeMap nodeMap = element.getAttributes(); + public void startElement(String name, AttributeList attrs) throws SAXParseException { + new NestedPropertyHandler(this, child).init(name, attrs); + } + } + private void configure(Object target, AttributeList attrs) throws BuildException { if( target instanceof TaskAdapter ) target=((TaskAdapter)target).getProxy(); @@ -332,48 +436,40 @@ public class ProjectHelper { } } - for (int i = 0; i < nodeMap.getLength(); i++) { - Node node = nodeMap.item(i); - - // these should only be attribs, we won't see anything - // else here. - - if (node.getNodeType() == Node.ATTRIBUTE_NODE) { - Attr attr = (Attr)node; - - // reflect these into the target + for (int i = 0; i < attrs.getLength(); i++) { + // reflect these into the target - Method setMethod = (Method)propertySetters.get(attr.getName()); - if (setMethod == null) { - if (attr.getName().equals("id")) { - project.addReference(attr.getValue(), target); - continue; - } - - String msg = "Configuration property \"" + attr.getName() + - "\" does not have a setMethod in " + target.getClass(); - throw new BuildException(msg); + Method setMethod = (Method)propertySetters.get(attrs.getName(i)); + if (setMethod == null) { + if (attrs.getName(i).equals("id")) { + project.addReference(attrs.getValue(i), target); + continue; } - String value=replaceProperties( attr.getValue(), project.getProperties() ); - try { - setMethod.invoke(target, new String[] {value}); - } catch (IllegalAccessException iae) { - String msg = "Error setting value for attrib: " + - attr.getName(); - iae.printStackTrace(); - throw new BuildException(msg); - } catch (InvocationTargetException ie) { - String msg = "Error setting value for attrib: " + - attr.getName() + " in " + target.getClass().getName(); - ie.printStackTrace(); - ie.getTargetException().printStackTrace(); - throw new BuildException(msg); - } + String msg = "Class " + target.getClass() + + " doesn't support the \"" + attrs.getName(i) + "\" property"; + throw new BuildException(msg); + } + + String value=replaceProperties(attrs.getValue(i), project.getProperties() ); + try { + setMethod.invoke(target, new String[] {value}); + } catch (IllegalAccessException iae) { + String msg = "Error setting value for attrib: " + + attrs.getName(i); + iae.printStackTrace(); + throw new BuildException(msg); + } catch (InvocationTargetException ie) { + String msg = "Error setting value for attrib: " + + attrs.getName(i) + " in " + target.getClass().getName(); + ie.printStackTrace(); + ie.getTargetException().printStackTrace(); + throw new BuildException(msg); } } } + /** Replace ${NAME} with the property value */ public static String replaceProperties( String value, Hashtable keys ) @@ -411,13 +507,12 @@ public class ProjectHelper { // System.out.println("Before replace: " + value); return sb.toString(); } -} - - - - - - - + private static SAXParserFactory getParserFactory() { + if (parserFactory == null) { + parserFactory = SAXParserFactory.newInstance(); + } + return parserFactory; + } +} diff --git a/src/main/org/apache/tools/ant/SunParser.java b/src/main/org/apache/tools/ant/SunParser.java deleted file mode 100644 index 2c68d1ade..000000000 --- a/src/main/org/apache/tools/ant/SunParser.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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", "Tomcat", 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 - * . - */ - -package org.apache.tools.ant; - -import java.io.File; -import java.io.IOException; -import com.sun.xml.parser.Resolver; -import com.sun.xml.tree.XmlDocument; -import org.w3c.dom.Document; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -/** - * Implementation of Parser using Sun ProjectX. - * - * @author pier@apache.org - */ -public class SunParser extends Parser { - /** - * Parse the specified file and return a DOM Document. - */ - public Document parse(File buildFile) - throws SAXException, IOException { - InputSource input = Resolver.createInputSource(buildFile); - return XmlDocument.createXmlDocument(input, false); - } -} - - \ No newline at end of file diff --git a/src/main/org/apache/tools/ant/Target.java b/src/main/org/apache/tools/ant/Target.java index f38259b25..ddc11bb37 100644 --- a/src/main/org/apache/tools/ant/Target.java +++ b/src/main/org/apache/tools/ant/Target.java @@ -117,7 +117,13 @@ public class Target { Enumeration enum = tasks.elements(); while (enum.hasMoreElements()) { Task task = (Task) enum.nextElement(); - task.execute(); + + try { + task.execute(); + } catch(BuildException exc) { + exc.setLocation(task.getLocation()); + throw exc; + } } } else { project.log("Skipped because property '" + this.condition + "' not set.", this.name, Project.MSG_VERBOSE); diff --git a/src/main/org/apache/tools/ant/Task.java b/src/main/org/apache/tools/ant/Task.java index 568f257c6..daf7fc1d2 100644 --- a/src/main/org/apache/tools/ant/Task.java +++ b/src/main/org/apache/tools/ant/Task.java @@ -57,13 +57,14 @@ package org.apache.tools.ant; /** * Base class for all tasks. */ - + public abstract class Task { protected Project project = null; protected Target target = null; protected String description=null; - + protected Location location = Location.UNKNOWN_LOCATION; + /** * Sets the project object of this task. This method is used by * project when a task is added to it so that the task has @@ -87,7 +88,7 @@ public abstract class Task { /** Sets a description of the current action. It will be usefull in commenting * what we are doing. - */ + */ public void setDescription( String desc ) { description=desc; } @@ -95,7 +96,7 @@ public abstract class Task { public String getDescription() { return description; } - + /** * Called by the project to let the task initialize properly. Normally it does nothing. * @@ -110,5 +111,18 @@ public abstract class Task { */ public void execute() throws BuildException {}; + /** + * Returns the file location where this task was defined. + */ + public Location getLocation() { + return location; + } + + /** + * Sets the file location where this task was defined. + */ + public void setLocation(Location location) { + this.location = location; + } } diff --git a/src/main/org/apache/tools/ant/parser.properties b/src/main/org/apache/tools/ant/parser.properties deleted file mode 100644 index 10716a480..000000000 --- a/src/main/org/apache/tools/ant/parser.properties +++ /dev/null @@ -1 +0,0 @@ -parser=org.apache.tools.ant.SunParser \ No newline at end of file