流程图状态机DEMO(附件wf-statemachine-demo.rar下载)

这是我写的一个DEOM,目的在于对 

 

jquery 简易的流程图编辑控件 新版(20100907)

的一个流程支持而写的状态机DEMO

 

表达式使用IK EXPRESSION,以后会支持EL,也可能会支持JS,或者其他的脚本语言

 

没有测试,默认实现还有错误,以后会更新稳定版本的

 

下面是其中的部分代码:

 

 

package keng.core.workflow.state.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import java.util.concurrent.TimeoutException;

import keng.core.util.StringUtil;
import keng.core.workflow.state.ISMActionProcessor;
import keng.core.workflow.state.ISMContext;
import keng.core.workflow.state.ISMListener;
import keng.core.workflow.state.ISMNode;
import keng.core.workflow.state.ISMTransition;
import keng.core.workflow.state.ISMTransitionMatcher;
import keng.core.workflow.state.IStateMachine;
import keng.core.workflow.state.StateMachineException;

/**
 * 默认的状态机实现
 * 
 * @author 5Di
 * 
 */
public class DefaultStateMachine implements IStateMachine {

	/**
	 * 自动节点的默认动作
	 */
	public static final String ACTION_DEFAULT = "send";

	/**
	 * 进入循环后的最大循环次数
	 */
	public static final int MAX_DEEPTH = 6;

	// --------------------

	Stack<ISMNode> register = new Stack<ISMNode>();

	ISMTransitionMatcher matcher;

	ISMContext context;

	ISMActionProcessor processor;

	List<ISMListener> listeners;

	/**
	 * 根节点
	 */
	ISMNode nodeMap;

	boolean strict = false;

	public DefaultStateMachine(ISMNode nodeMap, ISMContext context) {
		this.context = context;
		this.nodeMap = nodeMap;
	}

	public DefaultStateMachine(ISMNode nodeMap, ISMContext context,
			ISMTransitionMatcher matcher) {
		this.nodeMap = nodeMap;
		this.context = context;
		this.matcher = matcher;
	}

	public DefaultStateMachine(ISMNode nodeMap, ISMContext context,
			ISMTransitionMatcher matcher, boolean strict) {
		this.context = context;
		this.nodeMap = nodeMap;
		this.matcher = matcher;
		this.strict = strict;
	}

	@Override
	public boolean transit(ISMNode node, String action, String state)
			throws StateMachineException, TimeoutException {
		if (action == null || action.isEmpty())
			throw new IllegalArgumentException("action can not be empty!");

		if (StringUtil.isEmpty(state))
			throw new IllegalArgumentException("state can not be empty!");

		if (node == null)
			throw new IllegalArgumentException("node can not be null!");

		List<ISMTransition> transitions = node.getTransitions();

		if (transitions == null || transitions.isEmpty())
			throw new StateMachineException("transitions can not be empty !");

		// 检查节点图,限制自动节点的转化深度
		if (node.isAuto())
			if (!checkNodeMap(node))
				throw new TimeoutException("die cycle");

		boolean b = false;
		for (ISMTransition transition : transitions) {
			boolean bool = transit(transition, action, state, node);

			if (bool) {
				b = true;
				if (register.indexOf(node) == -1)
					register.push(node);

				this.fireNodeTransit(node, state, transition.getToState());

				if (node.isAuto())
					this.fireAutoNodeTransit(node, state,
							transition.getToState());
			}
		}

		transitNextAutoNodes(node);

		return b;
	}

	/**
	 * 转换 parent的直接下级自动节点<br />
	 * 当遇到非自动节点时,自动结束
	 * 
	 * @param parent
	 * @throws StateMachineException
	 * @throws TimeoutException
	 */
	void transitNextAutoNodes(ISMNode parent) throws StateMachineException,
			TimeoutException {
		List<ISMNode> children = parent.getNextAutoNodes();
		if (children != null && !children.isEmpty()) {
			for (ISMNode child : children) {
				String action = child.getAction();

				if (action == null || action.isEmpty())
					action = ACTION_DEFAULT;

				transit(child, action, child.getState());
			}
		}
	}

	/**
	 * 
	 * @param transition
	 * @param action
	 * @param state
	 * @param node
	 * @return
	 * @throws StateMachineException
	 * @throws TimeoutException
	 * 
	 * @return 该transition 是否被执行
	 */
	boolean transit(ISMTransition transition, String action, String state,
			ISMNode node) throws StateMachineException, TimeoutException {
		boolean b = matcher.match(context, transition, action, state, strict);

		this.fireTransitionMatch(action, state, transition, b);

		if (!b)
			return false;
		else {
			this.fireTransitionMatched(action, state, transition);
		}

		// process action
		processor.process(transition);

		node.setState(transition.getToState());
		return true;
	}

	/**
	 * 检查节点图,防止进入死循环<br />
	 * 
	 * @param node
	 * @return 是否成功
	 */
	public boolean checkNodeMap(ISMNode node) {
		int i = 0;

		Iterator<ISMNode> it = register.iterator();
		while (it.hasNext()) {
			i = node.equals(it.next()) ? i + 1 : i;
		}

		return i <= MAX_DEEPTH;
	}

	@Override
	public boolean removeListener(ISMListener listener) {
		if (listeners == null || listeners.isEmpty())
			return false;

		if (!listeners.contains(listener))
			return false;

		listeners.remove(listener);

		return true;
	}

	@Override
	public void addListener(ISMListener listener) {
		if (listeners == null)
			listeners = new ArrayList<ISMListener>();

		listeners.add(listener);
	}

	@Override
	public boolean existsListener(ISMListener listener) {
		if (listeners == null || listeners.isEmpty())
			return false;

		return listeners.contains(listener);
	}

	/**
	 * 响应事件
	 * 
	 * @param node
	 * @param fromState
	 * @param toState
	 */
	void fireNodeTransit(ISMNode node, String fromState, String toState) {
		if (listeners == null || listeners.isEmpty())
			return;

		for (ISMListener listener : listeners)
			listener.onNodeTransit(node, fromState, toState);
	}

	/**
	 * 
	 * @param node
	 * @param fromState
	 * @param toState
	 */
	void fireAutoNodeTransit(ISMNode node, String fromState, String toState) {
		if (listeners == null || listeners.isEmpty())
			return;

		for (ISMListener listener : listeners)
			listener.onAutoNodeTransit(node, fromState, toState);
	}

	/**
	 * 响应事件
	 * 
	 * @param action
	 * @param state
	 * @param transition
	 * @param matched
	 */
	void fireTransitionMatch(String action, String state,
			ISMTransition transition, boolean matched) {
		if (listeners == null || listeners.isEmpty())
			return;

		for (ISMListener listener : listeners)
			listener.onTransitionMatch(action, state, transition, matched);
	}

	/**
	 * 响应事件
	 * 
	 * @param action
	 * @param state
	 * @param transition
	 */
	void fireTransitionMatched(String action, String state,
			ISMTransition transition) {
		if (listeners == null || listeners.isEmpty())
			return;

		for (ISMListener listener : listeners)
			listener.onTransitionMatched(action, state, transition);
	}
}
 

 

 

package keng.core.workflow.state;

import java.util.concurrent.TimeoutException;

/**
 * 状态机模型
 * 
 * @author 5Di
 * 
 */
public interface IStateMachine {

	/**
	 * 执行<br />
	 * 挨个try transition ,遇到第一个成功,理解返回<br />
	 * 执行逻辑:先匹配action 和 fromState ,然后calculate condition <br />
	 * 匹配策略,先匹配action,再匹配fromState,最后是condition<br />
	 * 
	 * @param action
	 *            当前执行的行为
	 * 
	 * @param state
	 *            当前的状态
	 * @param node
	 *            当前操作的节点
	 * 
	 * @return 是否被执行(如果自动执行的子节点返回了false,也会返回false),false并不说明没有成功,因为如果步骤进入了死循环(
	 *         系统自动执行的的步骤之间会进入死循环) ,在这种情况下不会抛出异常,而是直接返回false
	 */
	public boolean transit(String action, String state, ISMNode node)
			throws StateMachineException, TimeoutException;

}

 

 

 

package keng.core.workflow.state;

/**
 * 状态机条件
 * 
 * @author 5Di
 * 
 */
public interface ISMTransition {

	/**
	 * 条件
	 * 
	 * @return
	 */
	public ISMCondition getCondition();

	/**
	 * 动作
	 * 
	 * @return
	 */
	public String getAction();

	/**
	 * 处理器
	 * 
	 * @return
	 */
	public ISMActionProcessor getActionProcessor();

	/**
	 * 原始状态
	 * 
	 * @return
	 */
	public String getFromState();

	/**
	 * 目标状态
	 * 
	 * @return
	 */
	public String getToState();
}

 

package keng.core.workflow.state;

import java.util.Map;

import keng.core.workflow.model.WfStep;
import keng.core.workflow.model.WorkFlow;

/**
 * 上下文环境
 * @author 5Di
 *
 */
public interface ISMContext extends Map<String,Object>{

	public WorkFlow getWorkFlow();
	
	public String getAction();
	
	public WfStep getStep();
	
}

 package keng.core.workflow.state;

 

/**
 * Action处理器<br />
 * 当Transit Transition 的时候,会执行相应的Action处理器,一般实现类会执行特定的业务代码
 * 
 * @author 5Di
 * 
 */
public interface ISMActionProcessor {

	/**
	 * 处理
	 * 
	 * @return
	 */
	public Object process() throws StateMachineException;

	public void beforeProcess() throws StateMachineException;

	public void afterProcess() throws StateMachineException;
}

 

其他的还有:ISMNode.java,ISMCondition.java.. 就不贴出来了

 

下面是DefaultStateMachine.java 是IStateMachine.java的默认实现

 

 

package keng.core.workflow.state.impl;

import java.util.List;
import java.util.Stack;
import java.util.concurrent.TimeoutException;

import keng.core.util.StringUtil;
import keng.core.workflow.state.ISMActionProcessor;
import keng.core.workflow.state.ISMCondition;
import keng.core.workflow.state.ISMContext;
import keng.core.workflow.state.ISMNode;
import keng.core.workflow.state.ISMTransition;
import keng.core.workflow.state.ISMTransitionMatcher;
import keng.core.workflow.state.IStateMachine;
import keng.core.workflow.state.StateMachineException;

/**
 * 默认的状态机实现
 * 
 * @author 5Di
 * 
 */
public class DefaultStateMachine implements IStateMachine {

	Stack<ISMNode> register = new Stack<ISMNode>();

	ISMTransitionMatcher matcher;

	ISMContext context;

	/**
	 * 根节点
	 */
	ISMNode root;

	boolean strict = false;

	public DefaultStateMachine(ISMNode root, ISMContext context) {
		this.context = context;
		this.root = root;
	}

	public DefaultStateMachine(ISMNode root, ISMContext context,
			ISMTransitionMatcher matcher) {
		this.root = root;
		this.context = context;
		this.matcher = matcher;
	}

	public DefaultStateMachine(ISMNode root, ISMContext context,
			ISMTransitionMatcher matcher, boolean strict) {
		this.context = context;
		this.root = root;
		this.matcher = matcher;
		this.strict = strict;
	}

	@Override
	public boolean transit(String action, String state, ISMNode node)
			throws StateMachineException, TimeoutException {
		if (StringUtil.isEmpty(action))
			throw new IllegalArgumentException("action can not be empty!");

		if (StringUtil.isEmpty(state))
			throw new IllegalArgumentException("state can not be empty!");

		if (node == null)
			throw new IllegalArgumentException("node can not be null!");

		List<ISMTransition> transitions = node.getTransitions();

		if (transitions == null || transitions.isEmpty())
			throw new StateMachineException("transitions can not be empty !");

		// check che node
		if (checkNodeMap(node))
			return false;

		// Match the transition
		ISMTransition transition = matchTransition(action, state, transitions);

		boolean b = false;

		ISMCondition condition = transition.getCondition();
		if (condition == null)
			if (!strict)
				b = true;
			else
				throw new StateMachineException(
						"transition's condition can not be null!");

		b = condition.calculate(context, strict);

		if (!b)
			throw new TimeoutException("no transition was matched!");

		// process action
		ISMActionProcessor processor = transition.getActionProcessor();
		processor.process();

		register.push(node);

		// auto process next auto steps
		List<ISMNode> children = node.getChildren();
		if (children != null && !children.isEmpty()) {
			for (ISMNode child : children) {
				transit(action, state, child);
			}
		}

		node.setState(transition.getToState());

		return true;
	}

	/**
	 * 匹配transition <br />
	 * 使用<code>keng.core.workflow.state.ISMTransitionMatcher.match</code>匹配
	 * 
	 * @param action
	 * @param state
	 * @param transitions
	 * @return
	 */
	ISMTransition matchTransition(String action, String state,
			List<ISMTransition> transitions) {
		if (matcher == null)
			matcher = new DefaultSMTransitionMatcher();

		transitions = matcher.sort(transitions);

		int i, len = transitions.size();
		for (i = 0; i < len; i++) {
			ISMTransition transition = transitions.get(i);
			if (matcher.match(action, state, transition))
				return transition;
		}

		return null;
	}

	/**
	 * 检查节点图,是否进入了死循环<br />
	 * 目前还不完备,只是检查了已经执行过的node
	 * 
	 * @param node
	 * @return 如果已经执行,返回true
	 */
	public boolean checkNodeMap(ISMNode node) {
		return register.indexOf(node) != -1;
	}
}

 

 

目前还处于DEMO 状态,如果大家有想要说的,尽管拍砖,共同进步

最后,给大家提供两个工作流方面的资料

《工作流模型分析》和《工作流管理联盟规范》

 

你可能感兴趣的:(jquery,工作,workflow,脚本)