views:

565

answers:

2

Hi all,

We are expanding an old Struts 1 project to be Spring managed - yet we wish to change the code and the flow as little as possible. We have therefore decided to leave Struts to manage the requests and have delegated the actions via the org.springframework.web.struts.DelegatingActionProxy class.

Example:

The struts-config.xml contains:

<action name="InvalidSession" 
        path="/pages/InvalidSession"
     type="org.springframework.web.struts.DelegatingActionProxy" 
        scope="request">
    <forward name="success" path="/pages/Startup.do" />
</action>

The action-servlet.xml contains:

<bean name="/pages/InvalidSession"
      class="com.xxx.actions.InvalidSessionAction" />

Now the plot thickens:

Normal Spring beans have been defined in the applicationContext.xml. An example:

<bean id="parserUtils" class="com.xxx.el.parser.ParserUtils" >
    <property name="parserFactory" ref="parserFactory"/>
</bean>

I now wish to wire (not automatically - but that is not an issue) the parserUtils bean to an ActionForm.

Had I wanted to wire it to an Action I would simply define the follwing in the action-servlet.xml:

<bean name="/pages/CaseUpdate"
      class="com.xxx.actions.CaseUpdateAction" >
   <property name="parserUtils" ref="parserUtils" />
</bean>

where the following is in the struts-config.xml:

<action path="/pages/CaseUpdate" 
        name="CaseUpdateForm"
     type="org.springframework.web.struts.DelegatingActionProxy" 
        scope="request">
   <forward name="success" path="/pages/SwitchView.do" />
</action>

But the stuts-config also contains the following ActionForm definition:

<form-bean name="CaseUpdateForm"
           type="com.xxx.forms.CaseUpdateForm" />

and I wish to wire the parserUtils bean to the CaseUpdateForm class.

What must I do?

Thanks all!

A: 

You always have the option of programmatically fetching the parserFactory bean from the Spring context.

Spring's DispatcherServlet "publishes" the servlet's application context as a session attribute. You can retrieve the application context from there, and manually obtain your parserFactory from that context.

Something to get you started:

public Object getBean(ServletContext servletContext, String servletName, String beanName) {
    String attrName = FrameworkServlet.SERVLET_CONTEXT_PREFIX + servletName;
    BeanFactory beanFactory = (BeanFactory) servletContext.getAttribute(attrName);
    return beanFactory.getBean(beanName);
}

As you can see, you need access to the ServletContext object (which your ActionForm should be able to get using getServlet().getServletContext()), plus the name of the Spring servlet (as defined in web.xml), plus the name of the bean in the Spring application context that you need to retrieve.

It's pretty ugly, but it should work, if you have access to the above information.

skaffman
I am trying to avoid all that and to somehow configure all this "magically" :)
Yaneeve
Nothing magical about Struts. Since your Struts objects are not Spring-managed (just delegated), Spring has no say in their construction or configuration.
skaffman
A: 

It seems as if I have found a solution:

In the struts-config.xml file I have changed:

<form-bean name="CaseUpdateForm"
           type="com.xxx.forms.CaseUpdateForm" />

to:

<form-bean name="CaseUpdateForm"
           type="org.springframework.web.struts.SpringBindingActionForm" />

I have added the following to the action-servlet.xml file:

<bean name="CaseUpdateForm" 
      class="com.xxx.forms.CaseUpdateForm" >
   <property name="parserUtils" ref="parserUtils" />
</bean>

And:

<bean name="/pages/CaseUpdate" 
      class="com.xxx.actions.CaseUpdateAction" >
   <property name="caseUpdateForm" ref="CaseUpdateForm" />
</bean>

I have added the following to the CaseUpdateForm.java class file:

private ParserUtils parserUtils;

public void setParserUtils(ParserUtils parserUtils) {
    this.parserUtils = parserUtils;
}

And the following to the CaseUpdateAction.java class file:

private CaseUpdateForm caseUpdateForm;

public void setCaseUpdateForm(CaseUpdateForm caseUpdateForm) {
    this.caseUpdateForm = caseUpdateForm;
}

Finally the method:

public ActionForward execute(ActionMapping mapping,
                ActionForm form,
           HttpServletRequest request,
           HttpServletResponse response) 
          throws Exception

got the following lines of code inserted to it:

SpringBindingActionForm springBindingActionForm = (SpringBindingActionForm) form;
ServletRequestDataBinder binder = 
    new ServletRequestDataBinder(caseUpdateForm, "CaseUpdateForm");

binder.bind(request);
springBindingActionForm.expose(binder.getBindingResult(), request);

I also had to include the following jar in the classpath:

spring-webmvc.jar

That is due to the usage of the class: ServletRequestDataBinder

Yaneeve