Monday, November 16, 2009

Configuring Struts 1.1 with Spring Framework:

Configuring Struts 1.1 with Spring Framework: Spring has its own MVC infrastructure base code, but Struts is widely uses MVC framework and much of the existing web application is built on Strut 1.1. As Spring has made J2EE development easier and DI (**Dependency Injection) is buzzword and has its benefits in moving dependency from Java code to XML configuration, thus making application more portable, easy maintenance, following contents discuss various option available for configuring Struts 1.1+ with Spring framework.
Spring has inbuilt support for integrating Struts 1.1 easily, if your application is using Struts for MVC.
There are various ways available for configuring Spring with Struts 1.1. Let’s walk through some of classes provided by Spring for Struts 1.1 support.
ActionServletAwareProcessor Spring ContextLoaderPlugin automatically registers this processor with underlying bean factory of its WebApplicationContext. It is implementation of BeanPostProcessor, passes ActionServlet to bean that extends Struts Action. ActionSupport Provides references for current Spring application Context. It auto detects ContextLoaderPlugIn context. AutowiringRequestProcessor Is subclass of Struts default RequestProcessor that autowires Struts Action with Spring beans defined in ContextLoaderPlugIn’s WebapplicationContext AutowiringTilesRequestProcessor Same as AutowiringRequestProcessor but also provides tiles functionality provided by original Struts TilesRequestProcessor ContextLoaderPlugin Struts 1.1+ PlugIn that loads a Spring application context for the Struts ActionServlet. This context automatically refers to root WebApplicationContext as parent. DelegatingActionProxy Proxy for spring managed Struts Action class. DelegatingActionUtils Provides common method for letting Struts Action to work with Spring WebApplicationContext. DelegatingRequestProcessor Subclass for Struts default RequestProcessor that looks up Spring managed Struts Action defined in ContextLoaderPlugIn. DelegatingTilesRequestprocessor Subcalss of Struts Tiles request processor that autowires Struts Action defined in ContextLoaderPlugIn’s WebApplicationContext.
DispatchActionSupport Convenient class for Spring aware Struts 1.1+ DispatchAction. LookupDispatchActionSupport Convenient class for Spring aware Struts 1.1+ LookupDispatchActions. MappingDispatchActionSupport Convenient class for Spring aware Stuts 1.2 MappingDispatchAction SpringBindingActionForm A thin Struts ActionForm adapter that delegates to Spring’s more complete and advanced data binder and Errors objects underneath the cover to bind POJOs and manage rejected values.
For more details, you can go through Spring API documentation or if more interested, you can walk through code of these classes (Source code is available on Spring framework Site). Spring provides following solutions for integrating Stuts with it. The options available are: • Writing Struts Action to extend Spring aware base class
• Delegating requests to Struts action configured in Spring application context.
Regardless of which approach one take, there is common configuration that need to take care of i.e. telling Struts about Spring application context. In order for Struts to have access to Spring-managed bean, a plug-in required to register, that is aware of the Spring application context. Spring provides Struts plug-in called ContextLoaderPlugIn. Following code is required struts-config.xml file to register this plug-in:




ContextLoaderPlugIn loads a Spring application context (for web, WebApplicationContext), using the context configuration files listed in contextConfigLocation property. Now that the plug-in is in place, we’re ready to choose an integration strategy. . Let’s look at how to create Struts actions that are aware of Spring application context. Spring’s WebApplicationContextUtils class provides convenient static methods that can be used to retrieve the application context. Using this context handle, Spring can be used as factory to retrieve beans required by action classes. Following code example shows this: public class DepartmentMaintAction extends BaseLookupDispatchAction
{
//This is service that will be required by this action class
//To fulfill client requirement.
private DepartmentService departmentService;
/**
* Save new department data to database *
* @param mapping Struts mapping object corresponding to this action
* @param form String ActionForm instance corresponding to this action
* @param request see
{@link HttpServletRequest}
* @param response see
{@link HttpServletResponse}
* @return ActionForward page to forward on success or failure */


public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { log.debug("DepartmentMaintenaceAction -save");
//Showing some portion of code , other code section removed //For sake of clarity
ActionMessages messages = new ActionMessages();
String forward = "afterSaveNew";

departmentForNew.setPuCode(puCode);
departmentForNew.setActInd(Constants.ACT_IND_N);
Date date = new Date();
departmentForNew.setLastUpdDate(date);
departmentForNew.setLastMakerDate(date);
if (isTokenValid(request)) {
// reset the token
resetToken(request);
//Calling utility method from WebApplicationContextUtils

//to retrieve ApplicationContext
ApplicationContext ctx=

WebApplicationContextUtils.getRequiredWebApplicationContext (getServlet().getServletContext());
departmentService= (DepartmentService)ctx.getBean(“departmentService”);
//Calling method on required service
isInsertSuccess =
departmentService.insertDepartment(departmentForNew);
} else {
return mapping.findForward("login"); }
return mapping.findForward(forward);
}
The code in bold (Green Color) uses getRequiredWebApplicationContext() method of WebApplicationContextUtils to retrieve Spring Application context and then retrieve required beans from it. The above approach has one drawback that it, for accessing required bean; you need to write above it every action class. One solution is to move this code to some base class and every Action will extend it. Spring provides some base Action class, ActionSupport or DispatchActionSupport or LookupDispatchActionSupport, for this. These classes are extension of respective Struts’s Action classes that overrides the setServlet() method to retrieve the Spring application context from the ContextLoaderPlugIn. Any class that extends ActionSupport will have access to Spring application context by calling getWebApplicationContext(). From there, the action class can retrieve beans directly from Spring by calling getBean() method. For Example, // This action class extends LookupDispatchActionSupport, from Spring API
public class DepartmentMaintAction extends LookupDispatchActionSupport
{
//Service required by this Action Class
private DepartmentService departmentService;
/**
* Save new department data to database *
* @param mapping Struts mapping object corresponding to this action
* @param form String ActionForm instance corresponding to this action
* @param request see
{@link HttpServletRequest}
* @param response see
{@link HttpServletResponse}
* @return ActionForward page to forward on success or failure */


public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)

{
log.debug("DepartmentMaintenaceAction -save");
ActionMessages messages = new ActionMessages();

departmentForNew.setLastMakerDate(date); ………………………………………………………………………………………………………………………………………………………………………………………
………………………………………………………………………………………………………………………………………………………………………………… //Showing only relevant code

//rest of code has been removed for clarity
if (isTokenValid(request)) {
// reset the token
resetToken(request);

departmentService= (DepartmentService)getWebApplicationContext.getBean(“departmentService” );
//Calling method on required service isInsertSuccess =
departmentService.insertDepartment(departmentForNew);
}
else {
return mapping.findForward("login");
}
return mapping.findForward(forward); }
Advantage of this approach to Struts-Spring integration is that it’s intuitive nature. Except extending to corresponding Strut’s action class, you extend various helper Action class provide by Spring support for Struts. But, disadvantage of this approach is that it tightly couples struts action code with Spring. Also, Struts action is responsible for looking up dependency from Spring Application Context. Spring provides other way to integrate Struts and Spring. In this approach you write Struts Action class that is completely unaware of integration with Spring. Using this approach, we can use Spring dependency injection to inject service beans into actions. Spring provides DelegatingRequestProcessor, a replacement of Struts’s default RequestProcessor. It looks up Struts Actions from Spring application Context. Following configuration required in struts-config.xml to achieve this.
If Struts application is using Tiles, then Spring provides DelegatingTilesRequestProcessor. This processor automatically send request to Struts actions that are configured in Spring application context. The way it finds the Spring-configured action depends on how you configure the actions in struts-config.xml file.
//struts-config.xml

// applicationContextWeb.xml


Whenever request comes in for /saveDepartment.do, DelegatingRequestProcessor will automatically refer to the Spring application context, looking for bean named /saveDepartment---same as action path defined in struts-config.xml file. DelegatingProcessor will look for bean /saveDepartment , so action path and bean name in context file should be same. public class DepartmentMaintAction extends BaseLookupDispatchAction {
private DepartmentService departmentService;
/**
* Save new department data to database *
* @param mapping Struts mapping object corresponding to this action
* @param form String ActionForm instance corresponding to this action
* @param request see
{@link HttpServletRequest}
* @param response see
{@link HttpServletResponse}
* @return ActionForward page to forward on success or failure */


public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) {
ActionMessages messages = new ActionMessages();
String forward = "afterSaveNew"; …………………………………………………………………………………………………………………………….. ……………………………………………………………………………………………………………………..
//Rest of codes have been removed for clarity
}
return mapping.findForward(forward); }
//Showing code section relevant to this concept //Setting Dependency
@Required public void setDepartmentService(DepartmentService departmentService) {
this.departmentService = departmentService; } } //end of class
Above declaration looks more like conventional Struts config. Action declaration. But difference is that DepartmentMaintAction is managed by Spring, not by Struts. When request comes for /saveDepartment, DelegatingRequestProcessor will ask Spring application context for bean whose type is com.struts.spring.tablemaint.action.DepartmentMaintAction and send the request to that bean. Also Spring will inject dependency departmentService for this action.
Configuration Specific to CQE: Plug-In configurations:




applicationContext.xml contains all Struts action that is going to managed by Spring. // applicationContext.xml (Please See Below)
As per above fig.., applicationContext.xml import other beans. Struts related Actions beans are defined in applicationContext-web.xml. For Example, . applicationContext-web.xml contains all Struts action managed by Spring container for table maintenance. Some Struts Action beans example:


ContextLoaderPlugIn load Spring beans declared in applicationContext.xml. CqeRequestProcessor actually extends Spring DelegatingRequestProcessor processor.
public class CqeRequestProcessor extends DelegatingRequestProcessor { //Other Code removed for sake of showing concept …………………………………………………………………………………………………………… …………………………………………………………………………………………………………… }

** Dependency Injection or Inversion of Control (IOC): IOC is a design pattern that externalizes application logic so that it can be injected into client code rather than written into it. Use of IOC in Spring framework separates the implementation logic from the client.

No comments: