I'm working on a drools project where every .drl
file is created dynamically from velocity template
. I've written every calculation and operations to be performed after successfull condition check in the then
of .drl
file itself.
Lets assume a simple condition
rule "Rule %"
no-loop
salience 10
when
$var: Map( this["Key"] == "SomeValue" )
then
$var.put("Discount%", Do-SOME-%-CALCULATION AND PUT IT HERE)
end
rule "Rule Amt"
no-loop
salience 9
when
$var: Map( this["Key"] == "SomeValue" )
then
$var.put("DiscountAmt", Do-SOME-Amt-CALCULATION AND PUT IT HERE)
end
rule "Rule % Amt"
no-loop
salience 8
when
$var: Map( this["Key"] == "SomeValue" )
then
$var.put("Discount%", Do-SOME-%-CALCULATION AND PUT IT HERE)
$var.put("DiscountAmt", Do-SOME-Amt-CALCULATION AND PUT IT HERE)
end
To form these kind of DRL files, I've formed the velocity template like this
#set($d = "$")
rule "$rule.name $rule.type"
no-loop
salience $rule.priority
when
${d}var: Map( this["$rule.keyName"] == "$rule.keyValue" )
then
#if( $rule.type == "%" )
${d}var.put("Discount%", CODE-FOR-%-CALCULATION);
#elseif( $rule.type == "Amt" )
${d}var.put("DiscountAmt", CODE-FOR-AMT-CALCULATION);
#elseif( $rule.type == "% Amt" )
${d}var.put("Discount%", CODE-FOR-%-CALCULATION);
${d}var.put("DiscountAmt", CODE-FOR-AMT-CALCULATION);
#end
I know that last #elseif( $rule.type == "% Amt" )
can be eliminated by utilising the first two if
and elseif
by putting || $rule.type == "% Amt"
in both those conditions. But this is just an example.
Just assume I dont have any choice to simplify those 3 condition to 2 conditions but to repeat my code itself. Believe me, I've a lot more calculations and I've to repeat those codes multiple types in the velocity code. This becomes a mess overall. Because, If I've to make a small change in the formula, I've to make changes in all those repetitive codes in velocity template which will definitely lead to human errors if we've missed out the change in a repetitive code.
Thats why I've thought to wrote those formulas and calculations in Java class and simply make calls to that class in .drl
. So .drl
and .vm
In .drl
import com.package.util.RuleUtil;
rule "Rule %"
no-loop
salience 10
when
$ruleUtil: RuleUtil()
$var: Map( this["Key"] == "SomeValue" )
then
$ruleUtil.discountPer($var);
end
rule "Rule Amt"
no-loop
salience 9
when
$ruleUtil: RuleUtil()
$var: Map( this["Key"] == "SomeValue" )
then
$ruleUtil.discountAmt($var);
end
rule "Rule % Amt"
no-loop
salience 8
when
$ruleUtil: RuleUtil()
$var: Map( this["Key"] == "SomeValue" )
then
$ruleUtil.discountPer($var);
$ruleUtil.discountAmt($var);
end
In .vm
#set($d = "$")
rule "$rule.name $rule.type"
no-loop
salience $rule.priority
when
${d}ruleUtil: RuleUtil()
${d}var: Map( this["$rule.keyName"] == "$rule.keyValue" )
then
#if( $rule.type == "%" )
${d}ruleUtil.discountPer(${d}var);
#elseif( $rule.type == "Amt" )
${d}ruleUtil.discountAmt(${d}var);
#elseif( $rule.type == "% Amt" )
${d}ruleUtil.discountPer(${d}var);
${d}ruleUtil.discountAmt(${d}var);
#end
If you want to know how many times I've repeated that discount formula code, I would say a minimum of 10 times and there involves a lot more repetitions for multiple type of discount calculations. TBH, I'm getting irritated when looking at the .vm
code. Because of all those code repetitions and poor maintainability in long run. I'm wondering whether to stick with the current code (Current vm code which involves multiple code repetions and hard to maintian) Or should I move all those formula calculations to Java method by implementing my proposed structure. I don't know how much it'll affect my .drl
file performance. Any suggestions will be appreciated.
Note: I prefer code maintainability the most. I don't want someone to break his head after he has taken over this project. Ofcourse, I too don't want to break my head while making any small change.