by ampatspell
in Code
I’ve created and uploaded to bitbucket a small test/sample GWT-Spring application what explores one of easiest ways to integrate GWT Command Pattern (See my previous blog entry) with Spring server back-end.

The app demonstrates integration with simple ServerInfoAction with ServerInfoResult and ServerInfoActionHandler:
public class ServerInfoAction implements Action<ServerInfoResult> { private boolean includeUserAgent; public ServerInfoAction() { ; } public ServerInfoAction(boolean includeUserAgent) { this.includeUserAgent = includeUserAgent; } public boolean isIncludeUserAgent() { return includeUserAgent; } }
public class ServerInfoResult implements Result { private String serverInfo; private String userAgent; public String getServerInfo() { return serverInfo; } public String getUserAgent() { return userAgent; } public void setServerInfo(String serverInfo) { this.serverInfo = serverInfo; } public void setUserAgent(String userAgent) { this.userAgent = userAgent; } }
public class ServerInfoActionHandler implements ActionHandler<ServerInfoAction, ↩ ServerInfoResult> { public ServerInfoResult execute(ServerInfoAction action) { ServerInfoResult res = new ServerInfoResult(); res.setServerInfo(ActionDispatchContext.getServletcontext().getServerInfo()); if (action.isIncludeUserAgent()) res.setUserAgent(ActionDispatchContext.getRequest().getHeader("User-Agent")); return res; } }
I’m not going to describe the command pattern itself. See GWT mailing list and in previous post mentioned Google I/O video for lots of details and better description than I could write. Instead I’ll step thru implementation details of Spring integration.
And let’s start with web.xml:
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <servlet> <servlet-name>rpc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:dispatchServletContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>rpc</servlet-name> <url-pattern>*.rpc</url-pattern> </servlet-mapping> </web-app>
I’m defining standard Spring DispatcherServlet, pointing to *.rpc this will handle GWT command requests. Next step is to handle requests. This is done by using Spring SimpleUrlHandlerMapping by mapping /**/dispatch.rpc to Spring Controller:
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="interceptors"> <list> <!-- <ref bean="openSessionInViewInterceptor" /> or whatever else per request --> </list> </property> <property name="mappings"> <value> /**/dispatch.rpc=actionDispatchTransportService </value> </property> </bean>
actionDispatchTransportService is defined as follows:
<bean id="actionDispatchTransportService" class="com.amateurinmotion.dispatch.server. ↩ action.support.impl.ActionDispatchTransportServiceImpl"> <property name="actionDispatcher"> <bean class="com.amateurinmotion.dispatch.server.action.support.impl.ActionDispatcherImpl"> <property name="actionHandlerRegistry" ref="actionHandlerRegistry" /> </bean> </property> </bean>
The ActionDispatchTransportServiceImpl by itself is RemoteServiceServlet and Controller:
@SuppressWarnings("serial") public class ActionDispatchTransportServiceImpl extends RemoteServiceServlet implements ↩ ActionDispatchTransportService, Controller, ServletContextAware { private ServletContext servletContext; private ActionDispatcher actionDispatcher; @Required public void setActionDispatcher(ActionDispatcher actionDispatcher) { this.actionDispatcher = actionDispatcher; } // ActionDispatchTransportService public Result execute(Action<?> action) throws Exception { return actionDispatcher.execute(action); } // Controller public ModelAndView handleRequest(HttpServletRequest request, ↩ HttpServletResponse response) throws Exception { ActionDispatchContext.set(request, response, getServletContext()); try { super.doPost(request, response); } finally { ActionDispatchContext.remove(); } return null; } // ServletContextAware public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } @Override public ServletContext getServletContext() { return servletContext; } }
When Controller receives request the handleRequest method is called, it is delegated to GWT doPost what after deserialization calls execute what delegates request to actionDispatcher who using actionHandlerRegistry lookups ActionHandler for given Action and invokes it.
ActionHandler definition list looks like this:
<bean id="actionHandlerRegistry" class="com.amateurinmotion.dispatch.server.action. ↩ support.impl.ActionHandlerRegistryImpl"> <property name="handlers"> <list> <bean class="com.amateurinmotion.dispatch.server.action.ServerInfoActionHandler" /> </list> </property> </bean>
For full details see http://bitbucket.org/ampatspell/dispatch (To run locally you’ll need Eclipse and few tweaks in .classpath)
Note: This is not production ready code