My Secret Life as a Spaghetti Coder
home | about | contact | privacy statement | getting started with cfrails
If you don't care about the background behind this, the reasons why you might want to use rules based programming, or a bit of theory, you can skip straight the Drools tutorial.

Background
One of the concepts I love to think about (and do) is raising the level of abstraction in a system. The more often you are telling the computer what, and not how, the better.

Of course, somewhere someone is doing imperative programming (telling it how), but I like to try to hide much of that somewhere and focus more on declarative programming (telling it what). Many times, that's the result of abstraction in general and DSLs and rules-based programming more specifically.

As a side note, let me say that this is not necessarily a zero-sum game. In one aspect you may be declaratively programming while in another you are doing so imperatively. Example:

function constructARecord()
{
  this.name=readFileLineNumber(fileName, 1);
  this.phone=readFileLineNumber(fileName, 2);
  this.address=readFileLineNumber(fileName, 3);
}

You are telling it how to construct a record, but you are not telling it how to read the file. Instead, you are just telling it to read the file.

Anyway, enough of that diversion. I hope I've convinced you.

When I finished writing the (half-working) partial order planner in Ruby, I mentioned I might like "to take actions as functions, which receive preconditions as their parameters, and whose output are effects" (let me give a special thanks to Hugh Sasse for his help and ideas in trying to use TSort for it while I'm on the subject).

Doing so may have worked well when generalizing the solution to a rules engine instead of just a planner (they are conceptually quite similar). That's often intrigued me from both a business application and game programming standpoint.

The good news is (as you probably already know), this has already been done for us. That was the subject of Venkat's talk that I attended at No Fluff Just Stuff at the end of June 2007.

Why use rules-based programming?
After a quick introduction, Venkat jumped right into why you might want to use a rules engine. The most prominent reasons all revolve around the benefits provided by separating concerns: When business rules change almost daily, changes to source code can be costly. Separation of knowledge from implementation reduces this cost by having no requirement to change the source code.

Additionally, instead of providing long chains of if...else statements, using a rule engine allows you the benefits of declarative programming.

A bit of theory
The three most important aspects for specifying the system are facts, patterns, and the rules themselves. It's hard to describe in a couple of sentences, but your intuition should serve you well - I don't think you need to know all of the theory to understand a rule-based system.

Rule Engine Design
Rules Engine based on Venkat's notes

Facts are just bits of information that can be used to make decisions. Patterns are similar, but can contain variables that allow them to be expanded into other patterns or facts. Finally, rules have predicates/premises that if met by the facts will fire the rule which allows the action to be performed (or conclusion to be made).

(Another side note: See JSR 94 for a Java spec for Rules Engines or this google query for some theory. Norvig's and Russell's Artificial Intelligence: A Modern Approach also has good explanations, and is a good introduction to AI in general (though being a textbook, it's pricey at > $90 US)).

(Yet another side note: the computational complexity of this pattern matching can be enormous, but the Rete Algorithm will help, so don't prematurely optimize your rules.)

Drools
Now that we know a bit of the theory behind rules-based systems, let's get into the practical to show how easy it can be (and aid in removing fear of new technology to become a generalist).

First, you can get Drools 2.5 at Codehaus or version 3, 4 or better from JBoss. At the time of writing, the original Drools lets you use XML with Java or Groovy, Python, or Drools' own DSL to implement rules, while the JBoss version (I believe) is (still) limited to Java or the DSL.

Since I avoid XML like the plague (well, not that bad), I'll go the DSL route.

First, you'll need to download Drools and unzip it to a place you keep external Java libraries. I'm working with Drools 4.0.1. After that, I created a new Java project in Eclipse and added a new user library for Drools, then added that to my build path (I used all of the Drools JARs in the library). (And don't forget JUnit if you don't have it come up automatically!)

Errors you might need to fix
For reference for anyone who might run across the problems I did, I'm going to include a few of the errors I came into contact with and how I resolved them. I was starting with a pre-done example, but I will show the process used to create it after trudging through the errors. Feel free to skip this section if you're not having problems.

After trying the minimal additions to the build path I mentioned above, I was seeing an error that javax.rules was not being recognized. I added jsr94-1.1.jar to my Drools library (this is included under /lib in the Drools download) and it was finally able to compile.

When running the unit tests, however, I still got this error:

org.drools.RuntimeDroolsException: Unable to load dialect 'org.drools.rule.builder.dialect.java.JavaDialectConfiguration:java'

At that point I just decided to add all the dependencies in /lib to my Drools library and the error went away. Obviously you don't need Ant, but I wasn't quite in the mood to go hunting for the minimum of what I needed. You might feel differently, however.

Now that the dialect was able to be loaded, I got another error:

org.drools.rule.InvalidRulePackage: Rule Compilation error : [Rule name=Some Rule Name, agendaGroup=MAIN, salience=-1, no-loop=false] com/codeodor/Rule_Some_Rule_Name_0.java (8:349) : Cannot invoke intValue() on the primitive type int

As you might expect, this was happening simply because the rule was receiving an int and was trying to call a method from Integer on it.

After all that, my pre-made example ran correctly, and being comfortable that I had Drools working, I was ready to try my own.

An Example: Getting a Home Loan
From where I sit, the process of determining how and when to give a home loan is complex and can change quite often. You need to consider an applicant's credit score, income, and down payment, among other things. Therefore, I think it is a good candidate for use with Drools.

To keep the tutorial simple (and short), our loan determinizer will only consider credit score and down payment in regards to the cost of the house.

First we'll define the HomeBuyer class. I don't feel the need for tests, because as you'll see, it does next to nothing.

package com.codeodor;

public class HomeBuyer {
        int _creditScore;
        int _downPayment;       
        String _name;
       
        public HomeBuyer(String buyerName, int creditScore, int downPayment) {
                _name = buyerName;
                _creditScore = creditScore;
                _downPayment = downPayment;
        }
       
        public String getName() {
                return _name;
        }
       
        public int getCreditScore(){
                return _creditScore;
        }
       
        public int getDownPayment(){
                return _downPayment;
        }
}

Next, we'll need a class that sets up and runs the rules. I'm not feeling the need to test this directly either, because it is 99% boilerplate and all of the code gets tested when we test the rules anyway. Here is our LoanDeterminizer:

package com.codeodor;
import org.drools.jsr94.rules.RuleServiceProviderImpl;

import javax.rules.RuleServiceProviderManager;
import javax.rules.RuleServiceProvider;
import javax.rules.StatelessRuleSession;
import javax.rules.RuleRuntime;
import javax.rules.admin.RuleAdministrator;
import javax.rules.admin.LocalRuleExecutionSetProvider;
import javax.rules.admin.RuleExecutionSet;
import java.io.InputStream;
import java.util.ArrayList;

public class LoanDeterminizer {
        // the meat of our class
        private boolean _okToGiveLoan;
        private HomeBuyer _homeBuyer;
        private int _costOfHome;
        public boolean giveLoan(HomeBuyer h, int costOfHome) {
                _okToGiveLoan = true;
                _homeBuyer = h;
                _costOfHome = costOfHome;
               
                ArrayList<Object> objectList = new ArrayList<Object>();
                objectList.add(h);
                objectList.add(costOfHome);
                objectList.add(this);
               
                return _okToGiveLoan;
        }
       
        public HomeBuyer getHomeBuyer() { return _homeBuyer; }
        public int getCostOfHome() { return _costOfHome; }
        public boolean getOkToGiveLoan() { return _okToGiveLoan; }
        public double getPercentDown() { return(double)(_homeBuyer.getDownPayment()/_costOfHome); }
       
        // semi boiler plate (values or names change based on name)
        private final String RULE_URI = "LoanRules.drl"; // this is the file name our Rules are contained in
       
        public LoanDeterminizer() throws Exception // the constructor name obviously changes based on class name
    {
        prepare();
    }
       
       
        // complete boiler plate code from Venkat's presentation examples follows
        // I imagine some of this changes based on how you want to use Drools
        private final String  RULE_SERVICE_PROVIDER = "http://drools.org/";
    
    private StatelessRuleSession _statelessRuleSession;
    private RuleAdministrator _ruleAdministrator;
       
    private boolean _clean = false;
            
    protected void finalize() throws Throwable
    {
        if (!_clean)  { cleanUp(); }
    }
    
    private void prepare() throws Exception
    {
        RuleServiceProviderManager.registerRuleServiceProvider(
                RULE_SERVICE_PROVIDER, RuleServiceProviderImpl.class );

        RuleServiceProvider ruleServiceProvider =
                RuleServiceProviderManager.getRuleServiceProvider(RULE_SERVICE_PROVIDER);

        _ruleAdministrator = ruleServiceProvider.getRuleAdministrator( );

        LocalRuleExecutionSetProvider ruleSetProvider =
                _ruleAdministrator.getLocalRuleExecutionSetProvider(null);

        InputStream rules = Exchange.class.getResourceAsStream(RULE_URI);
        RuleExecutionSet ruleExecutionSet =
                ruleSetProvider.createRuleExecutionSet(rules, null);

        _ruleAdministrator.registerRuleExecutionSet(RULE_URI, ruleExecutionSet, null);

        RuleRuntime ruleRuntime = ruleServiceProvider.getRuleRuntime();

        _statelessRuleSession =
                (StatelessRuleSession) ruleRuntime.createRuleSession(
                        RULE_URI, null, RuleRuntime.STATELESS_SESSION_TYPE );
    }

    public void cleanUp() throws Exception
    {
        _clean = true;
        _statelessRuleSession.release( );
        _ruleAdministrator.deregisterRuleExecutionSet(RULE_URI, null);
    }
    
}

I told you there was a lot of boilerplate code there. I won't explain it all because:
  1. It doesn't interest me
  2. I don't yet know as much as I should about it
I fully grant that reason number one may be partially or completely dependent on the second one.

In any case, now we can finally write our rules. I'll be starting with a test:

package com.codeodor;

import junit.framework.TestCase;

public class TestRules extends TestCase {
    public void test_poor_credit_rating_gets_no_loan() throws Exception
    {
        LoanDeterminizer ld = new LoanDeterminizer();
        HomeBuyer h = new HomeBuyer("Ima Inalotadebt and Idun Payet", 100, 20000);
        
        boolean result = ld.giveLoan(h, 150000);
        assertFalse(result);
        
        ld.cleanUp();
    }

}

And our test fails, which is what we wanted. We didn't yet create our rule file, LoanRules.drl, so let's do that now.

package com.codeodor

rule "Poor credit score never gets a loan"
  salience 2
  when
    buyer : HomeBuyer(creditScore < 400)
    loan_determinizer : LoanDeterminizer(homeBuyer == buyer)
  then
    System.out.println(buyer.getName() + " has too low a credit rating to get the loan.");
    loan_determinizer.setOkToGiveLoan(false);
end

The string following "rule" is the rule's name. Salience is one of the ways Drools performs conflict resolution. Finally, the first two lines tell it that buyer is a variable of type HomeBuyer with a credit score of less than 400 and loan_determinizer is the LoanDeterminizer passed in with the object list where the homeBuyer is what we've called buyer in our rule. If either of those conditions fails to match, this rule is skipped.

Hopefully that makes some sense to you. If not, let me know in the comments and I'll try again.

And now back to our regularly scheduled test: running it again still results in a red bar. This time, the problem is:

org.drools.rule.InvalidRulePackage: Rule Compilation error : [Rule name=Poor credit score never gets a loan, agendaGroup=MAIN, salience=2, no-loop=false]
  com/codeodor/Rule_Poor_credit_score_never_gets_a_loan_0.java (7:538) : The method setOkToGiveLoan(boolean) is undefined for the type LoanDeterminizer

The key part here is "the method setOkToGiveLoan(boolean) is undefined for the type LoanDeterminizer." Oops, we forgot that one. So let's add it to LoanDeterminizer:

public void setOkToGiveLoan(boolean value) { _okToGiveLoan = value; }

Now running the test results in yet another red bar! It turns out I forgot something pretty big (and basic) in LoanDeterminizer.giveLoan(): I didn't tell it to execute the rules. Therefore, the default case of "true" was the result since the rules were not executed.

Asking it to execute the rules is as easy as this one-liner, which passes it some working data: _statelessRuleSession.executeRules(objectList);

For reference, the entire working giveLoan method is below:

public boolean giveLoan(HomeBuyer h, int costOfHome) throws Exception {
        _okToGiveLoan = true;
        _homeBuyer = h;
        _costOfHome = costOfHome;
       
        ArrayList<Object> objectList = new ArrayList<Object>();
        objectList.add(h);
        objectList.add(costOfHome);
        objectList.add(this);
       
        _statelessRuleSession.executeRules(objectList);
       
        // here you might have some code to process
        // the loan if _okToGiveLoan is true
       
        return _okToGiveLoan;
}

Now our test bar is green and we can add more tests and rules. Thankfully, we're done with programming in Java (except for our unit tests, which I don't mind all that much).

To wrap-up the tutorial I want to focus on two more cases: Good credit score always gets the loan and medium credit score with small down payment does not get the loan. I wrote the tests and rules iteratively, but I'm going to combine them here for organization's sake seeing as I already demonstrated the iterative approach.

public void test_good_credit_rating_gets_the_loan() throws Exception {
        LoanDeterminizer ld = new LoanDeterminizer();
       
        HomeBuyer h = new HomeBuyer("Warren Buffet", 800, 0);
       
        boolean result = ld.giveLoan(h, 100000000);
        assertTrue(result);
        
        // maybe some more asserts if you performed processing in LoanDeterminizer.giveLoan()
      
        ld.cleanUp();
}


public void test_mid_credit_rating_gets_no_loan_with_small_downpayment() throws Exception {
        LoanDeterminizer ld = new LoanDeterminizer();
        
        HomeBuyer h = new HomeBuyer("Joe Middleclass", 500, 5000);
        
        boolean result = ld.giveLoan(h, 150000);
        assertFalse(result);
        
        ld.cleanUp();
}

And the associated rules added to LoanRules.drl:

rule "High credit score always gets a loan"
     salience 1
     when
         buyer : HomeBuyer(creditScore >= 700)
         loan_determinizer : LoanDeterminizer(homeBuyer == buyer)
     then
         System.out.println(buyer.getName() + " has a credit rating to get the loan no matter the down payment.");
         loan_determinizer.setOkToGiveLoan(true);
end

rule "Middle credit score fails to get a loan with small down payment"
     salience 0
     when
         buyer : HomeBuyer(creditScore >= 400 && creditScore < 700)
         loan_determinizer : LoanDeterminizer(homeBuyer == buyer && percentDown < 0.20)
     then
         System.out.println(buyer.getName() + " has a credit rating to get the loan but not enough down payment.");
         loan_determinizer.setOkToGiveLoan(false);
end

As you can see, there is a little bit of magic going on behind the scenes (as you'll also find in Groovy) where here in the DSL, you can call loan_determinizer.percentDown and it will call getPercentDown for you.

All three of our tests are running green and the console outputs what we expected:

Ima Inalotadebt and Idun Payet has too low a credit rating to get the loan.
Warren Buffet has a credit rating to get the loan no matter the down payment.
Joe Middleclass has a credit rating to get the loan but not enough down payment.


As always, questions, comments, and criticism are welcome. Leave your thoughts below. (I know it was the length of a book, so I don't expect many.)

For more on using Drools, see the Drools 4 docs.

Finally, as with my write-ups on Scott Davis's Groovy presentation, his keynote, Stuart Halloway's JavaScript for Ajax Programmers, and Neal Ford's 10 ways to improve your code, I have to give Venkat most of the credit for the good stuff here. I'm just reporting from my notes, his slides, and my memory, so any mistakes you find are probably mine. If they aren't, they likely should have been.

Hey! Why don't you make your life easier and subscribe to the full post or short blurb RSS feed? I'm so confident you'll love my smelly pasta plate wisdom that I'm offering a no-strings-attached, lifetime money back guarantee!


Comments
Leave a comment

Noting the 3 red bars when writing our first test, perhaps it would have been a good idea to write some tests for the LoanDeterminizer class.

Posted by Sam on Sep 10, 2007 at 12:51 PM UTC - 5 hrs

Te agradezco grandemente tus comenetarios, tenia al menos dos semanas tratando de reslver el mensaje de error. Trate de solucionar el error por muchos opciones.

saludos..

Posted by José Guadalupe García on Sep 11, 2007 at 10:31 PM UTC - 5 hrs

Gracias José. Mi español es no muy bueno (so forgive me). ¿Con qué error le tenían problemas?

(thanks to Babelfish for the correct conjugation of "tener" if that happens to be correct)

Posted by Sam on Sep 12, 2007 at 06:13 AM UTC - 5 hrs

JSR94 is a terrible standard with no redeeming features :) almost anyone that uses it ends up having to use proprietary extensions, via the properties map, thus defeating the point of the standard. So I would really recommend you use the Drools api directly. Other than great blog, it's really nice to see people out in the community doing this sort of thing :)

Thanks

Mark
http://blog.athico.com

Posted by Mark Proctor on Sep 12, 2007 at 07:36 AM UTC - 5 hrs

Thanks for the comment, Mark. I have read as much about JSR94 (that it stinks), but I forgot to include that bit in the post for some reason unbeknownst to me now. Always great to hear it straight from the horse's mouth though!

And I'm definitely looking forward to getting deeper into developing with Drools.

Posted by Sam on Sep 12, 2007 at 10:41 AM UTC - 5 hrs

Hi,

With respect to JBoss Rules,
We are currently planning to implement JBoss Rules using service-oriented architecture (SOA) in our mission critical project - We have used MS Excel file as templates where-in we have custom created and managed formula, for which we have properties exposed for get/set in C#.

The Drools Rules Language (DRL) and XML files are compiled from the source excel template file and are used to validate the results which have been placed in a shared folder. Currently we have hit a limitation in that the formula could not be extended based on the current design using excel file templates.

Can anyone throw more light on how well excel formula can be used in JBoss Rules Excel templates and in the compiled binaries (Drools Rule Language)

Also, do let me know if there are any limitations on using Excel files as templates. Thanks!

Kumar

Posted by Kumar on Oct 15, 2007 at 01:43 AM UTC - 5 hrs

Kumar,

I've yet to do anything like that before. I suspect if you are doing the integration yourself that there would be no limitation. But, if there is already a feature to do it for you, you might be running into problems.

I'm not sure I understand what is happening when you say "the formula could not be extended based on the current design using excel file templates." Are you saying you have to recompile each time?

Is there a way to code it such that you read the excel file each time and construct the rules on the fly? (and would that solve your problem?)

In any case, you might find better answers from the Rules-Users community mailing list at https://lists.jboss.org/mailman/listinfo/rules-use... ... although, I am always happy to help any way I can.

Posted by Sam on Oct 15, 2007 at 10:32 AM UTC - 5 hrs

HI,
I don't known the meaning of " buyer : HomeBuyer(creditScore >= 700)
loan_determinizer : LoanDeterminizer(homeBuyer == buyer)
",and I am a learner,Could you expain it ?Thank you very much

Posted by LanJIe Zhao on Feb 02, 2008 at 12:47 AM UTC - 5 hrs

Basically, it's saying set "buyer" variable (for reuse in the "then" part) to the HomeBuyer object that gets passed in. The creditScore >= 700 part is a condition, where if the credit score is less than that the "then" part won't execute.

The loan_determinizer part follows the same pattern.

Posted by Sammy Larbi on Feb 02, 2008 at 11:18 AM UTC - 5 hrs

hello,
we are migrating from drools 2.5 to drools 4.0
rest all is working fine but just we are finding problem in the ejb-jar.xml file.
In each <session> and <entity> tags one tag gets added when we try to build the project.
The line which is expected is : <session>
but the generated line is : <session xml:base="file:E:/ ... >
can anyone help!

Posted by Anupam on Feb 19, 2008 at 01:01 AM UTC - 5 hrs

Hi,
We are developing a travel site and in front end we are using struts framework,at back end we are using Hibernate frame work along with DAO's and between the layers we are using DTO's. In our application we need to use a rule engine for this we are using Drools4.0.4,now our problem is How to integrate the rule engine between struts and DAO which uses DTO's for transfering of data. We need to search flight fare and if the flight fare is 2000 then we need to give a discount of 20% on this. I read the article in Onjava (http://www.onjava.com/lpt/a/6160) but I am not understanding how the rule engine gets data from DTO's and again sets it.

please help me in this

regards
sudarshan

Posted by sudarshan on Feb 19, 2008 at 04:43 AM UTC - 5 hrs

@Anupam: I think you might find better answers on the mailing list at https://lists.jboss.org/mailman/listinfo/rules-use...

@sudarshan: Forget about DAOs and DTOs for the time being. What makes them so special they can't be used with the above tutorial? The tutorial shows how to get and set data in objects from the rules, and from the rule runner. There should be nothing about TLA (three-letter acronym) objects that I can see would be a problem.

Hope that helps!

Posted by Sammy Larbi on Feb 19, 2008 at 06:31 AM UTC - 5 hrs

Hi,
there is an example named "Honest Politician Example" in the Drools Reference Manual,but I am confused about the result,why the order is converse?It inserts new politician as follow:
"session.insert( schroder );
session.insert( chirac );
session.insert( bush );
session.insert( blair );
"
but the output result is as follow:
"I'm an evil corporation and I have corrupted blair
I'm an evil corporation and I have corrupted bush
I'm an evil corporation and I have corrupted chirac
I'm an evil corporation and I have corrupted schroder".

Could you please explain the executive order? Why it checks the "blair" firstly?

Thank you very much!

Posted by LanJie Zhao on Feb 27, 2008 at 04:07 AM UTC - 5 hrs

Maybe they use a stack? I haven't looked at the example though, so that could be way off base. What does the code look like?

Posted by Sammy Larbi on Feb 27, 2008 at 07:56 AM UTC - 5 hrs

Hi,
Thank you for your reply,"Honest Politician Example" is at
http://winnerqueen2008.blog.163.com/blog/static/26...
You can click the "HonestPoliticianExample"
Thank you very much!

Posted by LanJie Zhao on Feb 27, 2008 at 09:16 PM UTC - 5 hrs

@LanJie - I looked for a while into the java docs to see if I could tell how StatefulSession is implemented. I never did find the implementation class for it, but my best guess is to tell you:

Conceptually all you are doing when you call session.insert(object) is asserting a fact to the session. The order of the facts doesn't matter, so when you run the rules, it can choose them in any order (order of execution of rules matters, not choosing facts though).

I guess they implemented it in such a way that facts are inserted at the beginning of a list instead of the end, or perhaps they insert and remove at the end, or it could be a hash table, or something else entirely.

Posted by Sammy Larbi on Feb 28, 2008 at 06:39 AM UTC - 5 hrs

Hi,
There is an error in my program. Could you please help me figure out the reason? The error message is as following:

Exception in thread "main" org.drools.RuntimeDroolsException: Conversion to long not supported from java.lang.String
at org.drools.base.extractors. BaseObjectClassFieldExtractor.getLongValue (BaseObjectClassFieldExtractor.java:106)
at org.drools.base.ClassFieldExtractor. getLongValue(ClassFieldExtractor.java:203)
at org.drools.rule.VariableRestriction$ LongVariableContextEntry.updateFromTuple(VariableRestriction.java:284)
at org.drools.common.DefaultBetaConstraints. updateFromTuple(DefaultBetaConstraints.java:139)
at org.drools.reteoo.JoinNode.assertTuple (JoinNode.java:102)
at org.drools.reteoo.SingleTupleSinkAdapter. propagateAssertTuple(SingleTupleSinkAdapter.java:20)
at org.drools.reteoo.JoinNode.assertObject (JoinNode.java:151)
at org.drools.reteoo.SingleObjectSinkAdapter. propagateAssertObject(SingleObjectSinkAdapter.java:22)
at org.drools.reteoo.AlphaNode.assertObject (AlphaNode.java:140)
at org.drools.reteoo.SingleObjectSinkAdapter. propagateAssertObject(SingleObjectSinkAdapter.java:22)
at org.drools.reteoo.AlphaNode.assertObject (AlphaNode.java:140)
at org.drools.reteoo.CompositeObjectSinkAdapter. propagateAssertObject(CompositeObjectSinkAdapter.java:299)
at org.drools.reteoo.ObjectTypeNode.assertObject (ObjectTypeNode.java:153)
at org.drools.reteoo.Rete.assertObject (Rete.java:175)
at org.drools.reteoo.ReteooRuleBase. assertObject(ReteooRuleBase.java:192)
at org.drools.reteoo.ReteooWorkingMemory. doInsert(ReteooWorkingMemory.java:71)
at org.drools.common.AbstractWorkingMemory. insert(AbstractWorkingMemory.java:909)
at org.drools.common.AbstractWorkingMemory. insert(AbstractWorkingMemory.java:881)
at org.drools.common.AbstractWorkingMemory. insert(AbstractWorkingMemory.java:682)
at com.sample.Fishman.main(Fishman.java:30)

Part of code is below:
final StatefulSession session=ruleBase.newStatefulSession();
String[] country=new String[]{"Norway", "Danmark", "Britain", "Germany", "Sweden"};
String[] housecolor=new String[]{"yellow", "blue", "red", "green", "white"};
String[] drink=new String[]{"mineralwater", "tea", "milk", "coffee", "beer"};
String[] cigarettebrand=new String[]{"Dunhill", "Blends", "PallMall", "Prince", "BlueMaster"};
String[] pet=new String[] {"cat", "horse", "bird", "fish", "dog"};
int[] positions = new int[] { 1, 2, 3, 4,5 };

for (int i=0;i<country.length;i++)
{
for(int g=0;g<housecolor.length;g++){
for(int k=0;k<drink.length;k++){
for(int l=0;l<cigarettebrand.length;l++){
for(int j=0;j<pet.length;j++){
for(int h=0;h<positions.length;h++){
session.insert(new People(country[i], housecolor[g], drink[k], cigarettebrand[l], pet[j], positions[h])); //The mistake is located in this row and it is "Fishman.java:30"}
}
}
}
}
}

Posted by LanJie Zhao on Mar 10, 2008 at 01:01 AM UTC - 5 hrs

I'd check to ensure your parameters are in the correct order. More likely, I'd look in my rules file to check if my data types matched like I think they should be matching.

I don't notice anything obviously wrong with the code you posted.

Posted by Sammy Larbi on Mar 10, 2008 at 05:40 AM UTC - 5 hrs

hello, I went thru that website of which you gave me the link .. But I dint find anything of my concern ..

Posted by Anupam on Mar 14, 2008 at 12:22 AM UTC - 5 hrs

@Anupan - sorry I couldn't be of more help. Did you join the mailing list and ask your question?

Posted by Sammy Larbi on Mar 14, 2008 at 06:05 AM UTC - 5 hrs

hi,
can you help me , how to load the rules from database dynamically without .drl files.

thanks in advance.

Posted by kathir on Apr 22, 2008 at 10:06 PM UTC - 5 hrs

Hi,i am trying to learn Drools and i try to find a unique number in all numbers -some of them are same numbers - for example;the numbers : 1,2,3,4,4,5,6,1,1 and i want to find 2,3,5,6 and also the repeated numbers;but i dont know how can i do that it is necessary to use a method like iterator, but how? if you can help me ,it will be perfect.
Thanks for your attention.

Posted by Morv on Jul 03, 2008 at 04:30 AM UTC - 5 hrs

@Morv: I think Drools may be a bit overkill for such a problem. What I'd do is use a hash table with the numbers as the keys and the counts of each number as the values.

Then, you can loop over all keys and extract which ones have counts of 1, and you'll have your solution, in basically O(n) time.

Posted by Sammy Larbi on Jul 03, 2008 at 07:22 AM UTC - 5 hrs

package com.codeodor;
import org.drools.jsr94.rules.RuleServiceProviderImpl;

import javax.rules.RuleServiceProviderManager;
import javax.rules.RuleServiceProvider;
import javax.rules.StatelessRuleSession;
import javax.rules.RuleRuntime;
import javax.rules.admin.RuleAdministrator;
import javax.rules.admin.LocalRuleExecutionSetProvider;
import javax.rules.admin.RuleExecutionSet;
import java.io.InputStream;
import java.util.ArrayList;

public class LoanDeterminizer {
// the meat of our class
private boolean _okToGiveLoan;
private HomeBuyer _homeBuyer;
private int _costOfHome;
public boolean giveLoan(HomeBuyer h, int costOfHome) {
_okToGiveLoan = true;
_homeBuyer = h;
_costOfHome = costOfHome;

ArrayList<Object> objectList = new ArrayList<Object>();
objectList.add(h);
objectList.add(costOfHome);
objectList.add(this);

return _okToGiveLoan;
}

public HomeBuyer getHomeBuyer() { return _homeBuyer; }
public int getCostOfHome() { return _costOfHome; }
public boolean getOkToGiveLoan() { return _okToGiveLoan; }
public double getPercentDown() { return(double)(_homeBuyer.getDownPayment()/_costOfHome); }

// semi boiler plate (values or names change based on name)
private final String RULE_URI = "LoanRules.drl"; // this is the file name our Rules are contained in

public LoanDeterminizer() throws Exception // the constructor name obviously changes based on class name
{
prepare();
}


// complete boiler plate code from Venkat's presentation examples follows
// I imagine some of this changes based on how you want to use Drools
private final String RULE_SERVICE_PROVIDER = "http://drools.org/";

private StatelessRuleSession _statelessRuleSession;
private RuleAdministrator _ruleAdministrator;

private boolean _clean = false;

protected void finalize() throws Throwable
{
if (!_clean) { cleanUp(); }
}

private void prepare() throws Exception
{
RuleServiceProviderManager.registerRuleServiceProvider(
RULE_SERVICE_PROVIDER, RuleServiceProviderImpl.class );

RuleServiceProvider ruleServiceProvider =
RuleServiceProviderManager.getRuleServiceProvider(RULE_SERVICE_PROVIDER);

_ruleAdministrator = ruleServiceProvider.getRuleAdministrator( );

LocalRuleExecutionSetProvider ruleSetProvider =
_ruleAdministrator.getLocalRuleExecutionSetProvider(null);

InputStream rules = Exchange.class.getResourceAsStream(RULE_URI);
RuleExecutionSet ruleExecutionSet =
ruleSetProvider.createRuleExecutionSet(rules, null);

_ruleAdministrator.registerRuleExecutionSet(RULE_URI, ruleExecutionSet, null);

RuleRuntime ruleRuntime = ruleServiceProvider.getRuleRuntime();

_statelessRuleSession =
(StatelessRuleSession) ruleRuntime.createRuleSession(
RULE_URI, null, RuleRuntime.STATELESS_SESSION_TYPE );
}

public void cleanUp() throws Exception
{
_clean = true;
_statelessRuleSession.release( );
_ruleAdministrator.deregisterRuleExecutionSet(RULE_URI, null);
}

}


i got compile time error at Exchange what it is how to remove it thanks.

Posted by kiran on Jul 31, 2008 at 01:03 AM UTC - 5 hrs

can u give complete code? Instead off diffrent scroll.
is it possible to run the code in main class if yes den please forward the code.
if u know good book for drool rule engin den plz suggest.

thanks in adv

Posted by kiran on Jul 31, 2008 at 01:42 AM UTC - 5 hrs

Kiran,

The complete code is there. If you're having trouble piecing it together, I'd kindly suggest reading more in-depth.

As for the compile time error, I wonder if it's something covered in the tutorial? If not, perhaps you could post it?

Kind regards.

Posted by Sammy Larbi on Jul 31, 2008 at 07:10 AM UTC - 5 hrs

so what does RULE_SERVICE_PROVIDER do? If I use this example as a foundation for using the Rules engine, do I leave it set to "http://drools.org/".

Doesnt seem right....

AJ

Posted by AJ Weaver on Jul 31, 2008 at 08:53 AM UTC - 5 hrs

@AJ - I think it's something required by JSR94. In essence, you could choose to use any number of providers that implement the standard.

But that's only my guess.

Posted by Sammy Larbi on Jul 31, 2008 at 09:20 AM UTC - 5 hrs

hi,
i have run the program that read the rule from excel sheet,
felt great. for that i used drool 2.5. now i want to use drool 4. but dont know how to start for that.
please will give me code sinppet that show me how to load the excel sheet and fire all rule on that?.

thanks.

Posted by kiran on Aug 02, 2008 at 04:21 AM UTC - 5 hrs

Kiran, I don't know how to load rules from Excel. I would imagine you need to interface through COM to load the rules, but it's possible someone has written something that does it for you.

I'd check the Drools mailing list for more answers, or ask the question there: https://lists.jboss.org/mailman/listinfo/rules-use...

Note that another person in this comment thread asked a similar question and I pointed them to that list, so if you search the archives you might find the answer you're looking for without having to ask again. =)

Good luck!

Posted by Sammy Larbi on Aug 06, 2008 at 04:29 PM UTC - 5 hrs

Nice tutorial so far but I still got this error:

"Exchange can not be resolved to a type"

When you try to get the RuleExecutionSet in LoanDeterminizer.prepare() you use the "Exchange" -class

Where did you get it from?

Here's your code again :

InputStream rules = Exchange.class.getResourceAsStream(RULE_URI);
RuleExecutionSet ruleExecutionSet =
ruleSetProvider.createRuleExecutionSet(rules, null);

Posted by Corvan on Aug 20, 2008 at 06:03 AM UTC - 5 hrs

@Corvan - have you successfully imported all of the packages? That's about the only thing I can think of at the top of my head.

Posted by Sammy Larbi on Aug 20, 2008 at 08:36 AM UTC - 5 hrs

After I indeed had some problems figuring out which files should be included in wich way I've included all *.jar files from the downloaded "drools-5.0.0.M1-bin" directory and (to be shure) from the "drools-4.0.7-bin" folder into the Java Build Path for the project..

I'm not to shure if thats what i was supposed to do but it worked for my first hello-world RuleFlow

If that was wrong could you pls tell me where to install what?

thx for the quick response

Corvan

P.S. maybe I just need to know where this Exchange class comes from so i know what i've forgotten to include

Posted by Corvan on Aug 20, 2008 at 09:13 AM UTC - 5 hrs

getResourceFromStream is a method from ClassLoader (http://java.sun.com/j2se/1.4.2/docs/api/java/lang/...) but I cannot for the life of me remember where Exchange comes from, and searching on Google hasn't been a huge help.

I'm stuck.

What version of drools are you using? Oh, version 5. I wonder if they changed something in version 5 that was in the previous versions.

I have to run off to a meeting, so I don't have time to check, but I'd look in the Drools 5 docs about how to load the .DRL file, as that's what's going on.

The docs are currently at (in a ZIP) http://download.jboss.org/drools/release/5.0.0.208...

Posted by Sammy Larbi on Aug 20, 2008 at 10:15 AM UTC - 5 hrs

Well I got my answer:

instead of this Exchange-class I used the class that creates my RuleBase.
For example my class RuleFlowTest.java uses this code:

PackageBuilder builder = new PackageBuilder();
Reader source = new InputStreamReader(

RuleFlowTest.class.getResourceAsStream("/MyRuleFlow.rf"));

builder.addRuleFlow(source);
Package pkg = builder.getPackage();
RuleBase ruleBase = RuleBaseFactory.newRuleBase();
ruleBase.addPackage(pkg);

Its working fine :)

btw my RuleFlowTest.java only has static methods so if your own class isn't that static you could just write this.getClass().getResourceAsStream(...)

Posted by Corvan on Aug 25, 2008 at 10:00 AM UTC - 5 hrs

@Corvan - Excellent. Thanks for posting that here for everyone else who encounters similar problems.

Posted by Sammy Larbi on Aug 25, 2008 at 10:18 AM UTC - 5 hrs

PackageBuilder builder = new PackageBuilder();

is giving me the fallowing error

java.lang.NoClassDefFoundError: org/apache/commons/jci/compilers/EclipseJavaCompilerSettings

Posted by Rahul on Sep 23, 2008 at 06:40 AM UTC - 5 hrs

if i want to integrate this rules with web technologies
where i take care

Posted by Rahul on Sep 23, 2008 at 11:34 PM UTC - 5 hrs

Rahul, I can't answer specifics on that, as it would take a book. But suffice to say this would be considered part of your business object / model classes, so look towards the M in "MVC" architecture. You might do well to explore a/some frameworks in Java, or start with a search for Struts 2 or Tapestry.

Maybe a framework isn't right for what you're doing. I'm just looking at this question from a design angle. Using the rules engine is no different than using any other object, so you could put it in a jsp if you really wanted to (of course, I recommend against it in most cases).

Hope that helps.

Posted by Sammy Larbi on Sep 24, 2008 at 08:20 AM UTC - 5 hrs

Leave a comment

Leave this field empty
Your Name
Email (not displayed, more info?)
Website

Comment:

Subcribe to this comment thread
Remember my details
Google
Web CodeOdor.com

Me
Picture of me

Topics
.NET (24)
AI/Machine Learning (13)
Bioinformatics (2)
C++ (6)
cfrails (22)
ColdFusion (83)
Customer Relations (20)
DRY (19)
DSLs (13)
Future Tech (6)
Games (6)
Groovy/Grails (7)
IDEs (9)
Java (43)
JavaScript (3)
Lisp (1)
Mac OS (1)
Management (3)
Miscellany (61)
OOAD (38)
Programming (123)
Programming Quotables (8)
Rails (19)
Ruby (54)
Save Your Job (62)
scriptaGulous (4)
Software Development Process (26)
TDD (42)
TDDing xorblog (6)
Tools (4)
Web Development (5)
YAGNI (11)

Resources
Agile Manifesto & Principles
Principles Of OOD
ColdFusion
CFUnit
Ruby
Ruby on Rails
JUnit



RSS 2.0: Full Post | Short Blurb
Subscribe by email:

Delivered by FeedBurner