Browse Source

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.


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@267988 13f79535-47bb-0310-9956-ffa450edef68
master
Stefan Bodewig 25 years ago
parent
commit
6ecbe24218
11 changed files with 291 additions and 49 deletions
  1. +10
    -0
      WHATSNEW
  2. +1
    -1
      build.xml
  3. +39
    -3
      docs/index.html
  4. +86
    -41
      src/main/org/apache/tools/ant/ProjectHelper.java
  5. +130
    -0
      src/main/org/apache/tools/ant/RuntimeConfigurable.java
  6. +1
    -0
      src/main/org/apache/tools/ant/Target.java
  7. +20
    -0
      src/main/org/apache/tools/ant/Task.java
  8. +1
    -1
      src/main/org/apache/tools/ant/taskdefs/Available.java
  9. +1
    -1
      src/main/org/apache/tools/ant/taskdefs/Filter.java
  10. +1
    -1
      src/main/org/apache/tools/ant/taskdefs/Property.java
  11. +1
    -1
      src/main/org/apache/tools/ant/taskdefs/Tstamp.java

+ 10
- 0
WHATSNEW View File

@@ -3,6 +3,16 @@ Changes from Ant 1.1 to the current sources
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
- 1
build.xml View File

@@ -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"/>


+ 39
- 3
docs/index.html View File

@@ -25,7 +25,7 @@
<li>Dave Walend (<a href="mailto:dwalend@cs.tufts.edu">dwalend@cs.tufts.edu</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 @@ output.
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 &quot;message&quot;.</p>
<blockquote>


+ 86
- 41
src/main/org/apache/tools/ant/ProjectHelper.java View File

@@ -354,6 +354,7 @@ public class ProjectHelper {
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 class ProjectHelper {

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 @@ public class ProjectHelper {
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 @@ public class ProjectHelper {

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 @@ public class ProjectHelper {
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,18 +508,38 @@ public class ProjectHelper {
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
*/
@@ -562,4 +592,19 @@ public class ProjectHelper {

return parserFactory;
}

/**
* Scan AttributeList for the id attribute and maybe add a
* reference to project.
*
* <p>Moved out of {@link #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);
}
}

}

+ 130
- 0
src/main/org/apache/tools/ant/RuntimeConfigurable.java View File

@@ -0,0 +1,130 @@
/*
* 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 apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/

package org.apache.tools.ant;

import java.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="stefan.bodewig@megabit.net">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
- 0
src/main/org/apache/tools/ant/Target.java View File

@@ -138,6 +138,7 @@ public class Target {

try {
project.fireTaskStarted(task);
task.maybeConfigure();
task.execute();
project.fireTaskFinished(task, null);
}


+ 20
- 0
src/main/org/apache/tools/ant/Task.java View File

@@ -68,6 +68,7 @@ public abstract class Task {
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
@@ -193,5 +194,24 @@ public abstract class Task {
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
src/main/org/apache/tools/ant/taskdefs/Available.java View File

@@ -94,7 +94,7 @@ public class Available extends Task {
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
- 1
src/main/org/apache/tools/ant/taskdefs/Filter.java View File

@@ -75,7 +75,7 @@ public class Filter extends Task {
this.value = value;
}

public void init() throws BuildException {
public void execute() throws BuildException {
project.addFilter(token, value);
}
}

+ 1
- 1
src/main/org/apache/tools/ant/taskdefs/Property.java View File

@@ -107,7 +107,7 @@ public class Property extends Task {
return resource;
}

public void init() throws BuildException {
public void execute() throws BuildException {
try {
if ((name != null) && (value != null)) {
addProperty(name, value);


+ 1
- 1
src/main/org/apache/tools/ant/taskdefs/Tstamp.java View File

@@ -67,7 +67,7 @@ import java.text.*;
*/
public class Tstamp extends Task {

public void init() throws BuildException {
public void execute() throws BuildException {
try {
Date d = new Date();



Loading…
Cancel
Save