Ant and Tomcat

The purpose of today's lab is to learn about two Java technologies currently in vogue called Ant and Tomcat. We are teaching them together because in order to use Tomcat, it is very helpful to first know Ant.

Ant

Build files

In this class, you have mainly used graphical IDEs such as DrJava and Eclipse to compile and run your programs. However, when working on larger software projects involving multiple people, one typically wants to structure the project in such a way that it is not tied to a particular IDE. One benefit is that each developer can work in whatever environment she prefers --- DrJava, Eclipse, emacs, vi, etc. Another benefit is that automated programs can be invoked from the command line to perform useful tasks, for example, on a nightly schedule to make sure the source files all compile. Build files are used for this purpose. A build file specifies how a set of source files should be compiled (or tested, deployed, and so on). A tool is launched from the command-line to interpret the build file and carry out the instructions.

make

An older technology for build files that you will almost certainly encounter sooner or later is the Unix command-line tool make. It is still very commonly used, especially for C and C++ projects, although it can be used just as easily for other languages. The build files used by make are called makefiles, and this term is more or less synonomous with build files. Just to give you an idea of what a makefile looks like, here is an example corresponding to a C program with a single source file main.c:

all: main

main.o: main.c
        gcc -g -Wall -c main.c

main: main.o
        gcc -g main.o -o main

clean:
        /bin/rm -f main main.o

Despite its ubiquity, make is widely viewed as a less-than-ideal tool, suffering from an arcane and finicky syntax, a lack of built-in high level commands which makes writing portable makefiles difficult (that is, makefiles that run on many platforms instead of just one), and other problems. For these reasons, many other build file systems have been proposed over the years, although few have caught on.

ant

ant is a build file system for Java programs. It has only been around for a few years, but it has already become widely used. An ant build file is an XML file following a certain syntax. (XML stands for "extensible markup language" and is a plain text file format that looks a lot like HTML.)

The easiest way to learn how ant build files work is by example. We'll try writing an ant build file for an old assignment, Homework 7. An ant build file is usually called build.xml. We'll put it in the same directory as the source files (although other configurations are possible):

% cd ~/hw09
% emacs build.xml &
Now, here's what we'll put in our first build.xml file:
<project name="hw09" default="build" basedir=".">
    <target name="build">
        <javac srcdir="."/>
    </target>
</project>
We're ready to compile the project using the build file. Since we used the default file name build.xml, we just have to type ant to build the project:
% ant
Buildfile: build.xml

build:
    [javac] Compiling 11 source files

BUILD SUCCESSFUL
Total time: 2 seconds
So far, this isn't very interesting; we could have done all this by typing javac *. But there is much more you can do. For one thing, there are different targets which you can define, to perform different operations. These operations are usually lists of tasks such as javac above. Suppose we wanted to add a target to clean up after a compilation by removing all the .class files. We could do this by modifying our file to read:
<project name="hw07" default="build" basedir=".">
    <target name="build">
        <javac srcdir="."/>
    </target>
    <target name="clean">
        <delete verbose="true">
            <fileset dir="." includes="**/*.class"/>
        </delete>
    </target>
</project>
Here we have defined a new target called clean. When executed, this target deletes class files in the current directory via the delete task. Now, to remove the .class files, we do:
% ant clean
Buildfile: build.xml

clean:
   [delete] Deleting 14 files from /Users/tjgreen/hw07
   [delete] Deleting /Users/tjgreen/hw07/AllAcross.class
   [delete] Deleting /Users/tjgreen/hw07/ArrayBT$Iter.class
   [delete] Deleting /Users/tjgreen/hw07/ArrayBT.class
   [delete] Deleting /Users/tjgreen/hw07/ArrayNode$ArrayOrder.class
   [delete] Deleting /Users/tjgreen/hw07/ArrayNode.class
   [delete] Deleting /Users/tjgreen/hw07/BinaryHeap.class
   [delete] Deleting /Users/tjgreen/hw07/BinaryTree.class
   [delete] Deleting /Users/tjgreen/hw07/BTIterator.class
   [delete] Deleting /Users/tjgreen/hw07/LinkedBT$Iter.class
   [delete] Deleting /Users/tjgreen/hw07/LinkedBT.class
   [delete] Deleting /Users/tjgreen/hw07/LinkedNode.class
   [delete] Deleting /Users/tjgreen/hw07/Node.class
   [delete] Deleting /Users/tjgreen/hw07/PriorityQueue.class
   [delete] Deleting /Users/tjgreen/hw07/Tester.class

BUILD SUCCESSFUL
Total time: 2 seconds

Notice how in this case we explicitly specified the name of the target we wanted to execute, namely clean. When ant is invoked with no arguments, it executes the default target build. So we could have built the project in the first place by typing ant build instead of just ant. Notice also the verbose output. This is because we have specified verbose="true" in the delete task.

Filesets

In the example above, in order to specify which files were to be deleted, we used a special tag called fileset. By saying dir=".", we specified that the fileset should match files in the current directory. By saying includes="**/*.class", we specified that it should match files ending with .class. Filesets are quite powerful, allowing you to specify recursive paths to follow, both inclusion and exclusion patterns (e.g. include all files ending with .class except for files containing the string test), and more. See the documentation for details.

Properties

It is very convenient to be able to introduce something like variables into your build files. For example, you might want to use a variable for the build directory path, so that you can change the build directory easily later without having to touch many places in the build file. The mechanism ant uses for this is called properties. The special property tag allows one to define a property which can then be used in the rest of the build file. They are like Java final variables in the sense that their values are immutable and cannot be changed once defined. Let's see how our example build file would look if we used properties for the source and output directories:

<project name="hw07" default="build" basedir=".">
    <property name="srcdir" value="."/>
    <property name="destdir" value="out"/>
    <target name="build" depends="clean">
        <mkdir dir="${destdir}"/>
        <javac srcdir="${srcdir}" destdir="${destdir}"/>
    </target>
    <target name="clean">
        <delete verbose="true" quiet="true">
            <fileset dir="$destdir}" includes="**/*.class"/>
        </delete>
    </target>
</project>

Note how we have also used the depends attribute in our build target definition to force all builds to be clean. (This is just to demonstrate the usage of depends.)

Ant tasks

Here we summarize a few of the more commonly-used ant tasks. There are many more; a complete list is available in the documentation.

Task Description Example
ant Invokes ant itself on the specified build file.
<ant antfile="subbuild.xml"/>
chmod Change the permissions of a file or all files inside specified directories.
<chmod file="${dist}/start.sh" perm="700"/>
copy Copies a file or set of files to a new file or directory.
<copy file="myfile.txt" todir="../some/other/dir"/>
delete Deletes a single file, a specified directory and all its files and subdirectories, or a set of files specified by one or more filesets.
<delete file="/lib/ant.jar"/>
javac Compiles the specified Java source files.
<javac sourcepath="" srcdir="${src}"
       destdir="${build}">
    <include name="**/*.java"/>
    <exclude name="**/Example.java"/>
</javac>
javadoc Generates code documentation using the javadoc tool.
<javadoc sourcepath="." destdir="doc">
mkdir Creates a directory, creating parent directories as needed.
<mkdir dir="${dist}/lib"/>
move Moves a file or directory to a new file or directory, or sets of files to a new directory.
<move file="file.orig" todir="dir/to/move/to"/>
property Sets a property or set of properties (from file or resource) in the project.
<property name="foo.dist" value="dist"/>

Custom tasks

In addition to the built-in ant tasks such as those above, there is a very handy mechanism for supplying custom ant tasks to be used for special purposes, via the taskdef tag.

taskdef Adds a task definition to the current project, such that this new task can be used in the current project.
<taskdef name="myjavadoc" classname="com.mydomain.JavadocTask"/>

In the next section, we will see this mechanism used to deploy tomcat applications.

Servlets and Tomcat

What is a servlet?

Servlets are java programs that extend the Java interface HttpServlet. These are programs that can be run through the web. As such, they also have access to information that can come to them from the web. For those of you who are familiar with applets, servlets are like applets except they run on a server. A servlet outputs HTML or XML.

Why use servlets?

Servlets are extremely powerful because they are platform independent and allow you to use all the features of the Java API in the context of web programming.

When to use servlets

Servlets are best used when web pages need to be created dynamically. Dynamic web pages are use when:
  1. A web page can change based on user defined data e.g. Google's search results.
  2. The implicit data changes often e.g. A stock ticker.
  3. The web page uses information from a central database e.g. Your account on eBay or Amazon.

Servlets vs. JSP

Java Server Pages (JSP) lets you combine static and dynamic HTML, just like servlets. However, the difference between the two is the ease of programming. JSP embeds calls to Java programs within HTML, whereas Servlets print out HTML. JSP is best used for dynamic pages which change very little, while servlets are best used for rapidly changing pages.

What is Tomcat

Apache Tomcat is a web server, on which you can host and run servlets. Unlike applets which run on the user's machine, servlets run on a server (hence the name). Tomcat allows you to upload and manage servlets. When a user opens Internet Explorer and types in a URL, a web server generates the requested page. Tomcat is used for JSP and servlets. Other web servers include Microsoft's Webservices and BEA's Weblogic.

A Simple Servlet

Here is an example of a "hello, world" servlet. Note that it implements doGet. This means that it will be invoked in response to HTTP get requests. These correspond to the type of request generated when you type in a URL in your browser's address bar or click on a link on a web page. There is another kind of HTTP request called post. This corresponds to the type of request generated when you fill out a web page form and click the "submit" button, for example. To handle this kind of request, a servlet can override the method doPost.

import java.io.*;
import java.text.*;
import java.util.*;
import javax.swing.*;
import javax.servlet.*;
import javax.servlet.http.*;

/**
 * The simplest possible servlet.
 *
 * @author James Duncan Davidson
 */

public class HelloWorldExample extends HttpServlet {


    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)
        throws IOException, ServletException
    {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();

        out.println("<html>");
        out.println("<head>");

        String title = "Hello World!";

        out.println("<title>" + title + "</title>");
        out.println("</head>");
        out.println("<body bgcolor=\"white\">");
        out.println("<body>");

        out.println("<a href=\"/examples/servlets/helloworld.html\">");
        out.println("<img src=\"/examples/images/code.gif\" height=24 " +
                    "width=24 align=right border=0 alt=\"view code\"></a>");
        out.println("<a href=\"/examples/servlets/index.html\">");
        out.println("<img src=\"/examples/images/return.gif\" height=24 " +
                    "width=24 align=right border=0 alt=\"return\"></a>");
        out.println("<h1>" + title + "</h1>");
        out.println("</body>");
        out.println("</html>");
    }
}

Tomcat and Ant

To test or run a tomcat application, you have to deploy the files to the web server. Deployment basically just means copying the files (or a pointer to the files). It is a pain in the neck to have to do this by hand, so tomcat ships with a custom ant task to automate the process. Here is an excerpt from a real-world ant build file for a tomcat project (this comes from last year's final project in cse330):

<project name="pmail-skeleton" default="compile" basedir=".">
  ...
  <taskdef name="deploy"   classname="org.apache.catalina.ant.DeployTask"
           classpath ="${catalina.home}/server/lib/catalina-ant.jar"/>
  ...
  <target name="install" depends="compile"
   description="Install application to servlet container">

  	<chmod file="${build.home}" perm="755" type="both"/>
  	<chmod dir="${build.home}" perm="755" type="both" includes="**/*"/>

  	<deploy url="${manager.url}"
       username="${manager.username}"
       password="${manager.password}"
           path="${app.path}"
       localWar="file://${build.home}"/>
  </target>
  ...
</project>

Resources