I keep getting compile errors when I try to write my rules.
I am trying to translate this condition into drools
if(model.type.series != null && model.type.series.name.mathes(".*FANR.*") ||
model.type.series.name.matches(".*SANA.*"))
//do something....
This is what I have...
rule "Rule 01" salience 0
when
m : model(type.series != null,
type.series.name.matches(".*FANR.*") ||
type.series.name.matches(".*SANA.*")
a : Result(state == Result.GOOD )
then
a.setState(RESULT.BAD);
....
end
What I was trying to do is to use regular expression to match the part of the string where the 'name' is String type. As I am fair new to drools I don't see where it can cause problems, any help would be appreciated
Use correct Drools syntax, according to the matches operator, as described in the Drools manual.
rule FANRorSANA
when
$n: model($v: type.series.name matches ".*(FANR|SANA).*")
then
And you can use the power of regular expressions for testing alternatives.
Related
I am trying to write a drools rule that would check if a student has an average of more than 5 at a discipline and i get this error whenever i try to run a static method in the when clause. Moreover, i couldn't find in the drools documentation if it's possible to call a static method in the when section.
This is the rule :
rule "student with at least two grades and average less than 5" salience 8
when
$student : Student(grades.size() >= 2)
$list : ArrayList() from eval(computeAverageGrade($student))
$value : Double() from $list
Boolean(booleanValue() == true) from $value < 5.0
then
System.out.println(2);
student.setValid(false)
end
This is the method's header:
public static List<Double> computeAverageGrade(Student student)
and this is the error i am getting :
Caused by: org.mvel2.PropertyAccessException: [Error: null pointer or function not found: eval]
[Near : {... eval(computeAverageGrade($stud ....}]
^
[Line: 1, Column: 1]
The error explains what's wrong: that's not how you use eval.
Unlike other languages like Javascript, eval doesn't execute arbitary code and return a value: it executes arbitrary code and evaluates a boolean.
You should have declared $list like this:
$list: ArrayList() from computeAverageGrade($student)
$value : Double(this < 5.0) from $list
An example for how you'd use eval, would be to evaluate some sort of truthiness from arbitrary code ... for example like this:
eval( $someValue < someExampleFunctionCall() )
Of course you should always avoid the use of eval because Drools is very good at simplifying conditions for efficient processing, and eval forces it to evaluate your code as-written, thus losing all efficiencies/performance improvements the engine could otherwise give you.
Almost any place you can use eval can be rewritten in a better way -- the example above can, for instance, be rewritten as Double(this > $someValue) from someExampleFunctionCall().
Solved it by replacing ArrayList with Object() and removing eval from the static method call.
found it here : https://docs.drools.org/7.73.0.Final/drools-docs/html_single/index.html#drl-rules-WHEN-con_drl-rules
I'm working on writing a rule set in Drools and the following situation causes an infinite loop by retriggering the rule:
rule "My Rule"
when
a1:ObjectA()
b1:ObjectB(field1 > 0 || a1.field1 in (1,2,3))
ObjectB(field2 > 10)
then
modify( b1 ) { setField3(5) };
end
The following rule change doesn't result in an infinite loop, i.e., when a1 is no longer referenced within ObjectB:
rule "My Rule"
when
b1:ObjectB(field1 > 0 || field4 in (1,2,3))
ObjectB(field2 > 10)
then
modify( b1 ) { setField3(5) };
end
Another scenario which doesn't cause an infinite loop is when I change the || to an && in the second when line:
rule "My Rule"
when
a1:ObjectA()
b1:ObjectB(field1 > 0 && a1.field1 in (1,2,3))
ObjectB(field2 > 10)
then
modify( b1 ) { setField3(5) };
end
From the Drools docs I understand that calling modify(){} will "trigger a revaluation of all patterns of the matching object type in the knowledge base," but since the field I'm modifying, field3, isn't used in the LHS conditions, I didn't think it should reevaluate. However, I am faily certain it has to do with referencing a1.field1 within ObjectB, but I can't find a concrete reason why. Thanks in advance!
It matters at the object level, not the field level. Since you modify a1, the rule is re-evaluated because it relies on the ObjectA objects in working memory. Note that the docs indicate it will "trigger a reevaluation of all patterns of the matching object type in the knowledge base." Not the parameter values.
One way you could avoid this would be to add a constraint like field3 != 5 on the left hand side. That is:
rule "My Rule"
when
a1: ObjectA( field3 != 5 ) // <-- if field3 is already 5, don't fire the rule
b1: ObjectB(field1 > 0 || a1.field1 in (1,2,3))
exists(ObjectA(field2 > 10))
then
modify( a1 ) { setField3(5) };
end
Basically you need to make the rule no longer eligible for re-fire.
Alternatively, depending on your structure you could try to use no-loop, but that only keeps the rule from refiring when immediately triggered by the right hand side. If you have multiple modifications/updates/etc going on, you could get into a "broader" looping scenario where multiple rules cause reevaluation. (Example: Rule A does a re-evaluate, no-loop keeps A from firing again; then B causes re-eval, so A can trigger because no-loop does not apply.)
I want to use the Mule Expression Language to send two input parameters to an API (ex: CodePostal and LibelleVoie).
I do that :
[payload[1].getAdresseNonNormalisee().getObjetAttributs().getCodePostal()] && #[payload[1].getAdresseNonNormalisee().getObjetAttributs().getLibelleVoie()]]
But it does not work, it returns me a String
have you an idea please ?
You have to write everything in one MEL expression:
#[payload[1].getAdresseNonNormalisee().getObjetAttributs().getCodePostal() &&
payload[1].getAdresseNonNormalisee().getObjetAttributs().getLibelleVoie()]]
You used two expressions with some String in between: " && "
I want to evaluate facts dynamically using drool engine. Rule conditions attributes & their conditional operators are stored in database and load in to WM when engine start.
So I want to use that operator in rule file as below.
$dynCx : DynCustomer()
$attrib : Attribute() from $dynCx.attributes
$offer : Offer($ofCode : offer_code, $domainName : domainName )
$rdef : OfferRuleDef($entity : entity,
$code : code,
$value : value,
$atrName : attributeName,
$atrVal : attributeVal,
$op : operation,
$entity == $domainName,
$code == "OFFER_CODE",
$value == $ofCode,
$atrName == $attrib.name,
$atrVal $op $attrib.value
)
but I'm getting below error
Caused by: java.lang.RuntimeException: [59,14]: [ERR 102] Line 59:14 mismatched input '$op' in rule "Evaluate Generic Offer Eligibility"
[0,0]: Parser returned a null Package
How we can achieve this?
Operators can't be resolved at runtime, so you can't write that kind of rule. Based on the version you are using and the number of operators you envision, you have a few options.
1) Write a rule for each operator:
OfferRuleDef( ..., operator == "==", attributeVal == $attrib.value )
to avoid excessive code repetition, consider that rules can "extend" each other.
2) In recent versions, create a static helper function and pass the three values:
OfferRuleDef( ..., MyHelper.applyOperator($attrValue, $op, $attrib.value) )
I use java and a regexp.
I've made a regexp for password validation :
String PASSWORD_PATTERN_ADVANCED = "^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[\\\\##$¤£µ§%&<>,.!:?;~{-|`'_^¨éèçàù)=}()°\"\\]\\[²³*/+]).{8,20}$";
or without the extra slash :
^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[\\##$¤£µ§%&<>,.!:?;~{-|`'_^¨éèçàù)=}()°"\]\[²³*/+]).{8,20}$
whuch means (i may be wrong): at least one digit / at least one lowercase / at least one uppercase / at least one of the special chars listed / with a minimum total length of 8 and a max of 20...
made a test case generating password for success and failure...
success -> OK, all passed
failure -> Almost OK ...
The only password that fails to fail :D are the ones with space in it like :
iF\ !h6 2A3|Gm
¨I O7 gZ2%L£k vd~39
2< A Uw a7kEw6,6S^
cC2c5N#
6L kIw~ Béj7]5
ynRZ #44ç
9A `sè53Laj A
s²R[µ3 9UrR q8n
I am puzzled.
Any thoughts to make it works ?
Thanks
A regex may not be the right tool for the job here.
Regexes are best suited for matching patterns; what you're describing isn't really a pattern, per se; it's more of a rule set. Sure, you may be able to create some regex that helps, but it's a really complex and opaque piece of code which make maintenance a challenge.
A method like this might be a better fit:
public boolean isValidPassword(String password) {
boolean containsLowerCase;
boolean containsUpperCase;
boolean containsInvalid;
boolean containsSpecialChar;
boolean containsDigit;
for(char c: password.toCharArray()) {
containsLowerCase ||= Character.isLowerCase(c);
containsUpperCase ||= Character.isUpperCase(c);
containsDigit ||= Character.isDigit(c);
containsSpecialChar ||= someMethodForDetectingIfItIsSpecial(c);
}
return containsLowerCase &&
containsUpperCase &&
containsSpecialChar &&
containsDigit &&
!containsInvalid &&
password.length >=8 && password.length <=20;
}
You'd need to decide the best way to detect a special character (specialCharArray.contains(c), regular expression, etc).
However, this approach would make adding new rules a lot simpler.
I may be wrong but if you simply don't want spaces then use [^\\s] instead of . in your lookahead.
String PASSWORD_PATTERN_ADVANCED =
"^(?=[^\\s]*\\d)"
+ "(?=[^\\s]*[a-z])"
+ "(?=[^\\s]*[A-Z])"
+ "(?=[^\\s]*[\\\\##$¤£µ§%&<>,.!:?;~{-|`'_^¨éèçàù)=}()°\"\\]\\[²³*/+])"
+ ".{8,20}$";
None of your conditions are stating what can't be in the password, only what must. You need one more condition that combines all the possible valid characters and makes sure all characters in the password are in that list (i.e., (\d|[a-z]|[A-Z]|##$...){8,20} as the final condition). Either that or a list of rejected characters.