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.
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:
<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.
GWT projects are overlaid onto Java packages such that most of the configuration can be inferred from the classpath and the module definitions.
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.
For example, all the files for the "DynaTable" sample are organized in a main project directory also called "DynaTable".
The src directory contains an application's Java source files, the module definition, and external resource files.
|com.google.gwt.sample.dynatable||The project root package contains module XML files.|
|com.google.gwt.sample.dynatable||DynaTable.gwt.xml||Your application module. Inherits com.google.gwt.user.User and adds an entry point class, com.google.gwt.sample.dynatable.client.DynaTable.|
|com.google.gwt.sample.dynatable.public||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.|
|com.google.gwt.sample.dynatable.public||logo.gif||An image file available to the application code. You might load this file programmatically using this URL: GWT.getModuleBaseForStaticFiles() + "logo.gif".|
|com.google.gwt.sample.dynatable.client||Client-side source files and subpackages.|
|com.google.gwt.sample.dynatable.client||DynaTable.java||Client-side Java source for the entry-point class.|
|com.google.gwt.sample.dynatable.client||SchoolCalendarService.java||An RPC service interface.|
|com.google.gwt.sample.dynatable.server||Server-side code and subpackages.|
|com.google.gwt.sample.dynatable.server||SchoolCalendarServiceImpl.java||Server-side Java source that implements the logic of the service.|
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:
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:
|DynaTable.html||A host HTML page that loads the DynaTable app.|
|DynaTable.css||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.DynaTable. However, in our GWT module XML file we used the rename-to="dynatable" attribute to shorten it to a nice name.|
|dynatable.nocache.js||The "selection script" for DynaTable. This is the 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.|
The test directory contains the source files for any JUnit tests.
|com.google.gwt.sample.dynatable.client||Client-side test files and subpackages.|
|com.google.gwt.sample.dynatable.client||DynaTableTest.java||Test cases for the entry-point class.|
|com.google.gwt.sample.dynatable.server||Server-side test files and subpackages.|
|com.google.gwt.sample.dynatable.server||SchoolCalendarServiceImplTest.java||Test cases for server classes.|
Individual units of GWT configuration are called modules. A module bundles together all the configuration settings that your GWT project needs:
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.
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.
The default source path is the client subpackage underneath where the Module XML File is stored.
The default public path is the public subdirectory underneath where the Module XML File is stored.
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>
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...
...then the logical name of the module is:
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:
<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.)
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 GWT (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:
<module> ... <inherits name='com.google.gwt.gears.Gears' />
If you have multiple GWT modules in your application, there are two ways to approach loading them.
The first approach may seem the easiest and most obvious. However, the second approach will lead to much better end-user 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.
Several linkers are provided by Core.gwt.xml, which is automatically inherited by User.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>
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.
This section documents the most commonly used elements in the module XML file.
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.
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.
The <servlet> element applies only to GWT's embedded server server-side debugging feature.
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.
The following elements are used for defining deferred binding rules. Deferred binding is not commonly used in user projects.
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:
Several different predicates can be combined into an expression. Surround your <when...> elements using the following nesting elements begin/end tags:
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>
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.
|Module||Logical Name||Module Definition||Contents|
|User||com.google.gwt.user.User||User.gwt.xml||Core GWT functionality|
|HTTP||com.google.gwt.http.HTTP||HTTP.gwt.xml||Low-level HTTP communications library|
|JSON||com.google.gwt.json.JSON||JSON.gwt.xml||JSON creation and parsing|
|JUnit||com.google.gwt.junit.JUnit||JUnit.gwt.xml||JUnit testing framework integration|
|XML||com.google.gwt.xml.XML||XML.gwt.xml||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.
|Module||Logical Name||Module Definition||Contents|
|Chrome||com.google.gwt.user.theme.chrome.Chrome||Chrome.gwt.xml||Style sheet and images for the Chrome theme.|
|Dark||com.google.gwt.user.theme.dark.Dark||Dark.gwt.xml||Style sheet and images for the Dark theme.|
|Standard||com.google.gwt.user.theme.standard.Standard||Standard.gwt.xml||Style sheet and images for the Standard theme.|
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.
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.
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.
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.
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.
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.getModuleBaseForStaticFiles() + "foo.css" in client code. This is useful when the target resource is from the module's public path.
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:
Other attributes and nested elements are not supported.
The default value of defaultexcludes is true. By default, the patterns listed here are excluded.
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:
Applying these principles to the above example, we obtain the following sequence:
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
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.