Gwt-Platform event best practices (revisited)

Not too long ago, I started using GWT and GWTP and found it pretty hard to understand its event system.

I still can’t find much recent information about it, so I am writing this post to hopefully help others. Disclaimer: There many ways to achieve what I do in this post, but this is the way I prefer.

All right! Let’s demonstrate how events and the event bus work by creating a CSI-Hacking Dashboard. You can get the code on GitHub.

Post_gwtp_Howto_v1-03

We have ComputerPresenter, a HackerPresenter and a root Presenter that holds/creates other widgets. We also have a ComputerHackedEvent and ComputerHackedHandler. The event will be raised to signal that the computers got hacked, and the handler code will be executed after that.

Here’s the classic implementation of a GWT event. Our event will only carry the hacker’s name.

public class ComputerHackedEvent extends GwtEvent<ComputerHackedEvent.ComputerHackedHandler> {
    public interface ComputerHackedHandler extends EventHandler {
        void onSystemHacked(ComputerHackedEvent event);
    }

    public static final Type<ComputerHackedHandler> TYPE = new Type<>();

    private final String hackerName;

    public ComputerHackedEvent(String hackerName) {
        this.hackerName = hackerName;
    }

    public static void fire(String hackerName, HasHandlers source) {
        source.fireEvent(new ComputerHackedEvent(hackerName));
    }

    public String getHackerName() {
        return hackerName;
    }

    @Override
    public Type<ComputerHackedHandler> getAssociatedType() {
        return TYPE;
    }

    @Override
    protected void dispatch(ComputerHackedHandler handler) {
        handler.onSystemHacked(this);
    }
}

I usually declare my handler as a nested interface in the event declaration. That’s only a matter of personal preference though.

Next we have to raise the event. That will be done by our HackerPresenter. A really simple way of becoming a computer hacker, is by adding a button to the screen and pressing it, right CSI?

Here’s the code of the view and the presenter.

public class HackerView extends ViewWithUiHandlers<HackerUiHandlers>
        implements HackerPresenter.MyView {
    interface Binder extends UiBinder<Widget, HackerView> {
    }

    @UiField
    Button hackThePlanet;

    @Inject
    HackerView(Binder binder) {
        initWidget(binder.createAndBindUi(this));
    }

    @UiHandler("hackThePlanet")
    public void initiateHacking(ClickEvent event) {
        getUiHandlers().onInitiateHacking();
    }
}
public class HackerPresenter extends PresenterWidget<MyView>
        implements HackerUiHandlers {
    public interface MyView extends View, HasUiHandlers<HackerUiHandlers> {
    }

    private final String hackerName;

    @Inject
    HackerPresenter(
            EventBus eventBus,
            MyView view,
            @Assisted String hackerName) {
        super(eventBus, view);

        this.hackerName = hackerName;

        getView().setUiHandlers(this);
    }

    @Override
    public void onInitiateHacking() {
        ComputerHackedEvent.fire(hackerName, this);
    }
}

So we have a button, and when we click on it, it raises an event. There are a couple of ways to raise an event, but the one I usually use, is the static fire() method on the event. (I’ll talk about the other ways of firing an event later on.)

Now we have to handle the event somewhere. We want to know when the computers get hacked, so we’ll represent the computers with the ComputerPresenter. Its role will be to print in the console when it gets hacked, and by which hacker. Here’s the presenter code:

public class ComputerPresenter extends PresenterWidget<MyView>
        implements ComputerHackedEvent.ComputerHackedHandler {
    public interface MyView extends View {
        void setComputerName(String computerName);

        void displayStatus(String computerName, String hackerName);
    }

    private final String computerName;

    @Inject
    ComputerPresenter(
            EventBus eventBus,
            MyView view,
            @Assisted String computerName) {
        super(eventBus, view);

        this.computerName = computerName;

        view.setComputerName(computerName);
    }

    @Override
    protected void onBind() {
        super.onBind();

        addRegisteredHandler(ComputerHackedEvent.TYPE, this);
    }

    @Override
    public void onSystemHacked(ComputerHackedEvent event) {
        getView().displayStatus(computerName, event.getHackerName());
    }
}

This way, when a hacker clicks on the “start hacking” button, all the computers that are listening to the event will print something. As you can see, the ComputerPresenter registers itself as a handler for the ComputerHackedEvent through the addRegisteredHandler method.

This is a convenience method provided by GWTP. Using this method instead of registering directly on the EventBus will make the event registration part of GWTP’s lifecycle and unbind the event handler when the presenter is unbound. That means that if the presenter is unbound and rebound, you’ll have to re-register event handlers. This is why the onBind method is a good place to register handlers.

Here’s the code of the root presenter:

public class RootPresenter extends Presenter<RootPresenter.MyView, RootPresenter.MyProxy> {
    interface MyView extends View {
    }

    @ProxyStandard
    @NameToken(NameTokens.home)
    interface MyProxy extends ProxyPlace<RootPresenter> {
    }

    public static final Object SLOT_COMPUTERS = new Object();
    public static final Object SLOT_HACKERS = new Object();

    private final WidgetsFactory widgetsFactory;

    @Inject
    RootPresenter(
            EventBus eventBus,
            MyView view,
            MyProxy proxy,
            WidgetsFactory widgetsFactory) {
        super(eventBus, view, proxy, ApplicationPresenter.SLOT_SetMainContent);

        this.widgetsFactory = widgetsFactory;
    }

    @Override
    protected void onBind() {
        super.onBind();

        HackerPresenter zeroCool = widgetsFactory.createHacker("Zer0C00L");
        HackerPresenter acidBurn = widgetsFactory.createHacker("AcidBurn");

        addToSlot(SLOT_HACKERS, zeroCool);
        addToSlot(SLOT_HACKERS, acidBurn);

        ComputerPresenter computerA = widgetsFactory.createComputer("A");
        ComputerPresenter computerB = widgetsFactory.createComputer("B");

        addToSlot(SLOT_COMPUTERS, computerA);
        addToSlot(SLOT_COMPUTERS, computerB);
    }
}

We just create one hacker named Zer0C00L and 2 computers to hack. And now the view:

public class RootView extends ViewImpl
        implements RootPresenter.MyView {
    interface Binder extends UiBinder<Widget, RootView> {
    }

    @UiField
    HTMLPanel computers;
    @UiField
    HTMLPanel hackers;

    @Inject
    RootView(Binder uiBinder) {
        initWidget(uiBinder.createAndBindUi(this));
    }

    @Override
    public void addToSlot(Object slot, IsWidget content) {
        super.addToSlot(slot, content);

        if (slot == RootPresenter.SLOT_COMPUTERS) {
            computers.add(content);
        } else if (slot == RootPresenter.SLOT_HACKERS) {
            hackers.add(content);
        }
    }

    @Override
    public void removeFromSlot(Object slot, IsWidget content) {
        super.removeFromSlot(slot, content);

        if (slot == RootPresenter.SLOT_COMPUTERS) {
            computers.remove(content);
        } else if (slot == RootPresenter.SLOT_HACKERS) {
            hackers.remove(content);
        }
    }
}

Post_gwtp_Howto_v1-04

Nice! When I click on “Hack the planet!” I see the following result in the Javascript console:

I got hacked. (A) by Zer0C00L
I got hacked. (B) by Zer0C00L

I should start writing in l33tsp33k now.

Now what if you remove one of the ComputerWidgets from the DOM by calling removeFromSlot(SLOT_COMPUTERS, computerB); and still try to hack the planet?

If you read the output of the console you will see:

I got hacked. (A) by Zer0C00L
I got hacked. (B) by Zer0C00L

Wait… What? The handler for the computer B is still registered, the presenter wasn’t unbound, it was only removed from the DOM.

What if we want computer B to stop listening to the events when it’s not present in the DOM? Well that’s a job for addVisibleHandler. So instead of registering the handler using addRegisteredHandler we’ll use addVisibleHandler that will handle this for us. This way, when a presenter is considered “not visible” in GWTP’s lifecycle perspective (read: not visible as in “visible in the DOM”), the event will not reach the handler. The new output should now be:

I got hacked. (A) by Zer0C00L

There’s still a problem though. What if there were too many computers for a single hacker? I think at some point we’ll have to add someone to the team. Let’s do it!

// in the RootPresenter's OnBind method
HackerPresenter acidBurn = widgetsFactory.createHacker("AcidBurn");
addToSlot(SLOT_HACKERS, acidBurn);

You should see 2 buttons saying “Hack the planet!” and when you click them both, the output is:

I got hacked. (A) by Zer0C00L
I got hacked. (B) by Zer0C00L
I got hacked. (A) by AcidBurn
I got hacked. (B) by AcidBurn

All computers are reacting to every hacker, which is not what we want. This is happening because of the way we registered the handlers earlier. What we want is for the computers to react a specific hacker’s ComputerHackedEvent.

Since we can have a reference to the said hacker, that is pretty easy to accomplish. We have to delegate the handler registration to the concerned presenter. From the RootPresenter we’ll delegate the task, but first let’s create an interface :

import com.google.web.bindery.event.shared.HandlerRegistration;

public interface HasComputerHackedHandlers {
    HandlerRegistration addComputerHackedHandler(ComputerHackedEvent.ComputerHackedHandler handler, Object source);
}

We can then let ComputerPresenter implement it.

public HandlerRegistration addComputerHackedHandler(ComputerHackedEvent.ComputerHackedHandler handler, Object source) {
    HandlerRegistration hr = getEventBus().addHandlerToSource(ComputerHackedEvent.TYPE, source, handler);
    registerHandler(hr);
    return hr;
}

Note that instead of registerHandler() you can also use registerVisibleHandler().

And finally, when you click on both buttons, the output should be:

I got hacked. (A) by Zer0C00L
I got hacked. (B) by AcidBurn

All right! We’re ready to hack the planet! Are we?

Post_gwtp_Howto_v1-02

Remember when I said I would talk about the ways of firing events? If you are new to GWT and GWTP, you might have noticed that there are multiple methods available to fire events and register handlers.

// GWT
eventBus.addHandler(eventType, handler)
eventBus.addHandlerToSource(eventType, source, handler)

eventBus.fireEvent(event)
eventBus.fireEventFromSource(event, source)

// GWTP
presenterWidget.addHandler(eventType, handler) // deprecated
presenterWidget.addRegisteredHandler(eventType, handler)
presenterWidget.addVisibleHandler(eventType, handler)
presenterWidget.registerHandler(handlerRegistration)
presenterWidget.registerVisibleHandler(handlerRegistration)

presenterWidget.fireEvent(event)

Confused yet? I can say I was after seeing this. If you dig down you can see that a presenter widget gets an event bus injected and delegates most of its job to it. The only difference is that GWTP manages the handler registrations with its lifecycle (i.e: when a presenter gets unbound, the registered handlers get cleared). Also, if you dig for the fireEvent method, you’ll see GWTP delegates to eventBus.fireEventFromSource(). You may want to call the original fireEvent() if you want to match the following case (taken from the javadoc) “Fires the event from no source. Only unfiltered handlers will receive it”. Honestly, I’ve never faced that situation.

Here’s my cheat sheet of events in GWTP:

– Do I need to fire an event globally on the event bus? (i.e: everything registered to the event will handle it)
Y: presenterWidget.addRegisteredHandler() + SomeEvent.fire()
N: Go next

– Do I need to filter the handlers by the visibility of the handler?
Y: presenterWidget.addVisibleHandler() + SomeEvent.fire()
N: Go next

– Do I need specific handlers to handle events from a specific source?
Y: Create an interface called HasXXXHandlers and make your handling presenter implement it. GWTP gives PresenterWidget the capability to register handlers via registerHandler() and registerVisibleHandler(). Finally, fire the event with SomeEvent.fire()
N: That’s it. I usually don’t need more options, so the decision tree ends here. If you have another situation that doesn’t fit, let me know!

Post_gwtp_Howto_v1-05

GWTP 1.3 release

Two weeks ago we released GWTP 1.3. This release was a little bit stealthy and you have me to blame for that, I didn’t prepare an announcement! I hope you can forgive my oversight 😀

Here’s the complete list of changes:

GWTP

  • Improved Javadoc site
  • #14 : ActionException & ServiceException now implement IsSerializable
  • #282 : LazyActionHandlerValidatorRegistryImpl is now threadsafe
  • #467 : Allow REST and RPC dispatchers to be used at the same time
  • #517 : Updated to GWT 2.6.1 and updated DTDs (Thanks rdwallis)

MVP

  • Improved form-factor detection (Thanks rdwallis)
  • #184 : DefaultModule now has the Builder pattern
  • #284 : Add toString() to PlaceRequest
  • #346 : Map more than one name token to presenter
  • #489 : Added .without() to PlaceRequest.Builder to remove parameter from PlaceRequest
  • #492 : PlaceRequest.Builder(PlaceRequest request) now creates a deep copy
  • #499 : Decode embedded paramaters of RouteTokenFormatter (Thanks rdwallis)

RPC

  • #484 : Deprecated HttpSessionSecurityCookieFilter (Thanks bradcupit )

REST Dispatcher

  • Updated gwt-jackson to 0.6.1
  • #468 : Generate REST services based on the presence of @Path. Deprecate RestService interface
  • #498 : De/Serializing null/empty should result to null

Thanks to all contributors! We’re already working hard on GWTP 1.4 and should be out earlier than our usual release cycle. Stay tuned!

Jukito 1.4 and GWTP 1.2.1

In parrallel with the development of our next major commercial product, our ninja developers continue to work on our open source projects. We love working in the trenches of web application development. It’s what gives us the perspective we need to build the best web framework and tools we can.ninja.png

Your feedback is our most valuable guidance. It helps us polish our software and even inspires us to develop entirely new and unforeseen features !

Jukito 1.4

We’re proud to announce a new version of Jukito with three new kinds functionalities: support for private modules, ability to override the UseModules declaration, and inheritance of the UseModules annotation.

Here are the details of the changes on GitHub :

Added support for PrivateModules in the JukitoRunner

Enabling the use of UseModules on methods to override class level

Allow inheritance of @UseModules

GWTP 1.2.1

We’re also proud to release a new version of GWTP, which is compatible with the newest GWT 2.6. Also, you can now have access to the project information quickly by going to http://arcbees.github.io/GWTP/. Please give us feedback to help us improve the information published on this website with each future release.

We fixed a few failing tests and updated some librairies to get things right with GWT 2.6. Starting with 1.2.1, the build process will also display a warning if a newer version of GWTP is available.

We improved the Route Token Formatter by allowing the hashbang (#!/), so web crawlers can recognize your tokens. We also moved some classes to a shared package so you can reuse  the route token formatter from your server code. Please see the migration notes as the latter is a breaking change.

The Rest Dispatch project also got a load of new features. Most of them are configuration methods to help illuminate your development journey. The exhaustive list is available in the release notes, but we’ll review some of the key changes:

  • The CSRF protection header can be disabled on specific calls by using a new annotation.

  • It’s now possible to configure parameters that will be added automatically to your calls without specifying them in your service interface. Those parameters can be filtered out by HTTP method and parameter type.

  • We added some support for formatting dates.

You can see the release notes here or the details of the key commits on GitHub:

Changed version for Guava and Gin

Fixing CarStore’s selenium tests

Update gwt-jackson to 0.4.0

Fixing CarStore and selenium tests

Improved the ability to configure the serialization mechanism

Rest-Dispatch: Support for Sub-Resources

Retrieve the latest version and compare it when compilation

Custom request timeout configuration

Allow specific unsecured REST calls when SecurityCookie is bound

Move PlaceRequest and TokenFormatters to mvp-shared

Improvements to Route Token Formatter

Added customization methods for global Query and Header parameters

Fixed Fix Multimap Serialization

Fixed some checkstyle warnings

Allows interfaces compositions when creating RestService

Configurable date formats for resource parameters

In particular, thanks to aldenquimby, christiangoudreau, Chris-V, diamondq, jDramaix, meriouma, nmorel, olafleur, PhilBeaudoin, spg and tonuquq for this awesome release!

GWTP 1.1 is here !

I hope you’re having a good time at GWT.create !

We’re closing our round of annoucements with the release of a new version of our flagship product : GWTP.

In this release, we mostly focused on the dispatch projects. The REST Dispatch has had its serialization dependency updated to a library compatible with Jackson 2 annotations.

Also, all dispatch projects were cleaned up. As a side effect, the RPC dispatch artifacts were renamed and most of the code was moved to new packages. Whilst the old code is still there, it has been deprecated. We will write a migration guide to help you update your application so you don’t face major issues when we remove that code in the next major release.

What’s next for GWTP? For sure, one of our top priorities is to support the new GWT 2.6 .

We have big plans for that product, but your feedback and ideas are always welcome. We want to make that product fit your needs.

Thanks a lot to all the contributors in this release, but a special thanks to branflake2267, Chris-V, christiangoudreau, jDramaix, meriouma, nmorel, spg and StetsenkoEM

The team at ArcBees would like to wish you and your family happy holidays. Take some time to relax and be with your family.

We’ll be back in 2014 and ready to tackle big new projects !

Here are the details of this release :

Glass fix for IE

Add extension points to the REST dispatch code

Removed the compile warnings about JAX-RS annotations

Deprecated the old RPC dispatch code

Extracted common code between RPC and REST Dispatch projects

Added some javadoc to the REST dispatch project

Replaced the REST serialization library from piriti to gwt-jackson

Added the new dispatch dependencies to gwtp-all

Dispatch Projects Update (summary of the changes introduced in the dispatch projects)

 

GWTP-Platform 1.0.1

Hi everyone,

We just released GWTP 1.0.1! In this release, we’ve fixed few bugs and improved some already existing feature.

Here’s a list of those changes for GWTP:

Here’s a list of those changes for GWTP Spring:

I would like to thanks all contributors to this release, especially +Lalit Mishra +Mathieu Clavel +Björn Moritz +Brandon Donnelson +Julien Dramaix +Christopher Viel +Maxime Mériouma-Caron +Mrabti Idriss. If I’ve forgot anyone, just let me know 😀

Have a great time with the new release!

Upcoming Gwt-Platform talk

Just a word or two to officially announce two upcoming talks I will be giving in November. The first one is in Nantes on November 2nd. You can already register. The second one will be in Montréal at the Notman House on November 17th, registrations will likely be taken on Eventbrite, I’ll give you more information as soon as I have it.

Both will be on Gwt-Platform and the MVP and will be addressed to intermediate users.

Version 0.6 released!

We just released version 0.6 of GWTP. You can get it from the download section:
http://code.google.com/p/gwt-platform/downloads/list
Or from Maven Central, see:
http://code.google.com/p/gwt-platform/wiki/UsingGwtpWithMaven

See the release notes for details:
http://code.google.com/p/gwt-platform/wiki/ReleaseNotes

Highlights include:

  • Introduction of the GWTP Eclipse Plugin.
  • Support for search engine crawling.
  • Integration with Google Analytics.

This version has a few breaking changes, but they should all be easy to fix. Details on migrating to 0.6 are available here: http://code.google.com/p/gwt-platform/wiki/PortingV1#V0.6

You can get the samples from the downloads section. Information on how to run them from a command line or in Eclipse are given here: http://code.google.com/p/gwt-platform/wiki/RunningGwtpSamples

If you’re interested to see GWTP in production apps, check out:

(If you want to see your application in this list, just send me an email saying why you like GWTP! ;))

Have fun with GWTP!

Crawling and Google Analytics integration, done!

It’s been a while since we added features to Gwt-Platform and since Google I/O is finished, we felt that some feature needed to be dealt with. One of these is the ability to easily let any GWTP application be crawlable by a search engine crawler following Google’s guidelines. For a while now we had a basic implementation that was used by many of you to build your own solution. But speed issues and timing constraints made it impossible to use the same approach on AppEngine. Now with features like always on and warmup request we can offer something easy to install and responsive. For more information about how to make the crawler work, take a good look at this piece of documentation.

The second feature we worked on is the seamless integration of your presenter-based application with Google Analytics. This new feature will automatically track any navigation event and presenter change provided you add the following bindings to your gin module:

    bind(GoogleAnalytics.class).to(GoogleAnalyticsImpl.class).in(Singleton.class);
    bindConstant().annotatedWith(GaAccount.class).to("UA-XXXXXXX-X");
    bind(GoogleAnalyticsNavigationTracker.class).asEagerSingleton();

The first line let’s you bind the various google Analytics function to our implementation, this line can be avoided by installing the new default module that we introduce with GWTP 0.6. The second line is where you bind your Google Analytics account to this application and the last line is where the tracker is actually instanciated alongside your application. As you can see, these three little lines will take care of everything and you’ll even be able to go further by injecting the GoogleAnalytics interface wherever you need it, so you can easily track custom events right from your GWT code. For more information about GWTP integration with Google Analytics check out this documentation page.

These features are only available in trunk and 0.6-SNAPSHOT for now. However the official release of GWTP 0.6 is planned for very soon. Stay tuned!

Testing views using Gwt-Platform’s MockingBinder tool

Testing GWT views has always been difficult and really slow. This is due to the fact that instantiating javascript components makes it necessary to rely on GwtTestCase, which in turn instantiates HTMLUnit and turns a simple unit test into something that more closely resembles an integration test. In fact, the pain of relying on GwtTestCase is well documented. With the help of GWTMockUtilities, Jukito and our MockingBinder utility, views can be as easily tested as presenters!

Don’t shoot!

A well known trick that anybody who tried testing GWT code learns is to disarm. This is done simply by calling GWTMockUtilities.disarm(). This makes sure any call to GWT.create() returns null instead of launching its javascript infested voodoo.

As your spouse will tell you, however, returning null is not a solution! In many cases, you will run into null pointer exceptions when your code (or GWT’s internal code) expects an object but finds null. The key is therefore to never call GWT.create, either directly or via a call to new that would eventually lead to the dreaded GWT.create().

The first trick: don’t create your UiBinder yourself!

Let’s examine a typical view that relies on UiBinder:

public class HelloViewImpl extends ViewImpl implements HelloView {
  interface Binder extends UiBinder<Widget, HelloViewImpl> {
  }

  private static Binder uiBinder = GWT.create(Binder.class);
  ...
}

Our first call to GWT.create() is right there. Worse, it’s in a static variable, so it will get created as soon as the class is loaded! How do we get rid of this one?

Enters Google GIN, dependency injection at its finest. One feature of GIN is that, if it finds an interface that has not been bound, then it creates it with a call to GWT.create(). This is precisely what we want here. Let’s then rewrite the above to use GIN:

public class HelloViewImpl extends ViewImpl implements HelloView {
  public interface Binder extends UiBinder<Widget, HelloViewImpl> {
  }

  @UiField HasText firstNameTextBox;
  @UiField HasText helloLabel;

  @Inject
  public HelloView(final Binder uiBinder) {
    initWidget(uiBinder.createAndBindUi(this));
  }
  ...
}

You are probably wondering if the binder will be GWT.create()d every time the view is instantiated. Yes. This is not a problem if the view is a singleton, but it can become one if you plan of filling a huge table with instances of that view. For those cases, simply go in your Gin configuration file and bind(HelloViewImpl.Binder.class).in(Singleton.class). We ran some GwtTestCase to verify the exact behavior of GWT.create() and using this singleton trick this will result in the same behavior as using a static field, but without the GWT.create().

Another option would be to inject Binder in a static field and rely on GIN’s requestStaticInjection(). But we all know static injection is evil, right?

What to do when testing?

When testing, you replace GIN with Guice (Is there a morale here?). As a result you will no longer have the automatic call to GWT.create(). This is great, but it also means you have to pass something else as a parameter when instantiating your view.

The first idea could be to simply pass an anonymous Binder class. Remember, however, that one of the side effects of the call to createAndBindUi is to fill all your @UiFields. We need our replacement class to do the same.

This is exactly what MockingBinder sets out to solve! This class uses reflection to identify all you @UiFields and let you use the mocking framework you want to fill them with mocked object of the corresponding type. It also ensures the call to createAndBindUi() returns a mocked object of the right type.

Writing a test using Jukito

When testing, you will need a TestBinder class that both extends MockingBinder and implements your view’s Binder. If you’re doing your unit test the old fashioned way, you can simply pass a new TestBinder() when instantiating your view. However, if you’ve discovered the joy of using DI and automocking right in your unit tests, then you will want to use Jukito. Let’s see how to do this:

@RunWith(JukitoRunner.class)
public class HelloViewTest {
 /**
  * This is the Guice test module. Jukito runs the configureTest() method
  * to setup all the bindings used in the following unit tests.
  */
  public static class Module extends JukitoModule {
   /**
    * This is the test binder extending `MockingBinder` and implementing the view's `Binder`.
    */
    static class TestBinder extends MockingBinder implements Binder {
      @Inject
      public MyTestBinder(final MockitoMockFactory mockitoMockFactory) {
        super(Widget.class, mockitoMockFactory);
      }
    }

    @Override
    protected void configureTest() {
      GWTMockUtilities.disarm();
      bind(Binder.class).to(TestBinder.class);
    }
  }

  @AfterClass
  public static void tearDown() {
    GWTMockUtilities.restore();  // Just to be nice to future tests
  }

  @Inject HelloView view;

  @Test
  public void anyTest() {
    // given
    given(view.firstNameTextBox.getText()).willReturn("Christian");

    // when
    view.sayHello();

    // then
    verify(view.helloLabel).setText("Hello Christian!");
  }
}

And the factory:

public class MockitoMockFactory implements MockFactory {
  @Override
  public  T mock(Class classToMock) {
    return Mockito.mock(classToMock);
  }
}

The first thing we do here, as soon as Jukito’s test module is initializing with the configureTest() method, is to call GWTMockUtilities.disarm(). This ensures nothing bad happens when loading the GWT classes since some static variables are initialized with calls to GWT.create(). For the benefit of future tests, we rearm GWT later in the tearDown() method.

Then we tell Guice that it should use our new TestBinder whenever it needs a Binder. Finally, we inject BlogView in the test class, this is caught by Jukito who uses Guice to instantiate BlogView, filling-in any dependencies. In this case, the TestBinder.

Finally our test can stub and verify behavior on all the @UiField of our view.

What about views that create widgets dynamically?

Some views need to create widgets dynamically, for example to fill a table with rows as data becomes available. Creating these widgets is typically done with new, but this will trigger an internal call to GWT.create() which, as we’ve seen, may later lead to null pointer exceptions.

The key here is to skip the new, again using the magic of dependency injection. Say, for example, you need to create labels dynamically. Simply inject a Provider<Label> in your view and call labelProvider.get() whenever you need a new instance. In your production code, this will have exactly the same effect as calling new Label(). In your testing code, however, you can substitute the Provider<Label> for a class that generates mock labels. In fact, this is exactly what Jukito will do for you provided you include this line in your configureTest() method: forceMock(UiObject.class);

If you want to dynamically instantiate widgets that require construction parameters you may need to create a factory, or to rely on Guice’s assisted factories which will be coming soon to GIN.

Philosophical questions…

One of the goals of the model-view-presenter architecture was to remove all the logic from the views so that you can test the core of your application without having to rely on GwtTestCase. With UiBinder, you end up with something that looks like MVVP since the declarative UI can be somehow seen as a dumb view. With the approach proposed here, you can pack as much logic as you want in your view and test it as easily as if it were a presenter. Does it mean we should drop one V on the MVVP pattern? What do you think?

More examples

For more complete examples, the ArcBees hive project heavily relies on this pattern to test views that have a bit of logic in them.

How I made my GWT/AppEngine application appear to load quicker

It’s a well known “feature” of AppEngine for Java that if your application does not retrieve much traffic, it’ll be unloaded to free resources for other applications. When your application does receive a visitor, your java application must be started. This is referred to as a “cold start”.

Jakob Nielsen’s Usability Engineering guidelines state that for any delay of greater than 1 second feedback is required. A GWT application running on Google AppEngine takes much longer than 1 second to get started. My GWT 2.0 application takes about 7 seconds from cold, or about 4 seconds on a warm AppEngine.

The following describes how I made my AppEngine application appear to load faster, without losing the XSRF protection provided by the gwt-platform framework.

Previously, when I loaded my app, my browser would show a blank page for about 7 seconds while the main html page loaded. To improve the user experience, I wanted to show the user a “fake” progress indicator that makes it seem like something was happening while the application is loading. (Something like every second, % complete += (15% of percentage incomplete). If % complete > 95, then % complete = 50. Gmail used this same pattern when loading. For more discussion on progress indicators, see ajaxpatterns.org.

In my main html file, I moved the script tag that included my .nocache.js from the head, to the bottom of the body.

Above this script tag I added some javascript that renders my progress bar, and use setTimeout to update it every second. The progress bar will continue to update as the javascript is loaded in background, and once my application is ready to be loaded I hide the progress bar in revealInParent() of my top-level presenter. By ordering things this way, my progress bar was displayed first and then the browser made the request to AppEngine to load the .nocache.js file.

Main HTML page

<!doctype html>
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>MyApp</title>
  </head>
  <body>
    <div id="loading" style="display: none">
      <div id="progressbar" style="margin: 15px; width: 300px; height: 10px; border: 2px solid black; overflow: hidden;">
      <div id="progress" style="background: silver; height: 100%; width: 0;"></div>
        <script type="text/javascript">
          var loading = document.getElementById('loading');
          var progress = document.getElementById('progress');
          var progressbar = document.getElementById('progressbar');
          function updateProgress() {
            if(loading.style.display !== 'none') {
              var width = parseInt(progress.offsetWidth+((progressbar.offsetWidth-progress.offsetWidth)*.15));
              if(width > (progressbar.offsetWidth * .95)) {
                width = parseInt(progressbar.offsetWidth) * .5;
              }
              progress.style.width = width + 'px';
              window.setTimeout("updateProgress()", 1000);
            }
          }
          document.body.style.margin = 0;
          document.body.style.padding = 0;
          loading.style.display = 'block';
          updateProgress();
        </script>
       </div>
      </div>
      <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position: absolute; width: 0; height: 0; border: 0"></iframe>
      <noscript>
        <div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
          Your web browser must have JavaScript enabled in order for this application to display correctly.
        </div>
      </noscript>
    <script type="text/javascript" language="javascript" src="myapp/myapp.nocache.js"></script>
  </body>
</html>

AppPresenter.java

public class AppPresenterImpl extends ...
  // ...
  @Override
  protected void revealInParent() {
    DOM.setStyleAttribute(RootPanel.get("loading").getElement(), "display", "none");
    RevealRootContentEvent.fire(this, this);
  }
// ...
}

To return the main html before the java application starts, the main html file needs to be a static file, as App Engine serves static files from dedicated servers that are separate from the java application servers. Previously I used the code that was suggested in the wiki for XSRF protection, however this would no longer work as my main html file will be static and served from a different server.

DispatchServletModule.java

  • Send cookie to client attached to  .nocache.js

public class DispatchServletModule extends ServletModule {
  @Override
  public void configureServlets() {
    bindConstant().annotatedWith(SecurityCookie.class).to("MYCOOKIE");
    filter("*.nocache.js").through(HttpSessionSecurityCookieFilter.class);
    serve("/myapp/" + ActionImpl.DEFAULT_SERVICE_NAME + "*")
        .with(DispatchServiceImpl.class);
  }
}

appengine-web.xml

  • Aggressively cache index.html and *.cache.*
  • I use gwt-math which puts some javascript files in /myapp/js/, this should be served statically
  • Don’t cache *.nocache.*
  • *.gwt.rpc is required for gwt-rpc serialization
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
  <application>myapp</application>
  <version>...</version>
  <static-files>
    <include path="index.html" expiration="30d" />
    <include path="myapp/**.cache.*" expiration="30d" />
    <include path="myapp/js/*.js" expiration="30d" />
  </static-files>
  <resource-files>
    <include path="myapp/*.gwt.rpc" />
    <include path="myapp/*.nocache.*" />
  </resource-files>
  <precompilation-enabled>true</precompilation-enabled>
</appengine-web-app>

Using a combination of the above techniques has improved my application so that:

  • Users get feedback almost instantly when they first browse to my application (about 0.4s according to Firebug)
  • The security cookie is still provided to the client (Firecookie shows the cookie was sent to the client in the headers and saved when myapp.appspot.com/myapp/myapp.nocache.js was retrieved).
  • Aggressive caching settings means that everything that it makes sense to cache, is cached.