Ant

What is Ant?

By Thomas Paul

Ant is a Java based build tool developed as part of the Apache Jakarta project. It can be downloaded from the Ant home site: http://jakarta.apache.org/ant. Unlike make files, which are operating system specific, Ant is designed to be as cross platform as Java. Ant uses Java classes and XML scripts to provide an automated way to build applications and to be available on every Java compatible platform.

Ant (which stands for Another Neat Tool) was originally developed by James Duncan Davidson as part of the Tomcat project. Ant was developed specifically to simplify the process of building Tomcat. When Tomcat was donated to the Apache project, Ant went with it. It was soon realized that Ant was very useful and could be used in any project and became a separate Apache development effort. The current release of Ant is 1.4.1 (as of February, 2002).

What Ant can do

Ant is a build tool. But Ant will allow you to do much more than just build your code. Ant functionality includes:

  1. extract source from a version control system
  2. create directories
  3. delete directories
  4. compile code
  5. generate javadoc
  6. jar files
  7. copy files
  8. generate e-mail
  9. ftp files
  10. execute SQL statements
  11. run unit test
  12. or any other function that you might need!

Ant is fully expandable. It is open so that new functions can be added by simply writing a new Java class.

The easiest way to explain Ant is with an example so we will look at a typical build and deploy script and then we will look at some code to create our own function.

Installing Ant

Ant is simple enough to install. First, download the binaries from the Apache Ant web site. If you intend on writing your own Ant classes, you can download the source as it can be a useful guide to writing Ant classes. Next, extract the files from the Ant zip file. Update your classpath to point to the ant.jar file which is found in the ant/lib directory. According to the Ant installation documentation:

     Note: Do not install Ant's ant.jar file into the lib/ext directory of the JDK/JRE. 
     Ant is an application, whilst the extension directory is intended for JDK extensions. 
     In particular there are security restrictions on the classes which may be loaded by 
     an extension.

Next, add the bin directory to your path. Set the ANT_HOME environment variable to the directory where you installed Ant.

If everything is working, you should be able to type Ant at your command line prompt and get this response:

c:\>Ant
Buildfile: build.xml does not exist!
Build failed

Note: If you are running WinXP and are having problems getting Ant to run, you should download the latest nightly build and not the current release version of Ant.

A Build Script

Ant requires the use of a build script to tell Ant what to do. The default name of the script is build.xml but you can use any name you want. Let’s take a look at a typical build script.

<?xml version="1.0"?>
<project name="aag" default="compile" basedir=".">

Every Ant build file contains one project. The attributes on the project tag are the name of the project, the default target to run when no target is specified on the command line, and the base directory to use when locating files. Ant works best when relative directories are used. Here we are creating a project called “aag”. The target named “compile” will run as the default (more on targets in a moment), and the base directory to locate directories and files is the directory where this build file is located.

<!-- ===================================== -->
<!--         Global properties             -->
<!-- ===================================== -->

<property name="name" value="aag" />
<property name="build" value="${basedir}/build" />
<property name="baselib" value=”/jdk/jre/lib" />
<property name="dist" value="${basedir}/dist" />
<property name="source" value="${basedir}/source" />
<property name="docs" value="${basedir}/docs" />
<property name="api" value="${docs}/api" />
<property name="tomcat" value="/tomcat/webapps/aag/WEB-INF/lib" />
<property name="tomcat-jar" value="/tomcat/webapps/aag/jar" />

Ant allows the use of properties to save values. In this section we create a series of properties that will represent the various directories we will be using in our script. In this way, if we want to change a directory we can change it in the property list and we won’t need to find each place in our script that we used that directory. Whenever Ant sees ${AName} it will replace this with the associated property named AName. So value="${basedir}/build" becomes value="./build"since basedir was defined in the project tag. value="${docs}/api" will become value="./docs/api".

The Target Tag

<!--===================================== -->
<!--            Init                      -->
<!--===================================== -->
<target name="init" >
     <tstamp />
     <mkdir dir="${build}" />
     <mkdir dir="${api}" />
     <mkdir dir="${dist}" />
</target>

The section above is a target tag. Targets can be specified on the command line when executing Ant and Ant will then execute the specified target. All commands within the target tag are executed in the order specified.

Within the init target, we first initialize our timestamp. tstamp will initialize three properties which can be used within the build script. The DSTAMP property is in the format "yyyymmdd", TSTAMP is in the format "hhmm", and TODAY is in the format "month day year". These properties could be used, for example, to generate unique file names.

The next commands will create the directories required to compile and jar our application.

Compiling our code

<!-- ===================================== -->
<!-- Compile -->
<!-- ===================================== -->
<target name="compile" depends="init" >
     <javac srcdir="${source}" destdir="${build}"
        <classpath>
          <pathelement location="${baselib}/mysql_uncomp.jar" />
          <pathelement location="="${baselib}/struts.jar" />
        </classpath>
     </javac>
</target>

The next target is named compile and has the init target as a dependency. This means that if compile is specified as the target of a Ant run, the init target will automatically run first. The compile itself if fairly simple. Ant will compile each of the java files found in the source directory and place the class files in the destination directory. Ant will automatically place the class files in the correct structure based on their package. It will also skip compiling any java file that has already been compiled and has not been changed but only if the source files are in a directory structure exactly matching the package structure. Notice that the classpath to use for the compile can be specified with separate pathelement tags. It is recommended that the classpath be specified within the compile tag so that your compile doesn’t rely on the classpath being specified correctly outside of Ant.

Generating JavaDoc

<!-- ===================================== -->
<!--           JavaDoc                     -->
<!-- ===================================== -->
<target name="javadoc" depends="compile" >
     <javadoc sourcepath="${source}"
         destdir="${api}"
         packagenames="com.aag.*" />
</target>

The next target is javadoc which is dependent on the successful completion of the compile target. Since the compile target is dependant on the init target, specifying javadoc on the command line will cause init , compile , and javadoc all to run. The javadoc tag will cause JavaDoc to be generated for all classes in all packages that start with com.aag that are in the sourcepath . The JavaDoc will be placed in the destdir . In this example, packages such as com.aag.io , com.aag.database , and com.aag.database.pool will all have JavaDoc generated.

The Jar Tag

<!-- ===================================== -->
<!-- Jar and Copy -->
<!-- ===================================== -->
<target name="jar" depends="javadoc" >
	<jar jarfile="${dist}/${name}.jar" >
		<fileset dir="${build}" />
		<fileset dir="${docs}" />
	</jar>
	<copy todir="${tomcat}" file="${dist}/${name}.jar" />
</target>

The next target is named jar and depends upon the successful completion of the javadoc target. The jar tag will create a jar file. The name of the jar file is controlled by the jarfile attribute. The files that are included in the jar file are specified by separate fileset tags. The copy tag will copy the jar file into the tomcat webapps directory.

Cleaning Up

<!-- ===================================== -->
<!-- Remove build directories -->
<!-- ===================================== -->
<target name="clean" >
	<delete dir="${build}" />
	<delete dir="${docs}" />
	<delete dir="${dist}" />
</target>

</project>

The final target is named clean and since it has no other target dependent on it, will only run if specified on the command line. The delete tag will delete the specified directory.

The build script is terminated with a final </project> tag.

Running the Script

Here is the possible output if we ran this script from the command line with “ant jar”:

>ant jar
Buildfile: build.xml
init:
[mkdir] Created dir: C:\JavaProjects\AntTest\build
[mkdir] Created dir: C:\JavaProjects\AntTest\docs\api
[mkdir] Created dir: C:\JavaProjects\AntTest\dist
compile:
[javac] Compiling 12 source files to C:\JavaProjects\AntTest\build
javadoc:
[javadoc] Generating Javadoc
[javadoc] Javadoc execution
[javadoc] Loading source files for package com.aag.io...
[javadoc] Loading source files for package com.aag.database...
[javadoc] Loading source files for package com.aag.database.pool...
[javadoc] Constructing Javadoc information...
[javadoc] Building tree for all the packages and classes...
[javadoc] Building index for all the packages and classes...
[javadoc] Building index for all classes...
jar:
[jar] Building jar: C:\JavaProjects\AntTest\dist\aag.jar
[copy] Copying 1 file to C:\jakarta-tomcat-4.0.1\webapps\aag\WEB-INF\lib
BUILD SUCCESSFUL
Total time: 6 seconds

Ant first created our target directories, then compiled our source, generated the JavaDoc, put everything into a jar file, and then copied the jar file to our Tomcat installation.

Now we can clean up our directories by running “ant clean”:

>ant clean
Buildfile: build.xml
clean:
[delete] Deleting directory C:\JavaProjects\AntTest\build
[delete] Deleting directory C:\JavaProjects\AntTest\docs
[delete] Deleting directory C:\JavaProjects\AntTest\dist
BUILD SUCCESSFUL
Total time: 0 seconds

Creating our own tasks

Ant comes with a rich collection of tasks, some of which we have discussed. There are additional optional tasks available at the Ant home page. If none of these tasks meet your needs, Ant allows you to write your own tasks.

Writing your own task is not very complicated. What if we want to send the jar file that we just created to one of our staff members who works from home. We don’t want to send this jar file in the clear since it contains our top secret development work. We need to create a new task that can take a file, encrypt it, and then put it into a directory where our developer can find it. The Java class to perform this function is Listing 1.

The process starts by creating a java class that extends org.apache.tools.ant.Task. The class must have a default constructor. We need to create a setter method for each attribute we intend on adding to our tag. Finally, we need to create an execute( ) method that does all the work.

public void setKeyFile(String keyFile) {
	this.keyFile = keyFile;
}
public void setInputFile(String inputFile) {
	this.inputFile = inputFile;
}
public void setOutputFile(String outputFile) {
	this.outputFile = outputFile;
}

Each of these setter methods relates to an attribute on our tag:

<crypto keyFile="key.ser"
	inputFile="${dist}/${name}.jar"
	outputFile="${dist}/${name}.secret.jar" />

When the execute( ) method runs it will have access to all the attributes that were specified within the crypto tag.

The execute( ) method must be declared to throw org.apache.tools.ant.BuildException. No other exceptions can be thrown. The constructor for BuildException allows for the wrapping of other excpetions:

} catch (Exception e) {
	throw new BuildException("Problem with cipher", e);
}

The only thing left to do is to specify in the build script the actual name of the Java class. This is done with a taskdef tag which is normally specified in the section with our global variables.

<taskdef name="crypto" classname="com.tom.ant.Crypto" />

The complete script is specified in Listing 2.

The Future of Ant

Ant development continues and Ant 2.0 is currently being developed. It is expected that build files developed in Ant 1.4 will not work in Ant 2.0.

That wraps up our brief look at Ant. If this article has interested you in Ant, you should visit the Ant home page and look at the documentation. Ant contains many more features than what we have seen in this article. I hope that this has given you a flavor for the capabilities of Ant and the simplicity of using Ant to build applications. If you are interested in Ant, I recommend that you sign up for the Ant user list available here: http://jakarta.apache.org/site/mail2.html.