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,
Related
I have some difficulties to do Drools run in pseudo clock.
I configure my engine in stream Mode, and choose the kind of clock I use thru realMode property.
Date refDate = new Date(System.currentTimeMillis());
boolean realMode = false;
SessionPseudoClock clock = null;
KieServices ks = KieServices.Factory.get();
KieSessionConfiguration config = KieServices.Factory.get().newKieSessionConfiguration();
if(realMode) {
config.setOption( ClockTypeOption.get("realtime") );
} else {
config.setOption( ClockTypeOption.get("pseudo") );
}
KieContainer kc = ks.getKieClasspathContainer();
KieSession ksession = kc.newKieSession("cep-rules",config);
KieRuntimeLogger logger = ks.getLoggers().newFileLogger( ksession, "./out/helloworld" );
addNewLogLine (ksession, "GDE" , 0);
addNewLogLine (ksession, "GDE" , 11);
addNewLogLine (ksession, "GDE" , 3);
addNewLogLine (ksession, "GDE" , 8);
logger.close();
ksession.dispose();
The code of AddNewLogLine Function
if( realMode) {
try {
Thread.sleep(delaiInSeconds*1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
if (clock==null) {
clock = ksession.getSessionClock();
}
clock.advanceTime( delaiInSeconds, TimeUnit.SECONDS );
}
delai += delaiInSeconds;
LogItem logLine = new LogItem();
logLine.setEventDate(new Date (refDate.getTime()+(delai*1000)));
logLine.setMessage("Message number " + count);
logLine.setSourceSystemName(sourceSystemName);
System.out.println(logLine);
ksession.insert( logLine );
ksession.fireAllRules();
I leave appart some extra code that is not relevant for my problema.
The rule :
declare LogItem
#role (event)
#timestamp( eventDate )
end
rule "LogInserted"
dialect "mvel"
when
l : LogItem ( )
then
System.out.println ("New Log inside from " + l.getSourceSystemName() );
end
rule "Nb Log SameSystem"
dialect "mvel"
when
accumulate( LogItem ( sourceSystemName == "GDE") over window:time(10s) ; $cnt: count(1); $cnt == 2 )
then
System.out.println ("2 Logs in engine" );
end
The objective : Detect two logs line in a window of 10 seconds.
The first and seconds are not (11s) and the 2 following lines, yes.
In real mode it works fine. Here is the result :
LogItem { message : Message number 1, date : 28/03/2017 11:17:26, sourceSystemName : GDE }
New Log inside from GDE
LogItem { message : Message number 2, date : 28/03/2017 11:17:37, sourceSystemName : GDE }
New Log inside from GDE
LogItem { message : Message number 3, date : 28/03/2017 11:17:40, sourceSystemName : GDE }
New Log inside from GDE
2 Logs in engine
LogItem { message : Message number 4, date : 28/03/2017 11:17:48, sourceSystemName : GDE }
New Log inside from GDE
2 Logs in engine
In pseudo clock mode it doesn't work. Because the 4 lines are inserted in the same time, so the 2 first activate the rule. So the Pseudo clock isn't used.
Here is the result :
LogItem { message : Message number 1, date : 28/03/2017 11:17:26, sourceSystemName : GDE }
New Log inside from GDE
LogItem { message : Message number 2, date : 28/03/2017 11:17:37, sourceSystemName : GDE }
New Log inside from GDE
2 Logs in engine
LogItem { message : Message number 3, date : 28/03/2017 11:17:40, sourceSystemName : GDE }
New Log inside from GDE
LogItem { message : Message number 4, date : 28/03/2017 11:17:48, sourceSystemName : GDE }
New Log inside from GDE
I suppose it's because I don't manage de pseudo clock. But I'm not able to find where I'm wrong.
Anybody ?
Thanks in advance;
I think your problem is due to incorrect manipulation of the pseudo-clock. Also, for best results, run the session in a thread of its own which executes fireUntilHalt:
Runnable fireUntilHaltRunnable = new Runnable() {
public void run() {
// System.out.println( "fireUntilHalt" );
kSession.fireUntilHalt()
}
};
Thread fireUntilHaltThread = new Thread(fireUntilHaltRunnable);
Facts are inserted from another thread. If you are running tests with the pseudo-clock, make sure the pseudo-clock is set to the timestamp of the event if you are using events that contain the timestamp as a field:
private void advance( Date eventDate ){
long currentTime = clock.getCurrentTime();
long eventTime = eventDate.getTime();
clock.advanceTime( eventTime - currentTime, TimeUnit.MILLISECONDS );
}
Do this before you insert the next fact. There is no need to sleep between inserts.
Trying to process a list of long running jobs in a vertx way
One would hope one could do something like:
use the executeBlocking to process the long running job in an async manner
use the composite future to wait for the futures to complete
I'm aware this approach does not work .. the list of Futures is not complete before the code drops into the CompositeFuture.
Is there a executeBlocking approach or does one have to use either the eventbus, vertx utils that support lists?
java.util.ArrayList futureList = new ArrayList()
for (i = 0; i < 100; i ++){
vertx.executeBlocking({ future ->
int id = i
println "Running " + id
java.lang.Thread.sleep(1000)
println "Thread done " + id
future.complete()
}, true , { res ->
if (res.succeeded()) {
print "."
} else {
print "x"
}
})
}
CompositeFuture.join(futureList).setHandler({ ar ->
if (ar.succeeded()) {
System.err.println "all threads should be done.."
}
})
Results in .. "all threads should be done" printing early
Running 84
Running 87
Running 87
Running 95
all threads should be done..
done.
Thread done 3
Thread done 36
Thread done 3
Thread done 0
In your example, futureList is empty so CompositeFuture.join(futureList) is completed immediately.
Change your example like this:
java.util.ArrayList futureList = new ArrayList()
for (i = 0; i < 100; i ++){
Future jobFuture = Future.future()
futureList.add(jobFuture)
vertx.executeBlocking({ future ->
int id = i
println "Running " + id
java.lang.Thread.sleep(1000)
println "Thread done " + id
future.complete()
}, true , { res ->
if (res.succeeded()) {
print "."
} else {
print "x"
}
jobFuture.complete()
})
}
Notice the jobFuture creation:
Future jobFuture = Future.future()
futureList.add(jobFuture)
As well as completion:
jobFuture.complete()
Now the CompositeFuture.join(futureList) handler will be executed only after all jobs complete.
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
in flashbuilder debugger mode, I can examine all the props/vals of the FacebookSession object returned by FacebookDesktop.login when I place a breakpoint in my loginhandler method.
however, I cannot seem to iterate through the FacebookSession object using for...in. I have checked to see if the FacebookSession is dynamic using ObjectUtil.isDynamicObject(...), but it is not, so a for..in should work.
public function gf_handle_facebook_login_return( argl_success : Object ,
argl_failure : Object ) : void
{ // IF I ADD breakpoint here, I get a fully populated argl_success object in flashbuilder's Debugger Variables tab.
trace( "gf_handle_facebook_login_return , A : " + typeof( argl_success ) + " , " + argl_success[ "uid" ] ) ; // works
trace( "gf_handle_facebook_login_return , C : " + ObjectUtil.isDynamicObject( argl_success ) ) ; // false ... is NOT a dynamic class
var lvo_FBS : FacebookSession = FacebookSession ( argl_success ) ; // tried it with and without casting
var lvn_prop :* ;
for ( lvn_prop in lvo_FBS)
{ trace( "gf_handle_facebook_login_return , D : " + lvn_prop ) ; // is never called
}
for each( lvn_prop in lvo_FBS)
{ trace( "gf_handle_facebook_login_return , E : " + lvn_prop ) ; // is never called
}
}
For in will only loop through dynamic properties and as you said it is not a dynamic.
Try this example
//Get an XML description of this class
//and return the variable types as XMLList with e4x
var varList:XMLList = flash.utils.describeType(myVO)..variable;
for(var i:int; i < varList.length(); i++){
//Show the name and the value
trace(varList[i].#name+':'+ myVO[varList[i].#name]);
}
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