[jboss-svn-commits] JBL Code SVN: r25807 - labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Tue Mar 24 20:54:05 EDT 2009
Author: mark.proctor at jboss.com
Date: 2009-03-24 20:54:05 -0400 (Tue, 24 Mar 2009)
New Revision: 25807
Removed:
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Chapter-Quick_Start.html
Log:
remvong .html, should never have been committed
Deleted: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Chapter-Quick_Start.html
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Chapter-Quick_Start.html 2009-03-25 00:53:19 UTC (rev 25806)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Chapter-Quick_Start.html 2009-03-25 00:54:05 UTC (rev 25807)
@@ -1,590 +0,0 @@
-<html><head>
- <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Chapter 1. Quick Start</title><meta name="generator" content="DocBook XSL-NS Stylesheets V1.74.3-pre"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="d0e1"></a>Chapter 1. Quick Start</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#d0e4">The Basics</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e7">Stateless Knowledge Session</a></span></dt><dt><span class="section"><a href="#d0e73">Stateful Knowledge Session</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e159">A Little Theory</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e162">Methods versus Rules</a></span></dt><dt><span class="section"><a href="#d0e188">Cross Products</a></span></dt><dt><span class="section"><a href="#d0e207">Execution Control</a></span></dt!
></dl></dd></dl></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e4"></a>The Basics</h2></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e7"></a>Stateless Knowledge Session</h3></div></div></div><p>So where do we get started, there are so many use cases and so much functionality in a
- rule engine such as Drools that it becomes beguiling. Have no fear my intrepid adventurer,
- the complexity is layered and you can ease yourself into with simple use cases.</p><p>Stateless session, not utilising inference, forms the simplest of use case. A stateless
- session can be called like a function passing it some data and then receiving some results
- back. Some common use cases for stateless sessions are, but not limited to:</p><div class="itemizedlist"><ul type="disc"><li><p>Validation</p><div class="itemizedlist"><ul type="circle"><li><p>Is this person legible for a mortgage</p></li></ul></div></li><li><p>Calculation</p><div class="itemizedlist"><ul type="circle"><li><p>Mortgage premium</p></li></ul></div></li><li><p>Routing/Filtering</p><div class="itemizedlist"><ul type="circle"><li><p>Filtering incoming messages, such as emails, into folders</p></li><li><p>Sending incoming message to a destinatino</p></li></ul></div></li></ul></div><p>So lets start with a very simple example using a driving license application.</p><pre class="programlisting">public class Applicant {
- private String name;
- private int age;
- private boolean valid;
- // getter and setter methods here
-}
-</pre><p>Now we have our data model we can write our first rule, we assume the application starts
- off valid and rules would be used to disqualify the application. As this is a simple
- validation use case we will add a single rule to disqualify the applicant if they are
- younger than 18.</p><pre class="programlisting">package com.company.license
-
-rule "Is of valid age"
-when
- $a : Applicant( age < 18 )
-then
- $a.setValid( false );
-end</pre><p>To make the engine aware of data, so it can be processed against the rules, we have to
- "insert" the data, much like with a database. When the Applicant instance is inserted into
- the engine it is evaluated against the constraints of the rules, in this case just two
- constraint for one rule. We say two because the type Applicant is the first object type
- constraint, and the "age < 18" is the second field constraint. An object type constraint
- plus it's zero or more field constraints is referred to as a pattern. When an inserted
- instance satisfies both the object type constraint and all the field constraints, it is said
- to be matched. The "$a" is a binding and allows the matched object to be referenced in the
- consquence, so it's properties can be updated, the $ is optional, but it helps to
- differentiate the variables from the fields. This part of the engine is often referred to as
- pattern matchin, i.e. the matching of patterns against the inserted data.</p><p>Let's assume that the rules are in the same folder as the classes, so we can use the
- classpath resource loader to build our first KnowledgeBase. A KnowledgeBase is what we call
- our collection of compiled rules, which are compiled using the KnowledgeBuilder.</p><pre class="programlisting">KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
-kbuilder.add( ResourceFactory.newClasspathResource( "licenseApplication.drl", getClass() ),
- ResourceType.DRL );
-if ( kbuilder.hasErrors() ) {
- System.err.println( builder.getErrors().toString() );
-} </pre><p>The above looks on the classpath for the "licenseApplication.drl" file, using the given
- classes getResource() method. The ResourceType here is DRL, short for "Drools Rule
- Language". Once the drl has be added we can check the KnowledgeBuilder for any errors. If
- there are no errors, we are now ready to build our session and execute against some
- data:</p><pre class="programlisting">StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
-Applicant applicant = new Applicant( "Mr John Smith", 16 );
-assertTrue( applicant.isValid() );
-ksession.execute( applicant );
-assertFalse( applicant.isValid() );
-</pre><p>The above executes the data against the rules, the applicant is under the age of 18, so
- it marked invalid.</p><p>So far we've only used a single instance, but what if want to use more than one? We can
- also execute against an Iterable, such a a collection. Lets add another class called
- Application, which has the date of the application and we'll move the boolean valid field to
- the Application class.</p><pre class="programlisting">public class Applicant {
- private String name;
- private int age;
- // getter and setter methods here
-}
-
-
-public class Application {
- private Date dateApplied;
- private boolean valid;
- // getter and setter methods here
-}</pre><p>And we can also add another rule, that validates the Application was made within a
- period of time.</p><pre class="programlisting">package com.company.license
-
-rule "Is of valid age"
-when
- Applicant( age < 18 )
- $a : Application()
-then
- $a.setValid( false );
-end
-
-rule "Application was made this year"
-when
- $a : Application( dateApplied > "01-jan-2009" )
-then
- $a.setValid( false );
-end
-</pre><p>Unfortunately in java an array does not implement h the Iterable interface, so we have
- to use the JDK converter, asList(...). So code below executes against an Iterable, where
- each of the collection elements are inserted before any matched rules are fired.</p><pre class="programlisting">StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
-Applicant applicant = new Applicant( "Mr John Smith", 16 );
-Application application = new Application();
-assertTrue( application() );
-ksession.execute( Arrays.asList( new Object[] { application, applicant } ) );
-assertFalse( application() );
-</pre><p>The two execute methods execute(Object object ) and execute(Iterable objects) are
- actually convenience methods for the interface BatchExecutor's method execute(Command
- command). This allows for more than just fact insertion, and also handles "out" parameters
- and results.</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e73"></a>Stateful Knowledge Session</h3></div></div></div><p>Stateful sessions are longer lived and allow iterative changes over time. Some common
- use cases for stateful sessions are, but not limited to:</p><div class="itemizedlist"><ul type="disc"><li><p>Monitoring</p><div class="itemizedlist"><ul type="circle"><li><p>Stock market monitorig and analysis for semi-automatic buying.</p></li></ul></div></li><li><p>Diagnostics</p><div class="itemizedlist"><ul type="circle"><li><p>fault finding, medical diagnostics</p></li></ul></div></li><li><p>Logistics</p><div class="itemizedlist"><ul type="circle"><li><p>parcel tracking and delivery provisioning</p></li></ul></div></li><li><p>Compliance</p><div class="itemizedlist"><ul type="circle"><li><p>Validation of legality for market trades.</p></li></ul></div></li></ul></div><p>We can use a fire alarm example to explore the monitoring use case. The simple example
- has just 4 classes. We are monitoring the rooms in a house, each room has one sprinkler. If
- a fire starts in a room, we represent that with a single Fire instance.</p><pre class="programlisting">public class Room {
- private String name
- // getter and setter methods here
-}
-public classs Sprinkler {
- private Room room;
- private boolean on;
- // getter and setter methods here
-}
-public class Fire {
- private room room;
- // getter and setter methods here
-}
-public class Alarm {
-}
-</pre><p>In the previous section on stateless sessions the concepts of inserting and matching
- against data was introduced. That example assumed only a single instance of each object type
- was ever inserted and thus only used literal constraints. However a house has many rooms, so
- rules have the need to express joins that constraint to the desired objects, this can be
- done using a binding as a variable constraint in a pattern. This join process results in
- what is called cross products, which are covered in the next section.</p><p>When a fire occurs an instance of the Fire class is created, for that room, and insert
- it. The rule uses a binding on the room field of the Fire to constrain to the Sprinkler for
- that room, which is currently off. When this rule fires and the consequence is executed the
- sprinkler is turned on</p><pre class="programlisting">rule "When there is a fire turn on the sprinkler"
-when
- Fire($room : room)
- $sprinkler : Sprinkler( room == $room, on == false )
-then
- modify( $sprinkler ) { setOn( true ) };
- System.out.println( "Turn off the sprinkler for room " + $room.getName() );
-end</pre><p>Where as the stateless session used standard java syntax to modify a field, in the above
- rule we use the modify keyword, which acts as a sort of with statement, that contains a
- series of comma separated java expressions. Stateless sessions do not have inference, so the
- engine does not need to be aware of changes to data, however a stateful session does. The
- modify keyword allows the setters to modify the data, while make the engine aware of those
- changes so it can reason over them, this process is called inference.</p><p>So far we have rules that tell us when matching data exists, but what about when it
- doesn't exist? What about when there stops being a Fire? Previously the constraints have
- been propositional logic where the engine is constraining against individual intances,
- Drools also has support for first order logic that allows you to look at sets of data. The
- 'not' keyword matches when something does not exist. So for a Room with a Sprinkler that is
- on when the Fire for that room stops existing we can turn off the sprinkler.</p><pre class="programlisting">rule "When the fire is gone turn on the sprinkler"
-when
- $room : Room( )
- $sprinkler : Sprinkler( room == $room, on == true )
- not Fire( room == $room )
-then
- modify( $sprinkler ) { setOn( false ) };
- System.out.println( "Turn off the sprinkler for room " + $room.getName() );
-end</pre><p>While there is a Sprinkler per room, there is just a single Alarm for the building. An
- Alarm is created when a Fire is occurs, but only one Alarm is needed for the entire
- building, no matter how many Fires occur. Previously 'not' was introduced, the compliment to
- ths is 'exists' which matches for one or more of something.</p><pre class="programlisting">rule "Raise the alarm when we have one or more fires"
-when
- exists Fire()
-then
- insert( new Alarm() );
- System.out.println( "Raise the alarm" );
-end</pre><p>Likewise when there are no Fires we want to remove the alarm, so the 'not' keyword can
- be used again.</p><pre class="programlisting">rule "Lower the alarm when all the fires have gone"
-when
- not Fire()
- $alarm : Alarm()
-then
- retract( $alarm );
- System.out.println( "Lower the alarm" );
-end
-
-</pre><p>Finally there is a general health status message, that is printed when the application
- first starts and after the Alarm is removed and all Sprinklers have been turned off.</p><pre class="programlisting">rule "Status output when things are ok"
-when
- not Alarm()
- not Sprinkler( on === true )
-then
- System.out.println( "Everything is ok" );
-end</pre><p>The above rules should be placed in a single drl file and saved to the classpath using
- the file name "fireAlarm.drl", as per the stateless session example. We can then build a
- KnowledgeBase as before, just using the new name "fireAlarm.drl". The difference is this
- time we create a stateful session from the kbase, where as before we created a stateless
- session.</p><pre class="programlisting">KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
-kbuilder.add( ResourceFactory.newClasspathResource( "fireAlarm.drl", getClass() ),
- ResourceType.DRL );
-if ( kbuilder.hasErrors() ) {
- System.err.println( builder.getErrors().toString() );
-}
-StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();</pre><p>With the session created it is now possible to iteratvely work with it over time. Four
- Rooms are created and inserted, a Sprinkler for each room is also inserted. At this point
- the engine has done all it's matching, but no rules have fired. calling "fireAllRules" on
- the ksession allows the matched rules to fire, currently that is just the health
- message.</p><pre class="programlisting">Room kitchen = new Room( "kitchen" );
-Room bedroom = new Room( "bedroom" );
-Room office = new Room( "office" );
-Room livingRoom = new Room( "livingroom" );
-
-ksession.insert( kitchen );
-ksession.insert( bedroom );
-ksession.insert( office );
-ksession.insert( livingRoom );
-
-Sprinkler kitchenSprinkler = new Sprinkler( kitchen );
-Sprinkler bedroomSprinkler = new Sprinkler( bedroom );
-Sprinkler officeSprinkler = new Sprinkler( office );
-Sprinkler livingRoomSprinkler = new Sprinkler( livingRoom );
-
-
-ksession.insert( kitchenSprinkler );
-ksession.insert( bedroomSprinkler );
-ksession.insert( officeSprinkler );
-ksession.insert( livingRoomSprinkler );
-
-ksession.fireAllRules()
-</pre><pre class="programlisting">> Everything is ok</pre><p>We now create two fires and insert them, this time a referenced is kept for the returned
- FactHandle. The FactHandle is an internal engine reference to the inserted instance and
- allows that instance to be retracted or modified at a later point in time. With the Fires
- now in the engine, once "fireAllRules" is called, the Alarm is raised and the respectively
- Sprinklers are turned on.</p><pre class="programlisting">Fire kitchenFire = new Fire( kitchen );
-Fire officeFire = new Fire( office );
-
-FactHandle kitchenFireHandle = kession.insert( kitchenFire );
-FactHandle officeFireHandle = ksession.insert( officeFire );
-
-ksession.fireAllRules();</pre><pre class="programlisting">> Raise the alarm
-> Turn on the sprinkler for room kitchen
-> Turn on the sprinkler for room office</pre><p>After a while the fires will be put out and the Fire intances are retracted. This
- results in the Sprinklers being turned off, the Alarm being lowered and eventually the
- health message is printed again.</p><pre class="programlisting">ksession.retract( kitchenFire );
-ksession.retract( officeFire );
-
-ksession.fireAllRules();</pre><pre class="programlisting">> Turn on the sprinkler for room office
-> Turn on the sprinkler for room kitchen
-> Lower the alarm
-> Everything is ok</pre><p>Every one still with me? That wasn't so hard and already I'm hoping you can start to see
- the value and power of a declarative rule system.</p></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e159"></a>A Little Theory</h2></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e162"></a>Methods versus Rules</h3></div></div></div><p>People often confuse methods and rules, and new rule users regular ask, "how do I call a
- rule?". After the last section, you are now feeling like a rule expert and the answer to
- that is obvsious, but just to summarise.</p><pre class="programlisting">public void helloWorld(Person person) {
- if ( person.getName().equals( “Chuck” ) ) {
- System.out.println( “Hello Chuck” );
- }
-}</pre><div class="itemizedlist"><ul type="disc"><li><p>Methods are called directly.</p></li><li><p>Specific instances are passed.</p></li></ul></div><pre class="programlisting">rule “Hello World”
- when
- Person( name == “Chuck” )
- then
- System.out.println( “Hello Chuck” );
- end</pre><div class="itemizedlist"><ul type="disc"><li><p>Rules execute by matching against data inserted into the engine.</p></li><li><p>Rules can never be called directly.</p></li><li><p>Specific instances cannot be passed to a rule.</p></li></ul></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e188"></a>Cross Products</h3></div></div></div><p>Earlier the term "cross product" was mentioned, which is the result of a join. Imagine
- for a moment when using the previous data the following rules where used, with no field
- constraints:</p><pre class="programlisting">rule
-when
- $room : Room()
- $sprinkler : Sprinkler()
-then
- System.out.println( "room:" + $room.getName() + " sprinkler:" + $sprinkler.getRoom().getName() );
-end</pre><p>In SQL terms this would be like doing "select * from Room, Sprinkler" and every row in
- the Room table would be joined with every row in the Sprinkler table resulting in the
- following output:</p><pre class="programlisting">room:office sprinker:office
-room:office sprinker:kitchen
-room:office sprinker:livingroom
-room:office sprinker:bedroom
-room:kitchen sprinker:office
-room:kitchen sprinker:kitchen
-room:kitchen sprinker:livingroom
-room:kitchen sprinker:bedroom
-room:livingroom sprinker:office
-room:livingroom sprinker:kitchen
-room:livingroom sprinker:livingroom
-room:livingroom sprinker:bedroom
-room:bedroom sprinker:office
-room:bedroom sprinker:kitchen
-room:bedroom sprinker:livingroom
-room:bedroom sprinker:bedroom</pre><p>These cross products can obviously become huge as well as returning potentially
- incorrect data. The size of cross products is often source of performance problems for new
- rule authors. From this it can be seen that it's always desirable to constrain the cross
- products, which is done with the variable constriant.</p><pre class="programlisting">rule
-when
- $room : Room()
- $sprinkler : Sprinkler( room == $room )
-then
- System.out.println( "room:" + $room.getName() + " sprinkler:" + $sprinkler.getRoom().getName() );
-end</pre><p>Resulting in just for rows of data, with the correct Sprinkler for the Room. In SQL
- (actually HQL) terms that is like "select * from Room, Sprinkler where Room ==
- Sprinkler.room"</p><pre class="programlisting">room:office sprinker:office
-room:kitchen sprinker:kitchen
-room:livingroom sprinker:livingroom
-room:bedroom sprinker:bedroom</pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e207"></a>Execution Control</h3></div></div></div><p></p><pre class="programlisting">public class Cashflow {
- private Date date;
- private double amount;
- private int type;
- long accountNo;
- // getter and setter methods here
-}
-
-public class Account {
- private long accountNo;
- private double balance;
- // getter and setter methods here
-}
-
-public AccountPeriod {
- private Date start;
- private Dte end
- // getter and setter methods here
-}</pre><p>By now you already know how to create KnowledgeBases and how to instantiate facts to
- populate the StatefulKnowledgeSession, so tables will be used to show the state of the
- inserted data, as it makes things clearer for illustration purposes. The tables below show a
- single fact was inserted for the Account and a series of debit's and credit's as Cashflows
- over two quarters for that Account were inserted.</p><table border="0" id="d0e215"><tbody><tr>
- <td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse" id="d0e221"><thead><tr>
- <th colspan="2" align="left" valign="top">Account</th>
- </tr><tr align="center">
- <th>accountNo</th>
- <th>balance</th>
- </tr></thead><tbody><tr>
- <td>1</td>
- <td>0</td>
- </tr></tbody></table>
- </td>
- <td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse" id="d0e249"><thead><tr>
- <th colspan="4" align="left">Cashflow</th>
- </tr><tr align="center">
- <th>date</th>
- <th>amount</th>
- <th>type</th>
- <th>accountNo</th>
- </tr></thead><tbody><tr>
- <td>12-jan-09</td>
- <td>100</td>
- <td>CREDIT</td>
- <td>1</td>
- </tr><tr>
- <td>2-feb-09</td>
- <td>200</td>
- <td>DEBIT</td>
- <td>1</td>
- </tr><tr>
- <td>18-may-09</td>
- <td>50</td>
- <td>CREDIT</td>
- <td>1</td>
- </tr><tr>
- <td>09-mar-09</td>
- <td>75</td>
- <td>CREDIT</td>
- <td>1</td>
- </tr></tbody></table>
- </td>
- </tr></tbody></table><p>Two rules can be used to determine the debit and credit for that quarter and update the
- Account balance. The two rules below constraint the Cashflows for an Account for a given
- time period. Notice the "&&" which use short cut syntax to avoid repeating the field
- name twice.</p><table frame="void"><tbody><tr>
- <td align="left" valign="top">
- <pre class="programlisting">rule “increase balance for AccountPeriod Credits”
-when
- ap : AccountPeriod()
- acc : Account( $accountNo : accountNo )
- CashFlow( type == CREDIT,
- accountNo == $accountNo,
- date >= ap.start && <= ap.end,
- $ammount : ammount )
-then
- acc.balance += $amount;
-end</pre>
- </td>
- <td align="left" valign="top">
- <pre class="programlisting">rule “decrease balance for AccountPeriod Debits”
-when
- ap : AccountPeriod()
- acc : Account( $accountNo : accountNo )
- CashFlow( type == DEBIT,
- accountNo == $accountNo,
- date >= ap.start && <= ap.end,
- $ammount : ammount )
-then
- acc.balance -= $amount;
-end</pre>
- </td>
- </tr></tbody></table><p>If the AccountPeriod is set to the first quarter we constraint the “increase balance for
- AccountPeriod Credits” to two rows of data and “decrease balance for AccountPeriod Debits”
- to one row of data.</p><table border="0px" id="d0e349"><tbody><tr>
- <td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse" id="d0e355"><thead><tr>
- <th colspan="2" align="left">AccountPeriod</th>
- </tr><tr align="center">
- <th>start</th>
- <th>end</th>
- </tr></thead><tbody><tr>
- <td>01-jan-09</td>
- <td>31-mar-09</td>
- </tr></tbody></table>
- </td>
- </tr></tbody></table><table border="0px" id="d0e381"><tbody><tr>
- <td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse" id="d0e387"><thead><tr>
- <th colspan="3" align="left">Cashflow</th>
- </tr><tr align="center">
- <th>date</th>
- <th>amount</th>
- <th>type</th>
- </tr></thead><tbody><tr>
- <td>12-jan-09</td>
- <td>100</td>
- <td>CREDIT</td>
- </tr><tr>
- <td>09-mar-09</td>
- <td>75</td>
- <td>CREDIT</td>
- </tr></tbody></table>
- </td>
- <td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse" id="d0e432"><thead><tr>
- <th colspan="3" align="left">Cashflow</th>
- </tr><tr align="center">
- <th>date</th>
- <th>amount</th>
- <th>type</th>
- </tr></thead><tbody><tr>
- <td>02-feb-09</td>
- <td>200</td>
- <td>DEBIT</td>
- </tr></tbody></table>
- </td>
- </tr></tbody></table><p>The two Cashflow tables above represent the matched data for the two rules, the data is
- matched during the insertion stage and as you found in the previous chapter does not fire
- straight away, until fireAllRules() is called. Intstead the rule plus it's matched data is
- placed on the Agenda and referred to as an Activation. The Agenda is a table of Activations
- that are able to fire and have their consequences executed, when fireAllRules() is called.
- Each of the Activations on the Agneda are executed in turn. Notice that the order of
- execution so far is considered arbitrary.</p><table border="0px" id="d0e466"><tbody><tr>
- <td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse" id="d0e472"><thead><tr>
- <th colspan="3" align="left">Agenda</th>
- </tr></thead><tbody><tr>
- <td>1</td>
- <td>increase balance</td>
- <td rowspan="3">arbitrary</td>
- </tr><tr>
- <td>2</td>
- <td>decrease balance</td>
- </tr><tr>
- <td>3</td>
- <td>increase balance</td>
- </tr></tbody></table>
- </td>
- </tr></tbody></table><p>After each of the above activations are fired, the Account has a balance of -25.</p><table border="0px" id="d0e511"><tbody><tr>
- <td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse" id="d0e517"><thead><tr>
- <th colspan="2" align="left">Account</th>
- </tr><tr align="center">
- <th>accountNo</th>
- <th>balance</th>
- </tr></thead><tbody><tr>
- <td>1</td>
- <td>-25</td>
- </tr></tbody></table>
- </td>
- </tr></tbody></table><p>If the AccountPeriod is updated to Q2, we have just a single matched row of data, and
- thus just a single Activation on the Agenda.</p><table border="0px" id="d0e545"><tbody><tr>
- <td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse" id="d0e551"><thead><tr>
- <th colspan="2" align="left">AccountPeriod</th>
- </tr><tr align="center">
- <th>start</th>
- <th>end</th>
- </tr></thead><tbody><tr>
- <td>01-apr-09</td>
- <td>30-jun-09</td>
- </tr></tbody></table>
- </td>
- </tr></tbody></table><table border="0px" id="d0e577"><tbody><tr>
- <td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse" id="d0e583"><thead><tr>
- <th colspan="3" align="left">Cashflow</th>
- </tr><tr align="center">
- <th>date</th>
- <th>amount</th>
- <th>type</th>
- </tr></thead><tbody><tr>
- <td>18-may-09</td>
- <td>50</td>
- <td>CREDIT</td>
- </tr></tbody></table>
- </td>
- <td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse" id="d0e617"><thead><tr>
- <th colspan="3" align="left">Cashflow</th>
- </tr><tr align="center">
- <th>date</th>
- <th>amount</th>
- <th>type</th>
- </tr></thead><tbody><tr>
- <td></td>
- <td></td>
- <td></td>
- </tr></tbody></table>
- </td>
- </tr></tbody></table><p>The firing of that Activation results in a balance of 50.</p><table border="0px" id="d0e648"><tbody><tr>
- <td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse" id="d0e654"><thead><tr>
- <th colspan="2" align="left">Account</th>
- </tr><tr align="center">
- <th>accountNo</th>
- <th>balance</th>
- </tr></thead><tbody><tr>
- <td>1</td>
- <td>50</td>
- </tr></tbody></table>
- </td>
- </tr></tbody></table><p>So what happens if you don't want the order of Activation execution to be arbitrary?
- When there is one or more Activations on the Agenda they are said to be in conflict, and a
- conflict resolver strategy is used to determine the order of execution. At the simplest
- level the default strategy uses salience to determine rule priority. Each rule has a default
- value of 0, the higher the value the higher the priority. To illustrate this a rule to print
- the Account balance can be added, we want this rule to be executed after all the debit's and
- credit's have been applied for this rule, by setting the rule to have a salience of below 0
- we ensure it fires afterwards.</p><table border="0px" id="d0e682"><tbody><tr>
- <td>
- <pre class="programlisting">rule “Print blance for AccountPeriod”
- salience -50
- when
- ap : AccountPeriod()
- acc : Account( )
- then
- System.out.println( acc.accountNo + “ : “ acc.balance );
-end</pre>
- </td>
- </tr></tbody></table><p>The table below shows the resulting Agenda, the 3 debit and credit rules are shown to be
- arbitrary order, while the print rule is shown to execute aftwards.</p><table border="0px" id="d0e694"><tbody><tr>
- <td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse" id="d0e700"><thead><tr>
- <th colspan="3" align="left">Agenda</th>
- </tr></thead><tbody><tr>
- <td>1</td>
- <td>increase balance</td>
- <td rowspan="3">arbitrary</td>
- </tr><tr>
- <td>2</td>
- <td>decrease balance</td>
- </tr><tr>
- <td>3</td>
- <td>increase balance</td>
- </tr><tr>
- <td>4</td>
- <td>print balance</td>
- <td></td>
- </tr></tbody></table>
- </td>
- </tr></tbody></table><p>Earlier we showed how rules would equate to SQL, which can often be helpful for people
- with an SQL background when understanding rules. The two ruels above can be represented with
- two views and a trigger for each view, as below:</p><table border="0px" id="d0e749"><tbody><tr>
- <td align="left" valign="top">
- <pre class="programlisting">select * from Account acc, Cashflow cf, AccountPeriod ap
-where acc.accountNo == cf.accountNo and
- cf.type == CREDIT cf.date >= ap.start and
- cf.date <= ap.end</pre>
- </td>
- <td align="left" valign="top">
- <pre class="programlisting">select * from Account acc, Cashflow cf, AccountPeriod ap
-where acc.accountNo == cf.accountNo and
- cf.type == DEBIT cf.date >= ap.start and
- cf.date <= ap.end</pre>
- </td>
- </tr><tr>
- <td align="left" valign="top">
- <pre class="programlisting">trigger : acc.balance += cf.amount</pre>
- </td>
- <td align="left" valign="top">
- <pre class="programlisting">trigger : acc.balance -= cf.amount</pre>
- </td>
- </tr></tbody></table><p>Drools also features ruleflow-group attributes which allows workflow diagrams to
- declaratively specify when rules are allowed to fire. The screenshot below is taken from
- Eclipse using the Drools plugin. It has two ruleflow-group nodes that ensures the
- calculation rules are executed before the reporting rules.</p><div class="mediaobject"><img src="images/Chapter-Quick_Start/ruleflow.png"></div><p>The use of the ruleflow-group attribute in a rule is shown below.</p><table border="0px" id="d0e786"><tbody><tr>
- <td align="left" valign="top">
- <pre class="programlisting">rule “increase balance for AccountPeriod Credits”
- ruleflow-group “calculation”
-when
- ap : AccountPeriod()
- acc : Account( $accountNo : accountNo )
- CashFlow( type == CREDIT,
- accountNo == $accountNo,
- date >= ap.start && <= ap.end,
- $ammount : ammount )
-then
- acc.balance += $amount;
-end</pre>
- </td>
- <td align="left" valign="top">
- <pre class="programlisting">rule “Print blance for AccountPeriod”
- ruleflow-group “report”
- when
- ap : AccountPeriod()
- acc : Account( )
- then
- System.out.println( acc.accountNo + “ : “ acc.balance );
-end</pre>
- </td>
- </tr></tbody></table></div></div></div></body></html>
\ No newline at end of file
More information about the jboss-svn-commits
mailing list