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 );
}
}
Related
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
Continuing from my earlier question where I described my schema (repeated here for your convenience):
Parties ( PartyId, ClientId, AddressId, DateTime )
Tents ( PartyId, TentDetails... )
Clowns ( PartyId, AddressId, ClownDetails... )
SecurityAgentAssignment ( PartyId, AgentId, fromTime, untilTime )
Addresses ( AddressId, Street, City, State )
....and there's about 10 other tables of a similar design: all in a many-to-one relationship with Parties.
My ASP.NET MVC web application has a Summary page that displays every detail about a party. I'm using EF1.0 so I have to do my own eager-loading. Here's the logic I'm using:
Party dbParty = GetParty(partyId);
dbParty.Tents.EnsureLoaded();
dbParty.Clowns.EnsureLoaded();
foreach(Clown clown in dbParty.Clowns) clown.Address.EnsureLoaded();
dbParty.Security.EnsureLoaded();
foreach(SecurityAgentAssignment assignment in dbParty.Security) assignment.Agent.EnsureLoaded();
// and the 10 other relationships too
The code above takes about 3 seconds to run. Given this isn't eager-loading, but lazy-loading, surely it should just fire off about 15 simple SELECT queries and be done?
I don't have the SQL Server Profiler installed, and I don't know how to get the SQL generated when you're using .Load instead of IQueryable.
I use these extension methods as helpers:
private static readonly R.FieldInfo _entityReferenceContext = typeof(RelatedEnd).GetField("_context", R.BindingFlags.Instance | R.BindingFlags.NonPublic );
private static readonly R.PropertyInfo _relatedEndOwner = typeof(RelatedEnd).GetProperty("Owner", R.BindingFlags.Instance | R.BindingFlags.NonPublic );
private static Boolean IsAttached(this RelatedEnd relatedEnd) {
Object context = _entityReferenceContext.GetValue( relatedEnd );
return context != null;
}
public static TEntity EnsureLoaded<TEntity>(this EntityReference<TEntity> eref) where TEntity : class, IEntityWithRelationships {
// EntityReference<TEntity> derives from RelatedEnd.
RelatedEnd erefAsRelatedEnd = (RelatedEnd)eref;
erefAsRelatedEnd.EnsureLoaded();
return eref.Value;
}
public static void EnsureLoaded(this RelatedEnd end) {
IEntityWithRelationships owner = (IEntityWithRelationships)_relatedEndOwner.GetValue( end, null );
EntityObject ownerEntity = owner as EntityObject;
if( ownerEntity != null ) {
if( ownerEntity.EntityState == EntityState.Added || ownerEntity.EntityState == EntityState.Detached ) return; // calling .Load on a Added object causes an exception.
}
if( end.IsAttached() && !end.IsLoaded ) end.Load();
}
This question is moot - I was connecting to my database server over a VPN connection. I thought it would be okay as the ping time was only about 50ms between my computer and the database server, but I forget how chatty SQL Server is. Considering that it fires off about 60 queries at once it makes sense that 60 * 50ms == 3000ms.
When I retried my application on the same LAN as the server (ping time < 1ms) the whole load operation executes in under 30ms with no need for any further optimization. Problem solved.
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
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.