The GWT shell uses a stripped down and somewhat customized version of the Apache Tomcat servlet container as its development mode server. While this is a Tomcat instance, GWT sets things up differently to automate certain elements and facilitate quick and easy development mode use and testing.
GWT's deployment of applications to the local Tomcat can be somewhat confusing. Saying that GWT uses Tomcat is much like saying that your favorite driver drives a Camaro in NASCAR races. It might look like a Camaro, people might even call it a Camaro, but driving it's not like driving the Camaro your local GM dealer will sell you. GWT's Tomcat has a custom deployment descriptor, web.xml, which includes the configuration for the special GWTShellServlet. This servlet is used in hosted mode only to automatically dispatch servlet entries from your module file into the appropriate classes.
In addition, GWT's Tomcat doesn't honor any Tomcat context-configuration information (context.xml) stored in your application. Instead, the GWT Tomcat instance uses web.xml (its own variation of context.xml) and a set of pseudo-Tomcat home directories. This can be limiting and frustrating for developers who want to include additional container or application-level configuration for use inside Tomcat Lite. The first thing you're likely to want to modify to your own liking is web.xml.
The web.xml file
he Tomcat Lite development server won't honor your application's local web.xml deployment descriptor by default, so this is usually the first thing you have to deal with when it comes to setting up application-related parameters that you want in hosted mode. In order to enable such resources as filters or custom security constraints in your application in hosted mode, you can have your project's build file create or modify the appropriate [PROJECT_HOME]/tomcat structure. The [PROJECT_HOME]/tomcat directory, where the GWT shell's development-mode Tomcat Lite server is installed by default, has the following default structure:
- web.xml (see listing 1)
- web.xml (see listing 2)
With that structure in mind, we'll take a look at the files themselves to understand where to make modifications, should the need arise. The first web.xml file, shown in listing 1, is the one global to the whole server. By default, GWT sets this file up as a stripped-down version of the Tomcat base web.xml file that just includes some common MIME-type mappings. While the purist might argue that any MIME types you're going to use in your application should be included in your custom web.xml file, many people don't do this consistently.
Listing 1 The structure of the default server web.xml file
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!-- A tweaked version of the default Tomcat web.xml file
to remove everything except the stuff we want to use -->
<!-- stuff omitted... -->
The second web.xml file, displayed in listing 2, is the GWT-generated mapping for servlets specified in the module's gwt.xml file through the previously noted special servlet, GWTShellServlet. This effectively proxies servlet mappings for use in hosted mode. (This servlet should never be deployed with your application - it's only useful for hosted mode.)
Listing 2 The special GWTShellServlet mapping web.xml file
<?xml version="1.0" encoding="ISO-8859-1" ?>
Working with these GWT-specific files and having your own web.xml configuration ignored in a development context is, of course, limiting in a number of ways. GWT won't honor your security parameters or filter chains. Nor will GWT inject resource references into your JNDI tree. Synchronizing the servlet entries in both your GWT module file and a separate deployment descriptor that will later be included with your deployed application is also a pain, and prone to "fat-finger" errors.
The solution is to somehow modify the Tomcat Lite web.xml files to include your application's local configuration information when you launch GWTShell. You can do this by hand, but it's much more convenient to have a build process that inspects a local web.xml file (one that's included in the source for your project, intended to be used outside of the hosted mode when you deploy) and includes your configuration information in the GWT files automatically.
Because you don't want to define servlet elements in two places, and you ultimately want to have a web.xml file that's deployed with your application that also matters to the GWT development server, you have a two-sided problem. That is, you may have GWT servlet elements defined in your module, and you may also have other application resources, such as security realm information, defined in your application's web.xml. Yet you need configuration information from both sources to be available in both places (in hosted mode for Tomcat Lite, and outside of hosted mode in standard container format when deployed). To accomplish this, you can inject your configuration into the Tomcat Lite web.xml for hosted mode use, and you can copy the elements from your module file into your web.xml for standard deployment.
In order to make this happen, you can add some intelligence to your build process to create a new web.xml file for hosted mode use. You can then use this new file to replace the GWT default webapps/ROOT/web.xml file. The important thing to keep in mind here is that, regardless of how you do it, you can modify the Tomcat Lite web.xml file for hosted mode configuration. You can also modify the Tomcat context.xml context descriptor in the same manner.
The context.xml file
If you want to include configuration resources at the Tomcat context level when working with the embedded Tomcat instance, and also have those resources available in hosted mode, you again have to manipulate the GWT Tomcat files. As an example, we'll deal with a common problem: defining JNDI DataSource entries at the context level. We provide a sample method for getting around the overall issue.
First off, let's talk about dependencies. GWTShell's Tomcat instance does not include the libraries needed to load DataSource implementations into the JNDI tree on its own. If you want to use Tomcat's DataSource handling, you need to include (from the Jakarta Commons project, http://jakarta.apache.com) the commons-dbcp and commons-pool JAR files in the startup classpath for your project. You also need to include the appropriate JDBC driver for your particular database.
Once you have the dependencies in place, you have to start GWTShell once to get it to write out a [PROJECT_HOME]/tomcat directory tree. This is effectively what you'd expect from $CATALINA_HOME in a regular Tomcat installation. Once this has happened, you can create or modify the main Tomcat Lite context file, which is renamed ROOT.xml in GWT. This file can be used to define your DataSources: [PROJECT_HOME]/tomcat/conf/gwt/localhost/ROOT.xml
You can add your DataSource information to the ROOT.xml location, or copy a custom META-INF/context.xml from your project into that location and rename it. The configuration shown in listing 3 can be used as a reference.
Listing 3 Example DataSource configuration for Tomcat 5.0.x context.xml
<Resource name="jdbc/demogwt" auth="Container" type="javax.sql.DataSource"/>
When you do this, of course, you're duplicating your context information and once again manipulating the Tomcat Lite files, rather than resources local to your project as you might normally expect. This is ugly, but it does get around the issue of including context resources and still makes development mode resources available as they would be in production, because they will be present once things are deployed. (This example is based on Tomcat 5.0.x. If you deploy to a newer version or a different platform, you'll have to deal with configuration differences.)
GWT will also let you specify a base Tomcat directory using the catalina.base system property. You can use this behavior to specify an alternative internal Tomcat location, which gives you many options with regard to creating and maintaining the internal Tomcat structure.
As an alternative to configuring the GWT-embedded Tomcat server, you can also use the hosted mode browser in standalone mode with an external servlet container by passing the -noserver switch to GWTShell on the command line.
This article is excerpted from Chapter 1 of GWT in Practice, by Robert Cooper and Charlie Collins, and published in May 2008 by Manning Publications.