package org.jactr.core.module.retrieval.six; /* * default logging */ import javolution.util.FastList; import org.apache.commons.collections.map.LRUMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jactr.core.chunk.IChunk; import org.jactr.core.concurrent.ExecutorServices; import org.jactr.core.module.retrieval.IRetrievalModule; import org.jactr.core.module.retrieval.event.IRetrievalModuleListener; import org.jactr.core.module.retrieval.event.RetrievalModuleEvent; import org.jactr.core.queue.ITimedEvent; import org.jactr.core.queue.timedevents.AbstractTimedEvent; public class DeclarativeFINSTManager { /** * Logger definition */ static private final transient Log LOGGER = LogFactory .getLog(DeclarativeFINSTManager.class); static public final String NUMBER_OF_FINSTS_PARAM = "NumberOfFINSTs"; static public final String FINST_DURATION_PARAM = "FINSTDurationTime"; private double _finstDurationTime = 3; private int _numberOfFINSTs = 4; /** * keys on the retrieved chunk w/ a timed event value that handles the * expiration of the item. */ private LRUMap _recentlyRetrieved = new LRUMap( _numberOfFINSTs); private IRetrievalModuleListener _retrievalListener; private IChunk _errorChunk; public DeclarativeFINSTManager(IRetrievalModule retrievalModule) { _retrievalListener = new IRetrievalModuleListener() { public void retrievalInitiated(RetrievalModuleEvent rme) { } public void retrievalCompleted(RetrievalModuleEvent rme) { IChunk retrieved = rme.getChunk(); if (!_errorChunk.equals(retrieved)) addRecentRetrieval(retrieved, rme.getSimulationTime()); } }; retrievalModule.addListener(_retrievalListener, ExecutorServices.INLINE_EXECUTOR); } protected void setErrorChunk(IChunk errorChunk) { _errorChunk = errorChunk; } public void setFINSTDuration(double duration) { _finstDurationTime = duration; } public double getFINSTDuration() { return _finstDurationTime; } public void setNumberOfFINSTs(int number) { _numberOfFINSTs = number; if (_numberOfFINSTs != _recentlyRetrieved.maxSize()) synchronized (this) { LRUMap old = _recentlyRetrieved; _recentlyRetrieved = new LRUMap(_numberOfFINSTs); _recentlyRetrieved.putAll(old); } } public int getNumberOfFINSTs() { return _numberOfFINSTs; } public void addRecentRetrieval(IChunk retrievedChunk, double when) { // just in case removeRecentRetrieval(retrievedChunk); ITimedEvent expirationEvent = new FINSTExpirationTimedEvent(when, when + _finstDurationTime, retrievedChunk); if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format( "New retrieval of %s will be marked as old @ %.2f", retrievedChunk, expirationEvent.getEndTime())); synchronized (this) { _recentlyRetrieved.put(retrievedChunk, expirationEvent); } retrievedChunk.getModel().getTimedEventQueue().enqueue(expirationEvent); } public void removeRecentRetrieval(IChunk retrievedChunk) { ITimedEvent expirationEvent = null; synchronized (this) { expirationEvent = (ITimedEvent) _recentlyRetrieved.remove(retrievedChunk); } if (expirationEvent != null && !expirationEvent.hasAborted() && !expirationEvent.hasFired()) expirationEvent.abort(); } public void clearRecentRetrievals() { /* * abort the timed events */ FastList<ITimedEvent> expirationEvents = FastList.newInstance(); synchronized (this) { expirationEvents.addAll(_recentlyRetrieved.values()); _recentlyRetrieved.clear(); } for (ITimedEvent event : expirationEvents) if (!event.hasAborted() && !event.hasFired()) event.abort(); FastList.recycle(expirationEvents); } synchronized public boolean hasBeenRetrieved(IChunk chunk) { return _recentlyRetrieved.containsKey(chunk); } private class FINSTExpirationTimedEvent extends AbstractTimedEvent { final private IChunk _retrievedChunk; public FINSTExpirationTimedEvent(double start, double end, IChunk retrievedChunk) { super(start, end); _retrievedChunk = retrievedChunk; } @Override public void fire(double currentTime) { super.fire(currentTime); if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("Removing dec-finst for %s @ %.2f", _retrievedChunk, currentTime)); removeRecentRetrieval(_retrievedChunk); } @Override public void abort() { if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("Aborting expiration event for %s", _retrievedChunk)); super.abort(); } } }