Drools 5.1.1_DOC (58)
第14章 业务流程模型与表示法( Business Process Model and Notation——BPMN 2.0)
- 业务流程模型与表示法 (BPMN) 2.0规范正稳步向前成为一个伟大的标准,我们采用它在Drools流中建模。BPMN 2.0不仅就如何图形化表示一个业务流程(如BPMN 1)定义了一个标准,而且现在包括了用于元素定义的执行语义,以及有关如何存储(与共享)流程定义的一种XML格式。
Drools 流允许你执行用BPMN 2.0 XML格式定义的流程,正如它允许你执行用自定义规则流(RuleFlow)格式的流程一样的方式。这意味着你可以使用相同的API,引擎和组 件,如Guvnor和 gwt-console, 来执行和管理你的BPMN 2.0流程。
除了我们已经支持的非常重要的子集——包括所有通用节点类型外,我们还实现了所有定义在BPMN 2.0规范中的节点类型和属性。以下列表给出了已可以使用 BPMN 2.0 XML格式执行的各种元素的一个概述:
- Flow objects
- Events
- Start Event (None, Conditional, Signal, Message, Timer)
- End Event (None, Terminate, Error, Escalation, Signal, Message, Compensation)
- Intermediate Catch Event (Signal, Timer, Conditional, Message)
- Intermediate Throw Event (None, Signal, Escalation, Message, Compensation)
- Non-interrupting Boundary Event (Escalation, Timer)
- Interrupting Boundary Event (Escalation, Error, Timer, Compensation)
- Activities
- Script Task (Java or MVEL expression language)
- Task
- Service Task
- User Task
- Business Rule Task
- Manual Task
- Send Task
- Receive Task
- Reusable Sub-Process (Call Activity)
- Embedded Sub-Process
- Ad-Hoc Sub-Process
- Data-Object
- Gateways
- Diverging
- Exclusive (Java, MVEL or XPath expression language)
- Inclusive (Java, MVEL or XPath expression language)
- Parallel
- Event-Based
- Converging
- Exclusive
- Parallel
- Diverging
- Lanes
- Events
- Data
- Java type language
- Process properties
- Embedded Sub-Process properties
- Activity properties
- Connecting objects
- Sequence flow
例如,思考以下执行评估的BPMN流程。每当一个评估流程为一个特定雇员启动时,该雇员必须首先执行一个自我评估,然后才是那个项目管理员的,并且人力资源管理员也必须填写它们的评估,如下图所示 。
这个流程的一个可执行版本,使用BPMN 2.0 XML表达,看起来像这样(注意,该流程需要包含所有使它执行的细节,包括每个出现任务的所有参数,因此是一个大型流程定义):
<?xml version="1.0" encoding="UTF-8"?>
<definitions id="Definition"
targetNamespace="http://www.jboss.org/drools"
typeLanguage="http://www.java.com/javaTypes"
expressionLanguage="http://www.mvel.org/2.0"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd"
xmlns:g="http://www.jboss.org/drools/flow/gpd"
xmlns:tns="http://www.jboss.org/drools">
<process processType="Private" isExecutable="true" id="com.sample.evaluation" name="Evaluation Process" >
<!-- process variables -->
<property id="employee" itemSubjectRef="_employeeItem"/>
<!-- nodes -->
<startEvent id="_1" name="StartProcess" g:x="16" g:y="56" g:width="48" g:height="48" />
<userTask id="_2" name="Self Evaluation" g:x="96" g:y="56" g:width="143" g:height="48" >
<ioSpecification>
<dataInput id="_2_CommentInput" name="Comment" />
<dataInput id="_2_SkippableInput" name="Skippable" />
<dataInput id="_2_TaskNameInput" name="TaskName" />
<dataInput id="_2_ContentInput" name="Content" />
<dataInput id="_2_PriorityInput" name="Priority" />
<inputSet>
<dataInputRefs>_2_CommentInput</dataInputRefs>
<dataInputRefs>_2_SkippableInput</dataInputRefs>
<dataInputRefs>_2_TaskNameInput</dataInputRefs>
<dataInputRefs>_2_ContentInput</dataInputRefs>
<dataInputRefs>_2_PriorityInput</dataInputRefs>
</inputSet>
<outputSet>
</outputSet>
</ioSpecification>
<dataInputAssociation>
<targetRef>_2_CommentInput</targetRef>
<assignment>
<from xs:type="tFormalExpression">You need to perform a self-evaluation</from>
<to xs:type="tFormalExpression">_2_CommentInput</to>
</assignment>
</dataInputAssociation>
<dataInputAssociation>
<targetRef>_2_SkippableInput</targetRef>
<assignment>
<from xs:type="tFormalExpression">false</from>
<to xs:type="tFormalExpression">_2_SkippableInput</to>
</assignment>
</dataInputAssociation>
<dataInputAssociation>
<targetRef>_2_TaskNameInput</targetRef>
<assignment>
<from xs:type="tFormalExpression">Performance Evaluation</from>
<to xs:type="tFormalExpression">_2_TaskNameInput</to>
</assignment>
</dataInputAssociation>
<dataInputAssociation>
<targetRef>_2_ContentInput</targetRef>
<assignment>
<from xs:type="tFormalExpression"></from>
<to xs:type="tFormalExpression">_2_ContentInput</to>
</assignment>
</dataInputAssociation>
<dataInputAssociation>
<targetRef>_2_PriorityInput</targetRef>
<assignment>
<from xs:type="tFormalExpression">1</from>
<to xs:type="tFormalExpression">_2_PriorityInput</to>
</assignment>
</dataInputAssociation>
<potentialOwner>
<resourceAssignmentExpression>
<formalExpression>#{employee}</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
</userTask>
<parallelGateway id="_3" name="Diverge" g:x="271" g:y="56" g:width="49" g:height="49" gatewayDirection="Diverging" />
<userTask id="_4" name="HR Manager Evaluation" g:x="352" g:y="96" g:width="225" g:height="48" >
<ioSpecification>
<dataInput id="_4_CommentInput" name="Comment" />
<dataInput id="_4_SkippableInput" name="Skippable" />
<dataInput id="_4_TaskNameInput" name="TaskName" />
<dataInput id="_4_ContentInput" name="Content" />
<dataInput id="_4_PriorityInput" name="Priority" />
<inputSet>
<dataInputRefs>_4_CommentInput</dataInputRefs>
<dataInputRefs>_4_SkippableInput</dataInputRefs>
<dataInputRefs>_4_TaskNameInput</dataInputRefs>
<dataInputRefs>_4_ContentInput</dataInputRefs>
<dataInputRefs>_4_PriorityInput</dataInputRefs>
</inputSet>
<outputSet>
</outputSet>
</ioSpecification>
<dataInputAssociation>
<targetRef>_4_CommentInput</targetRef>
<assignment>
<from xs:type="tFormalExpression">You need to perform an evaluation for #{employee}</from>
<to xs:type="tFormalExpression">_4_CommentInput</to>
</assignment>
</dataInputAssociation>
<dataInputAssociation>
<targetRef>_4_SkippableInput</targetRef>
<assignment>
<from xs:type="tFormalExpression">false</from>
<to xs:type="tFormalExpression">_4_SkippableInput</to>
</assignment>
</dataInputAssociation>
<dataInputAssociation>
<targetRef>_4_TaskNameInput</targetRef>
<assignment>
<from xs:type="tFormalExpression">Performance Evaluation</from>
<to xs:type="tFormalExpression">_4_TaskNameInput</to>
</assignment>
</dataInputAssociation>
<dataInputAssociation>
<targetRef>_4_ContentInput</targetRef>
<assignment>
<from xs:type="tFormalExpression"></from>
<to xs:type="tFormalExpression">_4_ContentInput</to>
</assignment>
</dataInputAssociation>
<dataInputAssociation>
<targetRef>_4_PriorityInput</targetRef>
<assignment>
<from xs:type="tFormalExpression">1</from>
<to xs:type="tFormalExpression">_4_PriorityInput</to>
</assignment>
</dataInputAssociation>
<potentialOwner>
<resourceAssignmentExpression>
<formalExpression>mary</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
</userTask>
<userTask id="_5" name="Project Manager Evaluation" g:x="352" g:y="16" g:width="225" g:height="48" >
<ioSpecification>
<dataInput id="_5_CommentInput" name="Comment" />
<dataInput id="_5_SkippableInput" name="Skippable" />
<dataInput id="_5_TaskNameInput" name="TaskName" />
<dataInput id="_5_ContentInput" name="Content" />
<dataInput id="_5_PriorityInput" name="Priority" />
<inputSet>
<dataInputRefs>_5_CommentInput</dataInputRefs>
<dataInputRefs>_5_SkippableInput</dataInputRefs>
<dataInputRefs>_5_TaskNameInput</dataInputRefs>
<dataInputRefs>_5_ContentInput</dataInputRefs>
<dataInputRefs>_5_PriorityInput</dataInputRefs>
</inputSet>
<outputSet>
</outputSet>
</ioSpecification>
<dataInputAssociation>
<targetRef>_5_CommentInput</targetRef>
<assignment>
<from xs:type="tFormalExpression">You need to perform an evaluation for #{employee}</from>
<to xs:type="tFormalExpression">_5_CommentInput</to>
</assignment>
</dataInputAssociation>
<dataInputAssociation>
<targetRef>_5_SkippableInput</targetRef>
<assignment>
<from xs:type="tFormalExpression">false</from>
<to xs:type="tFormalExpression">_5_SkippableInput</to>
</assignment>
</dataInputAssociation>
<dataInputAssociation>
<targetRef>_5_TaskNameInput</targetRef>
<assignment>
<from xs:type="tFormalExpression">Performance Evaluation</from>
<to xs:type="tFormalExpression">_5_TaskNameInput</to>
</assignment>
</dataInputAssociation>
<dataInputAssociation>
<targetRef>_5_ContentInput</targetRef>
<assignment>
<from xs:type="tFormalExpression"></from>
<to xs:type="tFormalExpression">_5_ContentInput</to>
</assignment>
</dataInputAssociation>
<dataInputAssociation>
<targetRef>_5_PriorityInput</targetRef>
<assignment>
<from xs:type="tFormalExpression">1</from>
<to xs:type="tFormalExpression">_5_PriorityInput</to>
</assignment>
</dataInputAssociation>
<potentialOwner>
<resourceAssignmentExpression>
<formalExpression>john</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
</userTask>
<parallelGateway id="_6" name="Converge" g:x="603" g:y="55" g:width="49" g:height="49" gatewayDirection="Converging" />
<endEvent id="_7" name="EndProcess" g:x="690" g:y="56" g:width="48" g:height="48" >
<terminateEventDefinition/>
</endEvent>
<!-- connections -->
<sequenceFlow id="_1-_2" sourceRef="_1" targetRef="_2" />
<sequenceFlow id="_2-_3" sourceRef="_2" targetRef="_3" />
<sequenceFlow id="_3-_4" sourceRef="_3" targetRef="_4" g:bendpoints="[295,120]" />
<sequenceFlow id="_3-_5" sourceRef="_3" targetRef="_5" g:bendpoints="[295,39]" />
<sequenceFlow id="_5-_6" sourceRef="_5" targetRef="_6" g:bendpoints="[627,40]" />
<sequenceFlow id="_4-_6" sourceRef="_4" targetRef="_6" g:bendpoints="[627,121]" />
<sequenceFlow id="_6-_7" sourceRef="_6" targetRef="_7" />
</process>
</definitions>
要使用BPMN 2.0格式创建你自己的流程,你可以
-
使 用Drools Eclipse插件向导创建一个新的流(Flow),并且在这个向导的最后页面,确保你选择了Drools 5.1 code compatibility。这将创建一个使用 BPMN XML格式的新流程,而不是老的规则流(RuleFlow)格式。但是请注意,这不是一个真的BPMN 2.0编辑器,因为它仍然使用了不同的属性。然而,它使用有效的BPMN 2.0 语法保存流程。还要注意,该编辑器并不支持所有已经被执行引擎支持的节点类型和属性 。
-
Oryx 是一个支持 BPMN 2.0格式的基于网页开源编辑器。我们已经把它嵌入到Guvnor中,用于BPMN 2.0流程的可视化和编辑。 你也可以使用Oryx编辑器(独立的或集成的)创建/编辑BPMN 2.0流程,然后导出为BPMN 2.0格式,所以能够执行它们。然而要注意,Oryx仍然使用BPMN 2.0 beta 1格式, 它们的实现是不完整的(尤其是导入/导出功能)。
-
你也可以直接编写XML,手动创建你的BPMN 2.0流程文件。
下面的代码片断展示给你看,如何加载一个BPMN流程到你的知识库...
private static KnowledgeBase readKnowledgeBase() throws Exception {
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("sample.bpmn"), ResourceType.BPMN2);
return kbuilder.newKnowledgeBase();
}
... 以及如何执行这个流程。
KnowledgeBase kbase = readKnowledgeBase(); StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession(); KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test"); ksession.getWorkItemManager().registerWorkItemHandler("Human Task", new WSHumanTaskHandler()); // start a new process instance Map<String, Object> params = new HashMap<String, Object>(); params.put("employee", "krisv"); ksession.startProcess("com.sample.evaluation", params);
14.1 当前的限制
由 于BPMN 2.0规范还未定稿,BPMN2.0执行仍然是一个实验性功能。然而它使用与RuleFlow格式相同的执行引擎和结构(它只是另一个XML系列化格 式)。因此,所有可用于RuleFlow格式的功能与组件也适用于BPMN 2.0流程。在添加BPMN 2.0流程到你的知识库时,你只需要使用正确的ResourceType。因为规范还未定稿, 定义格式的XSD(XML Schemas Definition)仍有可能随规范的更新而改变(轻微地),所以如果你决定开始使用BPMN 2.0格式,要牢记这一点。
规 则的使用应该给你很多好处,由于规范为每个元素定义了确切格式(甚至执行语义)),因此它允许你跨工具共享你的流程,甚至能够跨引擎共享你的流程。然而在 这点上,不同的工具使用规范的不同中间版本是可能的。我们相信随着时间的推移,一旦规范定稿,这些问题会随之解决,并且所有人会使用相同版本的规范,但是 在这之前,你可能遭遇有关这个问题的兼容性问题。就此请多点耐心。
最后,BPMN 2.0规范定义了很多节点类型和属性,但是尽管如此,只使用由BPMN 2.0规范提供的结构表达一切是不可能的。然而,规范被设计成允许附加的节点类型、属性等等。虽然我们试图限制自定义扩展的使用为最低限度,我们有些时候 却必须定义定制属性,表达我们认为重要,但又不能由核心BPMN 2.0 语法表达的功能。下面的表,给出了已经从RuleFlow语言的功能移植到了BPMN 2.0 XML格式的一个概述。 绿色复选标记,指明该功能使用在BPMN 2.0 规范中的功能表达。橙色复选标记,指明我们用附加属性和/或元素扩展了BPMN 2.0 规范。如下表所示,已经支持大部分基本BPMN 2.0节点。我们决定了在默认时不能被BPMN 2.0表达的还没有实现的一些功能,例如,on-entry / on-exit 动作或状态节点。 当然,我们以后会决定,我们是否在将来希望支持这些功能用于 BPMN 2.0流程。
表 14.1 关键字
Feature | Drools BPMN | Drools Flow |
---|---|---|
A. Process-level | ||
Imports | ||
Function Imports | ||
Variable | ||
- primitive Java types | ||
- Java object types | ||
- default value | ||
Swimlanes | ||
Exception handlers | ||
- fault name | ||
- bind to variable | ||
- action | ||
B. Nodes | ||
1. Start Node | ||
- rule trigger | ||
- signal trigger | ||
- parameter mapping | ||
2. End Node | ||
- terminate | ||
3. Action Node | ||
- Java dialect | ||
* access to variables, global, context | ||
- MVEL dialect | ||
* access to variables, global, context | ||
4. RuleSet Node | ||
- timers | ||
5. Split Node | ||
- AND | ||
- XOR | ||
- OR | ||
- Java code constraints | ||
- MVEL code constraints | ||
- rule constraints | ||
- constraint names | ||
- constraint priorities | ||
6. Join Node | ||
AND | ||
XOR | ||
Discriminator | ||
n-of-m | ||
7. State Node | ||
- timers | ||
- on entry actions | ||
- on exit actions | ||
- automatic transition constraints | ||
- manual transition signal | ||
8. SubProcess Node | ||
- timers | ||
- on entry actions | ||
- on exit actions | ||
- wait for completion | ||
- independant | ||
- parameter mapping (in/out) | ||
- dynamic process id | ||
9. WorkItem Node | ||
- parameters | ||
- parameter mapping (in/out) | ||
- timers | ||
- on entry actions | ||
- on exit actions | ||
- wait for completion | ||
10. Timer Node | ||
- delay | ||
- period | ||
11. Human Task Node (also see WorkItem Node) | ||
- swimlane | ||
12. Composite Node | ||
- timers | ||
- on entry actions | ||
- on exit actions | ||
- variables | ||
- exception handlers | ||
- multiple entry points | ||
- multiple exit points | ||
13. ForEach Node | ||
- bind to variable | ||
- wait for completion | ||
- multiple entry points | ||
- multiple exit points | ||
14. Event Node | ||
- bind to variable | ||
- internal / external | ||
- event filters | ||
15. Fault Node | ||
- fault name | ||
- fault data | ||
Graphical information (x, y, width, height) | ||
C. Connections | ||
From, To | ||
From type | ||
To type | ||
Graphical information (bendpoints) |