The dispatch pattern is alternative to the usual GWT-RPC implementation where every remote service is a new servlet. You can learn more about it:
gwt-mpv’s implementation of the dispatch pattern is not terribly unique, other than providing:
GenDispatch annotation for no action/result DTO boilerplate,SuccessCallback for centralization of error handling, andIn short, instead of having an FooService/FooServiceAsync for every remote service your application calls:
You use the command pattern to make FooAction/FooResult DTOs that are submitted via a single DispatchService and then “dispatched” appropriately to the right command handler on the server-side:
While this seems more complex, the advantage is that making new FooAction/FooHandler classes should be easier than making new Foo/FooAsync classes.
Also, since the command pattern is used, your client-side application can pass the commands around to do interesting things (batching, caching, etc.).
What gwt-mpv adds to the dispatch pattern is a large reduction in the boilerplate for making new actions.
Where as traditionally every new action (distinct AJAX call) requires you need to hand-code a FooAction (with fields, getters, setters, equals, hashCode) and FooResult (also with fields, getters, setters, equals, and hashCode), with gwt-mpv (via it’s sister project gwt-mpv-apt), you just specify a “spec” (specification):
@GenDispatch
public class FooSpec {
@In(1)
String inputParam1;
@In(2)
String inputParam2;
@Out(1)
String outputParam1;
@Out(2)
String outputParam2;
}
And gwt-mpv-apt will generate FooAction and FooResult DTOs with all of the necessary boilerplate for you.
Every AJAX call may fail, but it’s not a good idea to reimplement failure logic at each AJAX call site in your application. To help facilitate this, gwt-mpv adds a SuccessCallback interface:
public interface SuccessCallback<T> {
void onSuccess(T result);
}
Which is just like AsyncCallback without the onFailure method. So, instead of reimplementing AsyncCallback.onFailure each time you make an AJAX call, gwt-mpv’s OutstandingDispatchAysnc accepts SuccessCallbacks and will provide a single onFailure implementation.
The default onFailure implementation fires a DispatchUnhandledFailureEvent on the applications EventBus, so anyone that is interested (e.g. an error popup listener) can listener for the failure and respond appropriately.
(Note that another common way of achieving this is to have an application-specific subclass of AsyncCallback that implements onFailure.)
gwt-mpv provides a StubDispatchAsync that facilitates testing dispatch actions/results in a fairly succinct manner.
Again using ClientPresenterTest, testing save looks like:
@Test
public void saving() {
bind();
view.name().type("bar");
view.submit().click();
// ensure we sent the right data
SaveClientAction sentAction =
async.getAction(SaveClientAction.class);
assertThat(sentAction.getClient().name, is("bar"));
// save on the server is successful
doSaveClientResult(true);
// assert that we've moved to #clients
assertThat(bus, hasPlaceRequests("clients"));
}
private void doSaveClientResult(boolean success) {
async.getCallback(SaveClientAction.class).onSuccess(
new SaveClientResult(success));
}
Where:
view.submit().click() fires a SaveClientAction command (done by the ClientPresenter we’re testing)
We can, if necessary, use async.getAction(SaveClientAction.class) to get the last-sent action of that type and make assertions against it, to ensure it has the correct data
We use async.getCallback(SaveClientAction.class) to get the last-sent action’s callback and can call either:
onSuccess with a SaveClientResult that came from the serveronFailure with a Throwable to test the failure conditionThis allows fairly quick, easy testing of dispatch-style actions and results without a lot of fuss.
RequestFactory is another alternative to traditional GWT-RPC. Nothing in gwt-mpv prevents users from using RequestFactory, in fact it might work quite well, it just has not been actively explored yet.