Targets

Ant targets define the user-accessible functionality of the build file. The targets are all named, and may have dependencies upon each other.

You interact with Ant by specifying target names on the command line. Here is how you can invoke the installTomcat target:

ant -buildfile studentInstall.xml installTomcat

To see a list of all target names, you can type ant -projecthelp. You can also execute multiple targets in a single command like this:

ant -buildfile studentInstall.xml uninstall installXalan

And finally, you can simply type ant to execute the default target. In our build file, installAll is the default target. This is specified in the <project> tag. You can type ant -help to learn about other Ant options.

Target Dependencies

As the example build file shows, targets can have dependencies on other targets. Take the prepare target, for instance:

<target name="prepare" depends="init">

Because of this dependency, the init target is executed before the prepare target executes. You use this dependency mechanism throughout your build files in order to ensure that operations complete in the correct order. The prepare target, for instance, ensures that the output directory is created before any other operation takes place.

As an alternative to target dependencies, your build file can call other targets explicitly, using the antcall task. To call targets in other buildfiles, use the ant task.

Other Target Attributes

Looking back at studentInstall.xml, you will notice that the installTomcat and installXalan targets use the unless attribute. The unless attribute ensures that the tasks within a target are executed unless the specified property is set. In our case, the haveTomcat and haveXalan properties are used to indicate whether or not the student has already unzipped these tools. The unless attribute improves performance by avoiding unzipping files multiple times. Ant also provides an if attribute, which specifies that the target in question is executed only if a property is set.

Targets may also have a description attribute. When you type ant -buildfile studentInstall.xml -projecthelp, Ant displays a list of all targets. These are separated according to whether or not the targets have descriptions. Targets with descriptions are listed first, and are displayed as "Main targets." Targets without descriptions are listed as "Subtargets." The distinction between main targets and subtargets is purely for documentation purposes. The general rule is that you list descriptions for those targets you wish the user to interact with. Other targets, which are commonly listed as dependencies of your main targets, should not have descriptions.

Tasks

No discussion of Ant is complete without talking about tasks, which do the work of the build file. Ant ships with well over 100 tasks, which perform operations that include compiling source code, unzipping files, copying files, creating .war files, and even playing sound files.

Ant tasks are implemented as Java classes, and are represented in the build file using XML tags. Ant parses the XML file and then uses Java reflection to figure out which methods to call on each Java task object. Since all tasks are implemented using Java classes, you can write your own tasks and extend the capability of Ant. Now, let's look at the tasks used in studentInstall.xml.

available

The available task is used to determine whether or not various resources exist. In studentInstall.xml, available sets properties if products are already installed:

As shown in the installTomcat and installXalan targets, these properties control whether or not the unzip task has to be executed.

The available task may also be used to determine whether or not Java class files are available on the classpath. This is very useful when determining if a particular version of an API is present. Here is how you can determine if JDK 1.4 or later is being used:

<available classname="javax.swing.Spring" property="jdk1.4.present"/>

This works because javax.swing.Spring was added in JDK 1.4. If you are running Ant with an older JDK, the jdk1.4.present property will not be set.

mkdir

mkdir creates a directory, if the directory does not already exist. The path is relative to the Ant project's base directory, which is specified in the <project> tag. While a simple task like mkdir does not do much, it is interesting because it works on any platform supported by Java. This means that the same build file will work on Unix, Windows, or any other platform. The same is true for other file system tasks, such as copy, delete, and move.

unzip

The unzip task unzips .zip archives to a specified directory. We use this task to expand Xalan and Tomcat to our destination directory. As described earlier, the files are unzipped unless a property is set, indicating that they have already been unzipped:

pathconvert

The pathconvert task converts an Ant path into a platform-specific path. On Windows, this means that / characters are changed to \ characters, the drive letter is prepended to the path, and directory separators are changed to ; characters. Once the path is converted into platform-specific form, it is assigned to an Ant property. This property may then be referenced later in your build file using the normal ${propname} syntax.

The build file outlined in this article uses pathconvert, along with the echo task, to tell the students what environment variables they need to set. Here is how pathconvert converts the ${destdir.tomcat} path into a Windows-specific path:

After this task runs, the tomcat_home property contains a path such as C:\AdvServletJSP\tools\jakarta-tomcat-4.0.3.

echo

The echo task writes text to System.out or to a file. I use this to print the results of the pathconvert task to the console:

<echo>
Unless you saw error messages, everything is now installed.
You should set the following environment variables:
TOMCAT_HOME=${tomcat_home}
XALAN_HOME=${xalan_home}
ANT_HOME=${ant_home}
</echo>

delete

delete is the last task used by studentInstall.xml. Its job is to delete files and directories. Most build files provide a target to remove all generated files, and ours is no exception:

<target name="uninstall"
description="Removes all files created by this buildfile">
<delete dir="${destdir}"/>
</target>

In the form shown here, the delete task removes an entire directory along with all files and directories contained within it. This is extremely dangerous, and should be used with caution. It is dangerous because you can accidentally delete your entire project, if you specify the wrong directory, and this operation cannot be undone. On Windows, this task does not send files to the recycler.

You can delete an individual file using this modified syntax:

<delete file="report.xml"/>

But don't do this:

<!-- don't do this!!! -->
<delete dir="reports" file="report.xml"/>

This will delete the entire reports directory, along with all files and directories within it! This is a good example of why you should be careful with the delete task. If you are at all unsure about what will be deleted, you might want to print the name of your directory first, using the <pathconvert> task along with <echo>, as shown earlier in the installAll target. When you are convinced that your build file is pointing to the correct directory, you can put in the delete task.

Ideas for Enhancement

studentInstall.xml is a simple build file, providing a fun way to introduce Ant concepts to students. But from a practical perspective, it does little more than unzip files to directories. Since Java's jar utility can expand .zip files, I could have used a simple batch file to unzip Tomcat and Xalan. But I like the idea of using Ant because it allows for all kinds of future enhancements that cannot be addressed with batch files.

There may come a time when I decide to install something other than .zip files. In addition to .zip, .jar, and .war files, Ant can expand .tar files and GZip files. These would be easy to expand on Unix platforms, but not so easy on Windows. Ant provides the untar and gunzip tasks for these file formats, making the job easy.

The next logical enhancement is to use the javac task to compile all of the student example programs. Compiling code is one of the main reasons for using Ant in the first place, so it makes sense to add this capability. As shown in this article, studentInstall.xml only installs Tomcat and Xalan. Assuming that it also installs a .zip file containing example code for the students, it could compile that code like this:

Because of its dependency on the installAll target, the build file ensures that everything is installed before it attempts to compile the examples. Since the installTomcat and installXalan targets use the unless attribute, they don't do any work if the software is already installed. This allows the build file to operate very quickly. The javac task is also smart about compilation. If the files are already compiled, they are not re-compiled.

After compiling the code, I could use Ant's junit task to run a suite of unit tests:

One final idea for enhancement is to use the ftp task to download software. This would be a really cool feature, because it would eliminate the need for me to distribute all of the .zip files to the student PCs. Instead, they would run the Ant build file, which would download the correct files using FTP. I probably won't do this for practical reasons, however. I fear that downloads will take too long, or that the lab might not have a reliable network connection.

Closing Remarks

I believe that experimentation is the best way to learn about tools like Ant. I taught myself Ant as a result of being frustrated with make files. My original build files did little more than compile code, but quickly became tools for checking out code from CVS, running unit tests, building .jar files, and deploying software to servlet containers. Ant is a neat technology because it allows you to pull together a wide variety of standalone tools into a cohesive development environment.

Ant's flexibility also lets you use it for other jobs, such as installing software. Hopefully you will try out Ant on your own projects, perhaps for something other than compiling code.