踩一踩OSWorkflow和jBMP:39行代码实现一个很好很强大的工作流引擎

踩一踩OSWorkflow和jBMP:39行代码实现一个很好很强大的工作流引擎,第1张

概述  现成的工作流引擎有很多,我以前曾浅尝过OSWorkflow和jBPM,但都未能深入研究。总感觉它们过于复杂,术语也特别多,让我对它们逐渐失去了兴趣(还有那些流程设计器,个人觉得完全没有存在的必要:1.一般的用户用不来;2.程序员直接写代码(流程定义代码量一般几十行就够了),要流程设计器干嘛?)。另外有一个开源的基于Grails的工作流项目:http://www.grailsflow.org/

 

现成的工作流引擎有很多,我以前曾浅尝过OSWorkflow和jBPM,但都未能深入研究。总感觉它们过于复杂,术语也特别多,让我对它们逐渐失去了兴趣(还有那些流程设计器,个人觉得完全没有存在的必要:1.一般的用户用不来;2.程序员直接写代码(流程定义代码量一般几十行就够了),要流程设计器干嘛?)。另外有一个开源的基于Grails的工作流项目:http://www.grailsflow.org/ ,尽管它宣称“GrailsFlow: Your Workflow just got easIEr!”,我感觉它还是做得太复杂,凭我多年的IT从业经验,竟然没看懂,我也不想继续把时间浪费在它上面。

 

工作流引擎,从本质上说,是状态机,只要控制好了各个状态之间的转换就行了。我使用Groovy/Grails有一段时间了,感觉Grails的webflow设计得不错,简单易懂,很好很强大,只可惜它只适合做在线支付之类的流程。但是webflow却给了我一些启发,尤其是它那优美的DSL方式的流程定义,让我印象深刻。利用Groovy的BuilderSupport,Closure,还有我已经整合到Grails中的db4o持久化框架,很容易快速写出一个工作流引擎。

 

我也用一把DSL,一个流程定义的例子如下:

 

   start {       on('submit') {o->           println o.state           // change o.state to a new state ...       }    }   state1 {       on('Action11') {o->           // do something with o and then change o.state to a new state ...       }   }   state2 {       on('Action21') {o->           // do something with o and then change o.state to a new state ...       }       on('Action22') {o->           // do something with o and then change o.state to a new state ...                  }   }
 

怎么样,够简洁吧?

在某个状态下,请求某个 *** 作后,要执行的具体动作在对应的closure中写好了。这些closures中的代码犹如诸葛亮的锦囊妙计,工作流引擎依计行事。

 

现在设想我们把DSL写在workflows目录下的demo.groovy(扩展名随便你怎么写)中,怎样使工作流引擎读懂这个流程呢?这需要一点点Groovy Builder的知识,自己看Groovy官方文档或Google。

 

我们的FlowBuilder长得像这个样子:

 

class FlowBuilder extends BuilderSupport {    private Map flow = [:]    private String _state    protected voID setParent(Object parent,Object child){}    protected Object createNode(Object name){        createNode(name,null)    }    protected Object createNode(Object name,Object value){        createNode(name,null,value)    }    protected Object createNode(Object name,Map attributes){        createNode(name,attributes,Map attributes,Object value){}    protected voID nodeCompleted(Object parent,Object node) {}    def invokeMethod(String name,args) {          switch(name) {            case 'flow':                super.invokeMethod name,args                break                case 'on':                flow[_state][args[0]] = args[1]                break            default:                _state = _state ? name : 'start' // the first state is always 'start'                flow[_state] = flow[_state] ?: [:]                super.invokeMethod name,args                break        }    }}
 

简单测试一下:

 

def builder = new FlowBuilder()def s = '{->'+'''   // DSL可从文件中读取   start {       on('submit') {o->           println o.state           // change o.state to a new state ...       }    }   state1 {       on('Action11') {o->           // do something with o and then change o.state to a new state ...       }   }   state2 {       on('Action21') {o->           // do something with o and then change o.state to a new state ...       }       on('Action22') {o->           // do something with o and then change o.state to a new state ...                  }   }'''+'}'this.class.classLoader.rootLoader.addURL( new URL("file:///E:/lib/bsf-2.4.0.jar") )def closure = new org.apache.bsf.BSFManager().eval("groovy",s)builder.flow closureprintln builder.flow

输出以下内容: 

[start:[submit:_$_run_closure1_closure2_closure5@31f2a7],state1:[action11:_$_run_closure1_closure3_closure6@131c89c],state2:[action21:_$_run_closure1_closure4_closure7@1697b67,action22:_$_run_closure1_closure4_closure8@24c4a3]]

 

这表明,流程定义已经被成功地装入一Map中。

 

其实,代码可以写得更精简:直接在文件中写成Map的形式(这可以看作另一种形式的DSL),以下是文章开头的图片所对应的工作流流程定义:

 

[    start : [        'Save as Draft' : {o,p,m->	        o.state = 'draft'            o.principals = [m]        },submit : {o,m->	        o.state = 'assign'	        o.principals = [p.principal]        }    ],draft : [        Save : {o,m->	        o.state = 'draft'            o.principals = [o.originator]        },assign : [        submit : {o,m->            o.state = 'working'        }    ],working : [        Ask : {o,m->            o.state = 'has_questions'            o.principals = [o.originator]        },m->            o.state = 'report_ready'            o.principals = [o.originator]        }    ],has_questions : [        Answer : {o,m->            o.state = 'working'            o.principals = [o.prevIoUsPrincipal]        }    ],report_ready : [        OK : {o,m->            o.state = 'end'            o.principals = [o.originator]        },NG : {o,_ds : [        report_type : {            return [['sas','SAS report'],['cogonos','Cogonos report']]            },principal : {	        def principals = []	    	User.findAll(sort:'username').each {			    principals << [it.username,it.profile?.name ?: it.username]		    }	        principals        }    ]]

 这样连FlowBuilder也省了,一行eval代码就解析并载入了流程定义。。。

 

以上内容还没涉及到我的工作流引擎,其实有了groovy语言的closure的强大支持,实现这个引擎实在是小菜一碟:

class WorkflowService {    static transactional = true    def formService	def process(params) {	    def params_values = JsON.parse(params.values)        def workflowBean = WorkflowBean.find(ID:params_values._bID)        def workflow        if(workflowBean) {            workflow = getWorkflow(workflowBean)        } else {            def workflowDef = WorkflowDeFinition.find(ID:params_values._fID)            if(workflowDef) {	            workflow = getWorkflow(workflowDef)                workflowBean = new WorkflowBean(state:'start',deFinition:workflowDef)            }        }	    def state = workflowBean.state		def action = workflow."$state"?."${params_values._action}"		if(action && action instanceof Closure) {			action.call(workflowBean,params_values,params.session.user.username)			workflowBean.save()			notifyPrincipals(workflowBean)			return [ok:true]		}        def arrayStore = [:]        workflow?._ds?.each {        	arrayStore[it.key] = it.value.call()        }	    def values = [_fID:workflowBean?.deFinition?.ID,_bID:workflowBean?.ID,_state:workflowBean?.state]	    workflowBean?.data?.each {		    values[it.key] = it.value	    }        [workflowBean:workflowBean,form:formService.getFlowForm(workflowBean,params.servletContext),values:values as JsON,arrayStore:arrayStore as JsON,_actions:workflow?."${workflowBean?.state}"?.keySet() as JsON]    }}

只有39行代码 -- 不能望39K女项背,我只能做个39L男 :-) 

总结

以上是内存溢出为你收集整理的踩一踩OSWorkflow和jBMP:39行代码实现一个很好很强大的工作流引擎全部内容,希望文章能够帮你解决踩一踩OSWorkflow和jBMP:39行代码实现一个很好很强大的工作流引擎所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1269660.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-08
下一篇 2022-06-08

发表评论

登录后才能评论

评论列表(0条)

保存