我总是和终端业务用户争论不休,理解规则和流程、最新规则和事件处理的区别。对此,在他们的意识中有这样的问题,并且他们希望使用某些软件模拟它。使用两个供应商提供的传统方式,强迫业务用户与一个刚刚获得方式的面向流程或面向规则的方法一起工作,他们将使用该工具模拟这点,往往整体是极为混乱的。
PegaSystems和Microsoft做了大量的工作,显示两者可以被结合,并且可以使用一个行为的模拟方法。这让业务用户更自然地应用提供给他们的各种方法工作,不必使用获得方式的工具。从面向流程到面向规则或中间的灰色地带——任何当时的相应问题被模拟。
Drools5.0更进了一步,不仅增加了基于工作流与Drools流的BPMN2,而且增加了事件处理与DroolsFusion(熔合),为软件开发者创建了一个更全面的方法。此处的术语“全面的”被用来强调整体和它局部间的相互依赖性的重要性。
Drools5.0现在被划分为5个模块,每个都自带手册——Guvnor(BRMS/BPMS),Expert(Rules),Fusion(CEP),Flow(Process/Workflow)和Planner。Guvnor是我们的基于网页的管理系统,在规则世界中传统提及的,如一个BRMS(商业规则管理系统)。我们决定抛弃一个担当管理工作的BRMS术语,因为它不是规则的细节。Expert是传统的规则引擎。Fusion是事件处理边,它担当数据/传感器的熔合术语。Flow是我们的工作流模块,由KrisVerlaenen领导,已经做了一些了不起的工作;他正把流与jBPM5合成一体。第5个模块是Planner,由GeoffreyDeSmet撰写,解决分配和调度类型的问题。虽然还处在开发的初期阶段,但已显示了许多期望。我们希望为2011版增加Semantics(语义),基于描述逻辑,并让它担当下一代Drools引擎的一部分。
我一直工作在规则领域,现在大约7年了。我终于感觉到我紧握东西,想法开始成形,并且真正的创新开始出现。对我来说,感觉就象我确实知道我们现在将做什么,与过去相比,有许多疯狂的猜想和探索。我与EdsonTirelli和DavideSottara一起努力工作在DroolsExpert设计文档上。我邀请你阅读文档和参与http://community.jboss.org/wiki/DroolsLanguageEnhancements。该文档带有东西给下一级,推动Drools成为一个混合的引擎,不仅是一个有能力生产规则的系统,而且混合了逻辑编程(prolog)与功能编程,以及带有其他想法的更有表现力和现代感语言的描述逻辑。
我希望你能感觉到我们的团队和我在Drools上工作的热情,希望在你的冒险期间能感染你。
MarkProctor(Drools创建者和领导)
2.1在Drools5.1.0中,值得注意的新东西。
2.1.1DroolsAPI
如在Drools5.0中一样,仍然可以使用配置配置一个KnowledgeBase(知识库),通过一个xml改变集合(changeset),而不是编程方式。然而,现在的change-set命名空间被版本化了。这意味着,在Drools5.1.0中,1.0.0xsd应该被引用。
例子2.1下面是一个简单的版本1.0.0改变集合
<change-setxmlns='http://drools.org/drools-5.0/change-set'
xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'
xs:schemaLocation='http://drools.org/drools-5.0/change-setchange-set-5.0.xsdhttp://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/drools-api/src/main/resources/change-set-1.0.0.xsd'>
<add>
<resourcesource='classpath:org/domain/someRules.drl'type='DRL'/>
<resourcesource='classpath:org/domain/aFlow.drf'type='DRF'/>
</add>
</change-set>
2.1.2核心
2.1.2.1JMX监控
JMX监控被添加来支持知识库监控。这尤其重要,象一个常需要事件处理的长期运行流程。初始化整合JOPR也被添加。JMX可以被启用,使用属性设置知识库:
drools.mbeans=<enabled|disabled>或者这个选项在运行时启用:
kbaseConf.setOption(MBeansOption.ENABLED)
2.1.2.2Spring
Drools现在有扩展的Spring支持,XSD可以在drools-springjar中发现。命名空间为"http://drools.org/schema/drools-spring"。
例子2.2知识库构建器例子
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:drools="http://drools.org/schema/drools-spring"
xmlns:camel="http://camel.apache.org/schema/spring"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://drools.org/schema/drools-springhttp://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/drools-container/drools-spring/src/main/resources/org/drools/container/spring/drools-spring-1.0.0.xsd
http://camel.apache.org/schema/springhttp://camel.apache.org/schema/spring/camel-spring.xsd">
<drools:resourceid="resource1"type="DRL"source="classpath:org/drools/container/spring/testSpring.drl"/>
<drools:kbaseid="kbase1">
<drools:resources>
<drools:resourcetype="DRL"source="classpath:org/drools/container/spring/testSpring.drl"/>
<drools:resourceref="resource1"/>
<drools:resourcesource="classpath:org/drools/container/spring/IntegrationExampleTest.xls"type="DTABLE">
<drools:decisiontable-confinput-type="XLS"worksheet-name="Tables_2"/>
</drools:resource>
</drools:resources>
<drools:configuration>
<drools:mbeansenabled="true"/>
<drools:event-processing-modemode="STREAM"/>
</drools:configuration>
</drools:kbase>
</beans>
知识库接受下面的配置:"advanced-process-rule-integration,multithread,mbeans,event-processing-mode,accumulate-functions,evaluatorsandassert-behavior"。
根据kbase参考可以创建ksessions
例子2.3知识会话
<drools:ksessionid="ksession1"type="stateless"name="stateless1"kbase="kbase1"/>
<drools:ksessionid="ksession2"type="stateful"kbase="kbase1"/>
象知识库的知识会话可以接受一些配置,包括"work-item-handlers,"keep-references","clock-type","jpa-persistence"。
例子2.4知识会话的配置
<drools:ksessionid="ksession1"type="stateful"kbase="kbase1">
<drools:configuration>
<drools:work-item-handlers>
<drools:work-item-handlername="handlername"ref="handlerid"/>
</drools:work-item-handlers>
<drools:keep-referenceenabled="true"/>
<drools:clock-typetype="REALTIME"/>
</drools:configuration>
</drools:ksession>
StatefulKnowledgeSessions(有状态知识会话)可以被配置为JPA持久化
例子2.5JPA配置用于StatefulKnowledgeSessions
<beanid="ds"class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<propertyname="driverClassName"value="org.h2.Driver"/>
<propertyname="url"value="jdbc:h2:tcp://localhost/DroolsFlow"/>
<propertyname="username"value="sa"/>
<propertyname="password"value=""/>
</bean>
<beanid="myEmf"class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<propertyname="dataSource"ref="ds"/>
<propertyname="persistenceUnitName"value="org.drools.persistence.jpa.local"/>
</bean>
<beanid="txManager"class="org.springframework.orm.jpa.JpaTransactionManager">
<propertyname="entityManagerFactory"ref="myEmf"/>
</bean>
<drools:ksessionid="jpaSingleSessionCommandService"type="stateful"kbase="kbase1">
<drools:configuration>
<drools:jpa-persistence>
<drools:transaction-managerref="txManager"/>
<drools:entity-manager-factoryref="myEmf"/>
<drools:variable-persisters>
<drools:persisterfor-class="javax.persistence.Entity"implementation="org.drools.persistence.processinstance.persisters.JPAVariablePersister"/>
<drools:persisterfor-class="java.lang.String"implementation="org.drools.container.spring.beans.persistence.StringVariablePersister"/>
<drools:persisterfor-class="java.io.Serializable"implementation="org.drools.persistence.processinstance.persisters.SerializableVariablePersister"/>
</drools:variable-persisters>
</drools:jpa-persistence>
</drools:configuration>
</drools:ksession>
知识库会话可以支持启动批处理脚本,前面的版本使用"script"元素名,它将被更新为"batch"。下面的命令被支持:"insert-object","set-global","fire-all-rules","fire-until-halt","start-process","signal-event"。可以使用匿名Bean或命名"ref"属性。
例子2.6启动批处理命令
<drools:ksessionid="jpaSingleSessionCommandService"type="stateful"kbase="kbase1">
<drools:script>
<drools:insert-objectref="person1"/>
<drools:start-processprocess-id="procname">
<drools:parameteridentifier="varName"ref="varRef"/>
</drools:start-process>
<drools:fire-all-rules/>
</drools:script>
</drools:ksession>
在Spring中支持执行节点(ExecutionNodes),它们提供了一个注册的ksessions。它可以与Camel一起提供ksessions路由。
2.1.2.3Camel
Spring可以与Camel组合,提供声明式规则服务。一个Camel策略从Drools被添加,Drools提供魔法注入类加载器(ClassLoader),类加载器被ksession用于任何数据的格式化,它还增强了JAXB和XStream数据的格式化。假如在Jaxb情况下,它添加另外的Drools路径信息,利用XStream注册Drools相关联的转换器,并取别名。
你可以使用不同的地址,创建你需要的尽可能多的端点。需要CommandMessagBodyReader分配有效负荷给Camel处理。
例子2.8Rest端点配置
<cxf:rsServerid="rsServer"
address="/kservice/rest"
serviceClass="org.drools.jax.rs.CommandExecutorImpl">
<cxf:providers>
<beanclass="org.drools.jax.rs.CommandMessageBodyReader"/>
</cxf:providers>
</cxf:rsServer>
然后,Camel路由可以连接到CXF端点,允许你控制如数据的格式化和根据Droolsksessions执行等事情的有效负荷。Drools策略增加某些智能给路由。如果使用JAXB或XStream,它将注入定制路径和转换器,它也可以在服务器边设置类加载器,基于目标ksessions的。在客户边,它自动解包Response(响应)对象。
这个例子使用了一个增强的XStream的数据格式解组有效负荷,并且根据ksession1实例执行它。"node"在这儿引用了ExecutionContext(执行上下文),它是一个注册的ksessions上下文。
例子2.9Camel路由
<beanid="droolsPolicy"class="org.drools.camel.component.DroolsPolicy"/>
<camelContextid="camel"xmlns="http://camel.apache.org/schema/spring">
<route>
<fromuri="cxfrs://bean://rsServer"/>
<policyref="droolsPolicy">
<unmarshalref="xstream"/>
<touri="drools://node/ksession1"/>
<marshalref="xstream"/>
</policy>
</route>
</camelContext>
Drools端点"drools:node/ksession1",由执行节点名字、分隔符和可选的知识会话名字构成。如果知识会话没有指定路由,会查找在输入的有效负荷的实例中的"lookup"属性,或者在头部属性"DroolsLookup"中去查找。
2.1.2.4Drools服务器
Spring,Camel和CXF可以被组合,用于声明式服务,drools-server是一个.war,组合了它们与某些开箱即用的例子xml,就像一类模板。如果你正在jboss容器中使用war,,那么你需要添加这个组件,http://camel.apache.org/camel-jboss.html。该war包含了一个test.jsp,显示一个象你开始的例子一样的回显。这个例子只是执行一个简单的"echo"类型的应用程序。它发送一个消息到规则服务器,规则服务器预先增加单词"echo"到开头,并发送它回去。默认时,消息是"HelloWorld",使用url参数msg——test.jsp?msg="MyCustomMessage",可以传递不同的消息。
2.1.2.5知识代理增量变化支持
新版的知识库代理在它配置中支持newInstance=false(增量变化集合构建)。
当设置这个属性为false,知识库代理使用存在的知识库参考应用增量变化。现在知识库代理可以用增量的方式处理监控的资源更改。更改的定义被编译,并和原始版本比较。根据定义的类型,以不同的方式表现:
l Rules:用于规则,代理搜索在它的属性中的更改,左手边和右手边。
l Queries:查询总在kbase上被替代,无论它们被更改还是没有被更改。
l 其他定义:所有其他定义总是在kbase中被替代(只要它们被更改)。我们希望在将来的版本中,为更改定义的探测增加更好的支持。
当前的实现只支持规则、查询和函数定义的探测。类型声明不能被探测。
2.1.2.6会话检查与报告框架
一个用于运行时会话检查与报告的基于框架的新的API被引入,从而更好地在调试或应用程序成型时采集数据。这个检查框架将成为加工功能的基础,用来帮助为每个会话的内容提供更详细的信息。这个api是实验性的,并不是用在drools-api中,但可自由的使用,并帮助我们改进它。
要检查一个会话,可以使用以下api调用之一:
例子2.10创建一个会话检查器
StatefulKnowledgeSessionksession=...
//...insertfacts,firerules,etc
SessionInspectorinspector=newSessionInspector(ksession);
StatefulKnowledgeSessionInfoinfo=inspector.getSessionInfo();
StatefulKnowledgeSessionInfo实例将包含许多在会话分析期间采集的相关数据。提供了一个简单的例子报告模板,并且可以利用下面的api调用产生:
例子2.11产生一个报告
Stringreport=SessionReporter.generateReport("simple",info,null);
2.1.3Expert
2.1.3.1差异更新
传统Rete算法用retract+assert(撤消+断言)做一个更新,对一个给定的事实,这导致所有的局部匹配被撤销,然而,在assert(断言)期间,其中一些会被再次重建;因为它们在更新前为true,并且在更新后仍然为true。这导致许多不需要的对象被摧毁,并且这些行为增加了垃圾收集器的负荷。现在的更新是一个单程,并在适当的位置检查局部匹配,避免不必要的局部匹配被摧毁。经历事件和实事维护的一个正规化过程也不再需要;正规化过程是我们准备着眼于激活retract(撤消)的地方,被插入的激活断定真正被添加的东西,由真正插入的东西确定“差异”。
2.1.3.2Channels(通道)
退出点已经用更合适的名字Channels(通道)替代,我们觉得它更合适,因为多个规则引擎可以使用它们,并且不是切入点的精确对立面。切入点明显与进入Rete网络中的一个分区有关联。
2.1.3.3现场查询
Doorls一直有一个查询支持,但结果是以一个可迭代的集合返回;这使监测随着时间的变化很困难。
我们现在用现场查询实现它,它与一个侦听器相连,而不是返回一个可迭代的集合。这些现实查询持续打开创建的一个视图,并且为这个视图的内容发布变化事件。所以,你现在可以执行你的查询,利用参数,并在结果视图中侦听变化。
例子2.12实现ViewChangedEventListener
finalListupdated=newArrayList();
finalListremoved=newArrayList();
finalListadded=newArrayList();
ViewChangedEventListenerlistener=newViewChangedEventListener(){
publicvoidrowUpdated(Rowrow){
updated.add(row.get("$price"));
}
publicvoidrowRemoved(Rowrow){
removed.add(row.get("$price"));
}
publicvoidrowAdded(Rowrow){
added.add(row.get("$price"));
}
};
//OpentheLiveQuery
LiveQueryquery=ksession.openLiveQuery("cheeses",newObject[]{"cheddar","stilton"},listener);
...
...
query.dispose()//makesureyoucalldisposewhenyouwantthequerytoclose
一个Doorls博客文章包含了一个用于现场查询的Glazed列表集成的例子
http://blog.athico.com/2010/07/glazed-lists-examples-for-drools-live.html(不可用)
2.1.3.4定时器和日历
规则现在支持基于interval(间隔)和cron定时器,替代了过时的duration(期限)属性。
例子2.13定时器属性使用的例子
timer(int:<initialdelay><repeatinterval>?)
timer(int:30s)
timer(int:30s5m)
timer(cron:<cronexpression>)
timer(cron:*0/15***?)
Interval"int:"定时器遵守JDK语义,初始化延迟,紧跟一个可选的重复间隔。Cron"cron:"定时器遵守标准的cron表达式:
例子2.14一个Cron例子
rule"SendSMSevery15minutes"
timer(cron:*0/15***?)
when
$a:Alarm(on==true)
then
channels["sms"].insert(newSms($a.mobileNumber,"Thealarmisstillon");
end
当规则被引发时,现在可以控制日历。日历api是模拟Quartzhttp://www.quartz-scheduler.org/:
例子2.15调节一个Quartz日历
CalendarweekDayCal=QuartzHelper.quartzCalendarAdapter(org.quartz.CalendarquartzCal)
日历使用StatefulKnowledgeSession(有状态知识会话)注册:
例子2.16注册一个日历
ksession.getCalendars().set("weekday",weekDayCal);
它们可以同时用于普通规则和包含定时器的规则中。规则的calendar属性可以有一个或多个逗点日历名字:
例子2.17一起使用日历和定时器
rule"weekdaysarehighpriority"
calendars"weekday"
timer(int:01h)
when
Alarm()
then
send("priorityhigh-wehaveanalarm);
end
rule"weekendarelowpriority"
calendars"weekend"
timer(int:04h)
when
Alarm()
then
send("prioritylow-wehaveanalarm);
end
2.1.3.5决策表(Excel)
2.1.3.5.1简单模板,用于单元格内部可变长度逗点分隔的列表
在一个单元格中可以有一个逗点分隔的列表,并且用一个forall模板可以渲染它们。
例子2.18DTableforall语法
forall(<separator>?){<codesnippt>}
例子2.19DTableforall例子
forall(,){propertyName==$}
forall(&&){propertyName==$}
forall(||){propertyName==$}
forall(||){propertyNameA==$}&&forall(||){propertyNameB==$}
等等
2.1.4Flow
2.1.4.1BPMN2
正如我们早期已宣称的一样,Dools团队已决定支持使用XML指定业务流程的即将到来的BPMN2.0规范。这个里程碑包含了BPMN2解析器的重大扩展,使用DroolsFlow来支持BPMN2的更多功能。更具体的有:
l 更广泛的事件支持:更多的事件类型组合(开始、中间、结束)和事件触发(例如,包括错误、升级、定时器、条件、信号事件),以及已包括(中断和非中断)边界事件。
l 子流程参数。
l 发散的综合性出入口
l 等等
BPMN2已被集成在完整的Dools工具链中,支持业务流程的整个生命周期。它包括:
l 能够与我们的Eclipse工具一起使用BPMN2流程。
l Guvnor作为流程库。
l 基于网页的管理,使用BPM控制台。
l 审计和调试。
l 特殊域流程。
l 等等
因此,DroolsFlow不仅是一流的开源流程引擎,天然地支持这样一个重要的BPMN2结构集合,而且我们的面向知识的方法,也允许你容易组合你的BPMN2流程与业务规则,以及复杂的事件处理,完全使用相同的APIs和工具。
2.1.4.2基于网页的管理控制台
现在也可以通过一个网页控制台管理DroolsFlow流程。它包括的功能有:管理你的流程实例(开始/停止/检查),检查你的(人的)任务列表,执行那些任务,产生报表。
这个控制台实际上是HeikoBraun的工作(卓越的),他创建了一个通用的BMP控制台,可以被用来支持多种流程语言。我们实现了必要的组件,允许这个控制台能与DroolsFlow引擎通信。
2.1.4.3可插式可变持久化
DroolsFlow可以持久化运行流程的运行时间状态到一个数据库(所以它们完全不需要在内存,并且在故障情况时可以被存储)。我们的默认持久化机制是用一个二进制对象(利用相关的元数据)存储关联于一个流程实例的所有运行时间信息。关联这个流程实例(又名流程实例变量)的数据也作为这个二进制对象的一部分被存储。然而这可以产生问题(1)在数据没有被序列化时,(2)当用流程实例状态的部分持久化,对象太大时,或者(3)在其他地方已经被持久化时。为此,我们实现了可插式可变持久化,用户可以定义多少变量的值被存储。例如,它允许你存储个别变量的值,并且支持JPA实体被分别存储和引用(避免状态重复)。
2.1.4.4改进的流程实例移植
随着时间的推移,流程可以进化。每当一个流程更新,确定已经运行的流程实例会发生什么是重要的。我们改进了我们的支持,用于移植运行的流程实例到流程定义的一个新版本。更多信息请看DroolsFlow文档。
2.1.4.5安装脚本
Drools构建输出了一个安装器,它简化了Guvnor和gwt-控制台的Eclipse插件的安装。它创建了和复制了需要的jars和war,并且布置它们到JBossAS。它也包含了一个简单的求值流程例子,你可以用它测试你的安装。更多信息,下载Drools安装器,请看其内部的自述文件readme。
2.1.5Guvnor
外观已被清洁,例如少了弹出窗口。意味着用断言和有关行为发生的信息更改之后的节省,以及如果出错时,更好的错误报告。
2.1.5.3讨论
注释是在下面的“文档”部分(当然是可选的)(并且有一个Atom供应给它们)
图2.1实时讨论
一个"backchannel(反向通道)"类型连接,保持了对浏览器的开放,允许消息推回——这意味着(在启用时)信息实时显示(和其他便利的事情一样,如果某东西添加到一个列表——列表就会被更新)
2.1.5.4收件箱
收件箱功能提供了这样的能力,跟踪你打开或编辑的东西——这显示在主导航器中的"Inbox"项目下。
图2.2收件箱分类
l 最近打开的
点击recentlyopened条目,会打开“最近”打开过的所有项目的一个列表(它跟踪最近你看过的数百个项目)。
l 最近编辑的
所有你保存过的项目,或者注释,将马上显示在这里。
l 收到的更改
它跟踪“其他人”对“你”的“最近编辑”列表中的项目所做的更改。当你打开这些项目,那么它们会从这个列表中删除(但仍然保留在你最近编辑过的列表中)
图2.3收件箱项目列表。
2.1.5.5批量导入器
Guvnor导入器是一个maven构建工具,递规你的规则目录结构,并且构建一个导入文件,通过import/export管理功能可以手动导入它到Drools-Guvnor网页界面。
2.1.5.6DroolsDoc
PDF文档包含了有关包和每个DRL资产(asset)的信息。DroolsDoc作为知识包可以从"InformationandimportantURLs"下的包视图(packageview)下载。
2.1.5.7更新为GWT2.0
GWT被更新,使DroolsGuvnor更快。
2.1.5.8安装选择器
安装选择器允许用户选择什么样的资产构建,依据:
n 状态(例如,开发,质量保证等)
n 分类
n 元数据
2.1.5.9单资产验证
只要是你正在运行的资产(规则流、规则、决策表),就可以验证。验证发现诸如在一个规则中的冲突限制或在决策表中的多余行等问题。
2.1.5.10全局区
储存在全局区的资产可以被所有包共享。
2.1.5.11快照之间的差异检查
列出两个快照之间的变化。
2.1.5.12在一个标签中查看多个资产
可以在一个视图中打开多个资产。所有的资产可以作为一个组被保存和编辑。
2.1.5.13From/Collect/Accumulate支持
指导编辑器已基本支持From,Accumulate和Collect模式。你可以添加它们中的任何一个结构作为正规模式。新的表达式构建器组件被创建,增加了对嵌套方法调用的一个变量支持。在规则的WHEN部分顶部使用了“加”按钮,或者使用呈现在每个模式中的新的“在后面增加”按钮,将打开弹出,添加新的条件元素到你的规则中。在可能元素的列表中的,你会发现三个新的条目:”From”,“FromAccumulate”和“FromCollect”。
当你添加一个新的”From”元素,你会在指导编辑器看到下面这样图象的东西。左边模式的”From”条件元素是一个正规模式。你可以在这里添加你希望的任何类型的条件元素。右边部分的”From”模式是一个表达式构建器。
图2.4来自一个CE构建器
当你在左边模式中使用“FromCollect”时,你可以选择“java.util.Collection”,“java.util.List”或“java.util.Set”事实类型。这个事实类型会被自动包含在事实类型列表中。
右边模式的收集条件元素可以是下面模式之一:
n FactTypePattern(事实类型模式)
n FreeFormExpression(自由表单表达式)
n FromPattern(From模式)
n FromCollectPattern(FromCollect模式)
n FromAccumulatePattern(FromAccumulate模式)
图2.5来自CollectCE构建器
当使用“FromAccumulate”时,左边模式可以是任何事实类型模式。这个条件元素的右边部分被划分成两个:
图2.6来自累积CE构建器
左边模式可以是任何事实类型模式。这个条件元素的右边部分被划分成两个:
源模式:(在载图中的,Bed$n)可以是任何事实类型、From、Collect或者Accumulate模式
累积函数:在这里你可发现一个标签式面板,你可以输入一个累积函数(在截图中的sum()),或者你可以使用“CustomCode”创建一个在线定制函数。
2.1.5.14规则模板
规则模板可以被指导编辑器用于编辑复杂的规则,然后通过一个电子表格的表格数据隐喻轻松地编写它。替代了一个字段的值,仅是用名为"TemplateKey"标识它,并且该key可以作为网格中的一个列。每行可以应用规则模板来产生一个规则。
图2.7在'WHEN'部分增加了一个TemplateKey。
图2.8"THEN"部分增加了一个TemplateKey。
图2.9根据这些TemplateKey填充行。
图2.10每行产生一个规则
2.1.5.15工作集
在建模规则时,用户暴露所有的事实类型,它可能是整个的很小部分。工作集允许相关的事实类型分组在一起,并在编写规则时,提供一个更易于管理的选择事实类型的视图。
图2.11显示导入的类型。
图2.12创建一个动物工作集。
图2.13没有使用工作集,所有类型是可见的。
图2.14选择动物工作集。
图2.15可用的类型减少了。
2.1.5.16事实约束
工作集可以与事实约束相结合,提供额外的设计时间验证。例如,如果你依据某个人的年龄编写一个规则,在设计时,我们可以分辨有效的范围,并且使用它来约束作者。事实约束是工作集的一部分,并且在编辑一个规则时,你必然选择工作集约束,那个你希望用于作为验证处理部分的约束。
图2.16选择字段。
图2.17选择字段约束类型.
图2.18一个范围选择的例子。
图2.19选择工作集,用于验证年龄字段。
图2.205岁是无效的。
2.1.5.17指导规则编辑器
编辑规则变得更明确。编辑器是更小“盒子”,且用一个普通文本编写更多规则。增加了"contains"关键字,现在在绑定变量给限制是更容易了。
2.1.5.17.1模式排序
指导编辑器在lhs和rhs部分支持模式重排序,以及位置插入,新的模式可以以任何顺序被插入(并不总是在最后)。
图2.21上下移动元素。
图2.22在任何位置插入元素。
2.1.5.18决策表(Guvnor)
增加了关键字"in"。
可以移动列,并且新行的位置可以自由选择。
2.1.6Eclipse
2.1.6.3在大纲视图中分组规则
现在你可以为议程组使用排序或分组。
图2.23分组议程组
图2.24排序议程组
2.1.6.4支持在审计视图中拖/放文件。
现在可以拖放日志文件到审计视图中。
2.1.7已知的问题
2.1.7.3多线程模式
使用试验的多线程执行模式存在一个已知的问题,如下面JIRA中描述的一样
https://jira.jboss.org/browse/JBRULES-2125
2.2 在Drools 5.0.0中值得关注的新东西
2.2.1 Drools API
Drools现在有完善的api/实现分离物,不再面向规则。当我们开始支持其他逻辑形式时,如工作流和事件处理时,这是一个重要的策略。最重要的改变是我们面向知识,而不是面向规则。drools-api模块提供接口和工厂,并且与以前相比,我们已竭力提供更好的javadocs,带有一些代码片段。drools-api还有助于清楚地显示有意作为一个用户的api是什么,只是一个引擎的api是什么,而Drools核心和Drools编译器没有充分明确这点。你将使用的最普通的接口有:
n org.drools.builder.KnowledgeBuilder
n org.drools.KnowledgeBase
n org.drools.agent.KnowledgeAgent
n org.drools.runtime.StatefulKnowledgeSession
n org.drools.runtime.StatelessKnowledgeSession
工厂类,带有静态方法,提供上面接口的实例。一个可插式提供者方法被用来允许提供者实现在运行时连接工厂。你将最常使用的工厂有:
n org.drools.builder.KnowledgeBuilderFactory
n org.drools.io.ResourceFactory
n org.drools.KnowledgeBaseFactory
n org.drools.agent.KnowledgeAgentFactory
例子2.20 加载一个规则资源的一个典型例子
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newUrlResource( url ), ResourceType.DRL );
if ( kbuilder.hasErrors() ) {
System.err.println( builder.getErrors().toString() );
}
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages( builder.getKnowledgePackages() );
StatefulKnowledgeSession ksession = knowledgeBase.newStatefulKnowledgeSession();
ksession.insert( new Fibonacci( 10 ) );
ksession.fireAllRules();
ksession.dispose();
一个典型的加载一个流程资源的例子。注意ResourceType使用相应的资源类型被改变。
例子 2.21一个典型的加载一个流程资源的例子。注意ResourceType使用相应的资源类型被改变。
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newUrlResource( url ),
ResourceType.DRF );
if ( kbuilder.hasErrors() ) {
System.err.println( builder.getErrors().toString() );
}
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages( builder.getKnowledgePackages() );
StatefulKnowledgeSession ksession = knowledgeBase.newStatefulKnowledgeSession();
ksession.startProcess( "Buy Order Process" );
ksession.dispose();
'kbuilder','kbase','ksession'是经常使用的变量标识符,用knowledge的k开头。
例子 2.22 我们已统一了决策树如何加载,现在不再需要利用电子表格编译器预先生成一致的DRL。
DecisionTableConfiguration dtconf = KnowledgeBuilderFactory.newDecisionTableConfiguration();
dtconf.setInputType( DecisionTableInputType.XLS );
dtconf.setWorksheetName( "Tables_2" );
kbuilder.add( ResourceFactory.newUrlResource( "file://IntegrationExampleTest.xls" ),
ResourceType.DTABLE,
dtconf );
使用配置也可以配置一个KnowledgeBase,通过一个xml更改集,而不是编程方式。
例子2.23 一个简单的更改集例子
<change-set xmlns='http://drools.org/drools-5.0/change-set'
xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'
xs:schemaLocation='http://drools.org/drools-5.0/change-set change-set-5.0.xsd' >
<add>
<resource source='classpath:org/domain/someRules.drl' type='DRL' />
<resource source='classpath:org/domain/aFlow.drf' type='DRF' />
</add>
</change-set>
例子 2.24 可以象其他资源类型一样添加
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newUrlResource( url ),
ResourceType.ChangeSet );
KnowledgeAgent与 RuleAgent相比较,其他较大的变化是轮询扫描现在是一个服务了。进一步说,是在代理通知与资源监视之间有一个抽象,允许使用其他轮询机制。
例子 2.25 这些服务当前不再默认启动,要启动它们要如下这样:
ResourceFactory.getResourceChangeNotifierService().start();
ResourceFactory.getResourceChangeScannerService().start();
增加了两个接口,ResourceChangeNotifier和ResourceChangeMonitor。KnowledgeAgent使用ResourceChangeNotifie实现订购资源更改通知。通过添加ResourceChangeMonitor通知ResourceChangeNotifie资源改变了。我们现在只提供一个开箱既用的的监视器, ResourceChangeScannerService,它轮询资源的变化。然而,存在有api用于用户添加自己的监视器,所以可以使用一个如jms这样的基于推的监视器。
ResourceFactory.getResourceChangeNotifierService().addResourceChangeMonitor( myJmsMonitor);
2.2.2 Drools Guvnor
n 新外观的网页工具
图2.25 新外观
n 网页基于决策表编辑器
图2.26网页基于决策表编辑器
n 集成的场景测试
图2.27 运行所有场景
图2.28 运行单个场景
n WebDAV文件基于接口库
图2.29 WebDAV
n 声明式模拟类型(不使用pojos的类型)
图2.30 声明式模拟
它与"declare"语句一起工作——你现在可以在drl本身内声明类型。然后你可以装配它们,不必使用pojo(如果你喜欢)。然后这些类型可用于规则库中。
u 细粒度安全(锁定访问每包或每分类应用程序)。只有分类权限的用户具有有限的UI能力(针对企业用户)
u 执行服务器——执行通过XML或JSON访问规则。
u 分类规则允许你为一个分类设置“父规则”。出现在给定分类的任何规则会“继承”指定的规则——例如,继承条件/ LHS。分类的基本规则可以在包配置标签上设置。RHS不被继承,只有LHS被继承。
u 场景运行器检测无限循环。
u 现在可以设置在指南编辑器中的DSL句子,用于显示作为一个下接菜单的枚举、作为一个数据拾取器的数据、作为一个单选框的布尔值,并且使用正则表达式来校验用户输入(在Guvnor中的DSL小饰件)。
u 函数可以使用文本编辑器进行编辑。
u 可以添加对象到全局集合。
u 翻译为英语,西班牙语,汉语和日语。
2.2.3 Drools Expert
2.2.3.1 非对称Rete算法实现
不再需要影子代理。影子代理保护引擎免受有关实事的信息变化的影响,如果发生在引擎控件的外部,它可能不会被修改或撤消。
2.2.3.2 包构建器现在可以构建多个命名空间
你不再需要对一个包命名空间构建一个PackageBuilder 。只要保持为所有命名空间增加你的DRLs,并且getPackages()为每个使用的命名空间返加一个包数组。
例子 2.26 获得多个包
Package[] packages = pkgBuilder.getPackages();
2.2.3.3 规则库连接包构建器
现在可以连接一个 RuleBase到一个 PackageBuilder,这意味着规则被构建,并且同时被添加到规则库。PackageBuilder使用现行的RuleBase的Package实例作为它的资源,取消了发生在现有方法中的Package创造和融合。
例子 2.27 连接规则库(RuleBase)到包构建器(PackageBuilder)
RuleBase ruleBase = RuleBaseFactory.newRuleBase();
PackageBuilder pkgBuilder = new PackageBuilder( ruleBase, null );
2.2.3.4 有状态会话的二进制编码
有状态会话现在可以保存,并可在以后的日期中恢复。预加载数据会话现在可以被创建。对用户对象的持久化可使用可插式策略,例如,hibernate或特征(identity)映射。
2.2.3.5 类型声明
Drools现在支持一种新的基础结构,称为类型声明。这个结构达到两个目的:能够声明实事元数据,以及能够为规则引擎动态地产生局部的新的事实类型。Guvnor模拟工具在底层使用了它。下面是该结构的一个例子:
例子 2.28 声明StockTick
declare StockTick
@role( event )
@timestamp( timestampAttr )
companySymbol : String
stockPrice : double
timestampAttr : long
end
2.2.3.6 声明实事元数据
要声明和关联事实的元数据,只需要对你想声明的每个元数据ID使用@符号。例子:
例子 2.29 声明元数据
declare StockTick
@role( event )
end
2.2.3.7 触发Bean产生
要激活动态bean产生,仅为你的类型声明添加字段和类型。
例子 2.30 声明Person
declare Person
name : String
age : int
end
2.2.3.8 DSL的改进
一系列DSL的改进被实现,包括一个完善的新解析器,并且能够为匹配的变量声明匹配的掩码(mask)。例如,它可限定一个电话号码字段为2位数的国家代码+ 3位区号+ 8位数字电话号码,所有连接以“ - ”(破折号)连接,通过象这样声明DSL映射:电话号码为{number:\d{2}-\d{3}-\d{8}},所有有效的Java正则表达式可以用于变量的掩码中。
2.2.3.9 fireUntilHalt()
Drools现在支持fireUntilHalt()功能,它以一种被动模式启动引擎,在那儿规则会被连续引发,直到调用了halt()。这尤其对CEP(complex event processing)场景有用,CEP场景需要俗称的“活动查询”。
2.2.3.10 规则库分区和多线程传播
Drools ReteOO算法现在支持一个选项,用于以多线程模式启动规则库,在那儿Drools ReteOO网络被划分为多个部分,然后规则被多个线程并发计算。对通常有几个独立规则并发运行的CEP,它也有一个要求,接近实时性能/吞吐量的要求,并且一个计算不能干扰其他的计算。
2.2.3.11 XSD模式支持
Drools现在支持XSD模式。记住虽然XSD模式以用于Drools类加载器的本地POJO类生成。在包构建器中存在有一个帮助类用于模式的产生。一旦数据模式被生成,你通常使用JAXB数据加载器插入数据。
2.2.3.12 数据加载器
Drools现在支持两种数据加载器,Smooks和JAXB。Smooks是一个用于ETL的开源数据转换工具,JAXB是一个标准的Sun数据映射工具。单元测试显示Smooks和JAXB均可在这里找到。
2.2.3.13 类型安全配置
在Drools中,除了能够通过配置文件配置选项外,也可用系统属性配置,通过API的 setProperty()方法设置属性,Drools-API现在支持类型安全配置。我们不希望为每个可能的配置方法增加特殊的方法,有两个原因:它污染了API,并且每次都有一个新选项增加到Drools,API将不得不改变。而这种方式,我们遵循模块化,类基于配置,在此处为每个可能的配置,一个新的选项类增加到了API,除了灵活之外,也维持了API的稳定。所以,现在为了设置配置选项,你只需要使用枚举或者提供每个选项的工厂。例如,如果你希望为断言行为"equality" 配置知识库,并且自动从模式匹配中删除特征(identities),你只需要使用下面的枚举:
例子2.31 配置
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( AssertBehaviorOption.EQUALITY );
config.setOption( RemoveIdentitiesOption.YES );
对于选项,我们不需要预定义约束,或者可以假设多个值,提供一个工厂方法。例如,配置alpha值为5,只使用get()工厂方法:
例子 2.32 配置alpha值
config.setOption( AlphaThresholdOption.get(5) );
正如你所见,为每个不同的可能配置,使用了相同的setOption()方法,然而它们仍然是类型安全的。
2.2.3.14 新的累积函数:collectSet和collectList
有时候,有必要收集来自实事属性的值的集合或列表,而不是实事本身。在这种情况下,不可能使用collect CE。所以对这种情况,现在Drools有两个新的累积函数:collectSet用于收集值的集合(即,无重复的值),collectList用于收集值的列表(即,允许重复的值):
例子 2.33 新的累积函数
# collect the set of unique names in the working memory
$names : Set() from accumulate( Person( $n : name, $s : surname ),
collectSet( $n + " " + $s ) )
# collect the list of alarm codes from the alarms in the working memory
$codes : List() from accumulate( Alarm( $c : code, $s : severity ),
collectList( $c + $s ) )
2.2.3.15 用于类型声明的新元数据:@propertyChangeSupport
事实实现了象定义在Javabean(tm)规范中的属性改变的支持。现在可以注释,让引擎注册自身来侦听事实属性的变化。在Drools 4 API的insert()方法中使用的布尔参数已过时,并且不存在于drools-aip模块中了。
例子 2.34 @propertyChangeSupport
declare Person
@propertyChangeSupport
end
2.2.3.16 批处理器
批处理器允许一个知识会话使用命令脚本,此外,无论是StatelessKnowledgeSession 还是 StatefulKnowledgeSession实现都可以使用CommandFactory创建这个接口命令,且使用"execute" 方法执行,如下所示:
例子 2.35 使用CommandFactory
ksession.execute( CommandFactory.newInsert( person ) );
尽管这样,你通常会希望执行一个批处理命令,通过组合命令 BatchExecution可以完成它。BatchExecutionResults现在用来处理结果,某些命令可以使用"out"标识符,用它来添加结果到BatchExecutionResult。现在可以轻松地执行查询,并把结果添加到BatchExecutionResult。这个结果进一步被限定到这个执行调用,并且通过BatchExecutionResults返回。
例子 2.36 使用BatchExecutionResult
List<Command> cmds = new ArrayList<Command>();
cmds.add( CommandFactory.newSetGlobal( "list1", new ArrayList(), true ) );
cmds.add( CommandFactory.newInsert( new Person( "jon", 102 ), "person" ) );
cmds.add( CommandFactory.newQuery( "Get People" "getPeople" );
BatchExecutionResults results = ksession.execute( CommandFactory.newBatchExecution( cmds ) );
results.getValue( "list1" ); // returns the ArrayList
results.getValue( "person" ); // returns the inserted fact Person
results.getValue( "Get People" );// returns the query as a QueryResults instance.
End
CommandFactory详细描述支持的命令,它们所有都可以使用XStream和BatchExecutionHelper进行编码。可以使用管道组合它们来自动化会话脚本。
例子 2.37 使用PipelineFactory
Action executeResultHandler = PipelineFactory.newExecuteResultHandler();
Action assignResult = PipelineFactory.newAssignObjectAsResult();
assignResult.setReceiver( executeResultHandler );
Transformer outTransformer = PipelineFactory.newXStreamToXmlTransformer( BatchExecutionHelper.newXStreamMarshaller() );
outTransformer.setReceiver( assignResult );
KnowledgeRuntimeCommand batchExecution = PipelineFactory.newBatchExecutor();
batchExecution.setReceiver( outTransformer );
Transformer inTransformer = PipelineFactory.newXStreamFromXmlTransformer( BatchExecutionHelper.newXStreamMarshaller() );
inTransformer.setReceiver( batchExecution );
Pipeline pipeline = PipelineFactory.newStatelessKnowledgeSessionPipeline( ksession );
pipeline.setReceiver( inTransformer );
对一个规则集使用上面所述的,会更新一个Cheese事实的价格,下面给定的xml会插入一个使用了输出标识符(out-identifier)的Cheese实例。
例子 2.38 更新Cheese实事
<batch-execution>
<insert out-identifier='outStilton'>
<org.drools.Cheese>
<type>stilton</type>
<price>25</price>
<oldPrice>0</oldPrice>
</org.drools.Cheese>
</insert>
</batch-execution>
然后我们会得到BatchExecutionResults:
例子 2.39 更新Cheese实事
<batch-execution-results>
<result identifier='outStilton'>
<org.drools.Cheese>
<type>stilton</type>
<oldPrice>0</oldPrice>
<price>30</price>
</org.drools.Cheese>
</result>
</batch-execution-results>
2.2.3.17 编码
MarshallerFactory被用来编码和解码StatefulKnowledgeSessions。最简单的,它可以象下面这样使用:
例子 2.40 使用MarshallerFactory
// ksession is the StatefulKnowledgeSession
// kbase is the KnowledgeBase
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Marshaller marshaller = MarshallerFactory.newMarshaller( kbase );
marshaller.marshall( baos, ksession );
baos.close();
然而,在处理引用的用户数据时,你需要更有弹性地使用编码。要达成它,我们有一个ObjectMarshallingStrategy接口。我们提供了两个实现,但是用户可以自己实现它。提供的两个是IdentityMarshallingStrategy和SerializeMarshallingStrategy。默认为SerializeMarshallingStrategy,如上例所示,它只在一个用户实例上调用Serializable或Externalizable方法。而IdentityMarshallingStrategy为每个用户对象创建了一个整数id,并存储它们在一个映射中,该id被写入到该流中。在解码时,它只简单地查看IdentityMarshallingStrategy映射,取回该实例。这意味着,如果你使用IdentityMarshallingStrategy,它对编码实例的生命周期是有状态的,并且会创建ids,保持它企图编码的所有对象的引用。
例子 2.41 使用IdentityMarshallingStrategy编码
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Marshaller marshaller = MarshallerFactory.newMarshaller( kbase, new ObjectMarshallingStrategy[] { MarshallerFactory.newIdentityMarshallingStrategy() } );
marshaller.marshall( baos, ksession );
baos.close();
为增加弹性,我们不能想当然地认为单策略更合适,所以我们增加了一个ObjectMarshallingStrategyAcceptor 接口,每个ObjectMarshallingStrategy都有。编码器有一个策略链,并且当它企图读或写一个用户对象时,它遍历策略,询问它们是否承担负责编码用户对象。提供了一个实现为ClassFilterAcceptor。它允许使用字符和通匹符匹配类名。默认为"*.*",所以在上面使用的IdentityMarshallingStrategy,它有一个默认的"*.*"接收器。然而,比方说,我们希望序列化所有类,一个给定的包除外,这种情况,我们会使用身份查询,如下所示:
例子 2.42 使用身份查询
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectMarshallingStrategyAcceptor identityAceceptor = MarshallerFactory.newClassFilterAcceptor( new String[] { "org.domain.pkg1.*" } );
ObjectMarshallingStrategy identityStratetgy = MarshallerFactory.newIdentityMarshallingStrategy( identityAceceptor );
Marshaller marshaller = MarshallerFactory.newMarshaller( kbase, new ObjectMarshallingStrategy[] { identityStratetgy, MarshallerFactory.newSerializeMarshallingStrategy() } );
marshaller.marshall( baos, ksession );
baos.close();
2.2.3.18 知识代理
KnowlegeAgent由 KnowlegeAgentFactory创建。KnowlegeAgent提供自动加载、缓存和重新加载资源,并且根据一个属性文件配置它。当KnowlegeBase使用的资源更改时,KnowlegeAgent可以更新或重构KnowlegeBase。通过给定工厂的配置确定KnowlegeAgent的策略,但通常使用基于标准轮询的拉策略。我们希望增加基于推的更新,并在将来的版本中重构它。下面的例子,构建了一个代理,它根据在路径字符串中指定的文件构建了一个新的KnowledgeBase。它会每30秒拉这些文件,而不是更新存在的一个,因为 "newInstance" 设置为了"true" (然而,目前只支持"true" 值,并且很难编码到引擎中)。
例子 2.43 构建一个代理
// Set the interval on the ResourceChangeScannerService if you are to use it and default of 60s is not desirable.
ResourceChangeScannerConfiguration sconf = ResourceFactory.getResourceChangeScannerService().newResourceChangeScannerConfiguration();
sconf.setProperty( "drools.resource.scanner.interval",
"30" ); // set the disk scanning interval to 30s, default is 60s
ResourceFactory.getResourceChangeScannerService().configure( sconf );
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
aconf.setProperty( "drools.agent.scanDirectories",
"true" ); // we want to scan directories, not just files, turning this on turns on file scanning
aconf.setProperty( "drools.agent.newInstance",
"true" ); // resource changes results in a new instance of the KnowledgeBase being built,
// this cannot currently be set to false for incremental building
KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "test agent", // the name of the agent
kbase, // the KnowledgeBase to use, the Agent will also monitor any exist knowledge definitions
aconf );
kagent.applyChangeSet( ResourceFactory.newUrlResource( url ) ); // resource to the change-set xml for the resources to add
KnowledgeAgents可以使用一个空的 KnowledgeBase或植入的一个。如果提供了一个植入的KnowledgeBase,KnowledgeAgent会遍历KnowledgeBase,并订阅它发现的资源。虽然KnowledgeBuilder可以构建在一个目录中发现的所有资源,但信息会被KnowledgeBuilder丢弃,因些那些目录不会继续被扫描。只有作为applyChangeSet(Resource)方法的一部分指定的目录才会被监控。