I have been working with drools rules for a while and just recently started on a dsl to make the rule authoring easier for end users. While I have been able to get a simple dsl defined and correctly compiling into drl as expected, i cannot get the dsl feature of 'adding constraints to previous expression' to work.
I am even trying the simplest of examples from the drools dsl guide and this will not compile the Conditions i have defined beginning with '-' into the previous expression. I keep getting a 'mismatched input 'price' in rule "Rule1Sample_0" error on compiling it.
as i said I have this working for straightforward Condition expressions and Consequence expressions. but adding contraints following the docs is just not working at all.
I am using drools version 7.0.0.Final, is this something thats not supported until a later version?
in the simple example i am testing, my dsl file just contains:
[condition][]There is a {ShoppingCart} that=${ShoppingCart!lc} : ${ShoppingCart!ucfirst}()
[condition][]- total price is greater than 1000 =totalPrice > 1000
[consequence]Update {ShoppingCart}=System.out.println("{ShoppingCart}" + " test")
Here is the Condition
"There is a ShoppingCart that total price is greater than 1000"
and Action which i am specifying for the when and then part of my template:
"Action" "Update ShoppingCart"
Here is the compiled drl before I pass it to the DrlParser:
rule "Test1"
dialect "mvel"
when
"There is a ShoppingCart that total price is greater than 1000"
then
"Update ShoppingCart"
end
This is what expandedDrl string contains after above code snippet runs:
package com.sample.test
rule "Test1"
dialect "mvel"
when
$shoppingcart : $Shoppingcart() total price is greater than 1000
then
System.out.println("ShoppingCart" + " test")
end
And here is the generated drl for this when i parse it using the DRLParser:
(code snippet here, some omitted)
DrlParser parser = new DrlParser();
DefaultExpanderResolver resolver = new DefaultExpanderResolver(new StringReader(dsl));
String expandedDrl = parser.getExpandedDRL(dslr, resolver);
This is what expandedDrl string contains after above code snippet runs:
package com.sample.test
rule "Test1"
dialect "mvel"
when
$shoppingcart : $Shoppingcart() total price is greater than 1000
then
System.out.println("ShoppingCart" + " test")
end
And the compiler error i see in the console:
[[13,43]: [ERR 102] Line 13:43 mismatched input 'price' in rule "Test1" ....
Could you try condition
There is a ShoppingCart that
- total price is greater than 1000
Could you try following dsl
... business definitions
[when]complex condition = (simple condition
or another condition)
[when]simple condition = (total price is not 0)
[when]another condition = (total price greater than 10)
... field definitions
[when]total price = totalPrice
... consequences I advise to wrap in java util class each as a static method to write java code in java code
[consequence]Update {ShoppingCart}=System.out.println("{ShoppingCart}" + " test")
... tech dsl at the bottom
[when]There (is( an?)?|are) {entityType}s?( that)? = ${entityType}: {entityType}()
[when](is\s+)?not less than(\s+an?)? = >=
[when](is\s+)?less than(\s+an?)? = <
[when](is\s+)?not greater than(\s+an?)? = <=
[when](is\s+)?greater than(\s+an?)? = >
[when]((is|do(es)?)\s+)?not equals?(\s+to)? = !=
[when](is\s+)?equals?(\s+to)? = ==
[when]is not(\s+an?)? = !=
[when]is(\s+an?)? = ==
[when]like(\s+an?)? = matches
[when]{prefix}?\s*(?<![\w])and(?![\w])\s*{suffix}? = {prefix} && {suffix}
[when]{prefix}?\s*(?<![\w])or(?![\w])\s*{suffix}? = {prefix} || {suffix}
[when]{prefix}?\s*(?<![\w])not(?! (in|matches|contains|memberOf|soundslike|str))(\s+an?)?(?![\w])\s*\({suffix}? = {prefix} false == (true && {suffix}
[when]{prefix}?\s*(?<![\w])not(?! (in|matches|contains|memberOf|soundslike|str))(\s+an?)?(?![\w])\s*{suffix}? = {prefix} !{suffix}
[when](?<![^\(,])\s*- =
this should be able to process rules like
There is a ShoppingCart that
- total price is greater than 1000
- not complex condition
If you want to reuse conditions in other conditions you want them to be atomic. Good rule of the thumb to embrace RHS with braces () not to break atomicy of the record
test
@DroolsSession({ "classpath:/test.rdslr", "classpath:/business.dsl", "classpath:/keywords.dsl" })
public class PlaygroundTest {
@Rule
public DroolsAssert drools = new DroolsAssert();
@Test
public void testIt() {
drools.insertAndFire(new ShoppingCart(BigDecimal.valueOf(1000.5)));
drools.insertAndFire(new ShoppingCart(BigDecimal.valueOf(999)));
}
}
domain
public class ShoppingCart {
public BigDecimal totalPrice;
public ShoppingCart(BigDecimal totalPrice) {
this.totalPrice = totalPrice;
}
}
rdslr
rule Test1
when
There is a ShoppingCart that
- total price is greater than 1000
then
print eligible price
end
rule Test2
when
There is a ShoppingCart that
- worth a discount
then
print eligible price
end
business.dsl
[when]worth a discount =
(total price is not less than 500
and not over limit
or total price is greater than 5000)
// stupid condition just for demonstration
[when]over limit = ((total price + total price * 0.05) > total price + 50)
[when]total price = totalPrice
[then]print eligible price = System.out.println($ShoppingCart.totalPrice);
keywords.dsl
[when]There (is( an?)?|are) {entityType}s?( that)? = ${entityType}: {entityType}()
[when](is )?not within\s*\({tail}?= not in ({tail}
[when](is )?within\s*\({tail}?= in ({tail}
[when](is )?not one of\s*\({tail}?= not in ({tail}
[when](is )?one of\s*\({tail}?= in ({tail}
[when]ignore case '{tail}?= '(?i){tail}
[when]{param:[$\w\.!'\[\]]+} as {param2:[$\w\.!'\[\]]+}=(({param2}) {param})
[when](is\s+)?not less than(\s+an?)? = >=
[when](is\s+)?less than(\s+an?)? = <
[when](is\s+)?not greater than(\s+an?)? = <=
[when](is\s+)?greater than(\s+an?)? = >
[when]((is|do(es)?)\s+)?not equals?(\s+to)? = !=
[when](is\s+)?equals?(\s+to)? = ==
[when]is not(\s+an?)? = !=
[when]is(\s+an?)? = ==
[when]like(\s+an?)? = matches
[when]{prefix}?\s*(?<![\w])and(?![\w])\s*{suffix}? = {prefix} && {suffix}
[when]{prefix}?\s*(?<![\w])or(?![\w])\s*{suffix}? = {prefix} || {suffix}
[when]{prefix}?\s*(?<![\w])not(?! (in|matches|contains|memberOf|soundslike|str))(\s+an?)?(?![\w])\s*\({suffix}? = {prefix} false == (true && {suffix}
[when]{prefix}?\s*(?<![\w])not(?! (in|matches|contains|memberOf|soundslike|str))(\s+an?)?(?![\w])\s*{suffix}? = {prefix} !{suffix}
[when](?<![^\(,])\s*- =
test output
00:00:00 --> inserted: ShoppingCart[totalPrice=1000.5]
00:00:00 --> fireAllRules
00:00:00 <-- 'Test1' has been activated by the tuple [ShoppingCart]
1000.5
00:00:00 --> inserted: ShoppingCart[totalPrice=999]
00:00:00 --> fireAllRules
00:00:00 <-- 'Test2' has been activated by the tuple [ShoppingCart]
999