You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by mp...@ThoughtWorks.com on 2000/04/11 14:19:52 UTC

[PATCH] SAX & JAXP

I've gone ahead and modified ProjectHelper to use SAX instead of DOM, if
anyone's interested. This version uses JAXP to create the correct parser,
so you'll need the jaxp.jar and parser.jar files from sun to run it. I've
also modified some of the error handling so that you get a filename and
line number if an error occurs.

The diffs for ProjectHelper.java, BuildException.java, Main.java,
Target.java and Task.java are below. I've also created a new file,
Location.java, which is in the attached zip file. I'm new to CVS so please
let me know if this is the way to do things...

Any feedback would be appreciated.

(See attached file: saxpatch.zip)

Index: ./jakarta-ant/src/main/org/apache/tools/ant/BuildException.java
===================================================================
RCS file:
/home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/BuildException.java,v
retrieving revision 1.3
diff -r1.3 BuildException.java
4c4
<  * Copyright (c) 1999 The Apache Software Foundation.  All rights
---
>  * Copyright (c) 1999 The Apache Software Foundation.  All rights
12c12
<  *    notice, this list of conditions and the following disclaimer.
---
>  *    notice, this list of conditions and the following disclaimer.
20,21c20,21
<  *    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
28c28
<  *    from this software without prior written permission. For written
---
>  *    from this software without prior written permission. For written
53c53
<  */
---
>  */
67a68,70
>     /** Location in the build file where the exception occured */
>     private Location location = Location.UNKNOWN_LOCATION;
>
71c74
<
---
>
80c83
<
---
>
96c99,112
<
---
>
>     /**
>      * 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;
>    }
>
101c117
<
---
>
105a122,154
>
>     /**
>      * 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;
>    }

Index: ./jakarta-ant/src/main/org/apache/tools/ant/Main.java
===================================================================
RCS file:
/home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/Main.java,v
retrieving revision 1.5
diff -r1.5 Main.java
144c144
<                  * goes ahead * and parses this out to args
---
>                  * goes ahead * and parses this out to args
192c192
<
---
>
219c219
<
---
>
225,227c225,229
<             String msg = "BUILD CONFIG ERROR: ";
<             System.out.println(msg + be.getMessage());
<             be.printStackTrace();
---
>             String msg = "\nBUILD CONFIG ERROR\n\n";
>             System.out.println(msg + be.toString());
>             if (be.getException() != null) {
>                   be.getException().printStackTrace();
>              }
243,244c245,246
<             String msg = "BUILD FATAL ERROR: ";
<             System.out.println(msg + be.getMessage());
---
>             String msg = "\nBUILD FATAL ERROR\n\n";
>             System.out.println(msg + be.toString());

Index: ./jakarta-ant/src/main/org/apache/tools/ant/ProjectHelper.java
===================================================================
RCS file:
/home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/ProjectHelper.java,v
retrieving revision 1.11
diff -r1.11 ProjectHelper.java
58,59c58
< import java.io.File;
< import java.io.IOException;
---
> import java.io.*;
62c61
< import org.xml.sax.SAXException;
---
> import org.xml.sax.*;
64a64
> import javax.xml.parsers.*;
75,224c75
<     public static void configureProject(Project project, File buildFile)
<         throws BuildException
<     {
<
<         // XXX
<         // need to get rid of the DOM layer and use SAX
<
<         Document doc;
<
<         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);
<         }
<
<         Element root = doc.getDocumentElement();
<
<         // sanity check, make sure that we have the right element
<         // as we aren't validating the input
<
<         if (!root.getTagName().equals("project")) {
<             String msg = "Config file is not of expected XML type";
<             throw new BuildException(msg);
<         }
<
<         project.setDefaultTarget(root.getAttribute("default"));
<
<         String name = root.getAttribute("name");
<         project.setName(name);
<         if (name != null) project.addReference(name, project);
<
<         String id = root.getAttribute("id");
<         if (id != null) project.addReference(id, project);
<
<         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
();
<             }
<         }
<         project.setBasedir(baseDir);
<
<         // set up any properties that may be in the config file
<
<         //      configureProperties(project, root);
<
<         // set up any task defs that may be in the config file
<
<         //      configureTaskDefs(project, root);
<
<         // set up the taskdefs, properties, and targets into the project
<         configureProject(project, root);
<     }
<
<     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);
<             }
<
<             Target target = new Target();
<             target.setName(targetName);
<             target.setCondition(targetCond);
<             project.addTarget(targetName, target);
<
<             if (targetId != null && !targetId.equals(""))
<                 project.addReference(targetId,target);
<
<             // take care of dependencies
<
<             if (targetDep.length() > 0) {
<                 StringTokenizer tok =
<                     new StringTokenizer(targetDep, ",", false);
<                 while (tok.hasMoreTokens()) {
<                     target.addDependency(tok.nextToken().trim());
<                 }
<             }
<
<             // populate target with tasks
<
<             configureTasks(project, target, element);
<         }
<     }
<
<     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();
<
<                 // XXX
<                 // put in some sanity checking
<
<                 Task task = project.createTask(taskType);
<
<                 // get the attributes of this element and reflect them
<                 // into the task
<
<                 configure(project, task, element);
<                 task.init();
<                 task.setTarget(target);
<                 target.addTask(task);
---
>    private static SAXParserFactory parserFactory = null;
226c77,317
<                 processNestedProperties(project, task, element);
---
>    private org.xml.sax.Parser parser;
>    private Project project;
>    private File buildFile;
>    private Locator locator;
>
>    /**
>     *   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 {
>              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);
>         }
>    }
>
>    /**
>     *   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;
>
>         public AbstractHandler(DocumentHandler parentHandler) {
>              this.parentHandler = parentHandler;
>
>              // Start handling SAX events
>              parser.setDocumentHandler(this);
>         }
>
>         public void startElement(String tag, AttributeList attrs) throws
SAXParseException {
>              throw new SAXParseException("Unexpected element \"" + tag +
"\"", locator);
>         }
>
>         public void characters(char[] buf, int start, int end) throws
SAXParseException {
>              String s = new String(buf, start, end).trim();
>
>              if (s.length() > 0) {
>                   throw new SAXParseException("Unexpected text \"" + s +
"\"", locator);
>              }
>         }
>
>         public void endElement(String name) throws SAXException {
>
>              // 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);
>              }
>         }
>
>         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);
>
>              project.setName(name);
>              if (name != null) project.addReference(name, project);
>
>              if (id != null) project.addReference(id, project);
>
>              if (project.getProperty("basedir") != null) {
>                   project.setBasedir(project.getProperty("basedir"));
>              }
>              else {
>                   project.setBasedir(baseDir);
>              }
>
>         }
>
>         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);
>         }
>    }
>
>    /**
>     *   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);
>                   }
>              }
>
>              if (name == null) {
>                   throw new SAXParseException("target element appears
without a name attribute", locator);
>              }
>
>              target = new Target();
>              target.setName(name);
>              target.setCondition(cond);
>              project.addTarget(name, target);
>
>              if (id != null && !id.equals("")) {
>                   project.addReference(id, target);
>              }
>
>              if (depends.length() > 0) {
>                   StringTokenizer tok = new StringTokenizer(depends, ",",
false);
>                   while (tok.hasMoreTokens()) {
>                        target.addDependency(tok.nextToken().trim());
>                   }
228,237c319
<         }
<     }
<
<     private static void processNestedProperties(Project project,
<                                                 Object target,
<                                                 Element targetElement)
<         throws BuildException
<     {
<         Class targetClass = target.getClass();
<         NodeList list = targetElement.getChildNodes();
---
>         }
239,295c321,415
<         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());
<                 }
<             }
<
<             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 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 TaskHandler(this, target).init(name, attrs);
>         }
>    }
>
>    /**
>     *   Handler for all task elements.
>     */
>    private class TaskHandler extends AbstractHandler {
>         private Target target;
>         private Task task;
>
>         public TaskHandler(DocumentHandler parentHandler, Target target)
{
>              super(parentHandler);
>
>              this.target = target;
>         }
>
>         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();
>
>              // Top level tasks don't have associated targets
>              if (target != null) {
>                   task.setTarget(target);
>                   target.addTask(task);
>              }
>         }
>
>         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);
>         }
>    }
>
>    /**
>     *   Handler for all nested properties.
>     */
>    private class NestedPropertyHandler extends AbstractHandler {
>         private DocumentHandler parentHandler;
>
>         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);
>              }
>         }
>
>         public void startElement(String name, AttributeList attrs) throws
SAXParseException {
>              new NestedPropertyHandler(this, child).init(name, attrs);
>         }
>    }
296a417
>    private void configure(Object target, AttributeList attrs) throws
BuildException {
335,342c456,457
<         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;
---
>         for (int i = 0; i < attrs.getLength(); i++) {
>              // reflect these into the target
344,373c459,485
<                 // 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);
<                 }
<
<                 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);
<                 }
<             }
---
>              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 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);
>              }
376a489
>
413a527,534
>
>    private static SAXParserFactory getParserFactory() {
>         if (parserFactory == null) {
>              parserFactory = SAXParserFactory.newInstance();
>         }
>
>         return parserFactory;
>    }

Index: ./jakarta-ant/src/main/org/apache/tools/ant/Target.java
===================================================================
RCS file:
/home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/Target.java,v
retrieving revision 1.3
diff -r1.3 Target.java
120c120,127
<                 task.execute();
---
>
>                 try {
>                   task.execute();
>                   }
>                   catch(BuildException exc) {
>                        exc.setLocation(task.getLocation());
>                        throw exc;
>                   }

Index: ./jakarta-ant/src/main/org/apache/tools/ant/Task.java
===================================================================
RCS file:
/home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/Task.java,v
retrieving revision 1.4
diff -r1.4 Task.java
60c60
<
---
>
66c66,67
<
---
>     protected Location location = Location.UNKNOWN_LOCATION;
>
90c91
<      */
---
>      */
98c99
<
---
>
112a114,126
>    /**
>     * 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;
>    }