- /*
- Ticket示例是对客户电影票分配的处理
- 本例要点:
- 1、使用了duration规则特性
- 因为规则引擎的执行本身是在另外一个线程中进行的,
- 因此使用了duration特性可以将指定的规则延迟一定时间运行
- 但是要注意的是主线程中也需要做相应的延时,否则主线程结束后不会再处理子线程的结果
- 2、使用了Function函数
- 思考:
- 1、原例子中使用不同的延迟时间决定规则的执行顺序,如果将所有"...Priority"规则的延时都设为相同会发生什么情况呢?
- 首先将"Silver Priority","Gold Priority"的duration统一设为2000
- 其次将源码中的t4.setStatus( "Done" );暂时注释,然后执行示例
- 我们会发现在没有使用duration之前规则的执行顺序为DCBA,(指客户名,按照Ticket插入的LIFO顺序激发)
- 而当使用duration之后,执行的顺序为ADCB,原来应当是最后执行的规则被调到最前面执行,而其它顺序不变;
- 如果调换一下Ticket插入顺序,会发现这个规律同样存在
- 2、取消t4.setStatus( "Done" )注释(原版中是t3.setStatus,这里为了方便演示改为t4)又会发生什么呢?
- 因为t4状态的改变会取消D规则,并激发一个新规则"Done"的执行。
- 此时之前的DCBA执行顺序变为AXCB,
- 如果调整Ticket插入顺序为CBAD,则执行顺序是CXBA,
- 调整Ticket插入顺序为BADC,则执行顺序是CXBA
- 也就是说当D正好是duration之后将被第一个执行的规则时,因为setStatus原因被取消了
- 此时其它规则的执行顺序不会被影响,否则将遵照第1点的情况。
- 从上面两个思考中我们可以得到Drools4.0规则对duration情况下执行顺序的潜在规则
- a) duration前应当最后执行的规则被放到了第一位执行,如果该规则在duration结束前被取消,其它规则顺序不会被影响。
- b) 在duration期间如果产生了新的规则,虽然它的优先顺序理论上要比duration之前的规则高(LIFO原则),
- 但是也必须在完成了第一条duration之前的规则执行之后,才能插入后面的规则。
- 从设计的角度来说潜在规则b是可以理解的,但是潜在规则a就让人觉得迷惑,可能是编码上的一个小问题,在Drools4.0中是存在的,
- 以后的版本可能会修正这个问题。
- */
Fact 数据插入
- // 建立客户以及贵宾卡等级
- final CustomerEx a = new CustomerEx( "A",
- "Gold" );
- final CustomerEx b = new CustomerEx( "B",
- "Platinum" );
- final CustomerEx c = new CustomerEx( "C",
- "Silver" );
- final CustomerEx d = new CustomerEx( "D",
- "Silver" );
- // 为客户分配电影票
- final Ticket t1 = new Ticket( a );
- final Ticket t2 = new Ticket( b );
- final Ticket t3 = new Ticket( c );
- final Ticket t4 = new Ticket( d );
- // 将客户数据插入WorkingMemory
- final FactHandle fa = session.insert( a );
- final FactHandle fb = session.insert( b );
- final FactHandle fc = session.insert( c );
- final FactHandle fd = session.insert( d );
- // 将电影票插入WorkingMemory
- final FactHandle ft1 = session.insert( t1 );
- final FactHandle ft2 = session.insert( t2 );
- final FactHandle ft3 = session.insert( t3 );
- final FactHandle ft4 = session.insert( t4 );
- // 激发规则
- session.fireAllRules();
- // 中途修改电影票状态
- // 注意session.update并不会重新激发规则,
- // 只是因为规则引擎之前有延时,所以新的激活规则在引擎完成激发之前插入并执行
- // 如果在引擎完成激发之后update,不会有规则再被激发
- t4.setStatus( "Done" );
- session.update( ft4, t4 );
- try {
- // 通过延时看出规则引擎是在单独的子线程中激发的,
- // 但是fireAllRules可以保证没有指定延时的规则在执行主线程的下一条语句前激发完毕
- System.err.println( "[[ Sleeping 5 seconds ]]" );
- Thread.sleep( 5000 );
- } catch ( final InterruptedException e ) {
- e.printStackTrace();
- }
- System.err.println( "[[ awake ]]" );
- session.dispose();
规则
- # 显示增加的门票情况
- rule "New Ticket"
- salience 10
- when
- customer : CustomerEx( )
- ticket : Ticket( customer == customer, status == "New" )
- then
- System.out.println( "New : " + ticket );
- end
- # 找到银卡会员,设置电影票状态
- rule "Silver Priority"
- duration 3000
- when
- customer : CustomerEx( subscription == "Silver" )
- ticket : Ticket( customer == customer, status == "New" )
- then
- ticket.setStatus( "Escalate" );
- update( ticket );
- end
- # 找到白金卡会员,设置电影票状态
- rule "Platinum Priority"
- when
- customer : CustomerEx( subscription == "Platinum" )
- ticket : Ticket( customer == customer, status == "New" )
- then;
- ticket.setStatus( "Escalate" );
- update( ticket );
- end
- # 找到金卡会员,设置电影票状态
- rule "Gold Priority"
- duration 1000
- when
- customer : CustomerEx( subscription == "Gold" )
- ticket : Ticket( customer == customer, status == "New" )
- then
- ticket.setStatus( "Escalate" );
- update( ticket );
- end
- # 对于被设置状态为Escalate的电影票发送邮件
- rule "Escalate"
- when
- customer : CustomerEx( )
- ticket : Ticket( customer == customer, status == "Escalate" )
- then
- sendEscalationEmail( customer, ticket );
- end
- # 显示状态设置为Done的电影票情况
- rule "Done"
- when
- customer : CustomerEx( )
- ticket : Ticket( customer == customer, status == "Done" )
- then
- System.out.println( "Done : " + ticket );
- end
- # 模拟发送邮件的函数
- function void sendEscalationEmail( CustomerEx customer, Ticket ticket ) {
- System.out.println( "Email : " + ticket );
- }