|
- <html>
-
- <head>
- <meta http-equiv="Content-Language" content="en-us">
- <title>Writing Your Own Task</title>
- </head>
-
- <body>
- <h1>Developing with Ant</h1>
-
- <h2><a name="writingowntask">Writing Your Own Task</a></h2>
- <p>It is very easy to write your own task:</p>
- <ol>
- <li>Create a Java class that extends <code>org.apache.tools.ant.Task</code>
- or <a href="base_task_classes.html">another class</a> that was desgined to be extended.</li>
- <li>For each attribute, write a <i>setter</i> method. The setter method must be a
- <code>public void</code> method that takes a single argument. The
- name of the method must begin with <code>set</code>, followed by the
- attribute name, with the first character of the name in uppercase, and the rest in
-
- lowercase. That is, to support an attribute named
- <code>file</code> you create a method <code>setFile</code>.
- Depending on the type of the argument, Ant will perform some
- conversions for you, see <a href="#set-magic">below</a>.</li>
-
- <li>If your task shall contain other tasks as nested elements (like
- <a href="CoreTasks/parallel.html"><code>parallel</code></a>), your
- class must implement the interface
- <code>org.apache.tools.ant.TaskContainer</code>. If you do so, your
- task can not support any other nested elements. See
- <a href="#taskcontainer">below</a>.</li>
-
- <li>If the task should support character data (text nested between the
- start end end tags), write a <code>public void addText(String)</code>
- method. Note that Ant does <strong>not</strong> expand properties on
- the text it passes to the task.</li>
-
- <li>For each nested element, write a <i>create</i>, <i>add</i> or
- <i>addConfigured</i> method. A create method must be a
- <code>public</code> method that takes no arguments and returns an
- <code>Object</code> type. The name of the create method must begin
- with <code>create</code>, followed by the element name. An add (or
- addConfigured) method must be a <code>public void</code> method that
- takes a single argument of an <code>Object</code> type with a
- no-argument constructor. The name of the add (addConfigured) method
- must begin with <code>add</code> (<code>addConfigured</code>),
- followed by the element name. For a more complete discussion see
- <a href="#nested-elements">below</a>.</li>
-
- <li>Write a <code>public void execute</code> method, with no arguments, that
- throws a <code>BuildException</code>. This method implements the task
- itself.</li>
- </ol>
-
- <h3>The Life-cycle of a Task</h3>
- <ol>
- <li>The task gets instantiated using a no-argument constructor, at parser
- time. This means even tasks that are never executed get
- instantiated.</li>
-
- <li>The task gets references to its project and location inside the
- buildfile via its inherited <code>project</code> and
- <code>location</code> variables.</li>
-
- <li>If the user specified an <code>id</code> attribute to this task,
- the project
- registers a reference to this newly created task, at parser
- time.</li>
-
- <li>The task gets a reference to the target it belongs to via its
- inherited <code>target</code> variable.</li>
-
- <li><code>init()</code> is called at parser time.</li>
-
- <li>All child elements of the XML element corresponding to this task
- are created via this task's <code>createXXX()</code> methods or
- instantiated and added to this task via its <code>addXXX()</code>
- methods, at parser time.</li>
-
- <li>All attributes of this task get set via their corresponding
- <code>setXXX</code> methods, at runtime.</li>
-
- <li>The content character data sections inside the XML element
- corresponding to this task is added to the task via its
- <code>addText</code> method, at runtime.</li>
-
- <li>All attributes of all child elements get set via their corresponding
- <code>setXXX</code> methods, at runtime.</li>
-
- <li><a name="execute"><code>execute()</code></a> is called at runtime. While the above initialization
- steps only occur once, the execute() method may be
- called more than once, if the task is invoked more than once. For example,
- if <code>target1</code> and <code>target2</code> both depend
- on <code>target3</code>, then running
- <code>'ant target1 target2'</code> will run all tasks in
- <code>target3</code> twice.</li>
- </ol>
-
- <h3><a name="set-magic">Conversions Ant will perform for attributes</a></h3>
-
- <p>Ant will always expand properties before it passes the value of an
- attribute to the corresponding setter method.</p>
-
- <p>The most common way to write an attribute setter is to use a
- <code>java.lang.String</code> argument. In this case Ant will pass
- the literal value (after property expansion) to your task. But there
- is more! If the argument of you setter method is</p>
-
- <ul>
-
- <li><code>boolean</code>, your method will be passed the value
- <i>true</i> if the value specified in the build file is one of
- <code>true</code>, <code>yes</code>, or <code>on</code> and
- <i>false</i> otherwise.</li>
-
- <li><code>char</code> or <code>java.lang.Character</code>, your
- method will be passed the first character of the value specified in
- the build file.</li>
-
- <li>any other primitive type (<code>int</code>, <code>short</code>
- and so on), Ant will convert the value of the attribute into this
- type, thus making sure that you'll never receive input that is not a
- number for that attribute.</li>
-
- <li><code>java.io.File</code>, Ant will first determine whether the
- value given in the build file represents an absolute path name. If
- not, Ant will interpret the value as a path name relative to the
- project's basedir.</li>
-
- <li><code>org.apache.tools.ant.types.Path</code>, Ant will tokenize
- the value specified in the build file, accepting <code>:</code> and
- <code>;</code> as path separators. Relative path names will be
- interpreted as relative to the project's basedir.</li>
-
- <li><code>java.lang.Class</code>, Ant will interpret the value
- given in the build file as a Java class name and load the named
- class from the system class loader.</li>
-
- <li>any other type that has a constructor with a single
- <code>String</code> argument, Ant will use this constructor to
- create a new instance from the value given in the build file.</li>
-
- <li>A subclass of
- <code>org.apache.tools.ant.types.EnumeratedAttribute</code>, Ant
- will invoke this classes <code>setValue</code> method. Use this if
- your task should support enumerated attributes (attributes with
- values that must be part of a predefined set of values). See
- <code>org/apache/tools/ant/taskdefs/FixCRLF.java</code> and the
- inner <code>AddAsisRemove</code> class used in <code>setCr</code>
- for an example.</li>
-
- </ul>
-
- <p>What happens if more than one setter method is present for a given
- attribute? A method taking a <code>String</code> argument will always
- lose against the more specific methods. If there are still more
- setters Ant could chose from, only one of them will be called, but we
- don't know which, this depends on the implementation of your Java
- virtual machine.</p>
-
- <h3><a name="nested-elements">Supporting nested elements</a></h3>
-
- <p>Let's assume your task shall support nested elements with the name
- <code>inner</code>. First of all, you need a class that represents
- this nested element. Often you simply want to use one of Ant's
- classes like <code>org.apache.tools.ant.types.FileSet</code> to
- support nested <code>fileset</code> elements.</p>
-
- <p>Attributes of the nested elements or nested child elements of them
- will be handled using the same mechanism used for tasks (i.e. setter
- methods for attributes, addText for nested text and
- create/add/addConfigured methods for child elements).</p>
-
- <p>Now you have a class <code>NestedElement</code> that is supposed to
- be used for your nested <code><inner></code> elements, you have
- three options:</p>
-
- <ol>
- <li><code>public NestedElement createInner()</code></li>
- <li><code>public void addInner(NestedElement anInner)</code></li>
- <li><code>public void addConfiguredInner(NestedElement anInner)</code></li>
- </ol>
-
- <p>What is the difference?</p>
-
- <p>Option 1 makes the task create the instance of
- <code>NestedElement</code>, there are no restrictions on the type.
- For the options 2 and 3, Ant has to create an instance of
- <code>NestedInner</code> before it can pass it to the task, this
- means, <code>NestedInner</code> must have a <code>public</code> no-arg
- constructor. This is the only difference between options 1 and 2.</p>
-
- <p>The difference between 2 and 3 is what Ant has done to the object
- before it passes it to the method. <code>addInner</code> will receive
- an object directly after the constructor has been called, while
- <code>addConfiguredInner</code> gets the object <em>after</em> the
- attributes and nested children for this new object have been
- handled.</p>
-
- <p>What happens if you use more than one of the options? Only one of
- the methods will be called, but we don't know which, this depends on
- the implementation of your Java virtual machine.</p>
-
- <h3><a name="taskcontainer">TaskContainer</a></h3>
-
- <p>The <code>TaskContainer</code> consists of a single method,
- <code>addTask</code> that basically is the same as an <a
- href="#nested-elements">add method</a> for nested elements. The task
- instances will be configured (their attributes and nested elements
- have been handled) when your task's <code>execute</code> method gets
- invoked, but not before that.</p>
-
- <p>When we <a href="#execute">said</a> <code>execute</code> would be
- called, we lied ;-). In fact, Ant will call the <code>perform</code>
- method in <code>org.apache.tools.ant.Task</code>, which in turn calls
- <code>execute</code>. This method makes sure that <a
- href="#buildevents">Build Events</a> will be triggered. If you
- execute the task instances nested into your task, you should also
- invoke <code>perform</code> on these instances instead of
- <code>execute</code>.</p>
-
- <h3>Example</h3>
- <p>Let's write our own task, which prints a message on the
- <code>System.out</code> stream.
- The
- task has one attribute, called <code>message</code>.</p>
- <blockquote>
- <pre>
- package com.mydomain;
-
- import org.apache.tools.ant.BuildException;
- import org.apache.tools.ant.Task;
-
- public class MyVeryOwnTask extends Task {
- private String msg;
-
- // The method executing the task
- public void execute() throws BuildException {
- System.out.println(msg);
- }
-
- // The setter for the "message" attribute
- public void setMessage(String msg) {
- this.msg = msg;
- }
- }
- </pre>
- </blockquote>
- <p>It's really this simple ;-)</p>
- <p>Adding your task to the system is rather simple too:</p>
- <ol>
- <li>Make sure the class that implements your task is in the classpath when
- starting Ant.</li>
- <li>Add a <code><taskdef></code> element to your project.
- This actually adds your task to the system.</li>
- <li>Use your task in the rest of the buildfile.</li>
- </ol>
-
-
- <h3>Example</h3>
- <blockquote>
- <pre>
- <?xml version="1.0"?>
-
- <project name="OwnTaskExample" default="main" basedir=".">
- <taskdef name="mytask" classname="com.mydomain.MyVeryOwnTask"/>
-
- <target name="main">
- <mytask message="Hello World! MyVeryOwnTask works!"/>
- </target>
- </project>
- </pre>
- </blockquote>
- <h3>Example 2</h3>
- To use a task directly from the buildfile which created it, place the
- <code><taskdef></code> declaration inside a target
- <i>after the compilation</i>. Use the <code>classpath</code> attribute of
- <code><taskdef></code> to point to where the code has just been
- compiled.
- <blockquote>
- <pre>
- <?xml version="1.0"?>
-
- <project name="OwnTaskExample2" default="main" basedir=".">
-
- <target name="build" >
- <mkdir dir="build"/>
- <javac srcdir="source" destdir="build"/>
- </target>
-
- <target name="declare" depends="build">
- <taskdef name="mytask"
- classname="com.mydomain.MyVeryOwnTask"
- classpath="build"/>
- </target>
-
- <target name="main" depends="declare">
- <mytask message="Hello World! MyVeryOwnTask works!"/>
- </target>
- </project>
- </pre>
- </blockquote>
-
-
- <p>Another way to add a task (more permanently), is to add the task name and
- implementing class name to the <code>default.properties</code> file in the
- <code>org.apache.tools.ant.taskdefs</code>
- package. Then you can use it as if it were a built-in task.</p>
-
- <hr>
- <h2><a name="buildevents">Build Events</a></h2>
- <P>Ant is capable of generating build events as it performs the tasks necessary to build a project.
- Listeners can be attached to Ant to receive these events. This capability could be used, for example,
- to connect Ant to a GUI or to integrate Ant with an IDE.
- </P>
- <p>To use build events you need to create an ant <code>Project</code> object. You can then call the
- <code>addBuildListener</code> method to add your listener to the project. Your listener must implement
- the <code>org.apache.tools.antBuildListener</code> interface. The listener will receive BuildEvents
- for the following events</P>
- <ul>
- <li>Build started</li>
- <li>Build finished</li>
- <li>Target started</li>
- <li>Target finished</li>
- <li>Task started</li>
- <li>Task finished</li>
- <li>Message logged</li>
- </ul>
-
- <p>
- If you wish to attach a listener from the command line you may use the
- <code>-listener</code> option. For example:</p>
- <blockquote>
- <pre>ant -listener org.apache.tools.ant.XmlLogger</pre>
- </blockquote>
- <p>will run Ant with a listener that generates an XML representation of the build progress. This
- listener is included with Ant, as is the default listener, which generates the logging to standard output.</p>
-
- <hr>
- <h2><a name="integration">Source code integration</a></h2>
-
-
- The other way to extend Ant through Java is to make changes to existing tasks, which is positively encouraged.
- Both changes to the existing source and new tasks can be incorporated back into the Ant codebase, which
- benefits all users and spreads the maintenance load around.
- <p>
-
- Please consult the
- <a href="http://jakarta.apache.org/site/getinvolved.html">Getting Involved</a> pages on the Jakarta web site
- for details on how to fetch the latest source and how to submit changes for reincorporation into the
- source tree.
- <p>
- Ant also has some
- <a href="http://jakarta.apache.org/ant/ant_task_guidelines.html">task guidelines</a>
- which provides some advice to people developing and testing tasks. Even if you intend to
- keep your tasks to yourself, you should still read this as it should be informative.
-
- <hr>
- <p align="center">Copyright © 2000-2002 Apache Software Foundation. All rights
- Reserved.</p>
-
- </body>
- </html>
|