我们先看个例子,然后在说明两个函数的作用。
kmodule.xml
<kbase name="FireKB" packages="org.drools.examples.fire.simple">
<ksession name="FireKS"/>
</kbase>
<kbase name="FireLogicalKB" packages="org.drools.examples.fire.logical">
<ksession name="FireLogicalKS"/>
</kbase>
Fire.drl在org.drools.examples.fire.simple下
package org.drools.examples.fire.simple;
import org.drools.examples.fire.Fire;
import org.drools.examples.fire.Alarm;
import org.drools.examples.fire.Room;
import org.drools.examples.fire.Sprinkler;
rule RaiseAlarm when
exists Fire()
then
insert( new Alarm( "house1" ) );
System.out.println( "Raise the Alarm");
end
rule CancelAlarm when
not Fire()
a : Alarm()
then
delete( a );
System.out.println( "Cancel the Alarm");
end
rule ThereIsAnAlarm when
Alarm()
then
System.out.println( "there is an Alarm " );
end
rule ThereIsNoAlarm when
not Alarm()
then
System.out.println( "there is no Alarm " );
end
rule TurnSprinklerOn when
s : Sprinkler( on == false )
f : Fire( room == s.room )
then
modify( s ) { setOn( true ) }
System.out.println( "Turn on the sprinkler for room " + f.getRoom().getName() );
end
rule TurnSprinklerOff when
s : Sprinkler( on == true )
not Fire( room == s.room )
then
modify( s ) { setOn( false ) }
System.out.println( "Turn off the sprinkler for room " + s.getRoom().getName() );
end
rule OK when
not Alarm()
not Sprinkler( on == true )
then
System.out.println( "Everything is ok" );
end
FireLogical.drl在org.drools.examples.fire.logical下
package org.drools.examples.fire.logical;
import org.drools.examples.fire.Fire;
import org.drools.examples.fire.Alarm;
import org.drools.examples.fire.Room;
import org.drools.examples.fire.Sprinkler;
rule RaiseAlarm when
Fire()
then
insertLogical( new Alarm( "house1" ) );
System.out.println( "Raise the Alarm");
end
rule ThereIsAnAlarm when
Alarm()
then
System.out.println( "there is an Alarm " );
end
rule ThereIsNoAlarm when
not Alarm()
then
System.out.println( "there is no Alarm " );
end
rule TurnSprinklerOn when
s : Sprinkler( on == false )
f : Fire( room == s.room )
then
modify( s ) { setOn( true ) }
System.out.println( "Turn on the sprinkler for room " + f.getRoom().getName() );
end
rule TurnSprinklerOff when
s : Sprinkler( on == true )
not Fire( room == s.room )
then
modify( s ) { setOn( false ) }
System.out.println( "Turn off the sprinkler for room " + s.getRoom().getName() );
end
rule OK when
not Alarm()
not Sprinkler( on == true )
then
System.out.println( "Everything is ok" );
end
下面是模型类。
package org.drools.examples.fire;
public class Alarm {
private String name;
public Alarm(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Alarm{" +
"name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) { return true; }
if (o == null || getClass() != o.getClass()) { return false; }
Alarm alarm = (Alarm) o;
if (!name.equals(alarm.name)) { return false; }
return true;
}
@Override
public int hashCode() {
return name.hashCode();
}
}
package org.drools.examples.fire;
public class Fire {
private Room room;
public Fire(Room room) {
this.room = room;
}
public Room getRoom() {
return room;
}
public void setRoom(Room room) {
this.room = room;
}
@Override
public String toString() {
return "Fire{" +
"room=" + room +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) { return true; }
if (o == null || getClass() != o.getClass()) { return false; }
Fire fire = (Fire) o;
if (!room.equals(fire.room)) { return false; }
return true;
}
@Override
public int hashCode() {
return room.hashCode();
}
}
package org.drools.examples.fire;
public class Room {
private String name;
public Room(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Room{" +
"name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) { return true; }
if (o == null || getClass() != o.getClass()) { return false; }
Room room = (Room) o;
if (!name.equals(room.name)) { return false; }
return true;
}
@Override
public int hashCode() {
return name.hashCode();
}
}
package org.drools.examples.fire;
public class Sprinkler {
private Room room;
private boolean on;
public Sprinkler(Room room) {
this.room = room;
}
public Sprinkler(Room room, boolean on) {
this.room = room;
this.on = on;
}
public Room getRoom() {
return room;
}
public void setRoom(Room room) {
this.room = room;
}
public boolean isOn() {
return on;
}
public void setOn(boolean on) {
this.on = on;
}
@Override
public String toString() {
return "Sprinkler{" +
"room=" + room +
", on=" + on +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) { return true; }
if (o == null || getClass() != o.getClass()) { return false; }
Sprinkler sprinkler = (Sprinkler) o;
if (on != sprinkler.on) { return false; }
if (!room.equals(sprinkler.room)) { return false; }
return true;
}
@Override
public int hashCode() {
int result = room.hashCode();
result = 31 * result + (on ? 1 : 0);
return result;
}
}
测试类。
package org.drools.examples.fire;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class FireExample {
public static void main(final String[] args) {
KieContainer kc = KieServices.Factory.get().getKieClasspathContainer();
KieSession ksession = kc.newKieSession("FireKS");
String[] names = new String[]{"kitchen", "bedroom", "office", "livingroom"};
Map<String,Room> name2room = new HashMap<>(4);
for( String name: names ){
Room room = new Room( name );
name2room.put( name, room );
ksession.insert( room );
Sprinkler sprinkler = new Sprinkler( room );
ksession.insert( sprinkler );
}
ksession.fireAllRules();
pause();
Fire kitchenFire = new Fire( name2room.get( "kitchen" ) );
Fire officeFire = new Fire( name2room.get( "office" ) );
FactHandle kitchenFireHandle = ksession.insert( kitchenFire );
FactHandle officeFireHandle = ksession.insert( officeFire );
ksession.fireAllRules();
pause();
ksession.delete( kitchenFireHandle );
ksession.delete(officeFireHandle);
ksession.fireAllRules();
ksession.dispose(); // Stateful rule session must always be disposed when finished
}
public static void pause() {
System.out.println( "Pressure enter to contnue" );
Scanner keyboard = new Scanner(System.in);
keyboard.nextLine();
}
}
运行结果
there is no Alarm
Everything is ok
Pressure enter to contnue
Raise the Alarm
there is an Alarm
Turn on the sprinkler for room kitchen
Turn on the sprinkler for room office
Pressure enter to contnue
Cancel the Alarm
there is no Alarm
Turn off the sprinkler for room kitchen
Turn off the sprinkler for room office
Everything is ok
测试类
package org.drools.examples.fire;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class FireLogicalExample {
public static void main(final String[] args) {
KieContainer kc = KieServices.Factory.get().getKieClasspathContainer();
KieSession ksession = kc.newKieSession("FireLogicalKS");
String[] names = new String[]{"kitchen", "bedroom", "office", "livingroom"};
Map<String,Room> name2room = new HashMap<>(4);
for( String name: names ){
Room room = new Room( name );
name2room.put( name, room );
ksession.insert( room );
Sprinkler sprinkler = new Sprinkler( room );
ksession.insert( sprinkler );
}
ksession.fireAllRules();
pause();
Fire kitchenFire = new Fire( name2room.get( "kitchen" ) );
Fire officeFire = new Fire( name2room.get( "office" ) );
FactHandle kitchenFireHandle = ksession.insert( kitchenFire );
FactHandle officeFireHandle = ksession.insert( officeFire );
ksession.fireAllRules();
pause();
ksession.delete( kitchenFireHandle );
ksession.delete(officeFireHandle);
ksession.fireAllRules();
pause();
ksession.dispose(); // Stateful rule session must always be disposed when finished
}
public static void pause() {
System.out.println( "Pressure enter to contnue" );
Scanner keyboard = new Scanner(System.in);
keyboard.nextLine();
}
}
运行结果
there is no Alarm
Everything is ok
Pressure enter to contnue
Raise the Alarm
Raise the Alarm
there is an Alarm
Turn on the sprinkler for room kitchen
Turn on the sprinkler for room office
Pressure enter to contnue
there is no Alarm
Turn off the sprinkler for room kitchen
Turn off the sprinkler for room office
Everything is ok
对比两次运行结果发现:
- 同样是插入了两个Fire对象,Fire.drl中规则RaiseAlarm只触发了一次,FireLogical.drl中规则RaiseAlarm触发了两次。
- 在将Fire对象全部删除后,Fire.drl中会触发规则CancelAlarm->ThereIsNoAlarm->TurnSprinklerOff->OK,FireLogical.drl中并没有像Fire.drl一样在规则CancelAlarm中删除Alarm但依旧触发了规则ThereIsNoAlarm。
综上:
- 对于exists Fire(),表示只在乎是否存在而不在乎存在几个,即使存在多个RHS只生效一次。对Fire(),存在几个RHS就会执行几次。
- insertLogical当没有更多的fact支持当前激发规则的真值状态时,对象自动删除。 对于FireLogical.drl,使用insertLogical插入一个Alarm对象后,会触发事件ThereIsAnAlarm后不会再触发新的规则,这个Alarm就会自动删除了,也就不需要显示删除了。