Date: 2004-03-16T07:54:42
   Editor: 193.109.238.66 <>
   Wiki: Ant Wiki
   Page: AntTutorialWritingTasks
   URL: http://wiki.apache.org/ant/AntTutorialWritingTasks

   hint to manual; remove my name; format codings

Change Log:

------------------------------------------------------------------------------
@@ -1,9 +1,9 @@
 = Tutorial: Writing Tasks =
 
-''Jan Matčrne, 2003-09-01''
-
 This document provides a step by step tutorial for writing tasks.
 
+This tutorial is part of the 
[http://ant.apache.org/manual/tutorial-writing-tasks.html Ant-Manual] 
+
 == Set up the build environment ==
 Ant builds itself, we are using Ant too (why we would write a task if not? :-) 
therefore we should use Ant for our build.
 
@@ -14,58 +14,60 @@
 
 So the buildfile contains three targets. 
 
-{{{    <?xml version="1.0" encoding="ISO-8859-1"?> }}}
-{{{    <project name="MyTask" basedir="." default="jar"> }}}
+{{{<?xml version="1.0" encoding="ISO-8859-1"?> 
+<project name="MyTask" basedir="." default="jar">
 
-{{{        <target name="clean" description="Delete all generated files"> }}}
-{{{            <delete dir="classes"/> }}}
-{{{            <delete file="MyTasks.jar"/> }}}
-{{{        </target> }}}
-
-{{{        <target name="compile" description="Compiles the Task"> }}}
-{{{            <javac srcdir="src" destdir="classes"/> }}}
-{{{        </target> }}}
-
-{{{        <target name="jar" description="JARs the Task"> }}}
-{{{            <jar destfile="MyTask.jar" basedir="classes"/> }}}
-{{{        </target> }}}
+    <target name="clean" description="Delete all generated files"> 
+        <delete dir="classes"/> 
+        <delete file="MyTasks.jar"/> 
+    </target> 
+
+    <target name="compile" description="Compiles the Task"> 
+        <javac srcdir="src" destdir="classes"/> 
+    </target> 
+
+    <target name="jar" description="JARs the Task"> 
+        <jar destfile="MyTask.jar" basedir="classes"/> 
+    </target> 
 
-{{{    </project> }}}
+</project> 
+}}}
 
 This buildfile uses often the same value (src, classes, MyTask.jar), so we 
should rewrite that using <property>s. On second there are some handicaps: 
<javac> requires that the destination directory exists; a call of "clean" with 
a non existing classes directory will fail; "jar" requires the execution of 
some steps bofore. So the refactored code is: 
 
-{{{    <?xml version="1.0" encoding="ISO-8859-1"?> }}}
-{{{    <project name="MyTask" basedir="." default="jar"> }}}
-{{{     }}}
-{{{        '''<property name="src.dir" value="src"/>''' }}}
-{{{        '''<property name="classes.dir" value="classes"/>''' }}}
-{{{     }}}
-{{{        <target name="clean" description="Delete all generated files"> }}}
-{{{            <delete dir="'''${classes.dir}'''" '''failonerror="false"'''/> 
}}}
-{{{            <delete file="${ant.project.name}.jar"/> }}}
-{{{        </target> }}}
-{{{     }}}
-{{{        <target name="compile" description="Compiles the Task"> }}}
-{{{            '''<mkdir dir="${classes.dir}"/>''' }}}
-{{{            <javac srcdir="${src.dir}" destdir="${classes.dir}"/> }}}
-{{{        </target> }}}
-{{{     }}}
-{{{        <target name="jar" description="JARs the Task" 
'''depends="compile"'''> }}}
-{{{            <jar destfile="${ant.project.name}.jar" 
basedir="${classes.dir}"/> }}}
-{{{        </target> }}}
-{{{     }}}
-{{{    </project> }}}
+{{{<?xml version="1.0" encoding="ISO-8859-1"?> 
+<project name="MyTask" basedir="." default="jar"> 
+
+    <property name="src.dir" value="src"/>
+    <property name="classes.dir" value="classes"/>
+
+    <target name="clean" description="Delete all generated files"> 
+        <delete dir="${classes.dir}" failonerror="false"/> 
+        <delete file="${ant.project.name}.jar"/> 
+    </target> 
+
+    <target name="compile" description="Compiles the Task"> 
+        <mkdir dir="${classes.dir}"/> 
+        <javac srcdir="${src.dir}" destdir="${classes.dir}"/> 
+    </target> 
+
+    <target name="jar" description="JARs the Task" depends="compile"> 
+        <jar destfile="${ant.project.name}.jar" basedir="${classes.dir}"/> 
+    </target> 
+
+</project>}}}
 
 ''ant.project.name'' is one of the 
[http://ant.apache.org/manual/using.html#built-in-props build-in properties 
[1]] of Ant. 
 
 == Write the Task ==
 Now we write the simplest Task - a HelloWorld-Task (what else?). Create a text 
file ''HelloWorld.java'' in the src-directory with: 
 
-{{{    public class HelloWorld { }}}
-{{{        public void execute() { }}}
-{{{            System.out.println("Hello World"); }}}
-{{{        } }}}
-{{{    } }}}
+{{{public class HelloWorld {
+    public void execute() {
+        System.out.println("Hello World");
+    }
+}
+}}}
 
 and we can compile and jar it with {{{ ant }}} (default target is "jar" and 
via its ''depends''-clause the "compile" is executed before). 
 
@@ -73,120 +75,140 @@
 == Use the Task ==
 But after creating the jar we want to use our new Task. Therefore we need a 
new target "use". Before we can use our new task we have to declare it with 
[http://ant.apache.org/manual/CoreTasks/taskdef.html <taskdef> [2]]. And for 
easier process we change the default clause: 
 
-{{{    <?xml version="1.0" encoding="ISO-8859-1"?> }}}
-{{{    <project name="MyTask" basedir="." default="use"> }}}
-{{{     }}}
-{{{        ... }}}
-{{{     }}}
-{{{        '''<target name="use" description="Use the Task" depends="jar">''' 
}}}
-{{{            '''<taskdef name="helloworld" classname="HelloWorld" 
classpath="${ant.project.name}.jar"/>''' }}}
-{{{            '''<helloworld/>''' }}}
-{{{        '''</target>''' }}}
-{{{     }}}
-{{{    </project> }}}
+{{{
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="MyTask" basedir="." default="use">
+
+    ...
+
+    <target name="use" description="Use the Task" depends="jar">
+        <taskdef name="helloworld" classname="HelloWorld" 
classpath="${ant.project.name}.jar"/>
+        <helloworld/>
+    </target>
+
+</project>
+}}}
 
 Important is the ''classpath''-attribute. Ant searches in its /lib directory 
for tasks and our task isnīt there. So we have to provide the right location. 
 
 Now we can type in {{{ ant }}} and all should work ... 
 
-{{{    Buildfile: build.xml }}}
-{{{     }}}
-{{{    compile: }}}
-{{{       ["mkdir"] Created dir: C:\tmp\anttests\MyFirstTask\classes }}}
-{{{       ["javac"] Compiling 1 source file to 
C:\tmp\anttests\MyFirstTask\classes }}}
-{{{     }}}
-{{{    jar: }}}
-{{{         ["jar"] Building jar: C:\tmp\anttests\MyFirstTask\MyTask.jar }}}
-{{{     }}}
-{{{    use: }}}
-{{{   ["helloworld"] Hello World }}}
-{{{     }}}
-{{{    BUILD SUCCESSFUL }}}
-{{{    Total time: 3 seconds }}}
+{{{
+Buildfile: build.xml
+
+compile:
+    [mkdir] Created dir: C:\tmp\anttests\MyFirstTask\classes
+    [javac] Compiling 1 source file to C:\tmp\anttests\MyFirstTask\classes
+
+jar:
+      [jar] Building jar: C:\tmp\anttests\MyFirstTask\MyTask.jar
+
+use:
+[helloworld] Hello World
+
+BUILD SUCCESSFUL
+Total time: 3 seconds
+}}}
+
 
 == Integration with TaskAdapter ==
 Our class has nothing to do with Ant. It extends no superclass and implements 
no interface. How does Ant know to integrate? Via name convention: our class 
provides a method with signature public void execute(). This class is wrapped 
by Antīs {{{ org.apache.tools.ant.TaskAdapter }}} which is a task and uses 
reflection for setting a reference to the project and calling the ''execute()'' 
method.
 
 ''Setting a reference to the project?'' Could be interesting. The Project 
class gives us some nice abilities: access to Antīs logging facilities getting 
and setting properties and much more. So we try to use that class: 
 
-{{{    import org.apache.tools.ant.Project; }}}
-{{{     }}}
-{{{    public class HelloWorld { }}}
-{{{     }}}
-{{{        private Project project; }}}
-{{{     }}}
-{{{        public void setProject(Project proj) { }}}
-{{{            project = proj; }}}
-{{{        } }}}
-{{{     }}}
-{{{        public void execute() { }}}
-{{{            String message = project.getProperty("ant.project.name"); }}}
-{{{            project.log("Here is project '" + message + "'.", 
Project.MSG_INFO); }}}
-{{{        } }}}
-{{{    } }}}
+{{{
+import org.apache.tools.ant.Project;
+
+public class HelloWorld {
+
+    private Project project;
+
+    public void setProject(Project proj) {
+        project = proj;
+    }
+
+    public void execute() {
+        String message = project.getProperty("ant.project.name");
+        project.log("Here is project '" + message + "'.", Project.MSG_INFO);
+    }
+}
+}}}
 
 and the execution with ant will show us the expected 
 
-{{{    use: }}}
-{{{    Here is project 'MyTask'. }}}
+{{{
+use:
+Here is project 'MyTask'.
+}}}
 
 == Deriving from Antīs Task ==
 Ok, that works ... But usually you will extend {{{ org.apache.tools.ant.Task 
}}}. That class is integrated in Ant, getīs the project-reference, provides 
documentation fiels, provides easier access to the logging facility and (very 
useful) gives you the exact location ''where in the buildfile this task 
instance is used''.
 
 Oki-doki - letīs us use some of these: 
 
-{{{    import org.apache.tools.ant.Task; }}}
-{{{     }}}
-{{{    public class HelloWorld extends Task { }}}
-{{{        public void execute() { }}}
-{{{            // use of the reference to Project-instance }}}
-{{{            String message = getProject().getProperty("ant.project.name"); 
}}}
-{{{     }}}
-{{{            // Taskīs log method }}}
-{{{            log("Here is project '" + message + "'."); }}}
-{{{     }}}
-{{{            // where this task is used? }}}
-{{{            log("I am used in: " +  getLocation() ); }}}
-{{{        } }}}
-{{{    } }}}
+{{{
+import org.apache.tools.ant.Task;
+
+public class HelloWorld extends Task {
+    public void execute() {
+        // use of the reference to Project-instance
+        String message = getProject().getProperty("ant.project.name");
+
+        // Task's log method
+        log("Here is project '" + message + "'.");
+
+        // where this task is used?
+        log("I am used in: " +  getLocation() );
+    }
+}
+}}}
 
 which gives us when running 
-{{{    use: }}}
-{{{   ["helloworld"] Here is project 'MyTask'. }}}
-{{{   ["helloworld"] I am used in: C:\tmp\anttests\MyFirstTask\build.xml:23: 
}}}
+
+{{{
+use:
+[helloworld] Here is project 'MyTask'.
+[helloworld] I am used in: C:\tmp\anttests\MyFirstTask\build.xml:23:
+}}}
 
 == Attributes ==
 Now we want to specify the text of our message (it seems that we are rewriting 
the <echo/> task :-). First we well do that with an attribute. It is very easy 
- for each attribute provide a public void {{{ set<attributename>(<type> 
newValue) }}} method and Ant will do the rest via reflection.
 
-{{{    import org.apache.tools.ant.Task; }}}
-{{{    import org.apache.tools.ant.BuildException; }}}
-{{{     }}}
-{{{    public class HelloWorld extends Task { }}}
-{{{     }}}
-{{{        String message; }}}
-{{{        public void setMessage(String msg) { }}}
-{{{            message = msg; }}}
-{{{        } }}}
-{{{     }}}
-{{{        public void execute() { }}}
-{{{            if (message==null) { }}}
-{{{                throw new BuildException("No message set."); }}}
-{{{            } }}}
-{{{            log(message); }}}
-{{{        } }}}
-{{{     }}}
-{{{    } }}}
+{{{
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+
+public class HelloWorld extends Task {
+
+    String message;
+    public void setMessage(String msg) {
+        message = msg;
+    }
+
+    public void execute() {
+        if (message==null) {
+            throw new BuildException("No message set.");
+        }
+        log(message);
+    }
+
+}
+}}}
 
 Oh, whatīs that in execute()? Throw a ''BuildException''? Yes, thatīs the 
usual way to show Ant that something important is missed and complete build 
should fail. The string provided there is written as build-failes-message. Here 
itīs necessary because the log() method canīt handle a ''null'' value as 
parameter and throws a NullPointerException. (Of course you can initialize the 
''message'' with a default string.)
 
 After that we have to modify our buildfile: 
 
-{{{    <target name="use" description="Use the Task" depends="jar"> }}}
-{{{        <taskdef name="helloworld" }}}
-{{{                 classname="HelloWorld" }}}
-{{{                 classpath="${ant.project.name}.jar"/> }}}
-{{{        <helloworld '''message="Hello World"'''/> }}}
-{{{    </target> }}}
+{{{
+    <target name="use" description="Use the Task" depends="jar">
+        <taskdef name="helloworld"
+                 classname="HelloWorld"
+                 classpath="${ant.project.name}.jar"/>
+        <helloworld message="Hello World"/>
+    </target>
+}}}
+
+
 
 Thatīs all.
 
@@ -200,14 +222,16 @@
 == Nested Text ==
 Maybe you have used the <echo> task in a way like <echo>Hello World</echo>. 
For that you have to provide a public void addText(String text) method. 
 
-{{{    ... }}}
-{{{    public class HelloWorld extends Task { }}}
-{{{        ... }}}
-{{{        public void addText(String text) { }}}
-{{{            message = text; }}}
-{{{        } }}}
-{{{        ... }}}
-{{{    } }}}
+{{{
+...
+public class HelloWorld extends Task {
+    ...
+    public void addText(String text) {
+        message = text;
+    }
+    ...
+}
+}}}
 
 But here properties are '''not''' resolved! For resolving properties we have 
to use Projectīs {{{ replaceProperties(String propname) : String }}} method 
which takes the property name as argument and returns its value (or ${propname} 
if not set).
 
@@ -218,240 +242,252 @@
  *  A factory method instantiates an object, saves the reference in the list 
and returns it to Ant Core. 
  *  The execute() method iterates over the list and evaluates its values. 
 
-{{{    import java.util.Vector; }}}
-{{{    import java.util.Iterator; }}}
-{{{    ... }}}
-{{{        public void execute() { }}}
-{{{            if (message!=null) log(message); }}}
-{{{            for (Iterator it=messages.iterator(); it.hasNext(); ) {      // 
4 }}}
-{{{                Message msg = (Message)it.next(); }}}
-{{{                log(msg.getMsg()); }}}
-{{{            } }}}
-{{{        } }}}
-{{{     }}}
-{{{     }}}
-{{{        Vector messages = new Vector();                                  // 
2 }}}
-{{{     }}}
-{{{        public Message createMessage() {                                 // 
3 }}}
-{{{            Message msg = new Message(); }}}
-{{{            messages.add(msg); }}}
-{{{            return msg; }}}
-{{{        } }}}
-{{{     }}}
-{{{        public class Message {                                           // 
1 }}}
-{{{            public Message() {} }}}
-{{{     }}}
-{{{            String msg; }}}
-{{{            public void setMsg(String msg) { this.msg = msg; } }}}
-{{{            public String getMsg() { return msg; } }}}
-{{{        } }}}
-{{{    ... }}}
+{{{
+import java.util.Vector;
+import java.util.Iterator;
+...
+    public void execute() {
+        if (message!=null) log(message);
+        for (Iterator it=messages.iterator(); it.hasNext(); ) {      // 4
+            Message msg = (Message)it.next();
+            log(msg.getMsg());
+        }
+    }
+
+
+    Vector messages = new Vector();                                  // 2
+
+    public Message createMessage() {                                 // 3
+        Message msg = new Message();
+        messages.add(msg);
+        return msg;
+    }
+
+    public class Message {                                           // 1
+        public Message() {}
+
+        String msg;
+        public void setMsg(String msg) { this.msg = msg; }
+        public String getMsg() { return msg; }
+    }
+...
+}}}
 
 Then we can use the new nested element. But where is xml-name for that 
defined? The mapping XML-name : classname is defined in the factory method: {{{ 
public classname createXML-name() }}}. Therefore we write in the buildfile 
 
-{{{    <helloworld> }}}
-{{{        <message msg="Nested Element 1"/> }}}
-{{{        <message msg="Nested Element 2"/> }}}
-{{{    </helloworld> }}}
+{{{
+        <helloworld>
+            <message msg="Nested Element 1"/>
+            <message msg="Nested Element 2"/>
+        </helloworld>
+}}}
+
 
 == Our task in a little more complex version ==
 For recapitulation now a little refactored buildfile: 
 
-{{{    <?xml version="1.0" encoding="ISO-8859-1"?> }}}
-{{{    <project name="MyTask" basedir="." default="use"> }}}
-{{{     }}}
-{{{        <property name="src.dir" value="src"/> }}}
-{{{        <property name="classes.dir" value="classes"/> }}}
-{{{     }}}
-{{{        <target name="clean" description="Delete all generated files"> }}}
-{{{            <delete dir="${classes.dir}" failonerror="false"/> }}}
-{{{            <delete file="${ant.project.name}.jar"/> }}}
-{{{        </target> }}}
-{{{     }}}
-{{{        <target name="compile" description="Compiles the Task"> }}}
-{{{            <mkdir dir="${classes.dir}"/> }}}
-{{{            <javac srcdir="${src.dir}" destdir="${classes.dir}"/> }}}
-{{{        </target> }}}
-{{{     }}}
-{{{        <target name="jar" description="JARs the Task" depends="compile"> 
}}}
-{{{            <jar destfile="${ant.project.name}.jar" 
basedir="${classes.dir}"/> }}}
-{{{        </target> }}}
-{{{     }}}
-{{{     }}}
-{{{        <target name="use.init" }}}
-{{{                description="Taskdef the HelloWorld-Task" }}}
-{{{                depends="jar"> }}}
-{{{            <taskdef name="helloworld" }}}
-{{{                     classname="HelloWorld" }}}
-{{{                     classpath="${ant.project.name}.jar"/> }}}
-{{{        </target> }}}
-{{{     }}}
-{{{     }}}
-{{{        <target name="use.without" }}}
-{{{                description="Use without any" }}}
-{{{                depends="use.init"> }}}
-{{{            <helloworld/> }}}
-{{{        </target> }}}
-{{{     }}}
-{{{        <target name="use.message" }}}
-{{{                description="Use with attribute 'message'" }}}
-{{{                depends="use.init"> }}}
-{{{            <helloworld message="attribute-text"/> }}}
-{{{        </target> }}}
-{{{     }}}
-{{{        <target name="use.fail" }}}
-{{{                description="Use with attribute 'fail'" }}}
-{{{                depends="use.init"> }}}
-{{{            <helloworld fail="true"/> }}}
-{{{        </target> }}}
-{{{     }}}
-{{{        <target name="use.nestedText" }}}
-{{{                description="Use with nested text" }}}
-{{{                depends="use.init"> }}}
-{{{            <helloworld>nested-text</helloworld> }}}
-{{{        </target> }}}
-{{{     }}}
-{{{        <target name="use.nestedElement" }}}
-{{{                description="Use with nested 'message'" }}}
-{{{                depends="use.init"> }}}
-{{{            <helloworld> }}}
-{{{                <message msg="Nested Element 1"/> }}}
-{{{                <message msg="Nested Element 2"/> }}}
-{{{            </helloworld> }}}
-{{{        </target> }}}
-{{{     }}}
-{{{     }}}
-{{{        <target name="use" }}}
-{{{                description="Try all (w/out use.fail)" }}}
-{{{                
depends="use.without,use.message,use.nestedText,use.nestedElement" }}}
-{{{        /> }}}
-{{{     }}}
-{{{    </project> }}}
-{{{     }}}
+{{{
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="MyTask" basedir="." default="use">
+
+    <property name="src.dir" value="src"/>
+    <property name="classes.dir" value="classes"/>
+
+    <target name="clean" description="Delete all generated files">
+        <delete dir="${classes.dir}" failonerror="false"/>
+        <delete file="${ant.project.name}.jar"/>
+    </target>
+
+    <target name="compile" description="Compiles the Task">
+        <mkdir dir="${classes.dir}"/>
+        <javac srcdir="${src.dir}" destdir="${classes.dir}"/>
+    </target>
+
+    <target name="jar" description="JARs the Task" depends="compile">
+        <jar destfile="${ant.project.name}.jar" basedir="${classes.dir}"/>
+    </target>
+
+
+    <target name="use.init"
+            description="Taskdef the HelloWorld-Task"
+            depends="jar">
+        <taskdef name="helloworld"
+                 classname="HelloWorld"
+                 classpath="${ant.project.name}.jar"/>
+    </target>
+
+
+    <target name="use.without"
+            description="Use without any"
+            depends="use.init">
+        <helloworld/>
+    </target>
+
+    <target name="use.message"
+            description="Use with attribute 'message'"
+            depends="use.init">
+        <helloworld message="attribute-text"/>
+    </target>
+
+    <target name="use.fail"
+            description="Use with attribute 'fail'"
+            depends="use.init">
+        <helloworld fail="true"/>
+    </target>
+
+    <target name="use.nestedText"
+            description="Use with nested text"
+            depends="use.init">
+        <helloworld>nested-text</helloworld>
+    </target>
+
+    <target name="use.nestedElement"
+            description="Use with nested 'message'"
+            depends="use.init">
+        <helloworld>
+            <message msg="Nested Element 1"/>
+            <message msg="Nested Element 2"/>
+        </helloworld>
+    </target>
+
+
+    <target name="use"
+            description="Try all (w/out use.fail)"
+            depends="use.without,use.message,use.nestedText,use.nestedElement"
+    />
+
+</project>
+}}}
+
+
 And the code of the task: 
 
-{{{    import org.apache.tools.ant.Task; }}}
-{{{    import org.apache.tools.ant.BuildException; }}}
-{{{    import java.util.Vector; }}}
-{{{    import java.util.Iterator; }}}
-{{{     }}}
-{{{    /** }}}
-{{{     * The task of the tutorial. }}}
-{{{     * Printīs a message or let the build fail. }}}
-{{{     * @author Jan Matčrne }}}
-{{{     * @since 2003-08-19 }}}
-{{{     */ }}}
-{{{    public class HelloWorld extends Task { }}}
-{{{     }}}
-{{{     }}}
-{{{        /** The message to print. As attribute. */ }}}
-{{{        String message; }}}
-{{{        public void setMessage(String msg) { }}}
-{{{            message = msg; }}}
-{{{        } }}}
-{{{     }}}
-{{{        /** Should the build fail? Defaults to false. As attribute. */ }}}
-{{{        boolean fail = false; }}}
-{{{        public void setFail(boolean b) { }}}
-{{{            fail = b; }}}
-{{{        } }}}
-{{{     }}}
-{{{        /** Support for nested text. */ }}}
-{{{        public void addText(String text) { }}}
-{{{            message = text; }}}
-{{{        } }}}
-{{{     }}}
-{{{     }}}
-{{{        /** Do the work. */ }}}
-{{{        public void execute() { }}}
-{{{            // handle attribute 'fail' }}}
-{{{            if (fail) throw new BuildException("Fail requested."); }}}
-{{{     }}}
-{{{            // handle attribute 'message' and nested text }}}
-{{{            if (message!=null) log(message); }}}
-{{{     }}}
-{{{            // handle nested elements }}}
-{{{            for (Iterator it=messages.iterator(); it.hasNext(); ) { }}}
-{{{                Message msg = (Message)it.next(); }}}
-{{{                log(msg.getMsg()); }}}
-{{{            } }}}
-{{{        } }}}
-{{{     }}}
-{{{     }}}
-{{{        /** Store nested 'message's. */ }}}
-{{{        Vector messages = new Vector(); }}}
-{{{     }}}
-{{{        /** Factory method for creating nested 'message's. */ }}}
-{{{        public Message createMessage() { }}}
-{{{            Message msg = new Message(); }}}
-{{{            messages.add(msg); }}}
-{{{            return msg; }}}
-{{{        } }}}
-{{{     }}}
-{{{        /** A nested 'message'. */ }}}
-{{{        public class Message { }}}
-{{{            // Bean constructor }}}
-{{{            public Message() {} }}}
-{{{     }}}
-{{{            /** Message to print. */ }}}
-{{{            String msg; }}}
-{{{            public void setMsg(String msg) { this.msg = msg; } }}}
-{{{            public String getMsg() { return msg; } }}}
-{{{        } }}}
-{{{     }}}
-{{{    } }}}
-{{{     }}}
+{{{
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+import java.util.Vector;
+import java.util.Iterator;
+
+/**
+ * The task of the tutorial.
+ * Print a message or let the build fail.
+ * @author Jan Matčrne
+ * @since 2003-08-19
+ */
+public class HelloWorld extends Task {
+
+
+    /** The message to print. As attribute. */
+    String message;
+    public void setMessage(String msg) {
+        message = msg;
+    }
+
+    /** Should the build fail? Defaults to false. As attribute. */
+    boolean fail = false;
+    public void setFail(boolean b) {
+        fail = b;
+    }
+
+    /** Support for nested text. */
+    public void addText(String text) {
+        message = text;
+    }
+
+
+    /** Do the work. */
+    public void execute() {
+        // handle attribute 'fail'
+        if (fail) throw new BuildException("Fail requested.");
+
+        // handle attribute 'message' and nested text
+        if (message!=null) log(message);
+
+        // handle nested elements
+        for (Iterator it=messages.iterator(); it.hasNext(); ) {
+            Message msg = (Message)it.next();
+            log(msg.getMsg());
+        }
+    }
+
+
+    /** Store nested 'message's. */
+    Vector messages = new Vector();
+
+    /** Factory method for creating nested 'message's. */
+    public Message createMessage() {
+        Message msg = new Message();
+        messages.add(msg);
+        return msg;
+    }
+
+    /** A nested 'message'. */
+    public class Message {
+        // Bean constructor
+        public Message() {}
+
+        /** Message to print. */
+        String msg;
+        public void setMsg(String msg) { this.msg = msg; }
+        public String getMsg() { return msg; }
+    }
+
+}
+}}}
+
 And it works: 
 
-{{{    C:\tmp\anttests\MyFirstTask>ant }}}
-{{{    Buildfile: build.xml }}}
-{{{     }}}
-{{{    compile: }}}
-{{{       ["mkdir"] Created dir: C:\tmp\anttests\MyFirstTask\classes }}}
-{{{       ["javac"] Compiling 1 source file to 
C:\tmp\anttests\MyFirstTask\classes }}}
-{{{     }}}
-{{{    jar: }}}
-{{{         ["jar"] Building jar: C:\tmp\anttests\MyFirstTask\MyTask.jar }}}
-{{{     }}}
-{{{    use.init: }}}
-{{{     }}}
-{{{    use.without: }}}
-{{{     }}}
-{{{    use.message: }}}
-{{{   ["helloworld"] attribute-text }}}
-{{{     }}}
-{{{    use.nestedText: }}}
-{{{   ["helloworld"] nested-text }}}
-{{{     }}}
-{{{    use.nestedElement: }}}
-{{{   ["helloworld"] }}}
-{{{   ["helloworld"] }}}
-{{{   ["helloworld"] }}}
-{{{   ["helloworld"] }}}
-{{{   ["helloworld"] Nested Element 1 }}}
-{{{   ["helloworld"] Nested Element 2 }}}
-{{{     }}}
-{{{    use: }}}
-{{{     }}}
-{{{    BUILD SUCCESSFUL }}}
-{{{    Total time: 3 seconds }}}
-{{{    C:\tmp\anttests\MyFirstTask>ant use.fail }}}
-{{{    Buildfile: build.xml }}}
-{{{     }}}
-{{{    compile: }}}
-{{{     }}}
-{{{    jar: }}}
-{{{     }}}
-{{{    use.init: }}}
-{{{     }}}
-{{{    use.fail: }}}
-{{{     }}}
-{{{    BUILD FAILED }}}
-{{{    C:\tmp\anttests\MyFirstTask\build.xml:36: Fail requested. }}}
-{{{     }}}
-{{{    Total time: 1 second }}}
-{{{    C:\tmp\anttests\MyFirstTask> }}}
-{{{     }}}
+{{{
+C:\tmp\anttests\MyFirstTask>ant
+Buildfile: build.xml
+
+compile:
+    [mkdir] Created dir: C:\tmp\anttests\MyFirstTask\classes
+    [javac] Compiling 1 source file to C:\tmp\anttests\MyFirstTask\classes
+
+jar:
+      [jar] Building jar: C:\tmp\anttests\MyFirstTask\MyTask.jar
+
+use.init:
+
+use.without:
+
+use.message:
+[helloworld] attribute-text
+
+use.nestedText:
+[helloworld] nested-text
+
+use.nestedElement:
+[helloworld]
+[helloworld]
+[helloworld]
+[helloworld]
+[helloworld] Nested Element 1
+[helloworld] Nested Element 2
+
+use:
+
+BUILD SUCCESSFUL
+Total time: 3 seconds
+C:\tmp\anttests\MyFirstTask>ant use.fail
+Buildfile: build.xml
+
+compile:
+
+jar:
+
+use.init:
+
+use.fail:
+
+BUILD FAILED
+C:\tmp\anttests\MyFirstTask\build.xml:36: Fail requested.
+
+Total time: 1 second
+C:\tmp\anttests\MyFirstTask>
+}}}
+
 Next step: test ... 
 
 == Test the Task ==
@@ -461,137 +497,143 @@
 
 For executing the test and creating a report we need the optional tasks 
<junit> and <junitreport>. So we add to the buildfile: 
 
-{{{    ... }}}
-{{{    <project name="MyTask" basedir="." '''default="test"'''> }}}
-{{{    ... }}}
-{{{        '''<property name="ant.test.lib" value="ant-testutil.jar"/>''' }}}
-{{{        <property name="report.dir"   value="report"/> }}}
-{{{        <property name="junit.out.dir.xml"  
value="${report.dir}/junit/xml"/> }}}
-{{{        <property name="junit.out.dir.html" 
value="${report.dir}/junit/html"/> }}}
-{{{     }}}
-{{{        <path id="classpath.run"> }}}
-{{{            <path path="${java.class.path}"/> }}}
-{{{            <path location="${ant.project.name}.jar"/> }}}
-{{{        </path> }}}
-{{{     }}}
-{{{        <path id="classpath.test"> }}}
-{{{            <path refid="classpath.run"/> }}}
-{{{            <path location="${ant.test.lib}"/> }}}
-{{{        </path> }}}
-{{{     }}}
-{{{        <target name="clean" description="Delete all generated files"> }}}
-{{{            <delete failonerror="false" includeEmptyDirs="true"> }}}
-{{{                <fileset dir="." includes="${ant.project.name}.jar"/> }}}
-{{{                <fileset dir="${classes.dir}"/> }}}
-{{{                <fileset dir="${report.dir}"/> }}}
-{{{            </delete> }}}
-{{{        </target> }}}
-{{{     }}}
-{{{        <target name="compile" description="Compiles the Task"> }}}
-{{{            <mkdir dir="${classes.dir}"/> }}}
-{{{            <javac srcdir="${src.dir}" destdir="${classes.dir}" 
'''classpath="${ant.test.lib}"'''/> }}}
-{{{        </target> }}}
-{{{    ... }}}
-{{{        <target name="junit" description="Runs the unit tests" 
depends="jar"> }}}
-{{{            <delete dir="${junit.out.dir.xml}" /> }}}
-{{{            <mkdir  dir="${junit.out.dir.xml}" /> }}}
-{{{            <junit printsummary="yes" haltonfailure="no"> }}}
-{{{                <classpath refid="classpath.test"/> }}}
-{{{                <formatter type="xml"/> }}}
-{{{                <batchtest fork="yes" todir="${junit.out.dir.xml}"> }}}
-{{{                    <fileset dir="${src.dir}" includes="**/*Test.java"/> }}}
-{{{                </batchtest> }}}
-{{{            </junit> }}}
-{{{        </target> }}}
-{{{     }}}
-{{{        <target name="junitreport" description="Create a report for the 
rest result"> }}}
-{{{            <mkdir dir="${junit.out.dir.html}" /> }}}
-{{{            <junitreport todir="${junit.out.dir.html}"> }}}
-{{{                <fileset dir="${junit.out.dir.xml}"> }}}
-{{{                    <include name="*.xml"/> }}}
-{{{                </fileset> }}}
-{{{                <report format="frames" todir="${junit.out.dir.html}"/> }}}
-{{{            </junitreport> }}}
-{{{        </target> }}}
-{{{     }}}
-{{{        <target name="test" }}}
-{{{                depends="junit,junitreport" }}}
-{{{                description="Runs unit tests and creates a report" }}}
-{{{        /> }}}
-{{{    ... }}}
-{{{     }}}
+{{{
+...
+<project name="MyTask" basedir="." default="test">
+...
+    <property name="ant.test.lib" value="ant-testutil.jar"/>
+    <property name="report.dir"   value="report"/>
+    <property name="junit.out.dir.xml"  value="${report.dir}/junit/xml"/>
+    <property name="junit.out.dir.html" value="${report.dir}/junit/html"/>
+
+    <path id="classpath.run">
+        <path path="${java.class.path}"/>
+        <path location="${ant.project.name}.jar"/>
+    </path>
+
+    <path id="classpath.test">
+        <path refid="classpath.run"/>
+        <path location="${ant.test.lib}"/>
+    </path>
+
+    <target name="clean" description="Delete all generated files">
+        <delete failonerror="false" includeEmptyDirs="true">
+            <fileset dir="." includes="${ant.project.name}.jar"/>
+            <fileset dir="${classes.dir}"/>
+            <fileset dir="${report.dir}"/>
+        </delete>
+    </target>
+
+    <target name="compile" description="Compiles the Task">
+        <mkdir dir="${classes.dir}"/>
+        <javac srcdir="${src.dir}" destdir="${classes.dir}" 
classpath="${ant.test.lib}"/>
+    </target>
+...
+    <target name="junit" description="Runs the unit tests" depends="jar">
+        <delete dir="${junit.out.dir.xml}" />
+        <mkdir  dir="${junit.out.dir.xml}" />
+        <junit printsummary="yes" haltonfailure="no">
+            <classpath refid="classpath.test"/>
+            <formatter type="xml"/>
+            <batchtest fork="yes" todir="${junit.out.dir.xml}">
+                <fileset dir="${src.dir}" includes="**/*Test.java"/>
+            </batchtest>
+        </junit>
+    </target>
+
+    <target name="junitreport" description="Create a report for the rest 
result">
+        <mkdir dir="${junit.out.dir.html}" />
+        <junitreport todir="${junit.out.dir.html}">
+            <fileset dir="${junit.out.dir.xml}">
+                <include name="*.xml"/>
+            </fileset>
+            <report format="frames" todir="${junit.out.dir.html}"/>
+        </junitreport>
+    </target>
+
+    <target name="test"
+            depends="junit,junitreport"
+            description="Runs unit tests and creates a report"
+    />
+...
+}}}
+
 Back to the ''src/HelloWorldTest.java''. We create a class extending 
''BuildFileTest'' with String-constructor (JUnit-standard), a ''setUp()'' 
method initializing Ant and for each testcase (targets use.*) a ''testXX()'' 
method invoking that target. 
 
-{{{    import org.apache.tools.ant.BuildFileTest; }}}
-{{{     }}}
-{{{    public class HelloWorldTest extends BuildFileTest { }}}
-{{{     }}}
-{{{        public HelloWorldTest(String s) { }}}
-{{{            super(s); }}}
-{{{        } }}}
-{{{     }}}
-{{{        public void setUp() { }}}
-{{{            // initialize Ant }}}
-{{{            configureProject("build.xml"); }}}
-{{{        } }}}
-{{{     }}}
-{{{        public void testWithout() { }}}
-{{{            executeTarget("use.without"); }}}
-{{{            assertEquals("Message was logged but should not.", getLog(), 
''''''); }}}
-{{{        } }}}
-{{{     }}}
-{{{        public void testMessage() { }}}
-{{{            // execute target 'use.nestedText' and expect a message }}}
-{{{            // 'attribute-text' in the log }}}
-{{{            expectLog("use.message", "attribute-text"); }}}
-{{{        } }}}
-{{{     }}}
-{{{        public void testFail() { }}}
-{{{            // execute target 'use.fail' and expect a BuildException }}}
-{{{            // with text 'Fail requested.' }}}
-{{{            expectBuildException("use.fail", "Fail requested."); }}}
-{{{        } }}}
-{{{     }}}
-{{{        public void testNestedText() { }}}
-{{{            expectLog("use.nestedText", "nested-text"); }}}
-{{{        } }}}
-{{{     }}}
-{{{        public void testNestedElement() { }}}
-{{{            executeTarget("use.nestedElement"); }}}
-{{{            assertLogContaining("Nested Element 1"); }}}
-{{{            assertLogContaining("Nested Element 2"); }}}
-{{{        } }}}
-{{{    } }}}
-{{{     }}}
+{{{
+import org.apache.tools.ant.BuildFileTest;
+
+public class HelloWorldTest extends BuildFileTest {
+
+    public HelloWorldTest(String s) {
+        super(s);
+    }
+
+    public void setUp() {
+        // initialize Ant
+        configureProject("build.xml");
+    }
+
+    public void testWithout() {
+        executeTarget("use.without");
+        assertEquals("Message was logged but should not.", getLog(), "");
+    }
+
+    public void testMessage() {
+        // execute target 'use.nestedText' and expect a message
+        // 'attribute-text' in the log
+        expectLog("use.message", "attribute-text");
+    }
+
+    public void testFail() {
+        // execute target 'use.fail' and expect a BuildException
+        // with text 'Fail requested.'
+        expectBuildException("use.fail", "Fail requested.");
+    }
+
+    public void testNestedText() {
+        expectLog("use.nestedText", "nested-text");
+    }
+
+    public void testNestedElement() {
+        executeTarget("use.nestedElement");
+        assertLogContaining("Nested Element 1");
+        assertLogContaining("Nested Element 2");
+    }
+}
+}}}
+
 When starting {{{ ant }}} weīll get a short message to STDOUT and a nice 
HTML-report. 
 
-{{{    C:\tmp\anttests\MyFirstTask>ant }}}
-{{{    Buildfile: build.xml }}}
-{{{     }}}
-{{{    compile: }}}
-{{{       ["mkdir"] Created dir: C:\tmp\anttests\MyFirstTask\classes }}}
-{{{       ["javac"] Compiling 2 source files to 
C:\tmp\anttests\MyFirstTask\classes }}}
-{{{     }}}
-{{{    jar: }}}
-{{{         ["jar"] Building jar: C:\tmp\anttests\MyFirstTask\MyTask.jar }}}
-{{{     }}}
-{{{    junit: }}}
-{{{       ["mkdir"] Created dir: C:\tmp\anttests\MyFirstTask\report\junit\xml 
}}}
-{{{       ["junit"] Running HelloWorldTest }}}
-{{{       ["junit"] Tests run: 5, Failures: 0, Errors: 0, Time elapsed: 2,334 
sec }}}
-{{{     }}}
-{{{     }}}
-{{{     }}}
-{{{    junitreport: }}}
-{{{       ["mkdir"] Created dir: C:\tmp\anttests\MyFirstTask\report\junit\html 
}}}
-{{{   ["junitreport"] Using Xalan version: Xalan Java 2.4.1 }}}
-{{{   ["junitreport"] Transform time: 661ms }}}
-{{{     }}}
-{{{    test: }}}
-{{{     }}}
-{{{    BUILD SUCCESSFUL }}}
-{{{    Total time: 7 seconds }}}
-{{{    C:\tmp\anttests\MyFirstTask> }}}
+{{{
+:\tmp\anttests\MyFirstTask>ant
+Buildfile: build.xml
+
+compile:
+    [mkdir] Created dir: C:\tmp\anttests\MyFirstTask\classes
+    [javac] Compiling 2 source files to C:\tmp\anttests\MyFirstTask\classes
+
+jar:
+      [jar] Building jar: C:\tmp\anttests\MyFirstTask\MyTask.jar
+
+junit:
+    [mkdir] Created dir: C:\tmp\anttests\MyFirstTask\report\junit\xml
+    [junit] Running HelloWorldTest
+    [junit] Tests run: 5, Failures: 0, Errors: 0, Time elapsed: 2,334 sec
+
+
+
+junitreport:
+    [mkdir] Created dir: C:\tmp\anttests\MyFirstTask\report\junit\html
+[junitreport] Using Xalan version: Xalan Java 2.4.1
+[junitreport] Transform time: 661ms
+
+test:
+
+BUILD SUCCESSFUL
+Total time: 7 seconds
+C:\tmp\anttests\MyFirstTask>
+}}}
 
 == Resources ==
 This tutorial and its resources are available via 
[http://nagoya.apache.org/bugzilla/show_bug.cgi?id=22570 BugZilla [6]]. The ZIP 
provided there contains
@@ -604,11 +646,13 @@
  *  generated jar 
  *  generated reports 
 
-Used Links:
-{{{  [1] http://ant.apache.org/manual/using.html#built-in-props }}}
-{{{  [2] http://ant.apache.org/manual/CoreTasks/taskdef.html }}}
-{{{  [3] http://ant.apache.org/manual/develop.html#set-magic }}}
-{{{  [4] http://ant.apache.org/manual/develop.html#nested-elements }}}
-{{{  [5] http://gump.covalent.net/jars/latest/ant/ant-testutil.jar }}}
-{{{  [6] http://nagoya.apache.org/bugzilla/show_bug.cgi?id=22570 }}}
+{{{Used Links:
+
+[1] http://ant.apache.org/manual/using.html#built-in-props 
+[2] http://ant.apache.org/manual/CoreTasks/taskdef.html 
+[3] http://ant.apache.org/manual/develop.html#set-magic 
+[4] http://ant.apache.org/manual/develop.html#nested-elements 
+[5] http://gump.covalent.net/jars/latest/ant/ant-testutil.jar 
+[6] http://nagoya.apache.org/bugzilla/show_bug.cgi?id=22570 
+}}}
 

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to