Ant Tutorial

Overview

This page is a tutorial of Ant. It starts with a simple example and progressively builds on that example to achieve greater functionality. In the course of the tutorial we’ll learn how to address two central issues to using Ant for large-scale builds: how to avoid a monolithic ‘build.xml’ file, and how to manage cross-project dependencies.

There are two aspects to cross-project dependency management. First, we want to enforce dependencies. That is, we want out build process to report a build failure if a project accesses a resource where that access violates declared dependencies. Second, we want to minimize build configuration effort in response to changes in dependencies. The final solution in this tutorial will address both these issues.

Prerequisites

This tutorial was developed with Ant 1.6.5, Ant-Contrib 1.0b2, JDK 1.5, and GraphViz 2.6.

Ant 1.6 introduced the ‘import’ task. This task, in conjunction with Ant-Contrib, will allow us to solve the monolithic build file problem. You will need to install Ant, but Ant-Contrib is packaged with the tutorial.

Weaver is a custom Ant task library that simplifies cross-project dependency management. It is packaged with the tutorial. Weaver uses JDK 1.5, so you will need to install JDK 1.5.

You only need to install GraphViz if you want to use the ‘WeaverGraph’ task to generate a picture of the project dependencies.

Step 1: Hello world

Our first assignment is to get a Java file to compile and run using Ant. First, we have to install Ant:

  1. Download and install Ant.
  2. Create ‘ANT_HOME’ environment variable.
  3. Add ‘%ANT_HOME%bin’ directory to ‘PATH’ environment variable.

Alright, go into directory ‘src/step-1’ and run ‘ant’ at the command-line.

Directory Structure

build.xml
HelloWorld.java

step-1/build.xml

<project default="run">
  <target name="run">
    <javac srcdir="." destdir="."/>
    <java classname="HelloWorld">
      <classpath>
        <pathelement location="."/>
      </classpath>
    </java>
  </target>
</project>

Step 2: Restructure directories and breakup targets

Okay, our hello world example works, but it’s a little too simple. It’s not good practice to have our ‘build.xml’, Java source, and Java class files all in the same directory. We’ll keep ‘build.xml’ in the root, but we’ll move everything else into designated subdirectories. Also, we’ll declare a package for the Java file. Lastly, we’ll separate the compile and run steps into separate Ant targets, and also add a ‘clean’ target.

Notice, you can type ‘ant -p’ to get a description of the Ant targets.

Directory Structure

build.xml
build\\\
src\\\
  com\\\
    jcky\\\
      HelloWorld.java

step-2/build.xml

<project default="run">
  <property name="src.dir" location="src"/>
  <property name="build.dir" location="build"/>

  <target name="clean" description="Clean all build targets">
    <delete dir="${build.dir}"/>
  </target>

  <target name="init">
    <mkdir dir="${build.dir}"/>
  </target>

  <target name="compile" depends="init" description="Compile program">
    <javac srcdir="${src.dir}" destdir="${build.dir}"/>
  </target>

  <target name="run" depends="compile" description="Run program">
    <java classname="com.jcky.HelloWorld">
      <classpath>
        <pathelement location="${build.dir}"/>
      </classpath>
    </java>
  </target>
</project>

Step 3: Multiple projects

Let’s assume you have multiple projects, each with their own subdirectory.

Directory Structure

helloworld\\\
  build.xml
  build\\\
  src\\\
    com\\\
      jcky\\\
        HelloWorld.java
myapplication\\\
  build.xml
  build\\\
  src\\\
    com\\\
      jcky\\\
        MyApplication.java

Step 4: Shared Ant file

The first problem we encounter is that each project has its own ‘build.xml’, which is mostly the same. Currently, only the name of the run class differs. If we have many projects, this duplication becomes costly to maintain. Let’s have all the projects share the same Ant code, and we’ll move the part that varies into a property file, ‘build.properties’, for each project.

Notice that the ‘myapplication’ project takes advantage of a mechanism that allows a project to override default property values. In that project’s ‘build.properties’ file, the value for the ‘src.dir’ property is set to ‘source’, rather than ‘src’. This is rather artificial, but illustrates the override mechanism.

Directory Structure

shared.xml
helloworld\\\
  build.properties
  build.xml
  build\\\
  src\\\
    com\\\
      jcky\\\
        HelloWorld.java
myapplication\\\
  build.properties
  build.xml
  build\\\
  source\\\
    com\\\
      jcky\\\
        MyApplication.java

step-4/helloworld/build.properties

run.class=com.jcky.HelloWorld

step-4/helloworld/build.xml

<project default="run">
  <import file="../shared.xml"/>
</project>

step-4/myapplication/build.properties

run.class=com.jcky.MyApplication
src.dir=source

step-4/myapplication/build.xml

<project default="run">
  <import file="../shared.xml"/>
</project>

step-4/shared.xml

<project>
  <property file="build.properties"/>

  <property name="src.dir" location="src"/>
  <property name="build.dir" location="build"/>

  <target name="clean" description="Clean all build targets">
    <delete dir="${build.dir}"/>
  </target>

  <target name="init">
    <mkdir dir="${build.dir}"/>
  </target>

  <target name="compile" depends="init" description="Compile program">
    <javac srcdir="${src.dir}" destdir="${build.dir}"/>
  </target>

  <target name="run" depends="compile" description="Run program">
    <java classname="${run.class}">
      <classpath>
        <pathelement location="${build.dir}"/>
      </classpath>
    </java>
  </target>
</project>

Step 5: Restructure directories

Let’s move the projects into a dedicated subdirectory and likewise for the shared Ant code. There is only a single shared Ant file at present, but that will change shortly.

While we’re doing that, let’s add a new project called ‘webapp’. This project does not have its own ‘build.xml’ file. Instead, it has two subprojects, ‘client’ and ‘server’, each having their own ‘build.xml’ file. Nested projects shows off this framework’s agnosticism towards project location. This indifference to location will be a guiding principle. Later, we will show how multiple projects can share a single source code directory.

Directory Structure

projects\\\
  helloworld\\\
    build.xml
    build\\\
    src\\\
      com\\\
        jcky\\\
          HelloWorld.java
  myapplication\\\
    build.xml
    build\\\
    source\\\
      com\\\
        jcky\\\
          MyApplication.java
  webapp\\\
    client\\\
      build.xml
      build\\\
      src\\\
        com\\\
          jcky\\\
            Client.java
    server\\\
      build.xml
      build\\\
      src\\\
        com\\\
          jcky\\\
            Server.java
shared\\\
  shared.xml

Step 6: Ant modules

This step is quite intimidating. We’re going to introduce a lot of new concepts here. Why this sudden jump in complexity? This step is the first time we start to encounter the shortcomings of Ant. Unadorned Ant is well-suited for quick and dirty builds; less so for creating modular build programs. To compensate for Ant’s shortcomings, we’re going to impose some naming standards and use a very popular Ant task library called Ant-Contrib.

The shared Ant file in the previous step only contains 4 targets. In practice, the build file will quickly explode with numerous targets. To avoid having a single monolithic file, let’s breakup the shared file into a set of Ant modules. The phrase “Ant module” is not standard terminology. I’ve coined the phrase for a mechanism I use for modularizing Ant code.

Before continuing, let’s talk about Ant variables. As a programming language, Ant is rather cumbersome. Ant variables are global and immutable. With the introduction of Ant modules, we now have 6 places for variables to reside:

  1. Project ‘build.xml’ file
  2. Project ‘build.properties’ file
  3. Module ‘module.xml’ file
  4. Module ‘module.properties’ file
  5. Shared ‘shared.xml’ file
  6. Shared ‘shared.properties’ file

We don’t have a ‘shared.properties’ file yet, but we will very soon. Since Ant does not have a variable scoping mechanism, we need to impose some standards to make variable location timely, and also avoid name clashes. Let’s first agree to never define properties in XML files. We’ll limit ourselves to properties files. This will vastly simplify variable management. Next, we will insist that variables defined in ‘shared.properties’ be prefixed with ‘shared.’; and module properties, prefixed with ‘module.MODULE_NAME.’. This naming standard should help us avoid name clashes and allow us to quickly locate variable definitions. Futhermore, we will allow each project’s ‘build.properties’ file to override values in ‘shared.properties’ and the modules’ properties files as well. Lastly, module properties may use ‘shared.*’ properties in their definitions, but may not override them. See ‘shared/modules/java/module.properties’ for an example of a module property definition referring to a shared property.

With the multiple Ant modules, Ant tasks (and later macrodefs) also have the same issue of location and clashing. We will solve these issues in the same fashion as with variables, by observing a naming standard. All targets created in an Ant module should be prefixed with the name of the module, where the module’s name is the name of the subdirectory containing the module.

When you import an Ant file (e.g. ‘build.xml’ imports ‘shared.xml’), all relative directory paths referenced in the imported file (e.g. ‘shared.xml’) will be relative to the location of the importing file (e.g. ‘build.xml’). This is usually what you want. For example, when you refer to the ‘src’ directory in ‘shared.xml’, you want to refer to the project’s subdirectory. However, in the case where you really want to refer to a path relative to the imported file (e.g. ‘shared.properties’), you need to employ a trick to do so. For each Ant file (imported or otherwise), Ant will set an Ant variable named ‘ant.file.PROJECT_NAME’ with the absolute path location of the Ant file. The ‘basedir’ Ant task can be used to extract the corresponding directory. Look at the top of ‘shared.xml’ to see this mechanism in action. It will be necessary to do this for every Ant module that has an associated file (e.g. ‘module.properties’).

Okay, now that we got that out of the way, let’s place the ‘clean’ target in its own module, and we’ll place ‘compile’, ‘run’, and ‘init’ into a ‘java’ module. Notice, we’re using Ant-Contrib, a handy set of Ant tasks. Specifically, we’re using the ‘for’ task for looping through a fileset to import all our Ant modules.

As an aside, notice that ‘ant-contrib.jar’ file has the version number stripped from the filename. All committed jars should have their version number removed. This allows upgrading of jars without having to change any build files. All such jars should have a corresponding ‘versions.txt’ in the same directory. This file contains the version number for the files in that directory. For an example, see ‘shared/lib/versions.txt’. This is not required by our framework, but I have found this to be a very useful convention.

With these changes, you now use ‘ant clean java.run’, instead of ‘ant clean run’. The ‘java.run’ target is abiding our nomenclature standard; it’s located in the ‘java’ module.

Directory Structure

projects\\\
  helloworld\\\
    build.xml
    build\\\
    src\\\
      com\\\
        jcky\\\
          HelloWorld.java
  myapplication\\\
    build.xml
    build\\\
    source\\\
      com\\\
        jcky\\\
          MyApplication.java
  webapp\\\
    client\\\
      build.xml
      build\\\
      src\\\
        com\\\
          jcky\\\
            Client.java
    server\\\
      build.xml
      build\\\
      src\\\
        com\\\
          jcky\\\
            Server.java
shared\\\
  shared.properties
  shared.xml
  lib\\\
    ant-contrib.jar
    versions.txt
  modules\\\
    clean\\\
      module.xml
    java\\\
      module.properties
      module.xml

step-6/shared/shared.properties

shared.build.dir=build

step-6/shared/shared.xml

<project name="shared">
  <property file="build.properties"/>

  <dirname property="shared.basedir" file="${ant.file.shared}" />
  <property file="${shared.basedir}/shared.properties"/>

  <taskdef resource="net/sf/antcontrib/antlib.xml">
    <classpath>
      <pathelement location="${shared.basedir}/lib/ant-contrib.jar"/>
    </classpath>
  </taskdef>

  <for param="module">
    <path>
      <fileset dir="${shared.basedir}/modules">
        <include name="*/module.xml"/>
      </fileset>
    </path>
    <sequential>
      <import file="@{module}"/>
    </sequential>
  </for>

</project>

step-6/shared/modules/clean/module.xml

<project name="clean">
  <target name="clean" description="Clean all build targets">
    <delete dir="${shared.build.dir}"/>
  </target>
</project>

step-6/shared/modules/java/module.properties

module.java.class.dir=${shared.build.dir}/class
module.java.run.class=Define property 'module.java.run.class' in the project's 'build.properties' file to use 'java.run' target.
module.java.src.dir=src

step-6/shared/modules/java/module.xml

<project name="java">

  <dirname property="java.basedir" file="${ant.file.java}" />
  <property file="${java.basedir}/module.properties"/>

  <target name="java.init">
    <mkdir dir="${module.java.class.dir}"/>
  </target>

  <target name="java.compile" depends="java.init" description="Compile program">
    <javac srcdir="${module.java.src.dir}" destdir="${module.java.class.dir}"/>
  </target>

  <target name="java.run" depends="java.compile" description="Run program">
    <java classname="${module.java.run.class}">
      <classpath>
        <pathelement location="${module.java.class.dir}"/>
      </classpath>
    </java>
  </target>
</project>

step-6/projects/helloworld/build.properties

module.java.run.class=com.jcky.HelloWorld

Step 7: Cross-project dependencies

I leave this step as an exercise for the reader. You can manage cross-project dependencies without custom Ant tasks by explicitly specifying dependencies with FileSets. This is extremely cumbersome to maintain for any build with a moderate number of projects.

Step 8: Cross-project dependencies using custom Ant tasks

This step supports easy cross-project dependency management with Weaver.

The ‘WeaverProjects’ task is used to register a set of projects, the artifacts that are published by each project, and the dependencies for each project. The ‘WeaverFileSet’ task is used to generate an Ant FileSet for a specified project and a specified artifact type. The FileSet generated by ‘WeaverFileSet’ will recursively include all artifacts of the specified type published by dependency projects.

A new ‘java.jar’ task has been added to the ‘java’ Ant module that will build a jar file. A new project ‘webapp/common’ has been added. This contains code used by projects ‘webapp/server’ and ‘webapp/client’. Each project registered with ‘WeaverProjects’ should declare a ‘build.xml’ file. This will be used by the root ‘build.xml’ to build all projects. Each project’s ‘build.xml’ will declare a ‘build’ target. By convention, all artifacts are located in a single directory, ‘repository’.

From any project directory, as well as the root directory for this step (i.e. ‘src/step-8’), you can type ‘ant graph’ to generate an image of the project graph. GraphViz must be installed for this to work. You will also need to specify the location of the GraphViz ‘dot.exe’ executable with property ‘module.graph.graphviz.exe’ in file ‘src/step-8/override.properties’. This property has a default value in ‘src/step-8/shared/modules/graph/module.properties’, but you shouldn’t modify that value. It is expected that ‘module.properties’ files reside in the source code respository and that values specific to a machine will be found in ‘src/step-8/override.properties’, which should not be committable (i.e. it should be listed in ‘.cvsignore’ or equivalent).

On Windows, you can run ‘ant graph.view’ in any project to not only generate the project graph, but view it as well.

To build all projects, execute ‘ant’ at the command-line in directory ‘src/step-8’. After building all projects, you can run the applications. To do so, go to the client or server project directory in the command-line, and execute ‘ant’. If you modify the source for one of those projects, you can rebuild and run by executing ‘ant clean build java.run’.

There are numerous embellishments in this step. Notice, that the Java source code has been moved into packages that correspond to the containing project. That now makes which project a class belongs to obvious. The ‘common’ project now uses Log4j. This dependency is made explicit in the ‘WeaverProjects’ task. The other two projects, ‘client’ and ‘server’ use Log4j, via ‘common’, but this relationship need not be explicit. Weaver will include the Log4j jars automatically. Note also, Log4j requires a ‘log4j.properties’ file to be available on the classpath. If a project declares a ‘resources’ subdirectory, the ‘java.jar’ task will package all files in that directory into the jar. This directory is optional. The ‘common’ project uses the ‘resources’ directory to include a ‘log4j.properties’ file.

A ‘java.dist’ target has been added to the ‘java’ module. This target can be run from either the ‘client’ or ‘server’ projects to create a binary distribution. It will create a zip file which will include all required jars. It will also include a build.xml file that can be used to run the application.

The last addition in this step is project ‘webapp2’. This project contains identical source code as ‘webapp’, but all the different projects (renamed to ‘server2’, ‘common2’, and ‘client2’ to avoid jar name collisions with the originals) share a single source code directory, ‘src/step-8/projects/webapp2/src’. The only change required to get the ‘webapp2’ projects to compile is that these projects define a ‘java.compile’ target in their project’s ‘build.xml’ to override the one the ‘java’ module.

Directory Structure

build.xml
override.properties
projects.xml
lib\\\
  log4j.jar
  versions.txt
projects\\\
  webapp\\\
    client\\\
      build.xml
      build.properties
      build\\\
      src\\\
        com\\\
          jcky\\\
            client\\\
              Client.java
    common\\\
      build.xml
      build.properties
      build\\\
      resources\\\
        log4j.properties
      src\\\
        com\\\
          jcky\\\
            common\\\
              Common.java
    server\\\
      build.xml
      build.properties
      build\\\
      src\\\
        com\\\
          jcky\\\
            server\\\
              Server.java
  webapp2\\\
    client2\\\
      build.xml
      build.properties
      build\\\
    common2\\\
      build.xml
      build.properties
      build\\\
      resources\\\
        log4j.properties
    server2\\\
      build.xml
      build.properties
      build\\\
    src\\\
      com\\\
        jcky\\\
          client\\\
            Client.java
          common\\\
            Common.java
          server\\\
            Server.java
shared\\\
  shared.properties
  shared.xml
  lib\\\
    ant-contrib.jar
    versions.txt
    weaver.jar
  modules\\\
    clean\\\
      module.xml
    graph\\\
      module.properties
      module.xml
    java\\\
      module.properties
      module.xml
      resources\\\
        build.xml
weaver\\\

step-8/projects.xml

<project name="projects">
  <dirname property="projects.basedir" file="${ant.file.projects}" />

  <weaverProjects dir="${projects.basedir}">
    <project name="client" depends="common">
      <artifact type="build.file" file="${shared.projects.dir}/webapp/client/build.xml"/>
      <artifact type="jar" file="${shared.repo.dir}/client.jar"/>
    </project>
    <project name="common" depends="log4j">
      <artifact type="build.file" file="${shared.projects.dir}/webapp/common/build.xml"/>
      <artifact type="jar" file="${shared.repo.dir}/common.jar"/>
    </project>
    <project name="log4j">
      <artifact type="jar" file="${shared.lib.dir}/log4j.jar"/>
    </project>
    <project name="server" depends="common">
      <artifact type="build.file" file="${shared.projects.dir}/webapp/server/build.xml"/>
      <artifact type="jar" file="${shared.repo.dir}/server.jar"/>
    </project>

    <project name="client2" depends="common2">
      <artifact type="build.file" file="${shared.projects.dir}/webapp2/client2/build.xml"/>
      <artifact type="jar" file="${shared.repo.dir}/client2.jar"/>
    </project>
    <project name="common2" depends="log4j">
      <artifact type="build.file" file="${shared.projects.dir}/webapp2/common2/build.xml"/>
      <artifact type="jar" file="${shared.repo.dir}/common2.jar"/>
    </project>
    <project name="server2" depends="common2">
      <artifact type="build.file" file="${shared.projects.dir}/webapp2/server2/build.xml"/>
      <artifact type="jar" file="${shared.repo.dir}/server2.jar"/>
    </project>

  </weaverProjects>
</project>

step-8/override.properties

module.graph.graphviz.exe=c:/root/bin/graphviz/Graphviz/bin/dot

step-8/build.xml

<project name="root" default="all">
  <import file="shared/shared.xml"/>

  <weaverFileList property="root.all.build.files" type="build.file"/>

  <target name="call.project.target">
    <property name="root.build.file" location="${projects.basedir}/${build.file}"/>
    <dirname property="root.build.dirname" file="${root.build.file}"/>
    <ant antfile="${root.build.file}" dir="${root.build.dirname}"
      target="${target}" inheritAll="false"/>
  </target>

  <target name="build" description="Build all projects">
    <for list="${root.all.build.files}" param="build.file">
      <sequential>
        <antcall target="call.project.target">
          <param name="build.file" value="@{build.file}"/>
          <param name="target" value="build"/>
        </antcall>
      </sequential>
    </for>
  </target>

  <target name="clean" depends="clean.clean" description="Delete all build products">
    <delete dir="${shared.root.dir}/${shared.repo.dir}"/>
    <for list="${root.all.build.files}" param="build.file">
      <sequential>
        <antcall target="call.project.target">
          <param name="build.file" value="@{build.file}"/>
          <param name="target" value="clean"/>
        </antcall>
      </sequential>
    </for>
  </target>

  <target name="all" depends="clean,build" description="Clean build"/>

</project>

step-8/projects/webapp/client/build.xml

<project default="java.run">
  <import file="../../../shared/shared.xml"/>
  <target name="build" depends="java.jar" description="Build project"/>
  <target name="clean" depends="clean.clean,java.clean" description="Delete project's build products"/>
</project>

step-8/projects/webapp2/client2/build.xml

<project default="java.run">
  <import file="../../../shared/shared.xml"/>
  <target name="build" depends="java.jar" description="Build project"/>
  <target name="clean" depends="clean.clean,java.clean" description="Delete project's build products"/>

  <target name="java.compile" depends="java.init" description="Compile program">
    <weaverFileSet fileset="java.compile.jars" project="${java.project.name}" type="jar"/>
    <javac includes="com/jcky/client/**/*" srcdir="../src" destdir="${module.java.class.dir}">
      <classpath>
        <fileset refid="java.compile.jars"/>
      </classpath>
    </javac>
  </target>

</project>

step-8/shared/shared.properties

shared.build.dir=build
shared.lib.dir=lib
shared.projects.dir=projects
shared.repo.dir=repository

step-8/shared/shared.xml

<project name="shared">

  <dirname property="shared.basedir" file="${ant.file.shared}" />
  <property name="shared.root.dir" location="${shared.basedir}/.."/>

  <!-- Load Ant-Contrib Ant task library -->
  <taskdef resource="net/sf/antcontrib/antlib.xml">
    <classpath>
      <pathelement location="${shared.basedir}/lib/ant-contrib.jar"/>
    </classpath>
  </taskdef>

  <!-- Load Weaver Ant task library -->
  <taskdef resource="com/jcky/weaver/weaver.properties">
    <classpath>
      <pathelement location="${shared.basedir}/lib/weaver.jar"/>
    </classpath>
  </taskdef>

  <!-- 1. Load local overrides. File 'override.properties' should not be
          committable to repository. -->
  <property file="${shared.root.dir}/override.properties"/>
  <!-- 2. Load project properties. Projects can override shared and module
          properties. -->
  <property file="build.properties"/>
  <!-- 3. Load shared properties. -->
  <property file="${shared.basedir}/shared.properties"/>

  <import file="${shared.root.dir}/projects.xml" />

  <!-- 4. Load modules. Each module is responsible for loading its own properties file.
          Module properties may use shared properties, but they cannot override
          any properties. -->
  <for param="module">
    <path>
      <fileset dir="${shared.basedir}/modules">
        <include name="*/module.xml"/>
      </fileset>
    </path>
    <sequential>
      <import file="@{module}"/>
    </sequential>
  </for>

</project>

step-8/shared/modules/graph/module.properties

module.graph.build.dir=${shared.build.dir}/graph
module.graph.dot.file=${module.graph.build.dir}/projects.dot
module.graph.jpeg.file=${module.graph.build.dir}/projects.jpeg
module.graph.graphviz.exe=C:/Program Files/ATT/Graphviz/bin/dot

step-8/shared/modules/graph/module.xml

<project name="graph">

  <dirname property="graph.basedir" file="${ant.file.graph}" />
  <property file="${graph.basedir}/module.properties"/>

  <target name="graph" description="Create graph of projects">
    <mkdir dir="${module.graph.build.dir}"/>
    <weaverGraph file="${module.graph.dot.file}"/>
    <exec executable="${module.graph.graphviz.exe}">
      <arg line="-Tjpeg ${module.graph.dot.file} -o ${module.graph.jpeg.file}"/>
    </exec>
    <echo message="Created graph: ${module.graph.jpeg.file}"/>
  </target>

  <target name="graph.view" depends="graph" description="View graph of projects">
    <property name="graph.view.file" location="${module.graph.jpeg.file}"/>
    <exec executable="mspaint">
      <arg line="${graph.view.file}"/>
    </exec>
  </target>

</project>

step-8/shared/modules/java/module.properties

module.java.class.dir=${shared.build.dir}/class
module.java.dist.dir=${shared.build.dir}/dist
module.java.run.class=Define property 'module.java.run.class' in the project's 'build.properties' file to use 'java.run' target.
module.java.src.dir=src
module.java.resource.dir=resources

step-8/shared/modules/java/module.xml

<project name="java">

  <dirname property="java.basedir" file="${ant.file.java}" />
  <property file="${java.basedir}/module.properties"/>

  <property name="java.resource.dir" location="${java.basedir}/resources"/>

  <basename property="java.project.name" file="${basedir}" />
  <property name="java.jar.file" location="${shared.root.dir}/${shared.repo.dir}/${java.project.name}.jar" />

  <target name="java.clean">
    <delete file="${java.jar.file}"/>
  </target>

  <target name="java.init">
    <mkdir dir="${module.java.class.dir}"/>
    <mkdir dir="${module.java.dist.dir}"/>
    <mkdir dir="${shared.root.dir}/${shared.repo.dir}"/>
  </target>

  <target name="java.compile" depends="java.init" description="Compile program">
    <weaverFileSet fileset="java.compile.jars" project="${java.project.name}" type="jar"/>
    <javac srcdir="${module.java.src.dir}" destdir="${module.java.class.dir}">
      <classpath>
        <fileset refid="java.compile.jars"/>
      </classpath>
    </javac>
  </target>

  <target name="java.jar" depends="java.compile" description="Build jar">
    <jar destfile="${java.jar.file}">
      <fileset dir="${module.java.class.dir}"/>
    </jar>
    <if>
      <available file="${module.java.resource.dir}" type="dir"/>
      <then>
        <jar destfile="${java.jar.file}" update="true">
          <fileset dir="${module.java.resource.dir}"/>
        </jar>
      </then>
    </if>
  </target>

  <target name="java.dist" depends="java.jar" description="Build binary project distribution">
    <weaverFileSet fileset="java.dist.jars" project="${java.project.name}" type="jar" inclusive="true"/>
    <echo file="${module.java.dist.dir}/build.properties"
      message="run.class=${module.java.run.class}"/>
    <zip destfile="${module.java.dist.dir}/${java.project.name}.zip">
      <fileset refid="java.dist.jars"/>
      <fileset dir="${module.java.dist.dir}" includes="build.properties"/>
      <fileset dir="${java.resource.dir}" includes="build.xml"/>
    </zip>
  </target>

  <target name="java.run" description="Run program">
    <weaverFileSet fileset="java.run.jars" project="${java.project.name}" type="jar" inclusive="true"/>
    <java classname="${module.java.run.class}">
      <classpath>
        <fileset refid="java.run.jars"/>
      </classpath>
    </java>
  </target>
</project>

step-8/shared/modules/java/resources/build.xml

<project default="run">
  <property file="build.properties"/>
  <target name="run" description="Run application">
    <java classname="${run.class}">
      <classpath>
        <fileset dir="lib"/>
        <fileset dir="repository"/>
      </classpath>
    </java>
  </target>
</project>

Reference

It's only fair to share...
Share on FacebookGoogle+Tweet about this on TwitterShare on LinkedIn

Leave a Reply