At least on Windows, GWTShellServlet has always had the rather nasty side effect of locking up public resources it serves. This translates into a user experience of sometimes having to kill hosted mode in order to save over a public resource, which is particularly annoying given that it's much faster to refresh hosted mode than to restart it.
After digging into this a while, I finally found the culprit, and it's URL.openConnection() . When using this method on a local file, you get back a Sun private FileURLConnection implementation subclass of URLConnection . Using the Java debugger, I was able to see that on return, a FileURLConnection contains an active FileInputStream ; the purpose of the internal stream is to be the return value of the URLConnection.getInputStream() . I suppose it's probably more efficient somehow for them to go ahead and create the stream up front, but if you don't end up using its internal stream, the stream doesn't get closed until the object is garbage collected, which potentially might not happen for a long time. And on Windows, at least, this locks up the target file.
In our case, we had wastefuly been doing a separate URL.openStream() to get a readable stream on the URL, so our fix was to simply use the stream already available in the URLConnection and then close it when done.
However, I've noticed a number of misunderstandings about GWT in this and other articles, and I feel some clarification is in order.
Why Java?
First and foremost, let me clarify yet again the reasons behind the decision to use Java as a source language. Allow me to quote from the "Making GWT Better" document:
Why does GWT support the Java programming language instead of language X? In a word, tools. There are lots of good Java tools. That's the entire explanation. It isn't that we don't like language X or that we think the Java programming language is somehow superior. We just like the tools.
This point has perhaps been beaten to death, but there are a lot of good tools for Java, whether you love the language itself or not. Code completion, automated refactoring, static error detection, code coverage, testing, and so forth, are pretty hard to give up once you're used to them.
But wait, there's more. Let's talk about compiler optimizations a bit. I'll quote Ray Cromwell, from the comments on Resig's article:
... Aggressive compiler optimizations, that happen before code is sent down the wire. This is a problem that no amount of trace-jitting will solve. Far from being bloated, as I demonstrated in my GWT Query presentation at Google I/O, GWT can produce code an order of magnitude smaller than most selector libraries in specific circumstances. GWT can prune dead code far better than any JS optimizer, and can obfuscate code to reduce size in a way that helps maximum GZIP/DEFLATE algorithms.
What Ray's referring to here is the fact that a statically-typed language like Java allows you to perform absolutely correct optimizations far in excess of what is achievable without type information (There's a lot more to say on this topic, which I'll save for a future post).
Why is this so important for JavaScript output? In a word (or two), code size. Code that grows without bound is a serious problem for Javascript applications, and static analysis gives us a lot of leverage over the problem. The GWT compiler can determine precisely which classes, methods, and fields are actually used and aggressively prune everything else. And this pruning feeds back into the iterative compilation process, allowing still more optimizations (e.g., type-tightening, devirtualization, and so forth) to be performed.
Indeed, you can take this even further, with a concept we refer to as runAsync(). With static whole-program analysis, it is possible to automatically break a program into optimal fragments at user-defined cut points. This is still experimental, but the preliminary results look pretty good.
To put all this in concrete terms, check out this great example on Ray's blog showing the following transformation:
public class MyArray implements Iterable { private String[] items = {"foo", "bar", "baz"};
public Iterator iterator() { return new StringArrayIterator(items); }
private class StringArrayIterator implements Iterator { private String[] items; private int index;
public boolean hasNext() { return index < items.length; } public String next() { return items[index++]; }
public void remove() { throw new UnsupportedOperaionException(); } } }
void iterate() { MyArray m = new MyArray(); for (String s : m) { Window.alert(s); } }
iterate() becomes
function $iterate(m){ var s, s$iterator; for (s$iterator = $MyArray$StringArrayIterator( new MyArray$StringArrayIterator(), m.items); s$iterator.index < s =" s$iterator.items[s$iterator.index++];">
which becomes something like
function x(a){var b,c;for(c=y(new z(),a.a);c.b
The point of going into all this detail about tools and optimization is that choosing Java as a source language gives GWT leverage that would have been provably impossible in JavaScript. It's most emphatically not about loving or hating any given language, or providing Java programmers with a way to avoid JavaScript -- it's a pragmatic decision based upon specific, measurable benefits.
I've seen lots of assertions that various languages are either "higher level" or "lower level" than others, without any clear definition of what metric is being used to justify these statements. For example, "JavaScript is the assembly language of the web" or "Java is a low-level language because it doesn't have closures and dynamic typing". These sorts of arguments are pointless at best, and at times simply disingenuous. What matters is not some ill-defined notion of a language's "level of abstraction", but rather what you can actually achieve with it.
JavaScript Interop
So what if I need to write or use existing Javascript code? Most everyone seems to finally be aware that it's possible to write JavaScript directly in your Java source using JavaScript Native Interface methods, like so:
// Java method declaration... native String flipName(String name) /*-{ // ...implemented with JavaScript var re = /(\w+)\s(\w+)/; return name.replace(re, '$2, $1'); }-*/;
What doesn't seem to be clear is just how fundamental a feature this is. I've seen various people suggest that this is somehow "circumventing" the "normal" way of doing things -- and while it's true that you lose some of the benefits of Java type-checking, optimization, and debugging in these methods, they're also the foundation upon which all the GWT libraries are built. And there's no particular reason they have to be short snippets, either. They can be complex methods and classes that reach back into Java code, pass exceptions around, and so forth.
What about calling into existing JavaScript libraries, or exposing GWT classes to JavaScript code? For the former, check out Sanjay Jivan's SmartGWT library, which wraps the massive Isomorphic SmartClient library. For the latter, have a look at Ray Cromwell's GWT-Exporter gwtexporter library.
It's also worth noting that this functionality, combined with Overlay Types makes it really easy to efficiently parse and operate on JSON structures. Once again, you get a side-benefit: once you've written the overlay type for a particular JSON type, everyone using it gets code completion and documentation for free. For example:
class Customer extends JavaScriptObject { protected Customer() { }
public final native String getFirstName() /*-{ return this.FirstName; }-*/; public final native String getLastName() /*-{ return this.LastName; }-*/; }
which means, as a user of this class, if I get a Customer type from somewhere, I don't have to ask what fields and methods are available. The IDE can simply tell me.
HTML DOM Integration
But don't GWT's abstractions keep you from just working with DOM elements? Again, no. It has always been possible to work with the DOM from GWT (how else do you think all those widgets get implemented?), but as of 1.5, it's gotten a lot easier. See this Google IO presentation for details. Here's a taste, though:
TableElement table = ...; String s = table.getRows().getItem(0).getCells().getItem(0).getInnerText();
Which of course translates to:
var s = table.rows[0].cells[0].innerText;
With the important addition that as you type "table.[ctrl-space]", the IDE can actually tell you that "getRows()" is an option. Given that TextAreaElement alone has nearly 100 methods, that starts to be pretty useful.
The statement "You are likely to never see a DOM object or pieces of the native JavaScript language" is actually only as true as you want it to be. Most JavaScript frameworks provide some sort of higher-level abstraction than simple DOM elements, and GWT is no exception, but you should pick the right level of abstraction for the task at hand.
Independently Useful Parts
Finally, we have the question of whether (GWT === GWT's libraries). This is another common misconception -- GWT looks interesting, but I don't like the way their widget library works. That's like saying you like JavaScript, but not the way Prototype (or whatever) works.
GWT "eats its own dogfood" almost all the way down. That is to say, there's practically no module you can't replace (including the JRE). Like the DOM and JRE modules, but not all the widgetry? Write your own widgets. Don't like any of the modules? Replace the whole bloody thing! The many problems of building browser-based UIs are not yet well-solved in the state of the art, so it's highly unlikely that GWT's widget library represents a "perfect" solution. For a completely different take on how a widget library should work, have a look at the Ext-GWT library.
To Sum Up
I hope I've managed to convey the pragmatic goals that underlie GWT's design decisions, and the methods we've used to achieve them. There are still a million things we'd like to build and/or change, but I feel like it's off to a pretty good start. Nothing would make me happier than if we could stop arguing about abstract notions of what language is "right" and focus on practical goals and metrics.
Following is attached the code to create a list box containing check box in it.using on gwt components and gwt-ext(version 0.9.3) components:~ Just copy this code and make the classes :~ /** * @(#) CommonFilterGridWitChkBx.java * @version 1.0 24Mar2008 */
/** * It is used to create List with Check box components present */ public class CommonFilterGridWitChkBx { private CheckBox cbAth[] = null;
private ScrollPanel checkboxScrollPanel = null;
/** * Constructor is used to create Vertical Panel with multiple check boxes * inside it. * * @param valueCriteria HashMap Containing the value to be made as checkbox * @param width String width of the panel * @param height String height of the panel * @param scrlPnlWid String width of the scrollPanel * @param scrlPnlHt String height of the scrollPanel */ CommonFilterGridWitChkBx(HashMap valueCriteria, String width, String height, String scrlPnlWid, String scrlPnlHt ) { cbAth = new CheckBox[valueCriteria.size()]; VerticalPanel vpForChkBx = new VerticalPanel(); vpForChkBx.setSize(width, height); // Map map = valueCriteria; ArrayList alKey = new ArrayList(valueCriteria.keySet()); Collections.sort(alKey); Iterator itr = alKey.iterator(); int i = 0; while (itr.hasNext()) { String key = (String) itr.next(); String lbl = (String) valueCriteria.get(key); cbAth[i] = new CheckBox(lbl); cbAth[i].setTitle(key.toString().trim()); vpForChkBx.add(cbAth[i]); i++; } vpForChkBx.setStyleName("gridBackground"); checkboxScrollPanel = new ScrollPanel(); checkboxScrollPanel.add(vpForChkBx); checkboxScrollPanel.setSize(scrlPnlWid, scrlPnlHt); }
/** * Returns the check box panel * * @return Panel containing all the chechBoxes */ public ScrollPanel getCheckboxPanel() { return checkboxScrollPanel; } }
Then copy the following code in onmodule load class:~ package com.client;
This will create the list box containing the items as a checkbox within the list box to give it more closer look as list box include this following css in ext-all.css file
Below is a set of books that have been published regarding the Google Web Toolkit, including a short description of each.
Please note that the books linked from this page are provided by third-parties and are not endorsed by Google. A dollar sign ($) denotes that the third-party vendor charges a fee for the tool. Please direct any questions about these resources to the appropriate contact listed below.
This eBook by Ed Burnette guides you through the GWT installation process and through the creation of your first application. This book teaches you about the UI elements, Remote Procedure Calls, and the ins and outs of the framework.
This shortcut, by David Geary, addresses several more advanced topics of GWT (like implementing drag and drop and Hibernate integration). It is especially appropriate for those of you who are already familiar with the basics of using GWT, and want to dive deeper.
While the Digital Short Cut (above) walks through sample apps of some advanced GWT topics, this book covers an even more comprehensive set of advanced topics and goes into greater detail on each of them chapter by chapter. This book is ideal for GWT developers who want to take a deeper and more complete look at advanced GWT development.
Ryan Dewsbury has translated his extensive experience and passion for the GWT platform into written word for this book. It explains both basic and advanced concepts involved in building large-scale, non-trivial GWT applications. Highly recommended for those who wish to want to learn the best practices in GWT application development.
Robert Hanson and Adam Tacy have developed a comprehensive tutorial for Java developers interested in building the next generation of rich, web-based applications. By following a running example in the book, you can learn GWT from the ground up.
Robert Cooper and Charles Collins have written an example-driven, code-rich book designed for web developers who already know the basics of GWT. After a quick review of GWT fundamentals, the book provides handy, reusable solutions to the problems you face when moving beyond "Hello World" and proof-of-concept apps.
The Google Web Toolkit $ Coming Soon!
Bruce Johnson and Joel Webber, creators of the Google Web Toolkit (GWT), have signed with Addison-Wesley to write the definitive guide to GWT. This book will be published in 2007.
How JavaScript exceptions interact with Java exceptions and vice-versa.
Overview
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. JSNI code is less portable across browsers, more likely to leak memory, less amenable to Java tools, and hard for the compiler to optimize.
We think of JSNI as the web equivalent of inline assembly code. You can:
Implement a Java method directly in JavaScript
Wrap type-safe Java method signatures around existing JavaScript
Call from JavaScript into Java code and vice-versa
Throw exceptions across Java/JavaScript boundaries
Read and write Java fields from JavaScript
Use hosted mode to debug both Java source (with a Java debugger) and JavaScript (with a script debugger, only in Windows right now)
Tip
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.
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 be called just like any normal Java method. They can be static or instance methods.
Example
public static native void alert(String msg) /*-{ $wnd.alert(msg); }-*/;
Tip
In hosted mode, you can set a breakpoint on the source line containing the opening brace of a JSNI method, allowing you to see invocation arguments.
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. There is a special syntax for this.
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 form
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 here but without the trailing signature of the method return type since it isn't needed to choose the overload
arguments
the actual argument list to pass to the called method
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
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);
// 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
When writing JSNI code, it's helpful to occasionally run in web mode. The JavaScript compiler checks your JSNI code and can flag errors at compile time that you wouldn't catch until runtime in hosted mode.
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 method call semantics, or through the special syntax.
a native JavaScript object, as in return document.createElement("div")
any other Java Object (including arrays)
a 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
A Java numeric primitive is one of byte, short, char, int, long, float, or double. You must ensure the value is appropriate for the declared type. Returning 3.7 when the declared type is int will cause unpredictable behavior.
Java null and JavaScript null are identical and always legal values for any non-primitive Java type. JavaScript undefined is not identical to null; never return undefined from a JSNI method or unpredictable behavior will occur.
Violating any of these marshaling rules in hosted mode will generate a com.google.gwt.dev.shell.HostedModeException detailing the problem. This exception is not translatable and never thrown in web mode.
JavaScriptObject is a magical type that gets special treatment from the GWT compiler and hosted browser. Its purpose is to provide an opaque representation of native JavaScript objects to Java code.
Tip
When returning a possibly undefined value from a JSNI method, we suggest using the idiom return (value == null) ? null : value; to avoid returning undefined.
Exceptions and JSNI
Exceptions can originate both in Java code and in handwritten JavaScript code.
An exception that originates in a JSNI method and escapes into Java code can be caught as a JavaScriptException. Relying on this behavior is discouraged because JavaScript exceptions are not usefully typed. The recommended practice is to handle JavaScript exceptions in JavaScript code and Java exceptions in Java code.
When a JSNI method invokes a Java method, a more complex call chain results. An exception thrown from the inner Java method can safely pass through the sandwiched JSNI method back to the original Java call site, retaining type fidelity. It can be caught as expected. For example,
Java method foo() calls JSNI method bar()
JavaScript method bar() calls Java method baz()
Java method baz() throws an exception
The exception thrown out of baz() will propagate through bar() and can be caught in foo().
A flexible and simplistic method of internationalizing strings that easily integrates with existing web applications that do not support the GWT locale client property.
How to create localized properties files for use with Constants or Messages
Overview
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.
Getting Started
Since GWT supports a variety of ways of internationalizing your code, begin by researching which approach best matches your development requirements.
Do you want to internationalize mostly settings or end-user messages? If you have mostly settings (the kind of thing for which you'd normally use simple properties files), consider Constants. If you have a lot a of end-user messages, then Messages is probably what you want.
Do you have existing localized properties files you'd like to reuse? The i18nCreator tool can automatically generate interfaces that extend either Constants 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 without specifying a locale.
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 refers to 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 and Messages.
At the other end of the spectrum, dynamic string internationalization is a simplistic 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.
Using an approach similar to static string internationalization, GWT also supports 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 Localizable.
The I18N Module
The core types related to internationalization reside in the com.google.gwt.i18n package:
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
The GWT internationalization types are included in the module com.google.gwt.i18n.I18N. To use any of these types, your module must inherit from it:
Static String Internationalization
Static string localization relies on code generation from properties files. GWT supports static string localization through two tag interfaces (that is, interfaces having no methods that represent a functionality contract) and a code generation library to generate implementations of those interfaces.
For example, if you wanted to localize the constant strings "hello, world" and "goodbye, world" in your GWT application, you could define an interface that abstracts those strings by extending the built-in Constants interface:
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 this interface:
permissionDenied = Error {0}: User {1} does not have permission to access {2}
results in a compile-time error because the message template in the properties file expects three arguments, while the permissionDenied method can only supply two.
Which Interface to Use?
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.
ConstantsWithLookup 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.
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.
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 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 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 string-based 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.
Specifying a Locale
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.
If that sounded like gibberish (and it probably did), a quick digression into the purpose of client properties is in order...
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. 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 gwt.js chooses the appropriate localized version of an application, providing ease of use (it's easier than it might sound!), optimized performance, and minimum script size.
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 last-resort match between a Localizable interface and a localized resource or class.
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 element in your module XML.
For example, the following module adds multiple locale values:
Choosing a Locale at Runtime
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:
For example, the following host HTML page sets the locale to "ja_JP":
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
Localized Properties Files
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.
How to use GWT's JUnit support to create and report on benchmarks to help you optimize your code.
Overview
GWT includes a special GWTTestCase base class that provides JUnit integration. Running a compiled GWTTestCase subclass under JUnit launches an invisible GWT browser.
By default, tests run in hosted mode as normal Java bytecode in a JVM. Overriding this default behavior requires passing arguments to the GWT shell. 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 GWT. For example, to run in web mode, declare -Dgwt.args="-web" 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).
Creating a Test Case
GWT includes a handy junitCreator tool that will generate a starter test case for you, plus scripts for testing in both hosted mode and web mode. But here are the steps if you want to set it up by hand:
Define a class that extends GWTTestCase.
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 usually just use the existing module.
Implement the method GWTTestCase.getModuleName() to return the fully-qualified name of the module.
Compile your test case class to bytecode (using javac or a Java IDE).
When running the test case, make sure your classpath includes:
your project's src directory
your project's bin directory
gwt-user.jar
gwt-dev-windows.jar (or gwt-dev-linux.jar)
junit.jar
Example
Write the com.example.foo.client.FooTest test case.
public class FooTest extends GWTTestCase {
/* * Specifies a module to use when running this test case. The returned * module must cause the source for this class to be included. * * @see com.google.gwt.junit.client.GWTTestCase#getModuleName() */ public String getModuleName() { return "com.example.foo.Foo"; }
You don't need to create a separate module for every test case. In the example above, any test cases in com.example.foo.client (or any subpackage) can share the com.example.foo.Foo module.
Asynchronous Testing
GWT's JUnit integration provides special support for testing functionality that cannot execute 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:
If finishTest() is called before the delay period expires, the test will succeed.
If any exception escapes from an event handler during the delay period, the test will error with the thrown exception.
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); }
Tip
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.
Benchmarking
GWT's JUnit integration provides special support for creating and reporting on benchmarks. Specifically, GWT has introduced a new Benchmark class which provides built-in facilities for common benchmarking needs. To take advantage of benchmarking support, take the following steps:
Review the documentation on Benchmark. Take a look at the example benchmark code.
Create your own benchmark by subclassing Benchmark. Execute your benchmark like you would any normal JUnit test. By default, the test results are written to a report XML file in your working directory.
Run benchmarkViewer to browse visualizations (graphs/charts) of your report data. The benchmarkViewer is a GWT tool in the root of your GWT installation directory that displays benchmark reports.
A fundamental difference between GWT applications and traditional HTML web applications is that GWT applications do not need to fetch new HTML pages while they execute. Because GWT-enhanced 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, GWT 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 isn't the same as the more general "web service" concept. In particular, GWT services are not related to the Simple Object Access Protocol (SOAP).
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.
In this screencast tutorial you are going to see how to use the Google Web Toolkit Remote Procedure Calls. This tutorial covers creation of a simple GWT RPC project in Eclipse IDE.
As shown in the gallery, GWT includes a variety of pre-built Java widgets and panels that serve as cross-browser building blocks for your application. GWT also includes unique and powerful optimization facilities such as image bundles.
Contents
Overview
As shown in the gallery, GWT includes a variety of pre-built Java widgets and panels that serve as cross-browser building blocks for your application. GWT also includes unique and powerful optimization facilities such as image bundles.
Widgets and Panels
Widgets and panels are client-side Java classes used to build user interfaces.
Widgets Gallery
A gallery of widgets and panels.
Events and Listeners
Widgets publish events using the well-known listener pattern.
Creating Custom Widgets
Create your own widgets completely in Java code.
Understanding Layout
Understanding how widgets are laid out within panels.
Style Sheets
Widgets are most easily styled using cascading style sheets (CSS).
Image Bundles
Optimize the performance of your application by reducing the number of HTTP requests for images.
Creating and Using an Image Bundle
Define an image bundle and use it in your application.
Image Bundles and Localization
Create locale-sensitive image bundles by using GWT's localization capabilities.
Overview
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.
While it is possible to manipulate the browser's DOM directly using the DOM interface, it is far easier to use classes from the Widget hierarchy. You should rarely, if ever, need to access the DOM directly. Using widgets makes it much easier to quickly build interfaces that will work correctly on all browsers.
Widgets and Panels
GWT applications construct user interfaces using widgets that are contained within panels. Examples of widgets include Button, TextBox, and Tree.
Widgets and panels work the same way on all browsers; by using them, you eliminate the need to write specialized code for each browser. But you are not limited to the set of widgets provided by the toolkit. There are a number of ways to create custom widgets yourself.
Panels
Panels, such as DockPanel, HorizontalPanel, and RootPanel, contain widgets and are used to define how they are laid out in the browser.
Styles
Visual styles are applied to widgets using Cascading Style Sheets (CSS). This section describes in detail how to use this feature.
Widgets Gallery
The following are widgets and panels available in the GWT user-interface library.
Button
RadioButton
PushButton
ToggleButton
CheckBox
TextBox
PasswordTextBox
TextArea
Hyperlink
ListBox
MenuBar
Tree
Table
TabBar
DialogBox
PopupPanel
StackPanel
HorizontalPanel
VerticalPanel
FlowPanel
VerticalSplitPanel
HorizontalSplitPanel
DockPanel
TabPanel
RichTextArea
DisclosurePanel
SuggestBox
Events and Listeners
Events in GWT use the "listener interface" model similar to other user interface frameworks. A listener 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 listener 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 listener interface is ClickListener.
public void anonClickListenerExample() {
Button b = new Button("Click Me");
b.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
// handle the click event
}
});
}
Using anonymous inner classes as in the above example can be inefficient for a large number of widgets, since it could result in the creation of many listener objects. Widgets supply their this pointer as the sender parameter when they invoke a listener method, allowing a single listener to distinguish between multiple event publishers. This makes better use of memory but requires slightly more code, as shown in the following example:
public class ListenerExample extends Composite implements ClickListener {
private FlowPanel fp = new FlowPanel();
private Button b1 = new Button("Button 1");
private Button b2 = new Button("Button 2");
public ListenerExample() {
initWidget(fp);
fp.add(b1);
fp.add(b2);
b1.addClickListener(this);
b2.addClickListener(this);
}
public void onClick(Widget sender) {
if (sender == b1) {
// handle b1 being clicked
} else if (sender == b2) {
// handle b2 being clicked
}
}
}
Some event interfaces specify more than one event. If you are only interested in a subset of these events, subclass one of the event "adapters". Adapters are simply empty concrete implementations of a particular event interface, from which you can derive a listener class without having to implement every method.
public void adapterExample() {
TextBox t = new TextBox();
t.addKeyboardListener(new KeyboardListenerAdapter() {
public void onKeyPress(Widget sender, char keyCode, int modifiers) {
// handle only this one event
}
});
}
Creating Custom Widgets
GWT makes it easy to create custom widgets entirely in the Java language.
Composites
Composites are by far the most effective way to create new widgets. You can easily combine groups of existing widgets into a composite that is itself a reusable widget. Composite is a specialized widget that can contain another component (typically, a panel) but behaves as if it were its contained widget. Using Composite is preferable to attempting to create complex widgets by subclassing Panel because a composite usually wants to control which methods are publicly accessible without exposing those methods that it would inherit from its panel superclass. This is an example of how to create a composite.
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.
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 be done only 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 its underlying implementation.
Understanding Layout
Panels in GWT are much like their counterparts in other user interface libraries. The main difference lies in the fact that they use HTML elements such as DIV and TABLE to layout their child widgets.
RootPanel
The first panel you're likely to encounter is the RootPanel. This panel is always at the top of the containment hierarchy. The default RootPanel wraps the HTML document's body, and is obtained by calling RootPanel.get(). If you need to get a root panel wrapping another element in the HTML document, you can do so using RootPanel.get(String).
CellPanel
CellPanel is the abstract base class for DockPanel, HorizontalPanel, and VerticalPanel. What these panels all have in common is that they position their child widgets within logical "cells". Thus, a child widget can be aligned within the cell that contains it, using setCellHorizontalAlignment() and setCellVerticalAlignment(). CellPanels also allow you to set the size of the cells themselves (relative to the panel as a whole) using CellPanel.setCellWidth and CellPanel.setCellHeight.
Other Panels
Other panels include DeckPanel, TabPanel, FlowPanel, HTMLPanel, and StackPanel.
Sizes and Measures
It is possible to set the size of a widget explicitly using setWidth(), setHeight(), and setSize(). The arguments to these methods are strings, rather than integers, because they accept any valid CSS measurements, such as pixels (128px), centimeters (3cm), and percentage (100%).
Style Sheets
GWT widgets rely on cascading style sheets (CSS) for visual styling. Each widget has an associated style name that binds it to a CSS rule. A widget's style name is set using setStyleName(). For example, the Button 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%; }
Complex Styles
Some widgets have somewhat more complex styles associated with them. MenuBar, for example, has the following styles:
.gwt-MenuBar { the menu bar itself }
.gwt-MenuBar .gwt-MenuItem { menu items }
.gwt-MenuBar .gwt-MenuItem-selected { selected menu items }
In this example, there are two styles 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.
CSS Files
Typically, stylesheets are placed in a package that is part of your module's public path. Then simply include a reference to the stylesheet in your host page, such as
Documentation
It is standard practice to document the relevant CSS style names for each widget class as part of its doc comment. For a simple example, see Button. For a more complex example, see MenuBar.
Image Bundles
Typically, an application uses many small images for icons. An HTTP request has to be sent to the server for each of these images, and in some cases, the size of the image is smaller than the HTTP response header that is sent back with the image data. These round trips to the server for small pieces of data are wasteful. 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.
Sending out requests and freshness checks for many images will slow down your application. 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. RPC requests are the real work that the application needs to do.
To solve this problem, GWT introduces the concept of an image bundle. An image bundle 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 an image bundle 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.
Since 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.
Tip
Check out the ImageBundle 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
Creating and Using an Image Bundle
To define an image bundle, the user needs to extend the ImageBundle interface. The ImageBundle interface is a tag interface that can be extended to define new image bundles.
The derived interface can have zero or more methods, where each method
takes no parameters,
has a return type of AbstractImagePrototype, and
may have an optional gwt.resource metadata tag which specifies the name of the image file in the module's classpath
Valid image file types are png, gif, and jpg. If the image name contains '/' characters, it is assumed to be the name of a resource on the classpath, formatted as would be expected by ClassLoader.getResource(String). Otherwise, the image must be located in the same package as the user-defined image bundle.
If the gwt.resource metadata tag is not specified, then
the image filename is assumed to match the method name,
the extension is assumed to be either .png, .gif, or .jpg, and
the file is assumed to be in the same package as the derived interface
In the event that there are multiple image files with different extensions, the order of extension precedence is (1) png, (2) gif, then (3) jpg.
An image bundle for icons in a word processor application could be defined as follows:
public interface WordProcessorImageBundle extends ImageBundle {
/**
* Would match the file 'new_file_icon.png', 'new_file_icon.gif', or
* 'new_file_icon.png' located in the same package as this type.
*/
public AbstractImagePrototype new_file_icon();
/**
* Would match the file 'open_file_icon.gif' located in the same
* package as this type.
*
* @gwt.resource open_file_icon.gif
*/
public AbstractImagePrototype openFileIcon();
/**
* Would match the file 'savefile.gif' located in the package
* 'com.mycompany.mygwtapp.icons', provided that this package is part
* of the module's classpath.
*
* @gwt.resource com/mycompany/mygwtapp/icons/savefile.gif
*/
public AbstractImagePrototype saveFileIcon();
}
Methods in an image bundle return AbstractImagePrototype objects (rather than Image objects, as you might have expected) because AbstractImagePrototype objects provide additional lightweight representations of an image. For example, the AbstractImagePrototype.getHTML() method provides an HTML fragment representing an image without having to create an actual instance of the Image widget. In some cases, it can be more efficient to manage images using these HTML fragments.
Another use of AbstractImagePrototype is to use AbstractImagePrototype.applyTo(Image) to transform an existing Image into one that matches the prototype without having to instantiate another Image object. This can be useful if your application has an image that needs to be swapped depending on some user-initiated action. Of course, if an Image is exactly what you need, the AbstractImagePrototype.createImage() method can be used to generate new Image instances.
The following example shows how to use the image bundle that we just defined in your application:
public void useImageBundle() {
WordProcessorImageBundle wpImageBundle = (WordProcessorImageBundle) GWT.create(WordProcessorImageBundle.class);
HorizontalPanel tbPanel = new HorizontalPanel();
tbPanel.add(wpImageBundle.new_file_icon().createImage());
tbPanel.add(wpImageBundle.openFileIcon().createImage());
tbPanel.add(wpImageBundle.saveFileIcon().createImage());
}
Tip
Image bundles are immutable, so you can keep a reference to a singleton instance of an image bundle instead of creating a new instance every time the image bundle is needed.
Image Bundles and Localization
Sometimes applications need different images depending on the locale that the user is in. When using image bundles, this means that we need different image bundles for different locales. Although image bundles and localization are orthogonal concepts, they can work together by having locale-specific factories create instances of image bundles.
The best way to explain this technique is with an example. Suppose that we define the following ImageBundle for use by a mail application:
public interface MailImageBundle extends ImageBundle {
/**
* The default 'Compose New Message' icon if no locale-specific
* image is specified.
*
* @gwt.resource compose_new_message_icon.gif
*/
public AbstractImagePrototype composeNewMessageIcon();
/**
* The default 'Help' icon if no locale-specific image is specified.
* Will match 'help_icon.png', 'help_icon.gif', or 'help_icon.jpg' in
* the same package as this type.
*/
public AbstractImagePrototype help_icon();
}
Suppose the application has to handle both English and French users. We define English and French variations of each image in MailImageBundle by creating locale-specific image bundles that extend MailImageBundle:
public interface MailImageBundle_en extends MailImageBundle {
/**
* The English version of the 'Compose New Message' icon.
* Since we are not overriding the help_icon() method, this bundle
* uses the inherited method from MailImageBundle.
*
* @gwt.resource compose_new_message_icon_en.gif
*/
public AbstractImagePrototype composeNewMessageIcon();
}
public interface MailImageBundle_fr extends MailImageBundle {
/**
* The French version of the 'Compose New Message' icon.
*
* @gwt.resource compose_new_message_icon_fr.gif
*/
public AbstractImagePrototype composeNewMessageIcon();
/**
* The French version of the 'Help' icon.
*
* @gwt.resource help_icon_fr.gif
*/
public AbstractImagePrototype help_icon();
}
The final step is to create a mechanism for choosing the correct image bundle based on the user's locale. By extending Localizable, we can create a locale-sensitive factory that will return new instances of MailImageBundle that match the factory's locale:
public interface MailImageBundleFactory extends Localizable {
public MailImageBundle createImageBundle();
}
public class MailImageBundleFactory_en implements MailImageBundleFactory {
public MailImageBundle createImageBundle() {
return (MailImageBundle) GWT.create(MailImageBundle_en.class);
}
}
public class MailImageBundleFactory_fr implements MailImageBundleFactory {
public MailImageBundle createImageBundle() {
return (MailImageBundle) GWT.create(MailImageBundle_fr.class);
}
}
The application code that utilizes a locale-sensitive image bundle would look something like this:
public void useLocalizedImageBundle() {
// Create a locale-sensitive MailImageBundleFactory
MailImageBundleFactory mailImageBundleFactory = (MailImageBundleFactory) GWT
.create(MailImageBundleFactory.class);
// This will return a locale-sensitive MailImageBundle, since we are using
// a locale-sensitive factory to create it.
MailImageBundle mailImageBundle = mailImageBundleFactory.createImageBundle();
// Get the image prototype for the icon that we are interested in.
AbstractImagePrototype helpIconProto = mailImageBundle.help_icon();
// Create an Image object from the prototype and add it to a panel.
HorizontalPanel panel = new HorizontalPanel();
panel.add(helpIconProto.createImage());
}