»
 
 
Articles in Code
February 09, 2010
»

Regarding GWT-MooTools

For those who don’t know, after spending a lot of time trying to write my own GWT-only animation framework and after trying to integrate Scriptaculous, later JQuery, I settled to MooTools as my animation library of choice and wrote small GWT wrapper around it.

Now along with already existing FX wrappers for:

  • Morph
  • Tween

Today I upgaded it to mootools 1.2.4 and added:

  • Slide
  • Reveal
  • Scroll

Live demo

gwt-mootools can be downloaded from project downloads, other stuff nearby.

February 01, 2010
»

GWT History Management With Places

This is a second post in two post series about History Management in GWT. In first part I introduced the definition of Place and few necessary “design patterns” which makes it easy to implement history aware rich applications in GWT. The only missing piece of puzzle I left till the next time was cleaning up the implementation of SimpleHistoryManager.

In first part the SimpleHistoryManager is the central compnent in whole application History architecture. It:

  • calls History.addItem(String)
  • handles history token value changes
  • handles application Events which should be turned in history items
  • fires application Events for each History Place

While for small applications this central history manager class may suffice, it is not flexible enough and it only grows in size as application functionalty grows. This “doesn’t scale”. We need to split HistoryManager in logical parts that can be easily managed independently. For history management, the smallest part is Place class and for each application place, Place implementation should:

  • fire application Events on place change
  • handle application Events which should be turned in History items

Also there are few things what Place implementations should not do:

  • parse, compare string tokens
  • create new string tokens
  • call History methods directly

Those tasks can be perfectly be abstracted away in Place library that can be reused (and improved separately) between projects.

It happens I’ve written Places library and the following will explain how to setup and use its public API. If you’re currious about implementation details, feel free to dig in to the sources.

Downloading

Currently Places is at 1.0-SNAPSHOT state. I’ll be releasing 1.0 soon.

Using Maven

If you’re using Maven, add the following repository to your pom (or better in your settings.xml / Nexus):

<repositories>
  <repository>
    <id>amateurinmotion</id>
    <name>amateurinmotion m2 repository</name>
    <url>http://www.amateurinmotion.com/repository</url>
  </repository>
</repositories>

And add dependencies:

<dependency>
  <groupId>com.ampatspell.places</groupId>
  <artifactId>places-client</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>com.ampatspell.places</groupId>
  <artifactId>places-client</artifactId>
  <version>1.0-SNAPSHOT</version>
  <classifier>sources</classifier>
  <scope>compile</scope>
</dependency>

Warning: Places library declares few dependencies which are not in central Maven repository like GIN, GWT, Guice version which works in AppEngine. They reside in my Maven repository and will be included in compile classpath. If it is not desired, maven dependency exclusions are your friends.

Manually

Places and its dependencies:

Now that you have all necessary jars we can move on GWT and GIN configuration.

Setup

Add the inherits to gwt.xml:

<module>
  <inherits name="com.ampatspell.bones.core.Core"/>
  <inherits name="com.ampatspell.places.Places"/>
</module>

Install PlacesModule in your GIN Module:

public class ExampleGinModule extends AbstractGinModule {

  @Override
  protected void configure() {
    // Bones (optional)
    install(new BonesCoreGinModule());
    bind(DispatchServiceAsync.class).to(DispatchServiceAsyncImpl.class);
    
    // Places Service
    install(new PlaceServiceModule());
    bind(PlacesLogger.class).to(GWTPlacesLogger.class);
    bind(EventBus.class).to(BaseEventBus.class); // or your EventBus implementation
  }
  
  @Provides
  @Singleton
  public List<Place> providePlaces() {
    List<Place> places = new ArrayList<Place>();
    return places;
  }  

}

If you don’t want to bring all Bones functionality (post about Bones library comming soon), you may install only PlacesModule and bind EventBus.class to your HandlerManager implementation that poses as EventBus in your application. No other dependencies exist.

Also, as we can see, there’s binding to empty List of Place instances bound. There we should list all application places.

Place

Lets start with Place interface and talk about what is Place scope is and what implementations should do:

public interface Place {

  /**
   * History token url sub-pattern for this {@link Place}.
   *
   * @return string pattern for {@link Place}. May be blank or null
   */
  String getPattern();

  /**
   * Returns if {@link Place#getPattern()} overrides it's parent pattern.
   *
   * @return <code>true</code> if pattern overrides parent, <code>false</code> otherwise
   */
  boolean overridesParent();

  /**
   * @return parent {@link Place} or null
   */
  Place getParent();

  /**
   * Parameters which will be added to token
   *
   * @return additional parameter names or null
   */
  String[] getAdditionalParameters();

  /**
   * Called before first place is invoked
   *
   * @param binding binding context for moving to next {@link Place} and 
   *                for registering event handlers
   */
  void bind(PlaceBindingContext binding);

  void unbind();

  /**
   * Called when History token matches given {@link Place} ir one of the 
   * child {@link Place}s.
   * <p/>
   * Note: {@code invocation.invoke()} <b>must</b> be called in each invoke call
   *
   * @param invocation context for getting current parameters (from pattern or from 
   *                   additional parameters) and continuing invocation chain
   */
  void invoke(PlaceInvocationContext invocation);

}

Place implementation does three things (three scopes):

  • Matching — provides information about History token pattern parts which this place manages
  • Binding — handles application Events which should add next History item
  • Invocation — fires application Events to restore place
Scope Method group Description
Matching getPattern() Relative History token pattern string
(may be blank or null)
Matching overridesParent() Whether pattern returned by getPattern() overrides
its parent pattern
Matching getParent() Parent Place (may be null)
Binding bind(PlaceBindingContext) Callback method for adding application Event handlers that should be
turned into new History items
Binding unbind() Invoked on HistoryService unbind. Nearly always useless
Invocation invoke(PlaceInvocationContext) Called when new history token matches this Place pattern
Binding & Invocation getAdditionalParameters() Additional parameter names of which values will be stored
after main token as name=value pairs (a la url parameters)
and should be added for consequent invocations

And my apologies for over-complicated explanation. As we’ll see later, this thing is easy to use.

Matching

Token matching is done using pattern and parent. A pattern can be composed by constant string parts and parameters using {name} syntax. If Place declares:

Pattern Parent Overrides parent
/person/show/{key} null false

The place will match:

Token Matches Key value
/person/show/zeeba true “zeeba”
/person/show/larry true “larry”
/person/show/ false
/person/show/zeeba/ false1

1 — the default parameter matcher uses the /^([a-zA-Z0-9\-_]+)(.*)$/ regex to find parameter value range in string. Let me know if it is too limiting.

When Place implementation returns other place as its parent things start to get more interesting. Those are all Place patterns used in demo application:

Place Pattern Parent Overrides parent
DefaultRedirectPlace("/index") null null false
IndexPlace /index SectionPlace true
PeoplePlace /people SectionPlace true
ShowPersonPlace /show PersonKeyPlace false
EditPersonPlace /edit PersonKeyPlace false
NewPersonPlace /new PersonPlace false
Parents
BasePlace null null false
SectionPlace /{section} BasePlace false
PersonPlace /person BasePlace false
PersonKeyPlace /{key} PersonPlace false

The resuling “full” place patterns are:

places.png

By the way, this UI is included in library. See “Registered Places” section below.

Where for example /person/zeeba/show will match ShowPersonPlace that has the following full parent-child hierarchy:

  • ShowPersonPlace
  • PersonKeyPlace
  • PersonPlace
  • BasePlace

Each of parent places takes a part in all three Place scopes: matching, binding and invocation. It makes sense because this way place binding and invocation can be greatly simplified for end-level Place implementations. Multiple Places can share common parent that can also be bound as @Singleton.

Also while all shown patterns are “one-slash with string or parameter”, its perfectly fine to have pattern with more than one parameter with some delimiter (“/” or something else) between (for example /list/{all}/{page} with PeoplePlace as parent and few additional parameters will work just fine).

Invocation

When Place matches current History token, invoke(PlaceInvocationContext) callbacks are invoked for whole this Place parent-child hierarchy. Invocations are starting with root parent.

For ShowPersonPlace invocation chain contents are:

// BasePlace
String title = invocation.get("title", "Places Example");
invocation.fireEvent(new SetTitleEvent(title));
invocation.proceed();

// PersonPlace
invocation.fireEvent(new WorkspaceSetContentEvent(people, new Command() {
  public void execute() {
    invocation.fireEvent(new MenuSetActiveEvent("people"));
    invocation.proceed();
  }
}));

// PersonKeyPlace
String key = invocation.get("key");
invocation.fireEvent(new ListSetActiveEvent(key));
invocation.proceed();

// ShowPersonPlace
final String key = invocation.get("key");
invocation.fireEvent(new PeopleSetContentEvent(show, new Command() {
  public void execute() {
    invocation.fireEvent(new PersonShowEvent(key));
  }
}));

PlaceInvocationContext (source) has the proceed() method which needs more clarification.

As we’ve seen in post’s first part, Place setup Events must not be fired one after another in one “batch”, instead next Event should only be fired after previous event is handled and presenter hierarchy is able to handle Events (see On-Ready Event Callback).

For this to work in Place parent-child hierarchy PlaceService needs to be notified when next Place.invoke(PlaceInvocationContext) can be safely called. This is done using proceed() method.

So while BasePlace invokes proceed() immediately, PersonPlace invokes it only after PeoplePresenter is bound and ready to receive events because otherwise ListSetActiveEvent won’t be handled.

Other PlaceInvocationMethods should be obvious (see javadocs for interface for more info).

Binding

Place.bind(PlaceBindingContext) callback is used to register application specific Event handlers for events which should be turned into the places. This is done using provided PlaceBindingContext which allows to register to EventBus and takes care of removing handlers on PlacesService unbind. Also PlaceBindingContext (sources) declares StateBuilder state() method which allows in declared event handlers perform transition to next History place (add new History item). StateBuilder (sources) allows to set values for declared pattern parameters and also parameters that are added after “?” as key=value pairs).

One of in ShowPersonPlace.onBind declared event handlers is:

binding.addHandler(PersonShowPlaceEvent.getType(), new PersonShowPlaceHandler() {
  public void onPersonShowPlace(PersonShowPlaceEvent event) {
    binding.state().set("key", event.getKey()).invoke();
  }
});

So when ShowPersonPlaceEvent is fired, this is handled here and History.newItem is called with ShowPersonPlace full history token and event provided person key.

/person/{key}/show
/person/zeeba/show

At some later time StateBuilder will have invokeCurrent() method which will allow to stay in “current” place and only change some additional parameters.

Additional Parameters

Sometimes it can be useful to declare some parameters as “persistent” between place invocations. grid=true comes in mind as a decent example. If all Place implementations share directly or indirectly single BasePlace parent with grid as a additional parameter, the grid value will be added for each and every place invocation and the same BasePlace can fire SetGridVisible event in invoke to show the grid (useful for laying out UI components).

Demo application has title declared as additional parameter in BasePlace and in invoke it fires SetTitleEvent:

@Singleton
public class BasePlace extends AbstractPlace {

  @Inject
  protected BasePlace() {
    addAdditionalParameter("title");
  }

  @Override
  public void onBind(final PlaceBindingContext binding) {
    binding.addHandler(SetTitlePlaceEvent.getType(), new SetTitlePlaceHandler() {
      public void onSetTitlePlace(SetTitlePlaceEvent event) {
        binding.state().set("title", event.getTitle()).invoke();
      }
    });
  }

  @Override
  public void onInvoke(PlaceInvocationContext invocation) {
    String title = invocation.get("title", "Places Example");
    invocation.fireEvent(new SetTitleEvent(title));
    invocation.proceed();
  }

}

To see the functionality in action, open demo application with ‘Additional Parameters’ as title and click on few links. The result is that the string “Additional Parameters” follows the place changes without explicit set in each binding().state() call.

Registered Places

Library also contains “Registered Places” UI for visualizing currently registered Placepattern bindings in application. Basic usage:

import com.ampatspell.places.client.api.PlacesService;
import com.ampatspell.places.client.ui.places.PlacesPresenter;

public class Example implements EntryPoint {

  public void onModuleLoad() {
    ExampleGinjector injector = GWT.create(ExampleGinjector.class);

    PlacesService placeService = injector.getPlacesService();
    placeService.bind();

    PlacesPresenter placesPresenter = injector.getPlacesPresenter();
    placesPresenter.bind();
    RootPanel.get().add(placesPresenter.getView().getViewWidget());
    placesPresenter.show();
  }

}

EOF

I hope this will help someone at least a bit to understand this approach of GWT History management in general and use of PlacesService. I’ve spent a lot of time trying to come up with some simple and useful history management guidelines for my projects and this is best approach I’m using with good results.

One more time few links:

Questions? Feel free to mail me directly to email address which can be found in about section.

January 28, 2010
»

Mercurial Branch in Bash Prompt

Git has nice bash function for showing current branch and status in bash prompt. Here is the branch only version for Mercurial:

hg_branch.png

__hg_ps1 ()
{
  if [ "$(hg root 2> /dev/null)" ]; then
    printf "$1" "$(hg branch)"
  fi
}

export PS1='\u:\w$(__hg_ps1 " (%s)\$ '

and PS1 version with colors:

export PS1='\u:\w$(__hg_ps1 " \[\033[1;31m\](%s)\[\033[0m\]")\$ '
January 17, 2010
»

GWT History Management

This is a first post in two post series about one history management approach for non-trivial GWT applications. This approach I deem done right (in contrast to good enough).

In the following I assume that general application architecture follows MVP (or similar) design and uses some global event or notification system (for example EventBus based on HandlerManager or something similar to NSNotificationCenter) used in Cocoa applications. Examples has GIN annotations where appropriate.

Fictional Application

Lets agree on one concrete application as a basis of discussion of history and places.

history-1/01.png

The application consists of two sections (managed by “root” WorkspacePresenter) that are represented with two top tabs, each section has root presenter and people section has nested child presenters:

Section Container Presenter
Index Content Index
People Master Person list
Detail Blank
Show person
Edit person

Screen shot is shows People section with “Show person” detail presenter open, linked site uses Places library (see “Terrible Footnote” below, but basic concepts described here apply).

History token — Place

From previous table we can gather a list of application states where permanent links (using history token) are needed. Lets call those states places.

Section State History token / Place pattern
Index /index
People No person selected /people
Showing person /person/{key}/show 1
Showing edit person form /person/{key}/edit 1

1 where {key} is Person model primary key.

In GWT the history management can be implemented using History singleton class what manages the part of the URL that comes after #. It allows us to:

  • register to token value changes,
  • change token (that will fire value change event) and
  • fire current token state.

When History#fireCurrentHistoryState() is called, it notifies handlers about new token value. Token itself is a String that can be parsed and reacted upon (think routes in Rails applications or Servlet mapping in web.xml).

This can be done in HistoryService class that must know about each and every history token pattern used in application and should be able to react on them. This way it is easy to implement GWT.runAsync based application code splitting where application initial download contains only HistoryService and split point loaders that initiates additional code loading when needed.

SimpleHistoryManager

Lets take a look at History manager simplified implementation (in next blog post this class will be replaced with sane implementation, other concepts still apply):

@Singleton
public class SimpleHistoryManager implements ValueChangeHandler<String> {

  private final EventBus eventBus;

  @Inject
  public SimpleHistoryManager(EventBus eventBus) {
    this.eventBus = eventBus;
  }

  public void bind() {
    History.addValueChangeHandler(this);
    History.fireCurrentHistoryState();
  }

  public void onValueChange(ValueChangeEvent<String> stringValueChangeEvent) {
    String token = stringValueChangeEvent.getValue();
    onTokenChanged(token);
  }

  private void onTokenChanged(String token) {
    if (token.equals("/index") || token.equals("")) {
      showIndexSection();
    } else if (token.equals("/people")) {
      showPeopleSection();
    } else if (token.startsWith("/person/")) {
      String[] array = token.split("/");
      String key = array[2];
      String action = array[3];

      if (action.equals("/show")) {
        showPerson(key);
      } else if (action.equals("/edit")) {
        showEditPerson(key);
      }
    }
  }

  private void showIndexSection() {
  }

  private void showPeopleSection() {
  }

  private void showPerson(String key) {
  }

  private void showEditPerson(String key) {
  }

}

When bind() is called, the instance registers itself as token value change handler and fires first value change event which in turn invokes onTokenChanged() for the first time in application current life cycle. onTokenChanged parses (parsing is incomplete and without any error handling) token string and delegates actual work to methods listed below. Fine, what’s next?

Events.

To presenter “Index section”:

  • WorkspacePresenter must show IndexPresenter by setting IndexPresenter#getView() to it’s View#setContentView(BaseView),
  • MenuPresenter must set “index” as active menu item.

Menu is easy:

eventBus.fireEvent(new MenuSetActiveEvent("index"));

But before we implement WorkspacePresenterIndexPresenter relations we have one design decision to make about Presenter hierarchy.

Presenter Hierarchy

Does WorkspacePresenter keeps reference to Provider<IndexPresenter> and all other presenter providers it may need?

It surely can be done (by using SectionService#getSectionByKey(String) or something like that) but it unnecessary complicates presenter and sometimes makes it harder to implement history support and GWT.runAsync’able code splitting. Instead of WorkspacePresenter (and presenters in general), HistoryManager should manage dynamic presenter hierarchy. By dynamic I mean those child presenters that can be replaced by different presenters in application runtime in contrast to static ones that can be safely bound in parent — for example MenuPresenter and LogPresenter is bound directly in WorkspacePresenterImpl.

So now we need an event that SimpleHistoryManager fires and WorkspacePresenter handles, gets Presenter instance from it, calls bind() and sets in its own View as sub-view:

BasePresenter<?> indexPresenter = ...;
eventBus.fireEvent(new WorkspaceSetContentEvent(indexPresenter));
public void onWorkspaceSetContent(final WorkspaceSetContentEvent event) {
  setContent(event.getPresenter());
}

public void setPresenter(BasePresenter<?> presenter) {
  presenter.bind();
  view.setContentView(presenter.getView());
  presenter.show();
}

But there is one small caveat with HandlerManager which nearly always is used as EventBus implementation. WorkspacePresenter content Presenter may register itself to @Singleton EventBus as an event handler. But if event handler is added to HandlerManager inside fired event from the same HandlerManager, that handler will be live only after original event handler has returned.

Basically it means that:

eventBus.addHandler(WorkspaceSetContentEvent.getType(), new WorkspaceSetContentHandler() {
  public void onWorkspaceSetContent(WorkspaceSetContentEvent event) {

    // this handler will handle PersonShowEvent only after this 
    // WorkspaceSetContentEvent handler will return
    eventBus.addHandler(PersonShowEvent.getType(), new PersonShowHandler() {
      public void onPersonShow(PersonShowEvent event) {
      }
    });

    // this event won't be handled by previous handler
    eventBus.fireEvent(new PersonShowEvent("foo"));
  }
});

To overcome this we need small design pattern. I’ll even give it a fancy name.

On-Ready Event Callback

Simply put it is an GwtEvent with additional Command parameter. This Command callback must be called when presenter’s bind() is called and bound presenter is ready to handle events (by using DeferredCommand if needed).

public class WorkspaceSetContentEvent extends GwtEvent<WorkspaceSetContentHandler> {

  // TYPE, ivars removed -- less noise

  public WorkspaceSetContentEvent(PresenterProvider<?> presenter, Command callback) {
    this.presenter = presenter;
    this.callback = callback;
  }

  public PresenterProvider<?> getPresenter() {
    return presenter;
  }

  public Command getCallback() {
    return callback;
  }

}

See WorkspaceSetContentEvent for full source code of this Event.

Lets ignore PresenterProvider interface for a moment — it needs it’s own small section.

Now we can implement all SimpleHandlerManager#show* methods:

private void showIndexSection() {
  fireMenuSetActive("index");
  fireWorkspaceSetContent(indexPresenterProvider, null);
}

private void showPeopleSection() {
  showPeopleSection(blankPresenterProvider, null, null);
}

private void showPerson(final String key) {
  showPeopleSection(showPresenterProvider, key, new Command() {
    public void execute() {
      eventBus.fireEvent(new PersonShowEvent(key));
    }
  });
}

private void showEditPerson(final String key) {
  showPeopleSection(editPresenterProvider, key, new Command() {
    public void execute() {
      eventBus.fireEvent(new PersonEditEvent(key));
    }
  });
}

private void showPeopleSection(final PresenterProvider<?> content, final String key, 
    final Command command) {
    
  fireMenuSetActive("people");
  fireWorkspaceSetContent(peoplePresenterProvider, new Command() {
    public void execute() {
      eventBus.fireEvent(new ListSetActiveEvent(key));
      eventBus.fireEvent(new PeopleSetContentEvent(content, command));
    }
  });
}

private void fireMenuSetActive(String key) {
  eventBus.fireEvent(new MenuSetActiveEvent(key));
}

private void fireWorkspaceSetContent(PresenterProvider<?> presenter, Command command) {
  eventBus.fireEvent(new WorkspaceSetContentEvent(presenter, command));
}

And for example WorkspaceSetContentHanlder inside WorkspacePresenter looks like this:

public void onWorkspaceSetContent(final WorkspaceSetContentEvent event) {
  content.set(event.getPresenter(), event.getCallback());
}

Next we need to define what is:

  • content from previous handler code listing,
  • PresenterProvider<P extends BasePresenter<?>>

They both forms one simple concept described in next section.

PresenterProvider & PresenterSwitch

Let’s start with some reasons behind PresenterProvider interface and what part it plays in overall architecture. Let’s return to two place implementations: “showing person” and “showing edit person form”:

private void showPerson(final String key) {
  showPeopleSection(showPresenterProvider, new Command() {
    public void execute() {
      eventBus.fireEvent(new PersonShowEvent(key));
    }
  });
}

private void showEditPerson(final String key) {
  showPeopleSection(editPresenterProvider, new Command() {
    public void execute() {
      eventBus.fireEvent(new PersonEditEvent(key));
    }
  });
}

private void showPeopleSection(final PresenterProvider<?> content, final Command command) {
  fireMenuSetActive("people");
  fireWorkspaceSetContent(peoplePresenterProvider, new Command() {
    public void execute() {
      eventBus.fireEvent(new PeopleSetContentEvent(content, command));
    }
  });
}

As we can see from code, both place implementations sets PeoplePresenter as WorkspacePresenter content and only changes PeoplePresenter content.

For the time being we have taken into consideration only one of two possible times when History value change handler is invoked:

  • after History.fireCurrentHistoryState() as a part of EntryPoint#onModuleLoad invocation,
  • any time after History.newItem(String token) is called.

When application is launched, WorkspacePresenter content view will be empty. It is History manager responsibility to fill it with requested-by-history-token Presenter-View. But when switching for example from “Showing person” to “Showing edit person form” places only PersonPresenter content needs to be switched from ShowPresenter to EditPresenter. The WorkspacePresenter content must not be replaced by new instance of the same PersonPresenter (otherwise content will blink because of DeferredCommand that is needed after Presenter#bind() and just because this is simply plain useless).

Though SimpleHistoryManager shouldn’t and doesn’t keep track of current presenter hierarchy the decision if “current” presenter in all presenter hierarchy levels needs to be done Presenters side because it is easier to implement and allows us to modify presenter hierarchy also without history support if such need arises (as not all application states needs history token).

PresenterProvider

GIN allows to inject class dependencies in two ways:

  • Instance directly
  • Instance via provider (using Provider<T>)

The Provider<T> interface declaration is:

public interface Provider<T> {
  T get();
}

This interface requires us construct a new Presenter in order to get the instance class that can be used in comparison between “current” Presenter and Presenter which is received as a part of *SetContentEvent. To remove this possibly unnecessary Presenter construction the minor extension to Provider<T> interface is needed:

public interface PresenterProvider<P extends BasePresenter<?>> 
  extends Provider<P>, HasInstanceClass {
}

public interface HasInstanceClass {
  Class<?> getInstanceClass();
}

Then by using PresenterProvider<P> we can efficiently handle *SetContentEvents:

private Class<?> currentPresenterInstanceClass;

public void onAnySetContentEvent(AnySetContentEvent event) {
  PresenterProvider<?> presenterProvider = event.getPresenter();

  Class<?> nextInstanceClass = presenterProvider.getInstanceClass();
  if (currentPresenterInstanceClass != nextInstanceClass) {
    BasePresenter<?> next = presenterProvider.get();
    currentPresenterInstanceClass = nextInstanceClass;
    // unbind previous presenter
    // bind, view.setSomethingView(next.getView()), show
    // DeferredCommand.addCommand(event.getCallback());
  }
}

Now we can construct and initialize Presenter instance only if it is not the same as current. But there is too much noise in event handler.

PresenterSwitch

Let’s create PresenterSwitch helper class that (fully, comparing to previous code snippet) implements and encapsulates the logic which resides in onAnySetContentEvent in previous snippet:

public class PresenterSwitch {

  public interface SwitchCallback {
    void onSetView(BasePresenter<?> presenter);
  }

  private SwitchCallback callback;
  private Class<?> presenterClass;
  private BasePresenter<?> presenter;

  public void bind(SwitchCallback callback) {
    this.callback = callback;
  }

  public void unbind() {
    callback = null;
    presenterClass = null;
    if (presenter != null) {
      presenter.unbind();
      presenter = null;
    }
  }

  public void set(PresenterProvider<?> provider, Command onBoundCommand) {
    Class<?> instance = provider != null ? provider.getInstanceClass() : null;
    if (presenterClass != instance) {
      final BasePresenter<?> next = provider != null ? provider.get() : null;

      if (presenter != null) {
        presenter.unbind();
      }

      presenter = next;
      presenterClass = instance;

      if (next != null) {
        next.bind();
        callback.onSetView(next);
        next.show();
        if (onBoundCommand != null)
          addDeferredCommand(onBoundCommand);
      } else {
        callback.onSetView(null);
        if (onBoundCommand != null)
          onBoundCommand.execute();
      }
    } else {
      if (onBoundCommand != null)
        onBoundCommand.execute();
    }
  }

  private void addDeferredCommand(Command command) {
    DeferredCommand.addCommand(command);
  }

}

And bind it inside WorkspacePresenter:

public class WorkspacePresenterImpl extends AbstractBasePresenter<WorkspaceView> 
  implements WorkspacePresenter, WorkspaceSetContentHandler {

  private final PresenterSwitch content = new PresenterSwitch();

  @Inject
  public WorkspacePresenterImpl(WorkspaceView view, EventBus eventBus) {
    super(view, eventBus);
  }

  @Override
  public void onBind() {
    register(eventBus.addHandler(WorkspaceSetContentEvent.getType(), this));
    content.bind(new SwitchCallback() {
      public void onSetView(BasePresenter<?> presenter) {
        view.setContentView(presenter != null ? presenter.getView() : null);
      }
    });
  }

  @Override
  public void onUnbind() {
    content.unbind();
  }

  @Override
  public void onShow() {
  }

  public void onWorkspaceSetContent(final WorkspaceSetContentEvent event) {
    content.set(event.getPresenter(), event.getCallback());
  }

}

The same goes with PeoplePresenter and its PeopleSetContentEvent.

Lastly we need to construct PresenterProvider instances for each Presenter in SimpleHistoryManager so lets create a PresenterProviderFactory interface:

public interface PresenterProviderFactory {

  <P extends BasePresenter<?>> PresenterProvider<P> create(Class<?> clazz, 
                                                           Provider<P> provider);

}

and define full constructor for SimpleHistoryManager:

private final EventBus eventBus;
private final PresenterProvider<IndexPresenter> indexPresenterProvider;
private final PresenterProvider<PeoplePresenter> peoplePresenterProvider;
private final PresenterProvider<BlankPresenter> blankPresenterProvider;
private final PresenterProvider<ShowPresenter> showPresenterProvider;
private final PresenterProvider<EditPresenter> editPresenterProvider;

@Inject
public SimpleHistoryManager(EventBus eventBus, PresenterProviderFactory f,
                            Provider<IndexPresenter> indexPresenterProvider,
                            Provider<PeoplePresenter> peoplePresenterProvider,
                            Provider<BlankPresenter> blankPresenterProvider,
                            Provider<ShowPresenter> showPresenterProvider,
                            Provider<EditPresenter> editPresenterProvider) {
  this.eventBus = eventBus;

  this.indexPresenterProvider = f.create(IndexPresenter.class, indexPresenterProvider);
  this.peoplePresenterProvider = f.create(PeoplePresenter.class, peoplePresenterProvider);
  this.blankPresenterProvider = f.create(BlankPresenter.class, blankPresenterProvider);
  this.showPresenterProvider = f.create(ShowPresenter.class, showPresenterProvider);
  this.editPresenterProvider = f.create(EditPresenter.class, editPresenterProvider);
}

Looks terrible, doesn’t it? See “Terrible Footnote” below.

Also note that get() may or may not be instance of getInstanceClass(). This actually calls for rename of getInstanceClass() to something different more adequate.

Changing place — Place Events

So we have implemented the complicated side of history management — reaction to history tokens. Last thing what’s missing is adding new history items.

If SimpleHistoryService parses history token, it also must create new tokens to encapsulate token string related functionality in one place and to hide token strings from other parts of application. If it creates tokens, it needs to know when create them. So we need few new events that can be fired from application presenters and handled by SimpleHistoryService. Full list for this application is:

  • MenuClickEvent
  • PeopleShowPlaceEvent
  • PeopleEditPlaceEvent
  • PersonShowPlaceEvent

For example MenuClickEvent is fired from MenuPresenter:

String key = ...;
eventBus.fireEvent(new MenuClickEvent(key)); 

And other events are fired similarly. Lets add bindHandlers() method to service and call it from bind():

public void bind() {
  History.addValueChangeHandler(this);
  History.fireCurrentHistoryState();

  bindHandlers();
}

private void bindHandlers() {
  eventBus.addHandler(PeopleShowPlaceEvent.getType(), new PeopleShowPlaceHandler() {
    public void onPeopleShowPlace(PeopleShowPlaceEvent event) {
      newItem("/people");
    }
  });
  eventBus.addHandler(PersonEditPlaceEvent.getType(), new PersonEditPlaceHandler() {
    public void onPersonEditPlace(PersonEditPlaceEvent event) {
      newItem("/person/" + event.getKey() + "/edit");
    }
  });
  eventBus.addHandler(PersonShowPlaceEvent.getType(), new PersonShowPlaceHandler() {
    public void onPersonShowPlace(PersonShowPlaceEvent event) {
      newItem("/person/" + event.getKey() + "/show");
    }
  });
  eventBus.addHandler(MenuClickEvent.getType(), new MenuClickHandler() {
    public void onMenuClick(MenuClickEvent event) {
      newItem("/" + event.getKey());
    }
  });
}

private void newItem(String token) {
  History.newItem(token);
}

Each of those event handlers will add new History item that will fire History value change handler logic inside onTokenChanged() method.

And this prototype of history aware application is working just fine.

That Terrible Footnote

Regarding those ugly SimpleHistoryManager bindHandlers(), constructor and string parsing: next blog post will be about Places library which will replace SimpleHistoryManager with more sophisticated solution — list of hierarchic Place instances where each manages only few Presenter providers, few events and only sub-part of history token pattern with or without parameters.

Update: Second post is online

January 06, 2010
»

My GWT & AppEngine Toys

For some time I’ve been building complete stack of tools for GWT projects hosted on Google AppEngine. This includes:

  • Maven plugin for AppEngine and GWT 2.0
  • Maven archetype for quick start
  • gaeds — easy to use AppEngine DataStore wrapper library
  • bones-client — library what implements MVP, EventBus and Command pattern (Also known as Action pattern in GWT corner of the world)
  • bones-appengine — library what provides Action server-side part, AppEngine JUnit TestRunner and so on
  • places — GWT library for History Management
  • bones-validator — GWT and Server-side Validation framework with shared definition
  • gwt-mootools — GWT Wrapper for MooTools Animation classes

All of those things are still in SNAPSHOT phase but I’m using them in multiple projects.

To try Bones, Gaeds (unfortunately this archetype doesn’t yet have Places library integrated) make sure you have latest Maven and run:

mvn archetype:generate -DarchetypeCatalog=http://www.amateurinmotion.com/repository
Choose archetype:
1: http://www.amateurinmotion.com/repository -> google-quickstart-archetype (Google GWT & AppEngine Web App)
2: http://www.amateurinmotion.com/repository -> bones-google-quickstart-archetype (Google GWT & AppEngine Web App With Bones and Gaeds)
Choose a number:  (1/2): 2
Define value for groupId: : som.something
Define value for artifactId: : something
Define value for version:  1.0-SNAPSHOT: : 
Define value for package:  som.something: : 
Confirm properties configuration:
groupId: som.something
artifactId: something
version: 1.0-SNAPSHOT
package: som.something
 Y: : y
cd something
mvn install

At this point you can run project in GWT Development Mode with AppEngine launcher:

cd something-gwt
mvn google:gwt-run

Or run compiled application in AppEngine Development server alone:

cd something-war
mvn google:appengine-run

Or deploy to AppEngine (make sure appengine-war.xml has correct id and version)

cd something-war
mvn google:appengine-deploy

In case you’re wondering, plugin supports multiple GWT modules.

More info

Have any questions? Feel free to reach me using twitter @ampatspell or email what can be found in about page.

January 04, 2010
»

GWT History Manager Almost Done

The same I wrote few days ago. Now with better API:

// One actual "place" in app. This class can handle some events and `invoke` itself 
// then handle it's place request no matter if it comes from History string token or 
// place change in app.
@Singleton
public class ShowPersonPlace implements Place {

  private final PresenterProvider<PeoplePresenter> people;
  private final PresenterProvider<ShowPresenter> show;

  @Inject
  public ShowPersonPlace(PresenterProviderFactory f, Provider<PeoplePresenter> people, 
      Provider<ShowPresenter> show) {
    // PresenterProvider allows reuse of already bound presenter. More on this later.
    this.people = f.create(PeoplePresenter.class, people);
    this.show = f.create(ShowPresenter.class, show);
  }

  public String getPattern() {
    // matches for example "/person/show/zeeba" history token and 
    // creates that token from {"key"=>"zeeba"} parameters
    return "/person/show/{key}";
  }

  public boolean isPatternAbsolute() {
    // Will be useful when parent-child relationships will be implemented in Place.
    // Place will be able to use <parent pattern> + <this pattern> for matching.
    return true;
  }

  // The "application" side of history. When application fires some event this Place can
  // handle it and cause History.newItem be called.
  public void bind(final PlaceBindingContext binding) {
    binding.addHandler(ListClickEvent.getType(), new ListClickHandler() {
      public void onListClick(ListClickEvent event) {
        navigateTo(binding, event.getKey());
      }
    });

    binding.addHandler(ShowPersonEvent.getType(), new ShowPersonHandler() {
      public void onShowPerson(ShowPersonEvent event) {
        navigateTo(binding, event.getKey());
      }
    });
  }

  private void navigateTo(PlaceBindingContext binding, String key) {
    // Takes current history state (no matter if its this Place or some other) and 
    // overwrites parameter(s) then invokes it what calls History.newItem under the hood.
    binding.state().set("key", key).invoke();
  }

  public void unbind() {
    // binding.addHandler takes care of HandlerRegistration but if there's need to 
    // unbind something else, this can be done here.
  }

  // This method is called when History state has changed and requested 
  // token matches given Place.
  public void invoke(final PlaceInvocationContext invocation) {
    // if place pattern has parameters in it (/foo/{bar} -- bar is parameter)
    final String key = invocation.get("key");

    // Events with Command on completion (sometimes wraps DeferredCommand to 
    // escape current event execution stack).
    // fireEvent method is delegate to EventBus. here just to simplify things a little.
    invocation.fireEvent(new WorkspaceSetContentEvent(people, new Command() {
      public void execute() {
        // this "people" will come from somewhere when 
        // parent-child relationships will be implemented
        invocation.fireEvent(new MenuSetActiveEvent("people"));
        invocation.fireEvent(new PeopleSetContentEvent(show, new Command() {
          public void execute() {
            invocation.fireEvent(new ListSetActiveEvent(key));
            invocation.fireEvent(new PersonShowEvent(key));
          }
        }));
      }
    }));
  }

}

On my TODO list:

  • Place parent-child relationships (all Place implementations shouldn’t fire WorkspaceSetContentEvent for example)
  • 100% Test coverage
  • Nice AbstractPlace class what implements Place interface but allows accessing PlaceBindingContext and PlaceInvocationContext methods directly.
  • Release as a module in bones library.

Live demo

January 03, 2010
»

Running guess-renames on Mac OS X

Guess-renames is nifty Mercurial extension (and standalone tool) written by Colin Barrett.

I’m not really that much familiar with Python that’s why I had a bit of trouble getting it to work so for those like me here is step by step instructions:

Get guess-renames

hg clone ssh://hg@bitbucket.org/cbarrett/guess-renames/

Try running tests

make tests

If this fails miserably with exceptions mentioning setuptools, install them.

Install Setuptools (if needed)

wget http://peak.telecommunity.com/dist/ez_setup.py
sudo python ./ez_setup.py

Install guess-renames

Tests should now pass. If so install:

make tests
sudo python ./setup.py install

Add guessrenames.hgext

add the following to ~/.hgrc:

[extensions]
guessrenames.hgext=

Note: If you already have [extensions] section, just add guessrenames to that one.

Done

hg addremove -g

For more information see guess-renames project page

December 29, 2009
»

GWT History Management (Idea)

Still thinking about API. But here is sneak peak of it:

public static class ShowSectionRoute implements Route {

  public Route getParent() {
    return null;
  }

  public String getPath() {
    return "/{section}";
  }

  public void handle(final HandleContext ctx) {
    ctx.register(ShowSectionEvent.getType(), new ShowSectionHandler() {
      public void onShowSection(ShowSectionEvent event) {
        ctx.param("section", event.getSection().name().toLowerCase());
      }
    });
  }

  public void perform(final PerformContext ctx) {
    final Section section = Section.valueOf(ctx.param("section").toUpperCase());
    ctx.register(SectionShownEvent.getType(), new SectionShownHandler() {
      public void onSectionShown(SectionShownEvent event) {
        if (event.getSection() == section) {

          // invokes ShowPersonRoute as it is child route for this one
          ctx.next();
        }
      }
    });
    ctx.fire(new ShowSectionHistoryEvent(section));
  }

}
public static class ShowPersonRoute implements Route {

  private ShowSectionRoute parent;

  public ShowPersonRoute(ShowSectionRoute parent) {
    this.parent = parent;
  }

  public Route getParent() {
    return parent;
  }

  public String getPath() {
    return "/show/{key}";
  }

  public void handle(final HandleContext ctx) {
    ctx.register(ShowPersonEvent.getType(), new ShowPersonHandler() {
      public void onShowPerson(ShowPersonEvent event) {
        ctx.param("key", event.getKey()).run();
      }
    });
  }

  public void perform(final PerformContext ctx) {
    String key = ctx.param("key");
    ctx.fire(new ShowPersonHistoryEvent(key));
  }

}
// Some presenter fires event:
eventBus.fireEvent(new ShowPersonEvent(personKeyAsString));

// ShowPersonRoute handles it and updates route
// History.addItem with "/people/show/<personKey>" is set
// ShowPerson.getParent() route perform() is called what fires ShowSectionHistoryEvent after 
// section is visible (it can be behind GWT.runAsync) ctx.next() is called. 
// It invokes ShowPerson#handle() what fires ShowPersonHistoryEvent with the same person key

// some persenter handles event:
public void onShowPersonHistoryEvent(ShowPersonHistoryEvent e) {
  String key = e.getKey();
}

More on this soon.

December 24, 2009
»

AppEngine BlobStore With Guice

Today I finally started to play with BlobStore introduced in AppEngine 1.3.0. Currently this service is in “experimental” stage (the same is for Task Queue) but works fine.

The only problem I came across was 404 on BlobStore upload success servlet what I had configured using Guice Servlet module:

serve("/upload/finished").with(UploadFinishedServlet.class);

Guice servlet module is bound to Servlet container infrastructure using filter and that filter is routing requests to actual servlets. But for some reason (at least on AppEngine dev server) the request to the callback path bypasses filters and Jetty reports 404. I came up with this solution:

1. declare upload URL callback servlet in web.xml

<servlet>
  <servlet-name>uploadFinished</servlet-name>
  <servlet-class>com.foo.servlet.UploadFinishedServlet</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>uploadFinished</servlet-name>
  <url-pattern>/upload/finished</url-pattern>
</servlet-mapping>

2. create upload URL with that path

// bound to "/upload/finished", see below
@Named("uploadFinishedPath") String uploadFinishedPath;

BlobStoreService bs = blobStoreServiceProvider.get();
String url = bs.createUploadUrl(uploadFinishedPath);

3. in servlet process uploaded BlobKeys and redirect to guice managed servlet

public class UploadFinishedServlet extends HttpServlet {

  public static final String REDIRECT_TO = "/upload/commit";
  public static final String KEY_PARAMETER = "key";
  public static final String FILE_FIELD = "file";

  @Override
  protected void service(HttpServletRequest req, HttpServletResponse resp) 
      throws ServletException, IOException {
      
    BlobStoreService blobStoreService = BlobstoreServiceFactory.getBlobstoreService();
    Map<String, BlobKey> keys = blobStoreService.getUploadedBlobs(req);
    BlobKey key = keys.get(FILE_FIELD);

    String parameters = getParameters(key);
    resp.sendRedirect(REDIRECT_TO + parameters);
  }

  private String getParameters(BlobKey key) {
    if (key != null) {
      return format("?%s=%s", KEY_PARAMETER, key.getKeyString());
    } else {
      return "";
    }
  }

}

4. In Guice servlet module bind servlet what responds to redirect url

bindConstant().annotatedWith(named("uploadFinishedPath")).to("/upload/finished");
bindConstant().annotatedWith(named("uploadFileField")).to(UploadFinishedServlet.FILE_FIELD);
serve(UploadedServlet.REDIRECT_TO).with(CommitUploadServlet.class);
@Singleton
public class CommitUploadServlet extends HttpServlet {

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
      throws ServletException, IOException {

    String key = req.getParameter(UploadFinishedServlet.KEY_PARAMETER);

    resp.setContentType("text/html");
    resp.setStatus(200);

    String result = key != null ? key : "";
    resp.getOutputStream().write(result.getBytes());
  }

}
December 09, 2009
»

LayoutPanel Fill Parent in GWT-2.0

When I started constructing UI with GWT 2.0 LayoutPanels it had Layout instance publicly available but somewhere between 2.0.0-ms2 and 2.0.0-rc2 the API has changed and now Layout is available only via LayoutPanel#setWidget* methods. This left me with non functional UI because I had used getLayout().fillParent() calls what forces Widget to fill its parent element. Why? Because most of UI is constructed with floating panels what are resizable and has container element for it’s content what may be LayoutPanel instance.

I’m not arguing that fillParent() should be publicly available (child widget should not be aware of it’s parent (in)capabilities but parent should be able to force child LayoutPanel to fill it’s content, ideally without knowing it’s LayoutPanel).

So here is kind-of hack to get back fillParent() in 2.0 release. This is wrapper widget what can be added in for example FloatingPanel:

package com.google.gwt.user.client.ui;

import com.google.gwt.dom.client.Style;

import static com.google.gwt.dom.client.Style.Overflow.HIDDEN;
import static com.google.gwt.dom.client.Style.Position.RELATIVE;
import static com.google.gwt.dom.client.Style.Unit.PCT;

/**
 * Widget what extends {@link com.google.gwt.user.client.ui.SimplePanel} and can be used as 
 * "host" for {@link com.google.gwt.user.client.ui.LayoutPanel} inside 
 * non-{@link com.google.gwt.layout.client.Layout} based UI.
 * <p/>
 * This widget forces {@link com.google.gwt.user.client.ui.LayoutPanel} to fill host 
 * dimensions by calling {@link com.google.gwt.layout.client.Layout#fillParent()} in
 * {@link com.google.gwt.user.client.ui.LayoutPanelHost#setWidget(Widget)}.
 *
 * @author ampatspell
 */
public class LayoutPanelHost extends SimplePanel implements RequiresResize {

  public LayoutPanelHost() {
    this(null);
  }

  /**
   * Child may be null
   *
   * @param child widget to set
   */
  public LayoutPanelHost(Widget child) {
    Style style = getElement().getStyle();
    style.setPosition(RELATIVE);
    style.setWidth(100, PCT);
    style.setHeight(100, PCT);
    // overflow: hidden is to hide ruler element what is added by Layout
    style.setOverflow(HIDDEN);

    if (child != null)
      setWidget(child);
  }

  /**
   * If widget is instanceof {@link com.google.gwt.user.client.ui.LayoutPanel},
   * {@link com.google.gwt.layout.client.Layout#fillParent()} is called for it.
   *
   * @param w any widget or null
   */
  @Override
  public void setWidget(Widget w) {
    LayoutPanel layoutPanel = cast(w);
    if (layoutPanel != null)
      layoutPanel.getLayout().fillParent();
    super.setWidget(w);
  }

  /**
   * Delegates call to {@link com.google.gwt.user.client.ui.LayoutPanel}.
   * Should be called whenever this Widget or some of its parents are resized. 
   * Normally {@link LayoutPanel#onResize()} is called automatically by GWT Layout API 
   * but here it is impossible as there is no way (except from polling) to get informed 
   * about Element dimension changes.
   *
   * Update: Is it really needed? LayoutImplIE6 adds js hook to onresize.
   */
  public void onResize() {
    LayoutPanel layoutPanel = cast(getWidget());
    if (layoutPanel != null)
      layoutPanel.onResize();
  }

  /**
   * Casts {@link com.google.gwt.user.client.ui.Widget} or 
   * {@link com.google.gwt.user.client.ui.Composite} child widget
   * to {@link com.google.gwt.user.client.ui.LayoutPanel} if widget is not null and
   * is instanceof {@link com.google.gwt.user.client.ui.LayoutPanel}.
   *
   * @param widget Widget
   * @return widget casted to LayoutPanel or null
   */
  private LayoutPanel cast(Widget widget) {
    Widget w = getActualWidget(widget);
    if (w != null && w instanceof LayoutPanel)
      return (LayoutPanel) w;
    return null;
  }

  private Widget getActualWidget(Widget widget) {
    if (widget != null && widget instanceof Composite) {
      return ((Composite) widget).getWidget();
    }
    return widget;
  }

}

Usage:

FlowPanel base = new FlowPanel();
base.add(new LayoutPanelHost(content = new SomeLayoutPanel()));

Here SomeLayoutPanel now fills entire base element.

Update: Forgot to mention that on modern browsers instead of this simple Widget#setSize should work:

FlowPanel base = new FlowPanel();
base.add(content = new SomeLayoutPanel());
content.setSize("100%", "100%");

But looking at LayoutImplIE6 it seems that won’t work reliably in IE6 (if anyone cares). Also see note in LayoutPanelHost#onResize method docs. Sorry, currently I can’t test it in IE6 so I’m not sure.

Update #2: LayoutPanelHost#cast now supports Composite and ResizeComposite.

With UIBinder

It turns out this helper class is also needed to compose Layout-based UIs using UIBinder while following MVP.

Let’s consider simple case. I have Workspace MVP stack what can contain either Index, People or Projects “content” presenter’s view:

<!-- Workspace.ui.xml -->
<g:LayoutPanel>
  <g:layer top="0px" height="30px">
    <!-- Some header or whatever -->
  </g:layer>
  <g:layer top="30px" bottom="0px">
    <g:LayoutPanelHost ui:field="content"/>
  </g:layer>
</g:LayoutPanel>
// WorkspacePresenterImpl
view.setContentView(presenter.getView());

Where given presenter instance has view based on LayoutPanel:

<g:LayoutPanel>
  <g:layer top="0px" height="50px">
  </g:layer>
  <g:layer top="50px" bottom="0px">
  </g:layer>
</g:LayoutPanel>

If Layout#fillParent() is not called for workspace content widget the widget must set it’s height explicitly (i.e. for example bottom="0px" doesn’t work).

 
Internet Explorer 6
Are you serious?