Drools 5.1.1_DOC (46) (转载)

Drools 5.1.1_DOC_Drools Flow


第4章     规则流

一 个规则流是一个流程,使用一个流程图描述一系列需要执行步骤的顺序。一个流程由使用线路互相连结的节点的一个集合构成。每个节点表示在整个流程中的一个步 骤,同时线路指定了如何从一个节点转换到另一个节点。一个全面的预定义节点类型已经被定义。本章描述如何定义这种流程,以及如何在你的应用程序中使用它 们。

 

4.1    创建一个规则流程

 

 

 

可以使用下面三种方法之一创建流程:

 

 

 

  1. 可以使用在Eclipse的Drools插件中的图形规则流编辑器。
  2. 用一个XML文件,根据XML流程格式,与定义在XML Schema中用于Drools流程的定义一样。
  3. 通过使用Process API直接创建一个流程。

 

 

 

4.1.1    图形规则流编辑器

 

 

 

图形规则流编辑器是一个编辑器,允许你在图布上拖放不同的节点创建一个流程,并且允许编辑这些节点的属性。这个图形编辑器是Eclipse的Drools插件的一部分。一旦你创建了一个Drools项目(如果你不知道如何做,请查看IDE章节),你就可以开始添加流程。当在一个项目中时,你可以启动"New"向导:使用Ctrl+N,或者在你想放置规则流的目录上右击,并选择"New",然后点取->Other..."-> "Drools"->"RuleFlow file"。这将创建一个新的.rf文件。

接下来你会看见图形规则流编辑器。现在是切换到Drools透视图的好时间(如果你还没有这样好)。这会调整用户界面,以便于它最优于规则。然后,确保你能够在Elicpse窗口的底部看见了Properties视图,因为需要用它来填充在你流程中的元素的不同属性。如果你没有看见Properties视图,点取"Window"->"Show View" -> "Other..."->"General" -> Properties View打开它。

规则流编辑器由一个调色板、一个画布和一个大纲视图构成。要添加新的元素到画布,在调色板中选取你想创建的元素,然后点击你喜欢的地方添加它们到画布。例如,点出在"Components"的GUI调色板中的"RuleFlowGroup"图标:然后你可以绘制出一些规则流组。点击在你规则流中的一个元素,允许你设置那个元素的属性。你也可以通过使用调色板中"Connection Creation"连接节点(只要是被允许的不同类型的节点)。

 

你可以继续添加节点,并连接到你的流程,直到它表示出你想指定的业务逻辑。尝试在应用程序中使用它之前,你可能需要为任何缺失的信息检查流程(通过点击在IDE菜单条中的绿色"Check"图标)。

4.1.2     使用XML定义流程

 

也可以直接使用底层XML确定流程。这些XML流程的语法是使用XML Schema定义被定义。例如,下面的XML片断显示了一个简单流程, 包含了一个Start节点、一个打印"Hello World"到控制台的 Action节点、和一个 End节点。

 

<?xml version="1.0" encoding="UTF-8"?>
<process xmlns="http://drools.org/drools-5.0/process"
         xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
         xs:schemaLocation="http://drools.org/drools-5.0/process drools-processes-5.0.xsd"
         type="RuleFlow" name="ruleflow" id="com.sample.ruleflow" package-name="com.sample" >

  <header>
  </header>

  <nodes>
    <start id="1" name="Start" x="16" y="16" />
    <actionNode id="2" name="Hello" x="128" y="16" >
     <action type="expression" dialect="mvel" >System.out.println("Hello World");</action>
    </actionNode>
    <end id="3" name="End" x="240" y="16" />
  </nodes>

  <connections>
    <connection from="1" to="2" />
    <connection from="2" to="3" />
  </connections>

</process>

 

流程应该严格地由一个<process>元素构成。这个元素包含了有关流程的参数(它的类型、名字、id、以及包名字),并且包含了三个子部分:

 

一个<header> (能够定义流程级信息的地方,如变量、全局、导入和泳道(swimlanes)的地方;一个<nodes> 部分,定义在流程中的每个节点; 一个<connections> 部分,包含在流程中所有节点间的线路。在节点部分,有一个特殊元素用于每个节点,定义各种参数,以及可能的用于子元素的节点类型。

4.1.3      使用Process API定义流程

 

虽然推荐使用图形编辑器或底层XML定义流程(保护你自己的内部APIs),但是也可以直接使用Process API定义流程。最重要的流程元素被定义在包org.drools.workflow.core 和org.drools.workflow.core.node中。提供了一个"fluent API",它允许你使用工厂以可读的方式轻松地构建流程。最后,你可以验证你以手动方式构建的流程。一些如何使用fluent API构建流程的例子被添加在下面。

 

4.1.3.1      例子1

 

这是一个简单的基本流程例子,只使用了一个规则集(ruleset)节点。

 

RuleFlowProcessFactory factory =
    RuleFlowProcessFactory.createProcess("org.drools.HelloWorldRuleSet");
factory
    // Header
    .name("HelloWorldRuleSet")
    .version("1.0")
    .packageName("org.drools")
    // Nodes
    .startNode(1).name("Start").done()
    .ruleSetNode(2)
        .name("RuleSet")
        .ruleFlowGroup("someGroup").done()
    .endNode(3).name("End").done()
    // Connections
    .connection(1, 2)
    .connection(2, 3);
RuleFlowProcess process = factory.validate().getProcess();

 

你可以看见,我们开始调用了来自RuleFlowProcessFactory的静态createProcess()方法。这个方法使用给定的id创建了一个新的流程,并返回给可以被用来创建流程的RuleFlowProcessFactory。一个典型的流程由三部分构成。Header部分由全局元素构成,如流程的名字、导入和变量等等。Nodes部分包含所有是流程的一部分的不同的节点。Connections部分最终互相连接这些节点,创建一个流程图。

 

在这个例子中,Header部分包含了流程的名字,版本号和包名。在这之后,你可以添加节点给当前的流程。如果你使用自动完成(auto-completion),你可以看见,在你安排时,你可使用不同的方法创建每种支持的节点类型。

 

当你开始添加节点到流程时,在这个例子中,通过调用startNode()、ruleSetNode()和endNode()方法,你可以看见这些节点返回了一个NodeFactory,它允许你设置这些节点的属性。一旦你完成了特殊节点的配置,done()方法返回给你当前的RuleFlowProcessFactory,如果需要,这样你可以添加更多的节点。

 

当你完成节点添加时,你必须在它们之间创建线路连接它们。这可以通过调用方法connection来做,它将连接前面创建的节点。

 

最后,你可以通过调用validate()方法验证产生的流程,并且检索创建的RuleFlowProcess对象。

4.1.3.2      例子2

 

这个例子使用了分枝(Split)和联合(Join)节点。

 

RuleFlowProcessFactory factory =
    RuleFlowProcessFactory.createProcess("org.drools.HelloWorldJoinSplit");
factory
    // Header
    .name("HelloWorldJoinSplit")
    .version("1.0")
    .packageName("org.drools")
    // Nodes
    .startNode(1).name("Start").done()
    .splitNode(2).name("Split").type(Split.TYPE_AND).done()
    .actionNode(3).name("Action 1")
        .action("mvel", "System.out.println(\"Inside Action 1\")").done()
    .actionNode(4).name("Action 2")
        .action("mvel", "System.out.println(\"Inside Action 2\")").done()
    .joinNode(5).type(Join.TYPE_AND).done()
    .endNode(6).name("End").done()
    // Connections
    .connection(1, 2)
    .connection(2, 3)
    .connection(2, 4)
    .connection(3, 5)
    .connection(4, 5)
    .connection(5, 6);
RuleFlowProcess process = factory.validate().getProcess();

 

这显示了一个使用了分枝和联合节点的简单例子。如你所见,一个分枝节点有多个输出路线,一个联合节点有多个输入路线。要理解不同类型的分枝和联合节点的行为,请参考这些节点的文档。

 

4.1.3.3      例子 3

 

现在我们显示一个更复杂的例子,使用了一个ForEach节点,在那儿我们可以嵌套节点。

 

RuleFlowProcessFactory factory =
    RuleFlowProcessFactory.createProcess("org.drools.HelloWorldForeach");
factory
    // Header
    .name("HelloWorldForeach")
    .version("1.0")
    .packageName("org.drools")
    // Nodes
    .startNode(1).name("Start").done()
    .forEachNode(2)
        // Properties
        .linkIncomingConnections(3)
        .linkOutgoingConnections(4)
        .collectionExpression("persons")
        .variable("child", new ObjectDataType("org.drools.Person"))
        // Nodes
        .actionNode(3)
            .action("mvel", "System.out.println(\"inside action1\")").done()
        .actionNode(4)
            .action("mvel", "System.out.println(\"inside action2\")").done()
        // Connections
        .connection(3, 4)
        .done()
    .endNode(5).name("End").done()
    // Connections
    .connection(1, 2)
    .connection(2, 5);
RuleFlowProcess process = factory.validate().getProcess();

 

在这儿你可以看见我们如何包含一个ForEach节点与嵌套动作节点。注意,调用linkIncomingConnections()和linkOutgoingConnections()方法,连接ForEach节点与内部动作节点。这些方法被用来指定在ForEach复合节点内部的第一个节点和最后一个节点。

 

4.2    在你的应用程序中使用一个流程

 

要能够从你的应用程序内部执行流程,有两件事情需要你做:(1)你需要创建一个包含流程定义的知识库,(2)你需要创建一个与流程引擎通信的会话来启动流程,并启动流程。

 

  1.  创建一个知识库:一旦你有一个有效的流程,你可以添加流程到知识库。注意,这几乎等同于添加规则到知识库,除添加的知识类型之外。

 

KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newClassPathResource("MyProcess.rf"),
              ResourceType.DRF );

 

在添加了所有知识到构建器后(你可以添加多个流程,甚至规则),你可以象以下这样创建一个知识库:

 

KnowledgeBase kbase = kbuilder.newKnowledgeBase();

 

注意,如果知识库包含错误,这将抛出一个异常(因为它不能正确解析你的流程)。

 

  1. 启动一个流程:只有你显示描述了流程应该被执行,它们才会被执行。这是因为在你的知识库中,你可能潜在地定义了许多流程,而且引擎没有办法知到在什么时候启动你想要启动的那个。要激活一个特殊的流程,你需要在你的会话上调用startProcess方法来启动它。例如:

 

StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
ksession.startProcess("com.sample.MyProcess");

 

startProcess方法的参数代表你需要启动流程的id。这个流程的id需要用流程的属性来指定,当你点击你的流程画布背景时,显示在Properties视图中。在流程的执行期间,如果你的流程也要求执行规则,你也需要调用ksession.fireAllRules()方法确保规则也被执行。就是这样!

 

你也可以使用其他参数,用于传递输入数据到流程,使用startProcess(String processId, Map parameters)方法,它获得了一个用名字-值(name-value)对为参数的附加集合。然后这些参数被复制到新创建的流程实例,作为流程的顶级变量。

 

你也可以在一个规则的推论内启动流程,或者,从一个流程的动作内部,使用预定的kcontext参数启动流程:

 

kcontext.getKnowledgeRuntime().startProcess("com.sample.MyProcess");

 


posted @ 2011-11-09 17:25  skyme  阅读(1261)  评论(1)    收藏  举报