2

i'm trying to write an accumulation function that needs to be aware of the current time. i could obviously use System.currentTimeMillis(), but for testing im running a drools session with a pseudo-clock and would like to be able to test this function.

im looking for a way of getting at the session clock (or better yet, the KnowledgeRuntime) either from within the getResult() method or, if thats not possible, from the drools code itself (in te when section) so i could pass the clock to the function

radai
  • 23,949
  • 10
  • 71
  • 115

2 Answers2

4

Be careful when working with clocks as you can have quite a few surprises. Please note that the constraints are evaluated when the facts/events are inserted into the session or modified with an update/modify call. This means that the clock time when the constraint is evaluated will probably be different from the clock time when the rule is fired. That is the reason why drools does not exposes the current time directly to the LHS patterns.

Having said that, the way to do it is insert the session clock as a fact into the session and bind it as any other fact:

rule X
when
    $clock : SessionClock()
    ... your patterns / accumulate / etc  ...
then
    ...
end
Edson Tirelli
  • 3,891
  • 20
  • 23
  • ok, but the SessionClock im inserting wont be a static copy - it will be a live object reference, right? this would mean getting the time from it will give me the "correct" time (session time at function evaluation, not event insertion). and, given that my sessions are persistent and serialized - is the session clock serializable in a quick manner ? if not, how do i set it up so i can avoid serializing it and re-provide it on session activation? – radai May 24 '12 at 04:37
  • If you insert the session clock as a fact, every time the clock time is advanced, you need to call update() to notify the engine. Maybe you can share what you want to do exactly with the clock, i.e., why your accumulate function needs it, and we can help you better that way. – Edson Tirelli May 24 '12 at 13:07
  • the idea is like this - lets say i have a hard drive (c:), which i sample every day. every sample has just two pieces of data - free space and timestamp. i want a rule to fire if my hard drive is about to fill up in less then a week. for that i need to write an accumulation function that performs linear regression on the latest N samples (length window), plots the trend line, calculates when the trend-line hits 0 (==out of free space) and checks if this time point is less then a week from "now". this "now" reference is where i need the clock. – radai May 24 '12 at 13:54
  • 1
    In your use case, time is definitively a fact you have to reason over, so I do recommend that you insert the session clock as a fact. Also, I am not sure the accumulate function itself needs to know current time... it seems to me that it only needs to know the time of the events it is using for the linear regression. The result will be the date when the trend-line hits 0 relative to the samples you have. Finally, a separate rule can use the result of the computation to fire alarms in case it will happen in less than a week using the clock. – Edson Tirelli May 24 '12 at 14:06
  • Serialization should work fine with the clock, but I never tested it myself. – Edson Tirelli May 24 '12 at 14:06
  • if i insert the session clock as a fact and use its getCurrentTime() in a DRL, will this work? wont drools cache the return value of getCurrentTime() ? also, since all these rules will be auto-generated i'd prefer to keep the wholr functionality in a single rule and not spread across several, for managability – radai May 24 '12 at 14:12
1

During unit testing, I found that adding $clock : SessionClock() to when would cause unit tests not to trigger, FWR (probably because I had mocked it as a SessionPseudoClock and thus were no SessionClock facts in working memory).

I was able to however obtain the session clock (Pseudo or real) without needing a conditional bind, by using the drools KnowledgeHelper instance:

e.g.

then
  System.out.println(String.format(
      "It is now %s", 
         new java.util.Date(drools.getWorkingMemory()
                                  .getSessionClock()
                                  .getCurrentTime())
         .toString()));
StuartLC
  • 104,537
  • 17
  • 209
  • 285