Thanks for your reply Wolfgang! I appreciate you leaving the summation out there a while back, it'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'm working in Groovy, thus the absence of semicolons in my code. I'll be putting your advice to good use today, thanks!

Jeremy


On Thu, Jan 10, 2013 at 1:32 AM, Wolfgang Laun <wolfgang.laun@gmail.com> wrote:
What is missing is that the thread signalling the condition must
acquire the lock guarding the condition. The event handler
should do:

  private Lock mutex = new ReentrantLock();
  private Condition change = mutex.newCondition();

  public void objectInserted( ObjectInsertedEvent event ) {
    Object object = event.getObject();
    mutex.lock();
    try {
      Long duration = ...;
      if( duration != null ){
        ...add to map...
        change.signalAll();
      }
    } finally {
      mutex.unlock();
    }
  }

Also, shouldn't the Runnable's "run()" method contain an infinite
loop? Due to the absence of semicolons I suspect something may have
happened to the text, but it seems that it signals only once.

-W


On 09/01/2013, Jeremy Ary <jeremy.ary@gmail.com> wrote:
> I'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:
>
> *****
> 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.
>
> My class FactWiper implements WorkingMemoryEventListener and Runnable.
>
>    - 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<Class,Long>, etc. If it is to be handled, it signals
>    Condition "change" to the thread.
>    - A SortedMap<Date,Object> expiry2fact keeps track of pending
>    retractions.
>    - The thread loops into an awaitUntil( x ) on the "change" 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.
>
> -W
> *****
>
> However, I'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'm doing wrong with the thread conditions? Thanks for your time.
> - Jeremy
>
> --------------------- LISTENER CLASS ------------------------
>
> @Slf4j
> @Component
> class RetractionListener implements WorkingMemoryEventListener, Runnable {
>
>     /** allow a sorted map to track dates and objects to be retracted */
>     NavigableMap<Date, Object> retractionSchedule = new TreeMap<Date,
> Object>();
>
>     /** allow some condition to signify when we have a new retractable fact
> to consider */
>     Condition change
>
>     /** session wrapper */
>     @Autowired
>     SessionManager sessionManager
>
>     /**
>      * runnable task entry point for executor
>      */
>     void run() {
>
>         Lock lock = new ReentrantLock()
>         change = lock.newCondition()
>         lock.lock()
>
>
>         while (retractionSchedule.isEmpty()) {
>             change.await()
>         }
>
>         try {
>             while (System.currentTimeMillis() <
> retractionSchedule.firstKey().time) {
>                 log.debug("issuing wait")
>                 change.awaitUntil(retractionSchedule.firstKey())
>             }
>             FactHandle handle =
> sessionManager.factHandleMap.get(retractionSchedule.firstEntry().value)
>             sessionManager.session.retract(handle)
>
>         } catch (InterruptedException e) {
>             log.error("RetractionListener thread
> ${Thread.currentThread().name} interrupted!")
>             throw e
>         } finally {
>             lock.unlock()
>         }
>     }
>
>     /**
>      * detect new facts, determine if they are retractable, and add to the
> tracker map if needed
>      *
>      * @param event
>      */
>     void objectInserted(ObjectInsertedEvent event) {
>
>         if (event.object.isRetractable) {
>             log.debug("retractable object of type
> ${event.object.class.simpleName} detected")
>             try {
>                 long duration = event.object.duration
>                 if (!duration) {
>                     // go ahead and throw up a similar exception to missing
> property for a missing value
>                     throw new MissingPropertyException("no value specified
> for retractable object's duration")
>                 } else {
>
>                     Calendar calendar = GregorianCalendar.getInstance()
>                     log.debug("duration of object noted to be ${duration}
> milliseconds")
>                     log.debug("current time: ${calendar.time}")
>
>                     calendar.add(Calendar.MILLISECOND,
> duration.toInteger())
>
>                     log.debug("setting schedule for ${calendar.time}")
>                     retractionSchedule.put(calendar.time, event.object)
>
>                     log.debug("signaling change condition")
>
>                     change.signal()
>                 }
>             } catch (MissingPropertyException e) {
>                 log.error("retractable object ${event.object} missing
> needed property/value 'duration'")
>                 throw e
>             }
>         }
>     }
>
>     ...[REST OF CLASS IRRELEVANT]...
> }
>
> --------------------- RULE FILE -------------------------
>
> declare Fire
>     @role(event)
> end
>
> declare SprinklerInterval
>     @role(event)
>     fire : Fire
>     isRetractable : boolean
>     duration : long
> end
>
> rule "fire detected"
> when
>     $f : Fire (  )
>     not SprinklerInterval ( fire == $f )
> then
>     insertLogical ( new SprinklerInterval($f, true, 500) );
> end
>
> rule "add sprinklers running notification"
> when
>     $s : SprinklerInterval ( )
> then
>     log.info("Sprinklers running on fire located in: " +
> $s.getFire().getName());
> end
>
_______________________________________________
rules-users mailing list
rules-users@lists.jboss.org
https://lists.jboss.org/mailman/listinfo/rules-users