found at runtime. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@268005 13f79535-47bb-0310-9956-ffa450edef68master
@@ -12,7 +12,7 @@ | |||||
<property name="Name" value="Ant"/> | <property name="Name" value="Ant"/> | ||||
<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="ant.home" value="."/> | ||||
<property name="src.bin.dir" value="src/bin"/> | <property name="src.bin.dir" value="src/bin"/> | ||||
@@ -178,6 +178,8 @@ | |||||
<copydir src="${docs.dir}" dest="${ant.dist.dir}/docs"/> | <copydir src="${docs.dir}" dest="${ant.dist.dir}/docs"/> | ||||
<copydir src="${build.javadocs}" dest="${ant.dist.dir}/docs/api"/> | <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"> | <chmod perm="+x"> | ||||
<fileset dir="${ant.dist.dir}/bin"> | <fileset dir="${ant.dist.dir}/bin"> | ||||
<patternset refid="chmod.patterns"/> | <patternset refid="chmod.patterns"/> | ||||
@@ -185,6 +187,7 @@ | |||||
</chmod> | </chmod> | ||||
<copyfile src="README" dest="${ant.dist.dir}/README"/> | <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="TODO" dest="${ant.dist.dir}/TODO"/> | ||||
<copyfile src="LICENSE" dest="${ant.dist.dir}/LICENSE"/> | <copyfile src="LICENSE" dest="${ant.dist.dir}/LICENSE"/> | ||||
</target> | </target> | ||||
@@ -302,11 +305,6 @@ | |||||
<!-- Run testcase --> | <!-- Run testcase --> | ||||
<!-- =================================================================== --> | <!-- =================================================================== --> | ||||
<target name="runtests" depends="compiletests" if="junit.present"> | <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"> | <junit printsummary="yes" fork="yes" haltonfailure="yes"> | ||||
<classpath> | <classpath> | ||||
<pathelement location="${lib.dir}/${name}.jar" /> | <pathelement location="${lib.dir}/${name}.jar" /> | ||||
@@ -324,19 +322,19 @@ | |||||
</fileset> | </fileset> | ||||
</batchtest> | </batchtest> | ||||
</junit> | </junit> | ||||
--> | |||||
<java fork="yes" | |||||
classname="junit.textui.TestRunner" | |||||
taskname="junit"> | |||||
<arg value="org.apache.tools.ant.AllJUnitTests" /> | |||||
<taskdef name="a" classname="A"> | |||||
<classpath> | <classpath> | ||||
<pathelement location="${lib.dir}/${name}.jar" /> | <pathelement location="${lib.dir}/${name}.jar" /> | ||||
<pathelement location="${build.tests}" /> | <pathelement location="${build.tests}" /> | ||||
<path refid="classpath" /> | <path refid="classpath" /> | ||||
<pathelement path="${java.class.path}" /> | <pathelement path="${java.class.path}" /> | ||||
<path location="/tmp" /> | |||||
</classpath> | </classpath> | ||||
</java> | |||||
</taskdef> | |||||
<a test="set"> | |||||
Bla | |||||
<c test="1" /> | |||||
</a> | |||||
</target> | </target> | ||||
</project> | </project> | ||||
@@ -1002,7 +1002,17 @@ execution depending on system parameters.</p> | |||||
<td valign="top">file</td> | <td valign="top">file</td> | ||||
<td valign="top">the file to look for.</td> | <td valign="top">the file to look for.</td> | ||||
</tr> | </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> | </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> | <h3>Examples</h3> | ||||
<pre> <available classname="org.whatever.Myclass" property="Myclass.present" /></pre> | <pre> <available classname="org.whatever.Myclass" property="Myclass.present" /></pre> | ||||
<p>sets the property <code><i>Myclass.present</i></code> to the value "true" | <p>sets the property <code><i>Myclass.present</i></code> to the value "true" | ||||
@@ -3650,7 +3660,17 @@ href="#writingowntask">Writing your own task</a>".</p> | |||||
<td valign="top">the full class name implementing the task</td> | <td valign="top">the full class name implementing the task</td> | ||||
<td valign="top" align="center">Yes</td> | <td valign="top" align="center">Yes</td> | ||||
</tr> | </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> | </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> | <h3>Examples</h3> | ||||
<pre> <taskdef name="myjavadoc" classname="com.mydomain.JavadocTask" /></pre> | <pre> <taskdef name="myjavadoc" classname="com.mydomain.JavadocTask" /></pre> | ||||
<p>makes a task called <code>myjavadoc</code> available to Ant. The class <code>com.mydomain.JavadocTask</code> | <p>makes a task called <code>myjavadoc</code> available to Ant. The class <code>com.mydomain.JavadocTask</code> | ||||
@@ -429,9 +429,7 @@ public class Project { | |||||
Class c = (Class) taskClassDefinitions.get(taskType); | Class c = (Class) taskClassDefinitions.get(taskType); | ||||
if (c == null) | 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 { | try { | ||||
Object o = c.newInstance(); | Object o = c.newInstance(); | ||||
Task task = null; | Task task = null; | ||||
@@ -363,7 +363,17 @@ public class ProjectHelper { | |||||
} | } | ||||
public void init(String tag, AttributeList attrs) throws SAXParseException { | 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())); | task.setLocation(new Location(buildFile.toString(), locator.getLineNumber(), locator.getColumnNumber())); | ||||
configureId(task, attrs); | configureId(task, attrs); | ||||
@@ -422,7 +432,13 @@ public class ProjectHelper { | |||||
IntrospectionHelper.getHelper(targetClass); | IntrospectionHelper.getHelper(targetClass); | ||||
try { | 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); | configureId(child, attrs); | ||||
if (parentWrapper != null) { | if (parentWrapper != null) { | ||||
@@ -80,6 +80,10 @@ public class RuntimeConfigurable { | |||||
wrappedObject = proxy; | wrappedObject = proxy; | ||||
} | } | ||||
void setProxy(Object proxy) { | |||||
wrappedObject = proxy; | |||||
} | |||||
/** | /** | ||||
* Set's the attributes for the wrapped element. | * Set's the attributes for the wrapped element. | ||||
*/ | */ | ||||
@@ -87,6 +91,13 @@ public class RuntimeConfigurable { | |||||
this.attributes = new AttributeListImpl(attributes); | this.attributes = new AttributeListImpl(attributes); | ||||
} | } | ||||
/** | |||||
* Returns the AttributeList of the wrapped element. | |||||
*/ | |||||
public AttributeList getAttributes() { | |||||
return attributes; | |||||
} | |||||
/** | /** | ||||
* Adds child elements to the wrapped element. | * Adds child elements to the wrapped element. | ||||
*/ | */ | ||||
@@ -94,6 +105,13 @@ public class RuntimeConfigurable { | |||||
children.addElement(child); | 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. | * Add characters from #PCDATA areas to the wrapped element. | ||||
*/ | */ | ||||
@@ -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() { | private boolean testIfCondition() { | ||||
return "".equals(ifCondition) | return "".equals(ifCondition) | ||||
|| project.getProperty(ifCondition) != null; | || project.getProperty(ifCondition) != null; | ||||
@@ -205,6 +205,10 @@ public abstract class Task { | |||||
return wrapper; | return wrapper; | ||||
} | } | ||||
protected void setRuntimeConfigurableWrapper(RuntimeConfigurable wrapper) { | |||||
this.wrapper = wrapper; | |||||
} | |||||
/** | /** | ||||
* Configure this task - if it hasn't been done already. | * Configure this task - if it hasn't been done already. | ||||
*/ | */ | ||||
@@ -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 |
@@ -242,6 +242,8 @@ public class AntStructure extends Task { | |||||
enum = ih.getAttributes(); | enum = ih.getAttributes(); | ||||
while (enum.hasMoreElements()) { | while (enum.hasMoreElements()) { | ||||
String attrName = (String) enum.nextElement(); | String attrName = (String) enum.nextElement(); | ||||
if ("id".equals(attrName)) continue; | |||||
sb.append(lSep).append(" ").append(attrName).append(" "); | sb.append(lSep).append(" ").append(attrName).append(" "); | ||||
Class type = ih.getAttributeType(attrName); | Class type = ih.getAttributeType(attrName); | ||||
if (type.equals(java.lang.Boolean.class) || | if (type.equals(java.lang.Boolean.class) || | ||||
@@ -55,6 +55,7 @@ | |||||
package org.apache.tools.ant.taskdefs; | package org.apache.tools.ant.taskdefs; | ||||
import org.apache.tools.ant.*; | import org.apache.tools.ant.*; | ||||
import org.apache.tools.ant.types.*; | |||||
/** | /** | ||||
* Define a new task - name and class | * Define a new task - name and class | ||||
@@ -64,6 +65,26 @@ import org.apache.tools.ant.*; | |||||
public class Taskdef extends Task { | public class Taskdef extends Task { | ||||
private String name; | private String name; | ||||
private String value; | 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 { | public void execute() throws BuildException { | ||||
if (name==null || value==null ) { | if (name==null || value==null ) { | ||||
@@ -72,8 +93,20 @@ public class Taskdef extends Task { | |||||
throw new BuildException(msg); | throw new BuildException(msg); | ||||
} | } | ||||
try { | 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) { | } catch (ClassNotFoundException cnfe) { | ||||
String msg = "taskdef class " + value + | String msg = "taskdef class " + value + | ||||
" cannot be found"; | " cannot be found"; | ||||
@@ -67,6 +67,8 @@ import java.util.*; | |||||
public class IntrospectionHelperTest extends TestCase { | public class IntrospectionHelperTest extends TestCase { | ||||
public static boolean isUnixStyle = File.pathSeparatorChar == ':'; | |||||
public IntrospectionHelperTest(String name) { | public IntrospectionHelperTest(String name) { | ||||
super(name); | super(name); | ||||
} | } | ||||
@@ -404,7 +406,11 @@ public class IntrospectionHelperTest extends TestCase { | |||||
} | } | ||||
public void setTen(File f) { | 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) { | public void setEleven(boolean b) { | ||||
@@ -129,7 +129,7 @@ public class PathTest extends TestCase { | |||||
assertEquals("/test", l[1]); | assertEquals("/test", l[1]); | ||||
} else { | } else { | ||||
assertEquals("drives on DOS", 1, l.length); | assertEquals("drives on DOS", 1, l.length); | ||||
assertEquals("c:\\test", l[0]); | |||||
assertEquals("c:\\test", l[0].toLowerCase()); | |||||
} | } | ||||
p = new Path(project, "c:/test"); | p = new Path(project, "c:/test"); | ||||
@@ -141,7 +141,7 @@ public class PathTest extends TestCase { | |||||
assertEquals("/test", l[1]); | assertEquals("/test", l[1]); | ||||
} else { | } else { | ||||
assertEquals("drives on DOS", 1, l.length); | assertEquals("drives on DOS", 1, l.length); | ||||
assertEquals("c:\\test", l[0]); | |||||
assertEquals("c:\\test", l[0].toLowerCase()); | |||||
} | } | ||||
} | } | ||||