<div dir="ltr">I&#39;ve found myself in need of something similar to what Wolfgang described in an archived post in order to handle retractions based on dynamic properties found on the fact itself:<br><div><br></div><div>*****</div>
<div><span style="color:rgb(0,0,0);font-family:Verdana,Geneva,Helvetica,Arial,sans-serif;font-size:13px">Just in case anybody wonders about the effort for building a mechanism for retracting facts based on fact attributes or other data, I outline the solution I have implemented.</span><br style="color:rgb(0,0,0);font-family:Verdana,Geneva,Helvetica,Arial,sans-serif;font-size:13px">
<br style="color:rgb(0,0,0);font-family:Verdana,Geneva,Helvetica,Arial,sans-serif;font-size:13px"><span style="color:rgb(0,0,0);font-family:Verdana,Geneva,Helvetica,Arial,sans-serif;font-size:13px">My class FactWiper implements WorkingMemoryEventListener and Runnable.</span><br style="color:rgb(0,0,0);font-family:Verdana,Geneva,Helvetica,Arial,sans-serif;font-size:13px">
<ul style="color:rgb(0,0,0);font-family:Verdana,Geneva,Helvetica,Arial,sans-serif;font-size:13px"><li>The implementation of objectInserted( ObjectInsertedEvent event ) determines whether the object needs handling and, if so, the retraction Date, based upon whatever strategy you care to implement, e.g., reflection method call, Map&lt;Class,Long&gt;, etc. If it is to be handled, it signals Condition &quot;change&quot; to the thread.<br>
</li><li>A SortedMap&lt;Date,Object&gt; expiry2fact keeps track of pending retractions.</li><li>The thread loops into an awaitUntil( x ) on the &quot;change&quot; condition, where x is (generally) the first retraction Date. If reached, it retracts according to the foremost Map entry; if signalled it reasesses the situation and reenters the awaitUntil.</li>
</ul><span style="color:rgb(0,0,0);font-family:Verdana,Geneva,Helvetica,Arial,sans-serif;font-size:13px">-W</span><br></div><div><span style="color:rgb(0,0,0);font-family:Verdana,Geneva,Helvetica,Arial,sans-serif;font-size:13px">*****</span></div>
<div><span style="color:rgb(0,0,0);font-family:Verdana,Geneva,Helvetica,Arial,sans-serif;font-size:13px"><br></span></div><div style><span style="color:rgb(0,0,0);font-family:Verdana,Geneva,Helvetica,Arial,sans-serif;font-size:13px">However, I&#39;ve been thus far unable to beat an IllegalMonitorStateException I encounter when looping back in from an insertLogical. Below is my Listener class and my example rules that demonstrate the exception. Anyone see what I&#39;m doing wrong with the thread conditions? Thanks for your time. - Jeremy</span></div>
<div style><span style="color:rgb(0,0,0);font-family:Verdana,Geneva,Helvetica,Arial,sans-serif;font-size:13px"><br></span></div><div style><span style="color:rgb(0,0,0);font-family:Verdana,Geneva,Helvetica,Arial,sans-serif;font-size:13px">--------------------- LISTENER CLASS ------------------------</span></div>
<div style><span style="color:rgb(0,0,0);font-family:Verdana,Geneva,Helvetica,Arial,sans-serif;font-size:13px"><br></span></div><div style><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">@Slf4j</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">@Component</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">class RetractionListener implements WorkingMemoryEventListener, Runnable {</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br></font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">    /** allow a sorted map to track dates and objects to be retracted */</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">    NavigableMap&lt;Date, Object&gt; retractionSchedule = new TreeMap&lt;Date, Object&gt;();</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br>
</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">    /** allow some condition to signify when we have a new retractable fact to consider */</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">    Condition change</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br></font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">    /** session wrapper */</font></div><div>
<font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">    @Autowired</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">    SessionManager sessionManager</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br></font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">    /**</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">     * runnable task entry point for executor</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">     */</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">    void run() {</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br>
</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">        Lock lock = new ReentrantLock()</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">        change = lock.newCondition()</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">        lock.lock()</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br></font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br>
</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">        while (retractionSchedule.isEmpty()) {</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">            change.await()</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">        }</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br></font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">        try {</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">            while (System.currentTimeMillis() &lt; retractionSchedule.firstKey().time) {</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                log.debug(&quot;issuing wait&quot;)</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                change.awaitUntil(retractionSchedule.firstKey())</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">            }</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">            FactHandle handle = sessionManager.factHandleMap.get(retractionSchedule.firstEntry().value)</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">            sessionManager.session.retract(handle)</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br></font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">        } catch (InterruptedException e) {</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">            log.error(&quot;RetractionListener thread ${Thread.currentThread().name} interrupted!&quot;)</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">            throw e</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">        } finally {</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">            lock.unlock()</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">        }</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">    }</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br>
</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">    /**</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">     * detect new facts, determine if they are retractable, and add to the tracker map if needed</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">     *</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">     * @param event</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">     */</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">    void objectInserted(ObjectInsertedEvent event) {</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br>
</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">        if (event.object.isRetractable) {</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">            log.debug(&quot;retractable object of type ${event.object.class.simpleName} detected&quot;)</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">            try {</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                long duration = event.object.duration</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                if (!duration) {</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                    // go ahead and throw up a similar exception to missing property for a missing value</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                    throw new MissingPropertyException(&quot;no value specified for retractable object&#39;s duration&quot;)</font></div><div>
<font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                } else {</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br></font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                    Calendar calendar = GregorianCalendar.getInstance()</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                    log.debug(&quot;duration of object noted to be ${duration} milliseconds&quot;)</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                    log.debug(&quot;current time: ${calendar.time}&quot;)</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br></font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                    calendar.add(Calendar.MILLISECOND, duration.toInteger())</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br></font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                    log.debug(&quot;setting schedule for ${calendar.time}&quot;)</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                    retractionSchedule.put(calendar.time, event.object)</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br>
</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                    log.debug(&quot;signaling change condition&quot;)</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br>
</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                    change.signal()</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                }</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">            } catch (MissingPropertyException e) {</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                log.error(&quot;retractable object ${event.object} missing needed property/value &#39;duration&#39;&quot;)</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">                throw e</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">            }</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">        }</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">    }</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br>
</font></div><div style><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">    ...[REST OF CLASS IRRELEVANT]...</font></div><div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">}</font></div>
<div><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br></font></div><div style><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif">--------------------- RULE FILE -------------------------</font></div>
<div style><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><br></font></div><div style><font color="#000000" face="Verdana, Geneva, Helvetica, Arial, sans-serif"><div>declare Fire</div><div>    @role(event)</div>
<div>end</div><div><br></div><div>declare SprinklerInterval</div><div>    @role(event)</div><div>    fire : Fire</div><div>    isRetractable : boolean</div><div>    duration : long</div><div>end</div><div><br></div><div>rule &quot;fire detected&quot;</div>
<div>when</div><div>    $f : Fire (  )</div><div>    not SprinklerInterval ( fire == $f )</div><div>then</div><div>    insertLogical ( new SprinklerInterval($f, true, 500) );</div><div>end</div><div><br></div><div>rule &quot;add sprinklers running notification&quot;</div>
<div>when</div><div>    $s : SprinklerInterval ( )</div><div>then</div><div>    <a href="http://log.info">log.info</a>(&quot;Sprinklers running on fire located in: &quot; + $s.getFire().getName());</div><div>end</div></font></div>
</div></div>