Using the GWTHandler
 

 

If you have used Spring before and are already using GWT for serious applications you might have considered using Spring controllers instead of GWT's RemoteServiceServlet. There are plenty good reasons for doing so actually.

Before: The GWTSpringController 

In my previous post about Using the GWTSpringController I explained the usage and the mechanics of the GWTSpringController which unifies the GWT RemoteServiceServlet with Spring, allowing it to run inside a Spring application context. This approach has the drawback that your service must extend the controller class, so you cannot inherit service behaviour from your (already existing) business logic, leading often to constructs that just wrapped around another service and forwarded calls.

Now: The GWTHandler 

The GWTHandler included in the new GWT Server Library (which is a spinoff of the GWT Widget Library) lets you write your services without extending any class, as long as you implement  GWT's RemoteService interface, allowing you to extend whichever class you like. In GWT-SL 0.1.4 you don't have to implement this interface any more, though you should still create and specify it in the configuration so that the GWTHandler knows which methods to publish to RPC and which to hide.

I wrote a small demonstration which invokes a test service performing an addition, playing around with the HTTP session and throwing an exception to test exception translation and propagation.  It's a WAR file which deploys to the Spring context, so in a plain Tomcat installation you can access it at http://localhost:8080/gwt-wl-sl/

The Recipe

First you need an interface which extends RemoteService:

public interface ServiceTest extends RemoteService{ 

public int add(int a, int b); 

...

}

Next you create your service:

public class ServiceTestImpl implements ServiceTest {
    public int add(int a, int b) {
    return new Integer(a + b);
    }

...
}

Last you register your services in the Spring servlet:

<beans>
 <bean id="urlMapping"   class="org.gwtwidgets.server.spring.GWTHandler">
  <property name="mapping">
   <map>
    <entry key="/add.rpc" value-ref="ServiceAdd"/>
   </map>
  </property>
  <property name="usingInstrumentation" value="true"/>
 </bean>
   
 <bean id="ServiceAdd" class="org.gwtwidgets.server.spring.test.serverimpl.ServiceAddImpl"/>
</beans>

And that's it! The GWTHandler will forward requests to the specified URLs to your service, in our example, that is the /add.rpc URL to the ServiceAdd service. Of course you can add as many services you like as long as they map to different URLs.


Internals

The GWTHandler actually does exactly what you would hand-code if you wanted to use the GWTSpringController to forward method invocations to a POJO service: it creates a new java class which extends the GWTSpringController, implements your service interface and forwards all method invocations to your service object. Unfortunately the RemoteServiceServlet on which the GWTSpringController relies expects itself to be the service, looking up via reflection the implemented service interfaces on itself. Thus it is imperative that the resulting class is an extension to RemoteServiceServlet.

Prior to 0.1.4 there were two other notable library dependencies: CGLIB and/or Javassist. Depending on which of the two you use (consult the javadocs on the usingInstrumentation property) either the CGLIB or the Javassist library is used. While the latter produces faster code, you may want to use CGLIB because it already ships with Spring, obviating a dependency on a further library. However GWT-SL 0.1.4 uses only reflection and does not use any of the aforementioned libraries.

Obtaining the HttpServletRequest 

Occasionally  you may want to access the http request (or response) from within your services even if they do not strictly depend on the Servlet API. You may want to do that especially if you are trying to access the user session or want to access a cookie. In the 1.2 version we introduced two ways of doing so:

  • Two static methods named getRequest() and getResponse() in the GWTSpringController which operate just like the getThreadLocalRequest() of GWT's RemoteServiceServlet. It is very easy to use:

    public void myServiceMethod(...){
    ...
    HttpServlerRequest request = ServletUtils.getRequest();
    ...

    }
  • The RequestInjection method interceptor which relies on Spring method proxies to provide the current request and response to your service. This one assumes that you have a setter for the request object on your service, and if you tell it it's name it will set for each method invocation the request and response objects. The following example illustrates how to wrap the RequestInjection around your service:

    <bean id="ServiceTestHTTP" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="ServiceTestHTTPTarget"/>
        <property name="autodetectInterfaces" value="true"/>
        <property name="interceptorNames">
            <list>
                <value>requestSetter</value>
            </list>
        </property>
        </bean>
       
        <bean id="requestSetter" class="org.gwtwidgets.server.spring.RequestInjection">
        <property name="requestSetterName" value="setRequest"/>
        <property name="responseSetterName" value="setResponse"/>
        </bean>


    Note that this one fails silently if it can't find the appropriate setters.

 Exception Translation

A fairly useful feature is exception translation.  GWT 1.4 allows you to serialise exceptions which implement Serializable or IsSerializable. These exceptions then travel back over the wire to the client in a meaningful way rather than the standard 'An error occurred on the server...' etc. message. The GWTHandler also propagates back exceptions implementing IsSerializable.

Hosted mode

Normally you should not run into any truble with hosted mode, as long as you use an external web server. I have not tried the GWTHandler with the integrated tomcat server. My eclipse launch configuration to run the hosted mode browser with the demo application is :

-noserver -port 8080 -out src/test/webapp/static gwt-wl-sl/static/org.gwtwidgets.server.spring.test.ClientApplication/ClientApplication.html