<div dir="ltr">Thanks for your reply Wolfgang! I appreciate you leaving the summation out there a while back, it&#39;s been helpful in pointing me in the right direction and proved as a sanity check in thinking that such a mechanism would benefit my application. I forgot to mention that I&#39;m working in Groovy, thus the absence of semicolons in my code. I&#39;ll be putting your advice to good use today, thanks!<div>
<br></div><div style>Jeremy</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, Jan 10, 2013 at 1:32 AM, Wolfgang Laun <span dir="ltr">&lt;<a href="mailto:wolfgang.laun@gmail.com" target="_blank">wolfgang.laun@gmail.com</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">What is missing is that the thread signalling the condition must<br>
acquire the lock guarding the condition. The event handler<br>
should do:<br>
<br>
  private Lock mutex = new ReentrantLock();<br>
  private Condition change = mutex.newCondition();<br>
<br>
  public void objectInserted( ObjectInsertedEvent event ) {<br>
    Object object = event.getObject();<br>
    mutex.lock();<br>
    try {<br>
      Long duration = ...;<br>
      if( duration != null ){<br>
        ...add to map...<br>
        change.signalAll();<br>
      }<br>
    } finally {<br>
      mutex.unlock();<br>
    }<br>
  }<br>
<br>
Also, shouldn&#39;t the Runnable&#39;s &quot;run()&quot; method contain an infinite<br>
loop? Due to the absence of semicolons I suspect something may have<br>
happened to the text, but it seems that it signals only once.<br>
<br>
-W<br>
<div class="im"><br>
<br>
On 09/01/2013, Jeremy Ary &lt;<a href="mailto:jeremy.ary@gmail.com">jeremy.ary@gmail.com</a>&gt; wrote:<br>
&gt; I&#39;ve found myself in need of something similar to what Wolfgang described<br>
&gt; in an archived post in order to handle retractions based on dynamic<br>
&gt; properties found on the fact itself:<br>
&gt;<br>
&gt; *****<br>
&gt; Just in case anybody wonders about the effort for building a mechanism for<br>
&gt; retracting facts based on fact attributes or other data, I outline the<br>
&gt; solution I have implemented.<br>
&gt;<br>
&gt; My class FactWiper implements WorkingMemoryEventListener and Runnable.<br>
&gt;<br>
</div>&gt;    - The implementation of objectInserted( ObjectInsertedEvent event )<br>
<div class="im">&gt;    determines whether the object needs handling and, if so, the retraction<br>
&gt;    Date, based upon whatever strategy you care to implement, e.g.,<br>
&gt; reflection<br>
&gt;    method call, Map&lt;Class,Long&gt;, etc. If it is to be handled, it signals<br>
&gt;    Condition &quot;change&quot; to the thread.<br>
</div>&gt;    - A SortedMap&lt;Date,Object&gt; expiry2fact keeps track of pending<br>
&gt;    retractions.<br>
&gt;    - The thread loops into an awaitUntil( x ) on the &quot;change&quot; condition,<br>
<div><div class="h5">&gt;    where x is (generally) the first retraction Date. If reached, it<br>
&gt; retracts<br>
&gt;    according to the foremost Map entry; if signalled it reasesses the<br>
&gt;    situation and reenters the awaitUntil.<br>
&gt;<br>
&gt; -W<br>
&gt; *****<br>
&gt;<br>
&gt; However, I&#39;ve been thus far unable to beat an IllegalMonitorStateException<br>
&gt; I encounter when looping back in from an insertLogical. Below is my<br>
&gt; Listener class and my example rules that demonstrate the exception. Anyone<br>
&gt; see what I&#39;m doing wrong with the thread conditions? Thanks for your time.<br>
&gt; - Jeremy<br>
&gt;<br>
&gt; --------------------- LISTENER CLASS ------------------------<br>
&gt;<br>
&gt; @Slf4j<br>
&gt; @Component<br>
&gt; class RetractionListener implements WorkingMemoryEventListener, Runnable {<br>
&gt;<br>
&gt;     /** allow a sorted map to track dates and objects to be retracted */<br>
&gt;     NavigableMap&lt;Date, Object&gt; retractionSchedule = new TreeMap&lt;Date,<br>
&gt; Object&gt;();<br>
&gt;<br>
&gt;     /** allow some condition to signify when we have a new retractable fact<br>
&gt; to consider */<br>
&gt;     Condition change<br>
&gt;<br>
&gt;     /** session wrapper */<br>
&gt;     @Autowired<br>
&gt;     SessionManager sessionManager<br>
&gt;<br>
&gt;     /**<br>
&gt;      * runnable task entry point for executor<br>
&gt;      */<br>
&gt;     void run() {<br>
&gt;<br>
&gt;         Lock lock = new ReentrantLock()<br>
&gt;         change = lock.newCondition()<br>
&gt;         lock.lock()<br>
&gt;<br>
&gt;<br>
&gt;         while (retractionSchedule.isEmpty()) {<br>
&gt;             change.await()<br>
&gt;         }<br>
&gt;<br>
&gt;         try {<br>
&gt;             while (System.currentTimeMillis() &lt;<br>
&gt; retractionSchedule.firstKey().time) {<br>
&gt;                 log.debug(&quot;issuing wait&quot;)<br>
&gt;                 change.awaitUntil(retractionSchedule.firstKey())<br>
&gt;             }<br>
&gt;             FactHandle handle =<br>
&gt; sessionManager.factHandleMap.get(retractionSchedule.firstEntry().value)<br>
&gt;             sessionManager.session.retract(handle)<br>
&gt;<br>
&gt;         } catch (InterruptedException e) {<br>
&gt;             log.error(&quot;RetractionListener thread<br>
&gt; ${Thread.currentThread().name} interrupted!&quot;)<br>
&gt;             throw e<br>
&gt;         } finally {<br>
&gt;             lock.unlock()<br>
&gt;         }<br>
&gt;     }<br>
&gt;<br>
&gt;     /**<br>
&gt;      * detect new facts, determine if they are retractable, and add to the<br>
&gt; tracker map if needed<br>
&gt;      *<br>
&gt;      * @param event<br>
&gt;      */<br>
&gt;     void objectInserted(ObjectInsertedEvent event) {<br>
&gt;<br>
&gt;         if (event.object.isRetractable) {<br>
&gt;             log.debug(&quot;retractable object of type<br>
&gt; ${event.object.class.simpleName} detected&quot;)<br>
&gt;             try {<br>
&gt;                 long duration = event.object.duration<br>
&gt;                 if (!duration) {<br>
&gt;                     // go ahead and throw up a similar exception to missing<br>
&gt; property for a missing value<br>
&gt;                     throw new MissingPropertyException(&quot;no value specified<br>
&gt; for retractable object&#39;s duration&quot;)<br>
&gt;                 } else {<br>
&gt;<br>
&gt;                     Calendar calendar = GregorianCalendar.getInstance()<br>
&gt;                     log.debug(&quot;duration of object noted to be ${duration}<br>
&gt; milliseconds&quot;)<br>
&gt;                     log.debug(&quot;current time: ${calendar.time}&quot;)<br>
&gt;<br>
&gt;                     calendar.add(Calendar.MILLISECOND,<br>
&gt; duration.toInteger())<br>
&gt;<br>
&gt;                     log.debug(&quot;setting schedule for ${calendar.time}&quot;)<br>
&gt;                     retractionSchedule.put(calendar.time, event.object)<br>
&gt;<br>
&gt;                     log.debug(&quot;signaling change condition&quot;)<br>
&gt;<br>
&gt;                     change.signal()<br>
&gt;                 }<br>
&gt;             } catch (MissingPropertyException e) {<br>
&gt;                 log.error(&quot;retractable object ${event.object} missing<br>
&gt; needed property/value &#39;duration&#39;&quot;)<br>
&gt;                 throw e<br>
&gt;             }<br>
&gt;         }<br>
&gt;     }<br>
&gt;<br>
&gt;     ...[REST OF CLASS IRRELEVANT]...<br>
&gt; }<br>
&gt;<br>
&gt; --------------------- RULE FILE -------------------------<br>
&gt;<br>
&gt; declare Fire<br>
&gt;     @role(event)<br>
&gt; end<br>
&gt;<br>
&gt; declare SprinklerInterval<br>
&gt;     @role(event)<br>
&gt;     fire : Fire<br>
&gt;     isRetractable : boolean<br>
&gt;     duration : long<br>
&gt; end<br>
&gt;<br>
&gt; rule &quot;fire detected&quot;<br>
&gt; when<br>
&gt;     $f : Fire (  )<br>
&gt;     not SprinklerInterval ( fire == $f )<br>
&gt; then<br>
&gt;     insertLogical ( new SprinklerInterval($f, true, 500) );<br>
&gt; end<br>
&gt;<br>
&gt; rule &quot;add sprinklers running notification&quot;<br>
&gt; when<br>
&gt;     $s : SprinklerInterval ( )<br>
&gt; then<br>
&gt;     <a href="http://log.info" target="_blank">log.info</a>(&quot;Sprinklers running on fire located in: &quot; +<br>
&gt; $s.getFire().getName());<br>
&gt; end<br>
&gt;<br>
</div></div>_______________________________________________<br>
rules-users mailing list<br>
<a href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a><br>
<a href="https://lists.jboss.org/mailman/listinfo/rules-users" target="_blank">https://lists.jboss.org/mailman/listinfo/rules-users</a><br>
</blockquote></div><br></div>