Article
First Steps with Jakarta Struts
To compile the application, we need to have the J2EE libraries on the classpath. Fortunately, the Apache Tomcat Web container already comes with these libraries, so the question becomes one of referencing. Rather than hard-code Tomcat's installation folder into our build file, let's set up an operating system environment variable called TOMCAT_HOME that refers to the root of the Tomcat installation folder, e.g. C:\Program Files\Apache Software Foundation\Tomcat 5.0. The procedure for doing this is exactly the same as the one we used to create the ANT_HOME and JAVA_HOME environment variables in Apache Ant Demystified.
With that done, we can add a couple of property declarations to the top of our build.xml file:
<project name="webforum" default="dist" basedir=".">
<description>
Build file for the Struts WebForum application.
</description>
<property environment="env" />
<property name="tomcat.dir" location="${env.TOMCAT_HOME}" />
The first property declaration simply says that we want to use the identifier env to refer to operating system environment variables. The second property sets the location of tomcat.dir to whatever env.TOMCAT_HOME is. Thus, from now on, when we want to refer to Tomcat's installation folder, we can simply use ${tomcat.dir}.
Later, we set up a property named j2ee.lib.dir that points to the location at which Tomcat keeps its J2EE libraries:
<property name="j2ee.lib.dir" location="${tomcat.dir}/common/lib" />
We now need to deal with setting up the classpath. Ant provides several ways to do this; we're going to set up a path structure which we'll assign the unique ID of classpath:
<path id="classpath">
<pathelement path="${j2ee.lib.dir}/servlet-api.jar" />
<fileset dir="${web.lib.dir}">
<include name="**/*.jar" />
</fileset>
</path>
The snippet above shows that there are two elements within this path structure. The first element is an individual reference to the servlet-api.jar file, which is referenced using the pathelement tag. The second element is Ant's fileset tag, which in our case has been set up to include all the JAR files within the folder represented by the ${web.lib.dir} property. To clarify, we're setting up a classpath that includes Tomcat's servlet-api.jar file and all the JAR files within public_html/WEB-INF/lib.
In order to use this classpath, the javac task within our build file's compile target contains a nested classpath tag, which has a refid attribute set to the name of the path structure that we defined above:
<javac srcdir="${src.dir}" destdir="${classes.dir}">
<classpath refid="classpath" />
</javac>
That's how we make sure that the Java compiler can find all the libraries it needs to compile our application. The javadocs target also makes use of this classpath, which we defined once and can then re-use anywhere within the build file.
The next task is to package the compiled code into a WAR file (Web ARchive) so that it can be run by Tomcat. We create a dist target that looks like this:
<target name="dist" depends="compile"
description="Create the binary distribution.">
<delete dir="${dist.dir}" />
<mkdir dir="${dist.dir}" />
<war basedir="${web.src.dir}"
destfile="${dist.warfile}"
compress="true"
webxml="${web.src.dir}/WEB-INF/web.xml"
excludes="**/web.xml">
<classes dir="${classes.dir}" />
</war>
</target>
Note that this target depends on the compile target, which makes sure that we always compile the code before we try to create a distribution in which it's included! After deleting and recreating the output directory, we use Ant's war task to create the WAR file. The basedir attribute points to a property that represents the public_html folder -- the root of our application. The destfile attribute simply specifies the name of the output WAR file that's to be created. We can choose whether or not to compress the file using -- you guessed it -- the compress attribute; the webxml attribute tells the war task where our Web application deployment descriptor is located. The use of this last attribute automatically ensures that the web.xml file is included in the WAR file. Thus, we use the excludes attribute to tell Ant not to generate a warning because it thinks we're trying to include web.xml twice. Finally, a nested classes element tells the war task where our compiled classes are located.
If you run the dist target and then open /dist/WebForum.war using WinZip (or download the pre-compiled version from this site), you can see that the layout within the archive precisely mirrors the source code tree mentioned earlier. The compiled code has been placed within WEB-INF/classes and the Struts and MySQL JDBC JAR files are within WEB-INF/lib.
Running The Application Using Apache Tomcat
These instructions describe how to configure the Apache Tomcat Web container to use a MySQL data source. They've been tested using Tomcat 5.0.28 and MySQL 4.0.18, but should work with Tomcat 4 and other versions of MySQL, too. Note that TOMCAT_HOME refers to the root of the Tomcat installation folder, e.g. C:\Program Files\Apache Software Foundation\Tomcat 5.0.
Copy the MySQL JDBC driver JAR file to TOMCAT_HOME/common/lib.
Edit the TOMCAT_HOME/conf/server.xml file so that it includes a context definition for the Web Forum application. The main elements of the server.xml file are shown below:
<Server>
<Service>
<Engine>
<Host>
:
<Context>
<!-- Existing context definitions. -->
</Context>
:
<!--
| Paste Web Forum context definition (shown below) here.
+-->
</Host>
</Engine>
</Service>
</Server>
Add the following context definition for the Web Forum application to the appropriate place in the server.xml file, substituting your MySQL webforum database user name and password where the italics indicate:
<!--
| Begin WebForum context definition.
+-->
<Context path="/WebForum" docBase="WebForum"
reloadable="true">
<Logger className="org.apache.catalina.logger.FileLogger"
prefix="localhost_WebForum." suffix=".txt" timestamp="true"/>
<Resource name="jdbc/WebForumDS" auth="Container"
type="javax.sql.DataSource"/>
<ResourceParams name="jdbc/WebForumDS">
<parameter>
<name>factory</name>
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
</parameter>
<!--
| The JDBC connection URL for connecting to your MySQL DB.
| The autoReconnect=true argument to the URL makes sure that the
| MySQL JDBC Driver will automatically reconnect if mysqld closed
| the connection. mysqld by default closes idle connections after
| 8 hours.
+-->
<parameter>
<name>url</name>
<value>jdbc:mysql://localhost:3306/webforum?
autoReconnect=true</value>
</parameter>
<!--
| MySQL username and password for DB connections.
+-->
<parameter>
<name>username</name>
<value>username</value>
</parameter>
<parameter>
<name>password</name>
<value>password</value>
</parameter>
<!--
| Class name for MySQL JDBC driver.
+-->
<parameter>
<name>driverClassName</name>
<value>com.mysql.jdbc.Driver</value>
</parameter>
<!--
| Maximum number of DB connections in pool. Make sure you
| configure your mysqld max_connections large enough to handle
| all of your DB connections. Set to 0 for no limit.
+-->
<parameter>
<name>maxActive</name>
<value>100</value>
</parameter>
<!--
| Maximum number of idle DB connections to retain in pool.
| Set to 0 for no limit.
+-->
<parameter>
<name>maxIdle</name>
<value>30</value>
</parameter>
<!--
| Maximum time to wait for a DB connection to become available
| in ms, in this example 10 seconds. An exception is thrown if
| this timeout is exceeded.
| Set to -1 to wait indefinitely.
+-->
<parameter>
<name>maxWait</name>
<value>10000</value>
</parameter>
</ResourceParams>
</Context>
<!--
| End WebForum context definition.
+-->
Next, copy the dist/WebForum.war we created earlier to TOMCAT_HOME/webapps. This archive will be automatically expanded and the Web Forum deployed the next time Tomcat is started.
After starting the MySQL and Tomcat servers, the application can be accessed in a Web browser using the URL: http://localhost:8080/WebForum/
We've covered a lot of important ground with this instalment. Next time, we'll take a look at how the Topics page works, and move on from there. See you then!