FileDocCategorySizeDatePackage
WorkflowDispatcher.javaAPI DocExample4078Sat Nov 22 19:35:12 GMT 2003s2wexample.controller

WorkflowDispatcher.java

package s2wexample.controller;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;

/**
 * An implementation of the dispatcher interface for processing
 * workflows.  A workflow is a linear path through a set of states,
 * with actions to determine each state transition.
 */
public class WorkflowDispatcher implements Dispatcher {
    /** tags used in the XML definition of workflows and states */
    private static final String WORKFLOW_TAG = "workflow";
    private static final String STATE_TAG = "state";
    
    /** attributes shared with JSP pages */
    private static final String NAME_ATTR = "name";
    private static final String ACTION_ATTR = "action";
    private static final String VIEW_ATTR = "viewURI";
    
    /** where action classes can be found */
    private static final String ACTION_PREFIX = "s2wexample.controller.actions.";
    
    /**
     * Internal representation of a state from the XML file
     */
    class State {
        /** state name */
        protected String name;
        
        /** transition action */
        protected Action action;
        
        /** uri to display */
        protected String viewUri;
    }
    
    /** the servlet context */
    private ServletContext context;
    
    /** the states this dispatcher uses as data */
    private State[] states;
    
    /** the current state of this dispatcher */
    private int currentState;
    
    /**
     * Called by the container to set the servlet context when this
     * dispatcher is initialized.
     */
    public void setContext(ServletContext context) throws IOException {
        // store the context
        this.context = context;
        
        // load the workflow from this file & parse it
        InputStream is = context.getResourceAsStream("/LanguageWorkflow.xml");
        try {
            states = parseXML(is);
        } catch(Exception ex) {
            throw new IOException(ex.getMessage());
        }
        
        // initialize the current state
        currentState = 0;
    }
    
    /**
     * Get the next page to forward the user to
     */
    public String getNextPage(HttpServletRequest req) {
        State s = states[currentState];
        
        // increment the state only if the action suceeds
        if ((s.action == null) || s.action.performAction(req, context)) {
            if (currentState < states.length - 1) {
                s = states[++currentState];
            } else {
                currentState = 0;
                s = states[currentState];
            }
        }
        
        // return the uri of the current state
        return s.viewUri;
    }
    
    /**
     * Parse the states XML file
     */
    private State[] parseXML(InputStream is) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        
        Document doc = builder.parse(is);
       
        // find the workflow element
        NodeList workflows = doc.getElementsByTagName(WORKFLOW_TAG);
        Element workflow = (Element)workflows.item(0);
        
        // find all the states
        NodeList states = doc.getElementsByTagName(STATE_TAG);
        State[] stateList = new State[states.getLength()];
        
        // read state information
        for(int i = 0; i < states.getLength(); i++) {
            stateList[i] = new State();
            
            Element curState = (Element)states.item(i);
            stateList[i].name = curState.getAttribute(NAME_ATTR);
            stateList[i].viewUri = curState.getAttribute(VIEW_ATTR);
            
            // convert action names into class instances
            String action = curState.getAttribute(ACTION_ATTR);
            if (action != null && action.length() > 0) {
                Class c = Class.forName(ACTION_PREFIX + action);
                stateList[i].action = (Action)c.newInstance();
            }
        }
        
        return stateList;
    }
}