You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

develop.html 23 KiB

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