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
|
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 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 has three Java classes, detailed below. Figure 1 shows how the classes are used within the Tomcat Servlet/JSP Container.

AddressBook.ContextListenerAddressBook.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.AddressesDBAddressBook.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:
getAddress(id) returns the address identified by the id,
or null if the address is not found.addAddress(address) adds an address and returns the number
of rows affected.deleteAddress(id) deletes the address identified by the id
and returns the number of rows affected.modifyAddress(address) modifies an address and returns the
number of rows affected.getAddresses() returns a sorted Collection of
all of the addresses in the database, or null if the addresses database is not
found. close() closes the database connection.See AddressesDB.java for the
complete, annotated source code.
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:
Address(id, surname, firstname, street, district, city, postcode)getId()getSurname()getFirstname()getStreet()getDistrict()getCity()getPostcode()getFullname() returns the firstname + " " + surnamegetFulladdress() returns street + " " + district + " " + city + " " + postcodecompareTo(address) returns a negative integer, zero, or a positive integer, depending on whether surname and firstname is greater than, equal to, or less than this surname and firstname, ignoring case considerations. It is used when sorting a Collection of addresses.See Address.java for the complete,
annotated source code.
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.

Home.jspHome.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.
RequestAdd.jsp.RequestDelete.jsp with the id of the address to be deleted.RequestModify.jsp with the id of the address to be modified.See Home.jsp for the complete, annotated source code.
RequestAdd.jspRequestAdd.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.
DoAdd.jsp with the new address fields (surname, firstname, street, district, city, and postcode).Home.jsp.See RequestAdd.jsp for the
complete, annotated source code.
DoAdd.jspDoAdd.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.
Home.jsp.See DoAdd.jsp for the complete,
annotated source code.
RequestDelete.jspRequestDelete.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.
DoDelete.jsp the id of the address to be deleted.Home.jsp.See RequestDelete.jsp for the
complete, annotated source code.
DoDelete.jspDoDelete.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.
Home.jsp.See DoDelete.jsp for the complete,
annotated source code.
RequestModify.jspRequestModify.jsp displays an
HTML form with the current address values. It also features a submit button and
a link to abort the request.
DoModify.jsp with its address fields (id, surname, firstname, street, district, city, and postcode).Home.jsp.See RequestModify.jsp for the
complete, annotated source code.
DoModify.jspDoModify.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.
Home.jsp.See DoModify.jsp for the complete,
annotated source code.
|
Addresses Database TableSetting 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:
id, the primary key, a numeric field that is automatically incremented by the database software.surname, a 24-character field that holds the surname of the owner of the address.firstname, a 24-character field that holds the first name of the owner of the address.street, an 80-character field that holds the address' first line.district, an 80-character field that holds the address' second line.city, a 40-character field that holds the address' city.postcode, a 10-character field that holds the address' postcode.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.
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.

Lets have a look at these files:
AddressBook/build.propertiesAddressBook/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.xmlAddressBook/build.xml contains the Ant configuration data. build.xml implements many Ant "targets."
Here are the more useful targets:
ant build builds the Web application.ant install installs the Web application for testing.ant remove uninstalls the Web application.ant deploy permanently installs the Web application.ant undeploy permanently undeploys the Web application.See build.xml for the complete,
annotated source code.
AddressBook/context.xmlAddressBook/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/*.javaThe 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/*.jspThe 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.xmlAddressBook/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.
|
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:
ant init initializes the time stamp.
ant prepare creates a war directory structure in the
AddressBook directory, as follows: a war directory, a
war/WEB-INF, a war/WEB-INF/classes directory, and a
war/WEB-INF/lib directory.
ant build builds the Web Application by copying the
jsp files into the war directory, copying the
context.xml files into the war/META-INF directory,
copying the web.xml file into the war/WEB-INF
directory, and compiling any Java files into the
war/WEB-INF/classes directory.
ant package creates the Web archive file from the
war directory. The Web archive file is a .jar file and is created
using the jar application.
Finally, ant install installs the Web archive file into Tomcat
using the war/META-INF/context.xml configuration file. Note that
there is no need to log in as root or Tomcat to install AddressBook in Tomcat;
your normal user account will do fine. ant uses the
tomcatusername and tomcatpassword specified in AddressBook/build.properties to
access Tomcat in a secure manner.
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.

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.

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.
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.
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.

Alternatively, you can issue these URLs directly:
http://localhost:8080/manager/listhttp://localhost:8080/manager/resourceshttp://localhost:8080/manager/roleshttp://localhost:8080/manager/start?path=/AddressBookhttp://localhost:8080/manager/stop?path=/AddressBookhttp://localhost:8080/manager/remove?path=/AddressBookhttp://localhost:8080/manager/sessions?path=/AddressBook
|
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.

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.
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.

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.
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.

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.
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.

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.
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 © 2007 O'Reilly Media, Inc.