论坛首页 Java企业应用论坛

工作流引擎是否应该建立在有限状态机(Finite State Machine, FSM)引擎之上?

浏览 17157 次
精华帖 (2) :: 良好帖 (16) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-07-30  
最近一直在研究工作流。

工作流的种类:
1、侧重人机交互的工作流,以WFMC规范为重点参考;
2、侧重服务整合和应用自动化的工作流,以BPEL规范为重点参考。

无论哪种,陷进去都是一个坑。我关注前者,研究思路和方法:
1、了解规范:看WFMC的资料,了解5个接口模型,了解XPDL;
2、了解开源产品:研究OSWorkflow(这个我花了些力气,也在整理学习笔记)、Shark、OBE;
3、适度看看当前强大的商用工作流,以ULTIMUS为重点。

研究了几天,总觉得应该工作流应该基于Event-Driven FSM才是引擎的微内核,也更贴近WFMC所描述的概念与状态模型,而Petri Nets总觉得有点怪怪的。

于是又google翻这些资料,得看大师的文章:
http://en.wikipedia.org/wiki/Finite_state_machine
http://en.wikipedia.org/wiki/Event_driven_finite_state_machine
……

也找到了一些java FSM的实现,但还没深入研究。

这时候我想试问一下了:工作流是否应该建立在有限状态机(Finite State Machine, FSM)引擎之上?
还希望大家切磋、指导。
   发表时间:2009-07-30  
这是jfsm提供的使用FSM来做计算器的demo,代码很强很简洁

package org.jfsm.demo.calculator;

import org.jfsm.core.FSMException;
import org.jfsm.core.FSMInput;
import org.jfsm.core.FSMOutput;
import org.jfsm.core.RetSignal;
import org.jfsm.core.SimpleFSM;
import org.jfsm.core.SimpleFSMContext;

class CalcController {

    static public class CalcContext extends SimpleFSMContext {
        int num1, display;
        char op;

        void calculate() {
            switch (op) {
            case '+':
                num1 += display;
                break;
            case '-':
                num1 -= display;
                break;
            case '*':
                num1 *= display;
                break;
            case '/':
                num1 /= display;
                break;
            default:

            }
            display = num1;
        }

        @Override
        public String toString() {
            return "( num1:" + num1 + ", display:" + display + ", op:" + op + " )";
        }
    }

    static public class CalcInputs extends FSMInput<CalcContext> {
        SignalM<Character> key, digit, op;
        Signal backspace, equals;
    };

    private enum State {
        Init, Num1, Op, Num2
    }

    static class CalcFSM extends SimpleFSM<CalcContext, CalcInputs, FSMOutput> {

        @Override
        protected void build(TransitionMap tm) {
            tm.setInitialState(State.Init);

            tm.putDefault(in.key, null, mhKey);

            tm.put(State.Init, in.digit, State.Num1, mhFirstDigit);
            tm.put(State.Init, in.backspace, State.Init, ehClear);
            tm.put(State.Init, in.op, State.Op, mhOp);
            tm.put(State.Init, in.equals, State.Init, null);

            tm.put(State.Num1, in.digit, State.Num1, mhNumAppend);
            tm.put(State.Num1, in.backspace, State.Num1, ehNumBack);
            tm.put(State.Num1, in.op, State.Op, mhOp);
            tm.put(State.Num1, in.equals, State.Init, null);

            tm.put(State.Op, in.digit, State.Num2, mhFirstDigit);
            tm.put(State.Op, in.backspace, State.Op, ehClear);
            tm.put(State.Op, in.op, State.Op, mhOp);
            tm.put(State.Op, in.equals, State.Init, ehEquals);

            tm.put(State.Num2, in.digit, State.Num2, mhNumAppend);
            tm.put(State.Num2, in.backspace, State.Op, ehNumBack);
            tm.put(State.Num2, in.op, State.Op, mhOpOnNum2);
            tm.put(State.Num2, in.equals, State.Init, ehEquals);
        }

        MH<Character> mhKey = new MH<Character>() {
            public RetSignal handle(CalcContext context, Character key) {

                if (key >= '0' && key <= '9') {
                    return in.digit.asNextSignal(key);
                } else if (key == '+' || key == '-' || key == '*' || key == '/') {
                    return in.op.asNextSignal(key);
                } else if (key == '=')
                    return in.equals;
                else if (key == 'D')
                    return in.backspace;
                else
                    return null;
            }
        };

        EH ehClear = new EH() {
            public RetSignal handle(CalcContext ctx) {
                ctx.display = 0;
                return null;
            }
        };

        MH<Character> mhFirstDigit = new MH<Character>() {
            public RetSignal handle(CalcContext ctx, Character key) {
                ctx.display = 0;
                return in.digit.asNextSignal(key);
            }
        };

        MH<Character> mhNumAppend = new MH<Character>() {
            public RetSignal handle(CalcContext ctx, Character key) {
                ctx.display = ctx.display * 10 + (key - '0');
                return null;
            }
        };

        EH ehNumBack = new EH() {
            public RetSignal handle(CalcContext ctx) {
                ctx.display /= 10;
                return null;
            }
        };

        MH<Character> mhOp = new MH<Character>() {
            public RetSignal handle(CalcContext ctx, Character key) {
                ctx.op = key;
                ctx.num1 = ctx.display;
                return null;
            }
        };

        MH<Character> mhOpOnNum2 = new MH<Character>() {
            public RetSignal handle(CalcContext ctx, Character key) {
                ctx.calculate();
                ctx.op = key;
                return null;
            }
        };

        EH ehEquals = new EH() {
            public RetSignal handle(CalcContext ctx) {
                ctx.calculate();
                return null;
            }
        };

    }

    CalcInputs dispatcher;
    CalcContext ctx;

    public CalcController() throws FSMException {
        dispatcher = new CalcFSM().createInstance().getInput();
        ctx = dispatcher.newContext();
    }

}

0 请登录后投票
   发表时间:2009-07-30  
如果我没弄错,工作流引擎就是个有限状态机:)

不知道实现起来是否会遇到麻烦,支持这个做法!
0 请登录后投票
   发表时间:2009-07-30  
没看到过比较“纯粹”使用FSM的工作流产品,我现在也拿捏不准:如果基于FSM来架构,会是什么样子,会不会遇到难以逾越的困难?

看来又得战死很多脑细胞:)
0 请登录后投票
   发表时间:2009-07-31  
做了两年的工作流开发得出的一个结论,当前的工作流产品还不如一个简单的有效状态机,代码简单直观。
0 请登录后投票
   发表时间:2009-07-31  
之前我们的工作流也在维护状态,做transition,但更多时候状态只是一个属性,改变了属性后,通过持久化的此属性进行检索什么的,说难听的,我一直称之为工具,不叫引擎。

现在看了workflow patterns,看了FSM/Petri Net,才真是有点感觉,现在的关键是论证,持续的论证
0 请登录后投票
   发表时间:2009-08-04  
FSM的组件模型:

说明:
1、核心包括State、Transition、Condition、Action等对象,复杂对象(如基于事件的TriggerCondition)可基于这些基对象进行扩展、变化;
2、Transition通过fromState(source)及toState(target)进行状态的变迁,可能会触发Action;
3、State的类型包括initialState、normalState、terminationState三种。

工作项的StateModel:


下一步关注的重点:FSM适用的具体场景
  • 大小: 7 KB
  • 大小: 3.1 KB
1 请登录后投票
   发表时间:2009-08-04  
不错,其实工作流就应该是这个样子的。

State为什么还要分3种,没有这个必要把,就是一个单纯的状态,或者可以理解为传统工作引擎的节点

还有就是Transition我觉得fromState(source)就可以了,好像没有必要搞toState(target)吧。

0 请登录后投票
   发表时间:2009-08-05   最后修改:2009-08-05
rain2005 写道
不错,其实工作流就应该是这个样子的。

State为什么还要分3种,没有这个必要把,就是一个单纯的状态,或者可以理解为传统工作引擎的节点

还有就是Transition我觉得fromState(source)就可以了,好像没有必要搞toState(target)吧。




过程状态可以很多(比如很多次审批,但流程还在运行),但起始状态只能是一种(比如命名为“new”或者就是“initial”,类型为initial),而结束状态可以有多种(比如命名为“canclled”或“finished”或“aborted”,类型为terminationState)

但从类型来说,总体就是三种——我的观点


另外,Transition务必是从哪儿到哪儿,肯定得有去处。当然了,这种去处可能是一种JOIN,或者是自动活动(比如自动发邮件),但总归有去处,否则路就断了。
0 请登录后投票
   发表时间:2009-08-05  
楼主的思路也是不错的一种,可以参考jbpm4.0啊,它采用PVM来设计的,个人认为是一个更power的FSM。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics