lock-on-active not working as expected - jboss

Rules are not fired even Once when lock-on-active is set true. Should it be fired once? I expect the Rule 1 to be fired once when using lock-on-active.
(Note: I have added the codes used to execute the rules )
Rule
rule "Rule 1"
lock-on-active true
ruleflow-group "Group A"
when
$c: Product()
then
System.out.println("Rule 1");
modify($c)
{
setAmount(1);
}
end
rule "Rule 2"
lock-on-active true
ruleflow-group "Group A"
when
$c: Product()
then
System.out.println("Rule 2");
modify($c){
setAmount($c.getAmount()+1)
}
end
Code for executing rules
KieServices kieServices=KieServices.Factory.get();
KieContainer kieContainer=kieServices.getKieClasspathContainer();
KieSession kieSession=kieContainer.newKieSession("ksession-lockOnActive");
Product product=new Product();
product.setName("Book");
product.setAmount(5);
((InternalAgenda)kieSession.getAgenda()).activateRuleFlowGroup("Group A");
kieSession.insert(product);
kieSession.fireAllRules();
kieSession.dispose();

First of all, the ruleflow-group attribute is meant to be used when using rules as part of a business process in JBPM. Latest versions of Drools have unified the behavior of ruleflow-group and agenda-groupso it shouldn't matter which one you use (even though I would recommend to use agenda-group).
Then, the way you are using to activate a flow group doesn't seem correct to me.
This is what I would do:
1) Use agenda-group in your rules:
rule "Rule 1"
lock-on-active true
agenda-group "Group A"
when
$c: Product()
then
...
end
rule "Rule 2"
lock-on-active true
agenda-group "Group A"
when
$c: Product()
then
...
end
2) Before firing the rules, set the focus on the agenda group:
kieSession.getAgenda().getAgendaGroup("Group A").setFocus();
kieSession.fireAllRules();
That should do the trick.
The rules still look odd to me, but maybe is because you are just doing a POC. Just a reminder: you shouldn't depend on the order of your rules in your DRLs to get the expected output.
Hope it helps,

Related

How to control rule evaluation (or rule execution) stages in Drools?

I know that "salience" in Drools provides control under rule execution sequence. But above is an example of the problem when "saliences" cannot help anymore that I've faced with.
Here I have three rules being executed one after another:
rule "Rule 1"
salience 30
when
then
Resource resource1 = new Resource();
resource1.setName("Resource 1");
resource1.setAmount("5");
insert(resource1);
System.out.println("First");
end
rule "Rule 2"
salience 20
//no-loop (interesting, it doesn't lead to a loop)
when
$resource1: Resource(name == "Resource 1")
then
modify($resource1) {setAmount("20")};
System.out.println("Second");
end
rule "Rule 3"
salience 10
when
$resource1: Resource(name == "Resource 1",
Double.parseDouble(amount) > 10)
then
System.out.println("Rule is fired");
end
I expected the third rule is fired and there's a "Rule is fired" line in the console, but it is not executed.
As I understand the issue is with rules evaluation stage when all three rules are evaluated at once before execution and only then are executed according to their "salience" turn.
And on the moment of evaluation $resource1.amount is 5, that is why third rule wasn't fired. If you put a number more than 10 in the first rule the 3d rule will fire. And if you don't set amount at all - it leads to exception.
How can I solve this issue so that the 3d rule fires?
My guess is that Drools doesn't understand that the expression Double.parseDouble(amount) > 10 must be re-evaluated when you change the amount of your fact. The problem is related with the way you are writing your expression.
You can take a look at my answer in this other question. Take a look at the "Another solution" part.
What I would suggest you to do is to modify your model and add a getAmountAsDouble() method to you class so the conversion happens inside it. You will also need to annotate the setAmount() method to let Drools know that it modifies the value returned by getAmountAsDouble():
public class Resource {
private String amount;
#Modifies( { "amountAsDouble" } )
private void setAmount(String amount){
this.amount = amount;
}
private String getAmount(){
return this.amount;
}
private String getAmountAsDouble(){
return Double.parseDouble(this.amount);
}
}
Now your rule can be rewritten as:
rule "Rule 3"
salience 10
when
$resource1: Resource(name == "Resource 1",
amountAsDouble > 10)
then
System.out.println("Rule is fired");
end
Hope it helps,
Look in the docs for Agenda/activation Groups, you can control the execution of rule groups using that concept
So it was a bug and now it is fixed in one of last updates.
Here is the issue: https://issues.jboss.org/browse/DROOLS-3972
I tested the code, and rule3 is fired
drools.version 7.32.0.Final

Drools dynamic salience

global Integer rank1;
global Integer rank2;
rule "Data"
salience 10
when
req : Requests(status == "ON")
then
drools.getWorkingMemory().setGlobal("rank1", 8);
drools.getWorkingMemory().setGlobal("rank2", 6);
end
rule "1" extends "Data"
salience 8
when
req1 : Requests()
then
System.out.print("1");
end
rule "2" extends "Data"
salience 6
when
req2 : Requests()
then
System.out.print("2");
end
Here rank1 and rank2 are initialised as 0 in java code.
the output is 11112222.
i want the same output but instead of using static salience, i want it dynamic.
rule "1" extends "Data"
salience rank1
.......
but the code output is 21212121.
You need to set the globals before you insert the facts. Globals are not evaluated dynamically.
If you really need a more dynamic salience you should create a class
class Salience {
private int rank1;
private int rank2;
// ...
}
and insert a fact with appropriate values and change them as required. You'll then need the pattern added to the root rule:
rule "Data"
when
Salience( $rank1: rank1, $rank2: rank2 )
Requests(...)
then
and you can use $rank1 and $rank2 in salience attributes.
Note: Almost certainly there is a solution to your problem that can be expressed in logic and without salience, the usage which is almost always a design flaw.

EqualsIgnoreCase on Drools

I am trying to rewrite my drl from using regex to equalsIgnoreCase as I think its faster. I am not sure its faster though. However, drools doesn't like it for some reason and I get unknown error.
The one on top works, but the one using equalsIgnoreCase doesn't
rule "name"
salience 0
activation-group "flow"
dialect "mvel"
no-loop true
when
$vurderinger: Vurderinger(vurdering1909 != null &&
vurdering1909.verdi matches "(?i)^FOO$")
then
modify( $vurderinger ) { setVurdering1913(new DroolsType("SHOW")) }
end
rule "name"
salience 0
activation-group "flow"
dialect "mvel"
no-loop true
when
$vurderinger: Vurderinger(vurdering1909 != null &&
eval("FOO".equalsIgnoreCase(vurdering1909.verdi)))
then
modify( $vurderinger ) { setVurdering1913(new DroolsType("SHOW")) }
end
Can anyone spot the mistake?
Within eval, stick to Java: refer to bound variables, use getter.
when
$vurderinger: Vurderinger($v: vurdering1909 != null &&
eval("FOO".equalsIgnoreCase($v.getVerdi())))
then
Edit Not knowing the class definition, the error and the version, I advise using eval/Java, to be on the safe side, no matter what the Drools version is. For 6.3.0, you can omit eval, and it works.
when
$vurderinger: Vurderinger(vurdering1909 != null &&
"FOO".equalsIgnoreCase(vurdering1909.verdi))
then
I have given solution for decision table i.e:
javaObject.getRisk().equalsIgnoreCase("$param")
for drools rules
rule "Rule To Check String Contains"
when
Pojo(name.contains("Loans"))
then
System.out.println(drools.getRule().getName());
end
rule "Rule To Check String Equals"
when
Pojo(name.equals("Personal Loans, Insuarnce"))
then
System.out.println(drools.getRule().getName());
end
rule "Rule To Check String EqualsIgnoreCase"
when
Pojo(name.equalsIgnoreCase("Personal loans, insuarnce"))
then
System.out.println(drools.getRule().getName());
end```

Using declare statement in drl files

I am declaring a SensorMode object in the DRL file
declare SensorMode
modeOffset: Integer
end
I have set the value to modeOffset using
FactType factType=kbase.getFactType("com.yob.pestway.
valueobjects", "SensorMode");
Object nc = factType.newInstance();
factType.set(nc, "modeOffset",sensorDataVO.getModeOffset());
I need to use the modeOffset in the following rule,It gives me an error saying $mode.modeOffset is not visible.
rule "Difference in offsets"
dialect "java"
no-loop true
when
$mode:SensorMode();
$snrData : SensorDataVO(getWeightOffset().size()>0,
$initOffset:getInitialOffset());
then
System.out.println("---modeOffset---"+$mode.modeOffset);
update($snrData);
end
Can you please suggest
Two alternatives:
rule "Difference in offsets"
dialect "java"
no-loop true
when
$mode:SensorMode( $mo: modeOffset );
//...
then
System.out.println("---modeOffset---"+ $mo);
//...
end
Or:
rule "Difference in offsets"
dialect "java"
no-loop true
when
$mode:SensorMode();
//...
then
System.out.println("---modeOffset---"+ $mode.getModeOffset() );
//...
end
It's possible that dialect "mvel" is a third option, but this may depend on the Drools version you are using.

Drools ignores the rest of rules if one of rules didn't pass

I'm starting a project with Drools. My project's drl file looks like:
rule "Rule 1"
when
Item( id > 100)
// consequence implementation
rule "Rule 2"
when
Item( type == "phone")
// consequence implementation
rule "Rule 3"
when
Item( screenSize == 5)
// consequence implementation
rule "Rule 4"
when
Item( branch == "motorola")
// consequence implementation
rule "Rule 5"
when
Item( price > 200)
// consequence implementation
When Drools runs I have 5 fired rules. If an item don't pass one of 5 fire rules, I want Drools will ignore the rest 4 fired rules. Does Drools have feature for my purpose?
Another important thing is my Drools runs with AgendaFilter. Does that feature have AgendaFilter support?
First, the phrase in the title "rest of rules" seems to indicate that you think that the rules are evaluated in a certain order (e.g. as written in the file). This is not so: there is no order. Thus, if rules #1 and #2 fired (ìd > 0 and type == "phone") and screenSize != 5, rules #4 and rules #5 will still fire, or they may already have been fired.
To discover whether some fact whose class is referenced in rules 1 to 5 participates in all or some or none of these rules you'll have to create some logic of your own. For instance, declare a type/class with
class Marker {
Set<Integer> rules;
TheClassOfYourItem item;
//...
}
and insert this along with an item. Each rule would then, when firing, add its number to the set.
rule "Rule 1"
when
$item: TheClassOfYourItem(...)
$m: Marker( item == $item )
then
$m.add( 1 );
end
And a rule with low salience can then check whether the set has all/some/none elements.
Edit due to some comment: If no rule should fire unless all rules can fire: simply put all conditions into a single rule and combine all consequences.
rule "Rule 1-5"
when
Item( id > 100, type == "phone". screenSize == 5,
branch == "motorola", price > 200)
then
// ... Do what needs to be done if all five conditions are true
end