List of Figures
Chapter 1. Introducing Ant
Figure 1.1. Conceptual view of a build file. The project encompasses a collection of targets. Inside each target are task
declarations, which are statements of the actions Ant must take to build that target. Targets can state their dependencies
on other targets, producing a graph of dependencies. When executing a target, all its dependents must execute first.
Chapter 2. A first Ant build
Figure 2.1. The XML Representation of a build file is a tree: the project at the root contains one target, which contains
two tasks. This matches the Ant conceptual model: projects contain targets; targets contain tasks.
Figure 2.2. The directory layout for our project—keeping source separate from generated files. The shaded directories and
files are created during the build.
Figure 2.3. Once you add dependencies, the graph of targets gets more complex. Here clean depends upon init; archive depends
on compile, and, indirectly, init. All of a target’s dependencies will be executed ahead of the target itself.
Figure 2.4. Our build file hosted under Eclipse. Consult Appendix C for the steps needed to do this.
Chapter 4. Testing with JUnit
Figure 4.1. UML diagram of the core of our diary. Interfaces and classes in grey are those of the Java libraries. We’re going
to assume they work and not test them ourselves.
Figure 4.2. JUnit UML diagram depicting the composite pattern utilized by TestCase and TestSuite. A TestSuite contains a collection
of tests, which could be either more TestSuites or TestCases, or even classes simply implementing the test interface. The
Assert class provides a set of static assertions you can make about your program.
Figure 4.3. JUnit’s Swing GUI has successfully run our test case. A green bar indicates that all is well. If there was a red
bar, we would have a problem.
Figure 4.4. Adding test targets to the build process. Tests can be compiled only after the main source is compiled; the test
run depends on the tests being compiled.
Figure 4.5. The test results presented by <junitreport>. The main page summarizes the test statistics and hyperlinks to test
case details.
Figure 4.6. Test case results showing the assertion that failed, and the stack trace. The output log is under the System.out
link. Keep an eye on the Time Stamp to make sure you’re not viewing old test results.
Chapter 5. Packaging projects
Figure 5.1. The packaging process: a JAR library consists of getting the source and data files into the JAR and the documentation
into a directory, then creating the Zip and tar packages for distribution.
Figure 5.2. The generated API documentation
Figure 5.3. A UML view of the Java archives. WAR and EAR files are subclasses of the JAR file, which is itself a subclass
of a Zip file class. WAR files can contain JAR libraries; EAR files can contain JAR and WAR files. JAR files contain a manifest,
and usually at least some .class files.
Figure 5.4. The implementation hierarchy of Ant’s packaging classes and tasks. The <zip>, <jar>, <war> and <ear> task hierarchy
resembles that of their respective file types.
Chapter 6. Executing programs
Figure 6.1. Ant can spawn native applications, while Java programs can run inside or outside Ant’s JVM.
Chapter 7. Distributing our application
Figure 7.1. Checking our mailbox. Our original message said “This is paypal security, please run this program to secure your
account,” but the spam filters kept deleting it.
Figure 7.2. A model of how <antcall> creates a new project, with its own internal state
Chapter 8. Putting it all together
Figure 8.1. How to lay out classes in a large project. The files and directories in white are the source; those in grey are
created in the build. Source and test source code trees are split up and compiled into different directories. Unit Test cases
are in /test packages.
Chapter 9. Beyond Ant’s core tasks
Figure 9.1. Stop! It’s the code police! The tool also has caught the fact that we’ve forgotten to make a constant final. The
case rule of constants (all capitals) did not match that of a variable.
Chapter 10. Working with big projects
Figure 10.1. A graph of the direct dependencies between our modules.
Figure 10.2. A master build can set the properties for the child projects, even if those projects try to override them. If
the master build had accidentally used value instead of location, the directory location would have still been resolved in
the client build files relative to their own directory, which would be a bug.
Chapter 11. Managing dependencies
Figure 11.1. Ivy reports the dependencies for one of the configurations
Figure 11.2. In this configuration, two obsolete modules are evicted.
Chapter 12. Developing for the Web
Figure 12.1. The basic workflow for constructing a web application
Chapter 13. Working with XML
Figure 13.1. The <xslt> task transforms XML into other file formats or into new XML files.
Figure 13.2. The generated HTML page. We can use this in developer documentation, or add it to the web site content.
Chapter 14. Enterprise Java
Figure 14.1. The new architecture of the diary application. The proxy class is created for us, and bridges from the web application
to the session bean.
Figure 14.2. How Cactus runs tests on the server. The client program relays test requests to the server over HTTP; results
come back the same way.
Chapter 15. Continuous integration
Figure 15.1. CruiseControl was the first continuous-integration server. The build loop polled for changes, ran the builds,
and published reports; the web front end displayed the results. Everything was driven by the config.xml file.
Figure 15.2. Adding a user to Luntbuild. You can be notified by email, IM, or blog postings.
Figure 15.3. A server populated with a full set of users
Figure 15.4. A Luntbuild project is bound to a source code repository and can have different builders to build parts of the
project on defined schedules.
Figure 15.5. The VCS Adaptor to check out the project from SourceForge
Figure 15.6. Luntbuild configuration of our builder. To create a new builder, click the “new document” icon on the top-right
corner.
Figure 15.7. The schedule contains the settings to run an incremental build of our project. It declares dependencies on other
schedules, the builder to run, and the actions to take on success.
Figure 15.8. Mappings from usernames in the repository to Luntbuild users
Figure 15.9. The Luntbuild status page. The book is building; some of the other projects are failing. A clean build is under
way.
Chapter 16. Deployment
Figure 16.1. The goal for our distribution: Ant telling SmartFrog to deploy our entire system, including setting up the application
server and the database
Figure 16.2. The SmartFrog daemons build up a distributed graph of things to deploy. Cross-references are still valid across
the network.
Figure 16.3. The lifecycle of a component. Things get deployed, then started, and finally terminated. Unless something fails,
of course.
Figure 16.4. A running system. JBoss and MySQL are running on separate hosts. The happy component’s action fetches the happy.jsp
page every time its parent pings it.
Figure 16.5. Package layout for deployment descriptors. Every descriptor is a resource in a Java package but is built into
a separate JAR from the application. That lets us change this JAR and sign it without having to rebuild the application itself.
Descriptors in the deploy. targets package are targeted at different machines, while those in the parent deploy package are
the reusable templates.
Figure 16.6. The management console, showing the status of the deployed application. The elements under the happy component
have not yet been deployed, as it delays for a minute before starting happy page checks.
Figure 16.7. The waterfall process is inflexible and widely discredited. But look how an iterative development cycle can revert
to a waterfall at the final stage.
Figure 16.8. Integrating deployment into the development cycle. Deploy to production systems, then test.
Chapter 17. Writing Ant tasks
Figure 17.1. Common classes encountered inside Ant. Projects, Targets, and Tasks map 1:1 with the <project>, <target>, and
task declarations. The other interfaces and classes are implementation details.
Figure 17.2. The Resource class has many derivatives, any of which can be added to resource collections. The Resource class
is in the org.apache.tools.ant.types package; all the derivatives go under the org.apache.tools.ant.types.resources.
Figure 17.3. A UML outline of the resource classes. The methods and attributes have been stripped off as the diagram is complex
enough already.
Chapter 18. Extending Ant further
Figure 18.1. The BuildListener and BuildLogger receive lifecycle events, events which are described by BuildEvent objects.
Appendix C. IDE Integration
Figure C.1. Eclipse debugging an Ant build. It has stopped at a breakpoint and is showing the current set of Ant properties.
Figure C.2. Eclipse projects “build” through builders. You can add a build file as a builder through the project’s properties
dialog, where it can live alongside the projects’ other builders.
Figure C.3. You can add any program as a new builder, but only Ant has built-in support from the IDE.
Figure C.4. The first step to setting up the new builder is to set the path to the build file and its base directory. You
also can add arguments to the command line, but not -lib or -logger related, as the IDE is in charge of those.
Figure C.5. You can add any number of targets to the IDE actions. “Auto Build” is the background compile of the application;
the “After a Clean” and “Manual Build” builds are the targets to do a clean and incremental build of the application.
Figure C.6. Selecting targets to run in response to IDE actions. Avoid setting up long lists of targets for each action; it’s
better to create new targets in the build file with the appropriate dependencies. This lets you use it from the command line
and makes it available to other developers.
Figure C.7. To choose and configure the Ant runtime in Eclipse, go through the Preferences dialog to the Ant runtime, and
select a new Ant Home, the base directory of the Ant installation.
Figure C.8. NetBeans running a build file that prompts for input. It brings up a dialog in this situation. We’ve set a breakpoint
on the following task, so the debugger will halt the build.
Figure C.9. Adding an existing Ant project to NetBeans. It will create a subdirectory, nbproject, to hold extra project information,
such as custom build files for the debugging actions.
Figure C.10. Binding targets to the stages in the build file. You don’t need a target for every action at this point, as you
can edit these bindings later
Figure C.11. Configuring Ant in NetBeans. We’ve entered the location of our command line Ant distribution. The IDE-supplied
Classpath option is left alone. Checking the “Save Files” option tells the IDE to save all files before running a build. Always
select this option.
Figure C.12. IntelliJ IDEA running the SSH upload targets of chapter 7. The connection is failing, and an error is appearing
in the messages window. Clicking on the error brings up the line of the build file. IDEA highlights all unknown properties—here
it is marking as unknown all properties loaded from the server-specific properties file.
Figure C.13. Selecting the actions for which we want a deployment target to run; here the Tomcat and JUnit activities both
trigger the action. You may find that you will need IDE-specific targets for such actions, targets that do not depend on the
complete build taking place. This is because the IDE has already taken on much of the build.
Figure C.14. IntelliJ IDEA lets developers run a version of Ant in the file system, rather than the built-in version, with
extra JARS on the classpath and with custom properties.