ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


Creating a Web Application with Ant and Tomcat 4

by Paul Wood
01/08/2003

Which Technologies to Use?

I have decided to use Tomcat 4 Servlet/JSP Container technologies to implement a Web application. This still leaves many options, and choosing between the various available technologies is not easy. For this article, I have chosen to keep it simple and use Java Server Pages (JSPs) in combination with Java classes.

You should really avoid using JSPs to implement complex logic; such applications may be fun to write, but can be frustrating to debug and almost impossible to understand and maintain. A really good solution is to use JSPs to handle the Web page presentation (because that is what JSPs are good for), and Java to implement complex logic, such as database access. This way, the software will be easier to write and debug, and later the code will be easier to understand and maintain.

Related Reading

Ant: The Definitive Guide
By Jesse E. Tilly, Eric M. Burke

The Web application can be served on a dedicated Web server or on a personal computer running a Windows, Linux, or Mac OS X operating system. It requires a Java runtime environment (JDK 1.2 or newer), a recent version of the Tomcat Servlet/JSP Container (version 4 or better), and the Ant development tool (version 1.4 or later). Ant is used to create the Web application's Web Archive (WAR) file, and to install and deploy the WAR file into Tomcat, configuring the javax.sql.DataSource relational database interface in the process. All of these packages are available on the Internet at no cost.

The Web application also requires a database. Almost any relational database will do, if it accepts SQL and has a JDBC driver. MySQL has a good reputation and fits the bill exactly. You can get the latest MySQL and its Connector/J JDBC Driver from MySQL.com.

To allow Ant to work with Tomcat's manager software, copy catalina-ant.jar from Tomcat's server/lib directory into Ant's lib directory. To give database access to Tomcat and its installed Web applications, copy your database's JDBC Driver file into Tomcat's common/lib directory. Finally, you must set up the Tomcat admin and manager roles, and the usernames and passwords. Edit the tomcat-users.xml file in Tomcat's conf directory, so that it looks like this:

<?xml version='1.0'?>
    <tomcat-users>
        <role rolename="admin"/>
        <role rolename="manager"/>
        <user username="tomcatusername" password="tomcatpassword"
                 roles="admin,manager"/>
    </tomcat-users>

For your information, I used Tomcat 4.1.12, Ant 1.5.1, MySQL 3.23.52, and Connector/J 3.0.1-beta running on an Apple Cube with Mac OS X 10.2.1 (which includes Java Development Kit 1.3.1) to develop this Web application. When Mac OS X 10.2.2 was released, I upgraded without problem. When Tomcat 4.1.17 was released, again I upgraded without problem.

The Web Application

The Web application used to demonstrate the technologies used in this article is a simple address book application, called AddressBook. It is not the purpose of this article to create the ultimate address book. It is just an example.

AddressBook's Java Classes

AddressBook has three Java classes, detailed below. Figure 1 shows how the classes are used within the Tomcat Servlet/JSP Container.

Figure 1

AddressBook.ContextListener

AddressBook.ContextListener is a servlet context listener that will be called when AddressBook starts up and shuts down. This is configured in AddressBook's deployment descriptor file, web.xml. When AddressBook is starting up, an instance of the AddressesDB object is created and stored as a context attribute; when it is shutting down, the AddressesDB object is retrieved from the context attribute and the database is closed. In between, the JSPs retrieve the AddressesDB object from the context attribute whenever they need to access the database.

See ContextListener.java for the complete, annotated source code.

AddressBook.AddressesDB

AddressBook.AddressesDB is a class that represents the addresses database. Its constructor establishes a connection to the database, and the session can be shared across several Web sessions. The class provides several database-access methods:

See AddressesDB.java for the complete, annotated source code.

AddressBook.Address

AddressBook.Address is a class that represents an address. Classes that collect data together are still a good idea when programming JSPs, so this class is a good idea for the AddressBook application.

The AddressBook.Address constructor stores the address fields in the object. This class also includes the usual get methods to retrieve address fields, two additional get methods to retrieve combined fields, and a method to compare addresses:

See Address.java for the complete, annotated source code.

AddressBook's Java Server Pages

AddressBook has seven JSPs. Each represents a Web page that performs an independent operation on the AddressBook's database. The state of the database in each page is independent of the state of the database for the previous page. If the database changes due to another user's request, the Web page will detect this and react accordingly. For example, if you are modifying an address and another user deletes that address before you confirm the modification request, the JSP will notify you of the failture to modify the now-non-existent address.

Figure 2 shows the logic flow between the JSPs.

Figure 2

Home.jsp

Home.jsp is the home page of the AddressBook Web application, and is the first page displayed when a user enters the AddressBook Web application. It displays a table showing all of the addresses in the Addresses database. Each row of the table shows an individual address, and links to delete or to modify that address. The bottom of the page has a link to add a new address. See the web.xml notes for information on how this is configured.

See Home.jsp for the complete, annotated source code.

RequestAdd.jsp

RequestAdd.jsp displays an address form in which you enter the new address fields. At the bottom of the Web page is an abort link for aborting the request.

See RequestAdd.jsp for the complete, annotated source code.

DoAdd.jsp

DoAdd.jsp displays the new address fields it receives. It then attempts to add the new address to the database and displays the success or failure of the attempt. At the bottom of the Web page is a continue link.

See DoAdd.jsp for the complete, annotated source code.

RequestDelete.jsp

RequestDelete.jsp reads the address corresponding to the id it received. It then displays the address fields in a table so that you can ensure that the correct address is to be deleted. At the bottom of the Web page are two links: a continue link for continuing with the request, and an abort link for aborting the request.

See RequestDelete.jsp for the complete, annotated source code.

DoDelete.jsp

DoDelete.jsp reads the address whose id was passed to it. It then displays the address in a table, attempts to delete the address from the database, and displays the success or failure of the attempt. At the bottom of the Web page is a continue link.

See DoDelete.jsp for the complete, annotated source code.

RequestModify.jsp

RequestModify.jsp displays an HTML form with the current address values. It also features a submit button and a link to abort the request.

See RequestModify.jsp for the complete, annotated source code.

DoModify.jsp

DoModify.jsp displays the modified address fields it receives in a table. It then attempts to modify the address in the database and displays the success or failure of the attempt. At the bottom of the Web page is a continue link.

See DoModify.jsp for the complete, annotated source code.

AddressBook's Addresses Database Table

Setting up the database depends on the database software being used. You will need to amend these instructions if you are not using MySQL. AddressBook employs a single table called Addresses in a database called Public. The Addresses table has seven fields:

Let's set up the MySQL database. Start the mysql command-line utility with root permissions. When requested, enter the password. Create the Public database and grant the mysqlusername permissions on that database, with a permission of mysqlpassword. The commands are:

# mysql -u root -p
mysql> create database Public;
mysql> grant all privileges on Public.* to mysqlusername@localhost \
identified by 'mysqlpassword' with grant option;
mysql> flush privileges;

Next, create the Addresses table in the Public database.

mysql> create table Addresses ( \
id        int(8) primary key auto_increment, \
surname   varchar(24) not null, \
firstname varchar(24) not null, \
street    varchar(80) not null, \
district  varchar(80) not null, \
city      varchar(40) not null, \
postcode  varchar(10) not null \
);

Commit the changes with the commit; command. To verify the table's configuration,issue the describe Addresses; command. You should get the following:

+-----------+-------------+------+-----+---------+----------------+
| Field     | Type        | Null | Key | Default | Extra          |
+-----------+-------------+------+-----+---------+----------------+
| id        | int(8)      |      | PRI | NULL    | auto_increment |
| surname   | varchar(24) |      |     |         |                |
| firstname | varchar(24) |      |     |         |                |
| street    | varchar(80) |      |     |         |                |
| district  | varchar(80) |      |     |         |                |
| city      | varchar(40) |      |     |         |                |
| postcode  | varchar(10) |      |     |         |                |
+-----------+-------------+------+-----+---------+----------------+

Now you can insert a row of data to test the database.

mysql> insert into Addresses (surname, firstname, street, district, \
city, postcode) values ("Smith", "John", "1, The High Street,", \
"Downtown,", "Metropolis.", "X99 9XX");
mysql> commit;
mysql> select * from Addresses;

This should produce the following output:

+----+---------+-----------+--------------+-----------+-------------+----------+
| id | surname | firstname | street       | district  | city        | postcode |
+----+---------+-----------+--------------+-----------+-------------+----------+
|  1 | Smith   | John      | 1, The       | Downtown, | Metropolis. | X99 9XX  |
|    |         |           | High Street, |           |             |          |
+----+---------+-----------+--------------+-----------+-------------+----------+

Notice that the address id has been automatically assigned a value of 1. AddressBook's database is now ready for use.

Configuring AddressBook's Development Directory

We are now ready to configure the development directory where AddressBook's source files are held, and the war directory where the Web application will be built and where the Web application's Web archive file will be held.

Download the AddressBook source files archive (AddressBook.zip). Unzip the archive. You now have the application's source files in a directory structure ready for processing by the Ant development tool, as you can see in Figure 3. There is no need to put AddressBook's development directory anywhere special -- I recommend that you put it somewhere in your home directory structure.

Figure 3

Lets have a look at these files:

AddressBook/build.properties

AddressBook/build.properties contains a number of configuration settings that are read into the AddressBook/build.xml file. To configure the build, you should edit the smaller build.properties file. Leave the more complex build.xml file alone as much as possible.

app.name=AddressBook
tomcat.home=/usr/local/jakarta-tomcat-4.1.12
manager.url=http://localhost:8080/manager
username=tomcatusername
password=tomcatpassword

You do not need to change the app.name parameter now. If you later reuse these files to create another Web application, you can change app.name to reflect the name of the new application. Assuming that you are using a Tomcat 4 instance running on your local machine, you should not need to change the manager.url parameter.

You will probably need to change the tomcat.home parameter to point at your Tomcat home directory. The above setting assumes that Tomcat 4.1.12 has been installed in the /usr/local directory. Ant uses this parameter to set up a CLASSPATH for compiling AddressBook's Java classes, with Tomcat's common/lib .jar files. (These .jar files are automatically available at runtime to both Tomcat and the Web application and do not need to be copied into the Web application's WEB-INF/lib directory.)

Tomcat has a similar directory: shared/lib. These .jar files are available at runtime to the Web application, but not to Tomcat itself.

You will need to change the tomcatusername and tomcatpassword parameters so that they match those in Tomcat's conf/tomcat-users.xml file. Ant uses these parameters, as well as manager.url, to establish its authority to install the AddressBook Web application into the Tomcat environment.

See build.properties for the complete, annotated source code.

AddressBook/build.xml

AddressBook/build.xml contains the Ant configuration data. build.xml implements many Ant "targets." Here are the more useful targets:

See build.xml for the complete, annotated source code.

AddressBook/context.xml

AddressBook/context.xml is installed into Tomcat by Ant when processing install, reload, remove, deploy, and undeploy requests. It contains the details of AddressBook's "context," or the parameters that Tomcat uses when executing AddressBook.

A Logger entry specifies that Tomcat should log AddressBook events into a text file stored in Tomcat's logs directory. Here is the Logger entry to name the log file localhost_AddressBook_log.YYYY-MM-DD.txt, where YYYY-MM-DD is the log's date:

<Logger className="org.apache.catalina.logger.FileLogger"
	prefix="localhost_AddressBook_log." suffix=".txt" timestamp="true"/>

A Resource entry, together with a ResourceParams entry, specifies that Tomcat should establish a javax.sql.DataSource named jdbc/Public for AddressBook. The following settings establish the javax.sql.DataSource as a org.apache.commons.dbcp.BasicDataSourceFactory class, the URL as jdbc:mysql://localhost:3306/Public?autoReconnect=true, a JDBC Driver Class of org.gjt.mm.mysql.Driver, a username of mysqlusername, and a password of mysqlpassword:

<Resource name="jdbc/Public" auth="Container" type="javax.sql.DataSource"/>

<ResourceParams name="jdbc/Public">

    <parameter>
        <name>factory</name>
        <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
    </parameter>

    <parameter>
        <name>url</name>
        <value>jdbc:mysql://localhost:3306/Public?autoReconnect=true</value>
    </parameter>

    <parameter>
        <name>driverClassName</name>
        <value>org.gjt.mm.mysql.Driver</value>
    </parameter>

    <parameter>
        <name>username</name>
        <value>mysqlusername</value>
    </parameter>

    <parameter>
        <name>password</name>
        <value>mysqlpassword</value>
    </parameter>

    ... [omitted] ...

</ResourceParams>

The above code creates the javax.sql.DataSource as part of the Web application's context. Alternatively, where the javax.sql.DataSource is to be used by more than one Web application, it may be defined as a global resource outside of the Web application's context with the Tomcat Administration software.

See context.xml for the complete, annotated source code.

AddressBook/src/*.java

The src directory contains the Web application's three Java classes. See Address.java, AddressesDB.java, and ContextListener.java for the complete, annotated source code.

AddressBook/web/*.jsp

The web directory contains the Web application's seven JSPs. See Home.jsp, RequestAdd.jsp, DoAdd.jsp, RequestDelete.jsp, DoDelete.jsp, RequestModify.jsp, and DoModify.jsp for the complete, annotated source code.

AddressBook/web/WEB-INF/web.xml

AddressBook/web/WEB-INF/web.xml is the Web application deployment descriptor for AddressBook. It contains two key parameters.

The listener parameter identifies the listener Java class AddressBook.ContextListener, which will be called during application startup and shutdown.

<listener>
   <listener-class>AddressBook.ContextListener</listener-class>
</listener>

The welcome-file-list parameter controls the entry point for AddressBook. The following code sets Home.jsp as AddressBook's only entry point.

<welcome-file-list>
   <welcome-file>Home.jsp</welcome-file>
</welcome-file-list>

See web.xml for the complete, annotated source code.

Building, Installing, Deploying, and Running AddressBook

To install the address book, change to the AddressBook directory, and issue the install command to Ant:

    $ cd AddressBook
    $ ant install

If the install failed, check that the tomcat-users.xml file in Tomcat's conf directory is set up correctly, and that catalina-ant.jar in Tomcat's server/lib directory has been copied into Ant's lib directory.

Note that ant install automatically triggers a number of other Ant targets, in this sequence: ant init, ant prepare, ant build, and ant package, as follows:

This is controlled by the depends option; see AddressBook/build.xml for details.

Figure 4 shows the war directory structure populated with the various files that compose the AddressBook Web application.

Figure 4

Point your browser at http://localhost:8080/AddressBook to test the AddressBook Web application. You can see AddressBook's Home Page in Figure 5. If it failed to execute correctly, check that you have put your database's JDBC driver file in Tomcat's common/lib directory. Finally, check in Tomcat's logs directory -- it contains various text files that will help you investigate the problem.

Figure 5

Try to add a new address, then modify it, then delete it, then add another new address. You will see that the id keeps incrementing automatically.

The Development Cycle

When AddressBook was installed, Tomcat called AddressBook.ContextListener.contextInitialized, which created an instance of AddressBook.AddressesDB. The AddressBook.AddressesDB constructor established a connection using the jdbc/Public DataSource. AddressBook.ContextListener.contextInitialized then saved the instance of AddressBook.AddressesDB as a servlet attribute called addressesDB.

When AddressBook's Home.jsp was first called up, Tomcat compiled and executed it. Home.jsp retrieved the servlet attribute called addressesDB and acquired the instance of AddressBook.AddressesDB. Home.jsp then read the addresses from the database and displayed them. As you proceeded through the other JSPs for the first time, they were also compiled and executed. The other JSPs access the database in the same way as Home.jsp.

Issue ant stop to stop the AddressBook Web application. Tomcat will automatically call AddressBook.ContextListener.contextDestroyed and retrieve the same addressesDB servlet attribute and acquire the same instance of AddressBook.AddressesDB. AddressBook.ContextListener.contextDestroyed will then close the database connection and remove the addressesDB servlet attribute.

Issue ant start to start the the AddressBook Web application. Tomcat will automatically call AddressBook.ContextListener.contextInitialized and the entire process will repeat.

When developing a Web application, the cycle goes as follows: make changes to your software; issue ant install to build and install the Web application; point your browser at http://localhost:8080/applicationName (or simply hit the browser's refresh button) to test the Web application; issue ant remove to remove the Web application's context; repeat. When you are happy with the application, issue ant deploy to permanently deploy the Web application. Now your Web application will be available after you restart Tomcat, or even after you reboot your server and start Tomcat. Issue ant undeploy to permanently undo deployment of the Web application.

Tomcat Manager

Instead of Ant, you can use the Tomcat manager Web page. Point your browser to http://localhost:8080/manager/html/list. You can see Tomcat's Manager Web page in Figure 6.

Figure 6

Alternatively, you can issue these URLs directly:

Tomcat Administration

To login to Tomcat's Web-based administration, point your browser at http://localhost:8080/admin. You will be presented with a login screen. Enter your Tomcat "admin" username and password. These are the same as the "manager" username and password: tomcatusername and tomcatpassword. The tomcat-users.xml file has been set up with a single account with admin, manager, and provider roles. It is a trivial change to set up multiple Tomcat accounts each with separate roles.

The resulting Web page is split into three panels: a heading panel, a tree panel, and a data panel. You can see this sequence of Web pages in Figure 7.

Figure 7

The tree can be used in the normal way -- branches can be opened, selected, etc. Open the Service (Tomcat-Standalone) branch, then the Host (localhost) branch, then the Context (/AddressBook) branch, and finally AddressBook's Resources branch.

Note the global Resources branch further down the tree panel. Do not mix up the global Resources branch with AddressBook's Resources branch. You may define global javax.sql.DataSource resources that can be used by any Web application in the global Resources branch.

AddressBook's Context Panel

Select the Context (/AddressBook) branch. AddressBook's context panel will appear in the data panel. You can see AddressBook's Context Web page in Figure 8.

Figure 8

You may make any changes you wish -- most interestingly, the three different Debug Level parameters. To save the changes, press the Save button, then press the Commit Changes button in the heading panel.

AddressBook's Data Source Panel

Select the Data Sources branch in the Context (/AddressBook)'s Resources branch of the tree. AddressBook's data sources panel will appear in the data panel.

Select the data source jdbc/Public to view that specific javax.sql.DataSource. You can see AddressBook's Data Source Web page in Figure 9.

Figure 9

You may make any changes you wish -- most interestingly, the Data Source URL, JDBC Driver Class, User Name, Password, Max. Active Connections, Max. Idle Connections, and Max. Wait for Connection. To save the changes, press the Save button, then press the Commit Changes button in the heading panel.

If you are simply working on your personal computer, this may not seem to be very important, but on your company's production Web server environment, this is a really important facility. These parameters are likely to change, and you don't need to be a programmer to change them -- a Tomcat administrator can do it. As a programmer, my head is already full of usernames and passwords, and I don't want to know any more. I certainly do not want to know my company's production database username and password. Quite rightfully, too -- such information should be on a need-to-know basis, and, because of javax.sql.DataSources, and Tomcat 4's administration service, I no longer need to know.

Using Ant to establish a Web application's context is fine when developing the software. Tomcat's administration service comes into its own in the production environment.

AddressBook's Logger Panel

Select the Logger for Context (/AddressBook) branch in the Context (/AddressBook) branch of the tree. AddressBook's logger panel will appear in the data panel. You can see AddressBook's Logger Web page in Figure 10.

Figure 10

You may make any changes you wish -- the most interesting options are Debug Level and Verbosity Level. To save the changes, press the Save button, then press the Commit Changes button in the heading panel.

Biblography

This article could not have been written without the assistance of these documents:

Tomcat Servlet/JSP Container Documentation
You can get the latest Tomcat, which includes documentation, from http://jakarta.apache.org/tomcat.

Java Web Services Developers Pack Tutorial
You can get the latest Java Web Services Developers Pack Tutorial from java.sun.com/webservices/tutorial.html.

Paul Wood has been programming for 32 years and is now a freelancer.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.