Browse Source

Allow tasks to be added at runtime and only fail if they cannot be

found at runtime.


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@268005 13f79535-47bb-0310-9956-ffa450edef68
master
Stefan Bodewig 25 years ago
parent
commit
8c59db7895
12 changed files with 270 additions and 23 deletions
  1. +11
    -13
      build.xml
  2. +20
    -0
      docs/index.html
  3. +1
    -3
      src/main/org/apache/tools/ant/Project.java
  4. +18
    -2
      src/main/org/apache/tools/ant/ProjectHelper.java
  5. +18
    -0
      src/main/org/apache/tools/ant/RuntimeConfigurable.java
  6. +7
    -0
      src/main/org/apache/tools/ant/Target.java
  7. +4
    -0
      src/main/org/apache/tools/ant/Task.java
  8. +145
    -0
      src/main/org/apache/tools/ant/UnknownElement.java
  9. +2
    -0
      src/main/org/apache/tools/ant/taskdefs/AntStructure.java
  10. +35
    -2
      src/main/org/apache/tools/ant/taskdefs/Taskdef.java
  11. +7
    -1
      src/testcases/org/apache/tools/ant/IntrospectionHelperTest.java
  12. +2
    -2
      src/testcases/org/apache/tools/ant/types/PathTest.java

+ 11
- 13
build.xml View File

@@ -12,7 +12,7 @@

<property name="Name" value="Ant"/>
<property name="name" value="ant"/>
<property name="version" value="1.2alpha2"/>
<property name="version" value="1.2alpha3"/>

<property name="ant.home" value="."/>
<property name="src.bin.dir" value="src/bin"/>
@@ -178,6 +178,8 @@
<copydir src="${docs.dir}" dest="${ant.dist.dir}/docs"/>
<copydir src="${build.javadocs}" dest="${ant.dist.dir}/docs/api"/>

<fixcrlf srcdir="${ant.dist.dir}/bin" includes="ant,antRun" cr="remove"/>
<fixcrlf srcdir="${ant.dist.dir}/bin" includes="*.bat" cr="add"/>
<chmod perm="+x">
<fileset dir="${ant.dist.dir}/bin">
<patternset refid="chmod.patterns"/>
@@ -185,6 +187,7 @@
</chmod>

<copyfile src="README" dest="${ant.dist.dir}/README"/>
<copyfile src="WHATSNEW" dest="${ant.dist.dir}/WHATSNEW"/>
<copyfile src="TODO" dest="${ant.dist.dir}/TODO"/>
<copyfile src="LICENSE" dest="${ant.dist.dir}/LICENSE"/>
</target>
@@ -302,11 +305,6 @@
<!-- Run testcase -->
<!-- =================================================================== -->
<target name="runtests" depends="compiletests" if="junit.present">

<!--
This would make the buildprocess fail if using an Ant version
without the junit task

<junit printsummary="yes" fork="yes" haltonfailure="yes">
<classpath>
<pathelement location="${lib.dir}/${name}.jar" />
@@ -324,19 +322,19 @@
</fileset>
</batchtest>
</junit>
-->

<java fork="yes"
classname="junit.textui.TestRunner"
taskname="junit">
<arg value="org.apache.tools.ant.AllJUnitTests" />
<taskdef name="a" classname="A">
<classpath>
<pathelement location="${lib.dir}/${name}.jar" />
<pathelement location="${build.tests}" />
<path refid="classpath" />
<pathelement path="${java.class.path}" />
<path location="/tmp" />
</classpath>
</java>
</taskdef>
<a test="set">
Bla
<c test="1" />
</a>
</target>

</project>


+ 20
- 0
docs/index.html View File

@@ -1002,7 +1002,17 @@ execution depending on system parameters.</p>
<td valign="top">file</td>
<td valign="top">the file to look for.</td>
</tr>
<tr>
<td valign="top">classpath</td> <td valign="top">the classpath to
use when looking up <code>classname</code>.</td> <td
align="center" valign="top">No</td>
</tr>
</table>
<h3>Parameters specified as nested elements</h3>
<h4>classpath</h4>
<p><code>Available</code>'s <em>classpath</em> attribute is a <a
href="#path">PATH like structure</a> and can also be set via a nested
<em>classpath</em> element.</p>
<h3>Examples</h3>
<pre> &lt;available classname=&quot;org.whatever.Myclass&quot; property=&quot;Myclass.present&quot; /&gt;</pre>
<p>sets the property <code><i>Myclass.present</i></code> to the value &quot;true&quot;
@@ -3650,7 +3660,17 @@ href="#writingowntask">Writing your own task</a>&quot;.</p>
<td valign="top">the full class name implementing the task</td>
<td valign="top" align="center">Yes</td>
</tr>
<tr>
<td valign="top">classpath</td> <td valign="top">the classpath to
use when looking up <code>classname</code>.</td> <td
align="center" valign="top">No</td>
</tr>
</table>
<h3>Parameters specified as nested elements</h3>
<h4>classpath</h4>
<p><code>Taskdef</code>'s <em>classpath</em> attribute is a <a
href="#path">PATH like structure</a> and can also be set via a nested
<em>classpath</em> element.</p>
<h3>Examples</h3>
<pre> &lt;taskdef name=&quot;myjavadoc&quot; classname=&quot;com.mydomain.JavadocTask&quot; /&gt;</pre>
<p>makes a task called <code>myjavadoc</code> available to Ant. The class <code>com.mydomain.JavadocTask</code>


+ 1
- 3
src/main/org/apache/tools/ant/Project.java View File

@@ -429,9 +429,7 @@ public class Project {
Class c = (Class) taskClassDefinitions.get(taskType);

if (c == null)
throw new BuildException("Could not create task of type: "+taskType+
" because I can't find it in the list of task"+
" class definitions");
return null;
try {
Object o = c.newInstance();
Task task = null;


+ 18
- 2
src/main/org/apache/tools/ant/ProjectHelper.java View File

@@ -363,7 +363,17 @@ public class ProjectHelper {
}

public void init(String tag, AttributeList attrs) throws SAXParseException {
task = project.createTask(tag);
try {
task = project.createTask(tag);
} catch (BuildException e) {
// swallow here, will be thrown again in
// UnknownElement.maybeConfigure if the problem persists.
}

if (task == null) {
task = new UnknownElement(tag);
task.setProject(project);
}

task.setLocation(new Location(buildFile.toString(), locator.getLineNumber(), locator.getColumnNumber()));
configureId(task, attrs);
@@ -422,7 +432,13 @@ public class ProjectHelper {
IntrospectionHelper.getHelper(targetClass);

try {
child = ih.createElement(target, propType.toLowerCase());
if (target instanceof UnknownElement) {
child = new UnknownElement(propType.toLowerCase());
((UnknownElement) target).addChild((UnknownElement) child);
} else {
child = ih.createElement(target, propType.toLowerCase());
}

configureId(child, attrs);

if (parentWrapper != null) {


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

@@ -80,6 +80,10 @@ public class RuntimeConfigurable {
wrappedObject = proxy;
}

void setProxy(Object proxy) {
wrappedObject = proxy;
}

/**
* Set's the attributes for the wrapped element.
*/
@@ -87,6 +91,13 @@ public class RuntimeConfigurable {
this.attributes = new AttributeListImpl(attributes);
}

/**
* Returns the AttributeList of the wrapped element.
*/
public AttributeList getAttributes() {
return attributes;
}

/**
* Adds child elements to the wrapped element.
*/
@@ -94,6 +105,13 @@ public class RuntimeConfigurable {
children.addElement(child);
}

/**
* Returns the child with index <code>index</code>.
*/
RuntimeConfigurable getChild(int index) {
return (RuntimeConfigurable) children.elementAt(index);
}

/**
* Add characters from #PCDATA areas to the wrapped element.
*/


+ 7
- 0
src/main/org/apache/tools/ant/Target.java View File

@@ -159,6 +159,13 @@ public class Target {
}
}

void replaceTask(UnknownElement el, Task t) {
int index = -1;
while ((index = tasks.indexOf(el)) >= 0) {
tasks.setElementAt(t, index);
}
}

private boolean testIfCondition() {
return "".equals(ifCondition)
|| project.getProperty(ifCondition) != null;


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

@@ -205,6 +205,10 @@ public abstract class Task {
return wrapper;
}

protected void setRuntimeConfigurableWrapper(RuntimeConfigurable wrapper) {
this.wrapper = wrapper;
}

/**
* Configure this task - if it hasn't been done already.
*/


+ 145
- 0
src/main/org/apache/tools/ant/UnknownElement.java View File

@@ -0,0 +1,145 @@
/*
* 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.Vector;

/**
* Wrapper class that holds all information necessary to create a task
* that did not exist when Ant started.
*
* @author <a href="stefan.bodewig@megabit.net">Stefan Bodewig</a>
*/
public class UnknownElement extends Task {

private String elementName;
private Task realTask;
private Vector children = new Vector();
public UnknownElement (String elementName) {
this.elementName = elementName;
}
/**
* return the corresponding XML tag.
*/
public String getTag() {
return elementName;
}

public void maybeConfigure() throws BuildException {
realTask = project.createTask(elementName);
if (realTask == null) {
throw new BuildException("Could not create task of type: "+elementName+
" because I can\'t find it in the list of task"+
" class definitions", location);
}

realTask.setLocation(location);
String id = wrapper.getAttributes().getValue("id");
if (id != null) {
project.addReference(id, realTask);
}
realTask.init();

// UnknownElement always has an associated target
realTask.setOwningTarget(target);

wrapper.setProxy(realTask);
realTask.setRuntimeConfigurableWrapper(wrapper);

handleChildren(realTask, wrapper);

realTask.maybeConfigure();
target.replaceTask(this, realTask);
}

/**
* Called when the real task has been configured for the first time.
*/
public void execute() {
if (realTask == null) {
// plain impossible to get here, maybeConfigure should
// have thrown an exception.
throw new BuildException("Could not create task of type: "
+ elementName, location);
}
realTask.execute();
}

public void addChild(UnknownElement child) {
children.addElement(child);
}

protected void handleChildren(Object parent,
RuntimeConfigurable parentWrapper)
throws BuildException {

if (parent instanceof TaskAdapter) {
parent = ((TaskAdapter) parent).getProxy();
}
Class parentClass = parent.getClass();
IntrospectionHelper ih = IntrospectionHelper.getHelper(parentClass);

for (int i=0; i<children.size(); i++) {
UnknownElement child = (UnknownElement) children.elementAt(i);
Object realChild = ih.createElement(parent, child.getTag());
RuntimeConfigurable childWrapper = parentWrapper.getChild(i);
childWrapper.setProxy(realChild);
child.handleChildren(realChild, childWrapper);
}
}

}// UnknownElement

+ 2
- 0
src/main/org/apache/tools/ant/taskdefs/AntStructure.java View File

@@ -242,6 +242,8 @@ public class AntStructure extends Task {
enum = ih.getAttributes();
while (enum.hasMoreElements()) {
String attrName = (String) enum.nextElement();
if ("id".equals(attrName)) continue;
sb.append(lSep).append(" ").append(attrName).append(" ");
Class type = ih.getAttributeType(attrName);
if (type.equals(java.lang.Boolean.class) ||


+ 35
- 2
src/main/org/apache/tools/ant/taskdefs/Taskdef.java View File

@@ -55,6 +55,7 @@
package org.apache.tools.ant.taskdefs;

import org.apache.tools.ant.*;
import org.apache.tools.ant.types.*;

/**
* Define a new task - name and class
@@ -64,6 +65,26 @@ import org.apache.tools.ant.*;
public class Taskdef extends Task {
private String name;
private String value;
private Path classpath;

public void setClasspath(Path classpath) {
if (this.classpath == null) {
this.classpath = classpath;
} else {
this.classpath.append(classpath);
}
}

public Path createClasspath() {
if (this.classpath == null) {
this.classpath = new Path(project);
}
return this.classpath.createPath();
}

public void setClasspathRef(Reference r) {
createClasspath().setRefid(r);
}

public void execute() throws BuildException {
if (name==null || value==null ) {
@@ -72,8 +93,20 @@ public class Taskdef extends Task {
throw new BuildException(msg);
}
try {
Class taskClass = Class.forName(value);
project.addTaskDefinition(name, taskClass);
ClassLoader loader = null;
if (classpath != null) {
loader = new AntClassLoader(project, classpath, false);
} else {
loader = this.getClass().getClassLoader();
}

Class taskClass = null;
if (loader != null) {
taskClass = loader.loadClass(value);
} else {
taskClass = Class.forName(value);
}
project.addTaskDefinition(name, taskClass);
} catch (ClassNotFoundException cnfe) {
String msg = "taskdef class " + value +
" cannot be found";


+ 7
- 1
src/testcases/org/apache/tools/ant/IntrospectionHelperTest.java View File

@@ -67,6 +67,8 @@ import java.util.*;

public class IntrospectionHelperTest extends TestCase {

public static boolean isUnixStyle = File.pathSeparatorChar == ':';

public IntrospectionHelperTest(String name) {
super(name);
}
@@ -404,7 +406,11 @@ public class IntrospectionHelperTest extends TestCase {
}

public void setTen(File f) {
assertEquals("/tmp/2", f.getAbsolutePath());
if (isUnixStyle) {
assertEquals("/tmp/2", f.getAbsolutePath());
} else {
assertEquals("c:\\tmp\\2", f.getAbsolutePath().toLowerCase());
}
}

public void setEleven(boolean b) {


+ 2
- 2
src/testcases/org/apache/tools/ant/types/PathTest.java View File

@@ -129,7 +129,7 @@ public class PathTest extends TestCase {
assertEquals("/test", l[1]);
} else {
assertEquals("drives on DOS", 1, l.length);
assertEquals("c:\\test", l[0]);
assertEquals("c:\\test", l[0].toLowerCase());
}

p = new Path(project, "c:/test");
@@ -141,7 +141,7 @@ public class PathTest extends TestCase {
assertEquals("/test", l[1]);
} else {
assertEquals("drives on DOS", 1, l.length);
assertEquals("c:\\test", l[0]);
assertEquals("c:\\test", l[0].toLowerCase());
}
}



Loading…
Cancel
Save