[ Team LiB ] Previous Section Next Section

Recipe 4.4 Compiling a Servlet with an Ant Build File

Problem

You want to set up a simple build file that you can use to compile individual servlets, without hardcoding servlet names.

Solution

Design a build file so that the name of the Java class to compile can be set from an external properties file or from the command line.

Discussion

If you are not using an IDE to develop and compile your servlets, an Ant build file can automate the compiling of your source files. In order to make this build file reusable, you should design it to get the name of the file from an external properties file or from the command line.

Ant's advantages come to the fore when it is used to automate all of the aspects of building, archiving, and deploying a web application. However, you can also use Ant as a kind of batch processor. In this recipe, I use Ant to dynamically choose a Java file to compile.

The build.xml file in Example 4-5 imports a couple of properties from a build.properties file, including the name of the servlet to be compiled. One way to choose a different Java file to compile is to change the value of the compiled.servlet property in this file, without touching the build file:

tomcat.dir=/users/bruceper/java/jakarta-tomcat-4.1.12
compiled.servlet=MyServlet

To run Example 4-5, change to the directory where the build.xml file is located and type ant without any options.

If you are running an Ant build file with a different name, then launch it with this command line:

ant -buildfile ant_compiler.xml

First, this file imports the tomcat.dir and compiled.servlet properties from a build.properties file. This file is located in the same directory as the build file. The tomcat.dir property is used to create a classpath composed of the JAR files in two directories that are a part of Tomcat's directory tree (see Recipe 4.2).

Example 4-5. Compiling a servlet with an Ant build file
<project name="servlet compiler" default="compile" basedir=".">

    <property file="build.properties" />
  
    <path id="servlet-classpath">

        <fileset dir="${tomcat.dir}/common/lib">
            <include name="*.jar" />
        </fileset>

        <fileset dir="${tomcat.dir}/common/endorsed">
            <include name="*.jar" />
        </fileset>

    </path>
  
    <target name="init"
      description="Initializes some properties.">
        <echo message="Initializing properties."/>
        <property name="build" value="./build" />
        <property name="src" value="./src" />

    </target>
  
    <target name="prepare" depends="init">
        <echo message="Cleaning up the build directory."/>
        <delete dir="${build}"/>
        <mkdir dir="${build}"/>
    </target>
 
    <target name="compile" depends="prepare" 
      description="Compile the servlet">
        <echo message="Compiling the Java file "/>
        <echo message="${compiled.servlet}.java..."/>
        <javac srcdir="${src}" destdir="${build}">
            <include name="${compiled.servlet}.java" />
            <classpath refid="servlet-classpath "/>
        </javac>
    </target>
</project>

The init target creates two properties representing the source (src) and destination (build) directories of the target servlet. The Java file waiting to be compiled is located in an src directory. A typical build file also has an init target that initializes several more properties. Since the compile target has a depends attribute that specifies the prepare target, and the prepare target depends on init, then the build sequence looks like init prepare compile.

The prepare target just cleans up the build directory to ensure that the build directory contains the latest compiled classes.

The compile target uses the javac task to actually compile the Java file. javac has attributes that specify the source and destination directories of the Java file(s) that it will attempt to compile. Example 4-5 uses the src and build properties to provide values for these attributes. Two nested elements of the javac task compile the specified servlet file and provide the classpath that the javac task uses (see Recipe 4.2).

Here is the console output after running this build file (with some editing for readability):

init:
     [echo] Initializing properties.

prepare:
     [echo] Cleaning up the build directory.
   [delete] Deleting directory 
          /Users/bruceper/books/cookbook/sec1/sec1_3/build
    [mkdir] Created dir: 
          /Users/bruceper/books/cookbook/sec1/sec1_3/build

compile:
     [echo] Compiling the Java file MyServlet.java...
    [javac] Compiling 1 source file to 
           /Users/bruceper/books/cookbook/sec1/sec1_3/build

BUILD SUCCESSFUL
Total time: 6 seconds
Using the command line to declare the target servlet

What if you want to change the servlet that you are compiling, but are not inclined to type the new Java filename into the build.properties file? Running the build.xml Ant file from the command line in the following manner will override the imported compiled.servlet property:

ant -Dcompiled.servlet=AnotherServlet

AnotherServlet.java is the filename in this example of the Java file that awaits compilation in the src directory. This fragment of output shows that any properties passed in from the command line override properties of the same name created within or imported into the build file:

compile:
     [echo] Compiling the Java file AnotherServlet.java...
    [javac] Compiling 1 source file to
           /Users/bruceper/books/cookbook/sec1/sec1_3/build

The javac task compiles only only the java files in the src directory that do not have a corresponding class file, or in cases where the class file is older than its corresponding .java file. As always, check the Ant manual to find out about all the different variations and attributes of javac: http://ant.apache.org/manual/CoreTasks/javac.html.

If you want to copy the compiled servlet class to a web application directory, you could add a deploy-servlet target that uses the copy Ant task:

<target name="deploy-servlet" depends="compile">
  <echo message=
    "Copying the servlet to Tomcat web app"/>
  <copy todir="${tomcat.webapps}/WEB-INF/classes">
    <fileset dir="${build}" />
  </copy>
</target>

The copy task takes its nested fileset, which represents the contents of the directory named by the build property value, and copies these class files to the WEB-INF/classes directory of Tomcat's default web application.

See Also

Recipe 4.1 on downloading and setting up Ant; Recipe 4.2 on writing Ant targets; Recipe 4.3 on creating a classpath for an Ant file; Recipe 4.5 on creating a WAR file with Ant; Recipe 4.6 on using Ant to create JAR files; Recipe 4.7 and Recipe 4.8 on starting and stopping Tomcat with Ant; Recipe 2.1 and Recipe 2.6 on deploying web applications using Ant; the Ant manual section on the property task: http://ant.apache.org/manual/CoreTasks/property.html; the Ant manual segment on targets: http://ant.apache.org/manual/using.html#targets; the Apache Ant manual index page: http://ant.apache.org/manual/index.html; the Apache Ant Project, http://ant.apache.org.

    [ Team LiB ] Previous Section Next Section