Search code examples
dispatchgwtpdispatch-async

GWTP Dispatch -- Replacement for DefaultDispatchAsync (RpcDispatchAsync)


We had been using GWT-Dispatch to support the RPC calls using command patterns. We now need to move to GWTP since Dispatch has been absorbed into that project. Would seem to be all well and good. The problem is that we are unable to get a DispatchAsync object anymore. In Dispatch, it was extremely simple to get the default implementation:

private final DispatchAsync dispatchAsync = GWT.create(DefaultDispatchAsync.class);

This no longer works. DefaultDispatchAsync is deprecated, and when we use the suggested replacement for it (RpcDispatchAsync) it looks like this:

private final DispatchAsync dispatchAsync = GWT.create(RpcDispatchAsync.class);

we get the following error:

 Rebind result 'com.gwtplatform.dispatch.rpc.client.RpcDispatchAsync' has no default (zero   argument) constructors.

Does anyone have an idea about how to do this? I know if we rewrite all the pages to use the GWTP MVP pattern that it's available in the Presenter but moving things over to use full GWTP is a long process and if we can't get the RPC calls up and working quickly that will be a problem for the project.

Thanks in advance -- hopefully it's something easy.


Solution

  • DispatchAsync is no longer generated via deferred binding. Thus you can’t use GWT.create to instantiate it.

    GWTP Dispatch is making heavy use of GIN/Guice. So I would recommend that you use this dependency injection framework to get GWTP Dispatch work.

    Here is an example, which provides easy access to the DispatchAsync (without the need of rewriting all pages to use the GWTP MVP Pattern):

    [Note: This example uses gwtp dispatch 1.0.3]

    Client:

    MyClientModule.java - configure injection-rules for DispatchAsync

    import com.google.gwt.inject.client.AbstractGinModule;
    import com.google.inject.Inject;
    import com.google.inject.Provider;
    import com.google.inject.Singleton;
    import com.gwtplatform.dispatch.client.DefaultExceptionHandler;
    import com.gwtplatform.dispatch.client.DefaultSecurityCookieAccessor;
    import com.gwtplatform.dispatch.client.ExceptionHandler;
    import com.gwtplatform.dispatch.client.RpcDispatchAsync;
    import com.gwtplatform.dispatch.client.actionhandler.ClientActionHandlerRegistry;
    import com.gwtplatform.dispatch.client.actionhandler.DefaultClientActionHandlerRegistry;
    import com.gwtplatform.dispatch.shared.DispatchAsync;
    import com.gwtplatform.dispatch.shared.SecurityCookie;
    import com.gwtplatform.dispatch.shared.SecurityCookieAccessor;
    
    public class MyClientModule extends AbstractGinModule {
    
        private static final String COOKIE_NAME = "JSESSIONID";
    
        @Override
        protected void configure() {
            bindConstant().annotatedWith(SecurityCookie.class).to(COOKIE_NAME);
            bind(ExceptionHandler.class).to(DefaultExceptionHandler.class);
            bind(SecurityCookieAccessor.class).to(DefaultSecurityCookieAccessor.class);
            bind(ClientActionHandlerRegistry.class).to(DefaultClientActionHandlerRegistry.class);
            bind(DispatchAsync.class).toProvider(DispatchAsyncProvider.class).in(Singleton.class);
        }
    
        public static class DispatchAsyncProvider implements Provider<DispatchAsync> {
    
            private final DispatchAsync fDispatchAsync;
    
            @Inject
            public DispatchAsyncProvider(ExceptionHandler eh, SecurityCookieAccessor sca, ClientActionHandlerRegistry cahr) {
                this.fDispatchAsync = new RpcDispatchAsync(eh, sca, cahr);
            }
    
            @Override
            public DispatchAsync get() {
                return fDispatchAsync;
            }
        }
    }
    

    MyClientInjector.java - injector provides access to DispatchAsync

    import com.google.gwt.inject.client.GinModules;
    import com.google.gwt.inject.client.Ginjector;
    import com.gwtplatform.dispatch.shared.DispatchAsync;
    
    @GinModules(MyClientModule.class)
    public interface MyClientInjector extends Ginjector {
    
        DispatchAsync getDispatchAsync();
    
    }
    

    Server:

    MyGuiceServletContextListener.java - create injector for the servlet, which receives the commands and the servermodule, in which the bindings between (clientside) command and (serverside) handler are defined.

    import com.google.inject.Guice;
    import com.google.inject.Injector;
    import com.google.inject.servlet.GuiceServletContextListener;
    
    public class MyGuiceServletContextListener extends GuiceServletContextListener {
    
        @Override
        protected Injector getInjector() {
            return Guice.createInjector(new ServerModule(), new DispatchServletModule());
        }
    }
    

    DispatchServletModule.java - configures the servlet, which receives the commands

    import com.google.inject.servlet.ServletModule;
    import com.gwtplatform.dispatch.server.guice.DispatchServiceImpl;
    import com.gwtplatform.dispatch.server.guice.HttpSessionSecurityCookieFilter;
    import com.gwtplatform.dispatch.shared.Action;
    import com.gwtplatform.dispatch.shared.SecurityCookie;
    
    public class DispatchServletModule extends ServletModule {
    
        @Override
        public void configureServlets() {
            bindConstant().annotatedWith(SecurityCookie.class).to("JSESSIONID");
            filter("*").through(HttpSessionSecurityCookieFilter.class);
            serve("/" + Action.DEFAULT_SERVICE_NAME + "*").with(DispatchServiceImpl.class);
        }
    
    }
    

    ServerModule.java - bindings between (clientside) command and (serverside) handler

    import com.gwtplatform.dispatch.server.guice.HandlerModule;
    
    public class ServerModule extends HandlerModule {
    
        @Override
        protected void configureHandlers() {
            bindHandler(YourCommand.class, YourHandler.class);
        }
    }
    

    web.xml - tell the web-server to use MyGuiceServletContextListener

    <filter>
        <filter-name>guiceFilter</filter-name>
        <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
    </filter>
    
    <filter-mapping>
        <filter-name>guiceFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!--
    This Guice listener hijacks all further filters and servlets. Extra
    filters and servlets have to be configured in your
    ServletModule#configureServlets() by calling
    serve(String).with(Class<? extends HttpServlet>) and
    filter(String).through(Class<? extends Filter)
    -->
    <listener>
        <listener-class>de.gwtpdispatch.server.MyGuiceServletContextListener</listener-class>
    </listener>
    

    Usage

    Now you can create the injector with deferred binding and get access to the DispatchAsync-instance:

    MyClientInjector injector = GWT.create(MyClientInjector.class);
    injector.getDispatchAsync().execute(...YourCommand...)
    

    (AND: Don't forget to include the jars of GIN and Guice in your project and add the gin-module to the project's gwt.xml)

    I hope this explanation is detailed enough. Happy coding :)