package org.jactr.modules.pm.visual.buffer.processor; /* * default logging */ import java.util.concurrent.Future; import javolution.util.FastList; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jactr.core.buffer.IActivationBuffer; import org.jactr.core.chunk.IChunk; import org.jactr.core.chunktype.IChunkType; import org.jactr.core.concurrent.ExecutorServices; import org.jactr.core.event.IParameterEvent; import org.jactr.core.logging.Logger; import org.jactr.core.model.IModel; import org.jactr.core.production.request.ChunkTypeRequest; import org.jactr.core.production.request.IRequest; import org.jactr.core.queue.ITimedEvent; import org.jactr.core.queue.timedevents.DelayedBufferInsertionTimedEvent; import org.jactr.core.slot.IConditionalSlot; import org.jactr.core.slot.ISlot; import org.jactr.modules.pm.common.buffer.AbstractRequestDelegate; import org.jactr.modules.pm.common.memory.PerceptualSearchResult; import org.jactr.modules.pm.visual.IVisualModule; import org.jactr.modules.pm.visual.buffer.IVisualActivationBuffer; import org.jactr.modules.pm.visual.event.IVisualModuleListener; import org.jactr.modules.pm.visual.event.VisualModuleEvent; import org.jactr.modules.pm.visual.memory.VisualUtilities; /** * attend-to and move-attention delegate that handles buffer states and routes * the request to the module * * @author harrison */ public class AttendToRequestDelegate extends AbstractRequestDelegate { /** * Logger definition */ static private final transient Log LOGGER = LogFactory .getLog(AttendToRequestDelegate.class); final private String _locationSlotName; final private IVisualModule _module; private ITimedEvent _pendingHarvest; public AttendToRequestDelegate(IVisualModule module, IChunkType attendChunkType, String locationSlotName) { super(attendChunkType); _module = module; _chunkType = attendChunkType; _locationSlotName = locationSlotName; setAsynchronous(true); setUseBlockingTimedEvents(true); _module.addListener(new IVisualModuleListener() { public void encodedVisualObject(VisualModuleEvent event) { if (LOGGER.isDebugEnabled()) LOGGER.debug("Encoded " + event.getChunk() + " releasing"); // release block, if any release(); } public void foundVisualLocation(VisualModuleEvent event) { } public void trackedObjectMoved(VisualModuleEvent event) { } public void trackingObjectStarted(VisualModuleEvent event) { } public void trackingObjectStopped(VisualModuleEvent event) { } public void visualSystemReset(VisualModuleEvent event) { // release if blocked release(); } @SuppressWarnings("unchecked") public void parameterChanged(IParameterEvent pe) { } }, ExecutorServices.INLINE_EXECUTOR); } /** * clear and possibly abort a pending encoding */ final public void clear() { super.clear(); if (_pendingHarvest != null) _pendingHarvest.abort(); } /** * returns a visual-location contained in the slot with the name matching the * constructor supplied name * * @param request * @return */ protected IChunk getVisualLocation(IRequest request) { /* * check to be sure the location slot is not null */ ChunkTypeRequest ctr = (ChunkTypeRequest) request; /* * figure out if this is a stuff request */ FastList<ISlot> slots = FastList.newInstance(); try { ctr.getSlots(slots); for (ISlot slot : slots) { IConditionalSlot cSlot = (IConditionalSlot) slot; if (cSlot.getName().equalsIgnoreCase(_locationSlotName) && cSlot.getValue() instanceof IChunk && cSlot.getCondition() == IConditionalSlot.EQUALS) return (IChunk) cSlot.getValue(); } return null; } finally { FastList.recycle(slots); } } /** * make sure the requst is properly formatted and that the visual system is * free * * @param request * @param buffer * @return * @throws IllegalArgumentException * @see org.jactr.core.buffer.delegate.AsynchronousRequestDelegate#isValid(org.jactr.core.production.request.IRequest, * org.jactr.core.buffer.IActivationBuffer) */ @Override final protected boolean isValid(IRequest request, IActivationBuffer buffer) throws IllegalArgumentException { /* * check to see if we are busy or not.. */ IModel model = _module.getModel(); if (isBusy(buffer)) { String msg = "Visual system is currently busy, cannot shift attention"; if (LOGGER.isDebugEnabled()) LOGGER.debug(msg); if (Logger.hasLoggers(model)) Logger.log(model, Logger.Stream.VISUAL, msg); return false; } IChunk location = getVisualLocation(request); if (location == null) { String msg = _locationSlotName + " is null, no clue where to look. Ignoring request."; if (LOGGER.isDebugEnabled()) LOGGER.debug(msg); if (Logger.hasLoggers(model)) Logger.log(model, Logger.Stream.VISUAL, msg); return false; } if (!location.isA(_module.getVisualLocationChunkType())) { String msg = "Content of " + _locationSlotName + "(" + location + ") is not visual-location. Ignoring request."; if (LOGGER.isDebugEnabled()) LOGGER.debug(msg); if (Logger.hasLoggers(model)) Logger.log(model, Logger.Stream.VISUAL, msg); return false; } return getMatchingResult(location) != null; } protected PerceptualSearchResult getMatchingResult(IChunk visualLocation) { PerceptualSearchResult searchResult = VisualUtilities.getSearchResult( visualLocation, _module.getVisualMemory()); IModel model = visualLocation.getModel(); if(searchResult==null) { String msg = "Cannot match location to visual search."; if (LOGGER.isDebugEnabled()) LOGGER.debug(msg); if (Logger.hasLoggers(model)) Logger.log(model, Logger.Stream.VISUAL, msg); } return searchResult; } /** * start the encoding request. first we remove the current contents, then * request the encoding. we return a Future<IChunk> for the finishRequest * method, allowing this to be processed asynchronously * * @param request * @param buffer * @return * @see org.jactr.core.buffer.delegate.AsynchronousRequestDelegate#startRequest(org.jactr.core.production.request.IRequest, * org.jactr.core.buffer.IActivationBuffer, double) */ @Override final protected Object startRequest(IRequest request, IActivationBuffer buffer, double requestTime) { IChunk location = getVisualLocation(request); PerceptualSearchResult result = getMatchingResult(location); /* * clear */ buffer.removeSourceChunk(buffer.getSourceChunk()); /* * flag as busy */ IVisualActivationBuffer actBuffer = _module.getVisualActivationBuffer(); IChunk busy = _module.getModel().getDeclarativeModule().getBusyChunk(); actBuffer.setStateChunk(busy); actBuffer.setModalityChunk(busy); actBuffer.setPreparationChunk(busy); actBuffer.setProcessorChunk(busy); actBuffer.setExecutionChunk(busy); return _module.encodeVisualChunkAt(result, requestTime); } /** * abort the request and reset to free * * @param request * @param buffer * @param startValue * @see org.jactr.core.buffer.delegate.AsynchronousRequestDelegate#abortRequest(org.jactr.core.production.request.IRequest, * org.jactr.core.buffer.IActivationBuffer, java.lang.Object) */ final protected void abortRequest(IRequest request, IActivationBuffer buffer, Object startValue) { IVisualActivationBuffer actBuffer = _module.getVisualActivationBuffer(); IChunk free = _module.getModel().getDeclarativeModule().getFreeChunk(); actBuffer.setStateChunk(free); actBuffer.setModalityChunk(free); actBuffer.setPreparationChunk(free); actBuffer.setProcessorChunk(free); actBuffer.setExecutionChunk(free); super.abortRequest(request, buffer, startValue); } /** * handles the completion of the encoding, but we then need to post an * additional event to deal with making the encoded chunk available * * @param request * @param buffer * @param startValue * @see org.jactr.core.buffer.delegate.AsynchronousRequestDelegate#finishRequest(org.jactr.core.production.request.IRequest, * org.jactr.core.buffer.IActivationBuffer, java.lang.Object) */ @SuppressWarnings("unchecked") @Override final protected void finishRequest(IRequest request, IActivationBuffer buffer, Object startValue) { IModel model = _module.getModel(); final IChunk errorChunk = model.getDeclarativeModule().getErrorChunk(); final IChunk freeChunk = model.getDeclarativeModule().getFreeChunk(); IChunk visualChunk = errorChunk; try { visualChunk = ((Future<IChunk>) startValue).get(); } catch (InterruptedException e) { return; } catch (Exception e) { LOGGER.error("Could not get future of encoding " + request, e); visualChunk = errorChunk; } /* * now we have the encoded chunk, but this is not the actual time to return * the result, we need to deal with the encoding time */ final IChunk result = visualChunk; final ChunkTypeRequest ctRequest = (ChunkTypeRequest) request; double startTime = getCurrentTimedEvent().getStartTime(); double encodingTime = _module.getEncodingTimeEquation() .computeEncodingTime(visualChunk, _module); _pendingHarvest = new DelayedBufferInsertionTimedEvent(buffer, visualChunk, startTime, startTime + encodingTime) { public void fire(double currentTime) { _pendingHarvest = null; super.fire(currentTime); harvest(ctRequest, result, errorChunk, freeChunk); } public void abort() { _pendingHarvest = null; super.abort(); abortRequest(ctRequest, null, null); } }; if (Logger.hasLoggers(model) || LOGGER.isDebugEnabled()) { String msg = "Will encode " + result + " by " + (encodingTime + startTime); if (LOGGER.isDebugEnabled()) LOGGER.debug(msg); if (Logger.hasLoggers(model)) Logger.log(model, Logger.Stream.VISUAL, msg); } _module.getModel().getTimedEventQueue().enqueue(_pendingHarvest); } /** * called when the actual harvest is to occur * * @param request * @param visualChunk * @param errorChunk * @param freeChunk */ private void harvest(ChunkTypeRequest request, IChunk visualChunk, IChunk errorChunk, IChunk freeChunk) { IModel model = _module.getModel(); IVisualActivationBuffer buffer = _module.getVisualActivationBuffer(); IChunk visualLocation = getVisualLocation(request); if (errorChunk.equals(visualChunk)) { if (LOGGER.isDebugEnabled() || Logger.hasLoggers(model)) { String msg = "No visual object could be encoded at " + visualLocation; LOGGER.debug(msg); Logger.log(model, Logger.Stream.VISUAL, msg); } buffer.setStateChunk(errorChunk); buffer.setModalityChunk(errorChunk); } else if (visualChunk.hasBeenDisposed()) { /* * this can occur if the cached visual object is disposed of before the * encoding request finishes.. */ if (LOGGER.isDebugEnabled() || Logger.hasLoggers(model)) { String msg = "Visual object has already been disposed, nothing left to encode "; LOGGER.debug(msg); Logger.log(model, Logger.Stream.VISUAL, msg); } buffer.setStateChunk(errorChunk); buffer.setModalityChunk(errorChunk); } else { buffer.setStateChunk(freeChunk); buffer.setModalityChunk(freeChunk); buffer.addSourceChunk(visualChunk); } buffer.setExecutionChunk(freeChunk); buffer.setProcessorChunk(freeChunk); buffer.setPreparationChunk(freeChunk); } }