|
GettingStarted
A short introduction to the GWT Dispatch API.
Featured IntroductionThis is a quick walkthrough of configuring the GWT Dispatch library and creating your own Action/Result/Handler. The code for this project is available at the gwt-dispatch-sample Github page. DetailsThis example is going to create a simple counter on the server. For simplicity, it will store it in memory. Firstly, we'll create an IncrementCounter action. public class IncrementCounter implements Action<IncrementCounterResult> {
private int amount;
/** For serialization only. */
IncrementCounter() {
}
public IncrementCounter( int amount ) {
this.amount = amount;
}
public int getAmount() {
return amount;
}
}Next, we define the IncrementCounterResult, which will also return the current counter value. public class IncrementCounterResult implements Result {
private int amount;
private int current;
/** For serialization only. */
IncrementCounterResult() {
}
public IncrementCounterResult( int amount, int current ) {
this.amount = amount;
this.current = current;
}
public int getAmount() {
return amount;
}
public int getCurrent() {
return current;
}
}Lastly, we define our IncrementCounterHandler class, which does the actual incrementing. public class IncrementCounterHandler implements ActionHandler<IncrementCounter, IncrementCounterResult> {
private int current = 0;
public Class<IncrementCounter> getActionType() {
return IncrementCounter.class;
}
public synchronized IncrementCounterResult execute( IncrementCounter action, ExecutionContext context ) throws ActionException {
current += action.getAmount();
return new IncrementCounterResult( action.getAmount(), current );
}
public synchronized void rollback( IncrementCounter action, IncrementCounterResult result, ExecutionContext context ) throws ActionException {
// Reset to the previous value.
current = result.getCurrent() - result.getAmount();
}
}Now, we have to hook up our action handler to the Dispatch service on the server side. Firstly, we create an implementation of the StandardDispatchService, which is GWT-dispatch's entry point for executing actions public class SimpleDispatchServlet extends RemoteServiceServlet implements StandardDispatchService {
private Dispatch dispatch;
public SimpleDispatchServlet() {
InstanceActionHandlerRegistry registry = new DefaultActionHandlerRegistry();
registry.addHandler(new IncrementCounterHandler());
dispatch = new SimpleDispatch(registry);
}
public Result execute(Action<?> action) throws DispatchException {
try {
return dispatch.execute(action);
} catch ( RuntimeException e) {
log( "Exception while executing " + action.getClass().getName() + ": " + e.getMessage(), e );
throw e;
}
}
}The SimpleDispatchService is in itself a GWT Remote Service, so it extends RemoteServiceServlet. It holds an ActionHandlerRegistry, which is used to route Actions to ActionHandlers. The execute implementation is trivial, since the Dispatch object does all of the hard work. Now, on the client-side, we first need to import the library into our *.gwt.xml file. Just add this: <inherits name='net.customware.gwt.dispatch.Dispatch' /> When you will first compile, the GWT compiler will output errors regarding com.google.gwt.inject and com.google.inject imports not being resolved. These can be safely ignored, as these classes are not referenced in our example. Next, you need to initialise an instance of DispatchAsync on the client side. The simplest way of doing this is to create an instance of StandardDispatchAsync: private final DispatchAsync dispatchAsync = new StandardDispatchAsync(new DefaultExceptionHandler()); Now, from your GWT client side code, use the dispatchAsync instance to execution Actions and handle Results. myButton.addClickHandler( new ClickHandler() {
public void onClick( ClickEvent evt ) {
dispatchAsync.execute( new IncrementCounter( 1 ), new AsyncCallback<IncrementCounterResult>() {
public void onFailure( Throwable e ) {
Window.alert( "Error: " + e.getMessage() );
}
public void onSuccess( IncrementCounterResult result ) {
Window.alert( "Incremented by " + result.getAmount() + ", new total is " + result.getCurrent() );
}
} );
}
});Server-sided integrationGWT-dispatch features rich integration with both Guice and Spring on the server side. Please see the manual configuration, Guice or Spring sections for details. |
Hi, great job with this project!
I was looking for this pattern, I even started implementing one of my own.
Following this tutorial to the end, I've encountered a problem: ERROR? Type 'net.customware.gwt.dispatch.shared.Result' was not serializable and has no concrete serializable subtypes
Do you know how to fix? Thanks, Alex
Hi, just wanted to point out that you cannot synchronize on a primitive in your IncrementCounterHandler? class
there is no method named "bindHandler" in the source code of ServerDispatchModule?
After browsing the source code, I think the bindHandler is now in ActionHandlerModule?. The following snippet should work:
public class CounterModule? extends ActionHandlerModule? {
}http://code.google.com/p/gwt-dispatch/source/detail?r=31&path=/trunk/src/main/java/net/customware/gwt/dispatch/server/guice/ServerDispatchModule.java
@alex - You shouldn't be returning 'Result' directly - you need a concrete implementation. What method/class is causing the error?
@jdpatterson - Good point (I should post examples I've actually tested...). I'll update the example.
@esnunes/ivo - You are correct - the module structure changed a bit (and will probably change again shortly - I've been doing some work on it the last couple of days). I've updated the example to reflect the class name change to ActionHandlerModule?.
jar:file:/wherever/war/WEB-INF/lib/gwt-dispatch-1.0.0-SNAPSHOT.jar!/net/customware/gwt/dispatch/client/DefaultDispatchAsync?.java
This is what I'm getting using the library. Can you help with this please?
@yesudeep: I believe you will get this if you haven't defined any Action/Result sub-classes which are being used on the client side.
The gwt-dispatch group is probably the best place for posting questions since I don't read these pages as regularly.
I think you might want to take the IncrementCounterHandler? and IncrementCounter? together in one object to make it a richer object. The IncrementCounter? object in your case is called an Action object but is actually just a value object... I don't really understand the separation....
@post2: Having them separate is essentially the point of the library. Keep in mind that the IncrementCounterHandler is a server-side-only class, while IncrementCounter is able to be created on the client-side also. In some ways, the 'Action' class is like an object container for method parameters, and the 'Result' contains the return value. They are both just data objects - they don't contain any actual functionality. And as far as the client-side is concerned, it has no idea how the command/action is executed. It just provides the parameters and processes the result.
The ActionHandler, on the other hand, is where the real action happens. It's essentially the functionality of the command. As such, it's on the server-side where it can access the database, authenticate, etc.
Hope that makes things a bit clearer.
I prefer to use Spring in the backend. With only a few changes it is perfectly possible to use it with spring:
http://pgt.de/2009/09/16/use-spring-with-gwt-dispatch/
Comments are welcome!
thanks.that is very useful!
I created a full test project configured with guice (not gin) here. it may help you all get through some of the gotchas in configuration.
http://github.com/pives/GWT-guice-commandpattern
I have created a demonstration project of gwt-presenter and gwt-dispatch based on Google's MVP tutorial codes. I hope it will complement the tutorial provided here. You can download the demo codes at the given link. It is a CRUD application with about 40 java files.
Demo codes: http://code.google.com/p/mvp-gwt-adaptation
Google's MVP tutorial codes: http://code.google.com/webtoolkit/doc/latest/tutorial/mvp-architecture.html"
Hello, It is mentioned here that in DispatchServletModule? file we need to give "/path/to/dispatch". What is this exactly, can you please explain!
Hello, in the new version 1.1.0, DispatchServiceServlet? disappears. What is object to be used instead?
Thank you very much for attention.
Yeah, we need to update the documentation. DispatchServiceServlet? has been replaced with either the StandardDispatchServiceServlet? or the SecureDispatchServiceServlet?, depending on your needs.
Not able to find either of StandardDispatchServiceServlet? or SecureDispatchServiceServlet? in the latest jar. Which class I should use instead?
Can use net.customware.gwt.dispatch.server.guice.GuiceStandardDispatchServlet? por guice or other engine implemented in net.customware.gwt.dispatch.server.(engine)