[jboss-svn-commits] JBL Code SVN: r25781 - in labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook: en-US/Chapter-Quick_Start and 2 other directories.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Mon Mar 23 04:15:27 EDT 2009
Author: mark.proctor at jboss.com
Date: 2009-03-23 04:15:27 -0400 (Mon, 23 Mar 2009)
New Revision: 25781
Added:
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/
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.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Section-The_Basics.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/images/Chapter-Quick_Start/
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/images/Chapter-Quick_Start/Tables.png
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/images/Chapter-Quick_Start/Tables.svg
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/images/Chapter-Quick_Start/Tables.vsd
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/images/Chapter-Quick_Start/ruleflow.png
Modified:
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/master.xml
Log:
added quick start guide
Added: 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 (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Chapter-Quick_Start.html 2009-03-23 08:15:27 UTC (rev 25781)
@@ -0,0 +1,591 @@
+<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="#d0e187">Cross Products</a></span></dt><dt><span class="section"><a href="#d0e206">XXXX</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, form 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” );
+ }
+}<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><pre class="programlisting">rule “Hello World”
+ when
+ Person( name == “Chuck” )
+ then
+ System.out.println( “Hello Chuck” );
+end<div class="itemizedlist"><ul type="disc"><li><p>Rules execute by matching against data inserted into the engine.</p></li><li>Rules can never be called directly.</li><li><p>Specific instances cannot be passed to a rule.</p></li></ul></div></pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e187"></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="d0e206"></a>XXXX</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 frame="void"><tbody><tr>
+ <td>
+ <table frame="box" rules="all"><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>0</td>
+ </tr></tbody></table>
+ </td>
+ <td>
+ <table frame="box" rules="all"><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 style="background-color:#ffcc99">
+ <td>12-jan-09</td>
+ <td>100</td>
+ <td>CREDIT</td>
+ <td>1</td>
+ </tr><tr style="background-color:#ccccff">
+ <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 style="background-color:#ffcc99">
+ <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>
+ <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>
+ <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 frame="void"><tbody><tr>
+ <td>
+ <table frame="box" rules="all"><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 frame="void"><tbody><tr>
+ <td>
+ <table frame="box" rules="all"><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 style="background-color:#ffcc99">
+ <td>12-jan-09</td>
+ <td>100</td>
+ <td>CREDIT</td>
+ </tr><tr style="background-color:#ffcc99">
+ <td>09-mar-09</td>
+ <td>75</td>
+ <td>CREDIT</td>
+ </tr></tbody></table>
+ </td>
+ <td>
+ <table frame="box" rules="all"><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 style="background-color:#ccccff">
+ <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 frame="void"><tbody><tr>
+ <td>
+ <table frame="box" rules="all"><thead><tr>
+ <th colspan="3" align="left">Agenda</th>
+ </tr></thead><tbody><tr style="background-color:#ffcc99">
+ <td>1</td>
+ <td>increase balance</td>
+ <td rowspan="3">arbitrary</td>
+ </tr><tr style="background-color:#ffcc99">
+ <td>2</td>
+ <td>decrease balance</td>
+ </tr><tr style="background-color:#ffcc99">
+ <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 frame="void"><tbody><tr>
+ <td>
+ <table frame="box" rules="all"><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 frame="void"><tbody><tr>
+ <td>
+ <table frame="box" rules="all"><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 frame="void"><tbody><tr>
+ <td>
+ <table frame="box" rules="all"><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 style="background-color:#ffcc99">
+ <td>18-may-09</td>
+ <td>50</td>
+ <td>CREDIT</td>
+ </tr></tbody></table>
+ </td>
+ <td>
+ <table frame="box" rules="all"><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></tbody></table>
+ </td>
+ </tr></tbody></table><p>The firing of that Activation results in a balance of
+ 50.</p><table frame="void"><tbody><tr>
+ <td>
+ <table frame="box" rules="all"><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 frame="void"><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 frame="void"><tbody><tr>
+ <td>
+ <table frame="box" rules="all"><thead><tr>
+ <th colspan="3" align="left">Agenda</th>
+ </tr></thead><tbody><tr style="background-color:#ffcc99">
+ <td>1</td>
+ <td>increase balance</td>
+ <td rowspan="3">arbitrary</td>
+ </tr><tr style="background-color:#ffcc99">
+ <td>2</td>
+ <td>decrease balance</td>
+ </tr><tr style="background-color:#ffcc99">
+ <td>3</td>
+ <td>increase balance</td>
+ </tr><tr style="background-color:#ccccff">
+ <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 frame="void"><tbody><tr>
+ <td>
+ <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>
+ <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>
+ <pre class="programlisting">trigger : acc.balance += cf.amount</pre>
+ </td>
+ <td>
+ <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><span class="inlinemediaobject"><img src="images/Chapter-Quick_Start/ruleflow.png"></span><table frame="void">The use of the ruleflow-group attribute in a rule is shown below.<tbody><tr>
+ <td>
+ <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>
+ <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
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Chapter-Quick_Start.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Chapter-Quick_Start.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Chapter-Quick_Start.xml 2009-03-23 08:15:27 UTC (rev 25781)
@@ -0,0 +1,894 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter version="5.0" xmlns="http://docbook.org/ns/docbook"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:svg="http://www.w3.org/2000/svg" xmlns:m="http://www.w3.org/1998/Math/MathML"
+ xmlns:html="http://www.w3.org/1999/xhtml" xml:base="./">
+ <title>Quick Start</title>
+ <section>
+ <title>The Basics</title>
+ <section>
+ <title>Stateless Knowledge Session</title>
+ <para>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.</para>
+ <para>Stateless session, not utilising inference, form 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:</para>
+ <itemizedlist>
+ <listitem>
+ <para>Validation</para>
+ <itemizedlist>
+ <listitem>
+ <para>Is this person legible for a mortgage</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>Calculation</para>
+ <itemizedlist>
+ <listitem>
+ <para>Mortgage premium</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>Routing/Filtering</para>
+ <itemizedlist>
+ <listitem>
+ <para>Filtering incoming messages, such as emails, into folders</para>
+ </listitem>
+ <listitem>
+ <para>Sending incoming message to a destinatino</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ <para>So lets start with a very simple example using a driving license application.</para>
+ <programlisting>public class Applicant {
+ private String name;
+ private int age;
+ private boolean valid;
+ // getter and setter methods here
+}
+</programlisting>
+ <para>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.</para>
+ <programlisting>package com.company.license
+
+rule "Is of valid age"
+when
+ $a : Applicant( age < 18 )
+then
+ $a.setValid( false );
+end</programlisting>
+ <para>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.</para>
+ <para>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.</para>
+ <programlisting>KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+kbuilder.add( ResourceFactory.newClasspathResource( "licenseApplication.drl", getClass() ),
+ ResourceType.DRL );
+if ( kbuilder.hasErrors() ) {
+ System.err.println( builder.getErrors().toString() );
+} </programlisting>
+ <para>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:</para>
+ <programlisting>StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
+Applicant applicant = new Applicant( "Mr John Smith", 16 );
+assertTrue( applicant.isValid() );
+ksession.execute( applicant );
+assertFalse( applicant.isValid() );
+</programlisting>
+ <para>The above executes the data against the rules, the applicant is under the age of 18, so
+ it marked invalid.</para>
+ <para>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.</para>
+ <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
+}</programlisting>
+ <para>And we can also add another rule, that validates the Application was made within a
+ period of time.</para>
+ <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
+</programlisting>
+ <para>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.</para>
+ <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() );
+</programlisting>
+ <para>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.</para>
+ </section>
+ <section>
+ <title>Stateful Knowledge Session</title>
+ <para>Stateful sessions are longer lived and allow iterative changes over time. Some common
+ use cases for stateful sessions are, but not limited to:</para>
+ <itemizedlist>
+ <listitem>
+ <para>Monitoring</para>
+ <itemizedlist>
+ <listitem>
+ <para>Stock market monitorig and analysis for semi-automatic buying.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>Diagnostics</para>
+ <itemizedlist>
+ <listitem>
+ <para>fault finding, medical diagnostics</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>Logistics</para>
+ <itemizedlist>
+ <listitem>
+ <para>parcel tracking and delivery provisioning</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>Compliance</para>
+ <itemizedlist>
+ <listitem>
+ <para>Validation of legality for market trades.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ <para>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.</para>
+ <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 {
+}
+</programlisting>
+ <para>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.</para>
+ <para>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</para>
+ <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</programlisting>
+ <para>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.</para>
+ <para>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.</para>
+ <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</programlisting>
+ <para>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.</para>
+ <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</programlisting>
+ <para>Likewise when there are no Fires we want to remove the alarm, so the 'not' keyword can
+ be used again.</para>
+ <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
+
+</programlisting>
+ <para>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.</para>
+ <programlisting>rule "Status output when things are ok"
+when
+ not Alarm()
+ not Sprinkler( on === true )
+then
+ System.out.println( "Everything is ok" );
+end</programlisting>
+ <para>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.</para>
+ <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();</programlisting>
+ <para>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.</para>
+ <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()
+</programlisting>
+ <programlisting>> Everything is ok</programlisting>
+ <para>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.</para>
+ <programlisting>Fire kitchenFire = new Fire( kitchen );
+Fire officeFire = new Fire( office );
+
+FactHandle kitchenFireHandle = kession.insert( kitchenFire );
+FactHandle officeFireHandle = ksession.insert( officeFire );
+
+ksession.fireAllRules();</programlisting>
+ <programlisting>> Raise the alarm
+> Turn on the sprinkler for room kitchen
+> Turn on the sprinkler for room office</programlisting>
+ <para>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.</para>
+ <programlisting>ksession.retract( kitchenFire );
+ksession.retract( officeFire );
+
+ksession.fireAllRules();</programlisting>
+ <programlisting>> Turn on the sprinkler for room office
+> Turn on the sprinkler for room kitchen
+> Lower the alarm
+> Everything is ok</programlisting>
+ <para>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.</para>
+ </section>
+ </section>
+ <section>
+ <title>A Little Theory</title>
+ <section>
+ <title>Methods versus Rules</title>
+ <para>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.</para>
+ <programlisting>public void helloWorld(Person person) {
+ if ( person.getName().equals( “Chuck” ) ) {
+ System.out.println( “Hello Chuck” );
+ }
+}<itemizedlist><listitem><para>Methods are called directly.</para></listitem><listitem><para>Specific instances are passed.</para></listitem></itemizedlist></programlisting>
+ <programlisting>rule “Hello World”
+ when
+ Person( name == “Chuck” )
+ then
+ System.out.println( “Hello Chuck” );
+end<itemizedlist><listitem><para>Rules execute by matching against data inserted into the engine.</para></listitem><listitem>Rules can never be called directly.</listitem><listitem><para>Specific instances cannot be passed to a rule.</para></listitem></itemizedlist></programlisting>
+ </section>
+ <section>
+ <title>Cross Products</title>
+ <para>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:</para>
+ <programlisting>rule
+when
+ $room : Room()
+ $sprinkler : Sprinkler()
+then
+ System.out.println( "room:" + $room.getName() + " sprinkler:" + $sprinkler.getRoom().getName() );
+end</programlisting>
+ <para>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:</para>
+ <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</programlisting>
+ <para>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.</para>
+ <programlisting>rule
+when
+ $room : Room()
+ $sprinkler : Sprinkler( room == $room )
+then
+ System.out.println( "room:" + $room.getName() + " sprinkler:" + $sprinkler.getRoom().getName() );
+end</programlisting>
+ <para>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"</para>
+ <programlisting>room:office sprinker:office
+room:kitchen sprinker:kitchen
+room:livingroom sprinker:livingroom
+room:bedroom sprinker:bedroom</programlisting>
+ </section>
+ <section><title>XXXX</title><para/><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
+}</programlisting><para>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.</para><informaltable frame="void">
+ <tbody>
+ <tr>
+ <td>
+ <informaltable frame="box" rules="all">
+ <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>0</td>
+ </tr>
+ </tbody>
+ </informaltable>
+ </td>
+ <td>
+ <informaltable frame="box" rules="all">
+ <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 style="background-color:#ffcc99">
+ <td>12-jan-09</td>
+ <td>100</td>
+ <td>CREDIT</td>
+ <td>1</td>
+ </tr>
+ <tr style="background-color:#ccccff">
+ <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 style="background-color:#ffcc99">
+ <td>09-mar-09</td>
+ <td>75</td>
+ <td>CREDIT</td>
+ <td>1</td>
+ </tr>
+ </tbody>
+ </informaltable>
+ </td>
+ </tr>
+ </tbody>
+ </informaltable><para>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.</para><informaltable frame="void">
+ <tbody>
+ <tr>
+ <td>
+ <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</programlisting>
+ </td>
+ <td>
+ <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</programlisting>
+ </td>
+ </tr>
+ </tbody>
+ </informaltable><para>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.</para><informaltable frame="void">
+ <tbody>
+ <tr>
+ <td>
+ <informaltable frame="box" rules="all">
+ <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>
+ </informaltable>
+ </td>
+ </tr>
+ </tbody>
+ </informaltable><informaltable frame="void">
+ <tbody>
+ <tr>
+ <td>
+ <informaltable frame="box" rules="all">
+ <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 style="background-color:#ffcc99">
+ <td>12-jan-09</td>
+ <td>100</td>
+ <td>CREDIT</td>
+ </tr>
+ <tr style="background-color:#ffcc99">
+ <td>09-mar-09</td>
+ <td>75</td>
+ <td>CREDIT</td>
+ </tr>
+ </tbody>
+ </informaltable>
+ </td>
+ <td>
+ <informaltable frame="box" rules="all">
+ <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 style="background-color:#ccccff">
+ <td>02-feb-09</td>
+ <td>200</td>
+ <td>DEBIT</td>
+ </tr>
+ </tbody>
+ </informaltable>
+ </td>
+ </tr>
+ </tbody>
+ </informaltable><para>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.</para><informaltable
+ frame="void">
+ <tbody>
+ <tr>
+ <td>
+ <informaltable frame="box" rules="all">
+ <thead>
+ <tr>
+ <th colspan="3" align="left">Agenda</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr style="background-color:#ffcc99">
+ <td>1</td>
+ <td>increase balance</td>
+ <td rowspan="3">arbitrary</td>
+ </tr>
+ <tr style="background-color:#ffcc99">
+ <td>2</td>
+ <td>decrease balance</td>
+ </tr>
+ <tr style="background-color:#ffcc99">
+ <td>3</td>
+ <td>increase balance</td>
+ </tr>
+ </tbody>
+ </informaltable>
+ </td>
+ </tr>
+ </tbody>
+ </informaltable><para>After each of the above activations are fired, the Account has a balance
+ of -25.</para><informaltable frame="void">
+ <tbody>
+ <tr>
+ <td>
+ <informaltable frame="box" rules="all">
+ <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>
+ </informaltable>
+ </td>
+ </tr>
+ </tbody>
+ </informaltable><para>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.</para><informaltable frame="void">
+ <tbody>
+ <tr>
+ <td>
+ <informaltable frame="box" rules="all">
+ <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>
+ </informaltable>
+ </td>
+ </tr>
+ </tbody>
+ </informaltable><informaltable frame="void">
+ <tbody>
+ <tr>
+ <td>
+ <informaltable frame="box" rules="all">
+ <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 style="background-color:#ffcc99">
+ <td>18-may-09</td>
+ <td>50</td>
+ <td>CREDIT</td>
+ </tr>
+ </tbody>
+ </informaltable>
+ </td>
+ <td>
+ <informaltable frame="box" rules="all">
+ <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>
+ </informaltable>
+ </td>
+ </tr>
+ </tbody>
+ </informaltable><para>The firing of that Activation results in a balance of
+ 50.</para><informaltable frame="void">
+ <tbody>
+ <tr>
+ <td>
+ <informaltable frame="box" rules="all">
+ <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>
+ </informaltable>
+ </td>
+ </tr>
+ </tbody>
+ </informaltable><para>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.</para><informaltable frame="void">
+ <tbody>
+ <tr>
+ <td>
+ <programlisting>rule “Print blance for AccountPeriod”
+ salience -50
+ when
+ ap : AccountPeriod()
+ acc : Account( )
+ then
+ System.out.println( acc.accountNo + “ : “ acc.balance );
+end</programlisting>
+ </td>
+ </tr>
+ </tbody>
+ </informaltable><para>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.</para><informaltable frame="void">
+ <tbody>
+ <tr>
+ <td>
+ <informaltable frame="box" rules="all">
+ <thead>
+ <tr>
+ <th colspan="3" align="left">Agenda</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr style="background-color:#ffcc99">
+ <td>1</td>
+ <td>increase balance</td>
+ <td rowspan="3">arbitrary</td>
+ </tr>
+ <tr style="background-color:#ffcc99">
+ <td>2</td>
+ <td>decrease balance</td>
+ </tr>
+ <tr style="background-color:#ffcc99">
+ <td>3</td>
+ <td>increase balance</td>
+ </tr>
+ <tr style="background-color:#ccccff">
+ <td>4</td>
+ <td>print balance</td>
+ <td/>
+ </tr>
+ </tbody>
+ </informaltable>
+ </td>
+ </tr>
+ </tbody>
+ </informaltable><para>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:</para><informaltable
+ frame="void">
+ <tbody>
+ <tr>
+ <td>
+ <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</programlisting>
+ </td>
+ <td>
+ <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</programlisting>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <programlisting>trigger : acc.balance += cf.amount</programlisting>
+ </td>
+ <td>
+ <programlisting>trigger : acc.balance -= cf.amount</programlisting>
+ </td>
+ </tr>
+ </tbody>
+ </informaltable><para>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.</para><mediaobject><imageobject><imagedata
+ fileref="images/Chapter-Quick_Start/ruleflow.png"
+ /></imageobject></mediaobject>
+ <para>The use of the ruleflow-group attribute in a rule is shown below.</para>
+ <informaltable frame="void">
+ <tbody>
+ <tr>
+ <td>
+ <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</programlisting>
+ </td>
+ <td>
+ <programlisting>rule “Print blance for AccountPeriod”
+ ruleflow-group “report”
+ when
+ ap : AccountPeriod()
+ acc : Account( )
+ then
+ System.out.println( acc.accountNo + “ : “ acc.balance );
+end</programlisting>
+ </td>
+ </tr>
+ </tbody>
+ </informaltable></section>
+ </section>
+</chapter>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Section-The_Basics.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Section-The_Basics.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Section-The_Basics.xml 2009-03-23 08:15:27 UTC (rev 25781)
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD Simplified DocBook XML V1.0//EN"
+"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd">
+<section>
+ <title>The Basics</title>
+</section>
\ No newline at end of file
Modified: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/master.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/master.xml 2009-03-23 06:53:48 UTC (rev 25780)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/master.xml 2009-03-23 08:15:27 UTC (rev 25781)
@@ -38,21 +38,7 @@
</imageobject> </mediaobject> <para /> </preface>
-->
- <xi:include href="Acknowledgements.xml" />
-
- <xi:include href="Chapter-Rule_Engine/Chapter-Rule_Engine.xml" />
+ <xi:include href="Chapter-Quick_Start/Chapter-Quick_Start.xml" />
- <xi:include href="Chapter-Decision_Tables/Chapter-Spreadsheet.xml" />
-
- <xi:include href="Chapter-IDE/Chapter-QuickStart.xml" />
-
- <xi:include href="Chapter-Deployment/Chapter-DepymentAndTest.xml" />
-
- <xi:include href="Chapter-JSR94/Chapter-JSR94.xml" />
-
- <xi:include href="Chapter-Rule_Language/Chapter-RuleLanguage.xml" />
-
- <xi:include href="Chapter-Examples/Chapter-Examples.xml" />
-
- <index />
+ <!--index /-->
</book>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/images/Chapter-Quick_Start/Tables.png
===================================================================
(Binary files differ)
Property changes on: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/images/Chapter-Quick_Start/Tables.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/images/Chapter-Quick_Start/Tables.svg
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/images/Chapter-Quick_Start/Tables.svg (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/images/Chapter-Quick_Start/Tables.svg 2009-03-23 08:15:27 UTC (rev 25781)
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Generated by Microsoft Visio 11.0, SVG Export, v1.0 Tables.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="5.84551in"
+ height="3.46457in" viewBox="0 0 420.877 249.449" xml:space="preserve" color-interpolation-filters="sRGB" class="st5">
+ <v:documentProperties v:langID="1033" v:metric="true" v:viewMarkup="false"/>
+
+ <style type="text/css">
+ <![CDATA[
+ .st1 {fill:#e8eef7;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+ .st2 {stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+ .st3 {stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+ .st4 {fill:#000000;font-family:Arial;font-size:1.5003em}
+ .st5 {fill:none;fill-rule:evenodd;font-size:12;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+ ]]>
+ </style>
+
+ <g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+ <title>Page-1</title>
+ <v:pageProperties v:drawingScale="0.0393701" v:pageScale="0.0393701" v:drawingUnits="24" v:shadowOffsetX="8.50394"
+ v:shadowOffsetY="-8.50394"/>
+ <g id="shape3-1" v:mID="3" v:groupContext="shape" transform="translate(226.772,-111.421)">
+ <title>Sheet.3</title>
+ <path d="M0 155.68 L0 249.45 L194.1 249.45 L194.1 155.68 L0 155.68 L0 155.68 Z" class="st1"/>
+ </g>
+ <g id="shape4-3" v:mID="4" v:groupContext="shape" transform="translate(226.772,-111.421)">
+ <title>Sheet.4</title>
+ <path d="M0 249.45 L194.1 249.45 L194.1 155.68 L0 155.68 L0 249.45" class="st2"/>
+ </g>
+ <g id="shape5-6" v:mID="5" v:groupContext="shape" transform="translate(234.266,-174.283)">
+ <title>Sheet.5</title>
+ <desc>Date date</desc>
+ <v:textBlock v:margins="rect(0,0,0,0)" v:tabSpace="42.5197"/>
+ <v:textRect cx="48.2003" cy="238.645" width="96.41" height="21.6079"/>
+ <path d="M96.4 227.84 L0 227.84 L0 249.45 L96.4 249.45 L96.4 227.84" class="st3"/>
+ <text x="9.16" y="244.05" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Date date</text> </g>
+ <g id="shape6-10" v:mID="6" v:groupContext="shape" transform="translate(234.266,-152.528)">
+ <title>Sheet.6</title>
+ <desc>double amount</desc>
+ <v:textBlock v:margins="rect(0,0,0,0)" v:tabSpace="42.5197"/>
+ <v:textRect cx="71.8006" cy="238.645" width="143.61" height="21.6079"/>
+ <path d="M143.6 227.84 L0 227.84 L0 249.45 L143.6 249.45 L143.6 227.84" class="st3"/>
+ <text x="12.24" y="244.05" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>double amount</text> </g>
+ <g id="shape7-14" v:mID="7" v:groupContext="shape" transform="translate(234.266,-130.774)">
+ <title>Sheet.7</title>
+ <desc>int type</desc>
+ <v:textBlock v:margins="rect(0,0,0,0)" v:tabSpace="42.5197"/>
+ <v:textRect cx="36.6859" cy="238.645" width="73.38" height="21.6079"/>
+ <path d="M73.37 227.84 L0 227.84 L0 249.45 L73.37 249.45 L73.37 227.84" class="st3"/>
+ <text x="12.65" y="244.05" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>int type</text> </g>
+ <g id="shape8-18" v:mID="8" v:groupContext="shape" transform="translate(234.266,-110.52)">
+ <title>Sheet.8</title>
+ <desc>long accountNo</desc>
+ <v:textBlock v:margins="rect(0,0,0,0)" v:tabSpace="42.5197"/>
+ <v:textRect cx="75.248" cy="238.645" width="150.5" height="21.6079"/>
+ <path d="M150.5 227.84 L0 227.84 L0 249.45 L150.5 249.45 L150.5 227.84" class="st3"/>
+ <text x="12.69" y="244.05" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>long accountNo</text> </g>
+ <g id="shape9-22" v:mID="9" v:groupContext="shape" transform="translate(226.772,-205.19)">
+ <title>Sheet.9</title>
+ <path d="M0 205.19 L0 249.45 L123.66 249.45 L123.66 205.19 L0 205.19 L0 205.19 Z" class="st1"/>
+ </g>
+ <g id="shape10-24" v:mID="10" v:groupContext="shape" transform="translate(226.772,-205.19)">
+ <title>Sheet.10</title>
+ <path d="M0 249.45 L123.66 249.45 L123.66 205.19 L0 205.19 L0 249.45" class="st2"/>
+ </g>
+ <g id="shape11-27" v:mID="11" v:groupContext="shape" transform="translate(254.501,-215.541)">
+ <title>Sheet.11</title>
+ <desc>Cashflow</desc>
+ <v:textBlock v:margins="rect(0,0,0,0)" v:tabSpace="42.5197"/>
+ <v:textRect cx="45.8852" cy="238.645" width="91.78" height="21.6079"/>
+ <path d="M91.77 227.84 L0 227.84 L0 249.45 L91.77 249.45 L91.77 227.84" class="st3"/>
+ <text x="8.85" y="244.05" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Cashflow</text> </g>
+ <g id="shape12-31" v:mID="12" v:groupContext="shape" transform="translate(0,-141.955)">
+ <title>Sheet.12</title>
+ <path d="M0 186.44 L0 249.45 L194.1 249.45 L194.1 186.44 L0 186.44 L0 186.44 Z" class="st1"/>
+ </g>
+ <g id="shape13-33" v:mID="13" v:groupContext="shape" transform="translate(0,-141.955)">
+ <title>Sheet.13</title>
+ <path d="M0 249.45 L194.1 249.45 L194.1 186.44 L0 186.44 L0 249.45" class="st2"/>
+ </g>
+ <g id="shape14-36" v:mID="14" v:groupContext="shape" transform="translate(8.99328,-172.56)">
+ <title>Sheet.14</title>
+ <desc>long accountNo</desc>
+ <v:textBlock v:margins="rect(0,0,0,0)" v:tabSpace="42.5197"/>
+ <v:textRect cx="75.248" cy="238.645" width="150.5" height="21.6079"/>
+ <path d="M150.5 227.84 L0 227.84 L0 249.45 L150.5 249.45 L150.5 227.84" class="st3"/>
+ <text x="12.69" y="244.05" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>long accountNo</text> </g>
+ <g id="shape15-40" v:mID="15" v:groupContext="shape" transform="translate(8.99328,-150.806)">
+ <title>Sheet.15</title>
+ <desc>double balance</desc>
+ <v:textBlock v:margins="rect(0,0,0,0)" v:tabSpace="42.5197"/>
+ <v:textRect cx="73.5344" cy="238.645" width="147.07" height="21.6079"/>
+ <path d="M147.07 227.84 L0 227.84 L0 249.45 L147.07 249.45 L147.07 227.84" class="st3"/>
+ <text x="12.46" y="244.05" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>double balance</text> </g>
+ <g id="shape16-44" v:mID="16" v:groupContext="shape" transform="translate(6.39488E-014,-204.967)">
+ <title>Sheet.16</title>
+ <path d="M0 205.19 L0 249.45 L123.66 249.45 L123.66 205.19 L0 205.19 L0 205.19 Z" class="st1"/>
+ </g>
+ <g id="shape17-46" v:mID="17" v:groupContext="shape" transform="translate(6.39488E-014,-204.967)">
+ <title>Sheet.17</title>
+ <path d="M0 249.45 L123.66 249.45 L123.66 205.19 L0 205.19 L0 249.45" class="st2"/>
+ </g>
+ <g id="shape18-49" v:mID="18" v:groupContext="shape" transform="translate(32.2259,-214.569)">
+ <title>Sheet.18</title>
+ <desc>Account</desc>
+ <v:textBlock v:margins="rect(0,0,0,0)" v:tabSpace="42.5197"/>
+ <v:textRect cx="40.7144" cy="238.645" width="81.43" height="21.6079"/>
+ <path d="M81.43 227.84 L0 227.84 L0 249.45 L81.43 249.45 L81.43 227.84" class="st3"/>
+ <text x="8.2" y="244.05" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Account</text> </g>
+ <g id="shape19-53" v:mID="19" v:groupContext="shape" transform="translate(1.48565,-2.84217E-014)">
+ <title>Sheet.19</title>
+ <path d="M0 186.44 L0 249.45 L194.1 249.45 L194.1 186.44 L0 186.44 L0 186.44 Z" class="st1"/>
+ </g>
+ <g id="shape20-55" v:mID="20" v:groupContext="shape" transform="translate(1.48565,-2.84217E-014)">
+ <title>Sheet.20</title>
+ <path d="M0 249.45 L194.1 249.45 L194.1 186.44 L0 186.44 L0 249.45" class="st2"/>
+ </g>
+ <g id="shape21-58" v:mID="21" v:groupContext="shape" transform="translate(8.98005,-31.3555)">
+ <title>Sheet.21</title>
+ <desc>Date start</desc>
+ <v:textBlock v:margins="rect(0,0,0,0)" v:tabSpace="42.5197"/>
+ <v:textRect cx="48.1853" cy="238.645" width="96.38" height="21.6079"/>
+ <path d="M96.37 227.84 L0 227.84 L0 249.45 L96.37 249.45 L96.37 227.84" class="st3"/>
+ <text x="0" y="244.05" class="st4" v:langID="1033"><v:paragraph/><v:tabList/>Date start</text> </g>
+ <g id="shape22-62" v:mID="22" v:groupContext="shape" transform="translate(8.98005,-9.60107)">
+ <title>Sheet.22</title>
+ <desc>Date end</desc>
+ <v:textBlock v:margins="rect(0,0,0,0)" v:tabSpace="42.5197"/>
+ <v:textRect cx="45.3241" cy="238.645" width="90.65" height="21.6079"/>
+ <path d="M90.65 227.84 L0 227.84 L0 249.45 L90.65 249.45 L90.65 227.84" class="st3"/>
+ <text x="0" y="244.05" class="st4" v:langID="1033"><v:paragraph/><v:tabList/>Date end</text> </g>
+ <g id="shape23-66" v:mID="23" v:groupContext="shape" transform="translate(1.48565,-63.0128)">
+ <title>Sheet.23</title>
+ <path d="M0 205.19 L0 249.45 L175.21 249.45 L175.21 205.19 L0 205.19 L0 205.19 Z" class="st1"/>
+ </g>
+ <g id="shape24-68" v:mID="24" v:groupContext="shape" transform="translate(1.48565,-63.0128)">
+ <title>Sheet.24</title>
+ <path d="M0 249.45 L175.21 249.45 L175.21 205.19 L0 205.19 L0 249.45" class="st2"/>
+ </g>
+ <g id="shape25-71" v:mID="25" v:groupContext="shape" transform="translate(13.4767,-72.6139)">
+ <title>Sheet.25</title>
+ <desc>AccountingPeriod</desc>
+ <v:textBlock v:margins="rect(0,0,0,0)" v:tabSpace="42.5197"/>
+ <v:textRect cx="84.4527" cy="238.645" width="168.91" height="21.6079"/>
+ <path d="M168.91 227.84 L0 227.84 L0 249.45 L168.91 249.45 L168.91 227.84" class="st3"/>
+ <text x="0" y="244.05" class="st4" v:langID="1033"><v:paragraph/><v:tabList/>AccountingPeriod</text> </g>
+ </g>
+</svg>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/images/Chapter-Quick_Start/Tables.vsd
===================================================================
(Binary files differ)
Property changes on: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/images/Chapter-Quick_Start/Tables.vsd
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/images/Chapter-Quick_Start/ruleflow.png
===================================================================
(Binary files differ)
Property changes on: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/images/Chapter-Quick_Start/ruleflow.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
More information about the jboss-svn-commits
mailing list