9.1. Getting the Examples

Make sure the Drools Eclipse plugin is installed, which
needs the Graphical Editing Framework (GEF) dependency installed
first. Then download and extract the
drools-examples zip file, which includes an already created Eclipse
project. Import that project into a new Eclipse workspace. The rules
all have example classes that execute the rules. If you want to try
the examples in another project (or another IDE) then you will need
to set up the dependencies by hand, of course. Many, but not all of the
examples are documented below, enjoy!

9.2. Hello World

The "Hello World" example shows a simple example of rules usage, and
both the MVEL and Java dialects.

This example demonstrates how to build Knowledge Bases and Sessions.
Also, audit logging and debug outputs are shown, which is ommitted
from other examples as it's all very similar. A KnowledgeBuilder
is used to turn a DRL source file into Package objects which
the Knowledge Base can consume. The add method takes a Resource
interface and a Resource Type as parameters. The Resource can be
used to retrieve a DRL source file from various locations; in this case the
DRL file is being retrieved from the classpath using a
ResourceFactory, but it could come from a disk file or a URL.
Here, we only add a single DRL source file, but multiple DRL files can be
added. Also, DRL files with different namespaces can be added, where
the Knowledge Builder creates a package for each namespace. Multiple
packages of different namespaces can be added to the same Knowledge Base.
When all the DRL files have been added, we should check the builder for
errors. While the Knowledge Base will validate the package, it will only
have access to the error information as a String, so if you wish to debug
the error information you should do it on the KnowledgeBuilder
instance. Once you know the builder is error free, get the
Package collection, instantiate a KnowledgeBase
from the KnowledgeBaseFactory and add the package
collection.

Example 9.1. HelloWorld: Creating the KnowledgeBase and Session

finalKnowledgeBuilder kbuilder =KnowledgeBuilderFactory.newKnowledgeBuilder();//this will parse and compile in one stepkbuilder.add(ResourceFactory.newClassPathResource("HelloWorld.drl",HelloWorldExample.class),ResourceType.DRL);//Check the builder for errorsif(kbuilder.hasErrors()){System.out.println(kbuilder.getErrors().toString());thrownewRuntimeException("Unable to compile \"HelloWorld.drl\".");}// get the compiled packages (which are serializable)finalCollection<KnowledgePackage> pkgs = kbuilder.getKnowledgePackages();// add the packages to a knowledgebase (deploy the knowledge packages).finalKnowledgeBase kbase =KnowledgeBaseFactory.newKnowledgeBase();kbase.addKnowledgePackages(pkgs);finalStatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();

Drools has an event model that exposes much of what's happening
internally. Two default debug listeners are supplied,
DebugAgendaEventListener and
DebugWorkingMemoryEventListener which print out
debug event information to the System.err stream displayed
in the Console window. Adding listeners to a
Session is trivial, as shown below. The KnowledgeRuntimeLogger
provides execution auditing, the result of which can be viewed in a
graphical viewer. The logger is actually a specialised implementation
built on the Agenda and Working Memory listeners. When the engine has
finished executing, logger.close() must be called.

Most of the examples use the Audit logging features of Drools to
record execution flow for later inspection.

A single Message object is created with the
message text "Hello World" and the status HELLO and then
inserted into the engine, at which point fireAllRules()
is executed. Remember that all the network evaluation is done
during the insert time, so that by the time the program execution reaches the
fireAllRules() method call the engine already knows which rules
are fully matches and able to fire.

Open the class org.drools.examples.helloworld.HelloWorldExample in your
Eclipse IDE

Right-click the class and select "Run as..." and then "Java
application"

If we put a breakpoint on the fireAllRules() method
and select the ksession variable, we can see that the
"Hello World" rule is already activated and on the Agenda, confirming
that all the pattern matching work was already done during the insert.

Figure 9.1. Hello World: fireAllRules Agenda View

The may application print outs go to to System.out while the debug
listener print outs go to System.err.

The LHS (after when) section of the rule states that it will be
activated for each Message object inserted into the Working
Memory whose status is Message.HELLO. Besides that, two
variable bindings are created: the variable message is bound
to the message attribute and the variable m
is bound to the matched Message object itself.

The RHS (after then) or consequence part of the rule is
written using the MVEL expression language, as declared by
the rule's attribute dialect. After printing the content of
the bound variable message to System.out,
the rule changes the values of the message and
status attributes of the Message object
bound to m. This is done MVEL's modify statement,
which allows you to apply a block of assignments in one statement, with the
engine being automatically notified of the changes at the end of the
block.

We can set a breakpoint into the DRL, on the modify
call, and inspect the Agenda view again during the execution of the
rule's consequence. This time we start the execution via "Debug As"
and "Drools application" and not by running a "Java application":

Open the class org.drools.examples.HelloWorld in your
Eclipse IDE.

Right-click the class and select "Debug as..." and then "Drools
application".

Now we can see that the other rule "Good Bye", which
uses the Java dialect, is activated and placed on the Agenda.

Figure 9.2. Hello World: rule "Hello World" Agenda View

The "Good Bye" rule, which specifies the "java" dialect, is similar
to the "Hello World" rule except that it matches Message
objects whose status is Message.GOODBYE.

Remember the Java code where we used the
KnowledgeRuntimeLoggerFactory method newFileLogger
to create a KnowledgeRuntimeLogger and called
logger.close() at the end. This created an audit log file that
can be shown in the Audit view. We use the Audit view in many of the
examples to demostrate the example execution flow. In the view screen shot
below we can see that the object is inserted, which creates an activation
for the "Hello World" rule; the activation is then executed which updates
the Message object causing the "Good Bye" rule to
activate; finally the "Good Bye" rule also executes. Selecting an event in
the Audit view highlights the origin event in green; therefore the
"Activation created" event is highlighted in green as the origin of the
"Activation executed" event.

Figure 9.3. Hello World: Audit View

9.3. State Example

This example is implemented in three different versions to
demonstrate different ways of implementing the same basic behavior:
forward chaining, i.e., the ability the engine has to evaluate,
activate and fire rules in sequence, based on changes on the facts
in the Working Memory.

Ignoring the PropertyChangeSupport, which will
be explained later, we see the creation of four State
objects named A, B, C and D. Initially their states are set to
NOTRUN, which is default for the used constructor.
Each instance is asserted in turn into the Session and then
fireAllRules() is called.

Open the class org.drools.examples.state.StateExampleUsingSalience in your Eclipse IDE.

Right-click the class and select "Run as..." and then
"Java application"

You will see the following output in the Eclipse console
window:

Example 9.11. Salience State: Console Output

A finished
B finished
C finished
D finished

There are four rules in total. First, the Bootstrap
rule fires, setting A to state FINISHED, which then
causes B to change its state to FINISHED. C and D are
both dependent on B, causing a conflict which is resolved by the
salience values. Let's look at the way this was executed.

The best way to understand what is happening is to use the
Audit Logging feature to graphically see the results of each
operation. To view the Audit log generated by a run of this
example:

If the Audit View is not visible, click on "Window" and
then select "Show View", then "Other..." and "Drools" and
finally "Audit View".

In the "Audit View" click the "Open Log" button and select
the file "<drools-examples-dir>/log/state.log".

After that, the "Audit view" will look like the following
screenshot:

Figure 9.4. Salience State Example Audit View

Reading the log in the "Audit View", top to bottom, we see every
action and the corresponding changes in the Working Memory. This way
we observe that the assertion of the State object A in the state
NOTRUN activates the Bootstrap rule, while
the assertions of the other State objects have no
immediate effect.

The execution of rule "A to B" changes the state of B to
FINISHED, which activates both, rules "B to C" and
"B to D", placing their Activations onto the Agenda. From this moment
on, both rules may fire and, therefore, they are said to be
"in conflict". The conflict resolution strategy allows the engine's
Agenda to decide which rule to fire. As rule "B to C" has the
higher salience value (10 versus
the default salience value of 0), it fires first, modifying object C
to state FINISHED. The Audit view shown above reflects
the modification of the State object in the rule "A to B",
which results in two activations being in conflict. The Agenda view
can also be used to investigate the state of the Agenda, with debug
points being placed in the rules themselves and the Agenda view opened.
The screen shot below shows the breakpoint in the rule "A to B" and
the state of the Agenda with the two conflicting rules.

Another notable concept in this example is the use of
dynamic facts, based on
PropertyChangeListener objects. As described in the
documentation, in order for the engine to see and react to changes of
fact properties, the application must tell the engine that changes
occurred. This can be done explicitly in the rules by using the
modify statement, or implicitly by letting the engine know
that the facts implement PropertyChangeSupport as defined
by the JavaBeans specification. This example
demonstrates how to use PropertyChangeSupport to avoid
the need for explicit modify statements in the rules. To
make use of this feature, ensure that your facts implement
PropertyChangeSupport, the same way the class
org.drools.example.State does, and use the following
code to insert the facts into the Working Memory:

Example 9.16. Inserting a Dynamic Fact

//By setting dynamic to TRUE,Drools will use JavaBean//PropertyChangeListeners so you don't have to call modify or update().finalboolean dynamic =true;session.insert( fact, dynamic );

When using PropertyChangeListener objects, each
setter must implement a little extra code for the notification. Here
is the setter for state in the class
org.drools.examples:

There are two other classes in this example:
StateExampleUsingAgendGroup and
StateExampleWithDynamicRules. Both execute from A to B
to C to D, as just shown. The StateExampleUsingAgendGroup
uses agenda-groups to control the rule conflict and which one fires
first. StateExampleWithDynamicRules shows how an
additional rule can be added to an already running Working Memory
with all the existing data applying to it at runtime.

Agenda groups are a way to partition the Agenda into groups
and to control which groups can execute. By default, all rules are
in the agenda group "MAIN". The "agenda-group" attribute lets
you specify a different agenda group for the rule. Initially,
a Working Memory has its focus on the Agenda group "MAIN". A group's
rules will only fire when the group receives the focus. This can be
achieved either ny using the method by setFocus() or the
rule attribute auto-focus. "auto-focus" means that the rule
automatically sets the focus to its agenda group when the rule is
matched and activated. It is this "auto-focus" that enables rule
"B to C" to fire before "B to D".

The single fact class Fibonacci is used in this
example. It has two fields, sequence and value. The sequence field
is used to indicate the position of the object in the Fibonacci
number sequence. The value field shows the value of that
Fibonacci object for that sequence position, using -1 to indicate
a value that still needs to be computed.

To kick this off from Java we only insert a single Fibonacci
object, with a sequence field of 50. A recursive rule is then used
to insert the other 49 Fibonacci objects. This example
doesn't use
PropertyChangeSupport. It uses the MVEL dialect, which
means we can use the modify keyword, which allows a block
setter action which also notifies the engine of changes.

Example 9.24. Fibonacci Example: Execution

ksession.insert(newFibonacci(50));ksession.fireAllRules();

The rule Recurse is very simple. It matches each asserted
Fibonacci object with a value of -1, creating and
asserting a new Fibonacci object with a sequence of
one less than the currently matched object. Each time a Fibonacci
object is added while the one with a sequence field equal to 1
does not exist, the rule re-matches and fires again. The
not conditional element is used to stop the rule's matching
once we have all 50 Fibonacci objects in memory. The rule also has a
salience value, because we need to have all 50 Fibonacci
objects asserted before we execute the Bootstrap rule.

The Audit view shows the original assertion of the
Fibonacci object with a sequence field of 50, done from
Java code. From there on, the Audit view shows the continual
recursion of the rule, where each asserted Fibonacci
object causes the Recurse rule to become activated and to fire again.

Figure 9.6. Fibonacci Example: "Recurse" Audit View 1

When a Fibonacci object with a sequence field of 2 is
asserted the "Bootstrap" rule is matched and activated along with the
"Recurse" rule. Note the multi-restriction on field
sequence, testing for equality with 1 or 2.

At this point the Agenda looks as shown below. However,
the "Bootstrap" rule does not fire because the "Recurse" rule has a higher
salience.

Figure 9.7. Fibonacci Example: "Recurse" Agenda View 1

When a Fibonacci object with a sequence of 1 is
asserted the Bootstrap rule is matched again, causing two activations
for this rule. Note that the "Recurse" rule does not match and activate
because the not conditional element stops the rule's matching
as soon as a Fibonacci object with a sequence of 1
exists.

Figure 9.8. Fibonacci Example: "Recurse" Agenda View 2

Once we have two Fibonacci objects with values
not equal to -1 the "Calculate" rule is able to match. It was
the "Bootstrap" rule that set the objects with sequence 1 and 2 to
values of 1. At this point we have 50 Fibonacci objects in the Working
Memory. Now we need to select a suitable triple to calculate each
of their values in turn. Using three Fibonacci patterns in a rule without
field constraints to confine the possible cross products would result
in 50x49x48 possible combinations, leading to about 125,000 possible rule
firings, most of them incorrect. The "Calculate" rule uses field
constraints to correctly constraint the thee Fibonacci patterns in the
correct order; this
technique is called cross product matching. The
first pattern finds any Fibonacci with a value != -1 and binds both
the pattern and the field. The second Fibonacci does this, too, but
it adds an additional field constraint to ensure that its sequence is
greater by one than the Fibonacci bound to f1. When this
rule fires for the first time, we know that only sequences 1 and 2
have values of 1, and the two constraints ensure that f1
references sequence 1 and f2 references sequence 2. The
final pattern finds the Fibonacci with a value equal to -1 and with a
sequence one greater than f2. At this point, we have
three Fibonacci objects correctly selected from the
available cross products, and we can calculate the value for the
third Fibonacci object that's bound to f3.

The modify statement updated the value of the
Fibonacci object bound to f3. This means
we now have another new Fibonacci object with a value not equal to -1,
which allows the "Calculate" rule to rematch and calculate the next
Fibonacci number. The Audit view below shows how the firing of the
last "Bootstrap" modifies the Fibonacci object,
enabling the "Calculate" rule to match, which then modifies
another Fibonacci object allowing the "Calculate" rule to match again.
This continues till the value is set for all Fibonacci
objects.

This tutorial demonstrates the process of developing a
complete personal banking application to handle credits and debits on
multiple accounts. It uses a set of design patterns that have
been created for the process.

The class RuleRunner is a simple harness to execute
one or more DRL files against a set of data. It compiles the Packages
and creates the Knowledge Base for each execution, allowing us to
easily execute each scenario and inspect the outputs. In reality this
is not a good solution for a production system, where the Knowledge Base
should be built just once and cached, but for the purposes of this
tutorial it shall suffice.

This doesn’t use any specific facts but instead asserts a set
of java.lang.Integer objects. This is not considered
"best practice" as a number is not a useful fact, but we use it here
to demonstrate basic techniques before more complexity is added.

Once again, this rule does nothing special. It identifies any
facts that are Number objects and prints out the values.
Notice the use of the abstract class Number: we inserted
Integer objects but we now look for any kind of number.
The pattern matching engine is able to match interfaces and
superclasses of asserted objects.

The output shows the DRL being loaded, the facts inserted and
then the matched and fired rules. We can see that each inserted number
is matched and fired and thus printed.

Example 9.34. Banking Tutorial: Output of Example2.java

Loading file: Example2.drl
Inserting fact: 3
Inserting fact: 1
Inserting fact: 4
Inserting fact: 1
Inserting fact: 5
Number found with value: 5
Number found with value: 1
Number found with value: 4
Number found with value: 1
Number found with value: 3

There are certainly many better ways to sort numbers than using
rules, but since we will need to apply some cashflows in date order
when we start looking at banking rules we'll develop simple rule
based sorting technique.

The first line of the rule identifies a Number and
extracts the value. The second line ensures that there does not exist
a smaller number than the one found by the first pattern. We might
expect to match only one number - the smallest in the set. However,
the retraction of the number after it has been printed means that the
smallest number has been removed, revealing the next smallest number,
and so on.

The resulting output shows that the numbers are now
sorted numerically.

Example 9.37. Banking Tutorial: Output of Example3.java

Loading file: Example3.drl
Inserting fact: 3
Inserting fact: 1
Inserting fact: 4
Inserting fact: 1
Inserting fact: 5
Number found with value: 1
Number found with value: 1
Number found with value: 3
Number found with value: 4
Number found with value: 5

We are ready to start moving towards our personal accounting
rules. The first step is to create a Cashflow object.

Class Cashflow has two simple attributes, a date
and an amount. (Note that using the type double for
monetary units is generally not a good idea
because floating point numbers cannot represent most numbers accurately.)
There is also an overloaded constructor to set the values, and a
method toString to print a cashflow. The Java code of
Example4.java inserts five Cashflow objects,
with varying dates and amounts.

Here, we identify a Cashflow and extract the date
and the amount. In the second line of the rule we ensure that there
is no Cashflow with an earlier date than the one found. In the
consequence, we print the Cashflow that satisfies the
rule and then retract it, making way for the next earliest
Cashflow. So, the output we generate is:

Next, we extend our Cashflow, resulting in a
TypedCashflow which can be a credit or a debit operation.
(Normally, we would just add this to the Cashflow type, but
we use extension to keep the previous version of the class intact.)

Here, we identify a Cashflow fact with a type
of CREDIT and extract the date and the amount. In the
second line of the rule we ensure that there is no Cashflow
of the same type with an earlier date than the one found. In the
consequence, we print the cashflow satisfying the patterns and then
retract it, making way for the next earliest cashflow of type
CREDIT.

Continuing our banking exercise, we are now going to process both
credits and debits on two bank accounts, calculating the account balance.
In order to do this, we create two separate Account objects
and inject them into the Cashflows objects before passing
them to the Rule Engine. The reason for this is to provide easy access
to the correct account without having to resort to helper classes. Let’s
take a look at the Account class first. This is a simple
Java object with an account number and balance:

Although we have separate rules for credits and debits, but we do
not specify a type when checking for earlier cashflows. This is so that
all cashflows are applied in date order, regardless of the cashflow type.
In the conditions we identify the account to work with, and in the
consequences we update it with the cashflow amount.

9.6. Pricing Rule Decision Table Example

The Pricing Rule decision table demonstrates the use of a
decision table in a spreadsheet, in Excel's XLS format, in calculating
the retail cost of an insurance policy. The purpose of the provide set
of rules is to calculate a base price and a discount for a
car driver applying for a specific policy. The driver's age, history and
the policy type all contribute to what the basic premium is, and an
additional chunk of rules deals with refining this with a discount
percentage.

Note the use of the DecisionTableConfiguration object.
Its input type is set to DecisionTableInputType.XLS.
If you use the BRMS, all this is of course taken care of for you.

There are two fact types used in this example, Driver
and Policy. Both are used with their default values. The
Driver is 30 years old, has had no prior claims and
currently has a risk profile of LOW. The Policy
being applied for is COMPREHENSIVE, and it has not yet been
approved.

9.6.2. The decision table

In this decision table, each row is a rule, and each column is
a condition or an action.

Figure 9.10. Decision table configuration

Referring to the spreadsheet show above, we have the
RuleSet declaration, which provides the package name.
There are also other optional items you can have here, such as
Variables for global variables, and Imports
for importing classes. In this case, the namespace of the rules is
the same as the fact classes we are using, so we can omit it.

Moving further down, we can see the RuleTable
declaration. The name after this (Pricing bracket) is used as the
prefix for all the generated rules. Below that, we have
"CONDITION or ACTION", indicating the purpose of the column, i.e.,
whether it forms part of the condition or the consequence of the rule
that will be generated.

You can see that there is a driver, his data spanned across three
cells, which means that the template expressions below it apply to that
fact. We observe the driver's age range (which uses $1 and
$2 with comma-separated values),
locationRiskProfile, and priorClaims in the
respective columns. In the action columns, we are set the policy
base price and log a message.

Figure 9.11. Base price calculation

In the preceding spreadsheet section, there are broad category
brackets, indicated by the comment in the leftmost column. As we know
the details of our drivers and their policies, we can tell (with a bit
of thought) that they should match row number 18, as they have no
prior accidents, and are 30 years old. This gives us a base price
of 120.

Figure 9.12. Discount calculation

The above section contains the conditions for the discount we
might grant our driver. The discount results from the Age
bracket, the number of prior claims, and the policy type. In our case,
the driver is 30, with no prior claims, and is applying for a
COMPREHENSIVE policy, which means we can give a discount
of 20%. Note that this is actually a separate table, but in the same
worksheet, so that different templates apply.

It is important to note that decision tables generate rules.
This means they aren't simply top-down logic, but more a means to
capture data resulting in rules. This is a subtle difference that
confuses some people. The evaluation of the rules is not necessarily
in the given order, since all the normal mechanics of the rule engine
still apply.

9.7. Pet Store Example

Name: Pet Store
Main class: org.drools.examples.petstore.PetStoreExample
Module: drools-examples
Type: Java application
Rules file: PetStore.drl
Objective: Demonstrate use of Agenda Groups, Global Variables and integration with a GUI,
including callbacks from within the rules

The Pet Store example shows how to integrate Rules with a GUI,
in this case a Swing based desktop application. Within the rules file,
it demonstrates how to use Agenda groups and auto-focus to control
which of a set of rules is allowed to fire at any given time. It also
illustrates the mixing of the Java and MVEL dialects within the rules,
the use of accumulate functions and the way of calling Java functions
from within the ruleset.

All of the Java code is contained in one file,
PetStore.java, defining the following principal
classes (in addition to several classes to handle Swing Events):

Petstore contains the main()
method that we will look at shortly.

PetStoreUI is responsible for creating and
displaying the Swing based GUI. It contains several smaller
classes, mainly for responding to various GUI events such as
mouse button clicks.

TableModel holds the table data. Think of it
as a JavaBean that extends the Swing class
AbstractTableModel.

CheckoutCallback allows the GUI to interact
with the Rules.

Ordershow keeps the items that we wish to
buy.

Purchase stores details of the order and
the products we are buying.

Product is a JavaBean holding details of
the product available for purchase, and its price.

Much of the Java code is either plain JavaBeans or Swing-based.
Only a few Swing-related points will be discussed in this section,
but a good tutorial about Swing components can be found at Sun's
Swing website, in
http://java.sun.com/docs/books/tutorial/uiswing/.

The pieces of Java code in Petstore.java
that relate to rules and facts are shown below.

The code shown above loads the rules from a DRL file on the
classpath. Unlike other examples where the facts are asserted and
fired straight away, this example defers this step to later. The
way it does this is via the second last line where a
PetStoreUI object is created using a constructor
accepting the Vector object stock
collecting our products, and an instance of
the CheckoutCallback class containing the Rule Base
that we have just loaded.

The Java code that fires the rules is within the
CheckoutCallBack.checkout() method. This is triggered
(eventually) when the Checkout button is pressed by the user.

Two items get passed into this method. One is the handle to the
JFrame Swing component surrounding the output text
frame, at the bottom of the GUI. The second is a list of order items;
this comes from the TableModel storing the information
from the "Table" area at the top right section of the GUI.

The for loop transforms the list of order items coming from the
GUI into the Order JavaBean, also contained in the
file PetStore.java. Note that it would be
possible to refer to the Swing dataset directly within the rules,
but it is better coding practice to do it this way, using simple
Java objects. It means that we are not tied to Swing if we wanted
to transform the sample into a Web application.

It is important to note that all state in this
example is stored in the Swing components, and that the rules are
effectively stateless. Each time the "Checkout" button is
pressed, this code copies the contents of the Swing
TableModel into the Session's Working Memory.

Within this code, there are nine calls to the Working Memory.
The first of these creates a new Working Memory, as a Stateful
Knowledge Session from the Knowledge Base. Remember that we passed
in this Knowledge Base when we created the CheckoutCallBack
class in the main() method. The next two calls pass in
two objects that we will hold as global variables in the rules: the
Swing text area and the Swing frame used for writing messages.

More inserts put information on products into the Working Memory,
as well as the order list. The final call is the standard
fireAllRules(). Next, we look at what this method causes
to happen within the rules file.

The first part of file PetStore.drl
contains the standard package and import statements to make various
Java classes available to the rules. New to us are the two globals
frame and textArea. They hold references
to the Swing components JFrame and JTextArea
components that were previously passed on by the Java code calling
the setGlobal() method. Unlike variables in rules,
which expire as soon as the rule has fired, global variables retain
their value for the lifetime of the Session.

The next extract from the file PetStore.drl
contains two functions that are referenced by the rules that we will
look at shortly.

Having these functions in the rules file just makes the Pet Store
example more compact. In real life you probably have the functions
in a file of their own, within the same rules package, or as a
static method on a standard Java class, and import them, using
import function my.package.Foo.hello.

The purpose of these two functions is:

doCheckout() displays a dialog asking users
whether they wish to checkout. If they do, focus is set to the
checkOut agenda-group, allowing rules in that group
to (potentially) fire.

requireTank() displays a dialog asking
users whether they wish to buy a tank. If so, a new fish tank
Product is added to the order list in Working
Memory.

We'll see the rules that call these functions later on. The
next set of examples are from the Pet Store rules themselves. The
first extract is the one that happens to fire first, partly because
it has the auto-focus attribute set to true.

Example 9.56. Putting items into working memory: extract from PetStore.drl

This rule matches against all orders that do not yet have their
grossTotal calculated . It loops for each purchase item
in that order. Some parts of the "Explode Cart" rule should be familiar:
the rule name, the salience (suggesting the order for the rules being
fired) and the dialect set to "java". There are three
new features:

agenda-group"init" defines the name
of the agenda group. In this case, there is only one rule in the
group. However, neither the Java code nor a rule consequence sets
the focus to this group, and therefore it relies on the next
attribute for its chance to fire.

auto-focustrue ensures that this rule,
while being the only rule in the agenda group, gets a chance to fire
when fireAllRules() is called from the Java code.

kcontext....setFocus() sets the focus to the
"show items" and "evaluate" agenda groups
in turn, permitting their rules to fire. In practice, we loop
through all items on the order, inserting them into memory, then
firing the other rules after each insert.

The next two listings show the rules within the
"show items" and evaluate agenda groups.
We look at them in the order that they are called.

The "show items" agenda-group has only one rule,
called "Show Items" (note the difference in case). For each purchase
on the order currently in the Working Memory (or Session), it logs
details to the text area at the bottom of the GUI. The
textArea variable used to do this is one of the global
variables we looked at earlier.

The evaluate Agenda group also gains focus from
the "Explode Cart" rule listed previously. This
Agenda group has two rules, "Free Fish Food Sample" and
"Suggest Tank", shown below.

If the rule does fire, it creates a new product (Fish Food Sample), and adds it to the
order in Working Memory.

The rule "Suggest Tank" will only fire if

we don't already have a Fish Tank in our order,
and

we do have more than 5 Gold Fish Products
in our order.

If the rule does fire, it calls the requireTank() function
that we looked at earlier (showing a Dialog to the user, and adding a Tank to
the order / working memory if confirmed). When calling the
requireTank() function the rule passes
the global frame variable so that the
function has a handle to the Swing GUI.

The next rule we look at is "do checkout".

Example 9.59. Doing the Checkout - extract (6) from PetStore.drl

rule "do checkout"
dialect "java"
when
then
doCheckout(frame, drools.getWorkingMemory());
end

The rule "do checkout" has no
agenda group set and no auto-focus attribute. As such, is is
deemed part of the default (MAIN) agenda group. This group gets focus by
default when all the rules in agenda-groups that explicity had focus set
to them have run their course.

There is no LHS to the rule, so the RHS will always call the
doCheckout() function. When calling the
doCheckout() function, the rule passes the global
frame variable to give the function a handle to the Swing GUI.
As we saw earlier, the doCheckout() function shows a
confirmation dialog to the user. If confirmed, the function sets the focus
to the checkout agenda-group, allowing
the next lot of rules to fire.

If we haven't already calculated the gross total,
Gross Total accumulates the product prices into a total,
puts this total into Working Memory, and displays it via the Swing
JTextArea, using the textArea global
variable yet again.

If our gross total is between 10 and 20,
"Apply 5% Discount" calculates the discounted total and
adds it to the Working Memory and displays it in the text area.

If our gross total is not less than 20,
"Apply 10% Discount" calculates the discounted total and
adds it to the Working Memory and displays it in the text area.

Now that we've run through what happens in the code, let's have a
look at what happens when we actually run the code. The file
PetStore.java contains a main() method,
so that it can be run as a standard Java application, either from the
command line or via the IDE. This assumes you have your classpath set
correctly. (See the start of the examples section for more information.)

The first screen that we see is the Pet Store Demo. It has a list
of available products (top left), an empty list of selected products
(top right), checkout and reset buttons (middle) and an empty system
messages area (bottom).

Figure 9.13. PetStore Demo just after Launch

To get to this point, the following things have happened:

The main() method has run and loaded the Rule Base
but not yet fired the rules. So far, this is the
only code in connection with rules that has been run.

A new PetStoreUI object has been created and given a
handle to the Rule Base, for later use.

Various Swing components do their stuff, and the above screen
is shown and waits for user input.

Clicking on various products from the list might give you a
screen similar to the one below.

Figure 9.14. PetStore Demo with Products Selected

Note that no rules code has been fired here. This
is only Swing code, listening for mouse click events, and adding some
selected product to the TableModel object for display in the
top right hand section. (As an aside, note that this is a classic use of
the Model View Controller design pattern).

It is only when we press the "Checkout" button that we fire our
business rules, in roughly the same order that we walked through the
code earlier.

Method CheckOutCallBack.checkout() is called
(eventually) by the Swing class waiting for the click on the
"Checkout" button. This inserts the data from the
TableModel object (top right hand side of the GUI),
and inserts it into the Session's Working Memory. It then fires
the rules.

The "Explode Cart" rule is the first to fire,
given that it has auto-focus set to true. It loops through
all the products in the cart, ensures that the products are in the
Working Memory, and then gives the "Show Items" and
Evaluation agenda groups a chance to fire. The rules
in these groups add the contents of the cart to the text area
(at the bottom of the window), decide whether or not to give us free
fish food, and to ask us whether we want to buy a fish tank. This
is shown in the figure below.

Figure 9.15. Do we want to buy a fish tank?

The Do Checkout rule is the next to fire as it (a) No other agenda group currently has focus and (b) it is part of the default (MAIN) agenda group. It always calls the doCheckout() function which displays a 'Would you like to Checkout?' Dialog Box.

The doCheckout() function sets the focus to the
checkout agenda-group, giving the rules in that group
the option to fire.

The rules in the the checkout agenda-group display
the contents of the cart and apply the appropriate discount.

Swing then waits for user input to either
checkout more products (and to cause the rules to fire again), or to
close the GUI - see the figure below.

Figure 9.16. Petstore Demo after all rules have fired.

We could add more System.out calls to demonstrate this flow of
events. The output, as it currently appears in the Console window, is
given in the listing below.

Example 9.61. Console (System.out) from running the PetStore GUI

Adding free Fish Food Sample to cart
SUGGESTION: Would you like to buy a tank for your 6 fish? - Yes

The Honest Politician example demonstrates truth maintenance with
logical assertions. The basic premise is that an object can only exist
while a statement is true. A rule's consequence can logically insert an
object with the insertLogical() method. This means the object
will only remain in the 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 there is the class Politician, with a
name and a boolean value for being honest. Four politicians with honest
state set to true are inserted.

The Console window output shows that, while there is at
least one honest politician, democracy lives. However, as each
politician is in turn corrupted by an evil corporation, so that
all politicians become dishonest, democracy is dead.

Example 9.64. Honest Politician: Console Output

Hurrah!!! Democracy Lives
I'm an evil corporation and I have corrupted schroder
I'm an evil corporation and I have corrupted chirac
I'm an evil corporation and I have corrupted bush
I'm an evil corporation and I have corrupted blair
We are all Doomed!!! Democracy is Dead

As soon as there is at least one honest politician in the
Working Memory a new Hope object is logically asserted.
This object will only exist while there is at least one honest
politician. As soon as all politicians are dishonest, the
Hope object will be automatically retracted. This rule
is given a salience of 10 to ensure that it fires before any other
rule, as at this stage the "Hope is Dead" rule is actually true.

Now that there is hope and we have, at the start, four honest
politicians, we have four activations for this rule, all in conflict.
They will fire in turn, corrupting each politician so that they are
no longer honest. When all four politicians have been corrupted we
have no politicians with the property honest == true.
Thus, the rule "We have an honest Politician" is no longer true and
the object it logical inserted (due to the last execution of
new Hope()) is automatically retracted.

With the Hope object being automatically retracted,
via the truth maintenance system, the conditional element not
applied to Hope is no longer true so that the following
rule will match and fire.

Example 9.68. Honest Politician: Rule "Hope is Dead"

rule "Hope is Dead"
when
not( Hope() )
then
System.out.println( "We are all Doomed!!! Democracy is Dead" );
end

Let's take a look at the Audit trail for this application:

Figure 9.17. Honest Politician Example Audit View

The moment we insert the first politician we have two activations.
The rule "We have an honest Politician" is activated only once for the first
inserted politician because it uses an exists conditional
element, which matches once for any number. The rule "Hope is Dead" is
also activated at this stage, because we have not yet inserted the
Hope object. Rule "We have an honest Politician" fires first,
as it has a higher salience than "Hope is Dead", which inserts the
Hope object. (That action is highlighted green.) The
insertion of the Hope object activates "Hope Lives" and
de-activates "Hope is Dead"; it also activates "Corrupt the Honest"
for each inserted honest politician. Rule "Hope Lives" executes,
printing "Hurrah!!! Democracy Lives". Then, for each politician, 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's honest value to false. When the last honest politician
is corrupted, Hope is automatically retracted, by the truth
maintenance system, as shown by the blue highlighted area. The green
highlighted area shows the origin of the currently selected blue
highlighted area. Once the Hope fact is retracted, "Hope is
dead" activates and fires printing "We are all Doomed!!! Democracy is
Dead".

This example demonstrates how Drools can be used to find a solution
in a large potential solution space based on a number of constraints. We
use the popular puzzle of Sudoku. This example also shows how Drools can
be integrated into a graphical interface and how callbacks can be used to
interact with a running Drools rules engine in order to update the
graphical interface based on changes in the Working Memory at
runtime.

9.9.1. Sudoku Overview

Sudoku is a logic-based number placement puzzle. The objective is
to fill a 9x9 grid so that each column, each row, and each of the nine
3x3 zones contains the digits from 1 to 9, once, and only once.

The puzzle setter provides a partially completed grid and the
puzzle solver's task is to complete the grid with these
constraints.

The general strategy to solve the problem is to ensure that when
you insert a new number it should be unique in its particular
3x3 zone, row and column.

9.9.2. Running the Example

Download and install drools-examples as described above and then
execute java org.drools.examples.DroolsExamplesApp and
click on "SudokuExample".

The window contains an empty grid, but the program comes
with a number of grids stored internally which can be loaded
and solved. Click on "File", then "Samples" and select "Simple"
to load one of the examples. Note that all buttons are disabled
until a grid is loaded.

Loading the "Simple" example fills the grid according to the
puzzle's initial state.

Click on the "Solve" button and the Drools-based engine will fill
out the remaining values, and the buttons are inactive once
more.

Alternatively, you may click on the "Step" button to see the next
digit found by the rule set. The Console window will display detailed
information about the rules which are executing to solve the step
in a human readable form. Some examples of these messages are
presented below.

single 8 at [0,1]
column elimination due to [1,2]: remove 9 from [4,2]
hidden single 9 at [1,2]
row elimination due to [2,8]: remove 7 from [2,4]
remove 6 from [3,8] due to naked pair at [3,2] and [3,7]
hidden pair in row at [4,6] and [4,4]

Click on the "Dump" button to see the state of the grid, with
cells showing either the established value or the remaining
possibilitiescandidates.

Now, let us load a Sudoku grid that is deliberately invalid. Click
on "File", "Samples" and "!DELIBERATELY BROKEN!". Note that this grid
starts with some issues, for example the value 5 appears twice in the
first row.

A few simple rules perform a sanity check, right after loading
a grid. In this case, the following messages are printed on
standard output:

cell [0,8]: 5 has a duplicate in row 0
cell [0,0]: 5 has a duplicate in row 0
cell [6,0]: 8 has a duplicate in col 0
cell [4,0]: 8 has a duplicate in col 0
Validation complete.

Nevertheless, click on the "Solve" button to apply the solving
rules to this invalid grid. This will not complete; some cells
remain empty.

The solving functionality has been achieved by the use of
rules that implement standard solving techniques. They are based
on the sets of values that are still candidates for a cell. If,
for instance, such a set contains a single value, then this is
the value for the cell. A little less obvious is the single
occurrence of a value in one of the groups of nine cells. The
rules detecting these situations insert a fact of type Setting
with the solution value for some specific cell. This fact causes the
elimination of this value from all other cells in any of the
groups the cell belongs to. Finally, it is retracted.

Other rules merely reduce the permissible values for some
cells. Rules "naked pair", "hidden pair in row", "hidden pair in column"
and "hidden pair in square" merely eliminate possibilities but
do not establish solutions. More sophisticated eliminations are done by
"X-wings in rows", "X-wings in columns", "intersection removal row" and
"intersection removal column".

9.9.3. Java Source and Rules Overview

The Java source code can be found in the
/src/main/java/org/drools/examples/sudoku directory, with the two DRL
files defining the rules located in the
/src/main/rules/org/drools/examples/sudoku directory.

The package org.drools.examples.sudoku.swing
contains a set of classes which implement a framework for Sudoku
puzzles. Note that this package does not have any dependencies on
the Drools libraries. SudokuGridModel defines an
interface which can be implemented to store a Sudoku puzzle as a 9x9
grid of Cell objects. SudokuGridView is
a Swing component which can visualize any implementation of
SudokuGridModel. SudokuGridEvent and
SudokuGridListener are used to
communicate state changes between the model and the view: events are
fired when a cell's value is resolved or changed. If you are familiar
with the model-view-controller patterns in other Swing components such
as JTable then this pattern should be familiar.
SudokuGridSamples provides a number of partially filled
Sudoku puzzles for demonstration purposes.

Package org.drools.examples.sudoku.rules contains a
utility class with a method for compiling DRL files.

The package org.drools.examples.sudoku contains a
set of classes implementing the elementary Cell object
and its various aggregations: the CellFile subtypes
CellRow and CellCol as well as
CellSqr, all of which are subtypes of
CellGroup. It's interesting to note that Cell
and CellGroup are subclasses of SetOfNine,
which provides a property free with the
type Set<Integer>. For a Cell it
represents the individual candidate set; for a CellGroup
the set is the union of all candidate sets of its cells, or, simply,
the set of digits that still need to be allocated.

With 81 Cell and 27 CellGroup objects and
the linkage provided by the Cell properties
cellRow, cellCol and cellSqr
and the CellGroup property cells, a list of
Cell objects, it is possible to write rules that
detect the specific sitations that permit the allocation of a
value to a cell or the elimination of a value from some candidate
set.

An object of class Setting is used for triggering
the operations that accompany the allocation of a value: its removal
from the candidata sets of sibling cells and associated cell groups.
Moreover, the presence of a Setting fact is used in
all rules that should detect a new situation; this is to avoid
reactions to inconsistent intermediary states.

An object of class Stepping is used in a
low priority rule to execute an emergency halt when a "Step"
does not terminate regularly. This indicates that the puzzle
cannot be solved by the program.

9.9.4. Sudoku Validator Rules (validate.drl)

Validation rules detect duplicate numbers in cell groups.
They are combined in an agenda group which enables us to activate
them, explicitly, after loading a puzzle.

The three rules "duplicate in cell..." are very similar.
The first pattern locates a cell with an allocated value. The second
pattern pulls in any of the three cell groups the cell belongs to.
The final pattern would find a cell (other than the first one) with
the same value as the first cell and in the same row, column or
square, respectively.

9.9.5. Sudoku Solving Rules (sudoku.drl)

There are three types of rules in this file: one group
handles the allocation of a number to a cell, another group
detects feasible allocations, and the third group eliminates
values from candidate sets.

Rules "set a value", "eliminate a value from Cell" and
"retract setting" depend on the presence of a Setting
object. The first rule handles the assignment to the cell and the
operations for removing the value from the "free" sets of the
cell's three groups. Also, it decrements a counter that, when
zero, returns control to the Java application that has called
fireUntilHalt(). The purpose of rule
"eliminate a value from Cell" is to reduce the candidate lists
of all cells that are related to the newly assigned cell. Finally,
when all eliminations have been made, rule "retract setting"
retracts the triggering Setting fact.

There are just two rules that detect a situation where an
allocation of a number to a cell is possible. Rule "single" fires
for a Cell with a candidate set containing a single
number. Rule "hidden single" fires when there is no cell with a
single candidate but when there is a cell containing a candidate but
this candidate is absent from all other cells in one of the three
groups the cell belongs to. Both rules create and insert a
Setting fact.

Rules from the largest group of rules implement, singly or
in groups of two or three, various solving techniques, as they are
employed when solving Sudoku puzzles manually.

Rule "naked pair" detects identical candidate sets of size 2
in two cells of a group; these two values may be removed from all
other candidate sets of that group.

A similar idea motivates the three rules "hidden pair in...";
here, the rules look for a subset of two numbers in exactly two cells
of a group, with neither value occurring in any of the other cells of
this group. This, then, means that all other candidates can be
eliminated from the two cells harbouring the hidden pair.

A pair of rules deals with "X-wings" in rows and columns.
When there are only two possible cells for a value in each of
two different rows (or columns) and these candidates lie also
in the same columns (or rows), then all other candidates for
this value in the columns (or rows) can be eliminated. If you
follow the pattern sequence in one of these rules, you will see
how the conditions that are conveniently expressed by words such as
"same" or "only" result in patterns with suitable constraints
or prefixed with "not".

The rule pair "intersection removal..." is based on the
restricted occurrence of some number within one square, either
in a single row or in a single column. This means that this number
must be in one of those two or three cells of the row or column;
hence it can be removed from the candidate sets of all other cells
of the group. The pattern establishes the restricted occurrence
and then fires for each cell outside the square and within the
same cell file.

These rules are sufficient for many but certainly not for all
Sudoku puzzles. To solve very difficult grids, the rule set would
need to be extended with more complex rules. (Ultimately, there
are puzzles that cannot be solved except by trial and error.)

9.10. Number Guess

Name: Number Guess
Main class: org.drools.examples.numberguess.NumberGuessExample
Module: droolsjbpm-integration-examples (Note: this is in a different download, the droolsjbpm-integration download.)
Type: Java application
Rules file: NumberGuess.drl
Objective: Demonstrate use of Rule Flow to organise Rules

The "Number Guess" example shows the use of Rule Flow, a way of controlling the order in which rules are fired.
It uses widely understood workflow diagrams for defining the order in which groups of rules will be executed.

The creation of the package and the loading of the rules (using the add() method) is the same as
the previous examples. There is an additional line to add the Rule Flow (NumberGuess.rf), which
provides the option of specifying different rule flows for the same Knowledge Base. Otherwise, the Knowledge Base is
created in the same manner as before.

Once we have a Knowledge Base, we can use it to obtain a Stateful Session. Into our session we insert our facts,
i.e., standard Java objects. (For simplicity, in this sample, these classes are all contained within our
NumberGuessExample.java file. Class GameRules provides the maximum range and the
number of guesses allowed. Class RandomNumber automatically generates a number between 0 and 100 and
makes it available to our rules, by insertion via the getValue() method. Class Game keeps
track of the guesses we have made before, and their number.

Note that before we call the standard fireAllRules() method, we also start the process that we
loaded earlier, via the startProcess() method. We'll learn where to obtain the parameter we pass ("Number
Guess", i.e., the identifier of the rule flow) when we talk about the rule flow file and the graphical Rule Flow
Editor below.

Before we finish the discussion of our Java code, we note that in some real-life application we would examine
the final state of the objects. (Here, we could retrieve the number of guesses, to add it to a high score table.) For
this example we are content to ensure that the Working Memory session is cleared by calling the dispose()
method.

Figure 9.18. RuleFlow for the NumberGuess Example

If you open the NumberGuess.rf file in the Drools IDE (provided you have the JBoss Rules
extensions installed correctly in Eclipse) you should see the above diagram, similar to a standard flowchart. Its
icons are similar (but not exactly the same) as in the JBoss jBPM workflow product. Should you wish to edit the
diagram, a menu of available components should be available to the left of the diagram in the IDE, which is called the
palette. This diagram is saved in XML, an (almost) human readable format, using XStream.

If it is not already open, ensure that the Properties View is visible in the IDE. It can be opened by clicking
"Window", then "Show View" and "Other", where you can select the "Properties" view. If you do this
before you select any item on the rule flow (or click on the blank space in the rule flow) you
should be presented with the following set of properties.

Figure 9.19. Properties for the Number Guess Rule Flow

Keep an eye on the Properties View as we progress through the example's rule flow, as it presents valuable
information. In this case, it provides us with the identification of the Rule Flow Process that we used in our earlier
code snippet, when we called session.startProcess().

In the "Number Guess" Rule Flow we encounter several node types, many of them identified by an icon.

The Start node (white arrow in a green circle) and the End node (red box) mark beginning and end of the
rule flow.

A Rule Flow Group box (yellow, without an icon) represents a Rule Flow Groups defined in our rules (DRL)
file that we will look at later. For example, when the flow reaches the Rule Flow Group "Too High", only those
rules marked with an attribute of ruleflow-group"Too High" can potentially
fire.

Split and Join Nodes (blue ovals, no icon) such as "Guess Correct?" and "More guesses Join" mark places
where the flow of control can split, according to various conditions, and rejoin, respectively

Arrows indicate the flow between the various nodes.

The various nodes in combination with the rules make the Number Guess game work. For example, the "Guess" Rule
Flow Group allows only the rule "Get user Guess" to fire, because only that rule has a matching attribute of
ruleflow-group"Guess".

Example 9.71. A Rule firing only at a specific point in the Rule Flow: NumberGuess.drl

The rest of this rule is fairly standard. The LHS section (after when) of the rule states
that it will be activated for each RandomNumber object inserted into the Working Memory where
guessCount is less than allowedGuesses from the GameRules object and where the
user has not guessed the correct number.

The RHS section (or consequence, after then) prints a message to the user and then awaits
user input from System.in. After obtaining this input (the readLine() method call blocks
until the return key is pressed) it modifies the guess count and inserts the new guess, making both available to the
Working Memory.

The rest of the rules file is fairly standard: the package declares the dialect as MVEL, and various Java
classes are imported. In total, there are five rules in this file:

Get User Guess, the Rule we examined above.

A Rule to record the highest guess.

A Rule to record the lowest guess.

A Rule to inspect the guess and retract it from memory if incorrect.

A Rule that notifies the user that all guesses have been used up.

One point of integration between the standard Rules and the RuleFlow is via the
ruleflow-group attribute on the rules, as dicussed above. A second point of integration
between the rules (.drl) file and the Rules Flow .rf files is that the Split Nodes (the blue ovals) can use
values in the Working Memory (as updated by the rules) to decide which flow of action to take. To see how this works,
click on the "Guess Correct Node"; then within the Properties View, open the Constraints Editor by clicking the button
at the right that appears once you click on the "Constraints" property line. You should see something similar to the
diagram below.

Figure 9.20. Edit Constraints for the "Guess Correct" Node

Click on the "Edit" button beside "To node Too High" and you'll see a dialog like the one below. The values in
the "Textual Editor" window follow the standard rule format for the LHS and can refer to objects in Working Memory.
The consequence (RHS) is that the flow of control follows this node (i.e., "To node Too High") if the LHS expression
evaluates to true.

Since the file NumberGuess.java contains a main() method, it can be run as a
standard Java application, either from the command line or via the IDE. A typical game might result in the interaction
below. The numbers in bold are typed in by the user.

Example 9.72. Example Console output where the Number Guess Example beat the human!

You have 5 out of 5 guesses left.
Please enter your guess from 0 to 100
50
Your guess was too high
You have 4 out of 5 guesses left.
Please enter your guess from 0 to 100
25
Your guess was too low
You have 3 out of 5 guesses left.
Please enter your guess from 0 to 100
37
Your guess was too low
You have 2 out of 5 guesses left.
Please enter your guess from 0 to 100
44
Your guess was too low
You have 1 out of 5 guesses left.
Please enter your guess from 0 to 100
47
Your guess was too low
You have no more guesses
The correct guess was 48

A summary of what is happening in this sample is:

The main() method of NumberGuessExample.java loads a Rule Base, creates a
Stateful Session and inserts Game, GameRules and RandomNumber (containing
the target number) objects into it. The method also sets the process flow we are going to use, and fires all
rules. Control passes to the Rule Flow.

File NumberGuess.rf, the Rule Flow, begins at the "Start" node.

Control passes (via the "More guesses" join node) to the Guess node.

At the Guess node, the appropriate Rule Flow Group ("Get user Guess") is enabled. In this case the Rule
"Guess" (in the NumberGuess.drl file) is triggered. This rule displays a message to the user,
takes the response, and puts it into Working Memory. Flow passes to the next Rule Flow Node.

At the next node, "Guess Correct", constraints inspect the current session and decide which path to
take.

If the guess in step 4 was too high or too low, flow proceeds along a path which has an action node with
normal Java code printing a suitable message and a Rule Flow Group causing a highest guess or lowest guess rule to
be triggered. Flow passes from these nodes to step 6.

If the guess in step 4 was right, we proceed along the path towards the end of the Rule Flow. Before we get
there, an action node with normal Java code prints a statement "you guessed correctly". There is a join node here
(just before the Rule Flow end) so that our no-more-guesses path (step 7) can also terminate the Rule Flow.

Control passes as per the Rule Flow via a join node, a guess incorrect Rule Flow Group (triggering a rule to
retract a guess from Working Memory) onto the "More guesses" decision node.

The "More guesses" decision node (on the right hand side of the rule flow) uses constraints, again looking
at values that the rules have put into the working memory, to decide if we have more guesses and if so, goto step
3. If not, we proceed to the end of the rule flow, via a Rule Flow Group that triggers a rule stating "you have no
more guesses".

The loop over steps 3 to 7 continues until the number is guessed correctly, or we run out of guesses.

9.11.1. Introduction

Miss Manners is throwing a party and, being a good host, she wants
to arrange good seating. Her initial design arranges everyone in
male-female pairs, but then she worries about people have things to talk
about. What is a good host to do? She decides to note the hobby of
each guest so she can then arrange guests not only pairing them according
to alternating sex but also ensuring that a guest has someone with a
common hobby, at least on one side.

Figure 9.22. Miss Manners' Guests

9.11.1.1. BenchMarking

Five benchmarks were established in the 1991 paper "Effects of
Database Size on Rule System Performance: Five Case Studies" by
David Brant, Timothy Grose, Bernie Lofaso and Daniel P. Miranker:

Manners uses a
depth-first search approach to determine the
seating arrangements alternating women and men and ensuring
one common hobby for neighbors.

Waltz establishes
a three-dimensional interpretation of a line drawing by
line labeling by constraint propagation.

WaltzDB is a more
general version of Waltz, supporting junctions of more
than three lines and using a database.

ARP is a
route planner for a robotic air vehicle using the A*
search algorithm to achieve minimal cost.

Weaver
VLSI router for channels and boxes using a black-board
technique.

Manners has become the de facto rule engine benchmark.
Its behavior, however, is now well known and many engines
optimize for this, thus negating its usefulness as a benchmark
which is why Waltz is becoming more favorable. These five
benchmarks are also published at the University of Texas http://www.cs.utexas.edu/ftp/pub/ops5-benchmark-suite/.

9.11.1.2. Miss Manners Execution Flow

After the first seating arrangement has been assigned, a
depth-first recursion occurs which repeatedly assigns correct
seating arrangements until the last seat is assigned. Manners
uses a Context instance to control execution flow.
The activity diagram is partitioned to show the relation of the
rule execution to the current Context state.

Figure 9.23. Manners Activity Diagram

9.11.1.3. The Data and Results

Before going deeper into the rules, let's first take a look
at the asserted data and the resulting seating arrangement. The
data is a simple set of five guests who should be arranged so
that sexes alternate and neighbors have a common hobby.

The Data

The data is given in OPS5 syntax, with a parenthesized
list of name and value pairs for each attribute. Each
person has only one hobby.

Each line of the results list is printed per execution of the
"Assign Seat" rule. They key bit to notice is that each line has
a "pid" value one greater than the last. (The significance of this
will be explained in the discussion of the rule "Assign Seating".)
The "ls", "rs", "ln" and "rn" refer to the left and right
seat and neighbor's name, respectively. The actual implementation
uses longer attribute names (e.g., leftGuestName,
but here we'll stick to the notation from the original
implementation.

9.11.2. Indepth Discussion

9.11.2.1. Cheating

Manners has been designed to exercise cross product
joins and Agenda activities. Many people not understanding this
tweak the example to achieve better performance, making their
port of the Manners benchmark pointless. Known cheats or
porting errors for Miss Manners are:

Using arrays for a guests hobbies, instead of asserting each
one as a single fact massively reduces the cross products.

Altering the sequence of data can also reduce the
amount of matching, increasing execution speed.

It's possible to change the not Conditional
Element so that the test algorithm only uses the
"first-best-match", which is, basically, transforming
the test algorithm to backward chaining. The results are only
comparable to other backward chaining rule engines or ports of
Manners.

Removing the context so the rule engine matches the guests
and seats prematurely. A proper port will prevent facts from
matching using the context start.

If no facts are retracted in the reasoning cycle, as a
result of the not CE, the port is incorrect.

9.11.2.2. Conflict Resolution

The Manners benchmark was written for OPS5 which has two conflict
resolution strategies, LEX and MEA. LEX is a chain of several
strategies including salience, recency and complexity. The recency
part of the strategy drives the depth first (LIFO) firing order.
The CLIPS manual documents the Recency strategy as follows:

Every fact and instance is marked internally with a "time tag"
to indicate its relative recency with respect to every other fact
and instance in the system. The pattern entities associated with
each rule activation are sorted in descending order for determining
placement. An activation with a more recent pattern entity is
placed before activations with less recent pattern entities. To
determine the placement order of two activations, compare the sorted
time tags of the two activations one by one starting with the
largest time tags. The comparison should continue until one
activation’s time tag is greater than the other activation’s
corresponding time tag. The activation with the greater time tag is
placed before the other activation on the agenda. If one activation
has more pattern entities than the other activation and the compared
time tags are all identical, then the activation with more time tags
is placed before the other activation on the agenda.

--CLIPS Reference Manual

However Jess and CLIPS both use the Depth strategy, which is
simpler and lighter, which Drools also adopted. The CLIPS manual
documents the Depth strategy as:

Newly activated rules are placed above all rules of the same
salience. For example, given that fact-a activates rule-1 and rule-2
and fact-b activates rule-3 and rule-4, then if fact-a is asserted
before fact-b, rule-3 and rule-4 will be above rule-1 and rule-2 on
the agenda. However, the position of rule-1 relative to rule-2 and
rule-3 relative to rule-4 will be arbitrary.

--CLIPS Reference Manual

The initial Drools implementation for the Depth strategy would
not work for Manners without the use of salience on the "make_path"
rule. The CLIPS support team had this to say:

The default conflict resolution strategy for CLIPS, Depth, is
different than the default conflict resolution strategy used by
OPS5. Therefore if you directly translate an OPS5 program to CLIPS,
but use the default depth conflict resolution strategy, you're only
likely to get the correct behavior by coincidence. The LEX and MEA
conflict resolution strategies are provided in CLIPS to allow you to
quickly convert and correctly run an OPS5 program in CLIPS.

--Clips Support Forum

Investigation into the CLIPS code reveals there is undocumented
functionality in the Depth strategy. There is an accumulated time tag
used in this strategy; it's not an extensively fact by fact comparison
as in the recency strategy, it simply adds the total of all the time
tags for each activation and compares.

9.11.2.3. Rule "assignFirstSeat"

Once the context is changed to START_UP,
activations are created for all asserted guest. Because all
activations are created as the result of a single Working Memory
action, they all have the same Activation time tag. The last
asserted Guest object would have a higher fact
time tag, and its Activation would fire because it has the highest
accumulated fact time tag. The execution order in this rule has little
importance, but has a big impact in the rule "Assign Seat". The
activation fires and asserts the first Seating
arrangement and a Path, and then sets the
Context attribute state to create
an activation for rule findSeating.

9.11.2.4. Rule "findSeating"

This rule determines each of the Seating
arrangements. The rule creates cross product solutions for
all asserted Seating arrangements
against all the asserted guests except
against itself or any already assigned chosen solutions.

However, as can be seen from the printed results shown earlier,
it is essential that only the Seating with the highest
pid cross product be chosen. How can this be possible
if we have activations, of the same time tag, for nearly all
existing Seating and Guest objects? For
example, on the third iteration of findDeating the
produced activations will be as shown below. Remember, this is from
a very small data set, and with larger data sets there would be many
more possible activated Seating solutions, with multiple
solutions per pid:

The creation of all these redundant activations might seem
pointless, but it must be remembered that Manners is not about good
rule design; it's purposefully designed as a bad ruleset to fully
stress-test the cross product matching process and the Agenda, which
this clearly does. Notice that each activation has the same time tag
of 35, as they were all activated by the change in the
Context object to ASSIGN_SEATS. With OPS5
and LEX it would correctly fire the activation with the
Seating asserted last. With Depth, the accumulated fact
time tag ensures that the activation with the last asserted
Seating fires.

9.11.2.5. Rules "makePath" and "pathDone"

Rule makePath must always fire before
pathDone. A Path object is asserted for
each Seating arrangement, up to the last asserted
Seating. Notice that the conditions in
pathDone are a subset of those in
makePath - so how do we ensure that makePath
fires first?

Both rules end up on the Agenda in conflict and with identical
activation time tags. However, the accumulate fact time tag is greater
for "Make Path" so it gets priority.

9.11.2.6. Rules "continue" and "areWeDone"

Rule areWeDone only activates when the last seat
is assigned, at which point both rules will be activated. For the
same reason that makePath always wins over
path Done, areWeDone will take
priority over rule continue.

9.12. Conway's Game Of Life

Name: Conway's Game Of Life
Main class: org.drools.examples.conway.ConwayAgendaGroupRun
org.drools.examples.conway.ConwayRuleFlowGroupRun
Module: droolsjbpm-integration-examples (Note: this is in a different download, the droolsjbpm-integration download.)
Type: Java application
Rules file: conway-ruleflow.drl conway-agendagroup.drl
Objective: Demonstrates 'accumulate', 'collect' and 'from'

Conway's Game Of Life, described in http://en.wikipedia.org/wiki/Conway's_Game_of_Life and in
http://www.math.com/students/wonders/life/life.html,
is a famous cellular automaton conceived in the early 1970's by the
mathematician John Conway. While the system is well known as "Conway's
Game Of Life", it really isn't a game at all. Conway's system is more like
a simulation of a form of life. Don't be intimidated. The system
is terribly simple and terribly interesting. Math and Computer Science
students alike have marvelled over Conway's system for more than 30 years
now. The application
presented here is a Swing-based implementation of Conway's Game of Life.
The rules that govern the system are implemented as business rules using
Drools. This document will explain the rules that drive the simulation and
discuss the Drools parts of the implementation.

We'll first introduce the grid view, shown below, designed for the
visualisation of the game, showing the "arena" where the life simuation
takes place. Initially the grid is empty, meaning that there are no live
cells in the system. Each cell is either alive or dead, with live cells
showing a green ball. Preselected patterns of live cells can be
chosen from the "Pattern" drop-down list. Alternatively, individual
cells can be doubled-clicked to toggle them between live and dead. It's
important to understand that each cell is related to its neighboring cells,
which is fundamental for the game's rules. Neighbors include not only
cells to the left, right, top and bottom but also cells that are connected
diagonally, so that each cell has a total of 8 neighbors. Exceptions
are the four corner cells which have only three neighbors, and the cells
along the four border, with five neighbors each.

Figure 9.25. Conway's Game of Life: Starting a new game

So what are the basic rules that govern this game? Its goal is to
show the development of a population, generation by generation. Each
generation results from the preceding one, based on the simultaneous
evaluation of all cells. This is the simple set of rules that
govern what the next generation will look like:

If a live cell has fewer than 2 live neighbors, it dies of
loneliness.

If a live cell has more than 3 live neighbors, it dies from
overcrowding.

If a dead cell has exactly 3 live neighbors, it comes to
life.

That is all there is to it. Any cell that doesn't meet any of those
criteria is left as is for the next generation. With those simple rules in
mind, go back and play with the system a little bit more and step through
some generations, one at a time, and notice these rules taking their
effect.

The screenshot below shows an example generation, with a number of
live cells. Don't worry about matching the exact patterns represented in
the screen shot. Just get some groups of cells added to the grid. Once you
have groups of live cells in the grid, or select a pre-designed pattern,
click the "Next Generation" button and notice what happens. Some of the
live cells are killed (the green ball disappears) and some dead cells come
to life (a green ball appears). Step through several generations and see
if you notice any patterns. If you click on the "Start" button, the system
will evolve itself so you don't need to click the "Next Generation" button
over and over. Play with the system a little and then come back here for
more details of how the application works.

Figure 9.26. Conway's Game of Life: A running game

Now lets delve into the code. As this is an advanced example we'll
assume that by now you know your way around the Drools framework and are
able to connect the presented highlight, so that we'll just focus at a
high level overview. The example has two ways to execute, one way
uses Agenda Groups to manage execution flow, and the other one uses
Rule Flow Groups to manage execution flow. These two versions are
implemented in ConwayAgendaGroupRun and
ConwayRuleFlowGroupRun, respectively. Here,
we'll discuss the Rule Flow version, as it's what most people will
use.

All the Cell objects are inserted into the Session
and the rules in the ruleflow-group "register neighbor" are
allowed to execute by the Rule Flow process. This group of four rules
creates Neighbor relations between some cell and its
northeastern, northern, northwestern and western neighbors. This
relation is bidirectional, which takes care of the other four directions.
Border cells don't need any special treatment - they simply won't be
paired with neighboring cells where there isn't any. By
the time all activations have fired for these rules, all cells are related
to all their neighboring cells.

Once all the cells are inserted, some Java code applies the pattern
to the grid, setting certain cells to Live. Then, when the user clicks
"Start" or "Next Generation", it executes the "Generation" ruleflow. This
ruleflow is responsible for the management of all changes of cells in each
generation cycle.

Figure 9.27. Conway's Game of Life: rule flow "Generation"

The rule flow process first enters the "evaluate" group, which means
that any active rule in the group can fire. The rules in this group apply
the Game-of-Life rules discussed in the beginning of the example,
determining the cells to be killed and the ones to be given life. We use
the "phase" attribute to drive the reasoning of the Cell by specific
groups of rules; typically the phase is tied to a Rule Flow Group in the
Rule Flow process definition. Notice that it doesn't actually change the
state of any Cell objectss at this point; this is because
it's evaluating the grid in turn and it must complete the full evaluation
until those changes can be applied. To achieve this, it sets the cell to
a "phase" which is either Phase.KILL or
Phase.BIRTH, used later to control actions applied
to the Cell object.

Example 9.74. Conway's Game of Life: Evaluate Cells with state changes

Once all Cell objects in the grid have been evaluated,
we first clear any calculation activations that occured from any previous
data changes. This is done via the "reset calculate" rule, which clears
any activations in the "calculate" group. We then enter a split in the
rule flow which allows any activations in both the "kill" and the "birth"
group to fire. These rules are responsible for applying the state
change.

At this stage, a number of Cell objects have been
modified with the state changed to either LIVE or
DEAD. Now we get to see the power of the
Neighbor facts defining the cell relations. When a cell
becomes live or dead, we use the Neighbor relation to
iterate over all surrounding cells, increasing or decreasing the
liveNeighbor count. Any cell that has its count changed
is also set to to the EVALUATE phase, to make sure
it is included in the reasoning during the evaluation stage of the
Rule Flow Process. Notice that we don't have to do any iteration
ourselves; simply by applying the relations in the rules we make
the rule engine do all the hard work for us, with a minimal amount of
code. Once the live count has been determined and set for all cells,
the Rule Flow Process comes to and end. If the user has initially
clicked the "Start" button, the engine will restart the rule flow;
otherwise the user may request another generation.

Example 9.76. Conway's Game of Life: Evaluate cells with state changes