source: other-projects/trunk/realistic-books/packages/AntInstaller/web/manual1.6.2/manual/develop.html@ 19253

Last change on this file since 19253 was 19253, checked in by davidb, 15 years ago

Establishing a source code repository for Veronica's Realistic Book's software

File size: 19.0 KB
Line 
1<html>
2
3<head>
4<meta http-equiv="Content-Language" content="en-us">
5<title>Writing Your Own Task</title>
6<link rel="stylesheet" type="text/css" href="stylesheets/antmanual.css">
7</head>
8
9<body>
10<h1>Developing with Ant</h1>
11
12<h2><a name="writingowntask">Writing Your Own Task</a></h2>
13<p>It is very easy to write your own task:</p>
14<ol>
15 <li>Create a Java class that extends <code>org.apache.tools.ant.Task</code>
16 or <a href="base_task_classes.html">another class</a> that was desgined to be extended.</li>
17 <li>For each attribute, write a <i>setter</i> method. The setter method must be a
18 <code>public void</code> method that takes a single argument. The
19 name of the method must begin with <code>set</code>, followed by the
20 attribute name, with the first character of the name in uppercase, and the rest in
21
22 lowercase<a href="#footnote-1"><sup>*</sup></a>. That is, to support an attribute named
23 <code>file</code> you create a method <code>setFile</code>.
24 Depending on the type of the argument, Ant will perform some
25 conversions for you, see <a href="#set-magic">below</a>.</li>
26
27 <li>If your task shall contain other tasks as nested elements (like
28 <a href="CoreTasks/parallel.html"><code>parallel</code></a>), your
29 class must implement the interface
30 <code>org.apache.tools.ant.TaskContainer</code>. If you do so, your
31 task can not support any other nested elements. See
32 <a href="#taskcontainer">below</a>.</li>
33
34<li>If the task should support character data (text nested between the
35start end end tags), write a <code>public void addText(String)</code>
36method. Note that Ant does <strong>not</strong> expand properties on
37the text it passes to the task.</li>
38
39<li>For each nested element, write a <i>create</i>, <i>add</i> or
40<i>addConfigured</i> method. A create method must be a
41<code>public</code> method that takes no arguments and returns an
42<code>Object</code> type. The name of the create method must begin
43with <code>create</code>, followed by the element name. An add (or
44addConfigured) method must be a <code>public void</code> method that
45takes a single argument of an <code>Object</code> type with a
46no-argument constructor. The name of the add (addConfigured) method
47must begin with <code>add</code> (<code>addConfigured</code>),
48followed by the element name. For a more complete discussion see
49<a href="#nested-elements">below</a>.</li>
50
51<li>Write a <code>public void execute</code> method, with no arguments, that
52throws a <code>BuildException</code>. This method implements the task
53itself.</li>
54</ol>
55
56<hr>
57<p><a name="footnote-1">*</a> Actually the case of the letters after
58the first one doesn't really matter to Ant, using all lower case is a
59good convention, though.</p>
60
61<h3>The Life-cycle of a Task</h3>
62<ol>
63 <li>The task gets instantiated using a no-argument constructor, at parser
64 time. This means even tasks that are never executed get
65 instantiated.</li>
66
67 <li>The task gets references to its project and location inside the
68 buildfile via its inherited <code>project</code> and
69 <code>location</code> variables.</li>
70
71 <li>If the user specified an <code>id</code> attribute to this task,
72 the project
73 registers a reference to this newly created task, at parser
74 time.</li>
75
76 <li>The task gets a reference to the target it belongs to via its
77 inherited <code>target</code> variable.</li>
78
79 <li><code>init()</code> is called at parser time.</li>
80
81 <li>All child elements of the XML element corresponding to this task
82 are created via this task's <code>createXXX()</code> methods or
83 instantiated and added to this task via its <code>addXXX()</code>
84 methods, at parser time.</li>
85
86 <li>All attributes of this task get set via their corresponding
87 <code>setXXX</code> methods, at runtime.</li>
88
89 <li>The content character data sections inside the XML element
90 corresponding to this task is added to the task via its
91 <code>addText</code> method, at runtime.</li>
92
93 <li>All attributes of all child elements get set via their corresponding
94 <code>setXXX</code> methods, at runtime.</li>
95
96 <li><a name="execute"><code>execute()</code></a> is called at runtime. While the above initialization
97 steps only occur once, the execute() method may be
98 called more than once, if the task is invoked more than once. For example,
99 if <code>target1</code> and <code>target2</code> both depend
100 on <code>target3</code>, then running
101 <code>'ant target1 target2'</code> will run all tasks in
102 <code>target3</code> twice.</li>
103</ol>
104
105<a name="set-magic"></a><h3>Conversions Ant will perform for attributes</h3>
106
107<p>Ant will always expand properties before it passes the value of an
108attribute to the corresponding setter method.</p>
109
110<p>The most common way to write an attribute setter is to use a
111<code>java.lang.String</code> argument. In this case Ant will pass
112the literal value (after property expansion) to your task. But there
113is more! If the argument of you setter method is</p>
114
115<ul>
116
117 <li><code>boolean</code>, your method will be passed the value
118 <i>true</i> if the value specified in the build file is one of
119 <code>true</code>, <code>yes</code>, or <code>on</code> and
120 <i>false</i> otherwise.</li>
121
122 <li><code>char</code> or <code>java.lang.Character</code>, your
123 method will be passed the first character of the value specified in
124 the build file.</li>
125
126 <li>any other primitive type (<code>int</code>, <code>short</code>
127 and so on), Ant will convert the value of the attribute into this
128 type, thus making sure that you'll never receive input that is not a
129 number for that attribute.</li>
130
131 <li><code>java.io.File</code>, Ant will first determine whether the
132 value given in the build file represents an absolute path name. If
133 not, Ant will interpret the value as a path name relative to the
134 project's basedir.</li>
135
136 <li><code>org.apache.tools.ant.types.Path</code>, Ant will tokenize
137 the value specified in the build file, accepting <code>:</code> and
138 <code>;</code> as path separators. Relative path names will be
139 interpreted as relative to the project's basedir.</li>
140
141 <li><code>java.lang.Class</code>, Ant will interpret the value
142 given in the build file as a Java class name and load the named
143 class from the system class loader.</li>
144
145 <li>any other type that has a constructor with a single
146 <code>String</code> argument, Ant will use this constructor to
147 create a new instance from the value given in the build file.</li>
148
149 <li>A subclass of
150 <code>org.apache.tools.ant.types.EnumeratedAttribute</code>, Ant
151 will invoke this classes <code>setValue</code> method. Use this if
152 your task should support enumerated attributes (attributes with
153 values that must be part of a predefined set of values). See
154 <code>org/apache/tools/ant/taskdefs/FixCRLF.java</code> and the
155 inner <code>AddAsisRemove</code> class used in <code>setCr</code>
156 for an example.</li>
157
158</ul>
159
160<p>What happens if more than one setter method is present for a given
161attribute? A method taking a <code>String</code> argument will always
162lose against the more specific methods. If there are still more
163setters Ant could chose from, only one of them will be called, but we
164don't know which, this depends on the implementation of your Java
165virtual machine.</p>
166
167<a name="nested-elements"></a><h3>Supporting nested elements</h3>
168
169<p>Let's assume your task shall support nested elements with the name
170<code>inner</code>. First of all, you need a class that represents
171this nested element. Often you simply want to use one of Ant's
172classes like <code>org.apache.tools.ant.types.FileSet</code> to
173support nested <code>fileset</code> elements.</p>
174
175<p>Attributes of the nested elements or nested child elements of them
176will be handled using the same mechanism used for tasks (i.e. setter
177methods for attributes, addText for nested text and
178create/add/addConfigured methods for child elements).</p>
179
180<p>Now you have a class <code>NestedElement</code> that is supposed to
181be used for your nested <code>&lt;inner&gt;</code> elements, you have
182three options:</p>
183
184<ol>
185 <li><code>public NestedElement createInner()</code></li>
186 <li><code>public void addInner(NestedElement anInner)</code></li>
187 <li><code>public void addConfiguredInner(NestedElement anInner)</code></li>
188</ol>
189
190<p>What is the difference?</p>
191
192<p>Option 1 makes the task create the instance of
193<code>NestedElement</code>, there are no restrictions on the type.
194For the options 2 and 3, Ant has to create an instance of
195<code>NestedInner</code> before it can pass it to the task, this
196means, <code>NestedInner</code> must have a <code>public</code> no-arg
197 constructor or a <code>public</code> one-arg constructor
198 taking a Project class as a parameter.
199This is the only difference between options 1 and 2.</p>
200
201<p>The difference between 2 and 3 is what Ant has done to the object
202before it passes it to the method. <code>addInner</code> will receive
203an object directly after the constructor has been called, while
204<code>addConfiguredInner</code> gets the object <em>after</em> the
205attributes and nested children for this new object have been
206handled.</p>
207
208<p>What happens if you use more than one of the options? Only one of
209the methods will be called, but we don't know which, this depends on
210the implementation of your Java virtual machine.</p>
211
212 <a name="nestedtype"></a><h3>Nested Types</h3>
213If your task needs to nest an arbitary type that has been defined
214 using &lt;typedef&gt; you have two options.
215 <ol>
216 <li><code>public void add(Type type)</code></li>
217 <li><code>public void addConfigured(Type type)</code></li>
218 </ol>
219 The difference between 1 and 2 is the same as between 2 and 3 in the
220 previous section.
221 <p>
222 For example suppose one wanted to handle objects object of type
223 org.apache.tools.ant.taskdefs.condition.Condition, one may
224 have a class:
225 </p>
226 <blockquote>
227 <pre>
228public class MyTask extends Task {
229 private List conditions = new ArrayList();
230 public void add(Condition c) {
231 conditions.add(c);
232 }
233 public void execute() {
234 // iterator over the conditions
235 }
236}
237 </pre>
238 </blockquote>
239 <p>
240 One may define and use this class like this:
241 </p>
242 <blockquote>
243 <pre>
244&lt;taskdef name="mytask" classname="MyTask" classpath="classes"/&gt;
245&lt;typedef name="condition.equals"
246 classname="org.apache.tools.ant.taskdefs.conditions.Equals"/&gt;
247&lt;mytask&gt;
248 &lt;condition.equals arg1="${debug}" arg2="true"/&gt;
249&lt;/mytask&gt;
250 </pre>
251 </blockquote>
252 <p>
253 A more complicated example follows:
254 </p>
255 <blockquote>
256 <pre>
257public class Sample {
258 public static class MyFileSelector implements FileSelector {
259 public void setAttrA(int a) {}
260 public void setAttrB(int b) {}
261 public void add(Path path) {}
262 public boolean isSelected(File basedir, String filename, File file) {
263 return true;
264 }
265 }
266
267 interface MyInterface {
268 void setVerbose(boolean val);
269 }
270
271 public static class BuildPath extends Path {
272 public BuildPath(Project project) {
273 super(project);
274 }
275
276 public void add(MyInterface inter) {}
277 public void setUrl(String url) {}
278 }
279
280 public static class XInterface implements MyInterface {
281 public void setVerbose(boolean x) {}
282 public void setCount(int c) {}
283 }
284}
285 </pre>
286 </blockquote>
287 <p>
288 This class defines a number of static classes that implement/extend
289 Path, MyFileSelector and MyInterface. These may be defined and used
290 as follows:
291 </p>
292 <pre>
293 <blockquote>
294&lt;typedef name="myfileselector" classname="Sample$MyFileSelector"
295 classpath="classes" loaderref="classes"/&gt;
296&lt;typedef name="buildpath" classname="Sample$BuildPath"
297 classpath="classes" loaderref="classes"/&gt;
298&lt;typedef name="xinterface" classname="Sample$XInterface"
299 classpath="classes" loaderref="classes"/&gt;
300
301&lt;copy todir="copy-classes"&gt;
302 &lt;fileset dir="classes"&gt;
303 &lt;myfileselector attra="10" attrB="-10"&gt;
304 &lt;buildpath path="." url="abc"&gt;
305 &lt;xinterface count="4"/&gt;
306 &lt;/buildpath&gt;
307 &lt;/myfileselector&gt;
308 &lt;/fileset&gt;
309&lt;/copy&gt;
310 </blockquote>
311 </pre>
312<a name="taskcontainer"></a><h3>TaskContainer</h3>
313
314<p>The <code>TaskContainer</code> consists of a single method,
315<code>addTask</code> that basically is the same as an <a
316href="#nested-elements">add method</a> for nested elements. The task
317instances will be configured (their attributes and nested elements
318have been handled) when your task's <code>execute</code> method gets
319invoked, but not before that.</p>
320
321<p>When we <a href="#execute">said</a> <code>execute</code> would be
322called, we lied ;-). In fact, Ant will call the <code>perform</code>
323method in <code>org.apache.tools.ant.Task</code>, which in turn calls
324<code>execute</code>. This method makes sure that <a
325href="#buildevents">Build Events</a> will be triggered. If you
326execute the task instances nested into your task, you should also
327invoke <code>perform</code> on these instances instead of
328<code>execute</code>.</p>
329
330<h3>Example</h3>
331<p>Let's write our own task, which prints a message on the
332<code>System.out</code> stream.
333The
334task has one attribute, called <code>message</code>.</p>
335<blockquote>
336<pre>
337package com.mydomain;
338
339import org.apache.tools.ant.BuildException;
340import org.apache.tools.ant.Task;
341
342public class MyVeryOwnTask extends Task {
343 private String msg;
344
345 // The method executing the task
346 public void execute() throws BuildException {
347 System.out.println(msg);
348 }
349
350 // The setter for the &quot;message&quot; attribute
351 public void setMessage(String msg) {
352 this.msg = msg;
353 }
354}
355</pre>
356</blockquote>
357<p>It's really this simple ;-)</p>
358<p>Adding your task to the system is rather simple too:</p>
359<ol>
360 <li>Make sure the class that implements your task is in the classpath when
361 starting Ant.</li>
362 <li>Add a <code>&lt;taskdef&gt;</code> element to your project.
363 This actually adds your task to the system.</li>
364 <li>Use your task in the rest of the buildfile.</li>
365</ol>
366
367
368<h3>Example</h3>
369<blockquote>
370<pre>
371&lt;?xml version=&quot;1.0&quot;?&gt;
372
373&lt;project name=&quot;OwnTaskExample&quot; default=&quot;main&quot; basedir=&quot;.&quot;&gt;
374 &lt;taskdef name=&quot;mytask&quot; classname=&quot;com.mydomain.MyVeryOwnTask&quot;/&gt;
375
376 &lt;target name=&quot;main&quot;&gt;
377 &lt;mytask message=&quot;Hello World! MyVeryOwnTask works!&quot;/&gt;
378 &lt;/target&gt;
379&lt;/project&gt;
380</pre>
381</blockquote>
382<h3>Example 2</h3>
383To use a task directly from the buildfile which created it, place the
384<code>&lt;taskdef&gt;</code> declaration inside a target
385<i>after the compilation</i>. Use the <code>classpath</code> attribute of
386<code>&lt;taskdef&gt;</code> to point to where the code has just been
387compiled.
388<blockquote>
389<pre>
390&lt;?xml version=&quot;1.0&quot;?&gt;
391
392&lt;project name=&quot;OwnTaskExample2&quot; default=&quot;main&quot; basedir=&quot;.&quot;&gt;
393
394 &lt;target name=&quot;build&quot; &gt;
395 &lt;mkdir dir=&quot;build&quot;/&gt;
396 &lt;javac srcdir=&quot;source&quot; destdir=&quot;build&quot;/&gt;
397 &lt;/target&gt;
398
399 &lt;target name=&quot;declare&quot; depends=&quot;build&quot;&gt;
400 &lt;taskdef name=&quot;mytask&quot;
401 classname=&quot;com.mydomain.MyVeryOwnTask&quot;
402 classpath=&quot;build&quot;/&gt;
403 &lt;/target&gt;
404
405 &lt;target name=&quot;main&quot; depends=&quot;declare&quot;&gt;
406 &lt;mytask message=&quot;Hello World! MyVeryOwnTask works!&quot;/&gt;
407 &lt;/target&gt;
408&lt;/project&gt;
409</pre>
410</blockquote>
411
412
413<p>Another way to add a task (more permanently), is to add the task name and
414implementing class name to the <code>default.properties</code> file in the
415<code>org.apache.tools.ant.taskdefs</code>
416package. Then you can use it as if it were a built-in task.</p>
417
418<hr>
419<a name="buildevents"></a><h2>Build Events</h2>
420<P>Ant is capable of generating build events as it performs the tasks necessary to build a project.
421Listeners can be attached to Ant to receive these events. This capability could be used, for example,
422to connect Ant to a GUI or to integrate Ant with an IDE.
423</P>
424<p>To use build events you need to create an ant <code>Project</code> object. You can then call the
425<code>addBuildListener</code> method to add your listener to the project. Your listener must implement
426the <code>org.apache.tools.antBuildListener</code> interface. The listener will receive BuildEvents
427for the following events</P>
428<ul>
429<li>Build started</li>
430<li>Build finished</li>
431<li>Target started</li>
432<li>Target finished</li>
433<li>Task started</li>
434<li>Task finished</li>
435<li>Message logged</li>
436</ul>
437
438<p>If the build file invokes another build file via <a
439href="CoreTasks/ant.html">&lt;ant&gt;</a> or <a
440href="CoreTasks/subant.html">&lt;subant&gt;</a> or uses <a
441href="CoreTasks/antcall.html">&lt;antcall&gt;</a>, you are creating a
442new Ant "project" that will send target and task level events of its
443own but never sends build started/finished events. Ant 1.6.2
444introduces an extension of the BuildListener interface named
445SubBuildListener that will receive two new events for</p>
446<ul>
447<li>SubBuild started</li>
448<li>SubBuild finished</li>
449</ul>
450<p>If you are interested in those events, all you need to do is to
451implement the new interface instead of BuildListener (and register the
452listener, of course).</p>
453
454<p>
455If you wish to attach a listener from the command line you may use the
456<code>-listener</code> option. For example:</p>
457<blockquote>
458 <pre>ant -listener org.apache.tools.ant.XmlLogger</pre>
459</blockquote>
460<p>will run Ant with a listener that generates an XML representation of the build progress. This
461listener is included with Ant, as is the default listener, which generates the logging to standard output.</p>
462
463<p><b>Note: </b>A listener must not access System.out and System.err directly since ouput on
464these streams is redirected by Ant's core to the build event system. Accessing these
465streams can cause an infinite loop in Ant. Depending on the version of Ant, this will
466either cause the build to terminate or the Java VM to run out of Stack space. A logger, also, may
467not access System.out and System.err directly. It must use the streams with which it has
468been configured.
469</p>
470
471<hr>
472<a name="integration"></a><h2>Source code integration</h2>
473
474
475The other way to extend Ant through Java is to make changes to existing tasks, which is positively encouraged.
476Both changes to the existing source and new tasks can be incorporated back into the Ant codebase, which
477benefits all users and spreads the maintenance load around.
478<p>
479
480Please consult the
481<a href="http://jakarta.apache.org/site/getinvolved.html">Getting Involved</a> pages on the Jakarta web site
482for details on how to fetch the latest source and how to submit changes for reincorporation into the
483source tree.
484<p>
485Ant also has some
486<a href="http://ant.apache.org/ant_task_guidelines.html">task guidelines</a>
487which provides some advice to people developing and testing tasks. Even if you intend to
488keep your tasks to yourself, you should still read this as it should be informative.
489
490<hr>
491<p align="center">Copyright &copy; 2000-2004 The Apache Software Foundation. All rights
492Reserved.</p>
493
494</body>
495</html>
496
Note: See TracBrowser for help on using the repository browser.