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.