0% found this document useful (0 votes)
240 views

Automate Your Build Process Using Java and Ant

A defined process is one of the most necessary but often least-used tools in software development. A defined build process helps close the gap between the development, integration, test, and production environments. Ant is a platform-independent scripting tool that lets you construct your build scripts.

Uploaded by

api-27399718
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
240 views

Automate Your Build Process Using Java and Ant

A defined process is one of the most necessary but often least-used tools in software development. A defined build process helps close the gap between the development, integration, test, and production environments. Ant is a platform-independent scripting tool that lets you construct your build scripts.

Uploaded by

api-27399718
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 14

Automate your build process using Java and

Ant
Introducing the powerful XML-based scripting tool, Ant
By Michael Cymerman, JavaWorld.com, 10/20/00

A defined process is one of the most necessary but often least-used


tools in software development. It is by nature an overhead task that
accompanies a development effort. A defined build process ensures
that the software in your development project is built in the exact
same manner each time a build is executed. As the build process
becomes more complex -- for example, with EJB builds or additional
tasks -- it becomes more necessary to achieve such standardization.
You should establish, document, and automate the exact series of
steps as much as possible.

Why do I need a defined build process?

A defined build process is an essential part of any development


cycle because it helps close the gap between the development,
integration, test, and production environments. A build process
alone will speed the migration of software from one environment
to another. It also removes many issues related to compilation,
classpath, or properties that cost many projects time and money.
What is Ant?
Ant is a platform-independent scripting tool that lets you construct
your build scripts in much the same fashion as the "make" tool in C or
C++. You can use a large number of built-in tasks in Ant without any
customization. Some of the most important tasks are shown in the
following table but explained in more detail in the example that
follows.

Here are some useful commands that are built in the Ant distribution.

Command Description
Ant Used to execute another ant
process from within the current
one.
Copydir Used to copy an entire directory.
Copyfile Used to copy a single file.
Cvs Handles packages/modules
retrieved from a CVS repository.
Delete Deletes either a single file or all
files in a specified directory and its
sub-directories.
Deltree Deletes a directory with all its files
and subdirectories.
Exec Executes a system command.
When the os attribute is specified,
then the command is only
executed when Ant is run on one of
the specified operating systems.
Get Gets a file from an URL.
Jar Jars a set of files.
Java Executes a Java class within the
running (Ant) VM or forks another
VM if specified.
Javac Compiles a source tree within the
running (Ant) VM.
Javadoc/Javadoc2 Generates code documentation
using the javadoc tool.
Mkdir Makes a directory.
Property Sets a property (by name and
value), or set of properties (from
file or resource) in the project.
Rmic Runs the rmic compiler for a
certain class.
Tstamp Sets the DSTAMP, TSTAMP, and
TODAY properties in the current
project.
Style Processes a set of documents via
XSLT.

While other tools are available for doing software builds, Ant is easy to
use and can be mastered within minutes. In addition, Ant lets you
create expanded functionality by extending some of its classes. I will
show this expansion in a following example.

What do I need to use Ant?


You must install three components on your machine to run Ant: JDK,
XML parser, and Ant (see Resources for links).

In many cases, the XML parser is part of the lib files distributed with
the Servlet runner or the Web Server. If not, the free XML parser from
java.sun.com is sufficient. Continued

Ant installation consists of downloading the files, adding the class


libraries to the classpath, and adding the Ant binaries to the path.

Example scenario
This example scenario should help show you the value of Ant and
provide insight into its benefits and how you can use it.

Because a large amount of the current Java development is focused on


server-side Java, I have chosen a server-side application for the
example. Developers working on server-side Java applications are
typically interested in the compilation of servlets, deployment of JSP
files, and deployment of HTML files, configuration files, or images.

A common scheme for doing this build would involve the development
of small scripts in platform-specific languages based on the server's
operating system. For example, a developer working on an NT machine
could create a batch file that performs the compilation tasks and then
runs the deployment. However, if the production environment had Unix
or Linux, the developer would have to rewrite the script, ensuring that
the scripts were in sync.

OK, show me how this works


So, I've hopefully convinced you of the need to use Ant and shown
how simple it is to install. Now I'll show you how simple Ant is to use
by stepping through an example that performs simple compilation and
deployment.

Simple build process with Ant (simple.xml)

<project name="simpleCompile" default="deploy" basedir=".">


<target name="init">
<property name="sourceDir" value="src"/ >
<property name="outputDir" value="classes" />
<property name="deployJSP" value="/web/deploy/jsp" />
<property name="deployProperties" value="/web/deploy/conf" />
</target>
<target name="clean" depends="init">
<deltree dir="${outputDir}" />
</target>
<target name="prepare" depends="clean">
<mkdir dir="${outputDir}" />
</target>
<target name="compile" depends="prepare">
<javac srcdir="${sourceDir}" destdir="${outputDir}" />
</target>
<target name="deploy" depends="compile,init">
<copydir src="${jsp}" dest="${deployJSP}"/>
<copyfile src="server.properties" dest="${deployProperties}"/>
</target>
</project>

There's a lot to explain in the above example. First, you should


understand the structure of the simple.xml file. It is a well-formatted
XML file containing a project entity that is comprised of several target
entities.

The first line contains information about the overall project that is to
be built.

<project name="simpleCompile" default="deploy" basedir=".">

The most important elements of the project line are the default and
the basedir.
The default attribute references the default target that is to be
executed. Because Ant is a command-line build tool, it is possible to
execute only a subset of the target steps in the Ant file. For example, I
could perform the following command:

% ant -buildfile simple.xml init


That will execute the ant command and run through the simple.xml
file until the init target is reached. So, in this example, the default is
deploy. The Ant process invoked in the following line will run through
the simple.xml file until the deploy command is reached: Continued

% ant -buildfile simple.xml

The basedir attribute is fairly self-explanatory as it is the base


directory from which the relative references contained in the build file
are retrieved. Each project can have only one basedir attribute so you
can choose to either include the fully qualified directory location or
break the large project file into smaller project files with different
basedir attributes.
The next line of interest is the target line. Two different versions are
shown here:

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

The target element contains four attributes: name, if, unless, and
depends. Ant requires the name attribute, but the other three
attributes are optional.
Using depends, you can stack the Ant tasks so that a dependent task
is not initiated until the task that it depends on is completed. In the
above example, the clean task will not start until the init task has
completed. The depends attribute may also contain a list of comma-
separated values indicating several tasks that the task in discussion
depends on.
The if and unless commands let you specify commands that are to
be performed either if a certain property is set or unless that property
is set. The if will execute when the property value is set, and the
unless will execute if the value is not set. You can use the available
command to set those properties as shown in a following example, or
you can set them via the command line.
The init target from the simple example contains four lines of
property commands as shown here:

<property name="sourceDir" value="src" />

These property lines let you specify commonly used directories or


files. A property is a simple name value pair that allows you to refer to
the directory or file as a logical entity rather than a physical one.
If you wanted to reference the sourceDir variable later in the Ant file,
you could simply use the following syntax to alert Ant to obtain the
value for this tag: ${sourceDir}.
Two other commands present in the above buildfile are:

<deltree dir="${ outputDir }" />


<mkdir dir="${ outputDir }" />

These commands are used to ensure that there are no extraneous files
in the outputDir (or classes directory when dereferenced as
mentioned above). The first command removes the entire tree
contained under the outputDir. The second command creates the
directory again.
The last line of major interest to the developer is the following
compilation line:

<javac srcdir="${sourceDir}" destdir="${outputDir}" />

The javac command requires a source directory (the input location of


the .java files) and a destination directory (the output location of the
.classes file). It is important to note that all directories must either
exist prior to the running of the ant command or be created using the
mkdir command. Ant does not create directories based upon intuition,
so you must create the outputDir, using the mkdir command prior to
the compilation step above.
After the compile task has completed, the deploy task will perform
the copy operation to move all JSP files from the source directory to a
deployment directory. By using the copydir command, you copy the
entire JSP directory from one location to another. I used the copyfile
command to copy a single properties file as part of the build.
While it took several lines to explain the example, it should be evident
that Ant is an easy-to-use tool. Using this buildfile as a starting point,
you should be able to incorporate Ant into your development effort.
The ant commands shown in the above example have further
functionality, some of which will be discussed in this article, the
remainder is left to you along with references to the documentation.
Important tasks
It is left to you to read through the built-in tasks included in the Ant
distribution. See the user guide in Resources for information about
each command. I have chosen two commonly used commands as
examples of additional options available to the build manager without
any customization.

Compiling code (including EJBs)


In the simple example discussed earlier, you saw a simple form of the
javac command. Now, if you examine it in more detail, you see that
you can specify the compilation flags such as deprecation, debug, or
optimize as well as the files that will or will not be included in the
compilation.

<javac srcdir="${src.dir}"
destdir="${build.classes}"
classpath="${classpath}"
debug="on"
deprecation="off"
optimize="on" >
<include name="**/*.java"/>
<exclude name="**/Script.java" unless="bsf.present" />
<exclude name="**/version.txt" />
</javac>
You can use the include/exclude entities inside the javac task to
include/exclude files matching the pattern in the name attribute from
the compilation. From the above example, you want to include files
contained in any directory ending in .java but, at the same time, you
want to exclude files named Script.java unless a property bsf.present
is set to true.
You set the bsf.present property using the following task that
searches the classpath for the classname specified and sets
bsf.present according to the search results:

<available property="bsf.present"
classname="com.ibm.bsf.BSFManager" />

The javac command will not include files called version.txt from the
compilation based upon the exclude command above.

Generating javadoc
Another task that Ant can help automate is the generation of javadoc.
You can use the following command to generate the javadoc:

<javadoc packagenames="${packages}"
sourcepath="${basedir}/${src.dir}"
destdir="${build.javadocs}"
author="true"
version="true"
windowtitle="${Name} API"
doctitle="${Name}"
bottom="Copyright © 2000 GroupServe. All Rights
Reserved."
/>

The packages specify the overall packages that the javadoc will
include. The sourcepath attribute points towards the location of the
source files. The javadoc command also provides attributes allowing
you to specify the title of the window and the document. You can also
include a copyright notice at the bottom of each javadoc page, using
the bottom attribute. Continued

Can Ant do XYZ?


At this point, you have seen some of the possible tasks in your build
process that Ant can automate. Those tasks are included out of the
box in Ant. You might want to customize Ant to help you perform some
more difficult tasks such as building EJBs and performing remote
configuration management. Some of you may want to increase Ant's
reporting capabilities or construct a user interface that can run the Ant
process.

The simple answer to the question "Can Ant do XYZ?" is "Yes, but you
may have to customize it."

Extending Ant
Two Ant extensions are interesting to discuss at this point. They are
increased reporting and the ability to distribute code remotely using
Ant.

Reporting enhancements
If you wanted to extend Ant's functionality to provide notification when
certain steps in the build process are completed or are in progress,
you can create a class to listen to the Ant process as shown in the
following example.

You can create a class that implements the BuildListener interface.


Using this class, you can catch each event that is part of the
Listener:

public void buildStarted(BuildEvent event);


public void buildFinished(BuildEvent event);
public void targetStarted(BuildEvent event);
public void targetFinished(BuildEvent event);
public void taskStarted(BuildEvent event);
public void taskFinished(BuildEvent event);
public void messageLogged(BuildEvent event);
The BuildEvent event object contains the following methods by which
you can obtain information about the current status of the build:

public Project getProject() ;


public Target getTarget() ;
public Task getTask();
public String getMessage();
public int getPriority();
public Throwable getException();

So if you wanted to write a reporting tool, you need only create a class
that implements the BuildListener interface and process the
BuildEvents as needed by your design. Because Ant initiates the Java
classloader, you must specify the listener as part of your command line
arguments. For example:

ant -listener org.apache.tools.ant.XmlLogger

This listener is included with the Ant distribution and outputs an XML
representation of the build process to a file called "log.xml".

Multiple machines
The above example shows how to extend the functionality of build
reporting. It is of more interest to show how to extend the
functionality of the build itself. For that, I've chosen to work through
an example in which two files are copied from one machine to another
machine, which then performs the Ant operation.

To do that, you can extend Ant by creating custom Task objects for the
remote copy and remote ant commands. Here's an explanation of the
remote copy task definition.
The RemoteTask object extends the Task object. The RemoteTask
object performs all of the functionality necessary for the maintenance
of the connection between the local and remote machines. In this
case, the connection is a socket-level connection.
The RemoteTask object contains the following method declaration that
is necessary for any object that is to extend the Task object:
Continued

public void execute() throws BuildException

The Ant processor calls this method after all of the attributes have
been set. Any custom Task object must override this method.
The RemoteCopyTask performs the steps required to execute the
remote copy operation. The copy operation is on the local machine and
transfers files from the local machine to the remote machine. Some
key things to notice in the RemoteCopyTask code are the three
accessor methods that allow the creator of the Ant buildfile to set the
name, directory, and file type of the file to be transferred.
The RemoteCopyTask, which is run on the local machine, creates a
Command object. The Command object loads the file into a byte array to
prepare for the transfer to the server. On execute, this command
object is serialized and passed to the remote machine.
The RemoteAntHandler object receives the Command object from the
ObjectInputStream. The RemoteAntHandler then deserializes the
object and determines what command to execute. At this point, I have
simplified the example and included both commands in the same
handler as different branches of the if statement. Ideally, another
framework would let the server process those commands more
efficiently.
Because the received command is a copy command, the handler will
write the file to disk with the filename and directory as specified in the
Command object.
In addition to the remote copy command, I have included a remote
ant command. In this case, the local machine can execute the ant
command on the remote machine.
I use the RemoteAntTask, which again extends the RemoteTask object.
The RemoteAntTask simply sets the command to Ant. Future
expansions of this task include the addition of a buildfile specification
and additional functionality contained in the original ant command
itself.
When the RemoteAntHandler object receives and then deserializes the
Command object, it will determine that it should invoke the ant
command. That is handled by having the server spawn another
process calling ant. Why spawn another process? Due to the
architecture of the Ant code, it's not currently possible to call ant and
maintain the JVM. So I've spawned another process, using the
RunProcess object. Please note that the script that invokes the
RemoteServer specifies some command line arguments such as
deployment directory. That was done to limit the potential harm that
an errant buildfile could cause on the remote machine.
The last step in extending Ant to perform the remote commands is to
incorporate these commands in the buildfile. The following buildfile
includes the new commands:

<project name="foo" default="ant" basedir=".">


<target name="init" >
<taskdef name="remoteCopy"
classname="local.RemoteCopyTask"/>
<taskdef name="remoteAnt" classname="local.RemoteAntTask"/>
</target>
<target name="deploy" depends="init2">
<remoteCopy machine="machinename.groupserve.com"
port="9090"
directory="e:\deve\ant\article\deploy" filetype="text"
filename="build.xml" />
<remoteCopy machine="machinename.groupserve.com"
port="9090"
directory="e:\deve\ant\article\deploy" filetype="binary"
filename="app.jar" />
</target>
<target name="ant" depends="deploy">
<remoteAnt machine="machinename.groupserve.com"
port="9090" />
</target>
</project>

Here's the first line of interest:

<taskdef name="remoteCopy"
classname="local.RemoteCopyTask" />
This line creates a taskdef task that associates the name remoteCopy
with the class contained in the file local.RemoteCopyTask. From this
point forward, I can call the task remoteCopy, and my new code will be
executed. For example:

<remoteCopy machine="machinename.groupserve.com"
port="9090"
directory="e:\deve\ant\article\deploy" filetype="text"
filename="build.xml"/>

The remoteCopy task will execute the RemoteCopyTask object and in


doing so, connect to the machine/port specified and copy the file over.
That task includes properties identifying the server/port of the
RemoteAntServer. Also, please note that the three file-related
properties correspond with the accessor methods contained in the
RemoteCopyTask object. Those values are converted into calls to those
methods.
The remoteAnt task has been defined by using a similar taskdef
object:

<taskdef name="remoteAnt" classname="local.RemoteAntTask"/>

The following task will execute the ant command on the remote
machine:

<remoteAnt machine="machinename.groupserve.com"
port="9090" />

Again, note that several command line tags are given when the server
starts to set up the Ant task.

To run the example, please perform the following steps:


1. Use the Ant buildfile build.xml jar to build the article code on the local machine
2. Copy the jar file to the remote machine
3. Execute the remote.bat (or rework for a Linux/Unix machine on the remote
machine)
4. Edit the build.xml file to use machine names and ports appropriate to your
environment
5. Use the Ant buildfile build.xml to execute the build and deploy functionality on
the local machine

If you've performed the above steps, you should notice that the jar file
and build file have been transferred to the remote machine and that
the Ant task has been performed on the remote machine.

Conclusion
So, you've read through all of this. What have you learned?

The biggest takeaway from this article should be the importance of a


build process to construct your environment in an effective and
efficient manner. With that understanding, it is less important that you
use Ant or some other homegrown scripting mechanism. However, I
feel that Ant is an easy-to-learn platform-independent tool that
provides expansion as needed. The XML involved in the buildfile is easy
to read and understand, and a large number of already supported
commands perform the vast majority of your build tasks without
expansion. If you find a limitation, you can expand Ant to include your
modifications.

Please review the Ant user guide found in Resources below to expand
your understanding of the predefined tasks included with Ant. I hope I
have given you a starting point for your future investigation of Ant and
have inspired you to incorporate this tool into your development
process.

You might also like