Dashboard > WebWork 1 > Spring Framework Integration
  WebWork 1 Log In View a printable version of the current page.  
  Spring Framework Integration
Added by Raymond Lai, last edited by Hani Suleiman on Sep 27, 2004  (view change)
Labels: 
(None)

Integrating the Spring Framework with Webwork 1.x (1.4.1 or higher)

This is a step by step guide on integrating WebWork with the Spring Framework http://www.springframework.org . Like the integration with PicoContainer (see PicoContainer Integration), Spring can be used to manage Webwork Actions, handle the "wiring" of business objects, action or any JavaBeans, by the time the web application starts up. Another benefit of integrating Spring is that it enables the use of interceptors and all other AOP features.

The first step is to ensure that you have the appropriate jars in place. Copy spring.jar to your WEB-INF/lib directory. If you want to use interceptors and other AOP features, then you should also copy cglib.jar, asm.jar, and aopalliance.jar to the web lib directory.

The next step is to specify an implementation of ActionFactoryProxy, SpringActionFactoryProxy. This will cause Webwork to first attempt to find actions in Spring's ApplicationContext; if it's not found Webwork will then look for it in the same manner as without Spring (simply instantiate the action class).

A custom ActionFactory, SpringActionFactory, must be specified to insert the SpringActionFactoryProxy into the ActionFactory stack.

In webwork.properties change/add this line:

webwork.action.factory=webwork.action.factory.SpringActionFactory

Finally, register the spring listener or servlet in your web.xml, by adding the following (this example uses the servlet for compatibility with old/odd containers, but if your container supports it you should use the spring listener instead).

web.xml

<servlet>
  <servlet-name>springloader</servlet-name>
    <servlet-class>
      org.springframework.web.context.ContextLoaderServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

This takes care of the webwork side of things. Next, spring must be configured.

For the purposes of this example, webwork has one Action class (com.springapp.TestAction). com.springapp.EntityManager is a 'manager' business object that the TestAction requires. TestAction has get/setManager methods that take in an EntityManager.

Spring can also be used to specify interceptors. In this example, a trivial TimerInterceptor is specified that simply logs the duration of method calls for all our beans (including actions).

WEB-INF/applicationContext.xml

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
  <!-- 
  The webwork action. Note that the name OR id must be the fully qualified 
  name, this is required for webwork to successfully look up the action, 
  as it uses class names. 

  The singleton property specifies that this bean should be created on 
  every call. WebWork assumes that there is an action is specific to 
  its request.
  ->
  <bean id="test" name="com.springapp.TestAction"
        class="com.springapp.TestAction" 
        singleton="false">
    <!- Specify the manager property of the action class ->
    <property name="manager"><ref local="entityManager"/></property>
  </bean>
  <!- Specify the entity manager. Here we are not required to us the 
  classname as the id or name, since it is not a webwork action. ->
  <bean id="entityManager" 
        class="com.springapp.EntityManager" singleton="true" />
  <!- Specify our timer interceptor ->
  <bean id="timerInterceptor" class="com.springapp.TimerInterceptor" />

  <!- 
  This bean is responsible for applying the interceptor to our classes.
  The proxyTargetClass must be set to true to enforce usage of cglib,
  rather than dynamic proxies. Dynamic proxies won't work with the valuestack
  ->
  <bean id="proxyCreator" 
        class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="proxyTargetClass">
      <value>true</value>
    </property>
    <!- Specify the interceptors to apply ->
    <property name="interceptorNames">
      <list>
        <ref bean="timerInterceptor"/>
      </list>
    </property>
    <!- Specify the beans to apply the interceptors on -->
    <property name="beanNames">
      <list>
        <value>test</value>
        <value>*Manager</value>
      </list>
    </property>
  </bean>
</beans>

For the sake of completeness, here are the Java sources:

TestAction.java

package com.springapp;

import webwork.action.ActionSupport;

public class TestAction extends ActionSupport
{
  private EntityManager manager;

  public EntityManager getManager()
  {
    return manager;
  }

  public void setManager(EntityManager manager)
  {
    this.manager = manager;
  }
}

EntityManager.java

package com.springapp;

public class EntityManager
{
  public String getStuff()
  {
    return "some stuff";
  }
}

TimerInterceptor.java

package com.springapp;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class TimerInterceptor implements MethodInterceptor
{
  private static final Log log = LogFactory.getLog(TimerInterceptor.class);

  public Object invoke(MethodInvocation methodInvocation) throws Throwable
  {
    if(methodInvocation.getMethod().getDeclaringClass()==Object.class)
    {
      return methodInvocation.proceed();
    }
    long startTime = System.currentTimeMillis();
    String className = methodInvocation.getThis().getClass().getName();
    int dot = className.lastIndexOf('.');
    if(dot > -1) className = className.substring(dot + 1, className.length());
    try
    {
      return methodInvocation.proceed();
    }
    finally
    {
      log.info(className + '.' + methodInvocation.getMethod().getName() 
      + " " + (System.currentTimeMillis() - startTime) + "ms");
    }
  }
}

All that remains is the standard webwork configuration of mapping views to actions via actions.xml or views.properties.

Finally, deploy your web application, and have Spring help with assembling and wiring business objects into your actions - no more lookup code across your Action code!

If you mean the getRootFactory method, then use the cvs version of webwork 1.4, which has this method. No new functionality, the sole purpose of it is some minor refactoring so that you can subclass it to just specify where to get java actions from, without having to copy and paste the rest of the action factories and proxies in your subclass.

Posted by Hani Suleiman at Jan 21, 2004 12:11 | Permalink

Does this example work with WebWork2? If not, what modifications would be required? Sorry newbie to WebWorks on a new project. Would prefer to use the latest and greatest.

Posted by Anonymous at Feb 03, 2004 17:14 | Permalink

This example works only with Webwork1. For Webwork2+XWork, there had been attempts done, like this

http://jira.opensymphony.com/secure/ViewIssue.jspa?key=XW-122

Also try search webwork's mailing list for details.

Posted by Raymond Lai at Feb 04, 2004 05:00 | Permalink

In the SpringActionFactoryProxy, the exception handling could be simplified a bit by only catching BeansException. NoSuchBeanDefinitionException extends BeansException.

Posted by Anonymous at Mar 03, 2004 13:42 | Permalink

Whoosh! The codes of SpringActionFactory and SpringActionFactoryProxy is now on Webwork1's CVS now! Hurray!

Posted by Raymond Lai at Mar 09, 2004 02:17 | Permalink

I have outlined what I had to do to get WebWork2 (and really XWork 1.0) configured for Spring here: http://www.ryandaigle.com/pebble/2004/03/08/1078768121000.html. I hope it's useful to some, or at least provides a different light on whatever else there may be out there.

Posted by rwdaigle at Mar 09, 2004 12:18 | Permalink

And have now posted it here on this wiki: [WW:WebWork 2 Spring Integration]

Posted by rwdaigle at Mar 14, 2004 19:42 | Permalink
Site powered by a free Open Source Project / Non-profit License (more) of Confluence - the Enterprise wiki.
Learn more or evaluate Confluence for your organisation.
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.2.9 Build:#527 Sep 07, 2006) - Bug/feature request - Contact Administrators