Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

struts independent workflow solution - feedback wanted

Status
Not open for further replies.

DaveInBristol

Programmer
Nov 11, 2005
1
GB
Whilst trying to develop a workflow system for struts we came across the problem of making separate workflows independent. Using, for example, the firefox browser, new tabs or windows maintain the same session ID in the HTTP request. This means that two separate workflows will interfere when beans are placed on the session. We developed the following solution, any comments or suggestions would be welcome as there could well be a simpler or more elegant solution.



* Commit actions call the commit() method in WorkflowBean,
* Step actions don't
* all .jsp files have 'page' as a hidden form value (used to determine commit positions)
* The '*' and '{1}' are how the workflowID is transfers through the workflow process


struts-config.xml:

<form-beans>
<form-bean name="ExampleBean"
type="example.ExampleBean"/>
</form-beans>


<action-mappings>
<action path="/exampleAction"
parameter="ExampleBean"
type="workflow.BeginSuccessAction"
roles="power">
<forward name="success"
path="/page_one.jsp"
redirect="false"/>
</action>


<action path="/stepOne*"
attribute="{1}"
type="workflow.StepSuccessAction"
roles="power"
name="exampleBean"
input="/page_one.jsp">
<forward name="success"
path="/page_two.jsp"
redirect="false"/>
<forward name="error"
path="/error_page.jsp"
redirect="false"/>
<forward name="invalid_page"
path="/invalid_page.jsp"
redirect="false"/>
</action>

<action path="stepTwo*"
attribute="{1}"
type="workflow.StepSuccessAction"
roles="power"
name="exampleBean"
input="/page_two.jsp">
<forward name="success"
path="/page_three.jsp"
redirect="false"/>
<forward name="error"
path="/error_page.jsp"
redirect="false"/>
<forward name="invalid_page"
path="/invalid_page.jsp"
redirect="false"/>
</action>

<action path="/commitProcess*"
attribute="{1}"
type="example.ExampleAction"
roles="power"
name="exampleBean"
input="/page_three.jsp">
<forward name="success"
path="/success.jsp"
redirect="false"/>
<forward name="error"
path="/error_page.jsp"
redirect="false"/>
<forward name="invalid_page"
path="/invalid_page.jsp"
redirect="false"/>
</action>

</action-mappings>



Example .jsp snippet:


....headers here.....

<bean:define id="exampleBean" name="${workflowID}" type="example.exampleBean"/>

<h1>Title</h1>

<html:form action="/....name of action here.....${workflowID}.do" method="post">

<html:hidden property="page" value="...page number here...."/>

etc... etc...



Java code:



/**
* Extend this bean to use within workflows
*
*/
public abstract class WorkflowBean extends ValidatorForm {

public static final String INVALID_PAGE="invalid_page";

private String workflowID;
private int committedTo=-1;

/**
* Initialises the bean
*/
public void initialise(String workflowID){
this.workflowID=workflowID;
}

/**
* Validate the page based on where the
* workflow should be and is.
*
* Remember forward and back clicks do not call the
* actions they simply load from cache. Therefore this
* method must determine certain pages as commit pages.
*
* @return True if an acceptable page number
*/
public boolean validatePage(){
logger.debug("Checking valid page "+getPage()+
" where committed to "+committedTo);
return getPage()>committedTo;
}

/**
* Commits the bean up to the current page
*/
public void commit(){
logger.debug("Committed bean to page "+getPage());
committedTo=getPage();
}


public ActionErrors validate(ActionMapping mapping, HttpServletRequest req){
//place the bean key back in the request for validation
req.setAttribute("workflowID", workflowID);
//StrutsDebug.outputSessionAndRequest(req);
if(validatePage()){
ActionErrors errors = super.validate(mapping, req);
return errors;
}else{
return new ActionErrors();
}
}

public String getValidationKey(ActionMapping mapping, HttpServletRequest request) {
logger.debug("validation key: "+HalvorString.decapital(getClass().getSimpleName()));
return HalvorString.decapital(getClass().getSimpleName());
}

}







public abstract class WorkflowAction extends Action {

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

request.setAttribute("workflowID", mapping.getAttribute());

WorkflowBean wb = ((WorkflowBean)form);
if(!wb.validatePage()){
return mapping.findForward(WorkflowBean.INVALID_PAGE);
}

return executeAction(mapping, wb, request, response);
}

public abstract ActionForward executeAction(ActionMapping mapping, WorkflowBean form,
HttpServletRequest request, HttpServletResponse response)
throws Exception;

/**
* When called the bean is committed meaning
* that any calls to the same or previous pages
* will result in an invalid page error.
*/
public void commit(WorkflowBean wb){
wb.commit();
}


}





public abstract class BeginAction extends Action {

private static Logger logger = Log4jInit.getLogger(BeginAction.class);


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

//StrutsDebug.outputSessionAndRequest(request);

String workflowID = mapping.getParameter()+HalvorSecurity.getRandomID();

request.setAttribute("workflowID", workflowID);

WorkflowBean wb = (WorkflowBean)Class.forName(
mapping.getModuleConfig()
.findFormBeanConfig(mapping.getParameter()).getType()).newInstance();
wb.initialise(workflowID);

request.getSession().setAttribute(workflowID, wb);

return begin(mapping, (WorkflowBean)form, request, response);
}

public abstract ActionForward begin(ActionMapping mapping, WorkflowBean form,
HttpServletRequest request, HttpServletResponse response)
throws Exception;

}
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top