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()); | |||||
| } | } | ||||
| } | } | ||||