Drools规则引擎中有如此多的用例和诸多功能,它变得令人难以置信。不过不用担心,复杂性是分层的,你可以用简单的用例来逐步了解drools。
无状态会话,不使用推理,形成最简单的用例。无状态会话可以被称为函数传递一些数据,然后再接收一些结果。无状态会话的一些常见用例有以下但不限于:
所以让我们从使用驾驶执照应用程序的一个非常简单的例子开始吧。
public class Applicant {
private String name;
private int age;
private boolean valid;
// getter and setter methods here
}
现在我们有了我们的数据模型,我们可以写出我们的第一个规则。我们假设应用程序使用规则来拒绝不符合规则的申请。由于这是一个简单的验证用例,我们将添加一条规则来取消任何18岁以下的申请人的资格。
package com.company.license
rule "Is of valid age"
when
$a : Applicant( age < 18 )
then
$a.setValid( false );
end
为了使引擎了解数据,所以可以根据规则进行处理,我们必须插入数据,就像数据库一样。当申请人实例插入到引擎中时,将根据规则的约束进行评估,在这种情况下,这只是一个规则的两个约束条件。我们说两个,因为申请人类型是第一个对象类型约束,而age <18是第二个字段约束。对象类型约束及其零个或多个字段约束被称为模式。当插入的实例同时满足对象类型约束和所有字段约束时,它被称为匹配。$a
是一个绑定变量,它允许我们引用匹配的对象。其属性可以更新。美元字符(’$’)是可选的,但它有助于区分变量名称和字段名称。匹配模式与插入数据的过程并不奇怪,通常被称为模式匹配。
要使用这个规则,有必要把它放在一个Drools文件中,只是一个带有.drl扩展名的纯文本文件,简称为“Drools Rule Language”。我们来调用licenseApplication.drl
这个文件,并将其存储在Kie Project中。 Kie项目具有正常的Maven项目的结构,并附加一个可以创建的KieBase
和KieSession
文件(kmodule.xml)。该文件必须放在Maven项目的resources/META-INF
文件夹中,而所有其他Drools工件(如包含前一规则的licenseApplication.drl
)必须存储在资源文件夹或其下的任何其他子文件夹中。
由于为所有配置方面提供了有意义的默认值,所以最简单的kmodule.xml文件只能包含一个空的kmodule标签,如下所示:
<kmodule xmlns="http://www.drools.org/xsd/kmodule"/>
此时,可以从类路径创建一个KieContainer来读取要构建的文件。
KieServices kieServices = KieServices.Factory.get();
KieContainer kContainer = kieServices.getKieClasspathContainer();
上面的代码段编译了类路径中找到的所有DRL文件,并将该编译结果KieModule
放在KieContainer
中。如果没有错误,我们现在可以从KieContainer
创建我们的会话并执行一些数据:
StatelessKieSession kSession = kContainer.newStatelessKieSession();
Applicant applicant = new Applicant( "Mr John Smith", 16 );
assertTrue( applicant.isValid() );
ksession.execute( applicant );
assertFalse( applicant.isValid() );
上述代码根据规则执行数据。由于申请人年龄未满18岁,申请被标记为无效。
到目前为止,我们只使用了一个实例,但是如果我们想要使用多个实例呢?我们可以执行任何实现Iterable的对象,如集合。我们再添加一个名为Application的类,它有应用程序的日期,我们还将布尔有效字段移到Application类。
public class Applicant {
private String name;
private int age;
// getter and setter methods here
}
public class Application {
private Date dateApplied;
private boolean valid;
// getter and setter methods here
}
我们还将添加另一条规则来验证申请是否在一段时间内进行。
package com.company.license
rule "Is of valid age"
when
Applicant( age < 18 )
$a : Application()
then
$a.setValid( false );
end
rule "Application was made this year"
when
$a : Application( dateApplied > "01-jan-2009" )
then
$a.setValid( false );
end
不幸的是,Java数组不实现Iterable接口,所以我们必须使用JDK转换器方法Arrays.asList(…)。下面显示的代码针对一个可迭代列表执行,其中在触发任何匹配的规则之前插入所有集合元素。
StatelessKieSession kSession = kContainer.newStatelessKieSession();
Applicant applicant = new Applicant( "Mr John Smith", 16 );
Application application = new Application();
assertTrue( application.isValid() );
ksession.execute( Arrays.asList( new Object[] { application, applicant } ) );
assertFalse( application.isValid() );
执行的两个执行方法(Object object)和execute(Iterable对象)实际上是接口BatchExecutor的方法execute(Command命令)的便利方法。
KieCommands命令工厂可以像KIE API的所有其他工厂一样从KieServices获取,用于创建命令,以便以下操作相当于执行(Iterable it):
ksession.execute( kieServices.getCommands().newInsertElements( Arrays.asList( new Object[] { application, applicant } ) );
批处理执行器和命令工厂在使用多个命令和输出标识符以获取结果时特别有用。
KieCommands kieCommands = kieServices.getCommands();
List cmds = new ArrayList();
cmds.add( kieCommands.newInsert( new Person( "Mr John Smith" ), "mrSmith", true, null ) );
cmds.add( kieCommands.newInsert( new Person( "Mr John Doe" ), "mrDoe", true, null ) );
BatchExecutionResults results = ksession.execute( kieCommands.newBatchExecution( cmds ) );
assertEquals( new Person( "Mr John Smith" ), results.getValue( "mrSmith" ) );