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