GWT


introduction | gwt webapp basics | gwt webapp features | practicalities

Last updated: September 2008

GWT (Google Web Toolkit) is different than the previous frameworks examined, because it is geared towards allowing high interactivity on the client -- which it does by translating Java into JavaScript, including Ajax calls. The possibility of creating RIAs (Rich Internet Applications) has fueled explosive growth in GWT during 2008.




introduction

For the GWT version of WebOfContacts these technologies were used:
  • Java 6 (a.k.a. 1.6)
  • GWT 1.5
  • Spring Framework 2.5.5
  • Hibernate 3.2
  • Tomcat 6.0.14
  • MySQL 5.0.45
  • JUnit 4
  • Eclipse 3.4
If you want to download the .war and run this application on your own machine, then you can as the GWT and Hibernate jars are included in the webapp. However you will already need to have a version of Java at 5 or greater, a recent version of Tomcat, and set up the database contactsdb. Then download the WAR (make sure to retain the .war extension) from this site into your Tomcat's webapps directory, and view the application in your browser at http://localhost:8888/com.oranda.webofcontacts.gwt.WebOfContactsMain/WebOfContactsMain.html (log in as admin/admin). The full source is available for download as an Eclipse project.



gwt webapp basics

First, note that if you are using the Eclipse platform, it is convenient to use the GWT plugin, which is called Cypal Studio. Follow the documentation to create GWT modules and run configurations. Cypal allows you to run your application in an embedded Tomcat server.

When you do run your application, you will get the Google Web Toolkit Development Shell (below) and a toy browser where you can test and debug applications until you click on "Compile/Browse" to see the results.



The structure of a GWT application is unlike the structure of webapps under most frameworks. For instance, in a GWT application you will generally divide the core code into client and server packages. The client package contains code that can be translated by GWT into JavaScript. This includes most but not all of the Java standard libraries. The server package contains the services that the client can call asynchronously -- it can of course can use anything in Java. (By the way, the JavaScript that is created for the client is actually generated in multiple versions, and then at runtime only one version is chosen for a particular client - this is called deferred binding).

For a GWT application you need to define at least one module. A module is defined in an XML file and defines the entry point of the webapp among other things. For example the core of WebOfContactsMain.gwt.xml looks like this:

<module>
    ...  
	<entry-point class="com.oranda.webofcontacts.gwt.client.WebOfContactsMain"/>
    ...       
    <servlet class="com.oranda.webofcontacts.gwt.server.ContactServiceImpl" path="/contactService"/>
    <servlet class="com.oranda.webofcontacts.gwt.server.UserServiceImpl" path="/userService"/>
    <servlet class="com.oranda.webofcontacts.gwt.server.UploadFileServlet" path="/uploadFileServlet"/>

</module>

Notice that the services used by the client are included. These are implemented as regular servlets and not web services. The module can also inherit settings from other modules (especially GWT's own User module) and specify the path of needed source.

In addition to the module file, there is a WebOfContactsMain.html file. There is generally no template HTML and no tag libraries involved here. The file just includes CSS styles and, crucially, a reference to the generated JavaScript for the module like this:

<script type="text/javascript" language="javascript" src="com.oranda.webofcontacts.gwt.WebOfContactsMain.nocache.js">

The WebOfContactsGwt application is structured so that the entry point (WebOfContactsMain.java) delegates most functionality to a ScreenManager singleton. The screen manager constructs the UI, maintains the list of screens, and manages authentication and authorization. (A more complex UI could be separated into MVC parts.)

To give you an idea of what UI code looks like in GWT, here is a snippet which constructs the general layout in a DockPanel containing a header, footer, and navigation bar.

DockPanel uiContainer = new DockPanel();
uiContainer.setStyleName("page");
		
uiContainer.add(this.headerArea, DockPanel.NORTH);
headerArea.setStyleName("header");
uiContainer.setCellHeight(this.headerArea, "80px");
uiContainer.setCellWidth(this.headerArea, "100%");

uiContainer.add(this.footerArea, DockPanel.SOUTH);
footerArea.setStyleName("footer");

uiContainer.add(this.navArea, DockPanel.WEST);
navArea.setStyleName("leftnav");

The actual screens are then dynamically loaded into the DockPanel.CENTER space, which is basically all the space that is left over. Notice the call to setStyleName: this ties each component in with the CSS code. Size and offsets are specified by a mix of CSS information and Java setter calls. (This duplication of function is perhaps a weakness of GWT. If you don't like CSS, you can try the GWT designer Eclipse plugin with a point and click interface for layouts.)

Each Screen object is responsible for making calls to the server. These calls are remote procedure calls, so the acronym RPC gets used a lot in GWT. They are also asynchronous calls. In other frameworks, calls to the service layer are synchronous and relatively straightforward. In GWT the client makes a call over the network to the server and waits for a response. As a result there is a lot of boilerplate code in making a service call. It looks like this:

this.service = GWT.create(ContactService.class);
ServiceDefTarget endpoint = (ServiceDefTarget) service;
endpoint.setServiceEntryPoint("contactService");
		  
// define a handler for what to do when the
// service returns a result
this.callback = new AsyncCallback() {
    public void onSuccess (E res) {
		...
	}

	public void onFailure (Throwable ex) {
		...
	}
};

try {
    // Here is the actual service call!
	((ContactServiceAsync) service).createContact(contact, callback);
} catch (Exception e) {
	...
}

ContactServiceAsync is an interface which duplicates the declarations in the standard ContactService but adds on a callback parameter to each method. This is simply what the GWT compiler needs and expects. On the server there is an implementation: ContactServiceImpl.

In WebOfContacts the code actually looks a bit different to what there is above. This is because I have abstracted out the boilerplate code into a class called UIAction which specific service calls subclass -- the Command Pattern. Admittedly it is still rather verbose (and reminiscent of Struts 1) to have a new action class on the client for every service call you want to make, but asynchrony in GWT comes at a price.

In the layout code above there was a reference to the DockPanel widget. GWT provides many other types of panel, and in fact a full set of widgets including form controls. In a typical form you might have a Grid with TextBox objects in the cells and a submit Button at the end. The Grid is added to a FormPanel and a FormHandler is attached to the FormPanel. The FormHandler has an onSubmit method, in which a call to the service layer is made via the usual action class.




gwt webapp features

There is no widely-used plugin for form validation: you just implement it yourself. In fact you don't really need anything special to translate your validation code into JavaScript as with other frameworks, because your client-side code is already being translated into JavaScript. In other words you can use the same Java code on the server side and client side. However, you cannot easily use java.util.regex because GWT only supports a subset of Java on the client side. See ContactValidator for an example of how validation is done in WebOfContacts.

File upload is a bit trickier than you would think. Although GWT includes a FileUpload widget in the the toolkit, you cannot just submit the file with the rest of the form. The Ajax XMLHttpRequest used by GWT can't deal with it. Instead you need to write an independent servlet to receive the file, and make a HTTP POST to it in a multipart request. You can set up the form like this:

		final FormPanel form = new FormPanel();
		form.setEncoding(FormPanel.ENCODING_MULTIPART);
		form.setMethod(FormPanel.METHOD_POST);
		form.setAction(GWT.getModuleBaseURL() + "uploadFileServlet"); 
        ...
		this.fuPhoto = new FileUpload();
		this.fuPhoto.setName("uploadFormElement");

You can still attach a form handler to the form to deal with the rest of the submitted data in the normal way. Meanwhile the upload servlet will find the file from the request using the GWT API like this:

		FileItemFactory factory = new DiskFileItemFactory();
		ServletFileUpload upload = new ServletFileUpload(factory);
		List items = upload.parseRequest(request);

		Iterator it = items.iterator();
		while (it.hasNext()) {
			FileItem item = (FileItem) it.next();
			if (!item.isFormField()
					&& "uploadFormElement".equals(item.getFieldName())) {

				InputStream in = item.getInputStream(); // got it!
                ...
			}
        }

As for authentication, again there is no single standard way. You can used form-based authentication, Acegi, a GWT plugin... WebOfContacts implements it in the ScreenManager. Before showing any page, AuthenticateAndShowAction.execute() is called. This makes a call to the service layer, UserService.authenticate() which looks for the User in the HttpSession. The User object of course is put in session by the UserService.login() method after credentials are successfully checked against the database. (The login screen is just a standard GWT form.)

A number of useful third-party libraries have been created to extend the power of GWT. A popular one is Ext GWT, which provides a number of desktop-like components for RIAs. Another library is gwt-dnd, useful for drag-and-drop. In fact the GWT version of WebOfContacts takes advantage of gwt-dnt to provide a special feature: the ability to drag contacts around in the List Contacts page, and have their priorities change automatically.



The code for drag-and-drop is a bit involved, but the basic idea is that you need both a drag controller on the panel you want to drag from and a drop controller on the area you want to drop on. In WebOfContacts the ScreenListContacts class creates a panel, then runs the following code to create the drag-and-drop infrastructure:

// Create the drag controller on the panel
FlexTableRowDragController tableRowDragController = new FlexTableRowDragController(panel);
	
// Write out the contacts
ContactFlexTable contactTable = new ContactFlexTable(contacts,  tableRowDragController);
panel.add(contactTable);

// Create the drop controller on the flex table
ContactRowDropController contactRowDropController = new ContactRowDropController(contactTable);
tableRowDragController.registerDropController(contactRowDropController);

Notice the creation of ContactFlexTable in the middle of this code. This is a custom WebOfContacts class which writes out the list of contacts in a GWT FlexTable widget and makes each contact draggable. This version of gwt-dnd (2.5.6) limits what you can make draggable so instead of making the whole row draggable, there is a handle on the left-hand side to do it. In ContactFlexTable the code to make this draggable is simply:

tableRowDragController.makeDraggable(handleHtml);

The final part of the drag-and-drop functionality is changing the priority of a contact whose position is changed. The ContactRowDropController does this in the onDrop callback. See the abbreviated code below:

	class ContactRowDropController extends FlexTableRowDropController {		
		...
		public void onDrop(DragContext context) {
			...			
			this.contactTable.changePriority(dragRow, targetRow);
		}
	}




practicalities

Because of the asynchronous nature of calls in GWT, there is special support for testing. Basicallly your JUnit test has to extend GWTTestCase and define a widgetSetup() method independently of the normal JUnit setUp(). widgetSetup() loads the module, and needs to be called explicity by every test method.

public class WebOfContactsMainTest extends GWTTestCase {

	private void widgetSetup() {
		// Build the web GUI.
        WebOfContactsMain webOfContactsMain = new WebOfContactsMain();
        webOfContactsMain.onModuleLoad();
    }
    ...
}

To support asynchronous calls, the key testing concept is the Timer: it waits for your call to complete. For instance:

// Perform the call to be tested
screenLogin.getForm().submit();

Timer timer = new Timer() {
public void run() {
    // on login the curScreen should be set to Home
	boolean atHome = ScreenManager.getInstance().isCurrentScreen(
	    ScreenHome.LINK_NAME);
	assertTrue(atHome);
	finishTest();
}
};
timer.schedule(3000);
delayTestFinish(5000);

So, what is the final verdict on GWT? I cannot give a final verdict because it feels like it is still very much in development. In fact it was only in 2008 that GWT started supporting Java 5. It is noteworthy that GWT still only supports a subset of the Java API on the client-side and this occasionally necessitates workarounds. For instance, you can't use log4j or java.util.logging on the client-side; you need to use the simple GWT.log() or a special GWT library.

GWT has a very attractive premise: you can make your web applications interactive without having to know JavaScript. You can code it in Java and debug it in Java using a tool like Eclipse. You don't have to worry about all the browser bugs and incompatibilities because GWT abstracts that away for you... That is, assuming that GWT is itself bug-free and does not require you to go debugging the thousands of lines of generated JavaScript code with a tool like Firebug. I did not have to do that with a simple application like WebOfContacts. However it seems GWT has not really been put to the test with a really large website, and you have to wonder how well it would scale. GWT is based around a single actual web page and it does not integrate well with other frameworks, so at the current time many consider it primarily good for single-function 100% AJAX web sites.

Another issue is connecting GWT applications to traditional databases. Most people will use an ORM like Hibernate, and want to be able to access domain objects on the client-side. However, it turns out that the proxying/lazy loading approach taken by Hibernate tends to confuse the Java->JavaScript compilation process. In order to avoid compiler errors you need to use the plug-in hibernate4gwt, ensuring all your services extend from HibernateRemoteService, and that you load the HibernateBeanManager. (This is the approach taken by WebOfContacts, and it works. The services rely on custom DAO classes injected by Spring. The DAOs use Spring's HibernateTemplate in the normal way.)

Google has taken on a significant challenge here, and it should not be surprising that GWT still feels a bit awkward, even as it tries to turn the Web into a rich client platform. As Google architect Josh Bloch remarked, "It's not that the dog talks beautifully, it's that the dog talks!" There is a good chance that either GWT or another framework with the same idea will become a standard choice for web development. In the meantime here is the documentation.