Drools 5.1.1_DOC (48)

Drools 5.1.1_DOC_Drools Flow

4.4      数据

 尽管流程图侧重于详细说明流程的控制流,但是通常也需要从数据的角度查看流程。在流程的整个执行过程中,数据可以检索、存储、传递和使用。

 

在流程的执行期间,为了存储运行时的数据,你使用变量。一个变量利用一个名字和一种类型定义。其可以是基本数据类型,比如boolean,int,或String,或任何种类的Object子类。变量可以定义在一个变量作用域中。顶级作用域是流程自身的变量作用域。子作用域可以使用复合(Composite)节点定义。在一个子作用域中定义的变量,在该作用域内的节点才可能访问。

 

无论何时访问一个变量,流程都会搜索定义变量的适当变量作用域。嵌套作用域是被允许的。一个节点总会在它的父容器中搜索变量。如果当前没有发现变量,它将会查看它的父容器,依此类推,直到达到流程实例本身。如果变量没有发现,随着流程的继续执行,读访问产生null,写访问导致一个错误消息。

 

以不同方式使用变量:

 

l 当通过提供一个参数映射调用startProcess方法启动一个流程时,可以设置流程级变量。这些参数会被设置为在流程作用域中的变量。

l 可以直接访问变量,仅通过使用一个变量名字作为参数名字。

 

// call method on the process variable "person"
person.setAge(10);

 

可以通过知识上下文(Knowledge Context)改变一个变量的值:

 

kcontext.setVariable(variableName, value);

 

l WorkItem和SubFlow可以传参数的值到外部世界,通过使用一个参数映射,或使用#{expression}插入它到一个字符串参数,映射变量到其中一个工作项目参数。WorkItem的结果也可以使用一个结果映射复制给一个变量。

l 各种其他节点也可以使用数据。例如,Event节点可以用一个变量存储与之关联的数据,异常处理程序也可以从一个指定的变量访问错误数据,等等。详情请查看“不同节点类型”的属性。

 

最后,流程和规则都可以访问全局变量,即,全局定义的变量,关于规则的计算被认为是不可变的,并且数据在知识会话中。使用知识上下文可以访问知识会话:

 

kcontext.getKnowledgeRuntime().insert( new Person(...) );

 

4.5     约束

 

约束可用于你流程中的任何地方,例如,在一个使用OR或XOR决定的Split节点中,或作为State节点的一个约束。Drools Flow支持两种类型的约束:

 

l 代码约束,是boolean表达式,只要达到它们,就会直接求值。表达代码约束目前我们支持两种方言:MVEL和Java。MVEL和Java两种代码约束都直接访问全局变量和定义在流程中的变量。下面的是一个有效的Java代码约束例子,person是一个流程中的变量:

 

return person.getAge() > 20;

 

下面是一个有效MVEL代码约束例子:

 

return person.age > 20;

 

l 规则约束,是等价于普通的Drool规则条件。它们使用Drool规则语言语法表达可能的复杂约束。这些规则可以象其他规则一样,引用在工作内存中的数据。它们也可以直接引用全局变量。下面是一个有效的规则约束例子:

 

Person( age > 20 )

 

它检测工作内在中一个人的年龄大于20岁。

 

规则约束不能直接访问期在流程中定义的变量。然而,在一个规则约束内部引用当前的流程实例是可以的,通过添加流程实例到工作内存,并在你的规则约束中匹配流程实例。我们增加了特殊的逻辑,确保类型为WorkflowProcessInstance的一个变量processInstance将只匹配当前的流程实例,而不是在工作内存中的其他流程实例。然而,注意,你是自己负责把流程实例插入到会话中,当然可以更新它,例如,使用java代码,或者使用on-entry 或on-exit,或者在你的流程中使用显式的动作。下面是一个规则约束例子,将搜索与存储在流程变量"name" 中的值相同名字的一个人:

 

processInstance : WorkflowProcessInstance()
Person( name == ( processInstance.getVariable("name") ) )
# add more constraints here ...

 

4.6    动作

 

可以以不同的方式使用动作:

 

l 在一个Action节点内。

l 作为一些节点的进入和退出的动作。

l 指定异常处理程序行为的动作。

 

动作能访问全局变量、流程定义的变量和预定义变量context。这个变量是org.drools.runtime.process.ProcessContext类型,可能于以下几种任务:

 

l 获取当前节点的实例(如果可应用)。节点实例可用于查询数据,如它的名字和类型。你也可以撤销当前节点实例。

 

NodeInstance node = context.getNodeInstance();
String name = node.getNodeName();

 

l 获取当前流程实例。一个流程实例可用于查询数据(name, id, processId等等),中止或发信号通知一个内部事件。

 

WorkflowProcessInstance proc = context.getProcessInstance();
proc.signalEvent( type, eventObject );

 

l 获取或设置变量的值。

l 访问知识运行时间(Knowledge Runtime),允许你做诸如启动一个流程、发信号通知一个内部事件、插入数据等等。

 

Drools目前支持两种方言,MVEL和Java。Java动作应该是一个有效的java代码。MVEL可以使用业务脚本语言来表达动作。MVEL接受任何有效的java代码,而且另外提供了对嵌套参数访问的支持(例如,person.name,而不是person.name()),以及许多其他脚本改进的东西。因此,对于业务用户,MVEL表达是更方便的。例如,一个动作,打印输出在"requester"流程变量中的人名,应该看起象这样:

 

// Java dialect
System.out.println( person.getName() );
 
//  MVEL dialect
System.out.println( person.name );

 

4.7     事件

在一个流程的执行期间,通过请求工作项目的执行和等待结果,引擎确保所有关联任务根据流程计划被执行。然而,流程也应该能够响应不是引擎直接请求的事件。在一个流程中显式表示这些事件,允许流程创作者指定如何对这些事件作出反应。

 

事件有一个类型,也可能有与它们关联的数据。用户自由地定义他们自己的事件类型和与它们关联的数据。

 

通过使用Event节点,一个流程可以指定如何响应事件。一个Event节点需要指定节点感兴趣的事件类型。它也可以定义一个变量名字,它将接收与那个事件关联的数据。它允许在流程中的随后节点访问事件数据,并且根据这些数据采取适当的动作。

 

一个事件能够以不同的方式发信号通知一个运行的流程实例:

 

l 内部事件:在一个流程内部的任何动作(例如,一个动作节点的动作,或者某些节点的on-entry或on-exit动作)能够围绕流程实例发信号通知一个内部事件的发生,使用如下代码:

 

context.getProcessInstance().signalEvent(type, eventData);

 

l 外部事件:一个来自外部的事件可以通知一个流程实例,使用如下代码:

 

ProcessInstance.signalEvent(type, eventData);

 

l 使用事件相关性的外部事件:不是直接通知流程实例,引擎能够自动决定那个流程感兴趣一个使用事件相关性的事件,其是基于事件类型的。只要这样一个事件发生,就会通知一个包含侦听某些类型的外部事件的事件节点的流程实例。要发信号通知这样一个事件给引擎,编写如下代码:

 

workingMemory.signalEvent(type, eventData);

 

事件也可以被用于启动流程。只要一个Start节点定义了一个特殊类型的事件触发器,每次那个类型的事件发信号通知引擎,一个新的流程实例就会被启动。

 

4.8     异常

在一个流程的执行期间,只要一个异常条件出现,就能够引发出一个故障,发信号通知这个异常事件出现。然后流程将搜索能够处理这种故障的异常处理程序。

 

相似于事件,故障也有类型和可能关联这个故障的数据。用户自由地定义自己的故障类型以及它们的数据。

 

故障由产生给定类型故障的故障节点实现,通过故障名字表示。如果故障节点指定了一个故障变量,给定变量的值将关联该故障。

 

只 要一个故障被创建,流程将搜索能够处理给定类型故障的合适异常处理程序。流程和复合节点两个都可以定义处理故障的异常处理程序。嵌套异常处理程序是被允许 的;一个节点总会在它的父容器中搜索合适的异常处理程序,如果没有发现,它将查看其的父容器,以此类推,直到达到流程实例本身。如果没能够发现异常处理程 序,流程实例将会被中止,导致在该流程内部的所有节点被撤销。

 

异常处理程序也能够指定一个故障变量。只要选择了异常处理程序来处理故障,与该故障关联的数据(如果有)将复制到这个变量。这允许在这个流程中,随后的动作节点访问故障数据,并且根据该数据采取合适的动作。

 

异常处理程序需要定义一个指定如何响应给定的故障的动作。在大多数情况下,需要响应给定故障的行为不能在一个动作中被表达。因此,采取异常处理程序发信号通知一个特殊类型的事件(在"Fault"情况下),建议使用:

 

context.getProcessInstance().signalEvent("FaultType", context.getVariable("FaultVariable");

 

4.9    计时器

 

计时器在触发前等待一次或反复等待预定时间量。它们可用于时间监督,或在一定的时期后触发一定的逻辑,或定期重复某些动作。

 

一个Timer节点设置一个延迟或一个周期。延迟指定在节点被激活后,在第一次被触发前等待的时间量(毫秒)。周期定义两个连续触发活动之间的时间。0周期产生一次性计时器。

 

计时器服务负责确保计时器在适当的时间得到触发。计时器也可以撤销,意味着它将不再被触发。

 

在一个流程中有两种方式使用计时器:

 

l 一个Timer节点可以被增加到一个流程的流。其的激活启动计时器,并且其一次或反复的触发,激活该Timer节点的后续者。这意味着一个正周期计时器的输出线路被触发多次。取消计时器节点也就取消了计时器,此后不再会产生触发。

l 计时器也可以关联基于事件的节点,如WorkItem, SubFlow等等。只要该节点变成活动的,关联该节点的计时器被激活。无论何时该计时器触发,关联的动作被执行。例如,当一个任务执行时间太长时,你可以使用它定期发送通知,或者在一次监督失效的情况下,发信号通知一个事件或一个故障。当节点完成了自己的计时器,计时器自动取消。

posted @ 2011-11-09 17:28  skyme  阅读(951)  评论(0)    收藏  举报