I'm trying to collect some objects in drools using this code:
rule "Evalua Anexo 10" salience 300 when
jul: ArchJuliano()
reg551: Registro551( fraccAne10 : getFraccion() ) from jul.getListReg551()
exists ( Anexo10( getFraccion() == fraccAne10 ) from jul.getListFraccAne10() )
then
// get pojo reg551
end
The above rule will fire once for each Registro551 when fraccAne10 exists in jul.getListFraccAne10. However, I want to get a list of Registro551 instead only the object.
rule "Evalua Anexo 10" salience 300 when
jul: ArchJuliano()
listOfReg551: List() from collect (
Registro551( fraccAne10 : getFraccion() ) from jul.getListReg551()
exists ( Anexo10( getFraccion() == fraccAne10 ) from jul.getListFraccAne10() )
)
then
// trying to get List<Registro551>
// fires error: mismatched input 'exists' in rule name-of-rule
end
facts:
public class Anexo10 {
private String fraccion;
// getters and setters
public class Registro551 {
private String fraccion;
// getters and setters
public class ArchJuliano {
private List<Anexo10> listFraccAne10;
private List<Registro551> listReg551;
// getters and setters
thank you very much.
rule "Evalua Anexo 10"
when
jul: ArchJuliano( $lAne: listFraccAne10, $lReg: listReg551 )
accumulate( Anexo10( $fA: fraccion ) from $lAne;
$fraccionsA: collectSet($fA) )
accumulate( Registro551( $fR: fraccion memberOf $fraccionsA ) from $lReg;
$fraccionsR: collectList($fR) )
then
...List<Registro551> $fraccionsR...
end
(I haven't tested this.)
Related
I tried to insert a value into a Hashmap() but my test case fails when I tried to put the result of an accumulate function($totals in the drl file) as the value of the Hashmap. I've also tried Integer.valueOf($totals) instead of $totals without luck.
My drl file contains:
rule "calculate total per item"
no-loop
when
$o : Order( $lines : orderLines)
$ol : OrderLine(this memberOf $lines.values() , quantity > 0)
$totals : Number(intValue > 0) from accumulate (
OrderLine($qty : quantity, item.barcode == $ol.getItem().getBarcode()) from $lines.values(),
sum($qty)
)
then
System.out.println("total: " + $totals); //prints out total: 7.0
modify($o){
getPerItems().put($ol.getItem().getBarcode(), $totals); //this line throws an error
//getPerItems().put($ol.getItem().getBarcode(), 1 ); // If I replace $totals with a number, it works
}
end
My Order class
public class Order {
private HashMap<Integer, OrderLine> orderLines = new HashMap<Integer, OrderLine>();
private HashMap<String, Integer> perItems = new HashMap<String, Integer>();
...
public HashMap<String, Integer> getPerItems() {
return perItems;
}
}
Any advice to overcome this issue?
Try this binding:
Number($totals : intValue > 0)
It would help if you add the error message verbatim to your question.
"Throws an error" - does it mean "throws an exception" or "reports an error". When and where ...?
How to define variable and add values to it inside DRL file that can be used between the rules as a static resource.
I tried to use global keyword but when add I add values to it i will not be effected inside Working Memory as it mentioned in documentation. And in my case i conn't add it from Application side.
Example :
global java.util.List myList;
function java.util.List initMyList() {
List list = new ArrayList();
list.add(1);
return list;
}
rule "initListRule"
salience 1001
when
eval(myList == null)
then
myList = initMyList();
end
rule "checkIfListIsStillEmptyRule"
salience 1000
when
eval(myList != null)
then
System.out.println("MyList is Not null");
end
as global are not stored in woking memory then myList will be always null as it is not provided from Application side. is there any alternative to define variables and fill them in DRL ?
A DRL global is not evaluated dynamically and therefore your rule "checkIfListIsStillEmptyRule" will not fire.
You can do
rule "initListFact"
when
not List()
then
insert( new ArrayList() );
end
rule "checkThatThereIsAnEmptyList"
when
$list: List( size == 0 )
then
modify( $list ){ add( "something" ) }
end
If you don't need to observe changes of a global you can initialize it in a rule with very high salience. It will be available as a resource but you cannot base rule conditions on its state.
global list myList
rule "initListRule"
salience 9999999999
when
then
myList = new ArrayList();
end
You can use more than one global:
global List myListOne
global List myListTwo
rule "initListsRule"
salience 9999999999
when
then
myListOne = new ArrayList();
myListTwo = new ArrayList();
end
If you need to react to changes, there's no way around facts.
declare NamedList
name: String
list: ArrayList
end
rule createListOne
when
not NamedList( name == "one" )
then
insert( new NamedList( "one", new ArrayList() ) );
end
rule "checkIfListOneIsStillEmpty"
when
$nl: NamedList( name == "one", eval( list.size() == 0 ) )
then
modify( $nl ){vgetList().add( "something" ) }
end
I am trying to execute the rules written in Kie workbench and integrated with Kie Exceution server and got the response as expected .
But my rquirement is to execute only one specific rule for list of large rules defined. What are the possible ways I can achieve .
I used Activation Group , rule flow group but no luck If any one can help me to achieve this .
I created Guided Decision table in KIE Workbench . and source was generated in this way
package demo.drools_examples;
//from row number: 1
rule "Row 1 Rule1"
dialect "mvel"
when
f1 : Account( accountType == "Regular" )
then
f1.setBaseAmount( 10.0 );
f1.setBaseThreshold( 10.0 );
calculateAmount(f1);
calculateThreshold(f1);
end
//from row number: 2
rule "Row 2 Rule1"
dialect "mvel"
when
f1 : Account( accountType == "Registered" )
then
f1.setBaseAmount( 5.0 );
f1.setBaseThreshold( 15.0 );
calculateAmount(f1);
calculateThreshold(f1);
end
//from row number: 3
rule "Row 3 Rule1"
dialect "mvel"
when
f1 : Account( accountType == "Saving" )
then
f1.setBaseAmount( 20.0 );
f1.setBaseThreshold( 10.0 );
calculateAmount(f1);
calculateThreshold(f1);
end
How can I define saliance , Activation group or any other policy to call only rule 1 rather than calling fireallRules(1).. Please help me
You'll have to call fireAllRules, but with a twist:
AgendaFilter af = new SingleRuleFilter( "Row 1 Rule1" );
int nFired = kieSession.fireAllRules( af );
And you only need to write something like this:
public class SingleRuleFilter implements AgendaFilter {
private String name;
public SingleRuleFilter( String name ){
this.name = name;
}
public boolean accept( Activation activation ){
return activation.getRule().getName().equals( name );
}
}
facing problem with List iteration in drools
GoodsShipment has the list of GoodsItems and
GoodsItem has the list of Documents
my requirement is, need to check atleast one document is available or no.
iam tried this
but failed
writen a class to checking purpose
public class CheckDocument {
public boolean flag = false;
public CheckPreviousDocument() {
}
public boolean getPreviousDocument(GoodsShipment goodsshipment) {
List<GoodsItem> list = goodsshipment.getGoodsItems();
Iterator<GoodsItem> itr = list.iterator();
while (itr.hasNext()) {
GovernmentAgencyGoodsItem document = itr.next();
if (document.getDocuments().size() > 0) {
flag = true;
break;
}
}
return flag;
}
}
rule "previousDocuments minimum 1"
when
$o: GoodsShipment()
%x: CheckPreviousDocuments(previousDocuments($o) == false)
then
insert(-------------)
end
can anyone please help me..
thanks in advance
Your code is somewhat unusual, but thus rule should do. Note that I have used Document as the type for the elements in the list returned by GovernmentAgencyGoodsItem.getDocuments().
rule atLeastOne
when
$gs: GoodsShipment()
List( size > 0 )
from accumulate ( $gi: GoodsItem() from $gs.getGoodsItems() and
$d: Document() from $gi.getDocuments();
collectList( $d ) )
then
// $gs contains at least one Document
end
The the following logic:
if (order.getPrice()<200 ) {
order.setPrice(order.getPrice()-10);
} else {
order.setPrice(order.getPrice()-20);
if (order.getPrice()<200 ) {
//do nothing
}else {
order.setFreeShip("true");
}
}
for above logic, if I want to implement in drools rule.
rule "rule 1"
when
$o:Order ( amount<200);
then
$o.setPrice($o.getPrice()-10);
end
rule "rule 2"
when
$o:Order (amount>200);
then
$o.setPrice($o.getPrice()-20);
end
If the fact's price is 210, the rule2 is activated then the rule1 will be fired. That is not expected. I don't want to retract(). So is there any better solution for this issue?
And can I specify the sequential rule once a rule is executed like a token mechanism.
Thanks.
No, you can't specify sequential for just one rule or group of rules. You'll need to create a flag and use it as a guard, for example:
rule "rule 1"
when
$o:Order ( amount<200);
not: Flag(object=$o)
then
$o.setPrice($o.getPrice()-10);
insert( new Flag($o) );
end
rule "rule 2"
when
$o:Order (amount>200);
not: Flag(object=$o)
then
$o.setPrice($o.getPrice()-20);
insert( new Flag($o) );
end
and
public class Flag {
private final Object object;
public Flag(Object o) {
this.object = o;
}
//add getter for object
//delegate equals and hashcode to object
}
rule "NYuser_Rule"
no-loop true
ruleflow-group "EvalLoopcondition"
when
m:HelloProcessModel(userlocation in ("NewYorkUser"), count < 4)
then
m.setLoopcondition(6);update(m);
end
rule "ChileUser_Rule"
no-loop true
ruleflow-group "EvalLoopcondition"
when
m:HelloProcessModel(userlocation in ("ChileUser"), count < 3)
then
m.setLoopcondition(5);update(m);
end
Something like this can help you out.