Drools rules with boolean variable - drools

I want to declare a boolean variable in my drl file and wants to write a rule based on the value of that variable. I am not able to find any good example for this.
I tried like:
declare Flag
flag: Boolean
end
In one of the rule, I am modifying like:
flag = Boolean.TRUE;
and my rule is:
rule "<210> Determine flag"
when
Flag(flag == true)
...
end
But it is giving me error as flag cannot be resolved.

You cannot declare variables in the usual way as (I think) you are trying to do. Please read the Drools documentation and distinguish binding variables, global variables, facts and their fields and right hand side local variables (as within a static Java method).
To see how declare with a boolean field works, use the following DRL code:
declare Flag
flag: Boolean
end
rule "hoist a Flag"
when
not Flag()
then
insert( new Flag( true ) );
end
rule "a true Flag"
when
Flag( flag )
then
System.out.println( "The Flag.flag is true." );
end

You can use the following:
rule "Test"
when
a: TestClass( getFlag())
then
//some action
end
Also see this answer: Drools Rule - writing rule against boolean field, name starting with "is"

Related

Are Ada function arguments evaluated if the body is empty?

According to this statement :
Trace.Debug("My String" & Integer'Image(x) & "is evaluated" & "or not" & "if my logger is disabled ?" & Boolean'Image(YesOrNo) );
And this implementation of Trace.Debug:
procedure Debug (Message : in String) is
begin
if Logger.Enabled then -- This boolean is defined during runtime by reading a value in a file
Put_Line(Message);
else
null; -- Do nothing
end if;
end Debug;
I have a software which can manage several levels of logs, and I would like to know what is the behavior in case of Logger.Enabled equals False.
I have a lot of logs calls, with sometimes complex strings to evaluate and I'm on a real time system, so I don't want to lost time to evaluate a string which will not printed.
I would like to know if compiler optimize the code in order to not evaluate the string in parameter of Trace.Debug while Logger.enabled is False, knowing that this boolean is set at the begging of runtime by reading a value in a file.
I am using gnat 7.3.2.
You can ensure that evaluation doesn't happen by providing a callback:
procedure Debug (Message : access function return String) is
begin
if Logger.Enabled then
Put_Line(Message.all);
end if;
end Debug;
Then to call it, do
declare
function Msg return String is
("My String" & Integer'Image(x) & "is evaluated" & "or not" & "if my logger is disabled ?" & Boolean'Image(YesOrNo));
begin
Debug (Msg'Access);
end;
In your original code, the only way that the compiler could skip the evaluation is when it inlines the Debug procedure and re-arranges the code so that the Message object is only assigned inside the if-block. You cannot force this; even pragma Inline is only a hint for the compiler.

Drools trigger one rule per item in list input for StatelessKieSession

I am using decision tables and would like to trigger one rule per input item.
I am using decision have set the Sequential = true and defined all rules as part of the same ACTIVATION-GROUP.
When I trigger the drools rules engine using below it just evaluates for the first input item and others are ignored. The behavior I want is to evaluate at most 1 rule per input item (rule order defined by the Salience).
kieStatelessSession.execute(inputList)
I can get this working by sending one item at a time to the kieStatelessSession, but would prefer to execute all at once.
I am using Drools verison 6.5.0.FINAL and Java 7.
There is no out of the box support in Drools for what you are trying to achieve. If you want your rules to be evaluated once for each fact, you will need to code it yourself.
One approach could be to have another type of facts to mark when one of the inputs is processed:
declare Marker
fact : Object
end
//Bellow are the rules that should be coming from your decision table.
//Each rule will do whatever it needs to do, and then it will create a
//Marker fact for the fact that was processed.
//These rules now include a "not" Conditional Element to avoid a fact to be
//evaluated more than once.
rule "Rule 1"
salience 100
when
$fact: Object(...) //your conditions
not Marker(fact == $fact)
then
//... Your logic
insert(new Marker($fact));
end
...
rule "Rule 50"
salience 50
when
$fact: Object(...) //your conditions
not Marker(fact == $fact)
then
//... Your logic
insert(new Marker($fact));
end
Hope it helps,

Drools if and else based on condition from another rule

I want to run a rule that calls Java method and passes the fact (or rather, its logical value) from another rule, although I don't know if the java methods are at all important for this problem. It's not easy to describe so I'll try to show it based on an example:
rule "Some rule determining fact"
when
... //some conditions
then
insert(new SomeCondition(callSomeJavaMethodReturningBoolean()))
end
rule "Some rule using SomeCondition"
when
SomeCondition($value: value)
... //some other conditions
then
insert(callJavaMethodUsingSomeCondition($value))
end
The problem here is that the first rule doesn't always fire, so SomeCondition is not always definded and second rule isn't evaluated.
My second try was to create two separate rules like this:
rule "Some rule determining fact"
when
... //some conditions
then
insert(new SomeCondition(callSomeJavaMethodReturningBoolean()))
end
rule "SomeConditionTrueRule"
when
SomeCondition(value == true)
... //some other conditions
then
insert(callJavaMethodUsingSomeCondition(true))
end
rule "SomeConditionFalseRule"
when
not SomeCondition() or SomeCondition(value == false)
... //some other conditions
then
insert(callJavaMethodUsingSomeCondition(false))
end
This doesn't work as intended either, because it first evaluates SomeConditionFalseRule before even evaluating my first rule. I'll appreciate any suggestions on how to solve this problem. Drools version used is 6.5.0 if that matters. Also, I want to avoid using salience if possible since I've read it is a bad practice (correct me if I'm wrong).
In this case, you need to separate the 2 groups of rules (the ones inserting SomeCondition objects and the ones executing the java code).
The easiest way would be to use a lower salience in the second group:
rule "Some rule determining fact"
when
... //some conditions
then
insert(new SomeCondition(callSomeJavaMethodReturningBoolean()))
end
rule "SomeConditionTrueRule"
salience -1
when
SomeCondition(value == true)
... //some other conditions
then
insert(callJavaMethodUsingSomeCondition(true))
end
rule "SomeConditionFalseRule"
salience -1
when
not SomeCondition() or SomeCondition(value == false)
... //some other conditions
then
insert(callJavaMethodUsingSomeCondition(false))
end
A more robust approach would be to use 2 agenda-groups and to activate them one after the other.
But the idea is that the rules executing the java code give time to the rules determining what needs to be executed to come up with the final decision.
In the case I've presented above, as soon as you create your session, you will have an activation (A1) for SomeConditionFalseRule but the activation will not be executed until you call fireAllRules(). If you then insert the necessary facts to make SomeConditionTrueRule true, you will have now an activation (A2) for it.
At this point, the agenda will look like this: | A1 | A2 |.
When calling fireAllRules(), Drools will pick the activation in the agenda with the higher salience (by default, rules have a salience of 0). In this case, A2 will be picked and executed.
The execution of A2 will insert a new Fact that will make A1 invalid and it will create a new activation (A3) for SomeConditionTrueRule. Drools will then proceed to remove A1 from the agenda, so the rule SomeConditionFalseRule will not be executed.
The agenda after A2 is executed will look like this: | A3 |
Hope it helps,

Boolean flags handing in Drools conditions

We are working on a monitoring application in which we follow the processing of a task in a set of applications.
We have a set of drools rules matching our needs but we have some performance issues (we may have easily up to 50k objects in session).
We are looking for best pactices
This question is about bloolean flag usage.
We are working to remove most of org.drools.core.rule.constraint.MvelConstraint: Exception jitting: ... warns.
We have often such warn on boolean flags.
for example in:
rule "PropagateDeprecation"
when
$parent:BaseChainStep( $parent.Deprecated )
$child:BaseChainStep( $parent.Id == $child.Parent, !$child.Deprecated )
then
modify($child){
setDeprecated(true)
}
end
we have warn on both $parent.Deprecated and !$child.Deprecated.
We would like to understand why there is such warn on boolean flags.
We would like to know also the impacts of the warn on composed conditions.
For example in:
rule "App1_TriggerExpected"
when $chainStep:App1ChainStep(
HasChain
, HasParent
, !$chainStep.Deprecated
, Status in ("error", "closed")
, Places != null
, Analysis != null)
then
..
end
if we have the warn on the first condition HasChain, how is resolved the when clause ?
Does other conditions are evaluated too (with iteration on all App1ChainStep objects) or some "index" are still used to help ?
If its matter, we are using flags as boolean (and not Boolean) to ensure false value as default.
Edit:
The problem may be linked to extended classes. In our use case we have something like:
declare BaseChainStep
parent : GUID
deprecated : boolean
end
declare App1ChainStep extends BaseChainStep
// specific App1 fields
end
BaseChainStep fields may be manipulated in rules using App1ChainStep objects or BaseChainStep objects.
rule "deprecateApp1"
when $app1:App1ChainStep( BusinessLogicCondition )
then
modify($app1) {
setDeprecated(true)
}
end
Then the deprecated flag is propagated to App1 children using "PropagateDeprecation" rule.
Boolean flag causing warn are declared in BaseChainStep class.
Although you are deviating from the conventional way of accessing attributes, this should not trigger the warning you have reported. I can't reproduce this using 6.3.0. You should add (a) the Drools version (b) the Java code for a class BaseChainStep with which the problem can be reproduced with the rule as shown.
This is another (much simpler) way of writing rules combining boolean attributes:
rule bool1
when
X( big, fast )
then
System.out.println( "big fast X" );
end
You may even use boolean operators:
rule bool2
when
X( big && ! fast )
then
System.out.println( "big slow X" );
end
Note the simple use of field name, assuming conventional naming, e.g., big for the field, isBig and setBig for the accessors.

How to instantiate local variables in decision tables

I am pretty new to drools and am given the below task.
I am inserting a few POJO into my KieSession object and am retreiving them into variables in my decision table as follows.
CONDITION CONDITION CONDITION ACTION
abc: classABC xyz: classXYZ lmn : classLMN
var1 == $param var2 == $param
1 2 3
As far as I understand, the above table would yield the following rule
when
abc:classABC(var1==1)
xyz:classXYZ(var2==2)
lmn:classLMN(var3==3)
then
some action
What I want is to get the following.
when
abc:classABC(var1==1)
xyz:classXYZ(var2==2)
lmn:classLMN(var3==3)
fgh:classFGH($var:var4) // I think this step is creating a new variable to hold value of var4
then
some action
How do I get this on a decision table ?
I tried just adding a condition column with the variable declaration as fgh :classFGH, but since there is no data to be provided in the data row, this column would be ignored. If I do, give some data, there is an error at compile time "no code sinppet at xyz column". All I need is to declare a variable that can hold the value of the object that I have passed in my main method and use that object later in a different column of my decision table.
I'm not sure I get the requirement around the decision table, but you can 'use' the firing of a rule to create new facts and insert them, with parameters from the original events. These can then be used to trigger further rules, like so (assuming var4 is boolean):
declare AllMoonsInAlignmentEvent
#role (event)
extraCheese : boolean
end
rule "Some Rule"
when
$abc:classABC(var1==1)
$xyz:classXYZ(var2==2)
$lmn:classLMN(var3==3)
$fgh:classFGH($var:var4)
then
... some action using `$var`, `$abc` etc
AllMoonsInAlignmentEvent myEvent= new AllMoonsInAlignmentEvent();
myEvent.extraCheese = $var;
insert(myEvent);
rule "With Extra Cheese"
when
$moonsAligned:AllMoonsInAlignmentEvent(extraCheese == true)
then
...
rule "Without Extra Cheese"
when
$moonsAligned:AllMoonsInAlignmentEvent(extraCheese == false)
then
...
You can get X($y:y) into a spreadsheet in two ways. First, in column 4
X($y:y /*$param*/)
and fill the column with any character you like. The other way might be in column 3 (!)
fgh:classFGH($var:var4) lmn:classLMN
var3==$param
These tricks are always a bit iffy. Rules requiring the simple "grab" of a fact aren't typical for spreadsheets and could be the first indication that you aren't pursuing the best approach.
CONDITION
fgh:classFGH
$param:var4
Comment cell
$var