Version: 1.0.0.rc5
The goals of AntAnt are to:
It's impossible to standardize every aspect of a build without inconveniencing some people or getting into endless arguments about best practices. However 80% of Ant files are the same for every projects (there's a lot of cut and paste in the Ant world) and duplicating the effort for every project gets old fast, as does understanding each and every project's quirks. The build and the project layout used by AntAnt is derived from what seems to work well enough, and from idioms shared by other Java shops, open source projects and outlined in some books.
Most of the tasks in AntAnt can be customized without too much effort. The 20% you need to customize most of the time can be altered via build.xml. Where Ant task tend to become custom is at the deployment end, so typically the things you will need to set up in Ant are:
Source code is available from a subversion repository at http://dehora.net/svn/antant/ - releases are in the tags directory. Releases can be also be found at http://dehora.net/code/antant/.
To run AntAnt you will need Ant 1.6 or greater and have declared an ANT_HOME envar.
Cd to where you want AntAnt installed and check it out from Subversion.
E:\home>cd e:\java E:\java>svn co http://dehora.net/svn/antant/tags/antant/1.0.0 antant-1.0.0 A antant-1.0.0\antant.xml A antant-1.0.0\antant A antant-1.0.0\doc A antant-1.0.0\doc\layout.png A antant-1.0.0\doc\readme.html A antant-1.0.0\lib A antant-1.0.0\lib\antant-ext.zip A antant-1.0.0\antant.bat A antant-1.0.0\README.txt A antant-1.0.0\template A antant-1.0.0\template\ant A antant-1.0.0\template\ant\import-war.xml A antant-1.0.0\template\ant\import-base.xml A antant-1.0.0\template\ant\tomcat.properties A antant-1.0.0\template\ant\jdepend.xml A antant-1.0.0\template\ant\get-ant-ext.xml A antant-1.0.0\template\ant\import-tomcat.xml A antant-1.0.0\template\run.xml A antant-1.0.0\template\ivy.xml A antant-1.0.0\template\src A antant-1.0.0\template\src\java A antant-1.0.0\template\src\java\META-INF A antant-1.0.0\template\src\java\META-INF\ejb-jar.xml A antant-1.0.0\template\src\java\WEB-INF A antant-1.0.0\template\src\java\WEB-INF\web.xml A antant-1.0.0\template\build.properties A antant-1.0.0\template\ivyconf.xml A antant-1.0.0\template\build.xml Checked out revision 6. E:\java>
AntAnt also requires some Ant extensions to be available on the classpath. The handiest place to put these is in Ant's lib folder. Run the setup target to perform the install:
E:\java>cd antant-1.0.0
E:\java\antant-1.0.0>antant setup
Buildfile: E:\java\antant-1.0.0\antant.xml
setup:
[get] Getting: http://dehora.net/code/antant-ext.zip
[get] To: E:\java\apache-ant-1.6.5\antant-ext.zip
[get] ...................
[get] last modified = Thu Sep 08 01:37:25 BST 2005
[unzip] Expanding: E:\java\apache-ant-1.6.5\antant-ext.zip into E:\java\apache-ant-1.6.5\lib
BUILD SUCCESSFUL
Total time: 14 seconds
E:\java\antant-1.0.0>
Now add the antant folder to your Path. To tests antant is available, run the version target:
E:\home>antant version
Buildfile: E:\java\antant\antant.xml
version:
[echo] AntAnt: version 1.0.0
BUILD SUCCESSFUL
Total time: 0 seconds
E:\home>
That's it. Let's create a project.
To create a project call the 'create' target. You'll be asked the following questions about your project:
E:\home>antant
Buildfile: E:\java\antant\antant.xml
create:
[echo] AntAnt: version 1.0.0.rc4
[input] Please enter the project location (an absolute path):
[input] Please enter project name (this will be the project directory):
Terminate batch job (Y/N)? y
E:\home>antant create
Buildfile: E:\java\antant\antant.xml
create:
[echo] AntAnt: version 1.0.0.rc3
[input] Please enter the project location (an absolute path):
e:/home
[input] Please enter project name (this will be the project directory):
world-domination
[input] Please enter project/package org name (this will be used in jar and dist names):
evilinc
[input] Do you want a web.xml file? (y,n)
y
[input] Do you want an SQL DDL area? (y,n)
y
[mkdir] Created dir: E:\home\world-domination
[mkdir] Created dir: E:\home\world-domination\ant
[mkdir] Created dir: E:\home\world-domination\bin
[mkdir] Created dir: E:\home\world-domination\build
[mkdir] Created dir: E:\home\world-domination\conf
[mkdir] Created dir: E:\home\world-domination\docs
[mkdir] Created dir: E:\home\world-domination\src
[mkdir] Created dir: E:\home\world-domination\src\main
[mkdir] Created dir: E:\home\world-domination\src\main\java
[mkdir] Created dir: E:\home\world-domination\src\test\java
[mkdir] Created dir: E:\home\world-domination\lib
[copy] Copying 1 file to E:\home\world-domination
[copy] Copying 1 file to E:\home\world-domination
[copy] Copying 1 file to E:\home\world-domination
[copy] Copying 1 file to E:\home\world-domination\ant
[copy] Copying 1 file to E:\home\world-domination
[copy] Copying 4 files to E:\home\world-domination
make.web-inf:
[echo] making WEB-INF in e:/home/world-domination/src/main/webapp/WEB-INF
[echo] ** WARNING: to use tomcat tasks, add the line to build.xml's imports
[echo] ** WARNING: to use war tasks, add the line to build.xml's imports
[mkdir] Created dir: E:\home\world-domination\src\main\webapp
[mkdir] Created dir: E:\home\world-domination\src\main\webapp\images
[mkdir] Created dir: E:\home\world-domination\src\main\webapp\style
[mkdir] Created dir: E:\home\world-domination\src\main\webapp\script
[mkdir] Created dir: E:\home\world-domination\src\main\webapp\WEB-INF
[mkdir] Created dir: E:\home\world-domination\src\main\webapp\WEB-INF\layout
[mkdir] Created dir: E:\home\world-domination\src\main\webapp\WEB-INF\pages
[copy] Copying 1 file to E:\home\world-domination\ant
[copy] Copying 1 file to E:\home\world-domination\ant
[copy] Copying 1 file to E:\home\world-domination\src\main\webapp\WEB-INF
make.ddl.dir:
[echo] making src/main/ddl
[mkdir] Created dir: E:\home\world-domination\src\main\ddl
[echo] Project 'world-domination' created in e:/home
BUILD SUCCESSFUL
Total time: 22 seconds
E:\home>
Produces the following layout:
The AntAnt project structure:
AntAnt generates a number of files:
If your project has a web application and you want to use Tomcat and War tasks, you need to have build.xml import the tomcat and war files. Change the generated build.xml to look as follows
<!-- =============================================================== Imports ==================================================================== --> <import file="ant/import-base.xml"/>
<import file="ant/import-tomcat.xml"/> <import file="ant/import-war.xml"/>
clean clean compile targets
compile build the code and copy over resources
doc generate the javadoc
jar Generate the jar file(s)
test run the junit tests
war build the war file
To see all the tasks run 'ant -projecthelp'
E:\temp\world-domination>ant -projecthelp
Buildfile: build.xml
Main targets:
antant.version print the AntAnt version used to create this build
clean clean compile targets
clean-dist blow away the last dist creation
compile build the code and copy over resources
cp.build print the build classpath
cp.test print the test classpath
dist create a binary distribution
dist-src prepare a source distribution
doc generate the javadoc
global-publish-jar build and install the jars to the global lib dir
ivy.configure setup Ivy with ivyconf.xml
ivy.report generates a report of dependencies with Ivy
ivy.resolve retrieve dependencies with Ivy
jar build all the jar packages
setup Download global jar extensions for Ant builds
test run the junit tests
test-report Executes the unit tests and produce the report
Default target: test
The build.properties file can be used to overrride any of the properties, and has the following fields declared by default:
# ------------------------------------------------------------------------------
# Project info
# ------------------------------------------------------------------------------
release.version=0.0.0
project.name=world-domination
project.org=evilinc
# ------------------------------------------------------------------------------
# Packaging,:
# ------------------------------------------------------------------------------
jar.name=${project.org}-${project.name}
# ------------------------------------------------------------------------------
# If you want to override a property, do it here:
# ------------------------------------------------------------------------------
AntAnt uses the macrodef feature of Ant to create jarfiles. Here's the jar task unchanged from a generated build file:
<!-- ====================================================================
Custom packaging: add macro-jar calls into the jar target
==================================================================== -->
<patternset id="jar.exclusion.set">
<!-- example: <exclude name="org/example/stuff/service/beans/**"/> -->
</patternset>
<patternset id="jar.inclusion.set">
<include name="**/**"/>
</patternset>
<target name="jar" depends="clean, compile" description="build all the jar packages">
<macro-jar
jarname="${jar.name}"
incl="jar.inclusion.set"
excl="jar.exclusion.set" />
</target>
The inclusion and exclusion patternsets are used to define what classes are included or excluded from the jar. To produce multiple jars from a single project you will need to add multiple macro-jar calls inside the jar target. For example the deps/service project creates a service and beans jar from a single project as follows:
<patternset id="jar.exclusion.set">
<exclude name="org/example/stuff/service/beans/**"/>
</patternset>
<patternset id="jar.inclusion.set">
<include name="**/**"/>
</patternset>
<patternset id="jar.beans.exclusion.set">
</patternset>
<patternset id="jar.beans.inclusion.set">
<include name="org/example/stuff/service/beans/**"/>
</patternset>
<target name="jar" depends="clean, compile" description="build all the jar packages">
<macro-jar
jarname="${jar.beans.name}"
incl="jar.beans.inclusion.set"
excl="jar.beans.exclusion.set" />
<macro-jar
jarname="${jar.name}"
incl="jar.inclusion.set"
excl="jar.exclusion.set" />
</target>
Deployment metadata
The jar/war tasks insert versioning data into the Manifest.mf file. This allows an association between
version control tags and deployed code. The version number is taken from 'release.version' property in
build.properties. Here's an example:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.6.1
Created-By: 1.4.2_03-b02 (Sun Microsystems Inc.)
Built-By: dehora
Sealed: false
Specification-Title: WorldDomination
Specification-Version: 1.0.0
Specification-Vendor: evilinc
Implementation-Title: WorldDomination
Implementation-Version: 1.0.0
Implementation-Vendor: evilinc
Creating Webapps and warfiles
Web applications tend to need custom setups, so all the war tasks are in a separate import file, ant/import-war.xml.
The war specific targets can be used to create, deploy wars or update static files; they assume a certain layout based
on the folder layout created during setup:
./src
/webapp
/images (gifs, pngs)
/script (javascript, xslt
/style (css sheets)
/WEB-INF
/web.xml
/layout (templates etc)
/pages (jsps etc)
I've used this layout on a few projects and it works fine. If you don't want this layout
you will have to edit the tasks and properties in ant/import-war.xml.
The following web related tasks are available:
deploy-unwar deploy webapp as unpacked to the servlet container
deploy-war deploy the war to the servlet container
rebuild-webapp create an unpacked webapp, deploy it and restart tomcat
war build the war file
deploy-webapp-static fast deploy, no jars or classes, good for jsp work
Some people will find setting up their IDE for servlet projects will result in
faster copy/reload cycles for webapp development. For that advantage you'll trade
some dissonance with the production application structure and the fact that
your IDE setup, classpath, etc is unique to you. The advantage of these tasks is that they'll
mirror the actual deployment process and classpath in a production environment.
When you ask for a webapp structure, AntAnt will copy over Tomcat Ant tasks to your project's ant folder.
The access control details can be specified in ant/tomcat.properties; see the Tomcat documentation for general
info on how to use these tasks. The project.servletcontainer.deploy property can be overridden to
specify a local Tomcat area; its default value is ${third.party.location}/jakarta-tomcat/webapps.
Dependency management and classpaths
There seems to be two schools of thought on managing third
party jar dependencies in Java projects:
Once Ivy is configured, the Ant build can find its jars in two places:
AntAnt has 2 classpath declarations in build.xml
Sometimes you won't be able to use an online repositories to grab a jar file. Either it's not there or the url is misconfigured so that Ivy can't locate the file. Or perhaps you just want to keep jars locally. Then you'll need a file system based repository. This can be located anywhere, but by default AntAnt has a filesystem repository location preconfigured. To understand this we'll need to look at the ivyconf.xml file:
<ivyconf>
<conf defaultResolver="default" checkUpToDate="true"/>
<resolvers>
<chain name="default">
<filesystem name="global.depend">
<artifact pattern="${global.depend.location}/[organisation]/[artifact]-[revision].[ext]" />
</filesystem>
<ivyrep name="ivyrep"/>
<ibiblio name="ibiblio" />
</chain>
</resolvers>
</ivyconf>
The main bit is the 'filesystem' element.
Here it says there is a filesystem repository called global.depend, which has a path pattern (layout) as follows:
${global.depend.location}/[organisation]/[artifact]-[revision].[ext]
Ivy (and Maven) repositories can be organised according to a standard layout.
${global.depend.location} is an ant expression and by default expands to "../lib"
in AntAnt. You can change this in build.xml, but this is a useful default location if your AntAnt project
is one of many subprojects - they can all depend on a relative lib folder at the superprojects' top level.
The rest of the path /[organisation]/[artifact]-[revision].[ext] is saying the lib folders
are organised by organisation folders (ie 'mysql') and the jarfile names will be project-revision.ext,
(ie "mysql-connector-java-3.1.11.jar"). New jars can now be declared in ivy.xml inside the 'dependencies' element something like this:
<dependency org="mysql" name="mysql-connector-java" rev="3.1.11" />Note how the 'org', 'name' and 'rev' attributes map onto the path structure declared in ivyconf.xml. If you had a project layout like this
./super-project
/test-project
build.xml
ivy.xml
ivyconf.xml
/ant
/bin
/conf
/bin
/docs
/lib
You could add a top level lib folder as follows:
./super-project
/test-project
build.xml
ivy.xml
ivyconf.xml
/ant
/bin
/conf
/bin
/docs
/lib
./lib
/mysql
/mysql-connector-java-3.1.11.jar
and if your ivy.xml and ivyconf.xml files are setup as above, Ivy will locate the mysql jar from the filesystem.
JDepend traverses Java class file directories and generates design quality metrics for each Java package. JDepend allows you to automatically measure extensibility, reusability, and maintainability aspacts of an object design and to manage package dependencies. The JDepend task in ant/jdepend.xml produces a html report for the project. Full documentation: http://www.clarkware.com/software/JDepend.html
To use JDepend, you need to import the jdepend tasks. Change build.xml to look as follows
<!-- ===============================================================
Imports
==================================================================== -->
<import file="ant/import-base.xml"/>
<import file="ant/import-jdepend.xml"/>
I've been using AntAnt in one form or another since 2001. AntAnt is not meant to be a framework and there are no plans to make it so. It's a stunt work - something that should be small enough to explained in an hour and after that hour something you should feel comfortable changing for your own needs.
Therefore I don't have new features planned, but if you find bugs mail me.