关于Drools的初步,迷醉状态认识
这两天在 springside受白衣的影响开始关注drools。说他是平民的脚本引擎一点都不假,使用起来极为方便,本来以为网上应该有不少的讲解了,但是发现几乎全是针对2.0版本讲解的。而drools加入jboss后有了质的变化,下面来看一下最新的3.0使用起来有什么不同:
首先我们要取得rule,规则引擎、规则引擎,取得规则是必要的。
private
static
RuleBase readRule()
throws
Exception
{
//read in the source
Reader source = new InputStreamReader( DroolsTest.class.getResourceAsStream( "/aclcreat.drl" ) );
//optionally read in the DSL (if you are using it).
Reader dsl = new InputStreamReader( DroolsTest.class.getResourceAsStream( "/mylang.dsl" ) );
//Use package builder to build up a rule package.
//An alternative lower level class called "DrlParser" can also be used
PackageBuilder builder = new PackageBuilder();
//this wil parse and compile in one step
//NOTE: There are 2 methods here, the one argument one is for normal DRL.
//builder.addPackageFromDrl( source );
//Use the following instead of above if you are using a DSL:
builder.addPackageFromDrl( source, dsl );
//get the compiled package (which is serializable)
Package pkg = builder.getPackage();
//add the package to a rulebase (deploy the rule package).
RuleBase ruleBase = RuleBaseFactory.newRuleBase();
ruleBase.addPackage( pkg );
return ruleBase;
}
//read in the source
Reader source = new InputStreamReader( DroolsTest.class.getResourceAsStream( "/aclcreat.drl" ) );
//optionally read in the DSL (if you are using it).
Reader dsl = new InputStreamReader( DroolsTest.class.getResourceAsStream( "/mylang.dsl" ) );
//Use package builder to build up a rule package.
//An alternative lower level class called "DrlParser" can also be used
PackageBuilder builder = new PackageBuilder();
//this wil parse and compile in one step
//NOTE: There are 2 methods here, the one argument one is for normal DRL.
//builder.addPackageFromDrl( source );
//Use the following instead of above if you are using a DSL:
builder.addPackageFromDrl( source, dsl );
//get the compiled package (which is serializable)
Package pkg = builder.getPackage();
//add the package to a rulebase (deploy the rule package).
RuleBase ruleBase = RuleBaseFactory.newRuleBase();
ruleBase.addPackage( pkg );
return ruleBase;
}
这里在官方的例子基础上做了自己的实现(其实什么都没改)。
可以看到,第一步是取得文件IO,这个文件就是我们要写得规则脚本,这个等下再说,大家可以假象一下脚本是个什么样子,现在只说怎么在程序中取得Rule。
接下来,是使用Builder取得一个package,既然builder都上来了说明能输入的脚本不止一个了。用addPackageFromDrl向这个builder压缩机里面输入脚本,当然还有另外一个文件dsl,这个后面再说。利用builder取得package。
最后构造一个BaseRule,利用Factory取得的时候是有选择的,RuleBaseFactory.newRuleBase(int type)其中的type可以为不同的Algorithm,有RETE和Leaps 两种。对这两种Algorithm的具体解释可以参看 http://citeseer.ist.psu.edu/context/505087/0 或是 drools的文档,其实我也不太懂。
把刚才的package添到ruleBase里面一个Rule就大功告成了。
接下来看看怎么执行它:
WorkingMemory workingMemory
=
ruleBase.newWorkingMemory();
// go !
Order order = new Order();
order.setId( 1 );
order.setName( " testOrder " );
order.setTotlePrice( 10 );
User user = new User();
user.setName( " testAdmin " );
user.setAuth( " USER_ADMIN " );
List < String > roles = new ArrayList < String > ();
roles.add( " ADMIN " );
user.setRoles(roles);
User user1 = new User();
user1.setName( " testUser " );
user1.setAuth( " USER_USER " );
List < String > roles1 = new ArrayList < String > ();
roles1.add( " USER " );
user1.setRoles(roles1);
workingMemory.assertObject(order);
workingMemory.assertObject(user);
workingMemory.assertObject(user1);
workingMemory.fireAllRules();
List < AclEntry > acls = workingMemory.getObjects(AclEntry. class );
// go !
Order order = new Order();
order.setId( 1 );
order.setName( " testOrder " );
order.setTotlePrice( 10 );
User user = new User();
user.setName( " testAdmin " );
user.setAuth( " USER_ADMIN " );
List < String > roles = new ArrayList < String > ();
roles.add( " ADMIN " );
user.setRoles(roles);
User user1 = new User();
user1.setName( " testUser " );
user1.setAuth( " USER_USER " );
List < String > roles1 = new ArrayList < String > ();
roles1.add( " USER " );
user1.setRoles(roles1);
workingMemory.assertObject(order);
workingMemory.assertObject(user);
workingMemory.assertObject(user1);
workingMemory.fireAllRules();
List < AclEntry > acls = workingMemory.getObjects(AclEntry. class );
用ruleBase生成一个WorkingMemory,WorkingMemory是Rule的执行引擎,装载rule和事实(很重要的概念),并统一执行他们。接下来我就在写我的事实,事实是什么,事实就是今天是什么天?订单总价多少?就是要告诉脚本的java对象。然后把事实一一压入WorkingMemory这个大压缩机。就瞧好吧。
OK可以执行了,fireAllRules!(真TM,COOL的名字)。当然有全部执行就有部分执行。你可以把规则分组,然后按组执行,或是指定rule的名字来执行(这里还是大家自己看看吧)。
???究竟执行了什么。当然是执行了我们的脚本,脚本在这里、看看它可不是xml了:
#created on:
2006
-
5
-
19
package com.sample;
#list any import classes here.
import com.sample.domain.Order;
import com.sample.domain.User;
import com.sample.AclEntry;
#expander mylang.dsl
#declare any global variables here
rule " Order TotlePrice more than $1000 "
when
#conditions
$order : Order( totlePrice > 1000 )
$user : User( roles contains " ADMIN " , $userName : name)
then
#actions
System.out.println( " More Than " );
assert ( new AclEntry($order, $user, 1 ));
end
rule " Order TotlePrice less or equl than $1000 "
when
#conditions
$order : Order( totlePrice <= 1000 )
$user : User( $userName : name )
then
#actions
System.out.println( " Less Than " );
assert ( new AclEntry($order, $user, 2 ));
end
package com.sample;
#list any import classes here.
import com.sample.domain.Order;
import com.sample.domain.User;
import com.sample.AclEntry;
#expander mylang.dsl
#declare any global variables here
rule " Order TotlePrice more than $1000 "
when
#conditions
$order : Order( totlePrice > 1000 )
$user : User( roles contains " ADMIN " , $userName : name)
then
#actions
System.out.println( " More Than " );
assert ( new AclEntry($order, $user, 1 ));
end
rule " Order TotlePrice less or equl than $1000 "
when
#conditions
$order : Order( totlePrice <= 1000 )
$user : User( $userName : name )
then
#actions
System.out.println( " Less Than " );
assert ( new AclEntry($order, $user, 2 ));
end
每一个rule就是一个规则,所有的事实要一一过一遍这些规则。when是规则提出的条件,如果哪个事实符合这个条件,就进入then的环节,进行相应的处理。
分析一下条件:$order : Order( totlePrice > 1000 )。一看就知道是总价超过1000的订单。$order是把这个订单邦定,后面可以使用。
分析一下then: System.out.println就不解释了。assert(new AclEntry($order, $user, 2)); 这里的assert的意义就是告诉WorkingMemory一个事实,其实跟前面的加入事实一个道理。打个比方,如果有闪电,那么就有雷。
这样走完一个rule后大家很容易发现,其实是根据订单和用户的角色不同产生了不同的acl,然后我要拿到这些由事实得到的事实。
List
<
AclEntry
>
acls
=
workingMemory.getObjects(AclEntry.
class
);
这样就能在workingMemory里面掏出我们需要的事实来,新鲜出炉的哦。
相当粗略的讲了一下drools,目的是希望大家都来了解一下,共同学习。