Thursday, 21 May 2009

Method B : Override the Struts RequestProcessor with Spring's DelegatingRequestProcessor

To avoid the above disadvantage of coupling the Struts Action to the Spring framework, you can override the Struts RequestProcessor processor with the org.springframework.web.struts.DelegatingRequestProcessor class.

To do the above just use tag to override the default Struts RequestProcessor with the DelegatingRequestProcessor in Struts-config file. Then register the action in Spring config file where you register other beans.


<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

<struts-config>
<form-beans>
<form-bean name="searchForm" type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="id" type="java.lang.Long"/>
</form-bean>

</form-beans>

<global-forwards type="org.apache.struts.action.ActionForward">
<forward name="welcome" path="/welcome.do"/>
<forward name="searchEntry" path="/searchEntry.do"/>
<forward name="searchSubmit" path="/searchSubmit.do"/>
</global-forwards>

<action-mappings>
<action path="/welcome" forward="/WEB-INF/pages/welcome.htm"/>

<action path="/searchEntry" forward="/WEB-INF/pages/search.jsp"/>

<action path="/searchSubmit"
type="struts.spring.employee.actions.FindEmployeeAction"
input="/searchEntry.do"
validate="true"
name="searchForm">
<forward name="success" path="/WEB-INF/pages/detail.jsp"/>
<forward name="failure" path="/WEB-INF/pages/search.jsp"/>
</action>

</action-mappings>

<message-resources parameter="ApplicationResources"/>

<controller processorClass="org.springframework.web.struts.DelegatingRequestProcessor"/>

<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames" value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>


<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/beans.xml"/>
</plug-in>


</struts-config>



and here is Spring config file. Register the action here and remember name attribute to match the struts-config action mapping name.
employeeService property will be populated at runtime using getter injection.


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<bean id="employee_1" class="struts.spring.employee.beans.Employee">
<property name="id" value="1" />
<property name="name" value="Sneha" />
</bean>

<bean id="employee_2" class="struts.spring.employee.beans.Employee">
<property name="id" value="2" />
<property name="name" value="Prashant" />
</bean>

<bean id="employeeService" class="struts.spring.employee.business.EmployeeImpl">
<property name="employees">
<map>
<entry key="1">
<ref bean="employee_1" />
</entry>
<entry key="2">
<ref bean="employee_2" />
</entry>
</map>
</property>
</bean>

<bean name="/searchSubmit"
class="struts.spring.employee.actions.FindEmployeeAction">
<property name="employeeService">
<ref bean="employeeService"/>
</property>
</bean>

</beans>



Now your action class extend the Struts's org.apache.struts.action.Action Class instead of Spring ActionSupport Class.


public class FindEmployeeAction extends Action{

private EmployeeI employeeService;

public EmployeeI getEmployeeService() {
return employeeService;
}

public void setEmployeeService(EmployeeI employeeService) { //1
this.employeeService = employeeService;
}

public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {

DynaActionForm searchForm = (DynaActionForm) form;
Long id = Long.parseLong(searchForm.get("id").toString());

System.out.println("Inside FindEmployeeAction_2 id = "+id);

Employee employee = getEmployeeService().findEmployeeById(id);

if (null == employee) {
System.out.println("employee not found");
return mapping.findForward("failure") ;
}

System.out.println("employee found");
request.setAttribute("emp", employee);
return mapping.findForward("success");
}
}



As you have seen at 1 employeeService JavaBean property will be automatically populated by the DelegatingRequestProcessor.

Merits:
1. Protects the Struts action from knowing it's being managed by Spring while giving you all the benefits of Spring's action management framework.
2. Because your Struts actions are oblivious to the existence of Spring, you can swap out Spring for some other inversion of control container without refactoring your Struts code.
3. This approach is definitely better than the first one

Demerits:
1. If you were using a different RequestProcessor, then you would need to integrate the Spring DelegatingRequestProcessor manually.
2. The added code would become a maintenance hassle and would also reduce your application's flexibility going forward. Moreover, there has been some talk of replacing the Struts RequestProcessor with a chain of command. Such a change would negatively impact the longevity of this solution.

Hope it will be useful...

References : http://www.ibm.com/developerworks/java/library/j-sr2.html

No comments: