Announcing gwt-maven-archetypes project

Crossposted to codehaus-mojo-gwt-maven-plugin-users

 

I started using Maven 2 years ago for a project at work, and I soon started to believe that “the Maven way” of doing a GWT project is to separate client (GWT-compiled) and server (servlets, javac'd) code into separate projects.

I undoubtedly was influenced by the Flexmojos, talked about in Sonatype's “Maven: The Complete Reference” book, but on the other hand, who knows better than Sonatype how to layout/structure your Maven projects?

 

In our project, I thus soon put that belief in action by creating (among many others: we have nearly 20 modules in the project) 4 modules: client, server, shared and webapp. You'd deploy your server code and then run GWT's DevMode in -noserver mode.

The separation between server and webapp was only so that server depends on our "api" modules only, while webapp depends on their specific implementations (for example, server would depend JAX-RS and webapp would use RestEasy as the implementation). I'm not sure it's worth it in many projects, but it helps segregating your dependencies if that's something you want to do.

Two years later, the project is going into production, and overall that project structure was a success (it should be noted that due to our project architecture –JNDI, extensive use of Jetty's XML configuration–, we couldn't use DevMode's embedded server; and we only use the gwt-maven-plugin for its gwt:compile goal: launching our customize Jetty server was done using a shell script, and the GWT DevMode was only ever launched from within Eclipse).

 

In the last few days (being on vacations), I spent some time making a Maven archetype for that setup, with working mvn jetty:run and mvn gwt:run goals (well, I have to admit: not fully tested yet): https://github.com/tbroyer/gwt-maven-archetypes

I intend to add at least another archetype for projects using RequestFactory instead of GWT-RPC, and there's currently absolutely no documentation (the browser tab next to the one I'm typing this in is the “Site Generation” chapter from the “Maven: The Complete Reference” book).

 

Here's how it goes (after you install it in your local repo):

  1. mvn archetype:generate -DarchetypeGroupId=net.ltgt.gwt -DarchetypeArtifactId=gwt-maven-archetypes-modular-webapp -DarchetypeVersion=1.0-SNAPSHOT
  2. mvn package -Pdraft
  3. In one terminal window: cd server; mvn jetty:start -Pdev
  4. In another (or you could use -Djetty.daemon in the previous step): cd client; mvn gwt:run -Ddev

Feedback, including issues and pull requests, is more than welcome!

GWT 2.1.1 RequestFactory – Part II

Last week, I posted a first article on GWT 2.1.1 RequestFactory, followed a few days later by one on GWT 2.1 Editors (and, as promised in the former, how to use them with RequestFactory). In this article, I'll deal with 3 topics I also promised to tackle: what changed since 2.1.0, how does RequestFactory compares to GWT-RPC, and finally how does it integrates with JSR-303 Bean Validation (feel free to jump directly your section of interest). But first, let's start with something I forgot to talk about in my previous article!

Chained persistence

When you're asked to retrieve a domain object from your datastore, you should use at most one instance of a given persisted object (e.g. if you're asked twice for the Person with identifier 1, you should return the same instance each time, or at least instances that live in the same context so that changes to one instance will be persisted when saving another instance representing the same entity). This is causing many incomprehensions. Fortunately, when using JPA or JDO, it's as easy as using a request-scoped transaction.

What's new in 2.1.1

RequestFactory saw its first stable release in GWT 2.1.0. In GWT 2.1.1, the server part was totally rewritten, and the client side was slightly reworked as well. But this is all transparent to the developer, and code that compiled and ran with GWT 2.1.0 should still work with GWT 2.1.1. The following will probably only be useful for people who started using RequestFactory in 2.1.0 and want to know which new things can benefit them.

Features GWT 2.1.1 provides are summed up in the release announcement:

  • "A service layer, which includes support for non-static service objects": GWT 2.1.1 introduced the Locator and ServiceLocator interfaces, which allow you to, respectively, get rid of the findXxx static method on entities (along with providing ID and version without necessarily using thus-named domain object properties), and instantiate a service class to be able to use instance methods for services.
  • "EntityProxy are no longer the only type of proxies you can use on the client-side": GWT 2.1.1 adds the ValueProxy interface (and the BaseProxy interface that's a common parent for both EntityProxy and ValueProxy).
  • "Multiple methods calls on a single request": in GWT 2.1.0 you could only have a single invocation on a give RequestContext before you fire() it. This limitation has simply been removed.

How does RequestFactory compare to GWT-RPC

Contrary to GWT-RPC which shares the same objects on the client and server side, RequestFactory uses proxy interfaces on the client-side (whose implementation is automatically generated). Thus, your real objects stay on the server, and are therefore not subject to the constraint of being translatable to JavaScript (remember having to fight with Hibernate's enhanced collections and lazy-loading until hibernate4gwt and gilead?). That dychotomy also allows a single server-side domain object to be represented by different proxy interfaces on the client-side, each proxy exposing a different set of properties.

The drawback is of course that there's a bit of redundancy (having to re-declare methods on the client-side interface), but on the other hand it brings flexibility and, if you ask me, removing the "must be translatable" constraint is enough to justify it.

It's worth mentionning that the dichotomy actually already existed in GWT-RPC in the service interfaces (synchronous, implemented by your RemoteServiceServlet, and asynchronous, used on the client-side).

Despite removing the "must be translatable" constraint, RequestFactory comes with a number of limitations regarding the types that can be transported: only primitive types and their boxed classes, enums, strings, dates (java.util.Date), BigInteger and BigDecimal, other proxies, and finally java.util.List and java.util.Set of any of the above, can be used. RequestFactory doesn't (yet!) support polymorphism (which means you have to use the exact classes I listed above; you cannot for instance declare a property of type java.util.SortedSet or java.sql.Timestamp).

However, because of those limitations, RequestFactory does not use serialization policies computed at compile-time, which means that your client and server code are much more loosely coupled than with GWT-RPC. With RequestFactory, provided the changes were made in a compatible way, you can independently deploy your client and server code, including using DevMode in -noserver mode against an already deployed application.

Actually, RequestFactory has all the advantages of De-RPC:

  • the protocol is JSON-based, which makes deserialization very fast on the browser.
  • client and server can use slightly different (but compatible) objects and still communicate (this was probably inspired by Protocol Buffers), which helps with hot-deployment.
  • you don't have to compile and deploy your app each time you change a service or domain object to be able to debug using DevMode in the -noserver case.

…and it works on Google AppEngine.

Finally, although the API and concepts are highly different, RequestFactory and its new (in 2.1.1) support for ValueProxy makes it possible to use it as a general-purpose RPC mechanism, at least to aid in migrating from GWT-RPC, and it's expected that De-RPC will die in favor of RequestFactory (don't worry, GWT-RPC will still be supported, we're only talking here about De-RPC, which never leaved the experimental state).

JSR-303 Bean Validation

When receiving a request to process, the RequestFactoryServlet applies the operations on the domain objects and validates them before processing any invocation. The default behavior for that validation is to use javax.validation, and that's why you might see an "Unable to initialize a JSR 303 Bean Validator" error in your server logs if you do not have a JSR 303 implementation (such as Hibernate Validator) in your classpath, and why you must have the validation API in your classpath for RequestFactory to work, to begin with.

ConstraintViolations are reported on the client side as a set of Violations to the onViolation() method of Receivers. Because validation is done before invocations are processed, all Receivers for a given RequestContext will receive the violations, and the default implementation of onViolation() is to call onFailure() with a fatal ServerFailure, which will by result in a RuntimeException.

What's next?

In the next article, I expect to write about the ServiceLayerDecorators, that is, the internals of the RequestFactoryServlet, where you can plug your own code to tweak a few things.

GWT 2.1 Editors

GWT 2.1 is advertized as providing "a framework for business apps", and one of the included features is the Editor framework, which provides data binding between bean-like objects and UI fields.

The Basics

On one hand you have an object graph that you want to display or edit, and on the other hand a set of widgets (let's call them editors, we'll see the why later). To use them together so that your objects are displayed in the editors, you'll use an editor driver.

GWT 2.1 comes with two editor drivers: the SimpleBeanEditorDriver and the RequestFactoryEditorDriver. Similarly to UiBinder, you'll declare an interface extending one of these with generic parameters.

The kind of objects that you can edit depends on the editor driver you use, but in any case they'll be bean-like objects. SimpleBeanEditorDriver edits any simple Java bean while RequestFactoryEditorDriver expects only RequestFactory proxies; and in case that's not enough (really?), it's technically possible to create your own editor driver flavor (and it's not that much work, though you have to be familiar with the editor framework internals).

Finally, editors are any class that implement the Editor marker-interface or the IsEditor interface. There are further constraints and features, and that's the whole point of this article, as we'll see below.

Editor drivers

Both editor driver interfaces have two generic parameters: the type of the object being displayed or edited (I'll always use edited from now on, but editors can be read-only, and thus only display data), and the type of the root editor.

The GWT Editor framework makes extensive use of code generation. Because everything is done at compile-time by inspecting classes, it means everything is based on the types you use in your interface declaration (and for sub-editors, see below, the field and method declarations). If you then use the generated code on a subclass of the editor for instance, only the bits inherited (and possibly overridden) from the declared editor type.

The Editor framework uses a Flow Synchronization pattern: you edit an object for the editor driver to populate editors from the object's values, and you later flush the editor driver to copy editors' values back into the edited object. During a flush, editors have an opportunity to report errors that will be available as EditorErrors.

The SimpleBeanEditorDriver provides just that: an edit() method, a flush() method, and a pair of hasErrors() and getErrors() accessors. But before you edit() an object, you'll first have to initialize() the editor driver with the actual editor instance to be used.

We'll look at the RequestFactoryEditorDriver later.

Editors

Editors are a graph of objects used to edit objects. Each editor is bound to a type of object that it can edit. Starting from a root editor type, the editor driver generator will build a representation of the editors tree using reflection: any non-private field or non-private no-args method whose (return) type is an editor will be seen as a sub-editor, unless it is annotated with @Ignore. The name of the edited property will be infered from the field or method name (it will be field/method name after an optional Editor suffix has been removed), unless it is annotated with @Path (which can use the dotted notation to reference a sub-property; in GWT 2.2 you'll also be able to use the empty string to reference the current object). At runtime, if any of these sub-editors is null, it will simply be ignored. This is known as the Editor contract.

A field or method will be treated as an editor if its type implements the Editor marker interface (or one of its subinterfaces, see below) or the IsEditor interface. There are several kinds of editors:

  • an IsEditor returns an Editor from its asEditor() method. When building its editors tree, the editor driver generator will descend into the Editor's type.
  • a LeafValueEditor represents a leaf in the editors tree. The editor driver generator won't try to find sub-editors.
  • a CompositeEditor contains an unknown, dynamic number of sub-editors of the same type. There are several built-in CompositeEditor to edit an optional value or conveniently adapt a List of objects: the ListEditor with which you manage the sub-editors display, and the HasDataEditor which uses a Data Presentation widget (such as a CellList or CellTable) to edit the objects in the list.

Editors can also implement a couple of other interfaces to extend their behavior:

Most widgets displaying or editing values are already editors (most are actually IsEditors of editor adapters): TextBox, Label, DateBox, CheckBox, etc. and a few widgets have been added to add type specialization: IntegerBox, DoubleBox, NumberLabel, DateLabel, etc. This makes the Editor framework a very good friend of UiBinder!

Integration with RequestFactory

The RequestFactoryEditorDriver is similar to the SimpleBeanEditorDriver but with a few key differences:

  • First, the initialize() method can also take a RequestFactoryand/or an EventBus to listen to EntityProxyChange events; it will then find() the object back from the server and refresh the editors.
  • The edit() method expects both the object to be editor and a RequestContext (so the driver can ensure all objects in the graph are mutable, by calling the RequestContext's edit() method.
  • If you just want to display a proxy, you can use the display() method, which works seamlessly with immutable objects.
  • The flush() method doesn't return the edited object, but the RequestContext passed to the edit() method.
  • A getPaths() method returns the list of all the properties being edited, and can be passed to a Request's with() to only ask the server for those properties.
  • Finally, you can display errors reported out-of-band (e.g. by the server) with the setViolations() method. Note that in GWT 2.2 this method is expected to be deprecated and replaced with a setConstaintViolations that will also be available on the SimpleBeanEditorDriver.

Conclusion

The GWT Editor framework is a real time-saver, because you no longer have to maintain the code to push your objects' properties into widgets and back to the objects, and you therefore no longer have to test that code (because as soon as you add a field, you'll probably copy/paste lines and can miss a change, injecting a property into the wrong field, or a field's value into the wrong property). As a proof of that, I've quickly drafted a before/after sample (only files that are necessary to understand the code are included, and I know there are typos and missing imports, but using this user script or Chrome extension you can then easily see a diff between the 2 versions)

GWT 2.1.1 RequestFactory

Updated 2011-02-10: I was wrong about optimistic locking. It was there in early versions of RequestFactory but never shipped in GA releases.

RequestFactory was already available in GWT 2.1 but really becomes usable starting with GWT 2.1.1.

RequestFactory is "an alternative to GWT-RPC for creating data-oriented services." It's been initially designed for CRUD on entities (domain objects with an identifier and version), but as of GWT 2.1.1 can actually also be used as a general-purpose RPC mechanism.

The Basics

With RequestFactory, you have a set of domain objects and services on the server-side, and proxy and stub interfaces on the client-side, using annotations and naming conventions to map ones to the others. Note that a single server-side object can have several different mappings on the client-side.

Whichever layout you have on the server-side, RequestFactory clearly separates domain objects (that only have properties) from services (methods acting on those objects) on the client-side: there's not necessarily a 1:1 mapping between your client-side proxies and service stub interfaces and your server-side domain objects and services.

As you could have guess from the above, RequestFactory makes extensive use of code generation: all you have on your client code are interfaces, whose implementations will entirely be generated when compiling your application from Java to JavaScript.

Domain objects

There are two kind of domain objects: entities and value objects. The difference is that entities have an identifier (and RequestFactory also mandates that they have a version, more on this later), and then RequestFactory can be used to update an existing object; while value objects are just that: values with properties, with no particular identity. Each one maps to a distinct base interface on the client-side: EntityProxy and ValueProxy, respectively. Apart from that, all a (client-side) proxy is allowed to have are property accessors (getters and setters).

The crux of RequestFactory, compared to classical RPC, are entities. On the client-side, RequestFactory will monitor your calls to property setters and only send a diff to the server, where the setters will be re-applied. This is why having an identifier and version are so important: the identifier allows RequestFactory to load the object so it can apply the diff to it, and the version is used to detect changes and fire update events (see below). When working with objects having many properties, and/or with many such objecs, this can significantly reduce the amount of data that goes over the wire (which also means RequestFactory is well-suite for mobile devices), while on the other hand, value objects are always sent with all their properties. Last, but not least, events will be dispatched on the client-side each time a domain object is persisted, updated or deleted on the server (it obviously only concerns entities, not value objects, and only those that have been sent in or returned from a given request).

Services

Services are methods. A method can take as argument and/or return domain objects (entities or value objects) or simple values. Most common such methods are those that implement CRUD on entities, but if you only use value objects and simple values you have a general-purpose RPC mechanism.

RequestFactory supports many use cases, as a service method can be (on the server-side) either a static method, an instance method on a service object, or an instance method on a domain object.

Putting it all together

Keep in mind that RequestFactory makes use of code generation, so you'll always start (in your client code) by GWT.create()ing a class, or rather in this case, an interface. This interface has to extend RequestFactory, and define no-args methods that return service stubs. Those method are factories: each call will return a new instance (hence the name of the interface: RequestFactory).

A service stub is an interface extending RequestContext and defining service methods. The interface has to be annotated with @Service or @ServiceName to map it to a server-side class. Those service methods have the same signature as their server-side counter-part, with the exception of the return type: it will be either Request<T> if the method lives in the server-side class referenced by the @Service/@ServiceName annotation, or an InstanceRequest<P,T> if the method is on a domain object (of the type mapped toP on the server-side). In any case, the T type is the actual return type of the method. If you have instance methods on the server-side service object, you have to provide a ServiceLocator class in the @Service/@ServiceName annotation; RequestFactory will instantiate that class to then ask it for an intance of the service class; otherwise, all methods declared as Request<T> will have to be static methods on the server-side class. As for the difference between @Service and @ServiceName, the former uses class literals that have to be available at compile-time while the latter uses class names; if you use the @Service interface, the RequestFactoryGenerator will automatically validate that the declared client-side methods actually map to existing server-side methods.

The RequestFactoryGenerator has found the service stub interfaces by examining the methods of the RequestFactory root interface, and it'll similarly find the domain objects' proxy interfaces looking at the arguments and return types of the service methods.

A proxy is an interface that extends either EntityProxy for an entity, or ValueProxy for a value object, and define accessors for the object's properties (you don't have to provide a getter/setter pair for each property, you can have a getter without a setter; you however cannot have a setter without an associated getter). The interface has to be annotated with @ProxyFor or @ProxyForName to map it to a server-side class (and similarly, the RequestFactoryGenerator will validate at compile-time that declared property accessors actually map to existing server-side peers if you use the @ProxyFor annotation, but won't if you use the @ProxyForName).

For entities, RequestFactory will have to load them by their identifier (so it can apply the diffs sent from the client before landing them to the service methods). To do so, it will either ask a Locator (that it will first instantiate, of course) or fallback to using a static method named findXxx (where Xxx is the name of the entity class). The Locator will also provide the entity's identifier and version, defaulting getId and getVersion accessors respectively.

All those interfaces have to be available to your client code, and also compiled and deployed to your server, as RequestFactory will need the @Service, @ProxyFor et al. at runtime (also note that the validation that is performed at compile-time if you use @Service and @ProxyFor will be done at runtime with all four annotations). For this reason, they're often placed in a sub-package called shared.

OK, but how to use it now?

The first thing to do is to declare a servlet mapping for the RequestFactoryServlet at path /gwtRequest (this is the default, it can be changed). That's all you have to do on the server side.

On the client side, you'll start by GWT.create()ing your RequestFactory root interface, and then immediately initialize() it before you can use it. The initialize() method expects an EventBus where the EntityProxyChange events will be dispatched, and an optional RequestTransport. If the RequestTransport is omitted, a DefaultTransport will be used, with the default servlet path of GWT.getHostPageBaseURL() + "gwtServlet" (in other words, this is where you have a chance of changing those default values).

Next you'll create a RequestContext (service stub) by calling one of the methods you defined on the RequestFactory root interface. As for the RequestFactory interface, the name RequestContext is not innocent: a RequestContext is a kind of builder for your request, this is where you'll queue entity property setters and service method calls. It represents the context in which things are done before you send them all in one bach request to the server.

On that context, as I said above, you'll be able to queue entity property setter calls. For that, you first have to edit() a proxy, as these are immutable by default (this holds true for value objects too, even though their property setters are not monitored like entities' ones). A proxy can only be edited by one RequestContext at a time; it however doesn't matter how many time you call edit() on the same proxy. Note that edit() doesn't update the given proxy in-place, it instead returns a new object. If you want to create a new proxy instead of editing an existing one, you can use the RequestContext's create() method. The returned object is mutable so you don't have to edit() it before you modify it.

You'll also be able to queue service method calls. To do that, you'll simply call the method on the service stub, passing the appropriate arguments. If you're calling an InstanceRequest<P,T>, you'll also have to call using() on the returned InstanceRequest to provide the object instance on which to call the method. You can further refine the invocation using the with() method which controls which properties of the returned entities will be sent back to the client (this helps reduce the response payload size), and the to() method where you'll give a Receiver<T> to actually receive the method's returned value.

When you're done setting up your RequestContext, you'll fire() it to actually send everything to the server. One thing to remember is that whichever the order you called them, operations (property setter calls on entity proxies) will always be processed before invocations (service method calls). This means you can create() an object, save() it right away and then starts modifying it; when processed on the server, the object will first be applied its setters, then the save() method will be called. However, the relative order of operations and invocations is respected (i.e. if you call setFoo before setBar, then setFoo will be applied before setBar on the server too; and similarly for service method calls).

You can pass a Receiver<Void> to the RequestContext.fire() method, and it will be called after the Receivers for each service method invocation. Note however that its onFailure will be called only in case of general failure, so in most case only its onSuccess method will be called, whether the distinct invocations are successful or not.

As a shortcut, you can also call a fire() directly on a Request object; and passing a Receiver to the fire() method is equivalent to calling to() and fire() sequentially. I'd only recommend doing this if you have only a single invocation in your RequestContext, though.

What's next?

In the following article(s), I'll deal with the changes between GWT 2.1.0 and 2.1.1, how RequestFactory compares to GWT-RPC, JSR 303 validation, integration with the GWT Editor framework, ServiceLayerDecorators (or how to tweak the server-side processing, for example to integrate nicely with Guice or Spring) and other advanced techniques.

GWT 2.1 Places & Activities – What changed between M3 and RC1

If you've started using GWT 2.1 Places and Activities with the Milestone 3, then here's what changed in the Release Candidate 1. I'll update my previous articles in the coming days to reflect those changes.

  • The com.google.gwt.app.place package has been split into the com.google.gwt.place and com.google.gwt.activity.
  • Activity.Display now is com.google.gwt.user.client.ui.AcceptsOneWidget, which is implemented by SimplePanel (showActivityWidget is thus renamed as setWidget).
  • IsWidget has been moved to com.google.gwt.user.client.ui and is now implemented by Widget (which returns itself); this means that if your view classes extends Widget (most views extend it through Composite) you no longer have to implement the asWidget method.
  • In addition, all widgets now accept IsWidget as argument where they already accepted Widget.
  • HandlerManager is @Deprecated and no longer implements EventBus; you'll now use a SimpleEventBus for your application-wide event bus.
  • PlaceHistoryHandler has been split into a concrete PlaceHistoryHandler and the PlaceHistoryMapper interface, which you're free to implement yourself or use as before, giving your sub-interface to GWT.create() so that it generates the implementation from the @WithTokenizers annotation (and/or factory if you're using PlaceHistoryMapperWithFactory); this approach is similar to the ActivityManager vs. ActivityMapper, with the added generator for the mapper based on PlaceTokenizers and @Prefix.
  • The ProxyPlace, ProxyListPlace and associated classes (and abstract activities) have been moved to the Expenses sample (which doesn't use them yet).

And this list is only about the Places and Activities part: RequestFactory's API has been deeply refactored, and a new Editor module is born!

GWT 2.1 Activities – nesting? YAGNI!

Updated 2010-10-16: updated to GWT 2.1.0.

I'm not going to beat around the bush, GWT 2.1 Activities have no support for nesting. Let's see when you might think you need it, and how you could do without.

The scenario

So let's say you identified those four layouts in your app (this is based on a real example, the only difference is I only needed a single master-detail layout):

Layouts

You might be tempted to build it as nested layouts, i.e. build the first one, and when needed put in the "main content" display region a master-detail or main-aside sub-layout, nesting two new display regions.

No nesting? Really?

Now, here's how you could do it without nesting, just showing hiding display regions when needed (and resizing the others to always fill the same dimensions):

Final_layout

Note that I chose the "detail" region to also serve as the "main content", but you could have decided otherwise, any region could have made it.

Mapping this layout to GWT 2.1 Activities

Each region is a display region, with its own ActivityManager and ActivityMapper.

    ActivityManager vertMasterActivityManager = new ActivityManager(vertMasterActivityMapper, eventBus);
    vertMasterActivityManager.setDisplay(vertMasterDisplay);
    
    ActivityManager horizMasterActivityManager = new ActivityManager(horizMasterActivityMapper, eventBus);
    horizMasterActivityManager.setDisplay(horizMasterDisplay);
    
    ActivityManager mainActivityManager = new ActivityManager(mainActivityMapper, eventBus);
    mainActivityManager.setDisplay(mainDisplay);
    
    ActivityManager asideActivityManager = new ActivityManager(asideActivityMapper, eventBus);
    asideActivityManager.setDisplay(asideDisplay);

When a region is not needed, the dedicated ActivityMapper just returns null, which the ActivityManager will relay to the display region. And you'll code your display regions so that a null activity widget hides it (in addition to emptying it).

    // Assumes a LayoutPanel is used for the layout, with a SimplePanel for each display region
    AcceptsOneWidget asideDisplay = new AcceptsOneWidget() {
       public void setWidget(IsWidget activityWidget) {
          Widget widget = Widget.asWidgetOrNull(activityWidget);
          layoutPanel.setWidgetVisible(asidePanel, widget != null);
          asidePanel.setWidget(widget);
       }
    };

Pros and Cons

On the pros side:

  • no matter how many "screens" share the same layout, they all share the same dimensions (leading to a consistent layout) without duplicate coding or code sharing (or even reuse, there's a single code path to manage the panels sizes);
  • using a LayoutPanel you can easily animate the transitions between layouts, with a single line of code!

On the cons side:

  • you'll have to dispatch between all the activities for a given "sub-region" in a single ActivityMapper; the no-nesting rule also applies here, but only in appearance: you'll just nest/split your dispatching code at another level.

    I'd suggest using a base Place, or a marker interface, to discriminate different groups of places/activities (a simple rule could be "those places with the vertical master-detail layout" vs. "those places with the main-aside layout" vs. etc., or a more complex, or more business-oriented one); and you can delegate each group to a more specific method, or even its own ActivityMapper (and this is not limited to this use-case of complex layouts):

        public Activity getActivity(Place place) {
           if (place instanceof MailPlace) {
              return mailActivityMapper.getActivity(place);
           }
           if (place instanceof ContactsPlace) {
              return contactsActivityMapper.getActivity(place);
           }
           if (place instanceof SettingsPlace) {
              return settingsActivityMapper.getActivity(place);
           }
           return null;
        }

All in all, there are more advantages than drawbacks! As always, it's just a different way to approach the problem.

Conclusion

As the title said, you ain't gonna need nesting. But if you can come up with a use case that couldn't be addressed as explained above, I'd really like to hear about it! (and I believe the GWT team too)

GWT 2.1 Activities

Updated 2010-10-16: updated to GWT 2.1.

GWT 2.1 activities sit on top of the GWT 2.1 places to help in managing the place change events and navigation confirmation, and are part of what the GWT Team calls GWT's MVP Framework.

The core concepts

There are two main concepts in GWT 2.1 activities: display regions and activities. A display region is a part of the screen/page whose content changes in response to navigation. An activity is what the user does in a display region for a given place.

An important property of activities is that their lifetime is different from the one of the application (actually, from the display region, but those will generally have the same lifetime as the application, so…)

Any in-the-wild example of those concepts?

As an example, even though it's not made with GWT, let's look at GMail. Leaving alone ads, gadgets, and tasks for simplicity, the screen is divided into several parts:

  • the top-level navigation menu (the menu with the “Mail”, “Contacts” and “Tasks” items)
  • the search bar
  • the navigation menu (on the left-hand side, below the top-level navigation menu)
  • the main region

All of these are display regions, except the top-level navigation menu, as it has the same lifetime as the application (note that it listens to some events, probably place change events, to update the selected item, but it does not mean that it is or should be a display region and/or activity).

The search bar and navigation menu are very simple, as they just swaps activity when you switch between “Mail” and “Contacts”, whereas the main region constantly changes to contain the “main activity”: e.g. some list of mail conversations, a particular mail conversation, some list of contacts, or a particular contact's details.

How those concepts map to classes in GWT?

An activity in GWT can be any class implementing the Activity interface, whereas a display region is a class implementing the AcceptsOneWidget interface. Swapping activities in a display region in response to a place change event is the job of an ActivityManager, which will ask an ActivityMapper the appropriate activity for the current place.

Activity life-cycle, from the ActivityManager point of view

When you navigate from one place to another, the current activity is first asked whether it mayStop(). This will eventually ask confirmation from the user before actually navigating (you'll probably recognize the PlaceChangeRequestEvent hidden behind this behavior).

If the navigation actually happens (i.e. the PlaceChangeEvent is fired), the current activity is first stopped (by a call to its onStop() method) before the next activity can be started.

The next activity is given by the ActivityMapper, depending on the current place. It is then start()ed within the ActivityManager's managed display region (AcceptsOneWidget). When the activity is fully initialized, it asks back to be displayed, and we're done… until the next place change request.

Initialization of an activity can be asynchronous (usually tied to a GWT-RPC or RequestFactory request), which means that the user can change its mind before the activity is fully initialized and navigate to yet another place. In that case, the current activity is cancelled (by a call to its onCancel() method) instead of stopped. Note that in this case, it isn't previously asked whether it mayStop(), as it isn't fully started yet.

Activity life-cycle, from the Activity point of view

In response to navigation, the activity is asked to start(). It's passed the display region and the event bus. Initialization can be asynchronous, and when fully initialized, the activity calls the display region back with an IsWidget object (i.e. an object capable of providing a Widget that displays it; note that the Widget base class implements IsWidget by returning itself, so you generally don't have to implement it yourself). The event bus is actually a ResettableEventBus, a wrapper around the application's global event bus, with the added property that any registered handler will automatically be unregistered when the activity is stopped, without it having to deal with HandlerRegistrations itself.

Once the activity has been started, and before it is fully initialized, it can be cancelled (by a call to its onCancel method) at any time if the user changes its mind and navigates to yet another place.

Otherwise (it's not been cancelled), when the user wants to navigate away, the activity will first be asked if it mayStop(), and will eventually be stopped (by a call to its onStop() method).

Note that because there can be several activities running concurrently (in different display regions), the activity might be stopped (or not) whichever the value it returned from the call to mayStop(). This is because a non-null return-value from mayStop() will only ask the user for confirmation, and null return-value won't overwrite a non-null value returned by another concurrently running activity (i.e. even if the activity returns null, another one might have returned a non-null value, asking the user for confirmation, and that one could finall have decided to stay at the current place). In other worlds, whichever the value you return from mayStop(), you shouldn't assume onStop() will or won't be called right away. However, onStop() won't ever be called without mayStop() being called first.

Activity life-cycle, from the display region and user point of view

The user interacts with the activities shown in display regions and isn't aware of this internal workflow. Stay concentrated as, because of the asynchronous nature of activities' startup, the notion of the current activity changes from the user's point of view!

In response to a user action (“show this mail conversation”, “go back to inbox”, etc.), the current activity has to be stopped and another started. As the next activity is starting (remember, this is already the current activity from the ActivityManager's point of view), the current activity (previous one actually) is still displayed, but it's already logically stopped (its onStop() method has already been called). Please note that this behavior will change in the next release: the display region's widget will be set to null as soon as the activity is stopped and until the next one is fully initialized.

It's your job as a developer to choose which behavior you want: the view is disabled, or it might trigger navigation.

Technically, it could still handle all user events but, because it's already stopped, it can be replaced at any given time and you won't have any notification (well, there's the widget's onUnload(), but anyway it's probably already too late to do anything useful). I'd therefore advise you to not do it, except to trigger navigation as it's about leaving the activity (which, you'll agree, doesn't conflicts with the already-stopped status of the activity).

The rule of thumb is thus to disable any action when an activity is stopped (i.e. from its onStop() method), except possibly navigation. It's up to you to decide whether this is done by disabling (graying out) widgets or just turning a deaf ear to their events.

Hey, where's the MVP framework you talked about?

Well, there's nothing forcing you to do MVP with GWT 2.1 activities, but it sure settles the basements for MVP: the Activity will be your presenter and the IsWidget you'll give back to the AcceptsOneWidget will be your view. And that's it. Really!

A note about performance

What takes most of the time in AJAX web apps on the client-side (i.e. with network and servers out of the equation) is manipulating the DOM. GWT 2.0 already gave us a wonderful tool to help us use the HTMLPanel, in the form of UiBinder, but it brings you nothing if you're constantly calling it. This means that your views should, when possible, be singletons. It doesn't imply though that your presenters should be!

If your presenters live longer than your activity (I mean from start to onStop here), they'll have to make sure they correctly clean up their internal state each time they're recycled. Because presenters are POJOs, they are actually quite lightweight, and the idea is that the cost for you to ensure the state is correctly cleaned up between uses of a singleton object outweighs the negligible performance lost induced by using many short-lived objects.

This works best if you listen to user events by registering a presenter delegate to your view: you'll call view.setDelegate(this) from start and view.setDelegate(null) from onStop. For your app to properly work, you only have to ensure that you don't try to use two presenters simultaneously with the same view, but it'll actually come naturally in most cases, and is really no different from ensuring a singleton presenter isn't used twice at a given time.

Conclusion

You're now ready to start coding wonderful applications, using a simple yet powerful approach to navigation handling, which integrates nicely with MVP.

GWT 2.1 Places – Part II

Translation available in: French.

Updated 2010-10-16: updated to GWT 2.1.0.

I previously described the core of GWT 2.1 Places and will now focus on the optional features.

User confirmation before navigating

In many applications, you want to have confirmation of the user before navigating away; this is mostly used when the user made changes and didn't yet save them. This can be easily accomplished with GWT 2.1 places: you'll register a PlaceChangeRequestEvent.Handler on the event bus and call the PlaceChangeRequestEvent's setWarning method with a non-null value that will be used to ask confirmation to the user.

When calling goTo on the PlaceController, before changing the current place, it actually first fires a PlaceChangeRequestEvent. Once the event has been dispatched to all the handlers, the current place will actually be changed and the PlaceChangeEvent fired only in two cases:

  • the event's warning property is null, or
  • the event's warning property is non-null and the user has confirmed the navigation. Confirmation is asked using a (browser-native) dialog box, with the event's warning property value used as the message presented to the user.

Additionally, when navigating away or closing the window or tab (i.e. quitting the application), such a PlaceChangeRequestEvent is also fired (with the next place set to Place.NOWHERE), and setting a non-null warning value will also ask the user confirmation (for those interested in the gory details, this is accomplished by setting the Window.ClosingEvent's message).

Integration with RequestFactory

GWT 2.1 does not come with built-in direct integration with RequestFactory. You'll find a preview of what'll come in a later release in the code for the Expenses sample, in the form of two concrete places that can help you when a place is tied to a EntityProxy instance or type: the ProxyListPlace represents the list of records of a given type, while the ProxyPlace models an operation (create, show details, or edit) on a particular record instance.

Integration with the browser's history

Integration with the browser's history means:

  1. serializing the current place to the URL so it can be bookmarked and creating an entry in the browser's navigation history; and
  2. deserializing the URL back to a place, and fire the appropriate events to the event bus to finally update the current place.

#1 is done when the place changes due to a call to the PlaceController's goTo, while #2 is triggered by the browser when the user either navigates in its history through the browser's "previous page" and "next page" buttons, or loads a previously bookmarked URL generated by #1.

To use this feature, you'll first create PlaceTokenizers to map history tokens to/from places, and then an (empty) interface, extending PlaceHistoryMapper and annotated with @WithTokenizers to declare the PlaceTokenizers to be used, that you'll GWT.create() and finally register, through a PlaceHistoryHandler, with the PlaceController, the EventBus and a default place (the place to use when there's no token, or when the token cannot be mapped to a place).

  @WithTokenizers(FooPlaceTokenizer.class, BarPlaceTokenizer.class)
  interface MyPlaceHistoryMapper extends PlaceHistoryMapper {
  }

  PlaceHistoryMapper historyMapper = GWT.create(MyPlaceHistoryMapper.class);
  PlaceHistoryHandler historyHandler = new PlaceHistoryHandler(historyMapper);
  historyHandler.register(placeController, eventBus, defaultPlace);

How does the PlaceHistoryHandler maps history tokens to places?

Each PlaceTokenizer is associated with a token prefix using a @Prefix annotation. The PlaceHistoryHandler splits the history token on the first colon, compares the left-hand part to the prefixes it knows, and then GWT.create() the matched PlaceTokenizer class and call its getPlace method with the right-hand part as the argument.

How does the PlaceHistoryHandler maps places to history tokens?

PlaceTokenizer is a generic class actually defined as PlaceTokenizer<P extends Place>. When the code generator runs on the PlaceHistoryHandler, it examines the PlaceTokenizers and extracts their P generic type argument. This information is then used at runtime to map a place to the appropriate PlaceTokenizer class, so that the PlaceHistoryHandler can GWT.create() an instance of it and call its getToken method. The returned value will them be prepended with the PlaceTokenizer's @Prefix and a colon as a separator, and the resulting String is used as the history token.

Using a factory for your PlaceTokenizer

There are times where your PlaceTokenizer has a dependency on other objects, but there's no place for customization in the above algorithm, instantiating a PlaceTokenizer every time they need one and throwing it away right after that. Here comes the PlaceHistoryHandlerWithFactory: you'll inherit from this interface instead of PlaceHistoryHandler and then call setFactory with a factory (or provider) of PlaceTokenizers right before initializing it.

PlaceHistoryHandlerWithFactory takes a generic type argument, which the code generator will introspect to collect all zero-argument methods whose return type is assignable to PlaceTokenizer. The generated class will call these methods instead of using GWT.create() when it needs a PlaceTokenizer; the methods can also be annotated with @Prefix to override the annotation possibly present on the PlaceTokenizer subclass; finally, PlaceTokenizer classes that your factory can provide mustn't be specified in the @WithTokenizer annotation, which therefore becomes optional.

Your factory can really be any class or interface, which means you can even use a Ginjector if you're using GIN for dependency-injection.

Using your own mapper, without PlaceTokenizer

You're actually not required to GWT.create() a ProxyHistoryMapper, and rely on the generated code based on PlaceTokenizers, you can very well implement the interface yourself, the way you want it. And not only it is technically possible, but it is a supported use case (believe me on this one, I'm the one who submitted the patch).

What's next?

The next article will be about GWT 2.1 activities, which sits above places, abstracting events' handling, and is probably what the GWT team call the "MVP framework" even though, actually, it helps in doing MVP but doesn't enforce its use, and you'll probably also need to build MVP components that are not activities… Still, GWT 2.1 activities are a wonderful API to work with, stay tuned!

GWT 2.1 Places

Translation available in: French.

Updated 2010-10-16: updated to GWT 2.1.0.

Ray Ryan made the buzz last year at Google I/O 2009 with his Google Web Toolkit Architecture: Best Practices For Architecting Your GWT App session, but what made the buzz the most was probably less what was said than what was only briefly mentionned: the Place Service. Since then, many developers (me included) took a stab at it, but Google made it part of GWT proper in GWT 2.1.

What is a Place?

In any application, particularly web applications, which only rarely use the concept of window (and if you ask me, web app developers should try hard to turn this "rarely" into a "never"), you generally describe what you see as a place: "where am I?", "going to…", etc. (you'll also "find your bearings", "find your way", or "navigate").

Examples of places include: your mail inbox, the search results for "GWT places", the user profile for "t.broyer", the expense with id "abcdefgh", etc.

So the idea is to use that notion of place to manage navigation within the application, by firing place change events.

The PlaceService here serves as a bridge between those events and the browser's history management (it would deserve a dedicated article, but let's just say it's about make the "previous page" and "next page" browser buttons work, while keeping the application as a single web page). The PlaceService therefore is, and should remain, the only component in the application to manage the browser's history and react to its changes.

Debunking misconceptions

Before going into the details, let's make a few things clear first: places have nothing to do with MVP, and nothing to do with the notion of an application-wide event bus (which one is also orthogonal to MVP). You can use each one independently, without any one of the others. It's becoming a best practice to use them all at the same time, but they each address different needs. This also means you don't have to understand any of the other concepts Ray Ryan talked about in his session (MVP, event bus, command pattern for RPCs, etc.) to understand places.

So what does it look like in GWT 2.1?

GWT 2.1 materializes the PlaceService as two layers (places and activities), and optional integration with other GWT features (History for now, and RequestFactory to come in a future release); they live in the com.google.gwt.place.Place and com.google.gwt.activity.Activity modules respectively.

The core of GWT 2.1 places is the PlaceController, which you'll use to navigate from places to places, but let's start by examining what a Place looks like in GWT 2.1 and what it represents.

What is a GWT 2.1 Place?

In GWT 2.1, places are lightweight objects extending the Place abstract class. They're generally throwable and immutable, even though this is not required and there are some good reasons to use non-throwable places, as we'll see later (I can't see any compelling reason for using mutable places though).

You can define as many Place subclasses as you need, with or without associated "data" (the id of a record, the query of a search, etc.), and you'll instantiate a new place each time you'll navigate within your application. The Place class doesn't define any method, but subclasses are expected to correctly implement Object.equals(Object) and Object.hashCode().

Introducing the PlaceController

The PlaceController is an object that manages the current place (where you are) and navigation between places. Because of that, you should not have more than one PlaceController instance per application.

To allow you application to react to place changes (to actually update the UI and application state so it reflects the new place), the PlaceControler fires events on an event bus. You don't need to really understand the notion of event bus to continue reading; let's just say that instead of registering your event handlers on the PlaceController itself, you'll add them to another object (the event bus, of which there should also be a single instance at most throughout your application), and you'll initialize the PlaceController so that it fires events on this bus.

Your application's entry-point will therefore generally contain this kind of code:

  EventBus eventBus = new SimpleEventBus();
  PlaceController placeController = new PlaceController(eventBus);

By default, the PlaceController initializes with the current place set to Place.NOWHERE (that is, placeController.getWhere() will return Place.NOWHERE). To navigate to another place, you'll pass a Place instance to the PlaceController's goTo method:

  placeController.goTo(new MyPlace());

This will have the effect of changing the current place and then firing a PlaceChangeEvent on the event bus, which your components will listen to by registering a PlaceChangeEvent.Handler:

  eventBus.addHandler(PlaceChangeEvent.TYPE, new PlaceChangeEvent.Handler() {
    public void onPlaceChange(PlaceChangeEvent event) {
      Place newPlace = event.getNewPlace();
      …
    }
  });

Where to go now?

This was only an overview of the core of GWT 2.1 places, so you can grasp the underlying concepts.

I'll cover navigation's user-confirmation, integration with the browser's history (which also means bookmarkable places), and activities (a higher-level API which, among other things, helps in doing MVP) in companion articles.

Using Protobuf client-side with GWT

This is a follow-up post to Exploring using Protobuf in the browser.

There are many different approaches to using Protocol Buffers with GWT, both for messages and services.

The Message API

Each language supported natively by protoc (C++, Python and Java) has a different API for Messages:

  • Java uses a builder approach: each message class has a corresponding builder class; the builder instance can only be used once, to initialize a single message instance; only the builder is mutable, a message instance is always immutable.
  • In Python, a message instance is always mutable.
  • C++ follows the same approach as Python but takes advantage of the const keyword to eventually freeze an object, so if a field's type is a message (or string), you have to explicitly ask for a mutable or immutable instance.

These differences are guided by each language's features: C++ can contextually make an object immutable, Java cannot but a builder can easily be given access to the message internals, and finally Python is all about unlocked access to objects, even their internals (while this has changed a bit in recent versions).

Closure Library, because JavaScript has similar features as Python, uses the same approach of always mutable message instances.

GWT is both in the Java and the JavaScript lands, but because it looks like Java, I'd rather go with the same API as the native Protobuf Java API. I'd even use the exact same package and class names and take advantage of GWT's emulation feature (see Overriding one package implementation with another) to only implement the subset of the API that's translatable to JavaScript (i.e. everything that doesn't involve java.io). Moreover, using this approach, because the developer never actually sees the emulation code, the message and builders could eventually be the very same object, possibly a lightweight JavaScript Overlay Type (this of course would have implications on instanceof results). Using overlay types though would make it impossible to implement the Message.getDescriptor() method, limiting the API to the subset of MessageLite (but using optimize_for = LITE_RUNTIME rules out defining services)

Message serialization

In addition to being an IDL with code generators, Protobuf is also an efficient, "language-neutral, platform-neutral, extensible mechanism for serializing structured data". However, due to limitations of browser APIs, the binary format wouldn't be usable (or with a considerable overhead). The structured format that works the best in the browser is undoubtedly JSON, and GWT implementation of Protobuf couldn't be complete without built-in JSON ser/deserialization (and using insertion points, protoc code generator plugins can easily add the same toJSON/parse/mergeFrom APIs on the server-side too.

With GWT however, there's another serialization format: the one used by GWT RPC. I said previously that GWT RPC tightly couples the client and server codebase and would make it impossible to extend messages without deploying them in one go. This isn't completely true though: GWT RPC versions classes based on their fully-qualified name, the fully-qualified name of parent classes, and the name of each of these classes' fields; but when you use a custom field serializer, the serializer class is used instead, which generally doesn't have fields or parent class (as its methods have to be static). This means that such a serializer could very well implement its own "error recovery" algorithm to ignore unknown fields (and narrow-cast numbers, so that a field's type could be changed from e.g. byte to int without fearing exceptions, similar to how Protobuf's binary format works; the exception here would be longs, as they are emulated as a pair of doubles in GWT).

The RPC services

Starting with version 2.3.0, Protobuf warns against using the generic services API but instead use plugins to generate code specific to your RPC implementation. GWT has a pretty good RPC-over-HTTP implementation, so it'd probably be the best fit (even though I believe the generic API could be implemented on the client side, with an overhead comparable to GWT RPC, maybe even smaller if you serialize to/from JSON and keep the deserialized object as-is, in which case the native JSON.parse/stringify browser implementations could be used).

But actually, whichever the chosen API, the underlying implementation could be the other one; i.e. it's possible to implement Protobuf's generic services API on top the GWT RPC protocol, or the GWT RPC API on top of some some other serialization such as JSON (as already done in gwt-rpc-plus).

The major drawback with Protobuf's generic services API is that it relies on Protobuf reflexivity, and removing it from the API would actually make it too different from the original one to justify using it (what would be an RpcChannel without MethodDescriptor?)

Where to go now?

Well, experiment? And make compromises: Is the full Message API worth it if you could have a much lighter-weight implementation of MessageLite based on JavaScript Overlay Types? Is instanceof support a must-have? Should extensions be supported? Would it be a problem if the emulation of the Protobuf library used interfaces in place of the original classes in some cases? (it would allow the emulated message and builder be the same class)