i need declare a new type in my drl like this example.
package com.sample
import com.sample.DroolsTest.Message;
declare Variavel
valor : Integer
end
rule "Hello World"
when
m : Message( status == Message.HELLO, myMessage : message )
-----> v : Variavel() Problem here, the variable is not instantiated
then
System.out.println( myMessage );
m.setMessage( "Goodbye cruel world" );
m.setStatus( Message.GOODBYE );
update( m );
end
rule "GoodBye"
when
Message( status == Message.GOODBYE, myMessage : message )
then
System.out.println( myMessage );
end
My problem: I want use the variable without put this code
FactType personType = kbase.getFactType( "com.sample","Variavel" );
Object test = personType.newInstance();
ksession.insert(test);
Its possible use the declared field without put this code when i fire the rule, like a static field?
A type declaration in Drools is like declaring a class in Java. You have the type there, but no instances. What you can do is have a higher priority rule instantiate and insert it as a fact instead of having the application doing it. E.g.:
declare Variavel
valor : Integer
end
rule "create variable"
salience 100
when
then
insert( new Variavel() );
end
rule "Hello World"
when
m : Message( status == Message.HELLO, myMessage : message )
v : Variavel()
then
// do something
end
Related
I am trying to count the number of objects by using QueryResults. My rule is:
query "Test"
m : Message()
end
function int countFacts(String queryString) {
QueryResults queryResults = DroolsTest.getQueryResults(queryString);
if (queryResults != null) {
System.out.println("Total FACTS found: " + queryResults.size());
return queryResults.size();
}
return 0;
}
rule "Hello World"
when
m : Message( status == Message.HELLO, myMessage : message )
eval(countFacts("Test")>0 )
then
System.out.println( myMessage );
end
And in the java side
public static QueryResults getQueryResults(String queryName) {
System.out.println("inside queryResults for queryName " +queryName );
QueryResults queryResults = kSession.getQueryResults(queryName);
return queryResults;
}
When I am trying to run the rule, execution stops and nothing happens.
The kSession.getQueryResults(queryName) returns nothing and after some time I have to manually terminate the execution.
what is wrong here?
I think the issue here is your thread being blocked. If your requirement is to count the number of facts in your session as part of a rule, then you can do it in a much more "Drools-friendly" way using an accumulate:
rule "More than 2 HELLO messages"
when
Number(longValue > 2) from accumulate (
Message( status == Message.HELLO),
count(1)
)
then
System.out.println( myMessage );
end
If you really want to call a query from the when part of a rule, you will need to pass an unbound variable to the query in order to get the result back in your rule:
query countMessages(long $n)
Number($n:= longValue) from accumulate (
Message(),
count(1)
)
end
rule "Hello World"
when
m : Message( status == Message.HELLO, myMessage : message )
countMessages($n;)
eval($n > 0)
then
System.out.println( m );
end
Hope it helps,
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.)
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 );
}
}
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.