[rules-users] retracting facts based on fact properties

Jeremy Ary jeremy.ary at gmail.com
Wed Jan 9 16:04:53 EST 2013


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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-users/attachments/20130109/1e4359d7/attachment.html 


More information about the rules-users mailing list