User Tools
Table of Contents
This content is copied from http://blog.cacoethes.co.uk/groovyandgrails/the-command-pattern-with-the-grails-gwt-plugin so that we don't lost good content we need for GWT assessment in case that website is gone from internet.
The Command Pattern with the Grails GWT Plugin
A talk by Ray Ryan of Google at the 2009 Google IO conference has caused a bit of a buzz in the GWT community. In that talk, Ray recommends several design patterns that will help make your projects more manageable as they grow in size. The particular suggestion I’ll be focusing on in this post concerns using the Command Pattern for server requests.
The idea is to encapsulate the stuff you want the server to do for your client in command or action objects instead of using standard service methods. For example, rather than calling a search() method on a remote service, you have a search object that gets sent to the server and the server returns the corresponding result or response object. By using this pattern, you can effectively implement caching, batching, undo/redo, etc. See Ray’s presentation for a bit more info on this.
One ready-made implementation of the pattern for GWT is the gwt-dispatch library. I considered integrating this into the Grails plugin, but its server-side components weren’t really suitable for a Grails project. Anyway, I wanted to write something myself so I could better understand what the implementation should do. The result is the plugin’s new action framework, which you can test out with an intermediate release of the plugin.
Getting started
Using the framework is simplicity itself. Let’s say you want to implement a search action. You first create the appropriate classes for it by running a new Grails command:
grails create-gwt-action org.example.myapp.Search
This will create the following files:
- src/java/org/example/myapp/client/SearchAction.java
- src/java/org/example/myapp/client/SearchResponse.java
- grails-app/actionHandlers/org/example/myapp/SearchActionHandler.groovy
The action and response classes represent the request and response data respectively. Both of them implement Serializable, so they have to have a default constructor (which can be private) and can only contain other serializable data. Note that they are added to the client sub-package of the package you specify, because they are used on the client was well as the server.
The action handler is an instance of a Grails artifact type added by the plugin. Its role is to process actions and return the appropriate responses. It would typically offload the majority of the work to a standard Grails service that could then be used by other code, such as a REST or web services interface.
The code
Update I have updated the plugin packages in the following examples, so “org.grails.” is now just “grails.” The change was made for the final release of version 0.5.
The action object should contain only the information necessary to complete the request. Remember, it’s a data object and typically won’t have any behaviour. In the case of our search action, we might need a query string and the maximum number of results the search should return:
package org.example.myapp.client; import grails.plugins.gwt.client.Action; public final class SearchAction implements Action<SearchResponse> { private static final long serialVersionUID = 1L; private String query; private SearchAction() {} public SearchAction(String query) { this.query = query; } public String getQuery() { return query; } }
Likewise, the response should only contain the data required by the client:
package org.example.myapp.client; import java.util.ArrayList; import java.util.Collections; import java.util.List; import grails.plugins.gwt.client.Response; public class SearchResponse implements Response { private static final long serialVersionUID = 1L; private ArrayList<Long> ids = new ArrayList<Long>(); private SearchResponse() {} public SearchResponse(List<Long> ids) { this.ids.addAll(ids); } public List<Integer> getIds() { return Collections.unmodifiableList(this.ids); } }
All very straightforward so far. The final step is to implement the action handler. As I said, this typically offloads the work to a service and in our example we will make use of a search service:
package org.example.myapp import org.example.myapp.client.SearchAction import org.example.myapp.client.SearchResults class SearchActionHandler { SearchService searchService SearchResponse execute(SearchAction action) { def results = searchService.executeSearch(action.query) return new SearchResponse(results) } }
As you can see, all the action needs to do is unwrap the action and create the response. Everything else is handled by the search service. We haven’t even needed to expose a service via GWT! That’s all you need to do on the server side, which just leaves the question of how you execute an action from the client.
On the client
The plugin comes with a dedicated GWT RPC service that you can use to dispatch all your actions: GwtActionService. All you have to do in your GWT code is create the service, instantiate your action, and then call the execute() method:
... import grails.plugins.gwt.client.GwtActionService; import grails.plugins.gwt.client.GwtActionServiceAsync; ... protected void doSearch(String query) { GwtActionServiceAsync service = GWT.create(GwtActionService.class); ((ServiceDefTarget) service).setServiceEntryPoint(GWT.getModuleBaseURL() + "rpc"); service.execute(new SearchAction(query), new AsyncCallback<SearchResponse>() { public void onFailure (Throwable caught) { ... } public void onSuccess (GetRecentResponse result) { ... } }); }
You could even wrap the action service with another implementation that does caching and/or batching of commands.
If you use Google Gin, you can simplify your code by having the action service injected into the classes that need it. Simply add something like this to your Gin module definition:
... import grails.plugins.gwt.client.GwtActionService; import grails.plugins.gwt.client.GwtActionServiceAsync; public class MainModule extends AbstractGinModule { protected void configure() { ... } @Provides @Singleton GwtActionServiceAsync provideGwtActionService() { GwtActionServiceAsync service = GWT.create(GwtActionService.class); ((ServiceDefTarget) service).setServiceEntryPoint(GWT.getModuleBaseURL() + "rpc"); return service; } }
Since GwtActionService is provided by the plugin, you also need to configure your module to inherit from the plugin’s (new) module:
<module> ... <inherits name="grails.plugins.gwt.Grails"/> ... </module>
I think this is a really clean approach to GWT RPC that reduces the burden on you as a developer. In particular, you no longer have to implement GWT services because you can create simple action handlers instead. Before I implemented this framework, I found that I was creating specific GWT versions of each service. So for example, I had a SearchService and a GwtSearchService, which was pretty inefficient.
I hope you like the new approach!