21.7. Honest Politician example decisions (truth maintenance and salience)
The Honest Politician example decision set demonstrates the concept of truth maintenance with logical insertions and the use of salience in rules.
The following is an overview of the Honest Politician example:
-
Name:
honestpolitician
-
Main class:
org.drools.examples.honestpolitician.HonestPoliticianExample
(insrc/main/java
) -
Module:
drools-examples
- Type: Java application
-
Rule file:
org.drools.examples.honestpolitician.HonestPolitician.drl
(insrc/main/resources
) - Objective: Demonstrates the concept of truth maintenance based on the logical insertion of facts and the use of salience in rules
The basic premise of the Honest Politician example is that an object can only exist while a statement is true. A rule consequence can logically insert an object with the insertLogical()
method. This means the object remains in the KIE session working memory as long as the rule that logically inserted it remains true. When the rule is no longer true, the object is automatically retracted.
In this example, rule execution causes a group of politicians to change from being honest to being dishonest as a result of a corrupt corporation. As each politician is evaluated, they start out with their honesty attribute being set to true
, but a rule fires that makes the politicians no longer honest. As they switch their state from being honest to dishonest, they are then removed from the working memory. The rule salience notifies the decision engine how to prioritize any rules that have a salience defined for them, otherwise utilizing the default salience value of 0
. Rules with a higher salience value are given higher priority when ordered in the activation queue.
Politician and Hope classes
The sample class Politician
in the example is configured for an honest politician. The Politician
class is made up of a String item name
and a Boolean item honest
:
Politician class
public class Politician { private String name; private boolean honest; ... }
The Hope
class determines if a Hope
object exists. This class has no meaningful members, but is present in the working memory as long as society has hope.
Hope class
public class Hope { public Hope() { } }
Rule definitions for politician honesty
In the Honest Politician example, when at least one honest politician exists in the working memory, the "We have an honest Politician"
rule logically inserts a new Hope
object. As soon as all politicians become dishonest, the Hope
object is automatically retracted. This rule has a salience
attribute with a value of 10
to ensure that it fires before any other rule, because at that stage the "Hope is Dead"
rule is true.
Rule "We have an honest politician"
rule "We have an honest Politician" salience 10 when exists( Politician( honest == true ) ) then insertLogical( new Hope() ); end
As soon as a Hope
object exists, the "Hope Lives"
rule matches and fires. This rule also has a salience
value of 10
so that it takes priority over the "Corrupt the Honest"
rule.
Rule "Hope Lives"
rule "Hope Lives" salience 10 when exists( Hope() ) then System.out.println("Hurrah!!! Democracy Lives"); end
Initially, four honest politicians exist so this rule has four activations, all in conflict. Each rule fires in turn, corrupting each politician so that they are no longer honest. When all four politicians have been corrupted, no politicians have the property honest == true
. The rule "We have an honest Politician"
is no longer true and the object it logically inserted (due to the last execution of new Hope()
) is automatically retracted.
Rule "Corrupt the Honest"
rule "Corrupt the Honest" when politician : Politician( honest == true ) exists( Hope() ) then System.out.println( "I'm an evil corporation and I have corrupted " + politician.getName() ); modify ( politician ) { honest = false }; end
With the Hope
object automatically retracted through the truth maintenance system, the conditional element not
applied to Hope
is no longer true so that the "Hope is Dead"
rule matches and fires.
Rule "Hope is Dead"
rule "Hope is Dead" when not( Hope() ) then System.out.println( "We are all Doomed!!! Democracy is Dead" ); end
Example execution and audit trail
In the HonestPoliticianExample.java
class, the four politicians with the honest state set to true
are inserted for evaluation against the defined business rules:
HonestPoliticianExample.java class execution
public static void execute( KieContainer kc ) { KieSession ksession = kc.newKieSession("HonestPoliticianKS"); final Politician p1 = new Politician( "President of Umpa Lumpa", true ); final Politician p2 = new Politician( "Prime Minster of Cheeseland", true ); final Politician p3 = new Politician( "Tsar of Pringapopaloo", true ); final Politician p4 = new Politician( "Omnipotence Om", true ); ksession.insert( p1 ); ksession.insert( p2 ); ksession.insert( p3 ); ksession.insert( p4 ); ksession.fireAllRules(); ksession.dispose(); }
To execute the example, run the org.drools.examples.honestpolitician.HonestPoliticianExample
class as a Java application in your IDE.
After the execution, the following output appears in the IDE console window:
Execution output in the IDE console
Hurrah!!! Democracy Lives I'm an evil corporation and I have corrupted President of Umpa Lumpa I'm an evil corporation and I have corrupted Prime Minster of Cheeseland I'm an evil corporation and I have corrupted Tsar of Pringapopaloo I'm an evil corporation and I have corrupted Omnipotence Om We are all Doomed!!! Democracy is Dead
The output shows that, while there is at least one honest politician, democracy lives. However, as each politician is corrupted by some corporation, all politicians become dishonest, and democracy is dead.
To better understand the execution flow of this example, you can modify the HonestPoliticianExample.java
class to include a DebugRuleRuntimeEventListener
listener and an audit logger to view execution details:
HonestPoliticianExample.java class with an audit logger
package org.drools.examples.honestpolitician; import org.kie.api.KieServices; import org.kie.api.event.rule.DebugAgendaEventListener; 1 import org.kie.api.event.rule.DebugRuleRuntimeEventListener; import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieSession; public class HonestPoliticianExample { /** * @param args */ public static void main(final String[] args) { KieServices ks = KieServices.Factory.get(); 2 //ks = KieServices.Factory.get(); KieContainer kc = KieServices.Factory.get().getKieClasspathContainer(); System.out.println(kc.verify().getMessages().toString()); //execute( kc ); execute( ks, kc); 3 } public static void execute( KieServices ks, KieContainer kc ) { 4 KieSession ksession = kc.newKieSession("HonestPoliticianKS"); final Politician p1 = new Politician( "President of Umpa Lumpa", true ); final Politician p2 = new Politician( "Prime Minster of Cheeseland", true ); final Politician p3 = new Politician( "Tsar of Pringapopaloo", true ); final Politician p4 = new Politician( "Omnipotence Om", true ); ksession.insert( p1 ); ksession.insert( p2 ); ksession.insert( p3 ); ksession.insert( p4 ); // The application can also setup listeners 5 ksession.addEventListener( new DebugAgendaEventListener() ); ksession.addEventListener( new DebugRuleRuntimeEventListener() ); // Set up a file-based audit logger. ks.getLoggers().newFileLogger( ksession, "./target/honestpolitician" ); 6 ksession.fireAllRules(); ksession.dispose(); } }
- 1
- Adds to your imports the packages that handle the
DebugAgendaEventListener
andDebugRuleRuntimeEventListener
- 2
- Creates a
KieServices Factory
and aks
element to produce the logs because this audit log is not available at theKieContainer
level - 3
- Modifies the
execute
method to use bothKieServices
andKieContainer
- 4
- Modifies the
execute
method to pass inKieServices
in addition to theKieContainer
- 5
- Creates the listeners
- 6
- Builds the log that can be passed into the debug view or Audit View or your IDE after executing of the rules
When you run the Honest Politician with this modified logging capability, you can load the audit log file from target/honestpolitician.log
into your IDE debug view or Audit View, if available (for example, in Window → Show View in some IDEs).
In this example, the Audit View shows the flow of executions, insertions, and retractions as defined in the example classes and rules:
図21.18 Honest Politician example Audit View
When the first politician is inserted, two activations occur. The rule "We have an honest Politician"
is activated only one time for the first inserted politician because it uses an exists
conditional element, which matches when at least one politician is inserted. The rule "Hope is Dead"
is also activated at this stage because the Hope
object is not yet inserted. The rule "We have an honest Politician"
fires first because it has a higher salience
value than the rule "Hope is Dead"
, and inserts the Hope
object (highlighted in green). The insertion of the Hope
object activates the rule "Hope Lives"
and deactivates the rule "Hope is Dead"
. The insertion also activates the rule "Corrupt the Honest"
for each inserted honest politician. The rule "Hope Lives"
is executed and prints "Hurrah!!! Democracy Lives"
.
Next, for each politician, the rule "Corrupt the Honest"
fires, printing "I’m an evil corporation and I have corrupted X"
, where X
is the name of the politician, and modifies the politician honesty value to false
. When the last honest politician is corrupted, Hope
is automatically retracted by the truth maintenance system (highlighted in blue). The green highlighted area shows the origin of the currently selected blue highlighted area. After the Hope
fact is retracted, the rule "Hope is dead"
fires, printing "We are all Doomed!!! Democracy is Dead"
.