I am trying to learn drools. Following is the code – and the rule is not firing though fireAllRules is called .
Product class
package com.abc.main;
public class Product {
private String RegionName = "South";
private String CouponCode = "A";
public String getType() {
return RegionName;
}
public void setType(String regionName) {
this.RegionName = regionName;
}
public String getCouponCode() {
return CouponCode;
}
public void setCouponCode(String couponCode) {
this.CouponCode = couponCode;
}
}
Rules.drl file
package com.abc.main;
import com. abc.main.Product
rule "Offer for Diamond"
when
productObject: Product(RegionName=="South")
then
productObject.setCouponCode("B");
end
rule "Offer for Gold"
when
productObject: Product(RegionName=="North")
then
productObject.setCouponCode("C");
end
Class6 (Test class)
package com.abc.main;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.drools.compiler.compiler.DroolsParserException;
import org.drools.compiler.compiler.PackageBuilder;
import org.drools.core.RuleBase;
import org.drools.core.RuleBaseFactory;
import org.drools.core.WorkingMemory;
public class Class6 {
public static void main(String[] args) throws DroolsParserException,IOException
{
Class6 droolsTest = new Class6();
System.out.println("Reached point 1A");
droolsTest.executeDrools2();
}
public void executeDrools2() throws DroolsParserException, IOException
{
System.out.println("Reached point 2J");
PackageBuilder packageBuilder = new PackageBuilder();
String ruleFile = "Rules.drl";
InputStream resourceAsStream = getClass().getResourceAsStream(ruleFile);
System.out.println("Reached point 3");
String result = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8);
System.out.println("Reached point 3b - " + result);
System.out.println("Reached point 3C");
Reader reader = new InputStreamReader(resourceAsStream);
System.out.println("Reached point 4K");
packageBuilder.addPackageFromDrl(reader);
System.out.println("Reached point 5");
org.drools.core.rule.Package rulesPackage = packageBuilder.getPackage();
RuleBase ruleBase = RuleBaseFactory.newRuleBase();
ruleBase.addPackage(rulesPackage);
WorkingMemory workingMemory = ruleBase.newStatefulSession();
Product product = new Product();
product.setType("South");
System.out.println("Original product " + product.getType()+ "'s coupon code is " + product.getCouponCode());
//Working Memory
workingMemory.insert(product);
workingMemory.fireAllRules();
System.out.println("The coupon code for the product " + product.getType() + " is " + product.getCouponCode());
}
}
Output
Though I added the fact and rule in memory, looks like the rules are not fired with “fireAllRules” call. How to make this rule firing? Is the stateful
session causing this issue (with “newStatefulSession” ) ?
I think you based your code in this example.
After reviewing both code snippets, I think the problem with your code is related to this debug related code fragment:
System.out.println("Reached point 3");
String result = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8);
System.out.println("Reached point 3b - " + result);
System.out.println("Reached point 3C");
Note that with that code fragment you are consuming the InputStream
that points to the rules definition file obtained here:
String ruleFile = "Rules.drl";
InputStream resourceAsStream = getClass().getResourceAsStream(ruleFile);
As a consequence, no rules are associated with your rule package when running this code fragment:
Reader reader = new InputStreamReader(resourceAsStream);
System.out.println("Reached point 4K");
packageBuilder.addPackageFromDrl(reader);
and that causes the wrong behavior you see later when trying activating then.
Please, as stated, to solve the problem, consider comment that debug code fragment:
package com.abc.main;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.drools.compiler.compiler.DroolsParserException;
import org.drools.compiler.compiler.PackageBuilder;
import org.drools.core.RuleBase;
import org.drools.core.RuleBaseFactory;
import org.drools.core.WorkingMemory;
public class Class6 {
public static void main(String[] args) throws DroolsParserException,IOException
{
Class6 droolsTest = new Class6();
System.out.println("Reached point 1A");
droolsTest.executeDrools2();
}
public void executeDrools2() throws DroolsParserException, IOException
{
System.out.println("Reached point 2J");
PackageBuilder packageBuilder = new PackageBuilder();
String ruleFile = "Rules.drl";
InputStream resourceAsStream = getClass().getResourceAsStream(ruleFile);
/*System.out.println("Reached point 3");
String result = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8);
System.out.println("Reached point 3b - " + result);
System.out.println("Reached point 3C");*/
Reader reader = new InputStreamReader(resourceAsStream);
System.out.println("Reached point 4K");
packageBuilder.addPackageFromDrl(reader);
System.out.println("Reached point 5");
org.drools.core.rule.Package rulesPackage = packageBuilder.getPackage();
RuleBase ruleBase = RuleBaseFactory.newRuleBase();
ruleBase.addPackage(rulesPackage);
WorkingMemory workingMemory = ruleBase.newStatefulSession();
Product product = new Product();
product.setType("South");
System.out.println("Original product " + product.getType()+ "'s coupon code is " + product.getCouponCode());
//Working Memory
workingMemory.insert(product);
workingMemory.fireAllRules();
System.out.println("The coupon code for the product " + product.getType() + " is " + product.getCouponCode());
}
}
As an alternative, if you prefer to keep your debug traces, you can try building the Reader
passed as argument to addPackageFromDrl
in the following way:
Reader reader = new StringReader(result);
System.out.println("Reached point 4K");
packageBuilder.addPackageFromDrl(reader);
System.out.println("Reached point 5");
Please, note the use of StringReader
. The entire code fragment:
package com.abc.main;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.drools.compiler.compiler.DroolsParserException;
import org.drools.compiler.compiler.PackageBuilder;
import org.drools.core.RuleBase;
import org.drools.core.RuleBaseFactory;
import org.drools.core.WorkingMemory;
public class Class6 {
public static void main(String[] args) throws DroolsParserException,IOException
{
Class6 droolsTest = new Class6();
System.out.println("Reached point 1A");
droolsTest.executeDrools2();
}
public void executeDrools2() throws DroolsParserException, IOException
{
System.out.println("Reached point 2J");
PackageBuilder packageBuilder = new PackageBuilder();
String ruleFile = "Rules.drl";
InputStream resourceAsStream = getClass().getResourceAsStream(ruleFile);
System.out.println("Reached point 3");
String result = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8);
System.out.println("Reached point 3b - " + result);
System.out.println("Reached point 3C");
Reader reader = new StringReader(result);
System.out.println("Reached point 4K");
packageBuilder.addPackageFromDrl(reader);
System.out.println("Reached point 5");
org.drools.core.rule.Package rulesPackage = packageBuilder.getPackage();
RuleBase ruleBase = RuleBaseFactory.newRuleBase();
ruleBase.addPackage(rulesPackage);
WorkingMemory workingMemory = ruleBase.newStatefulSession();
Product product = new Product();
product.setType("South");
System.out.println("Original product " + product.getType()+ "'s coupon code is " + product.getCouponCode());
//Working Memory
workingMemory.insert(product);
workingMemory.fireAllRules();
System.out.println("The coupon code for the product " + product.getType() + " is " + product.getCouponCode());
}
}
Which outputs:
In any case, to make the example work you will need to change your rules file and use type
instead of RegionName
as well:
package com.abc.main
import com. abc.main.Product
rule "Offer for Diamond"
when
productObject: Product(type=="South")
then
productObject.setCouponCode("B");
end
rule "Offer for Gold"
when
productObject: Product(type=="North")
then
productObject.setCouponCode("C");
end
Note that Drools uses JavaBeans conventions to access model properties, al least I always took it for sure: like in C#, the property is defined by the combination of a read (get
) and write (set
) optional methods but, in contrast, in Java you need to explicitly include the property name in the get
and set
methods. for instance, for defining the property type
in Product
you need to define the proper getType
and/or setType
methods. The name of the internal variable used to hold the property value, in your example, RegionName
, doesn't actually matter. By convention in Java you will use always camel case syntax for property names, with the first letter being lowercase, not uppercase such as in C#.
As described, the use of the stateful session is not related to the problem.
Having said all that, as pointed out by @RoddyoftheFrozenPeas in his comment, you could let Drools trying finding the different rules defined in your classpath. You can follow his answer as reference. This Github repository provides great guidance as well for this and other stuff.
Please note that the last references provided use the new KIE APIs instead of the old Drools ones that you are using. This excellent blog post provides a great introduction about the change.
If, as you mentioned, you are learning Drools, the aforementioned blog contains posts of very good quality that could be of help. Drools itself provides an excellent documentation and additional help resources too.