Vous êtes sur la page 1sur 9

Dynamic Flow Control in Struts Applications

Author : Arun Kumar Dubagunta

1Preface
1.1Objective

Objective of this document is to discuss a solution to dynamically control the flow


in struts applications.

1.2Scope

Any struts application can use the solution discussed to control the flow.

2Flow control in Struts Applications


The Struts Framework provides ActionForward class, which can transfer the
control from an Action class to another resource (JSP, HTML, call to another
action etc.,).

There are two ways to specify the next resource in the flow.

Using the <forward> tag in the <action-mapping> of the Struts-Config.xml file


and using mapping.findForward(<forwardname>) in the

<action path="/testaction"

type="com.mycom.test.TestAction"

parameter="method" >
<forward name="success" path="welcome.jsp" />

</action>

ActionForward forward = mapping.findForward(“success”);

By creating the new instance of the ActionForward.

ActionForward forward = new ActionForward(“welcome.jsp”);

In most of the applications the first way is used to control the flow. Even when
the second method is used the destination resource is hardcoded or read from
a constants/properties file, but most of the times it is specific to an action.

3Dynamic flow control.


One of the solutions would be to move the control logic to a custom
ActionMapping class so that the flow of control across resources can be
controlled dynamically.

The mapping information can be maintained in a database or in an XML or any


other persistence storage.

The solution discussed here makes use of an XML to maintain the mapping
information, similar to the one shown below.

<config>

<action>

<name>/loginl</name>

<success>loginsuccess.jsp</ success>

<failure>loginfailure.jsp</ failure>

</action>

<action>

<name>/welcome</name>

<welcome>/general/welcome.jsp</welcome>

<b2bwelcome>/b2b//b2bwelcome.jsp</b2bwelcome>

</action>

</config>
4Custom ActionMapping
A Custom ActionMapping class is created which extends the Struts provided
ActionMapping. The forward method is overridden to pass the control to next
resource location, this method looks for the presence of the resource in the
Map object which gets updated at regular intervals,

i. If it is available this creates a new instance of ActionForward with the


resource location

ii. If not, the ActionForward corresponding to the forward name in the


structs-config.xml is returned.

public class FlowersActionMapping extends ActionMapping{

public ActionForward findForward(String forwardName) {

Map map = new HashMap();

String forwardPath = null;

map = DynamicMappingUtilPlugIn.getInstance().forwardMap;

if(map != null){

forwardPath = (String)map.get(getPath()+":"+forwardName);

if(forwardPath != null){

return new ActionForward(forwardPath);

}else if(forwardName != null ){

return super.findForward(forwardName);

}else{

return null;

The custom ActionMapping class can be associated with the <action> tag
using the attribute classname.
<action path="/welcome"

type="com.mycom.test.TestAction"

parameter="method"

className="com.mycom.struts.mapping.CustomActionMapping">

<forward name="success" path="welcome.jsp" />

</action>

5Forward Info Caching.


As getting the information from a Database/ reading an XML is an expensive
operation we use a Singleton class which implements the Runnable interface,
this class reads mapping information at regular intervals and stores it in a local
Map object.

public class DynamicMappingUtilPlugIn implements Runnable, PlugIn{

private ServletContext context = null;

private String configRel = "/WEB-INF/config/";

private static String configPath = null;

private String configFile = "dynamic-mapping.xml";

private static Thread starter = null;

Map forwardMap = null;

private static long cacheInterval = 60000;

private static DynamicMappingUtilPlugIn dynamicMappingPlugIn = null;

public void init(ActionServlet servlet, ModuleConfig modConfig) throws


ServletException {

DynamicMappingUtilPlugIn.getInstance(servlet.getServletConfig());

/**

* Returns the singletonInstance of the DynamicMapping Plugin

* @return
*/

public static DynamicMappingUtilPlugIn getInstance() {

if(dynamicMappingPlugIn == null) {

dynamicMappingPlugIn = new DynamicMappingUtilPlugIn();

log.debug("Inside getInstance starting the Thread");

return dynamicMappingPlugIn;

/**

* Returns the singletonInstance of the DynamicMapping Plugin

* @return

*/

public static DynamicMappingUtilPlugIn getInstance(ServletConfig


servletconfig) {

if(dynamicMappingPlugIn == null) {

dynamicMappingPlugIn = new DynamicMappingUtilPlugIn();

log.debug("Inside getInstance starting the Thread");

dynamicMappingPlugIn.init(servletconfig);

return dynamicMappingPlugIn;

private void init(ServletConfig servletconfig)

log.debug("Initializing DynamicMappingCache...");

configPath = servletconfig.getServletContext().

getRealPath( configRel + configFile);

starter = new Thread(dynamicMappingPlugIn);


starter.setDaemon(true);

starter.start();

log.debug("DynamicMappingCache initialized...");

public void run()

try

Thread.sleep(10000);

while(true)

log.debug("Inside thread run method ");

populateForwardMap();

Thread.sleep(cacheInterval);

catch(InterruptedException ex)

log.error(ex);

private void populateForwardMap(){

try {

DocumentBuilderFactory docBuilderFactory =

DocumentBuilderFactory.newInstance();

DocumentBuilder docBuilder =
docBuilderFactory.newDocumentBuilder();

Document doc = docBuilder.parse(configPath);

// normalize text representation

doc.getDocumentElement().normalize();

NodeList listOfMappings = null;

listOfMappings = doc.getElementsByTagName("action");

int noOfDataSources = listOfMappings.getLength();

String nodeName = "";

forwardMap = new HashMap();

for (int s = 0; s < noOfDataSources; s++) {

Node firstDataSetNode = listOfMappings.item(s);

NodeList childNodeList =

firstDataSetNode.getChildNodes();

if(childNodeList != null){

int noOfChildNodes = childNodeList.getLength();

for (int i = 0; i < noOfChildNodes; i++) {

if(childNodeList.item(i).getNodeName().equals("name"))

nodeName = childNodeList.item(i).getChildNodes().

item(0).getNodeValue();

if(!childNodeList.item(i).getNodeName().equals("name") &&
childNodeList.item(i).hasChildNodes()){

forwardMap.put(nodeName + ":" +
childNodeList.item(i). getNodeName(),
childNodeList.item(i).getChildNodes().

item(0).getNodeValue());

}
}

} catch (SAXParseException err) {

err.printStackTrace();

} catch (SAXException e) {

e.printStackTrace();

Exception x = e.getException();

((x == null) ? e : x).printStackTrace();

} catch (Exception t) {

t.printStackTrace();

public String getConfigFile() {

return configFile;

public String getConfigRel() {

return configRel;

public void setConfigFile(String string) {

configFile = string;

public void setConfigRel(String string) {

configRel = string;

Vous aimerez peut-être aussi