============================
Project Automation Using Ant
============================
:Author: Nick Efford
:Contact: N.D.Efford@leeds.ac.uk
:Status: Final
:Revised: 2017-09-13
The objectives of this worksheet are for you to learn the main features of
the Ant_ build tool, for you to gain experience of running Ant from the
command line and for you to see how Ant is used within Intellij IDEA.
You may find it useful to consult the `Ant manual`_ as you carry out the
tasks below.
.. _Ant: http://ant.apache.org/
.. _Ant manual: http://ant.apache.org/manual/
Getting Started
===============
#. Create a directory in your filestore for this worksheet, then download Zip
archive :download:`Ant.zip` into that directory.
#. Unpack the Zip archive - e.g., using the ``unzip`` command in a terminal
window. This will give you a directory tree like the following
.. code-block:: none
build.xml
lib/
hamcrest-core-1.3.jar
junit-4.12.jar
scripts/
alarmclock.bat
alarmclock.sh
clock.bat
clock.sh
src/
comp2931/
time/
AlarmClock.java
Clock.java
Time.java
TimeTest.java
Spend a couple of minutes examining these files.
Ant Concepts
============
The file :file:`build.xml` is an **Ant buildfile**. Open it in an ordinary
text editor such as Atom or gedit. You should see this:
.. literalinclude:: build.xml
:language: xml
:linenos:
* Everything is defined inside a ``project`` element, which has attributes
to specify the project name and the base directory from which all paths
to files and directories are computed.
* Inside the ``project`` element are four **property settings** (lines 4-7).
Rather like variables in a program, these provide a single point of
definition for frequently-used values, making it easier to change those
values in future.
In this case, the buildfile defines properties specifying the three
existing directories plus one that doesn't yet exist. The latter is
where the ``.class`` files produced by the compiler will be stored.
* After the properties is a **path definition** (lines 9-13). This defines
the project's classpath - i.e., the path that will be used to find
classes when invoking the Java compiler or JVM.
* After the path definition are three **targets**, with names ``init``,
``compile`` and ``clean``. Targets are sets of tasks to be peformed
by Ant. You specify one or more targets to be executed when you run Ant.
The ``compile`` target contains the ``javac`` task, which runs the Java
compiler on the code in the directory subtree specified by property
``src.dir``. Notice that ``compile`` depends on ``init``. This means
that ``init`` will run if necessary before ``compile`` runs. In this
case, ``init`` simply runs the ``mkdir`` task to create the
subdirectory for compiled code.
Basic Usage
===========
#. In a terminal window, cd to the directory containing the buildfile and
enter the command ``ant -h``. This will show you the various options
that can be specified when running Ant.
#. Enter ``ant -p``. This provides 'project help' by listing the targets
defined in the buildfile.
#. Run the ``compile`` target by entering ``ant compile``. Ant will
report on the tasks it is executing. (You can suppress this using the
``-q`` option.) Notice that ``init`` runs first.
Use ``ls`` to list directory contents. Notice that a ``bin`` directory
now exists. Look into the subdirectories of ``bin`` and you will
find the ``.class`` files generated by the compiler.
#. Enter ``ant compile`` a second time. Ant will do nothing because the
``bin`` directory already exists and the bytecode it contains is
up-to-date.
#. Edit one of the ``.java`` files under ``src`` and make a trivial change
to one of the files (such as altering one of the comments). Save your
change, then go back to the command prompt and enter ``ant compile``
again. Notice that only the changed file is recompiled.
#. Enter ``ant clean`` to remove the ``bin`` directory.
#. Try entering ``ant`` with no arguments. Ant will run and report 'BUILD
SUCCESSFUL', but it won't actually do anything because we haven't
specified a default target. Specify one now by going to your text
editor and adding ``default="compile"`` to the ``project`` tag at the
start of the buildfile.
Enter ``ant`` again with no arguments. The ``init`` and ``compile``
tasks will be executed.
Running Applications
====================
We have two Java applications: ``Clock`` and ``AlarmClock``. The former
simulates a clock by printing the current time once every second. The latter
also displays the time but uses a Swing-based graphical user interface and
adds the ability to set an alarm to a time specified via a command line
argument.
Let's add targets to run these applications.
#. Edit ``build.xml`` and, beneath the ``compile`` target, add the following
chunk of XML:
.. code-block:: xml
Notice the dependency on ``compile`` and the way in which the classpath
is specified for the ``java`` task.
Try running the ``Clock`` application by entering ``ant clock``. The
application will run for 10 seconds and then stop. You can terminate it
prematurely by pressing :kbd:`Ctrl+C`.
#. Now add the following target to ``build.xml``:
.. code-block:: xml
Notice the use of ``fork="true"`` in the ``java`` task. This means that
the application will run in a separate JVM rather than in the JVM that is
running Ant. This ensures correct behaviour for Swing-based applications.
The ``AlarmClock`` application requires a command line argument to specify
alarm time, which we supply by nesting an ``arg`` element inside the
``java`` element. The value of ``+10`` means an offset of 10 seconds in
the future.
Try running ``AlarmClock`` by entering ``ant alarmclock``. After 10
seconds, the window should flash with a yellow background. You can
disable the alarm by clicking on the background. The application can be
shut down in the usual way.
Running Tests
=============
Ant provides the ``junit`` task, which can run unit tests using JUnit and
collect the results.
#. Add the following new target to ``build.xml``, beneath the ``alarmclock``
target:
.. code-block:: xml
The ``formatter`` element inside the task configures how test output
will be collected. In this case, it will be displayed as plain
text on screen rather than being directed to a file. The ``test``
element is used to specify the test classes you wish to run [#]_.
#. Run the target with ``ant test``. Ant should run the ``junit`` target
and report that 11 tests have passed, as well as listing the individual
test cases and how long it took to execute them. (The latter can be
avoided by specifying a formatter type of ``brief`` rather than
``plain``.)
Generating Documentation
========================
Ant can run the Javadoc tool, which extracts information from comments in
Java source code and generates HTML documentation for that code.
#. Add the following to ``build.xml``, beneath the existing property
definitions:
.. code-block:: xml
#. Now add a new target called ``docs`` that executes the ``javadoc``
task:
.. code-block:: xml
This target creates a new directory if necessary and then runs Javadoc,
putting the generated HTML files in that directory. The ``fileset``
element specifies the files to be processed as everything under the
``src`` directory with a name that does not end in ``Test.java``.
This ensures that documentation isn't generated for any unit testing
classes.
#. Run the new target by entering ``ant docs``. This should create a new
directory called ``doc`` and then populate that directory with HTML
pages generated for the ``Time``, ``Clock`` and ``AlarmClock`` classes.
View this documentation by loading ``doc/index.html`` into a web browser.
Adding Targets For Packaging
============================
It is often convenient to bundle the ``.class`` files for an application
into a **JAR file** (Java Archive file). This makes distributing
applications in executable form easier. We might also want to distribute
code with accompanying documentation, bundling both together in a Zip
archive. Ant supports both of these tasks.
#. Add the following to ``build.xml``, beneath the existing property
definitions:
.. code-block:: xml
These define the names and locations of the JAR file that will hold the
compiled applications and a Zip archive that could be used to ship this
JAR file plus other associated files (shell scripts and documentation)
to users.
#. Add the following target to support JAR file creation:
.. code-block:: xml
The ``jar`` target has successful compilation as a prerequisite. It
packages the ``.class`` files under ``bin``, excluding ``TimeTest.class``,
as a single JAR file called ``clocks.jar`` and puts this in the ``dist``
directory. This directory will be created if it doesn't already exist.
Try this out now. Run the target with ``ant jar``, then move into the
``dist`` directory and try running the ``AlarmClock`` application
like so:
.. code-block:: none
java -jar clocks.jar +10
#. Add the following target to support Zip archive creation:
.. code-block:: xml
The ``zip`` target expects a JAR file and Javadoc-generated documentation
to be present and will execute the relevant targets if not. It packages
these elements along with the scripts in the ``scripts`` directory as
a single Zip archive. Try running the target now with ``ant zip``.
You should see a ``.zip`` file created in the ``dist`` directory. Copy
this file somewhere else, unzip it and try running the applications
via the scripts.
#. Finally, alter the existing clean-up target and add another one, so that
you end up with the following code:
.. code-block:: xml
You now have two ways of cleaning up the project: ``ant clean`` will
remove compiled code and documentation, leaving files for distribution
untouched, whereas ``ant veryclean`` will remove all files generated
by the other targets. Try the latter now.
Try running ``ant zip`` again to see how the distributable Zip archive
can be built from scratch with a single command.
Using Ant With IntelliJ
=======================
#. IntelliJ provides some rudimentary support for Ant buildfiles. To try
this out, open an existing Java project - e.g. the ``JUnit`` project
created for :doc:`/junit/main`. Once the project is open, choose
:menuselection:`&Build --> &Generate Ant Build...`.
On the resulting dialog, select the option to 'Generate single-file ant
build' and specify ``build`` as the output file name. Then untick
the checkbox for 'Enable UI forms compilation' and click
:guilabel:`OK`. Two new files should be created in the project:
:file:`build.xml` and :file:`build.properties`.
#. Open :file:`build.xml` in the code editor. You will see that it is
fairly complex. Fortunately, IntelliJ provides an easier way to interact
with it.
Click on the :guilabel:`Ant Build` tab, normally located on the right
edge of the UI. The Ant Build tool window will slide out. Click on the
green 'plus' button at the top of the tool window, select
:file:`build.xml` on the resulting dialog and click :guilabel:`OK`.
The targets from the buildfile should now appear in the Ant Build window.
.. figure:: antbuild.png
:align: center
#. Right-click on the 'clean' target in the Ant Build window and choose
:menuselection:`Run Target`. Activate the Messages tool window by
clicking the :guilabel:`0: Messages` tab or by pressing :kbd:`Alt+0`.
You should see a series of messages on the progress of the build
displayed. These are organised hierarchically; you can double-click
on entries to go deeper and get more detail.
Now turn your attention to the Project tool window. If you expand the
:file:`out` directory, you should see that its sudirectories are
now empty.
#. Right-click on the 'compile.module.testing' target in the Ant Build
window and choose :menuselection:`Run Target`. This compiles both the
``Time`` class and the ``TimeTest`` class. If you check the :file:`out`
folder again, you should see that the corresponding ``.class`` files
have now been added.
.. note::
Support for Ant in IntelliJ is limited. Automatically generated buildfiles
contain targets to compile and clean a project, but if you want anything
else (e.g., a target to run unit tests) you will need to add it yourself.
Other build tools such as Gradle_ are better supported by IntelliJ.
.. _Gradle: https://gradle.org
----
.. [#] If there are multiple test classes, you either use multiple ``test``
elements or use a ``batchtest`` element to tell Ant it should run
all the test classes that match a particular pattern.)