[rules-users] retracting facts based on fact properties

Jeremy Ary jeremy.ary at gmail.com
Thu Jan 10 09:21:41 EST 2013


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 at 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 at 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 at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-users
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-users/attachments/20130110/8a79b779/attachment.html 


More information about the rules-users mailing list