How to split up GWT applications into modules

Did you know? GWT has its own modularization.

There is this module description xml file, which we know is the key element in how the compiler gets to know what it should consider to cross compile into javascript.

A GWT module is not only there to hold 3rd party library imports, i18n settings or compiler tweaks. GWT uses it as key modularization concept, and it is open for us to use it to structure and modularize parts of your own application.

People can get touchy whenever one says A or B is a modularization concept. OSGi does modularization, and so does maven as well. There are products that define a lifecycle at runtime (OSGi), and there is this “just a bit of modularization” at compile time, which we in fact should rather call dependency management (and sometimes mediation). Either way, at the end we always have to define packaging, eventually setup a runtime and follow deployment instructions.

Instead of rediscussing modularization concepts, frameworks and runtimes all over again, let us just have a look at what we have with GWT, ok? We have a compile time module concept that does not provide dynamic loading (or unloading) of modules. Interestingly, GWT does provide a minimalistic lifecycle for its modules at runtime: all the entry points of all modules in the application do get called. The order of execution is defined by the order of declaration. So, in fact, we have a concept that allows us to split our code into chunks and, while those chunks only exist at compile time, it does provide us hooks to start up things, depending on which modules have been compiled into the final product.

One very interesting use case of GWT modules is to use them to create different products that consist of different combinations of your own “business-case”-modules. You can also share common functionality between different GWT projects, e.g. you can extract infrastructure code into base modules, which you include into your various GWT projects.

So it is up to you – application architect – to identify and to name the parts in your application. We could use different names:

  • libraries, that just don’t do more than provide class sharing,
  • appmodules, that do interact at runtime with the application and do encapsulate some feature set.

Summing up: GWT provides a module concept that lets you do class sharing and runtime bootstrapping.

How GWT’s modularization approach works

In GWT, everythings is inside a module. A module is defined by a corresponding module definition file (XML), with a file name ending with .gwt.xml. When you start a GWT project, you typically start with one single module, e.g. MyApp.gwt.xml.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.5.0//EN"
  "http://google-web-toolkit.googlecode.com/svn/tags/2.5.0/distro-source/core/src/gwt-module.dtd">
<module>
  <inherits name='com.google.gwt.user.User'/>
  <inherits name='com.google.gwt.user.theme.clean.Clean'/>

  <entry-point class='de.oio.gwtmod.application.client.AppEntryPoint'/>

  <source path='client'/>
  <source path='common'/>
</module>

As you can see, the module definiton file defines the paths of translatable code (in this case the packages client and common will be translated by the GWT compiler to JavaScript).
A module can inherit other modules. In this context, to inherit actually means to import another module.

A project can provide multiple modules, but it requires at least one.
Your main module must contain an entry point – otherwise you couln’t start the application. In the entry point, you initialize and active the infrastructure of your application – e.g. boot up GWT’s places framework and the event bus, followed by displaying the very first widget of your application.
Here is some sample code of a an entry point of a GWT application.

public class AppEntryPoint implements EntryPoint {

	private final EventBus eventBus = new SimpleEventBus();
	private final PlaceController placeController = new PlaceController(eventBus);
	private Place defaultPlace = new Module1Place();
	private SimplePanel shell = new SimplePanel();

	public void onModuleLoad() {
		ActivityMapper activityMapper = new MyActivityMapper(placeController);
		ActivityManager activityManager = new ActivityManager(activityMapper, eventBus);
		activityManager.setDisplay(shell);
		PlaceHistoryMapper historyMapper = GWT.create(MyPlaceHistoryMapper.class);
		PlaceHistoryHandler historyHandler = new PlaceHistoryHandler(historyMapper);
		historyHandler.register(placeController, eventBus, defaultPlace);

		RootLayoutPanel.get().add(shell);
		historyHandler.handleCurrentHistory();
	}

}

When you start to develop a fresh application, you typically include some of the modules provided by GWT.
The module definition file shown above imports two modules: com.google.gwt.user.User and com.google.gwt.user.theme.clean.Clean. The User module includes core GWT stuff like different widgets. The Clean module applies a theme called “clean” to the GWT widgets.

In GWT, every module may but is not required to have an entry point. As being said, modules that are intended to be launched need to have an entry point. But also modules that will never be launched standalone (they are only imported by other modules) can provide an entry point. In that case, the entry point of the launched module will be executed first, followed by the entry points of the imported modules. That way you can “initialize” sub modules.

A typical GWT modularization scenario

The following diagram shows a typical GWT modularization scenario.
gwt-modularization-diagram

You have a main module (in this case named “application“) with an entry point that initializes and activates the infrastructure.
The main module inports two additional modules: module1 and module2, which will contain screens and business logic.
module1 and module2 share same common functionality by importing another module, in this case named core.

Allowing modules to be launched standalone

Sometimes you want to include modules in a GWT application to combine them into a product, but you also want to be able to launch a module standalone.
To achieve that, you provide two module definition files for the same module: one for standalone mode and one for embedded mode.
The two module definition files are mostly identical but point to different entry points (or the module definition file for the embedded mode could have no entry point at all).
In the entry point for standalone mode you have to initialize and activate the infrastructure, like you do in your main module.

The following image shows a typical project layout for this scenario.
gwt-modularization-structure

Conclusion

GWT’s built-in modularization concept doesn’t provide things like skinning or customization out of the box (these things could be built on top of it), but it is easy to use and should be sufficient for most use cases. It allows to share modules between multiple GWT projects and makes it possible to construct products with different module combinations. It also allows you to not only embed modules, but also launch them standalone.

Short URL for this post: http://wp.me/p4nxik-1hb
This entry was posted in Java Web Frameworks and tagged , , . Bookmark the permalink.

Leave a Reply