11.27.06

HOWTO: Use Direct Web Remoting (DWR) with Spring Framework and Java5 Annotations

Posted in Java, Web Development at 12:20 am by skoobi

DWR is an Open Source Java library that allows to write AJAX-enabled Web Sites. Since the “AJAX” term is used to to describe pretty much anything from rich Web User Interfaces to auto-completing combo boxes to asynchronous communication between the web client and the server, here is a more technical introduction that explains what DWR allows to do :

DWR is basically a Remote Method Invocation framework that allows to “export” server-side Java Objects to the javascript-enabled web client thanks to a transparent communication layer that dynamically (at runtime) generates the client stubs. So, in other terms, You have server side Java methods that you want to run from the client. DWR takes these classes/methods and provides you with a javascript file (generated on-the-fly) that provides javascript classes/methods that once called, will handle all the method calls, marshalling/unmarshalling, etc..

DWR does not provide any UI-abstraction layer. In order to create nifty graphics, you have to complement it with another framework like Dojo toolkit, or Script.aculo.us
Since the official documentation isn’t particularly clear on how to get DWR to work with Spring-managed beans and Java5 Annotations, here is a mini-HOWTO that completes it. (Anyone is free to use this HOWTO under any OSI-approved Open Source license). Nothing is easier to understand than a simple example, so we are going to create a Client Side Logger API that logs the events on the server-side thanks to Log4j. (A real-world example should use some abstraction layer like Commons-Logging , and should result in the creation of a backend to some of the popular Javascript logging frameworks, like Log4Javascript, instead of reinventing yet another logging API).

As a sidenote, DWR is part of the typical Bleeding Edge Web-Framework Stack that I wrote about in a previous post. Surely, not everybody uses this Stack, but it gives an idea of what the current trend in the Java world is. The current java world is full of innovation. Every 2 days, a new framework arrives on the scene, and beginners are more and more afraid of the overall complexity of the platform (if we can call this a platform, because it more looks like a set of unrelatedĀ  tools that people struggle to use together, in opposition to Microsoft .Net’s stack that we can safely call a “solution” because of the tight integration between the components). Innovation is doublessly a very good thing, and nothing should prevent innovation from happening. However, I believe it is also very important to document the best practices and tools and try to gather the community around a limited set of paradigms and frameworks. It doesn’t make sense to have a different framework for each programmer in this world. And in my humble opinion, using such an RMI-like system for communicating between Java classes and Javascript is definitely one of the best and efficient (from the developers viewpoint) practices around.
Java class

The first step is to create the annotated Java5 class that will be exported to the Javascript client. All exported methods must be annotated thanks to the @RemoteMethod annotation, and the @Create annotation is used at the class level to tell DWR that the class is instantiated using the Spring Framework. The beanName parameter must reflect the name of the bean in Spring’s application context file.

@Create(creator = SpringCreator.class, creatorParams = { @Param(name = “beanName”, value = “clientSideLogger”) })
public class ClientSideLogger {

public static Logger logger = Logger.getLogger(ClientSideLogger.class);

/**
* @param arg0
* @see org.apache.log4j.Category#debug(java.lang.Object)
*/
@RemoteMethod
public void debug(String arg0) {
logger.debug(arg0);
}

/**
* @param arg0
* @see org.apache.log4j.Category#error(java.lang.Object)
*/
@RemoteMethod
public void error(String arg0) {
logger.error(arg0);
}

/**
* @param arg0
* @see org.apache.log4j.Category#fatal(java.lang.Object)
*/
@RemoteMethod
public void fatal(String arg0) {
logger.fatal(arg0);
}

/**
* @param arg0
* @see org.apache.log4j.Category#info(java.lang.Object)
*/
@RemoteMethod
public void info(String arg0) {
logger.info(arg0);
}

/**
* @param arg0
* @see org.apache.log4j.Category#warn(java.lang.Object)
*/
@RemoteMethod
public void warn(String arg0) {
logger.warn(arg0);
}

Spring Configuration

In order to instantiate the ClientSideLogger class with Spring, we can create the following dwr.xml file, that is going to create a “clientSideLogger” singleton :

<?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:aop=”http://www.springframework.org/schema/aop” xmlns:tx=”http://www.springframework.org/schema/tx”
xsi:schemaLocation=”http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd”>

<bean id=”clientSideLogger” class=”fr.cvf.vodoo.ihm.portal.dwr.ClientSideLogger” />

</beans>

Web.xml glue

The next step is to write the usual glue (setup the DWR/Spring servlet, etc…).

In your web.xml, you can add :

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/dwr.xml</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!– DWR servlet , that should list all annotated classes–>
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<display-name>DWR Servlet</display-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>classes</param-name>
<param-value>
package.ClientSideLogger
</param-value>
</init-param>
</servlet>

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

Javascript Code
The final step is to use the logging using the automagically generated javascript API.

First, make sure the following javascript files are included :

<script type=’text/javascript’ xsrc=’/dwr/interface/ClientSideLogger.js’>
</script>
<script type=’text/javascript’ xsrc=’/dwr/engine.js’></script>
<script type=’text/javascript’ xsrc=’/dwr/util.js’></script>

And you can use the API :

ClientSideLogger.error(”error message”);

That’s all you have to do !

Leave a Comment