/* * WorkflowManager.java * * Created on July 7, 2005, 4:57 PM * * To change this template, choose Tools | Options and locate the template under * the Source Creation and Management node. Right-click the template and choose * Open. You can then make changes to the template in the Source Editor. */ package org.tgdb.frame; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * * @author heto */ public class WorkflowManager implements IWorkFlowManager { private static final String WORKFLOWS_TAG = "workflows"; private static final String WORKFLOW_TAG = "workflow"; private static final String STATE_TAG = "state"; private static final String NAME_ATTR = "name"; private static final String ACTION_ATTR = "action"; private static final String PRE_ACTION_ATTR = "preaction"; private static final String VIEW_ATTR = "viewURI"; private static final String NEW_WORKFLOW_ATTR = "workflow"; private static final String ACTION_PREFIX = "org.tgdb.webapp.action."; private Caller caller; /** * Handles a workflow. */ class WorkflowObject { private String name; protected State[] states; public WorkflowObject(String name) { this.name = name; } public String getName() { return name; } } class State { protected String name; protected Action action; protected Action preAction; protected String viewURI; protected String newWorkflow; } private String currentWorkflowName; private int currentState; private boolean firstDone = false; private HashMap workflows; private int get; /** * Called by the controller */ public void setContext(ServletContext context) throws IOException { InputStream is = context.getResourceAsStream("xml/workflow.xml"); try { if (context == null) throw new Exception("Context is null!"); // Init the HashMap workflows = new HashMap(); // Parse XML and populate HashMap. parseXML(is); } catch (Exception e) { e.printStackTrace(); throw new IOException("WorkflowManager#setContext: "+e.getMessage()); } currentState=0; } public void setCaller(Caller caller) { this.caller = caller; } /** * Get the action class for an action name */ private Action getAction(String name) throws Exception { if (name != null && name.length() > 0) { Class c = Class.forName(ACTION_PREFIX + name); return (Action)c.newInstance(); } return null; } private void reset() { currentState = 0; firstDone = false; //currentWorkflowName = null; } /** * Get the workflow object from the request parameter "workflow". * If workflow not found, return null. * */ private WorkflowObject getWorkflow(HttpServletRequest req) { if (req.getParameter("workflow") != null) { reset(); currentWorkflowName = req.getParameter("workflow"); } if (currentWorkflowName == null) { reset(); return null; } /** * Get the right workflow object by the currentWorkflowName */ return (WorkflowObject)workflows.get(currentWorkflowName); } private boolean executePreAction(State s, HttpServletRequest req, ServletContext context) throws ActionException { if (s.preAction != null) { System.err.println("PreAction: State="+s.name+", PreAction="+s.preAction.getName()); return s.preAction.performAction(req, context); } else return true; } private String next(State s1, State s2, HttpServletRequest req, ServletContext context) throws ActionException { // Action if (s1==null || s1.action==null || s1.action.performAction(req, context)) { // Action ok } // PreAction if (s2==null || s2.preAction==null || s2.preAction.performAction(req, context)) { // PreAction ok } // Next Page if (s2!=null) return s2.viewURI; else return null; } private State getState(WorkflowObject wfo, int index) { State s = null; try { s = wfo.states[index]; } catch (Exception e) { e.printStackTrace(); } return s; } public String getNextPage3(HttpServletRequest req, ServletContext context) { String page = ""; try { HttpSession session = req.getSession(); /** Get workflow */ WorkflowObject wfo = getWorkflow(req); if (wfo==null) { reset(); throw new Exception("Workflow \""+req.getParameter("workflow")+"\" not found"); } // Get previous state State s0 = getState(wfo, get-1); /** Get current state */ State s1 = getState(wfo, get); //State s1 = wfo.states[currentState]; // Action (last state) if (s0==null || s0.action==null || s0.action.performAction(req, context)) { // Action ok if (s0!=null) { //Previous Action ok, get next state //currentState++; } } // PreAction if (s1==null || s1.preAction==null || s1.preAction.performAction(req, context)) { // PreAction ok } // View if (s1!=null) { page = s1.viewURI; } if (get>wfo.states.length) { get=0; } else get++; } catch (Exception e) { req.setAttribute("exception", e); e.printStackTrace(); page="error/GeneralError.jsp"; } return page; } /** * Get the next page in workflow. */ public String getNextPage(HttpServletRequest req, ServletContext context) { String page = ""; try { HttpSession session = req.getSession(); /** Get workflow */ WorkflowObject wfo = getWorkflow(req); if (wfo==null) { reset(); throw new Exception("Workflow \""+req.getParameter("workflow")+"\" not found"); } /** Get current state */ State s = wfo.states[currentState]; /** Is this the first state? */ if (currentState==0 && !firstDone) { /** Set current workflow */ Navigator nav = (Navigator)session.getAttribute("navigator"); nav.setCurrentWorkflow(wfo.getName()); firstDone = true; } else if (s.action==null || s.action.performAction(req, context)) { // Action completed successfully or there were no action. if (s.action!=null) System.err.println("Action: State="+s.name+", Action="+s.action.getName()); // Check the states number. if (currentState < wfo.states.length-1) { // Some state (not the last one) /** Go to next state */ s = wfo.states[++currentState]; } else { // Last State. Reset all variables. reset(); } } else { // Action failed throw new Exception("Action \""+s.action.getName()+"\" failed"); } /** Execute pre-action */ if (!executePreAction(s, req, context)) { throw new Exception("PreAction \""+s.preAction.getName()+"\"failed"); } // Check a reference to another workflow. // Begin the new workflow instead of current one. if (s.newWorkflow!=null && !s.newWorkflow.equals("")) { currentWorkflowName = s.newWorkflow; currentState=0; wfo = getWorkflow(req); if (wfo==null) { reset(); throw new Exception("Workflow \""+req.getParameter("workflow")+"\" not found"); } /** Get current state */ s = wfo.states[currentState]; /** Set current workflow */ Navigator nav = (Navigator)session.getAttribute("navigator"); nav.setCurrentWorkflow(wfo.getName()); /** Execute pre-action */ if (!executePreAction(s, req, context)) { throw new Exception("PreAction \""+s.preAction.getName()+"\"failed"); } page = s.viewURI; } else { /** Get view */ page = s.viewURI; } } catch (Exception e) { req.setAttribute("exception", e); e.printStackTrace(); page="error/GeneralError.jsp"; } return page; } public void printWorkflow() { String out = ""; Collection flows = workflows.values(); Iterator itr = flows.iterator(); out += "<workflows>\n"; while (itr.hasNext()) { WorkflowObject wf = (WorkflowObject)itr.next(); out += "<workflow name="+wf.name+">\n"; for (int i=0;i<wf.states.length;i++) { String actionName = ""; if (wf.states[i].action != null) actionName = wf.states[i].action.getName(); String viewURI = ""; if (wf.states[i].viewURI != null) viewURI = wf.states[i].viewURI; out += "<state name="+wf.states[i].name+" action="+actionName+" viewURI="+viewURI+"/>\n"; } out += "</workflow>\n"; } out += "</workflows>\n"; System.err.println(out); } private void parseXML(InputStream is) throws Exception { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(is); // Find the workflows element NodeList wrkflws = doc.getElementsByTagName(WORKFLOWS_TAG); Element e_wrkflws = (Element)wrkflws.item(0); // Find the workflow element NodeList workflows = doc.getElementsByTagName(WORKFLOW_TAG); //Element workflow = (Element)workflows.item(0); for (int j=0;j<workflows.getLength();j++) { Element workflow = (Element)workflows.item(j); WorkflowObject w = new WorkflowObject((String)workflow.getAttribute(NAME_ATTR)); // Find all states NodeList states = workflow.getChildNodes(); //NodeList states = doc.getElementsByTagNameNS(workflow.getPrefix(), STATE_TAG); // Create an array for states ArrayList arr = new ArrayList(); // Read state info for (int i=0;i<states.getLength();i++) { // Get element Node node = states.item(i); Element curState = null; if (node.getNodeType()==node.ELEMENT_NODE) { curState = (Element)node; State state = new State(); state.name = curState.getAttribute(NAME_ATTR); state.viewURI = curState.getAttribute(VIEW_ATTR); state.newWorkflow = curState.getAttribute(NEW_WORKFLOW_ATTR); // Convert Action names into class instances state.action = getAction(curState.getAttribute(ACTION_ATTR)); state.preAction = getAction(curState.getAttribute(PRE_ACTION_ATTR)); arr.add(state); } } State[] stateList = new State[arr.size()]; for (int k=0;k<arr.size();k++) { stateList[k] = (State)arr.get(k); } w.states = stateList; // Add the workflow object to the hashmap. this.workflows.put(w.getName(), w); } } catch (Exception e) { e.printStackTrace(); throw new Exception("WorkflowManager#parseXML: Error parsing XML. "+e.getMessage()); } } /** Creates a new instance of WorkflowManager */ public WorkflowManager() { //logger.debug("WorkflowManager#WorkflowManager: New WorkflowManager"); } }