Wednesday, 29 May 2013

STRUTS ACTION - AGGREGATING ACTIONS IN STRUTS



If you are a Struts developer then you might have experienced the pain of writing huge number of Action classes for your project. The latest version of struts provides classes using which you can aggregate a related set of actions into a single unified action. In this article we will see how to achieve this. Struts provides four important classes for this purpose. These classes are called as Dispatchers. The important Dispatchers that struts provides includes : DispatchAction, ActionDispatcher , LookupDispatchAction andMappingDispatchAction.

All these classes can be found in the package org.apache.struts.actions. Let us look in to each of these in detail. Our examples use the simple CRUD actions.

DispatchAction: In this type of aggregation, the action class must extend DispatchAction class as shown.

public final class CRUDDispatchAction extends DispatchAction {

public ActionForward create(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
return (mapping.findForward("success"));
}
... 


and the action mapping will be as

<action path="/crudDispatchAction" type="com.companyname.projname.CRUDDispatchAction" name="formName" scope="request" input=" homeDef" parameter="methodToCall">
<forward name="success" path="targetDefName"/>
</action>


in your jsp you can call this action as

<html:link action="crudDispatchAction?methodToCall=create">Create</html:link>
... 


Observe that the above class extends DispatchAction and so you cannot use this method if your class already extends your (some) super class (eg., the class where the session is validated/invalidated). Here the user has to send a query string variable (methodToCall) to set the action name to call.

ActionDispatcher: This flavor of aggregation is same as DispatchAction except that we need not extend ActionDispatcher, so we can use this method even if our class extends a super class. The following code snippet shows this scenario.


public final class CRUDActionDispatcher extends Action {

protected ActionDispatcher dispatcher = new ActionDispatcher(this, ActionDispatcher.DEFAULT_FLAVOR);

public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
return dispatcher.execute(mapping, form, request, response);
}

The DEFAULT_FLAVOR field suggests that the default parameter is "method" if none is specified as parameter in struts-config.xml (eg,. methodToCall).
ActionDispatcher flavor also needs methodToCall parameter to be set (using hidden variable or a query string) as in case of DispatchAction.

LookupDispatchAction: This type of aggregation is useful in situations where in you have multiple submit buttons in a single form. The class must extend LookupDispatchAction. However, the great thing about this type is that its java script free. That means, you need not set any hidden variables or pass query string however, you must use submit buttons as shown.

<html:submit property="submit"><bean:message key="button.create"/></html: submit >
<html:submit property="submit"><bean:message key="button.read"/></html: submit >
...
The example Action class will be as follows

public class CRUDLookUpDispatchAction extends LookupDispatchAction {

protected Map getKeyMethodMap() {
Map map = new HashMap();
map.put("button.create", "create");
?
return map;
}
public ActionForward create(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
return (mapping.findForward("success"));
}
Observe the getKeyMethodMap() method. The submit button names are specified in a Map and their keys comes from MessageResources file. Struts picks up the name from this file and redirects it to the value specified in the Map. The calling code in jsp however has multiple submit buttons only differing in their names.

MappingDispatchAction: This aggregation extends MappingDispatchAction class. This is the most useful type among the four types available. But as seen in other cases, you can use this type only when your action does not extend any other action. The good thing about this type is that the action mappings can differ and so need not be the same as in all other cases. To illustrate this consider the below mappings.

<action path="/createMappingAction" type="com.bodhtree.CRUDMappingDispatchAction" scope="request" input="homeDef" parameter="create">
<forward name="success" path="targetDef"/>
</action>
<action path="/readMappingAction" type="com.bodhtree.CRUDMappingDispatchAction" name=" formName" scope="request" input="homeDef" parameter=" read">
<forward name="success" path="targetDef"/>
</action> 


Notice that in the first action mapping, there is no form bean while in the second the bean name is specified. This means that the user has the flexibility to change the mapping according to his needs and hence not been contained to use a constant mapping for all the CRUD actions. Note that in all the other types of aggregations, we must use the same mapping for all the CRUD actions.

Conclusion: Each of these types has their own pros and cons. DispatchAction is the default type which uses java script and we must extend DispatchAction to use it, ActionDispatcher is same as DispathAction except that we do not extend any action , LookupDispatchAction gives the flexibility to use multiple submit buttons while MappingDispatchAction allows us to change the action mappings according to our need. So each one of these has a particular usage and which one to use depends on the user requirement.

No comments:

Post a Comment

Simple CRUD in Laravel Framework

Creating, reading, updating, and deleting resources is used in pretty much every application. Laravel helps make the process easy using reso...