@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