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
> - The implementation of objectInserted( ObjectInsertedEvent event )
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.
>
> determines whether the object needs handling and, if so, the retraction> - A SortedMap<Date,Object> expiry2fact keeps track of pending
> 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.
> 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