PR: 4143 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@269893 13f79535-47bb-0310-9956-ffa450edef68master
@@ -28,6 +28,10 @@ Fixed bugs: | |||
contain at least a manifest file, therefore it will now print a | |||
warning and do nothing. | |||
* <typedef> hasn't been all that useful as it couldn't be used outside | |||
of targets (it can now) and nested "unknown" elements have always | |||
been considered to be tasks (changed as well). | |||
Other changes: | |||
-------------- | |||
@@ -7,6 +7,11 @@ | |||
<pathelement path="${java.class.path}" /> | |||
</path> | |||
<taskdef name="global" | |||
classname="org.example.tasks.TaskdefTestContainerTask"> | |||
<classpath refid="testclasses" /> | |||
</taskdef> | |||
<target name="test1"> | |||
<taskdef/> | |||
</target> | |||
@@ -51,4 +56,10 @@ | |||
</test7> | |||
</target> | |||
<target name="testGlobal"> | |||
<global> | |||
<echo message="worked" /> | |||
</global> | |||
</target> | |||
</project> |
@@ -0,0 +1,49 @@ | |||
<?xml version="1.0"?> | |||
<project name="test" basedir="." default="invalid"> | |||
<target name="invalid"> | |||
<fail>This file should only be run via a testcase</fail> | |||
</target> | |||
<target name="empty"> | |||
<typedef /> | |||
</target> | |||
<target name="noClassname"> | |||
<typedef name="dummy" /> | |||
</target> | |||
<target name="noName"> | |||
<typedef classname="org.example.types.TypedefTestType"> | |||
<classpath refid="testclasses" /> | |||
</typedef> | |||
</target> | |||
<target name="classNotFound"> | |||
<typedef name="" classname="oops"/> | |||
</target> | |||
<path id="testclasses"> | |||
<pathelement location="../../../../build/testcases" /> | |||
<pathelement path="${java.class.path}" /> | |||
</path> | |||
<typedef name="global" | |||
classname="org.example.types.TypedefTestType"> | |||
<classpath refid="testclasses" /> | |||
</typedef> | |||
<target name="testGlobal"> | |||
<global id="global" /> | |||
</target> | |||
<target name="testLocal"> | |||
<typedef name="local" | |||
classname="org.example.types.TypedefTestType"> | |||
<classpath refid="testclasses" /> | |||
</typedef> | |||
<local id="local" /> | |||
</target> | |||
</project> |
@@ -350,6 +350,8 @@ public class ProjectHelper { | |||
public void startElement(String name, AttributeList attrs) throws SAXParseException { | |||
if (name.equals("taskdef")) { | |||
handleTaskdef(name, attrs); | |||
} else if (name.equals("typedef")) { | |||
handleTypedef(name, attrs); | |||
} else if (name.equals("property")) { | |||
handleProperty(name, attrs); | |||
} else if (name.equals("target")) { | |||
@@ -365,6 +367,10 @@ public class ProjectHelper { | |||
(new TaskHandler(this, null, null, null)).init(name, attrs); | |||
} | |||
private void handleTypedef(String name, AttributeList attrs) throws SAXParseException { | |||
(new TaskHandler(this, null, null, null)).init(name, attrs); | |||
} | |||
private void handleProperty(String name, AttributeList attrs) throws SAXParseException { | |||
(new TaskHandler(this, null, null, null)).init(name, attrs); | |||
} | |||
@@ -210,10 +210,10 @@ public class Target implements TaskContainer { | |||
} | |||
} | |||
void replaceTask(UnknownElement el, Task t) { | |||
void replaceChild(UnknownElement el, Object o) { | |||
int index = -1; | |||
while ((index = children.indexOf(el)) >= 0) { | |||
children.setElementAt(t, index); | |||
children.setElementAt(o, index); | |||
} | |||
} | |||
@@ -58,22 +58,22 @@ import java.util.Vector; | |||
/** | |||
* Wrapper class that holds all information necessary to create a task | |||
* that did not exist when Ant started. | |||
* or data type that did not exist when Ant started. | |||
* | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
*/ | |||
public class UnknownElement extends Task { | |||
/** | |||
* Holds the name of the task or nested child element of a task | |||
* that hasn't been defined at parser time. | |||
* Holds the name of the task/type or nested child element of a | |||
* task/type that hasn't been defined at parser time. | |||
*/ | |||
private String elementName; | |||
/** | |||
* The task after it has been loaded. | |||
* The real object after it has been loaded. | |||
*/ | |||
private Task realTask; | |||
private Object realThing; | |||
/** | |||
* Childelements, holds UnknownElement instances. | |||
@@ -92,33 +92,41 @@ public class UnknownElement extends Task { | |||
} | |||
/** | |||
* creates the task instance, creates child elements, configures | |||
* the attributes of the task. | |||
* creates the real object instance, creates child elements, configures | |||
* the attributes of the real object. | |||
*/ | |||
public void maybeConfigure() throws BuildException { | |||
realTask = makeTask(this, wrapper); | |||
realThing = makeObject(this, wrapper); | |||
wrapper.setProxy(realTask); | |||
realTask.setRuntimeConfigurableWrapper(wrapper); | |||
wrapper.setProxy(realThing); | |||
if (realThing instanceof Task) { | |||
((Task) realThing).setRuntimeConfigurableWrapper(wrapper); | |||
} | |||
handleChildren(realTask, wrapper); | |||
handleChildren(realThing, wrapper); | |||
realTask.maybeConfigure(); | |||
target.replaceTask(this, realTask); | |||
wrapper.maybeConfigure(project); | |||
if (realThing instanceof Task) { | |||
target.replaceChild(this, realThing); | |||
} else { | |||
target.replaceChild(this, wrapper); | |||
} | |||
} | |||
/** | |||
* Called when the real task has been configured for the first time. | |||
*/ | |||
public void execute() { | |||
if (realTask == null) { | |||
if (realThing == null) { | |||
// plain impossible to get here, maybeConfigure should | |||
// have thrown an exception. | |||
throw new BuildException("Could not create task of type: " | |||
+ elementName, location); | |||
} | |||
realTask.perform(); | |||
if (realThing instanceof Task) { | |||
((Task) realThing).perform(); | |||
} | |||
} | |||
/** | |||
@@ -149,7 +157,7 @@ public class UnknownElement extends Task { | |||
Object realChild = null; | |||
if (parent instanceof TaskContainer) { | |||
realChild = makeTask(child, childWrapper); | |||
realChild = makeTask(child, childWrapper, false); | |||
((TaskContainer) parent).addTask((Task) realChild); | |||
} else { | |||
realChild = ih.createElement(project, parent, child.getTag()); | |||
@@ -168,44 +176,62 @@ public class UnknownElement extends Task { | |||
} | |||
} | |||
/** | |||
* Creates a named task or data type - if it is a task, configure it up to the init() stage. | |||
*/ | |||
protected Object makeObject(UnknownElement ue, RuntimeConfigurable w) { | |||
Object o = makeTask(ue, w, true); | |||
if (o == null) { | |||
o = project.createDataType(ue.getTag()); | |||
} | |||
if (o == null) { | |||
throw getNotFoundException("task or type", ue.getTag()); | |||
} | |||
return o; | |||
} | |||
/** | |||
* Create a named task and configure it up to the init() stage. | |||
*/ | |||
protected Task makeTask(UnknownElement ue, RuntimeConfigurable w) { | |||
protected Task makeTask(UnknownElement ue, RuntimeConfigurable w, | |||
boolean onTopLevel) { | |||
Task task = project.createTask(ue.getTag()); | |||
if (task == null) { | |||
String lSep = System.getProperty("line.separator"); | |||
String msg = "Could not create task of type: " + elementName | |||
+ "." + lSep | |||
+ "Ant could not find the task or a class this" + lSep | |||
+ "task relies upon." + lSep | |||
+ "Common solutions are to use taskdef to declare" + lSep | |||
+ "your task, or, if this is an optional task," + lSep | |||
+ "to put the optional.jar and all required libraries of" +lSep | |||
+ "this task in the lib directory of" + lSep | |||
+ "your ant installation (ANT_HOME)."; | |||
throw new BuildException(msg, location); | |||
if (task == null && !onTopLevel) { | |||
throw getNotFoundException("task", ue.getTag()); | |||
} | |||
task.setLocation(getLocation()); | |||
String id = w.getAttributes().getValue("id"); | |||
if (id != null) { | |||
project.addReference(id, task); | |||
if (task != null) { | |||
task.setLocation(getLocation()); | |||
// UnknownElement always has an associated target | |||
task.setOwningTarget(target); | |||
task.init(); | |||
} | |||
// UnknownElement always has an associated target | |||
task.setOwningTarget(target); | |||
task.init(); | |||
return task; | |||
} | |||
protected BuildException getNotFoundException(String what, | |||
String elementName) { | |||
String lSep = System.getProperty("line.separator"); | |||
String msg = "Could not create " + what + " of type: " + elementName | |||
+ "." + lSep | |||
+ "Ant could not find the task or a class this" + lSep | |||
+ "task relies upon." + lSep | |||
+ "Common solutions are to use taskdef to declare" + lSep | |||
+ "your task, or, if this is an optional task," + lSep | |||
+ "to put the optional.jar and all required libraries of" +lSep | |||
+ "this task in the lib directory of" + lSep | |||
+ "your ant installation (ANT_HOME)."; | |||
return new BuildException(msg, location); | |||
} | |||
/** | |||
* Get the name to use in logging messages. | |||
* | |||
* @return the name to use in logging messages. | |||
*/ | |||
public String getTaskName() { | |||
return realTask == null ? super.getTaskName() : realTask.getTaskName(); | |||
return realThing == null || !(realThing instanceof Task) ? | |||
super.getTaskName() : ((Task) realThing).getTaskName(); | |||
} | |||
}// UnknownElement |
@@ -100,4 +100,8 @@ public class TaskdefTest extends TaskdefsTest { | |||
public void test7() { | |||
expectLog("test7", "worked"); | |||
} | |||
public void testGlobal() { | |||
expectLog("testGlobal", "worked"); | |||
} | |||
} |
@@ -0,0 +1,107 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2001 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", "Ant", 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.taskdefs; | |||
import org.apache.tools.ant.Project; | |||
/** | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @version $Revision$ | |||
*/ | |||
public class TypedefTest extends TaskdefsTest { | |||
public TypedefTest(String name) { | |||
super(name); | |||
} | |||
public void setUp() { | |||
configureProject("src/etc/testcases/taskdefs/typedef.xml"); | |||
} | |||
public void testEmpty() { | |||
expectBuildException("empty", "required argument not specified"); | |||
} | |||
public void testNoName() { | |||
expectBuildException("noName", "required argument not specified"); | |||
} | |||
public void testNoClassname() { | |||
expectBuildException("noClassname", "required argument not specified"); | |||
} | |||
public void testClassNotFound() { | |||
expectBuildException("classNotFound", | |||
"classname specified doesn't exist"); | |||
} | |||
public void testGlobal() { | |||
expectLog("testGlobal", ""); | |||
Object ref = project.getReferences().get("global"); | |||
assertNotNull("ref is not null", ref); | |||
assertEquals("org.example.types.TypedefTestType", | |||
ref.getClass().getName()); | |||
} | |||
public void testLocal() { | |||
expectLog("testLocal", | |||
"Overriding previous definition of reference to local"); | |||
Object ref = project.getReferences().get("local"); | |||
assertNotNull("ref is not null", ref); | |||
assertEquals("org.example.types.TypedefTestType", | |||
ref.getClass().getName()); | |||
} | |||
} |
@@ -0,0 +1,61 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2001 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", "Ant", 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.example.types; | |||
import org.apache.tools.ant.ProjectComponent; | |||
public class TypedefTestType extends ProjectComponent { | |||
} | |||