GWT makes building a rich Ajax browser client interface even easier than building traditional Java GUI interfaces. As fabulous as GWT is, however, it can't create an entire Web application by itself. You must still have a data store on the server and some kind of framework for converting that data into Java objects that GWT can pass from the server to its client. In this series of articles, you'll use Apache Derby, a 100% pure Java database that you can embed in the same Java Virtual Machine (JVM) as the rest of your server-side code.
The first article in this series focuses on GWT. Here you'll learn how to set up GWT and create a simple client interface that responds to user actions. Future articles will show you how to set up the Derby database and connect the GWT front end to the Derby-based back end. Finally, you'll learn how to deploy your system outside of your development environment.
With GWT, you can develop Ajax applications in the Java programming language. The hallmark of an Ajax application is a rich, interactive environment more often associated with traditional UI applications. Figure 1 shows a sample GWT interface that mimics a desktop e-mail application. This demo is visible at the GWT Web site.
Figure 1. A GWT e-mail demonstration
GWT's most unique feature is that you can create your Ajax application and still write your code in the Java language. You can use your favorite Java integrated development environment (IDE) and, even better, you can debug your client in that Java IDE. You can communicate between the client and server using Java objects, and it's all much lighter weight in the client than a Java applet would be.
At base, GWT is a compiler. It converts the Java code you write into JavaScript code that is then inserted into the HTML page and used to run the client side of your application. This functionality frees you from the details of supporting JavaScript code on multiple browsers, allowing you to focus on the interface and interaction of your program.
Of course, if the compiler were the only thing GWT had to offer, that wouldn't be very exciting. Luckily, there's more. With GWT, the compiler is just a mechanism for delivering an entire client/server application architecture. The features include:
- A set of standard UI widgets that look good, are flexible, and are already tuned to work in all the major browsers (including Safari and Opera).
- An event mechanism for catching and responding to events completely on the client side.
- A framework for managing the asynchronous calls between your Web application and the server.
- A mechanism for creating stateful browser history so that your Ajax application doesn't mess with expected Back button behavior.
- A test framework for using JUnit to write unit tests for your client application.
This series will examine many of these features. But let's start with downloading and installing GWT.
As of this writing, the current version of GWT is version 1.2. (See Resources at the end of this article for links to the download site.) GWT is fully supported under Microsoft® Windows® XP, Windows 2000, Linux® systems that run GTK+ 2.2.1 or later, and Mac OS X.
Your download is a compressed file. Extract it, and then place the resulting directory somewhere convenient. The details of the distribution vary slightly among the versions, but the basic elements are:
- Three .jar files: The one that contains the user classes that you'll need in
your project
classpathis called gwt-user.jar, while the one that contains the bulk of the compiler code is called either gwt-dev-windows.jar or gwt-dev-linux.jar. The third file, gwt-servlet.jar, is used in deployment. - Three command-line utilities:
applicationCreator,junitCreator, andprojectCreator. (On Windows, they have a .cmd suffix.) More about these in a moment. - A directory of sample code.
As you use GWT, some other files are placed in the GWT home directory to manage your temporary files.
Now that everything is downloaded, your first order of business is to create a project. You're going to be building an online site for a hot new Web 2.0 business called Slicr, which sells pizza online. The exact details of how to set up your GWT project differ depending on whether you plan to use an IDE. For your purposes, you'll be using Eclipse because it's free and also directly supported by the GWT command-line utilities.
Start by using those command-line utilities to create your Eclipse project:
- Create a new directory called slicr in any convenient place on your hard drive.
- Open a command prompt in the new slicr directory.
- Type the following command (you'll need to convert the slashes and whatnot to conform to your operating system choice):
<GWT_HOME>/projectCreator -eclipse slicr
This command creates the minimum needed for a GWT project. The result is a new src subdirectory and new .project and .classpath files.
You can start with just the project as it stands right now, but GWT expects some further structure, which you can set up with the following command:
<GWT_HOME>/applicationCreator -eclipse slicr com.ibm.examples.client.Slicr
The -eclipse slicr argument is the name of the
Eclipse project and must be the same as what you used in
projectCreator. (If it's not, you'll have trouble
launching your GWT application from inside Eclipse.) The final argument is the
fully qualified class name of what will be your application's main class. You
want the lowest-level package to be named client,
but beyond that, you're on your own.
This command sets up a few files. The .java file is your main class (and all the parent directories it must create). You get a public directory at the same level as the client directory, and this directory contains a file called Slicr.html. The directory above contains an important file called Slicr.gwt.xml. GWT also creates a Slicr.launch file that Eclipse uses as well as a couple of shell scripts.
Almost there. Now, you must get the project into Eclipse.
- Open Eclipse, and then click File > Import.
- In the window that appears, expand the General tree, and then select Existing Projects into Workspace.
- Click Next, and then click Browse to select the Slicr root directory.
- Select the project, and make sure that the Copy projects into workspace option is not set; you don't want to move the project.
This process places your code into Eclipse, where you can take a good look at
it. GWT has created three important files. The first is in the
com.ibm.examples package and is called slicr.gwt.xml.
This is your XML configuration file. Right now, it
looks like Listing 1.
Listing 1. slicr.gwt.xml
<module>
<inherits name='com.google.gwt.user.User'/>
<entry-point class='com.ibm.examples.client.Slicr'/>
</module>
|
In this XML document, you can define the modules for your GWT application. The module is the basic unit of your GWT code and is referenced by the HTML pages that your client uses.
The second file of interest is the Slicr.html file created in the public directory. This is the .html file that is actually sent to the client as the front page of your Web application. The default contains a lot of comments that you really don't need. The guts of the file are shown in Listing 2.
Listing 2. Slicr.html
<html>
<head>
<title>Wrapper HTML for Slicr</title>
<meta name='gwt:module'
content='com.ibm.examples.Slicr'>
</head>
<body>
<script language="javascript"
src="gwt.js"></script>
<iframe id="__gwt_historyFrame"
style="width:0;height:0;border:0"></iframe>
<h1>Slicr</h1>
<p>
This is an example of a host page for
the Slicr application.
</p>
<table align=center>
<tr>
<td id="slot1"></td>
<td id="slot2"></td>
</tr>
</table>
</body>
</html>
|
The most important thing to realize about this is that at the end of the day, it's an ordinary .html file. Include any arbitrary HTML you want. There are four elements in this .html file that identify it as a file used by GWT. They are:
- The
metatag: Thenameattribute must be as shown, and thecontentattribute is the fully qualified logical name of your module. (It's the package containing the XML module file and then the file name of the XML without the extensions.) This tag associates your HTML page with a specific module. Invoking the page starts the module. (Specifically, all the entry point classes in that module are initialized.) - The
scripttag: This tag loads a file called gwt.js, which is one of the files created when you convert your GWT Java code to JavaScript code. Because this file controls the loading of all your client code, including it is rather important to the running of your program. - The
iframetag: Including this tag exactly -- precisely as written -- allows your Web application to remember history and state, meaning that your GWT application will not disable a user's Back button. - The
tdtags: These tags in this particular .html file contain JavaScript identifiers. There's nothing particularly unusual about that, but as you'll see in a moment, GWT uses those identifiers as a place to put elements.
The boilerplate Java startup class
GWT also creates a boilerplate Java startup class for you, as shown in Listing 3.
Listing 3. Boilerplate Java startup class
public class Slicr implements EntryPoint {
public void onModuleLoad() {
final Button button = new Button("Click me");
final Label label = new Label();
button.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
if (label.getText().equals(""))
label.setText("Hello World!");
else
label.setText("");
}
});
RootPanel.get("slot1").add(button);
RootPanel.get("slot2").add(label);
}
}
|
Just a couple of things to note about this class right now. The Java class is
in your client package, meaning that it's intended
to be compiled by GWT into JavaScript code. This places certain limitations on
what can be in this file, but for the most part, it's just basic Java 1.4 code.
The class that is created implements the interface EntryPoint,
which only defines the one method, onModuleLoad().
GWT automatically invokes this method when an HTML page referencing this module
is loaded.
This particular EntryPoint is simple. It
defines a button and a label in the first two lines. In the last two lines,
it associates these widgets with specific elements of the HTML page by using
the RootPanel.get() method. The argument to this
method is the JavaScript ID of the element as defined in the HTML page.
Between those lines, you define an event listener using an idiom similar to what
you would use to bind an event in Swing. In this case, the
ClickListener is called when your button is clicked
and simply toggles the text in the label widget back and forth.
Now you can try to run the sample program that GWT has created. There are two different ways to run a GWT program: Web mode and hosted mode. Web mode is the full deployment mode; it's what you would use after you compile your GWT program to JavaScript code.
You use hosted mode during development; it's an emulator with which you can simulate both client and server code at once, dramatically simplifying deployment while you are developing. (Hosted mode doesn't currently work in Mac OS X.) If you're using an IDE with a debugger, you can run your GWT program in hosted mode under the debugger, which allows you to set breakpoints and variable watches even on the client part of your code that is going to be compiled into JavaScript code. This is, of course, very cool and really useful. As you work in GWT, you'll be spending a lot of time in hosted mode.
You can invoke hosted mode in any of several ways. The
applicationCreator script that you ran earlier created a
Slicr-shell script that you can invoke from the command
line to start hosted mode. Earlier in the article, you saw how to import your GWT
project into Eclipse. From your Eclipse project, you can choose either Debug
or Run from the Run menu or the toolbar. In the window that appears,
click Java Application to see the Slicr option. This option is made
possible by a Slicr.launch file that GWT created and that you imported into Eclipse with
the rest of the project. The launch file describes the classpath
and start class for Eclipse. Of course, after you run the launcher once, it will be
the default when you click the toolbar button. Figure 2 shows
what that window looks like in practice.
Figure 2. Invoking hosted mode
When you run in hosted mode, two windows come up. (Note that it takes a minute or so for the hosted mode setup to initialize, especially when run for the first time.) The first window, shown in Figure 3, is named Google Web Toolkit Development Shell / Port 8888. This window contains error and log messages from GWT. Using the toolbar, you can open a new hosted browser as well as expand, contract, and clear your on-screen log.
Figure 3. Hosted mode shell window
The second window, shown in Figure 4 is the simulated browser.
As you can see, it contains the static HTML from your slicr.html page as well as
the button widget created in your Slicr.java EntryPoint
class. Clicking the button toggles the label. If you've done something wrong in
the setup steps, you won't see this window; instead, you'll get an error message in
the shell. Verify that all your names are correct. (In particular, look in the
.launch file, and verify that it specifies the correct project directory.)
Figure 4. Hosted mode simulated browser
For this article, you focus on getting widgets on the screen and a bit of interactivity. You'll end up with the screen shown in Figure 5, which can charitably be described as plain but functional.
Figure 5. Slicr
To have these widgets created when the page is loaded, you must put the code in the
onModuleLoad() method of your EntryPoint
class. Listing 4 defines a couple of instance data members and
a top-level method that calls helpers to build each panel. For this listing to work, you need to have an element in your HTML page with an ID of slicr. This allows the RootPanel.get() command in this listing to find an element in the page. The easiest way to accomplish this is to replace the table in the previous HTML listing with >div id="slicr" /<.
Listing 4. Module load event handler
private DockPanel panel;
private List clearables;
public void onModuleLoad() {
clearables = new ArrayList();
initDockPanel();
panel.add(buildActionPanel(), DockPanel.SOUTH);
panel.add(buildPizzaTypePanel(), DockPanel.WEST);
panel.add(buildToppingPanel(), DockPanel.EAST);
RootPanel.get("slicr").add(panel);
}
|
You put everything inside a DockPanel, which is the
GWT equivalent of a Swing panel that uses BorderLayout.
Where Swing has one Panel class and multiple layout
managers, GWT has multiple panel subclasses, each
with its own algorithm for laying out child widgets. Other panel classes include
SimplePanel, HTMLTable,
FlowPanel, and StackPanel.
Creating the dock panel isn't difficult: The setters do what you expect, as
Listing 5 shows.
Listing 5. Initializing the main panel
private void initDockPanel() {
panel = new DockPanel();
panel.setBorderWidth(1);
panel.setSpacing(5);
}
|
Create the SOUTH (button) panel
You define the SOUTH (button) panel first, because a DockPanel
is first come, first served when it comes to claiming corner space. This way,
the south widget runs across the entire panel. You build up the action panel as
a HorizontalPanel, roughly the equivalent of a Swing
box, as shown in Listing 6.
Listing 6. The SOUTH (button) panel
public HorizontalPanel buildActionPanel() {
HorizontalPanel actions = new HorizontalPanel();
actions.setSpacing(10);
Button clear = new Button("Clear");
clear.addClickListener(new ClearClickListener());
Button newPizza = new Button("Another Pizza");
Button submitOrder = new Button("Submit");
actions.add(clear);
actions.add(newPizza);
actions.add(submitOrder);
return actions;
}
|
You use the GWT Button widget to create three buttons,
and then you add them to the panel. You also create a ClickListener
for the Clear button, which you'll define later. GWT splits its event
listeners differently from Swing: The ClickListener
listens for mouse clicks and only for mouse clicks. (Often, you'd see the
listener defined as an inline anonymous class. I find that style difficult to
read and test, so I created a named inner class.)
Create the WEST (pizza type) panel
The panel with the pizza types isn't complicated. You use the GWT
RadioButton widget, as shown in
Listing 7.
Listing 7. The WEST (pizza type) panel
public static final String[] PIZZA_TYPES = new String[] {
"Thin Crust Medium", "Thin Crust Large",
"Thin Crust X-Large", "Thick Crust Medium",
"Thick Crust Large"
};
private VerticalPanel buildPizzaTypePanel() {
VerticalPanel pizzaTypes = new VerticalPanel();
HTML label = new HTML("<h2>Pizza</h2>");
pizzaTypes.add(label);
for (int i = 0; i < PIZZA_TYPES.length; i++) {
RadioButton radio = new RadioButton("pizzaGroup",
PIZZA_TYPES[i]);
clearables.add(radio);
pizzaTypes.add(radio);
}
return pizzaTypes;
}
|
You'll do something smarter with the data later on. This time, you're using a
VerticalPanel, which is the vertical equivalent of
HorizontalPanel. You're also using the
HTML widget, which is simply a label that renders
HTML. (Essentially, it's a wrapper around an HTML <span>
tag.) The RadioButton constructor takes two
arguments. The first is a string label for the radio button group, and
the second is a text label. You add each button both to the panel and to the
instance list of clearable items, which you'll use in one of the listeners.
Create the EAST (toppings) panel
The topping panel is a bit more complicated. You want to allow users to create a pizza with different toppings on each half. Clicking the button for a topping checks both halves, but each half can be checked or cleared independently. You want everything to line up, so you use a grid, as shown in Listing 8.
Listing 8. The toppings grid
public static final String[] TOPPINGS = new String[] {
"Anchovy", "Gardineria", "Garlic",
"Green Pepper", "Mushrooms", "Olives",
"Onions", "Pepperoni", "Pineapple",
"Sausage", "Spinach"
};
private VerticalPanel buildToppingPanel() {
VerticalPanel toppings = new VerticalPanel();
toppings.add(new HTML("<h2>Toppings</h2>"));
Grid topGrid = new Grid(TOPPINGS.length + 1, 3);
topGrid.setText(0, 0, "Topping");
topGrid.setText(0, 1, "Left");
topGrid.setText(0, 2, "Right");
for (int i = 0; i < TOPPINGS.length; i++) {
Button button = new Button(TOPPINGS[i]);
CheckBox leftCheckBox = new CheckBox();
CheckBox rightCheckBox = new CheckBox();
clearables.add(leftCheckBox);
clearables.add(rightCheckBox);
button.addClickListener(new ToppingButtonListener(
leftCheckBox, rightCheckBox));
topGrid.setWidget(i + 1, 0, button);
topGrid.setWidget(i + 1, 1, leftCheckBox);
topGrid.setWidget(i + 1, 2, rightCheckBox);
}
toppings.add(topGrid);
return toppings;
}
|
Once again, you use a VerticalPanel and the
HTML widget. You're putting everything in a GWT
Grid, so you must set the size of the grid when you
create it. Each cell in the grid can contain either plain text or another GWT
widget. For each row, create the button and two check boxes, and then assign
them to their cells. Add a listener for the button, and then put the check
boxes in the clearable list.
With the widgets set up, it's time to look at your two defined listeners. The
simpler of the two is for the Clear button. This button simply walks
through the clearable list and clears everything, as
shown in Listing 9.
Listing 9. Defined listener for the Clear button
private class ClearClickListener implements ClickListener {
public void onClick(Widget sender) {
for (Iterator iter = clearables.iterator(); iter.hasNext();) {
CheckBox cb = (CheckBox) iter.next();
cb.setChecked(false);
}
}
}
|
Note: In GWT, RadioButton is actually a
subclass of CheckBox. So the above code does not
trigger a class cast exception.
The listener for the topping buttons is only a bit more complicated. If neither of the associated check boxes is selected, this listener selects both check boxes. Otherwise, it clears them both, as shown in Listing 10.
Listing 10. Defined listener for the buttons
private class ToppingButtonListener implements ClickListener {
private CheckBox cb1;
private CheckBox cb2;
public ToppingButtonListener(CheckBox cb1, CheckBox cb2) {
this.cb1 = cb1;
this.cb2 = cb2;
}
public void onClick(Widget sender) {
boolean unchecked = !cb1.isChecked() && !cb2.isChecked();
cb1.setChecked(unchecked);
cb2.setChecked(unchecked);
}
}
|
You've used all the code necessary to create this simple version of the Slicr client. The next article will show you how to build a data layer on the server side using the Derby database and convert the data from its database form into Java objects that can be sent to your GWT client. Then you'll meet the remote procedure architecture that connects the server and the client.
When your server side must run separately, you'll have to worry about how to deploy it, both for development and for your production environment. You'll also learn some ways to make the interface a little more aesthetically pleasing. In the meantime, head over to the GWT download site and try it out for yourself.
Learn
-
Visit the Google Groups
forum for GWT.
-
Check out the official GWT blog.
- Get Apache Derby resources at the Derby site.
- Check out the developerWorks Apache Derby project area for articles, tutorials, and other resources to help you get started with Derby today.
- Learn more about the IBM® Cloudscape™ database, which is built using the Apache Derby code base.
- Visit the developerWorks Eclipse project area
for all your Eclipse development needs.
-
Stay current with
developerWorks
technical events and Webcasts.
- Learn more about the Eclipse Foundation and its many projects.
- Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
- Browse all the Apache articles and free Apache tutorials available in the developerWorks Open source zone.
- Browse for books on these and other technical topics at the Safari bookstore.
- Get an RSS feed for this series. (Find out more about RSS.)
Get products and technologies
- Download Apache Derby.
-
Download the Google Web Toolkit.
- Innovate your next open source development project with IBM trial software, available for download or on DVD.
Discuss
- Get involved in the developerWorks community by participating in developerWorks blogs.
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.




