 | Level: Intermediate Noel Rappin (noelrappin@gmail.com), Senior Software Engineer, Motorola, Inc.
27 Feb 2007 In the past three articles in this series, you've built a simple but functional Web application using the Google Web Toolkit (GWT). Until now, you've been editing and debugging the application using GWT's hosted mode, which allows you to simulate a Web server environment within your Java™ development tool. Sadly, it's impractical to have all your users download Eclipse just to run your Web application. So, in this article, the fourth in this series, you'll learn how to deploy your GWT application within a Java Web application server and get tips on using the Apache Derby database to drive the GWT.
In this article, you'll use Apache Tomcat as your example servlet container, because it's both widely used and available at no cost. Other servlet containers will behave similarly.
You'll often be deploying to an existing server; but if not, the links in the
Resources section at the end of this article point you to
the Tomcat download location. If you're running the Microsoft® Windows® operating system,
Tomcat has a binary installer for Windows that's relatively simple to use. If you're
on a Mac or a UNIX® system, there's a compiled version that you can extract and
place in a convenient location (/usr/local is common); after setting a few environment
variables, you're good to go.
Compile your client code
Broadly speaking, there are two steps to deploying your GWT application in Tomcat.
- Gather all the files you'll need and put them where Tomcat can see them.
- Make Tomcat aware of all the server-side actions you call from your GWT page.
 | | Check out the Ajax Resource Center, your one-stop shop for information on the Ajax programming model, including articles and tutorials, discussion forums, blogs, wikis, events, and news. If it's happening, it's covered here. |
|
The process has a few more steps than is
desirable, and as of this writing there's no official method of automating it.
I describe the manual process here. By the time you read this, however, there
may be more robust tool support for deployment.
- Locate your Tomcat installation's root directory. One level down from that
directory you'll see a subdirectory called webapps. Every application
running within the Tomcat servlet container gets its own directory there. So
create a directory called slicr within webapps. The structure of a Java
server-side application is set by the servlet standard, and all servlet runners
should support the same structure.
- Within your slicr directory, create a
subdirectory called WEB-INF -- and yes, the capitalization is important.
- To your slicr directory, move both your GWT-compiled JavaScript pages and your
normally compiled Java classes. I'll show how to do the Java classes first.
- Compile
your Java code as you normally would, using your integrated development environment
(IDE), Apache Ant, or whatever you wish. You have a couple of options at this
point:
- The quickest option is to copy your entire tree of .class files to the
Tomcat subdirectory webapps/slicr/WEB-INF/classes, which Tomcat automatically
places in the classpath variable of your webapps
directory when run.
- Alternately, you could convert the compiled classes to a
JAR file using the tool of your choice, and then place that JAR file in the
webapps/slicer/WEB-INF/lib directory. Again, Tomcat places the JAR file in
that directory in your classpath variable.
Compile your GWT client files
Next up, compile and move your GWT client files. Because you've done most of
your work in hosted mode, you've been able to skip performing this step
explicitly to date. The quickest way to compile your code is to use the
Compile button from the hosted mode console. But there's another way
that might be more convenient for automating.
In Part 1 of
this series, you used the GWT applicationCreator script to create your GWT
project. At the time, I casually alluded to "a couple of shell scripts" created
along with the GWT project files but didn't go into more detail.
One of the shell files created is called Slicr-compile. In Windows, the
file also has a .cmd extension. (Generically, of course, it's
your project name-compile.) Invoke the file from a command line, or click
it depending on your operating system. The script putters around for a while
before outputting something like this:
Output will be written into ./www/com.ibm.examples.Slicr
Compilation succeeded
What's happening here is that GWT is compiling all your client-side Java code
into JavaScript code. Client-side code, by default, is all the code in your
project's client source directory; however, you can explicitly change
that directory in your project .gwt.xml file by adding a tag of the form
<source path=path/>, where path
is the source path you want to add. Note that the default path is no longer
included if you add your own path, so if you also want the default path, you
must add it explicitly.
The GWT compiler usually converts legal Java code successfully. However, some
items will cause problems. Following are some things to be particularly aware of:
- GWT client code must be compatible with Java 1.4. That means no
generics, no autoboxing, and no new-style for-each loop. Supposedly, Java 1.5
compatibility is planned for the future.
- Only a minimal subset of the Java Standard Library is supported.
Supported library classes are limited to the java.util and java.lang
packages. Not all of these packages are supported. In particular, the
java.lang.reflect package is not supported. As you saw in
Part 2
of this series, this restriction means that you must put items like
database code in other parts of your system.
- If you use regular expressions, they are interpreted at run time using
the JavaScript rules, not the Java rules.
- Java serialization is not supported. The GWT remote procedure mechanism
is used instead, as discussed in
Part 3
of this series.
- There are differences in the definition of floating-point numbers and
long variable types. Calculations that require
strict floating-point semantics should be handled on the server side.
- The GWT compiler ignores Java
assert
statements. Also ignored are synchronized declarations,
as the JavaScript interpreter does not support threading.
Investigate the compilation output
Assuming that your Java code passes those requirements and your compilation is
successful, you can follow the output of the compile script and investigate
the ./www/com.ibm.examples.Slicr directory, as shown in Listing 1.
Some of your file names may differ.
Listing 1. Output from GWT compilation
1A0A627040909C0818A7A71B13246DCD.cache.html
1A0A627040909C0818A7A71B13246DCD.cache.xml
587B8CC6CF487EBD41844000481528BF.cache.html
587B8CC6CF487EBD41844000481528BF.cache.xml
64AF143E1C4C5866446137A8C42B4609.cache.html
64AF143E1C4C5866446137A8C42B4609.cache.xml
B01955141995DDAD97AFC2941024CE4E.cache.html
B01955141995DDAD97AFC2941024CE4E.cache.xml
Slicr.html
com.ibm.examples.Slicr.nocache.html
gwt.js
history.html
tree_closed.gif
tree_open.gif
tree_white.gif
|
Easy things first: Slicr.html is the HTML page you
coded, copied here directly from your public directory. Anything in the
public directory will be placed here. The three .gif files are, as you might
expect from their names, used by GWT in rendering tree widgets. Because you
have no tree widgets in the Slicr application, you can assume that GWT always
puts these images in your output. Moving on to the rest of the files with
pronounceable names, history.html has some JavaScript code for managing state
and preserving Back button behavior. The gwt.js and nocache.html files
both contain more or less boilerplate code designed to start and load your GWT
application properly.
Which brings you to the files with the hex digit gobbledygook names. There are
six HTML/XML pairs. Open the .html files and
you'll see a lot of highly obfuscated JavaScript code, as shown in Listing 2, chosen at random.
Listing 2. JavaScript code
function ob(pb,qb){z();pb.F = qb;return pb;}
function rb(sb,tb,ub){z();sb.D = ub;sb.F = tb;return sb;}
function vb(){}
_ = vb.prototype = new f();_.jb = C;_.hb = E;_.i = 'java.lang.Throwable';
_.j = 1;_.D = null;_.F = null;function wb(xb){mb(xb);return xb;}
function yb(zb,Ab){ob(zb,Ab);return zb;}
function Bb(Cb,Db,Eb){rb(Cb,Db,Eb);return Cb;}
|
Hope that's clear. That's actually your nice, neat Java code compiled to
JavaScript code by the GWT compiler. There are five HTML/XML pairs, one
for each of the major Web browser rendering engines: Firefox/Gecko (old and
new versions), Windows Internet Explorer, Opera, and Safari. The XML
files manage some data type mapping so that the correct data types for that
engine are used. The obfuscation is there to compress the size of the text
file that has to be sent to the browser. When a user hits the GWT page from
a browser, the JavaScript code in the boilerplate pages automatically
retrieves and loads the correct version of your code for the user's browser.
To deploy your GWT pages, all these files from the www/com.ibm.examples.Slicr
directory must be copied into the Tomcat Home/webapps/slicr directory.
That takes care of the client side, now onto the server side.
Deploy the server side
If you've done servlet development before, then this part of the GWT process should
be familiar. The server-side code you've written is just another servlet
application and is deployed using the Servlet standard.
First, you must compile all your Java code using a plain, ordinary Java compiler. At
this point, you have two options:
- You can place all the .class files in the
Tomcat Home/webapps/WEB-INF/classes directory.
- Alternately, you can combine
all your .class files into a .jar file and place that file in the
Tomcat Home/webapps/WEB-INF/lib directory.
The compiled code should include
the client-side code you've already compiled using GWT -- remember, you use some of
those client classes on the server side to facilitate data transfer.
You must also put any third-party libraries you use in the same /lib directory. This
directory always includes the file gwt-servlet.jar, which is itself included
with the GWT distribution. This file contains all the GWT user files that your
application needs.
Note: The original distribution of GWT did not include this file. However,
you still may see Web deployment instructions that involve hacking the gwt-user.jar
file to remove servlet classes that would interfere with Tomcat. If your GWT
distribution is up-to-date, this step is not necessary.
In this case, you also need the derby.jar file, which is part of the Derby
distribution and which contains the Derby database classes you need. If you want to
transfer the Derby database so as not to lose the toppings data you put into
it, simply place the slicr directory database that Derby created in
Part 2 of this
series. (If you followed the directions in Part 2, this directory should be under
your project top level at the same level with the /src directory.) It doesn't
matter where you put the directory, but the line in the
ToppingServiceImpl class that defines the JDBC URL for Derby must reflect that location:
public static final String PROTOCOL =
"jdbc:derby:[LOCATION OF SLICR DB DIRECTORY]/slicr;";
I placed my Derby database inside the Tomcat webapps/slicr directory, at the same
level as the WEB-INF directory, so my code looks like this:
public static final String PROTOCOL =
"jdbc:derby:/usr/local/apache-tomcat-5.5.20/webapps/slicr/slicr;";
Define your server-side calls in web.xml
After your code is visible to the Tomcat servlet container, you must also
specifically define all the server-side calls from your GWT application in
terms that the Tomcat Web server can understand. Doing so involves defining
these server-side calls as servlets in the Tomcat application's web.xml file.
Essentially, for each servlet defined in your gwt.xml file like this:
<servlet path="/toppings" class="com.ibm.examples.server.ToppingServiceImpl"/>
you must create a <servlet> and a
<servlet-mapping> tag in the web.xml file.
Listing 3 shows the entire web.xml file for your GWT
project, containing both of these tags for your one
ToppngService servlet.
Listing 3. Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<servlet-name>ToppingService</servlet-name>
<servlet-class>
com.ibm.examples.server.ToppingServiceImpl
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ToppingService</servlet-name>
<url-pattern>/toppings</url-pattern>
</servlet-mapping>
</web-app>
|
Within the web.xml file, the two pieces of information given in your gwt.xml
file are split into two different tags, as part of the Java make-everything-as-verbose-as-possible initiative. The <servlet>
tag takes the fully qualified class name for the servlet, and the
<servlet-mapping> tag takes the URL path name
as you defined it in the GWT file. The two are unified through the common
servlet-name attribute, which can be anything you
like as long as you're consistent. However, it's probably best to use a simple
naming convention, such as the GWT name of the actual service.
Creation of this file is, of course, eminently automatable by any number of
methods ranging from pure text manipulation to XML Document Object Model (DOM)
manipulation. When you've written this file, place it inside your Tomcat
WEB-INF directory. At this point, the Slicr deployment is complete, and you can
test the application by starting Tomcat and typing in the URL, which will be
something like http://localhost:8080/slicr/Slicr.html. If successful, you'll see
the Slicr page just as it was at the end of
Part 3 of this
series.
Troubleshooting deployment problems
| Problem | Cause |
|---|
| You don't see anything at all when you type in the URL. | Most likely the cause
is that the Slicr.html page is not in the right place. If you just get Welcome
to Slicr but none of the GWT widgets, you most likely didn't properly place
the GWT JavaScript files. |
|---|
| You see the left side of the page but nothing on the
toppings pane except the headers. | This means that the server call failed. You'll
have to go to the Tomcat logs to diagnose this problem properly (or
alternately, change the OnFailure() method in the
callback to print an error message to the pane). The first possibility is that
you don't have your Slicr Java class files in place, which is preventing the
servlet from even loading. (This might also happen if the web.xml file isn't
set up properly.) |
|---|
| You encounter a Derby failure. | Make sure that the JDBC URL matches the
location of the Derby data directory. |
|---|
Now that I've described this entire process, you can see that although there are
many steps, none of them is particularly complex. I strongly recommend automating
your deployment as much as possible by using scripts, Ant tasks, or any other
means that work for your project. You'll see one example in
Resources, and the various Java IDEs are increasingly
adding GWT support, including deployment. Having a one-button deployment saves
you a lot of headaches.
More to explore
Over the course of this article series on GWT, you've built a simple Web application
that demonstrates how you can use GWT with a database back end to create a robust
Web application with rich client behavior. Even after four articles, you've only
scratched the surface of what GWT has to offer. Powerful features -- such as JUnit
test integration, using other Web services through JavaScript Serialized Object
Notation (JSON) data exchange, and the new GWT internationalization features -- are
well worth your time to check out. GWT development continues to grow, and new
features and add-on tools are being added all the time. I hope that you'll be able
to take a look around and find the tools you need to build the application you
want.
Resources Learn
Get products and technologies
Discuss
About the author  | |  | Noel Rappin, a Ph.D. from the Graphics, Visualization, and Usability Center at the Georgia Institute of Technology, is a senior software engineer at Motorola. He is also the coauthor of wxPython in Action and Jython Essentials. You can check out Noel's blog at 10printhello.blogspot.com. |
Rate this page
|  |