Tuesday 6 November 2007

Banking on Rules Part II

Creating a RuleFlow


In this example, we are going to create a simple RuleFlow and add it to our Banking example from Part I.

Paul Browne has already posted an excellent blog on this topic, which has a slightly more complicated example.

Caveat


This example is so simple, that it would actually be easier done with an Agenda-Group, but the purpose of this post is to demonstrate a very simple example of RuleFlow. I will post a more complicated one later on.

Pre-Requisites


In order to run this example you will need Eclipse with the latest Drools plug-in (Eclipse Workbench). Eclipse can be downloaded from http://www.eclipse.org/ and the Eclipse Workbench can be downloaded from http://labs.jboss.com/drools/downloads.html.

Step 1 - Creating the Rules


For those who have already downloaded the examples in Drools Part I, I am going to use that code as the starting point for this.

Our first task, is to create a rule and allocate it to a ruleflow-group so that we can use the RuleFlow to include and exclude
rules. To do this, copy rule07.drl to rule08.drl and rename the rules to be prefixed with "Rule 08" instead of "Rule 07". Now, add the ruleflow-group entries for "Rule 08 - Credit" and "Rule 08 - Debit":

rule08.drl

package simple;

import net.tplusplus.drools.bankingondrools1.*;

rule "Rule 08 - Credit"
    ruleflow-group "CreditGroup"
    salience 100
    when
        AccountingPeriod( $start : start, $end : end )
        $cashflow : AllocatedCashflow( $account : account, $date : date <= $end, $amount : amount, type==TypedCashflow.CREDIT )
        not AccountingPeriod( start < $start)
    then
        System.out.println("Credit: "+$date+" :: "+$amount);
        
        $account.setBalance($account.getBalance()+$amount);
        System.out.println("Account: "+$account.getAccountNo()+" - new balance: "+$account.getBalance());
            
        retract($cashflow);
end

rule "Rule 08 - Debit"
    ruleflow-group "DebitGroup"
    salience 100
    when
        AccountingPeriod( $start : start, $end : end )
        $cashflow : AllocatedCashflow( $account : account, $date : date <= $end, $amount : amount, type==TypedCashflow.DEBIT )
        not AccountingPeriod( start < $start)
    then
        System.out.println("Debit: "+$date+" :: "+$amount);
        
        $account.setBalance($account.getBalance()-$amount);
        System.out.println("Account: "+$account.getAccountNo()+" - new balance: "+$account.getBalance());
            
        retract($cashflow);
end

rule "Rule 08 - Retract Accounting Period"
    salience 50
    when
        $accountingPeriod : AccountingPeriod( $start : start, $end : end )
        not AccountingPeriod( start < $start)
    then
        System.out.println("Retracting Accounting Period: "+$start+" - "+$end);
        retract($accountingPeriod);
end

Open the class net.tplusplus.drools.bankingondrools1.RuleRunner and add the following method:

RuleRunner.java

    public static void simple8()
    throws Exception
    {
        Account acc1 = new Account(1);
        Account acc2 = new Account(2);
        
        Object[] facts =
        {
            new AllocatedCashflow(acc1,new SimpleDate("01/01/2007"), TypedCashflow.CREDIT, 300.00),
            new AllocatedCashflow(acc1,new SimpleDate("05/02/2007"), TypedCashflow.CREDIT, 100.00),
            new AllocatedCashflow(acc2,new SimpleDate("11/03/2007"), TypedCashflow.CREDIT, 500.00),
            new AllocatedCashflow(acc1,new SimpleDate("07/02/2007"), TypedCashflow.DEBIT, 800.00),
            new AllocatedCashflow(acc2,new SimpleDate("02/03/2007"), TypedCashflow.DEBIT, 400.00),
            new AllocatedCashflow(acc1,new SimpleDate("01/04/2007"), TypedCashflow.CREDIT, 200.00),
            new AllocatedCashflow(acc1,new SimpleDate("05/04/2007"), TypedCashflow.CREDIT, 300.00),
            new AllocatedCashflow(acc2,new SimpleDate("11/05/2007"), TypedCashflow.CREDIT, 700.00),
            new AllocatedCashflow(acc1,new SimpleDate("07/05/2007"), TypedCashflow.DEBIT, 900.00),
            new AllocatedCashflow(acc2,new SimpleDate("02/05/2007"), TypedCashflow.DEBIT, 100.00),
            
            new AccountingPeriod(new SimpleDate("01/01/2007"),new SimpleDate("31/03/2007")),
            new AccountingPeriod(new SimpleDate("01/04/2007"),new SimpleDate("30/06/2007"))
            
        };
        
        new RuleRunner().runRules(new String[]{"/simple/rule08.drl"},facts);        
    }


This gives us the ability to use a RuleFlow to include rule "Rule 08 - Credit" and not rule "Rule 08 - Debit" by specifying the ruleflow-group "CreditGroup", and vice versa by specifying the ruleflow-group "DebitGroup".

Now, modify the main method in RuleRunner to comment out calls to all the methods except rule08(). This will just tidy up the output, and exclude output from Banking On Drools - Part I:

RuleRunner.java

    public static void main(String[] args)
    throws Exception
    {
        //simple1();
        //simple2();
        //simple3();
        //simple4();
        //simple5();
        //simple6();
        //simple7();
        simple8();
    }


So far, all we have done is allocate two rules to RuleFlow groups. What happens if we run the code as it stands without introducing a RuleFlow?

Run the class RuleRunner, and we get the output:

output:

Loading file: /simple/rule08.drl
Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],
date=Mon Jan 01 00:00:00 GMT 2007,type=Credit,amount=300.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],
date=Mon Feb 05 00:00:00 GMT 2007,type=Credit,amount=100.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=2,balance=0.0],
date=Sun Mar 11 00:00:00 GMT 2007,type=Credit,amount=500.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],
date=Wed Feb 07 00:00:00 GMT 2007,type=Debit,amount=800.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=2,balance=0.0],
date=Fri Mar 02 00:00:00 GMT 2007,type=Debit,amount=400.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],
date=Sun Apr 01 00:00:00 BST 2007,type=Credit,amount=200.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],
date=Thu Apr 05 00:00:00 BST 2007,type=Credit,amount=300.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=2,balance=0.0],
date=Fri May 11 00:00:00 BST 2007,type=Credit,amount=700.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],
date=Mon May 07 00:00:00 BST 2007,type=Debit,amount=900.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=2,balance=0.0],
date=Wed May 02 00:00:00 BST 2007,type=Debit,amount=100.0]
Inserting fact: AccountingPeriod[start=Mon Jan 01 00:00:00 GMT 2007,
end=Sat Mar 31 00:00:00 BST 2007]
Inserting fact: AccountingPeriod[start=Sun Apr 01 00:00:00 BST 2007,
end=Sat Jun 30 00:00:00 BST 2007]
Retracting Accounting Period: Mon Jan 01 00:00:00 GMT 2007
- Sat Mar 31 00:00:00 BST 2007
Retracting Accounting Period: Sun Apr 01 00:00:00 BST 2007
- Sat Jun 30 00:00:00 BST 2007

From the output, we can see that neither the Credit Rule nor the Debit Rule ran.

So, if we allocate a Rule to a RuleFlow Group, then we need to find some way of specifying the RuleFlow Group to run if we are to include these rules.

Step 2 - Modifying the RuleRunner


Our next step is to modify the RuleRunner runRules() method to allow us to specify a all the RuleFlows for the rule engine, and the initial RuleFlow Group to use.

To do this we need to overload the RunRules() method in RuleRunner to provide the RuleFlows and the process to start, as follows:

RuleRunner.java

    public void runRules(String process, String[] ruleflows, String[] rules, Object... facts)
    throws Exception
    {        
        RuleBase ruleBase = RuleBaseFactory.newRuleBase();
        PackageBuilder builder = new PackageBuilder();        
        
        for(String ruleflow : ruleflows)
        {
            builder.addRuleFlow( new InputStreamReader(
                    RuleRunner.class.getResourceAsStream( ruleflow ) ) );
        }
        
        for(String ruleFile : rules)
        {
            System.out.println("Loading file: "+ruleFile);
            builder.addPackageFromDrl(new InputStreamReader(this.getClass().getResourceAsStream(ruleFile)));
        }
        
        Package pkg = builder.getPackage();        
        ruleBase.addPackage(pkg);
        
        WorkingMemory workingMemory = ruleBase.newStatefulSession();    

        for(Object fact : facts)
        {
            System.out.println("Inserting fact: "+fact);
            workingMemory.insert(fact);
        }

        workingMemory.startProcess(process);
        workingMemory.fireAllRules();
    }

Step 3 - Creating the RuleFlow


By now we have allocated two of our rules to RuleFlow Groups and have provided a runRules() method that allows us to specify RuleFlows and a starting RuleFlow Group. Now, we need to create the RuleFlow.

To do this we are going to use the Eclipse Workbench (for Drools).

Open the Drools perspective and first let's create a source folder for our ruleflows:

Create a new source folder called ruleflows:



In Package Explorer, right click on the new ruleFlow folder and select New -> Other. From the Wizard select RuleFlow File.



Click on Next, and enter the filename creditFlows



Click on finish and eclipse will open the creditFlows.rf document in the graphical editor as follows:



Our next step is to create a simple ruleFlow for processing credits only.

The editor pane already contains a Start element. Next, we need to place a RuleFlowGroup on the editor, by clicking on RuleFlowGroup element in the left pane and then clicking on the edit pane below the Start element.

Repeat the process with the End element and place them in the editor as shown below:



Now we need to create the connections between the elements. Click on the ConnectionCreation element in the left pane and click on the Start element in the editor pane. Move the cursor to the RuleSet element and click again. A connection will be created between the two elements.

Repeat the process to connect the RuleSet element to the End element. Your edit pane should now look like:



Ok. So far we have a rule flow diagram with a Start, RuleFlow, and End element connected. This is all pretty much meaningless, however, until we set the properties in the ruleflow so that it is associated with a ruleflow group.

We want this ruleflow to execute the Credit rule that we created earlier in rule08.drl

rule08.drl

rule "Rule 08 - Credit"
    ruleflow-group "CreditGroup"
    salience 100
    when
        AccountingPeriod( $start : start, $end : end )
        $cashflow : AllocatedCashflow( $account : account, $date : date <= $end, $amount : amount, type==TypedCashflow.CREDIT )
        not AccountingPeriod( start < $start)
    then
        System.out.println("Credit: "+$date+" :: "+$amount);
        
        $account.setBalance($account.getBalance()+$amount);
        System.out.println("Account: "+$account.getAccountNo()+" - new balance: "+$account.getBalance());
            
        retract($cashflow);
end

This means we need to set up our ruleflow to call the ruleflow-group "CreditGroup".

So, here we go:

Click on the RuleSet element in the editor pane and then click on the properties tab.

Set the Name to CreditFlow, and set the RuleFlowGroup to CreditGroup (same as the ruleflow-group in the rule above).

The screen shot is show below:



The name simply gives our element a display name that should be meaningful to us as we review the ruleflow diagram. The important property is the RuleFlowGroup which should be the same as the RuleFlowGroup of the rules that we want to include in this RuleFlow.

Finally, we need to set the properties for the CreditFlows ruleFlow itself. Click anywhere in the design screen to display the properties for the ruleFlow.

Set the properties as follows:

Connection Layout = Shortest Path
Id = credits
Name = creditFlows
Package = simple
Version = 1




The Id is the id by which we will indentify this ruleflow when we want to invoke it. To start this process we will call workingMemory.startProcess("credits"). The name is simply the name by which we want to identify this ruleflow. The package is the same package as that to which our rules belong (see rule08.drl), and the version is our latest version.

Specifying the RuleFlow to Run


Now let’s modify our simple8() method in RuleRunner to call our ruleflow.

    public static void simple8()
    throws Exception
    {
        Account acc1 = new Account(1);
        Account acc2 = new Account(2);
        
        Object[] facts =
        {
            new AllocatedCashflow(acc1,new SimpleDate("01/01/2007"), TypedCashflow.CREDIT, 300.00),
            new AllocatedCashflow(acc1,new SimpleDate("05/02/2007"), TypedCashflow.CREDIT, 100.00),
            new AllocatedCashflow(acc2,new SimpleDate("11/03/2007"), TypedCashflow.CREDIT, 500.00),
            new AllocatedCashflow(acc1,new SimpleDate("07/02/2007"), TypedCashflow.DEBIT, 800.00),
            new AllocatedCashflow(acc2,new SimpleDate("02/03/2007"), TypedCashflow.DEBIT, 400.00),
            new AllocatedCashflow(acc1,new SimpleDate("01/04/2007"), TypedCashflow.CREDIT, 200.00),
            new AllocatedCashflow(acc1,new SimpleDate("05/04/2007"), TypedCashflow.CREDIT, 300.00),
            new AllocatedCashflow(acc2,new SimpleDate("11/05/2007"), TypedCashflow.CREDIT, 700.00),
            new AllocatedCashflow(acc1,new SimpleDate("07/05/2007"), TypedCashflow.DEBIT, 900.00),
            new AllocatedCashflow(acc2,new SimpleDate("02/05/2007"), TypedCashflow.DEBIT, 100.00),
            
            new AccountingPeriod(new SimpleDate("01/01/2007"),new SimpleDate("31/03/2007")),
            new AccountingPeriod(new SimpleDate("01/04/2007"),new SimpleDate("30/06/2007"))
            
        };
        
        String[] ruleFiles = { "/simple/rule08.drl" };
        String[] ruleFlows = { "/creditFlows.rfm" };
        
        new RuleRunner().runRules("credits",ruleFlows,ruleFiles,facts);        
    }


Finally, let's compile the project and run it.

output:

Loading file: /simple/rule08.drl
...
Credit: Sun Mar 11 00:00:00 GMT 2007 :: 500.0
Account: 2 - new balance: 500.0
Credit: Mon Feb 05 00:00:00 GMT 2007 :: 100.0
Account: 1 - new balance: 100.0
Credit: Mon Jan 01 00:00:00 GMT 2007 :: 300.0
Account: 1 - new balance: 400.0
Retracting Accounting Period: Mon Jan 01 00:00:00 GMT 2007
- Sat Mar 31 00:00:00 BST 2007
Retracting Accounting Period: Sun Apr 01 00:00:00 BST 2007
- Sat Jun 30 00:00:00 BST 2007


Notice, now we have all the Credits being applied, but no Debits!!


36 comments:

Tanhausser said...

thnks for your post
I'm having a bad time, It doesn't work. It seems that the flow doesn't find the .drl.
The output on the console is empty, no runtime errors neither at compilation. Could anybody tell me how to solve it?
Thanks in advance.

lsilva said...

Hi, could you helpme with this problem? thanks you.

http://www.nabble.com/Can%27t-see-changes-made-in-another-agenda-group-p22612788.html

Anonymous said...

http://drools-java-rules-engine.46999.n3.nabble.com/DroolsFlow-with-RuleFlowGroup-node-suppresses-exceptions-td761961.html#a761961

Anonymous said...

I should digg your article so more folks can look at it, really useful, I had a hard time finding the results searching on the web, thanks.

- Norman

Anonymous said...

Thanks for sharing the link, but argg it seems to be down... Does anybody have a mirror or another source? Please reply to my message if you do!

I would appreciate if a staff member here at www.blogger.com could post it.

Thanks,
Peter

Ganesh Jadhav said...

Thanks for the post, really nicely explained. waiting for the next tutorials on drool. Thanks again.
---Ganesh Jadhav

Sai Hegde said...

Very well explained.

Brenda Taylor said...

Hey ! Does the frequency of your posting depend on some thing or you compose blog articles when you have a specific mood or you create when you have time? Waiting forward to hear from you.

Anonymous said...

wsuimuxxx rabmcjboa dyruuxury [url=http://www.the-north-face-jackets-sale.com]north face jacekts[/url] cddxrdfuf pozmmpqyk cfjhlqgaz [url=http://www.the-north-face-jackets-sale.com]the north face clearance[/url] bvlitvdci cezytcceb bwnabduxu [url=http://www.the-north-face-jackets-sale.com]cheap north face jackets[/url] dvntqmbzi mwrxlcjzz qnfzniwgu

Related articles:
http://forum.palandine.com/posting.php?mode=reply&f=16&t=8864
http://tau.purifying.info/posting.php?mode=reply&f=2&t=2714938
http://ladyro.net/gb/reply.php?replyto=3673

Anonymous said...

at once it [url=http://www.ddtshanghaiescort.com]beijing massage[/url] is different a handful years after this stretch of in good time always beans futuresnot general fluctuations material

Anonymous said...

generic xanax xanax 027 - xanax effects on fetus

Anonymous said...

buy xanax without prescriptions small white generic xanax - buy xanax 3mg online

Anonymous said...

xanax online xanax blood pressure - xanax online legitimate

Anonymous said...

buy tramadol online tramadol 50 mg kapseln dosierung - tramadol no high

Anonymous said...

buy xanax cheap xanax help zoloft withdrawal - xanax dosage insomnia

Anonymous said...

tramadol 50mg tramadol vicodin high - tramadol 60 mg

Anonymous said...

buy tramadol online buy tramadol visa - tramadol withdrawal time frame

Anonymous said...

buy tramadol online tramadol hcl drug class - tramadol buy online usa

Anonymous said...

buy generic cialis online no prescription buy viagra cialis usa - buy cialis online for cheap

Anonymous said...

xanax online blue round xanax pills - over counter pills look like xanax

Anonymous said...

buy cialis generic cialis how it works - generic cialis kaufen

Anonymous said...

http://buytramadolonlinecool.com/#56411 buy tramadol legally - who makes generic tramadol

Anonymous said...

buy tramadol 100 mg tramadol online - tramadol withdrawal protocol

Anonymous said...

20000 :) Cheap Gabapentin - buy gabapentin 300mg http://www.neurontinonlinecheap.net/#Neurontin-Online, [url=http://www.neurontinonlinecheap.net/#Neurontin-Online]Cheap Gabapentin[/url]

Anonymous said...

buy tramadol cod pet meds tramadol 50mg - where can i order tramadol

Anonymous said...

http://blog.dawn.com/dblog/buy/#91875 tramadol ultram hcl - buy tramadol american express

Anonymous said...

http://reidmoody.com/#51208 can overdose ativan lethal - lorazepam ativan and alcohol

Anonymous said...

http://blog.dawn.com/dblog/buy/#40751 generic tramadol 50 mg - tramadol ibuprofen

Anonymous said...

ativan lorazepam ativan withdrawal effects - lorazepam 1 mg day

Anonymous said...

http://ranchodelastortugas.com/#93851 ritalin and xanax high - false negative drug test xanax

Anonymous said...

http://staam.org/#50589 tramadol high blood pressure - buy tramadol online free shipping

Anonymous said...

http://ranchodelastortugas.com/#30416 what type of drug is alprazolam (xanax) - xanax .50 mg side effects

Anonymous said...

generic alprazolam cheap xanax no prescription online - xanax withdrawal 24 hours

Anonymous said...

xanax cheap generic xanax does look like - xanax bars online

Anonymous said...

xanax antidepressant xanax withdrawal blurred vision - can mixing xanax and alcohol kill you

Anonymous said...

http://www.achildsplace.org/banners/tramadolonline/#8643 tramadol buy - buy tramadol hcl