diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/manual/develop.html')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/manual/develop.html | 544 |
1 files changed, 544 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/manual/develop.html b/framework/src/ant/apache-ant-1.9.6/manual/develop.html new file mode 100644 index 00000000..ed06d301 --- /dev/null +++ b/framework/src/ant/apache-ant-1.9.6/manual/develop.html @@ -0,0 +1,544 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<html> + +<head> +<meta http-equiv="Content-Language" content="en-us"> +<link rel="stylesheet" type="text/css" href="stylesheets/style.css"> +<title>Writing Your Own Task</title> +</head> + +<body> +<h1>Developing with Apache 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 designed 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<a href="#footnote-1"><sup>*</sup></a>. 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="Tasks/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> + +<hr> +<p><a name="footnote-1">*</a> Actually the case of the letters after +the first one doesn't really matter to Ant, using all lower case is a +good convention, though.</p> + +<h3>The Life-cycle of a Task</h3> +<ol> + <li> + The xml element that contains the tag corresponding to the + task gets converted to an UnknownElement at parser time. + This UnknownElement gets placed in a list within a target + object, or recursively within another UnknownElement. + </li> + <li> + When the target is executed, each UnknownElement is invoked + using an <code>perform()</code> method. This instantiates + the task. This means that tasks only gets + instantiated at run time. + </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 run + 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 run 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 run time. Child elements corresponding + to <code>addConfiguredXXX()</code> are created at this point but + the actual <code>addCondifgired</code> method is not called.</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>If child elements of the XML element corresponding to this task + have been created for <code>addConfiguredXXX()</code> methods, + those methods get invoked now.</li> + + <li><a name="execute"><code>execute()</code></a> is called at runtime. + 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. <b>Since Ant 1.8</b>, it is +possible to <a href="Tasks/propertyhelper.html">extend Ant's property handling</a> +such that a non-string Object may be the result of the evaluation of a string +containing a single property reference. These will be assigned directly via +setter methods of matching type. Since it requires some beyond-the-basics +intervention to enable this behavior, it may be a good idea to flag attributes +intended to permit this usage paradigm. +</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.Resource</code> + <code>org.apache.tools.ant.types.Resource</code>, Ant will + resolve the string as a <code>java.io.File</code> as above, then + pass in as a <code>org.apache.tools.ant.types.resources.FileResource</code>. + <b>Since Ant 1.8</b> + </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> + + <li>A (Java 5) enumeration. Ant will call the setter with the enum constant + matching the value given in the build file. This is easier than using + <code>EnumeratedAttribute</code> and can result in cleaner code, but of course + your task will not run on JDK 1.4 or earlier. Note that any override of + <code>toString()</code> in the enumeration is ignored; the build file must use + the declared name (see <code>Enum.getName()</code>). You may wish to use lowercase + enum constant names, in contrast to usual Java style, to look better in build files. + <em>As of Ant 1.7.0.</em></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 or a <code>public</code> one-arg constructor + taking a Project class as a parameter. +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="nestedtype">Nested Types</a></h3> +If your task needs to nest an arbitrary type that has been defined + using <code><typedef></code> you have two options. + <ol> + <li><code>public void add(Type type)</code></li> + <li><code>public void addConfigured(Type type)</code></li> + </ol> + The difference between 1 and 2 is the same as between 2 and 3 in the + previous section. + <p> + For example suppose one wanted to handle objects object of type + org.apache.tools.ant.taskdefs.condition.Condition, one may + have a class: + </p> + <blockquote> + <pre> +public class MyTask extends Task { + private List conditions = new ArrayList(); + public void add(Condition c) { + conditions.add(c); + } + public void execute() { + // iterator over the conditions + } +} + </pre> + </blockquote> + <p> + One may define and use this class like this: + </p> + <blockquote> + <pre> +<taskdef name="mytask" classname="MyTask" classpath="classes"/> +<typedef name="condition.equals" + classname="org.apache.tools.ant.taskdefs.conditions.Equals"/> +<mytask> + <condition.equals arg1="${debug}" arg2="true"/> +</mytask> + </pre> + </blockquote> + <p> + A more complicated example follows: + </p> + <blockquote> + <pre> +public class Sample { + public static class MyFileSelector implements FileSelector { + public void setAttrA(int a) {} + public void setAttrB(int b) {} + public void add(Path path) {} + public boolean isSelected(File basedir, String filename, File file) { + return true; + } + } + + interface MyInterface { + void setVerbose(boolean val); + } + + public static class BuildPath extends Path { + public BuildPath(Project project) { + super(project); + } + + public void add(MyInterface inter) {} + public void setUrl(String url) {} + } + + public static class XInterface implements MyInterface { + public void setVerbose(boolean x) {} + public void setCount(int c) {} + } +} + </pre> + </blockquote> + <p> + This class defines a number of static classes that implement/extend + Path, MyFileSelector and MyInterface. These may be defined and used + as follows: + </p> + <pre> + <blockquote> +<typedef name="myfileselector" classname="Sample$MyFileSelector" + classpath="classes" loaderref="classes"/> +<typedef name="buildpath" classname="Sample$BuildPath" + classpath="classes" loaderref="classes"/> +<typedef name="xinterface" classname="Sample$XInterface" + classpath="classes" loaderref="classes"/> + +<copy todir="copy-classes"> + <fileset dir="classes"> + <myfileselector attra="10" attrB="-10"> + <buildpath path="." url="abc"> + <xinterface count="4"/> + </buildpath> + </myfileselector> + </fileset> +</copy> + </blockquote> + </pre> + +<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 the build file invokes another build file via +<a href="Tasks/ant.html"><code><ant></code></a> or +<a href="Tasks/subant.html"><code><subant></code></a> or uses +<a href="Tasks/antcall.html"><code><antcall></code></a>, you are creating a +new Ant "project" that will send target and task level events of its +own but never sends build started/finished events. Ant 1.6.2 +introduces an extension of the BuildListener interface named +SubBuildListener that will receive two new events for</p> +<ul> + <li>SubBuild started</li> + <li>SubBuild finished</li> +</ul> +<p>If you are interested in those events, all you need to do is to +implement the new interface instead of BuildListener (and register the +listener, of course).</p> + +<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> + +<p><b>Note: </b>A listener must not access System.out and System.err directly since output on +these streams is redirected by Ant's core to the build event system. Accessing these +streams can cause an infinite loop in Ant. Depending on the version of Ant, this will +either cause the build to terminate or the Java VM to run out of Stack space. A logger, also, may +not access System.out and System.err directly. It must use the streams with which it has +been configured.</p> + +<p><b>Note2:</b> All methods of a BuildListener except for the "Build + Started" and "Build Finished" events may occur on several threads + simultaneously - for example while Ant is executing + a <code><parallel></code> task.</p> + +<hr> +<h2><a name="integration">Source code integration</a></h2> + +<p>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> + +<p>Please consult the +<a href="http://www.apache.org/foundation/getinvolved.html">Getting Involved</a> pages on the Apache web site +for details on how to fetch the latest source and how to submit changes for reincorporation into the +source tree.</p> + +<p>Ant also has some +<a href="http://ant.apache.org/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.</p> + +</body> +</html> + |