Previous Section
Table of Contents
Next Section


Writing Tasks

Ant tasks are Java classes that describe the functioning of the task. To write Ant tasks:

  1. Build a Java class that extends org.apache.tools.ant.Task.

  2. Build a setter method for each attribute. The setter method needs to be a public void method that accepts only one argument. The method name needs to start with set. The method name is followed by the type of the attribute with the first character of the attribute in uppercase and the rest in lowercase.

  3. Implement the org.apache.tools.ant.TaskContainer interface in the Java class if the task contains other tasks as nested elements.

  4. Build a public void addText(string) method to specify the text between the tags if the task allows the use of character data.

  5. Build a create(), add(), or addConfigured() function for each nested element. The create() function specifies a public function without any argument that returns an object type. The name of the create() function starts with create followed by the element name. The add() or addConfigured() function specifies a public void function that accepts only one argument of Object type with a no-argument constructor. The add() or addConfigured() function name starts with add or addConfigured followed by the element name.

  6. Build a public void execute() function that throws BuildException. The execute() function cannot contain an argument. This function implements the task.

Setting Up the Build Environment

You can use Ant to set up the Build environment, as follows:

  1. Select a directory as the root directory of the project.

  2. Create the build.xml text file in the root directory.

The objectives of the build file are:

  • Compiling the task.

  • Creating the Jar of the task so that you can deploy it.

  • Deleting all the created files.

Listing 3-11 shows how to compile and clean up the files:

Listing 3-11: Compiling and Cleaning Files
Start example
<?xml version="1.0"  encoding ="ISO-8859-1"?>
<project name="abctask" basedir="." default="jar">
<property name="src.dir" value="src"/>
<property name="classes.dir" value="classes"/>
<target name="clean" description="Delete all the created files">
<delete dir="${classes.dir}">
<delete file="${ant.project.name}.jar"/>
</target>
<target name="compile" description="Compiles the task">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="{classes.dir}"/>
</target>
<target name="jar" description="JARs the task" depends="compile">
<jar destdir="${ant.project.name}.jar" basedir="${classes.dir}"/>
</target>
</project> 
End example

The listing shows how to compile and clean up the files. The current directory is the root directory of the abctask project. The parser assumes UTF-8 encoding, by default. Before implementing the targets, you need to define them. To delete all the created files, the delete tag contains the name of the file.

Writing Tasks

Ant tasks are Java classes that you can write using XML tags to perform a specific operation.

Listing 3-12 shows a simple text file, Welcome.java, which shows a message in the standard output:

Listing 3-12: The Welcome Program
Start example
public class Welcome
{
    public void execute()
    {
        System.out.println ("Welcome to Ant");
    }
}
End example

The above listing shows the Welcome class that contains the execute() function that helps you view a message on the console. You can compile and JAR this code with Ant.

Using Tasks

Ant provides various tasks, such as built-in, optional, and custom. Each task provides different functions. You can use these tasks for different purposes, such as creating a directory, querying a database, accessing a telnet server, and uploading a file to an FTP site. Listing 3-13 shows how to create a task:

Listing 3-13: Creating a Task
Start example
<?xml version="1.0"  encoding ="ISO-8859-1"?>
<project name="abctask" basedir="." default="use">
<target name="use" description="Use the task" depends="jar">
<taskdef name="Welcome"  classname="Welcome" classpath="${ant.project.name}.jar"/>
<Welcome/>
</target>
</project>
End example

The above listing shows how to declare a new task using the <taskdef> task, which helps add a task definition to the current project for future use. The most important attribute in this code is the classpath attribute, because Ant searches the task in the /lib directory, by default. As a result, the classpath attribute helps specify the correct location of the task.

Testing Tasks

To test Java classes, you can use an optional task, <junit>. The JUnit testing framework provides the <junit> task, which is an open-source project that simplifies the testing procedure.

Listing 3-14 shows how to use the <junit> task to test code:

Listing 3-14: A Sample Class with an Error
Start example
public class errorClass extends object {
    int a;
    public errorClass (int a) {
        this.a = a;
    }
    public int geta() {
        return a;
    }
    public void multiplytwo() {
        a *= 3;
    }
} 	
End example

The above listing wrongly multiplies three instead of multiplying two, leading to an error.

When you compile the code, it will not show an error. To test this code, you need to create a separate class.

Note 

To use the <junit> task properly, you need junit.jar, which you can download from http://www.junit.org and copy it to the /lib/directory with Ant installed.

You can use the <junit> framework to create a test class. Listing 3-15 shows the JUnit class for testing errorClass:

Listing 3-15: The JUnit Class
Start example
import junit.framework.*;
public errorClassTest extends TestCase {
    public errorClassTest (String_string) {
        super(_string);
    }
    public void testmultiplication() {
        errorClass eC = new errorClass(2);
        eC.multiplytwo();
        assertsEquals(eC.getA(), 4);
    }
}
End example

The above listing extends the junit.framework.testcase class and creates a constructor that passes a specific string to the base class. To identify the tests that have to run, the JUnit framework employs Java Reflection. A series of tests can be described by declaring a separate method, public void testmultiplication(). Within this method, you can place the test cases. To identify an error, use the asertEquals() method to execute tests under different conditions. For example, in Listing 3-15, if the return value is not equal to 4, the test will show an error.

After you have created a testing class, you need to integrate this with Ant using the <junit> task.

Listing 3-16 shows how to integrate the testing class with Ant using the <junit> task:

Listing 3-16: Using the JUnit Task
Start example
<target name="comptests"> 
<javac srcdir="${src}" 
destdir="${build}" 
includes="errorClass*.java" 
optimize="off" 
debug="on"/> 
</target> 
<target name="junitTests" depends="comptests"> 
<junit printsummary="on" showoutput="yes"> 
<classpath> 
<pathelement path="${build}"/> 
</classpath> 
<test name="errorClassTest"/> 
</junit> 
</target>                    
End example

The above listing shows how to set up a simple target that will control the compilation of the tests. Define the <junit> task within the junitTests target. This runs the <junit> framework in the errorClassTest class. To run the target, go to the directory where you have stored the target and type the following command:

C:\ant\ant junitTests

Listing 3-17 shows the output of the above command:

Listing 3-17: The junitTests Output
Start example
Buildfile: build.xml 
compiletests: 
    [javac] Compiling 1 source file to c:\ant\classes 
junitTests: 
    [junit] Running errorClassTest 
    [junit] Tests run: 1, Failures: 1, Errors: 0, Time elapsed: 0.02 sec 
    [junit] TEST errorClassTest FAILED 
BUILD SUCCESSFUL 
Total time: 7 seconds
End example

The above listing shows the output that indicates that one of the tests failed.

The optional attributes available to the <junit> task are:

  • printsummary: Checks whether the output to the console per test is a one-line summary. If the value of the flag is On, a summary is printed. If the value is Off, the summary is not printed. A value of withOutAndError provides the same output as On but includes the output from the System.out and System.err files.

  • fork: Checks whether the tests run in a separate JVM.

  • haltonerror: Verifies whether the build process halts when the tests encounter an error.

  • errorproperty: Specifies the name of the property that will be set if an error occurs.

  • haltonfailure: Checks whether the build process halts if an error takes place in the tests.

  • failureproperty: Specifies the name of the property that will be set if you encounter an error.

  • filtertrace: Separates all the stack traces that belong to Ant and JUnit for filtered output.

  • timeout: Specifies that a test will be cancelled if it does not finish in the specified time.

  • maxmemory: Checks the allocation of the maximum amount of memory if another split occurs in JVM.

  • jvm: Invokes the JVM if the split is set.

  • dir: Specifies the directory to split the JVM from if you need to split another JVM.

  • newenvironment: Withholds the old environment when you specify new environment variables.

  • includeantruntime: Includes the Ant classes needed to run the tests and the JUnit framework to the classpath in split mode.

  • showoutput: Transmits output that are generated by tests to Ant’s logging system and to the formatters.

A major feature of the <junit> task is the ability to run the test in a different JVM from the one that manages Ant. The benefit is to run tests in a filtered environment with a managed classpath. If an error occurs in the test classes, it will not affect the Ant build process.

To support the above feature, you can deploy the <jvmarg> nested element inside the <junit> task to transmit different parameters to the new JVM instance.

The attributes of the <jvmarg> nested element are:

  • value: Specifies a command-line attribute.

  • line: Specifies a space-enclosed list of command-line arguments.

  • file: Specifies the name of a file as a command-line argument that you can substitute with the absolute filename of the file.

  • path: Specifies a string that you can view as one command-line argument.

Apart from transmitting values to the JVM, you can also configure environment variables that will be accessible at run time using the <sysproperty> nested element.

The <sysproperty> nested element attributes are:

  • key: Specifies the name of the environment variable.

  • value: Indicates the value of the key.

  • path: Indicates the value of a PATH-like environment variable.

  • file: Specifies the value of the environment variable that you can substitute by the absolute filename of the file attribute.

Another characteristic of the <junit> task is its ability to gather information about the tests that are presently running and to present this information in XML format using the <formatter> nested element. This information can be used later with the <junitreport> task.

The attributes of the <formatter> nested element are:

  • type: Indicates the type of format that is generated, such as xml, plain, or brief.

  • classname: Specifies the name of the class if you use a custom formatter.

  • extension: Specifies the extension that will append to the output filename.

  • usefile: Specifies whether the output needs to be sent to a file.

To include the class files in the test, the JUnit task provides many methods. You can identify a particular class for testing using the nested <test> element. The <batchtest> nested element allows you to pull in a list of classes simultaneously. The attributes of the <test> and <batchtest> elements are the same.

The optional attributes of the <test>/<batchtest> elements are:

  • name: Indicates the name of the class to be tested.

  • todir: Indicates the directory to enter the reports.

  • outfile: Specifies the base name of the test result. You can find out the full filename using this attribute and the extension of formatter.

  • if: Specifies to run this test only if the named property is set.

  • unless: Specifies to run this test only if the named property is not set.

To combine the different XML files generated by the <junit> task into HTML files for viewing, you can use the optional task, <junitreport>. This task presents a report that shows the status of all tests. The <junitreport> task includes many libraries, such as Xalan2.x, to operate properly.

The optional attributes of the <junitreport> task are:

  • tofile: Specifies the name of the main XML file generated by the <junit> task.

  • todir: Indicates the directory where all the XML files from the <junit> task are stored.

The <junitreport> tasks collect all files from the output of the <junit> task using a standard <fileset> nested element. After you collect all the files, you need to plan the format of the report. You have to indicate frames, the locations of your output files, and an alternative stylesheet to change the data. You can do this using the <report> nested element.

The attributes of the <report> nested element are:

  • format: Specifies the use of a frame, whether yes or no.

  • styledir: Allows you to alter the directory of the alternative stylesheet to be used.

  • todir: Specifies the directory where the stylesheet will be stored.

Listing 3-18 shows how to use the <junitreport> task:

Listing 3-18: Using the JUnitReport Task
Start example
<junitreport todir = "${output}">
<fileset dir = "${output}">
<include name= "UNIT-*.xml"/>
</fileset>
<report format = "frames" todir="${output}/html"/>
</junitreport> 
End example

The above listing shows that when the program executes, the output directory ${output}/html consists of a group of HTML files starting from the index.html file that encapsulates the complete Unit group.



Previous Section
Table of Contents
Next Section