Tuesday, August 19, 2008

Integrating DWR 2.0.5 with Spring 2.5.5 and web flow 2.0.3

Overview
DWR is an open source Remote Procedure Call (RPC) library that makes it easy to call Java functions from JavaScript and to call JavaScript functions from Java via Reverse Ajax functionality that is introduced in DWR 2.0 version. This article is limited to explaining as to how to configure DWR 2.0.5 using XML namespace support available in Spring 2.0 version and above.

Detailed Steps
  • Step 1 - Add dwr to web.xml file

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">

......

<!-- DWR 2.0.5 Integration -->
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.spring.DwrSpringServlet</servlet-class>

<!-- Turn debug to false in production-->
<init-param>
<param-name>debug</param-name>
<param-value>false</param-value>
</init-param>

<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>

</web-app>

  • Step 2 - Add the dwr namespace and schema to your spring configuration file. The namespace is xmlns:dwr=”http://www.directwebremoting.org/schema/spring-dwr” The schemaLocation is http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-2.0.xsd. Also map engine.js, util.js, call, dwr and interface request URIS to dwrcontroller (see example below)
Example: Sample Spring MVC configuraton (webmvc-config.xml)


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr"
xsi:schemaLocation=" http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.directwebremoting.org/schema/spring-dwr
http://www.directwebremoting.org/schema/spring-dwr-2.0.xsd">

<!-- Maps request URIs to controllers -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>
/engine.js=dwrController
/util.js=dwrController
/call/**=dwrController
/dwr/**"=dwrController
/interface/**=dwrController
</value>
</property>
<property name="defaultHandler">
<!-- Selects view names to render based on the request URI: e.g. /main selects "main" -->
<bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
</property>
<property name="order" value="0"/>
</bean>

.....

<!-- Enable DWR AJAX functionality -->
<dwr:configuration>
<dwr:create javascript="TestData" type="spring" class="com.web.ajax.TestData"/>
<dwr:convert type="bean" class="com.data.ClassLoadingData" />
</dwr:configuration>

<dwr:controller id="dwrController" debug="true" />

<!-- configure spring creators -->
<bean id="testData" class="com.web.ajax.TestData">
<dwr:remote javascript="TestData">
<dwr:include method="refreshClassLoadingData" />
</dwr:remote>
<property name="jvmDataManager" ref="jvmDataManager"/>
</bean>

<bean id="jvmDataManager" class="com.web.jvm.impl.JvmDataManagerImpl/>



  • Step 3 Configure Spring creators - In the above configuration, we expose it directly as spring beans (e.g. testData ).

    The dwr:remote element is the element that will expose the bean to dwr. This is the best approach as it allows you to wire your dependencies like any other spring object.

    Secondly you can configure them in a dwr:configuration much in the same as the standard dwr.xml file works.

  • Step 4 Configure Spring converters - The spring converters must be configured inside of a dwr:configuration element in spring. Please refer the configuration above.

  • Other important elements to know:
  1. dwr:include : Used to include specific methods. Can be used with dwr:convert, dwr:create, or dwr:remote element
  2. dwr:exclude : Used to exclude specific methods. Can be used with dwr:convert, dwr:create, or dwr:remote element
  3. dwr:init : Optional element that will allow you to specify custom creator types and converter types.
  4. dwr:converter : Specifies a custom converter type, must be used within dwr:init.
  5. dwr:create : Specifies a custom creator type, must be used within a dwr:init.
  6. dwr:signature : Used to specify signatures much like the element in the standard dwr.xml.

NOTE: Please make sure you source TestData.js in the page as in the example below.

<script language='JavaScript' type='text/javascript' src='<root-context>/dwr/interface/TestData.js'/>

Replace <root-context> with your app's root context.

Example: AJAX Javascript function refreshClassLoadingData()

function refreshClassLoadingData(){
TestData.refreshClassLoadingData(function(data){
if (data != null){
DWRUtil.setValue('currentLoadedClasses', data.loadedClassCount);
}
});
}
//Please note the "data" represent the ClassLoadingData returned from AJAX function. So
//it is possible to access the variables of ClassLoadingData object in Javascript since
//it is converted as a bean in Javascript.

Example: TestData.java

public class TestData{
@Autowired
@Qualifier("jvmDataManager")
private IjvmDataManager jvmDataManager;

/**
* This is the AJAX function that can be called from UI via DWR AJAX
*/
public ClassLoadingData refreshClassLoadingData(){
return this.jvmDataManager.getClassLoadingData();
}
}


Conclusion
The DWR namespace support in spring configuration eliminates the need of having dwr.xml file placed inside WEB-INF folder. The sample configuration shown above is sufficient enough to get the DWR working with Spring 2.5.5 and spring webflow 2.0.3. Please note the TestData, ClassLoadingData shown above are all plain old java objects.

More Information on DWR is available here.