Using declare statement in drl files - drools

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.

Related

lock-on-active not working as expected

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,

Drools Instanceof with Inheritance

I have 5 fact types: BaseFact, AFact, BFact, CFact and DFact.
AFact, BFact, CFact and DFact all inherit from BaseFact.
I have some rules that run on BaseFacts, that I can no longer run on CFacts or DFacts.
What is the best way to modify my BaseFact rules so that they only run on BaseFacts, AFacts and BFacts.
Is there some sort of instanceOf function I can check, like the following?
rule "BaseRule"
when
fact : BaseFact(this instanceOf AFact || this instanceOf BFact)
...
then
...
end
Or do I need to split this rule into 2 new rules, for AFact and BFact?
Even if there is no instanceOf operator, there are several ways to achieve what you are looking for.
These are some ideas:
rule "BaseRule"
when
fact : BaseFact(class == AFact.class || == BFact.class)
...
then
//note that the variable fact is still of type BaseFact
...
end
A nastier version:
rule "BaseRule"
when
fact : BaseFact()
not CFact(this == fact)
not DFact(this == fact)
...
then
//note that the variable fact is still of type BaseFact
...
end
Or:
rule "BaseRule"
when
AFact() OR
BFact()
...
then
//note you can't bind a variable to AFact or BFact
...
end
If you only have 2 concrete types you want to match, then having 2 individual rules doesn't sound like a bad idea either.
Hope it helps,
Quick update: I was also able to use:
rule "MyRow"
dialect "mvel"
when
f1 : Wrapper( eval( nestedProperty#MyNestedClass ), ... )
then
...
end
Which is handy for testing classes of (nested) properties.

Get LHS in drools 6.5 to show in taskform

We have a situation where if rule fails, we need to show what condition is failed. For that I need to show LHS of a particular rule. How can we do that in drools6.5. I am using it in jbpm6.5. Please help.
import java.lang.Number;
rule "parent"
#author(rupesh)
dialect "mvel"
ruleflow-group "grp"
when
obj : Player( totalWinnings >= 10.0 )
then
System.out.println(drools.getRule().getMetaData());
System.out.println(drools.getRule().getMetaAttributes());
System.out.println(drools.getRule());
end
I am not able to get LHS in sysout.
I am assuming that you want to see the LHS values when a rule is not activated to understand why it happened.
To do that, create a function like this:
function boolean debug(double x) {
System.out.println("lhs_debug(): "+x);
return true;
}
and then modify the rule to use it, like this:
rule "parent"
when
obj : Player( debug(totalWinnings), totalWinnings >= 10.0 )
then
System.out.println("activated: "+obj.totalWinnings);
//do something
end
This will show you all attempts to activate the rule and will help you debug when it was not activated.
Please note that it will be very verbose and time consuming, so it should be removed after debugging.

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```