这是我写的一个DEOM,目的在于对
的一个流程支持而写的状态机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 状态,如果大家有想要说的,尽管拍砖,共同进步
最后,给大家提供两个工作流方面的资料
《工作流模型分析》和《工作流管理联盟规范》