bodewig 00/09/14 00:19:53
Modified: . WHATSNEW build.xml
docs index.html
src/main/org/apache/tools/ant ProjectHelper.java Target.java
Task.java
src/main/org/apache/tools/ant/taskdefs Available.java
Filter.java Property.java Tstamp.java
Added: src/main/org/apache/tools/ant RuntimeConfigurable.java
Log:
Moved ${} expansion and task evaluation to runtime.
This has a lot of consequences, most notably those listed in
WHATSNEW. This also affects the behavior of several other tasks like
<available> who will now do their job at runtime instead of parser
time as well.
I've changed the version number in build.xml to reflect this bigger
change.
Revision Changes Path
1.27 +10 -0 jakarta-ant/WHATSNEW
Index: WHATSNEW
===================================================================
RCS file: /home/cvs/jakarta-ant/WHATSNEW,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -r1.26 -r1.27
--- WHATSNEW 2000/09/11 13:08:33 1.26
+++ WHATSNEW 2000/09/14 07:19:50 1.27
@@ -3,6 +3,16 @@
Changes that could break older environments:
--------------------------------------------
+* Semantics of <property> has changed again in the hope to be more
+intuitive. ${} expansion now happens at runtime and <property> tags
+living inside of targets only take effect if they are visited at
+runtime.
+
+As a side effect of this change, task's attributes get set at runtime
+not at parser time as well, which might change the results of
+<script>s or other custom tasks that reference other tasks by their id
+attribute.
+
* copying of support files in <javac> has been removed - as well as
the filtering attribute.
1.70 +1 -1 jakarta-ant/build.xml
Index: build.xml
===================================================================
RCS file: /home/cvs/jakarta-ant/build.xml,v
retrieving revision 1.69
retrieving revision 1.70
diff -u -r1.69 -r1.70
--- build.xml 2000/09/12 14:44:02 1.69
+++ build.xml 2000/09/14 07:19:50 1.70
@@ -12,7 +12,7 @@
<property name="Name" value="Ant"/>
<property name="name" value="ant"/>
- <property name="version" value="1.2alpha"/>
+ <property name="version" value="1.2alpha2"/>
<property name="ant.home" value="."/>
<property name="src.bin.dir" value="src/bin"/>
1.99 +39 -3 jakarta-ant/docs/index.html
Index: index.html
===================================================================
RCS file: /home/cvs/jakarta-ant/docs/index.html,v
retrieving revision 1.98
retrieving revision 1.99
diff -u -r1.98 -r1.99
--- index.html 2000/09/12 14:44:05 1.98
+++ index.html 2000/09/14 07:19:51 1.99
@@ -25,7 +25,7 @@
<li>Dave Walend (<a href="mailto:[EMAIL PROTECTED]">[EMAIL
PROTECTED]</a>)</li>
</ul>
-<p>Version 1.2 - 2000/09/07</p>
+<p>Version 1.2 - 2000/09/14</p>
<hr>
<h2>Table of Contents</h2>
@@ -4778,8 +4778,44 @@
throws a <code>BuildException</code>. This method implements the task
itself.</li>
</ol>
-<p>It is important to know that Ant first calls the setters for the
attributes
-it encounters for a specific task in the buildfile, before it executes
is.</p>
+<h3>The life cycle of a task</h3>
+<ol>
+ <li>The task gets instantiated using a no-arg constructor at parser
+ time. This means even tasks that are never executed get
+ instantiated.</li>
+
+ <li>The tasks gets references to its project and location inside the
+ build file via their inherited <code>project</code> and
+ <code>location</code> variables.</li>
+
+ <li>If the user specified an id attribute to this task, the project
+ registers a reference to this newly created task - at parser
+ time.</li>
+
+ <li><code>init()</code> is called at parser time.</li>
+
+ <li>The task gets a reference to the target it belongs to via its
+ inherited <code>target</code> variable.</li>
+
+ <li>All child elements of the XML element corresponding to this task
+ are created via this task's <code>createXXX()</code> methods or
+ instantiated and added to this task via its <code>addXXX()</code>
+ methods - at parser time.</li>
+
+ <li>All attributes of this task get set via their corresponding
+ <code>setXXX</code> methods - at runtime.</li>
+
+ <li>The content character data sections inside the XML element
+ corresponding to this task is added to the task via its
+ <code>addText</code> method - at runtime.</li>
+
+ <li>All attributes of all child elements get set via their corresponding
+ <code>setXXX</code> methods - at runtime.</li>
+
+ <li><code>execute()</code> is called at runtime.</li>
+
+</ol>
+<h3>Example</h3>
<p>Let's write our own task, that prints a message on the System.out stream.
The
task has one attribute called "message".</p>
<blockquote>
1.28 +86 -41
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.27
retrieving revision 1.28
diff -u -r1.27 -r1.28
--- ProjectHelper.java 2000/09/08 07:20:57 1.27
+++ ProjectHelper.java 2000/09/14 07:19:51 1.28
@@ -354,6 +354,7 @@
private class TaskHandler extends AbstractHandler {
private Target target;
private Task task;
+ private RuntimeConfigurable wrapper = null;
public TaskHandler(DocumentHandler parentHandler, Target target) {
super(parentHandler);
@@ -363,35 +364,37 @@
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()));
+ configureId(task, attrs);
task.init();
// Top level tasks don't have associated targets
if (target != null) {
task.setOwningTarget(target);
target.addTask(task);
+ wrapper = task.getRuntimeConfigurableWrapper();
+ wrapper.setAttributes(attrs);
} else {
+ configure(task, attrs, project);
task.execute();
}
}
public void characters(char[] buf, int start, int end) throws
SAXParseException {
- String text = new String(buf, start, end).trim();
- if (text.length() == 0) return;
-
- IntrospectionHelper ih =
- IntrospectionHelper.getHelper(task.getClass());
-
- try {
- ih.addText(task, text);
- } catch (BuildException exc) {
- throw new SAXParseException(exc.getMessage(), locator, exc);
+ if (wrapper == null) {
+ try {
+ addText(task, buf, start, end);
+ } catch (BuildException exc) {
+ throw new SAXParseException(exc.getMessage(), locator,
exc);
+ }
+ } else {
+ wrapper.addText(buf, start, end);
}
}
public void startElement(String name, AttributeList attrs) throws
SAXParseException {
- new NestedElementHandler(this, task).init(name, attrs);
+ new NestedElementHandler(this, task, wrapper).init(name, attrs);
}
}
@@ -401,11 +404,16 @@
private class NestedElementHandler extends AbstractHandler {
private Object target;
private Object child;
+ private RuntimeConfigurable parentWrapper;
+ private RuntimeConfigurable childWrapper = null;
- public NestedElementHandler(DocumentHandler parentHandler, Object
target) {
+ public NestedElementHandler(DocumentHandler parentHandler,
+ Object target,
+ RuntimeConfigurable parentWrapper) {
super(parentHandler);
this.target = target;
+ this.parentWrapper = parentWrapper;
}
public void init(String propType, AttributeList attrs) throws
SAXParseException {
@@ -415,28 +423,34 @@
try {
child = ih.createElement(target, propType.toLowerCase());
- configure(child, attrs);
+ configureId(child, attrs);
+
+ if (parentWrapper != null) {
+ childWrapper = new RuntimeConfigurable(child);
+ childWrapper.setAttributes(attrs);
+ parentWrapper.addChild(childWrapper);
+ } else {
+ configure(child, attrs, project);
+ }
} catch (BuildException exc) {
throw new SAXParseException(exc.getMessage(), locator, exc);
}
}
public void characters(char[] buf, int start, int end) throws
SAXParseException {
- String text = new String(buf, start, end).trim();
- if (text.length() == 0) return;
-
- IntrospectionHelper ih =
- IntrospectionHelper.getHelper(child.getClass());
-
- try {
- ih.addText(child, text);
- } catch (BuildException exc) {
- throw new SAXParseException(exc.getMessage(), locator, exc);
+ if (parentWrapper == null) {
+ try {
+ addText(child, buf, start, end);
+ } catch (BuildException exc) {
+ throw new SAXParseException(exc.getMessage(), locator,
exc);
+ }
+ } else {
+ childWrapper.addText(buf, start, end);
}
}
public void startElement(String name, AttributeList attrs) throws
SAXParseException {
- new NestedElementHandler(this, child).init(name, attrs);
+ new NestedElementHandler(this, child, childWrapper).init(name,
attrs);
}
}
@@ -457,32 +471,28 @@
throw new BuildException("Unknown data type "+propType);
}
- configure(element, attrs);
+ configureId(element, attrs);
+ configure(element, attrs, project);
} catch (BuildException exc) {
throw new SAXParseException(exc.getMessage(), locator, exc);
}
}
public void characters(char[] buf, int start, int end) throws
SAXParseException {
- String text = new String(buf, start, end).trim();
- if (text.length() == 0) return;
-
- IntrospectionHelper ih =
- IntrospectionHelper.getHelper(element.getClass());
-
try {
- ih.addText(element, text);
+ addText(element, buf, start, end);
} catch (BuildException exc) {
throw new SAXParseException(exc.getMessage(), locator, exc);
}
}
public void startElement(String name, AttributeList attrs) throws
SAXParseException {
- new NestedElementHandler(this, element).init(name, attrs);
+ new NestedElementHandler(this, element, null).init(name, attrs);
}
}
- private void configure(Object target, AttributeList attrs) throws
BuildException {
+ public static void configure(Object target, AttributeList attrs,
+ Project project) throws BuildException {
if( target instanceof TaskAdapter )
target=((TaskAdapter)target).getProxy();
@@ -498,19 +508,39 @@
attrs.getName(i).toLowerCase(), value);
} catch (BuildException be) {
- if (attrs.getName(i).equals("id")) {
- project.addReference(attrs.getValue(i), target);
- } else {
- be.setLocation(new Location(buildFile.toString(),
- locator.getLineNumber(),
- locator.getColumnNumber()));
+ // id attribute must be set externally
+ if (!attrs.getName(i).equals("id")) {
throw be;
}
}
}
}
+ /**
+ * Adds the content of #PCDATA sections to an element.
+ */
+ public static void addText(Object target, char[] buf, int start, int end)
+ throws BuildException {
+ addText(target, new String(buf, start, end).trim());
+ }
+
+ /**
+ * Adds the content of #PCDATA sections to an element.
+ */
+ public static void addText(Object target, String text)
+ throws BuildException {
+
+ if (text == null || text.length() == 0) {
+ return;
+ }
+ if(target instanceof TaskAdapter)
+ target = ((TaskAdapter) target).getProxy();
+
+ IntrospectionHelper.getHelper(target.getClass()).addText(target,
text);
+ }
+
+
/** Replace ${NAME} with the property value
*/
public static String replaceProperties( String value, Hashtable keys )
@@ -562,4 +592,19 @@
return parserFactory;
}
+
+ /**
+ * Scan AttributeList for the id attribute and maybe add a
+ * reference to project.
+ *
+ * <p>Moved out of [EMAIL PROTECTED] #configure configure} to make it
happen
+ * at parser time.</p>
+ */
+ private void configureId(Object target, AttributeList attr) {
+ String id = attr.getValue("id");
+ if (id != null) {
+ project.addReference(id, target);
+ }
+ }
+
}
1.10 +1 -0 jakarta-ant/src/main/org/apache/tools/ant/Target.java
Index: Target.java
===================================================================
RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/Target.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- Target.java 2000/08/22 15:38:33 1.9
+++ Target.java 2000/09/14 07:19:51 1.10
@@ -138,6 +138,7 @@
try {
project.fireTaskStarted(task);
+ task.maybeConfigure();
task.execute();
project.fireTaskFinished(task, null);
}
1.13 +20 -0 jakarta-ant/src/main/org/apache/tools/ant/Task.java
Index: Task.java
===================================================================
RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/Task.java,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- Task.java 2000/07/12 11:51:30 1.12
+++ Task.java 2000/09/14 07:19:51 1.13
@@ -68,6 +68,7 @@
protected Location location = Location.UNKNOWN_LOCATION;
protected String taskName = null;
protected String taskType = null;
+ protected RuntimeConfigurable wrapper;
/**
* Sets the project object of this task. This method is used by
@@ -192,6 +193,25 @@
*/
public void setLocation(Location location) {
this.location = location;
+ }
+
+ /**
+ * Returns the wrapper class for runtime configuration.
+ */
+ public RuntimeConfigurable getRuntimeConfigurableWrapper() {
+ if (wrapper == null) {
+ wrapper = new RuntimeConfigurable(this);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Configure this task - if it hasn't been done already.
+ */
+ public void maybeConfigure() throws BuildException {
+ if (wrapper != null) {
+ wrapper.maybeConfigure(project);
+ }
}
}
1.1
jakarta-ant/src/main/org/apache/tools/ant/RuntimeConfigurable.java
Index: RuntimeConfigurable.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000 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 [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.tools.ant;
import java.util.Enumeration;
import java.util.Vector;
import org.xml.sax.AttributeList;
import org.xml.sax.helpers.AttributeListImpl;
/**
* Wrapper class that holds the attributes of a Task (or elements
* nested below that level) and takes care of configuring that element
* at runtime.
*
* @author <a href="[EMAIL PROTECTED]">Stefan Bodewig</a>
*/
public class RuntimeConfigurable {
private Vector children = new Vector();
private Object wrappedObject = null;
private AttributeList attributes;
private StringBuffer characters = new StringBuffer();
/**
* @param proxy The element to wrap.
*/
public RuntimeConfigurable(Object proxy) {
wrappedObject = proxy;
}
/**
* Set's the attributes for the wrapped element.
*/
public void setAttributes(AttributeList attributes) {
this.attributes = new AttributeListImpl(attributes);
}
/**
* Adds child elements to the wrapped element.
*/
public void addChild(RuntimeConfigurable child) {
children.addElement(child);
}
/**
* Add characters from #PCDATA areas to the wrapped element.
*/
public void addText(String data) {
characters.append(data);
}
/**
* Add characters from #PCDATA areas to the wrapped element.
*/
public void addText(char[] buf, int start, int end) {
addText(new String(buf, start, end).trim());
}
/**
* Configure the wrapped element and all children.
*/
public void maybeConfigure(Project p) throws BuildException {
if (attributes != null) {
ProjectHelper.configure(wrappedObject, attributes, p);
attributes = null;
}
if (characters.length() != 0) {
ProjectHelper.addText(wrappedObject, characters.toString());
characters.setLength(0);
}
Enumeration enum = children.elements();
while (enum.hasMoreElements()) {
RuntimeConfigurable child = (RuntimeConfigurable)
enum.nextElement();
child.maybeConfigure(p);
}
}
}
1.9 +1 -1
jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Available.java
Index: Available.java
===================================================================
RCS file:
/home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Available.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- Available.java 2000/08/10 12:58:54 1.8
+++ Available.java 2000/09/14 07:19:52 1.9
@@ -94,7 +94,7 @@
this.resource = resource;
}
- public void init() throws BuildException {
+ public void execute() throws BuildException {
if ((classname != null) && !checkClass(classname)) return;
if ((file != null) && !checkFile(file)) return;
if ((resource != null) && !checkResource(resource)) return;
1.2 +1 -1
jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Filter.java
Index: Filter.java
===================================================================
RCS file:
/home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Filter.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Filter.java 2000/02/13 18:24:18 1.1
+++ Filter.java 2000/09/14 07:19:52 1.2
@@ -75,7 +75,7 @@
this.value = value;
}
- public void init() throws BuildException {
+ public void execute() throws BuildException {
project.addFilter(token, value);
}
}
1.15 +1 -1
jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Property.java
Index: Property.java
===================================================================
RCS file:
/home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Property.java,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- Property.java 2000/09/04 13:29:50 1.14
+++ Property.java 2000/09/14 07:19:52 1.15
@@ -107,7 +107,7 @@
return resource;
}
- public void init() throws BuildException {
+ public void execute() throws BuildException {
try {
if ((name != null) && (value != null)) {
addProperty(name, value);
1.5 +1 -1
jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Tstamp.java
Index: Tstamp.java
===================================================================
RCS file:
/home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Tstamp.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- Tstamp.java 2000/02/11 16:17:03 1.4
+++ Tstamp.java 2000/09/14 07:19:52 1.5
@@ -67,7 +67,7 @@
*/
public class Tstamp extends Task {
- public void init() throws BuildException {
+ public void execute() throws BuildException {
try {
Date d = new Date();