Your first cup of DWR…

by Bram SmeetsApril 24, 2005

Ok, so you want to create a more intuitive and responsive web application?
And you’ve decided to give AJAX, HttpXmlRequest, DWR or any other buzzword of the last few months, a try?
Now, if you’re also using the Spring framework for building you’re applications, than you’ve come to the right blog..This blog entry provides you with an introduction to Direct Web Remoting (DWR) in conjunction with Spring. It assumes a basic knowledge of both JavaScript and building applications using Spring.

DWR

DWR makes it easy to use of Asynchronous JavaScript and XML (AJAX) for calling methods in your business layer. It allows you to use the AJAX technology without having to deal with the implementation details and cross-browser issues.
Although DWR comes with some build-in Spring support, there is no out-of-the-box seamless integration with your Spring web application. For instance, it requires a separate servlet to be defined in your web.xml and has no means of accessing beans from your web application context.

Let’s get started

Ok, first of all let’s configure the DwrServlet as a Spring MVC controller instead of a separate servlet. Luckily for us, Spring provides a controller which does just that, the ServletWrappingController. Add the following code to your dispatcher servlet application context in order to enable DWR as a standard controller.

<bean id="dwrController" class= "org.springframework.web.servlet.mvc.ServletWrappingController">
  <property name="servletClass">
    <value>uk.ltd.getahead.dwr.DWRServlet</value>
  </property>
  <property name="initParameters">
    <props>
      <prop key="debug">true</prop>
    </props>
  </property>
</bean>

Note the debug init parameter, which is recommended during development, as it provides useful bean listings. More importantly, note the way to specify init parameters to configure DWR.
Add an entry to your url mapping which maps all requests for a certain context path to this controller. Note that the example below is just one example of how to map all request for an entire path. Note that the mapping of the dwrController should be the last mapping as it catches all requests.

<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  <property name="mappings">
    <props>
      <prop key="/**/*.html">defaultController</prop>
      <prop key="/**/*">dwrController</prop>
    </props>
  </property>
</bean>

Also make sure to map requests for files with all extensions (and without extensions) to the Spring dispatcher servlet in your web.xml. So, instead of mapping just JSP or HTML extensions, make sure to map request for all file extensions like in the example below. The example assumes a Spring DispatcherServlet to be defined, named main.

<servlet-mapping>
  <servlet-name>main</servlet-name>
  <url-pattern>/dwr/*</url-pattern>
</servlet-mapping>

Configure DWR

The DWR servlet assumes a configuration file: /WEB-INF/dwr.xml, although this is configurable as an init parameter. Below is a sample configuration file, which assumes a bean with id productManager in your application context.

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE dwr PUBLIC
    "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
    "http://www.getahead.ltd.uk/dwr/dwr10.dtd">

<dwr>
  <allow>
    <convert
        converter=”bean”
        match=”your.package.*”/>

    <create
        creator=”spring”
        javascript=”productManager”>
      <param name=”beanName” value=”productManager”/>
    </create>
  </allow>
</dwr>

First of all, note that currently DWR includes a Spring creator by default. This creator allows you to expose the productManager which is defined in your web application context. This can either be used to create a new application context, or to lookup an existing servlet application context or global web application context. This example assumes an existing application context to be available.

In the <allow> section of your configuration you first of all define a converter for converting standard JavaBeans to JavaScript objects. Although this comes with DWR it is not enabled by default. DWR does support conversion of amongst others primitives, Strings, Collections and Maps. Note, that you enable the bean converter only for the packages in which your data classes exist.

Last, you define a <create> entry for each bean you want to expose through DWR. In this example we expose a bean with id productManager. Note the javascript attribute which specifies the name of the JavaScript file to include in your page, as discussed below.

Access your bean

Now that we’re all set up, let’s access our exposed product manager. Assume the product manager has a method getAllProducts() which returns a List of all known products (which are JavaBeans). First we have to include the following two JavaScript files in our page:

<script type='text/javascript' xsrc='/dwrPath/interface/productManager.js'></script>
<script type='text/javascript' xsrc='/dwrPath/engine.js'></script>

Where ‘dwrPath‘ is the path under which you mapped the dwrController. Now, the only thing you have to do is call the method on the product manager. Assume we want have a button to retrieve the information and a span to display the product information in an unordered list:

<input type="button" onclick="productManager.getAllProducts(productCallback);" value="Get all products"/>
<script type="text/javascript">
  var productCallback = function(products) {
  var text = 'Products: <br><ul>';
  for(i = 0; i < products.length; i++) {
    text += '<li>';
    text += products[i].name;

    text += ‘ (’;
    price= products[i].price;
    text += price.currency;
    text += ‘ ‘;
    text += price.value;
    text += ‘)’;
    text += ‘</li>’;
  }
  text += '</ul>';
  document.getElementById(’productlist’).innerHTML = text;
}
</script>
<span id=”productlist”>

Note the nested properties price.currency and price.value. They are resolved correctly only when the Product and Price class are under the path matched by the bean converter (i.e. your.package. in this example). Posting nested properties back to the server is not yet supported.

Debugging

DWR has some build in debugging support. As we set the debug init parameter to true, this debugging support is enabled. Point your browser to the path /dwrPath, where ‘dwrPath‘ is the path under which you mapped the dwrController. You will now get a listing of all beans that are exposed through DWR. By clicking one of them, you get a listing of all methods that are exposed. You can use this page to get examples of how to call the method (in the source).

Utilities

DWR has also some build in utility functions and means to perform error handling. More information on this can be found here. Also note that DWR claims to fallback to iframes for invoking methods on the server on platforms that do not support the HttpXmlRequest method, which should ensure high browser compatibility.

Good luck

I hope this small tutorial has given you some inside into how to use DWR in conjunction with Spring and help you to easily build web application using the AJAX technology. I’m currently looking into real-time, server-side form validation using this technology. Check back on this blog in order to stay up to date on the progress.