package org.jactr.core.module.retrieval.buffer; /* * default logging */ import java.util.concurrent.Future; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jactr.core.buffer.IActivationBuffer; import org.jactr.core.buffer.delegate.AsynchronousRequestDelegate; import org.jactr.core.chunk.IChunk; import org.jactr.core.chunktype.IChunkType; import org.jactr.core.chunktype.ISymbolicChunkType; import org.jactr.core.chunktype.IllegalChunkTypeStateException; import org.jactr.core.logging.Logger; import org.jactr.core.model.IModel; import org.jactr.core.module.retrieval.IRetrievalModule; import org.jactr.core.module.retrieval.six.DefaultRetrievalModule6; import org.jactr.core.production.request.ChunkRequest; 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.ISlot; public class RetrievalRequestDelegate extends AsynchronousRequestDelegate { /** * Logger definition */ static private final transient Log LOGGER = LogFactory .getLog(RetrievalRequestDelegate.class); private IRetrievalModule _retrievalModule; private boolean _includeNullValues; public RetrievalRequestDelegate(IRetrievalModule module) { _retrievalModule = module; setUseBlockingTimedEvents(false); setAsynchronous(true); } public void clear() { super.clear(); ITimedEvent previous = getCurrentTimedEvent(); if (previous != null && !previous.hasAborted() && !previous.hasFired()) previous.abort(); } private boolean indexedRetrievalsEnabled() { if (_retrievalModule instanceof DefaultRetrievalModule6) return ((DefaultRetrievalModule6) _retrievalModule) .isIndexedRetrievalEnabled(); return false; } /** * when chunks are expanded into search patterns, this determines whether null * slot values will be included in the search pattern, defaults to false * * @param includeNulls */ public void setIncludeNullValues(boolean includeNulls) { _includeNullValues = includeNulls; } /** * test to make sure all the slots are contained in the chunktype */ @Override protected boolean isValid(IRequest request, IActivationBuffer buffer) throws IllegalArgumentException { IChunkType chunkType = ((ChunkTypeRequest) request).getChunkType(); ISymbolicChunkType sChunkType = chunkType.getSymbolicChunkType(); for (ISlot slot : ((ChunkTypeRequest) request).getSlots()) { boolean valid = false; try { valid = null != sChunkType.getSlot(slot.getName()); } catch (IllegalChunkTypeStateException icse) { } if (!valid) throw new IllegalArgumentException("No slot named " + slot.getName() + " available in " + chunkType); } return true; } /** * expands chunk requests into chunktype requests, unless indexed retrievals * are enabled. * * @param request * @return */ @Override protected IRequest expandRequest(IRequest request) { if (request instanceof ChunkRequest && !indexedRetrievalsEnabled()) { IChunk chunk = ((ChunkRequest) request).getChunk(); ChunkTypeRequest ctr = new ChunkTypeRequest(chunk.getSymbolicChunk() .getChunkType()); for (ISlot slot : chunk.getSymbolicChunk().getSlots()) if (slot.getValue() != null || _includeNullValues) ctr.addSlot(slot); request = ctr; } return request; } @Override protected Object startRequest(IRequest request, IActivationBuffer buffer, double requestTime) { IModel model = buffer.getModel(); /* * abort previous retrieval attempt */ ITimedEvent previousRetrieval = getCurrentTimedEvent(); if (previousRetrieval != null && !previousRetrieval.hasAborted() && !previousRetrieval.hasFired()) { previousRetrieval.abort(); /* * log that we are aborting */ if (Logger.hasLoggers(model) || LOGGER.isDebugEnabled()) { String msg = "Aborted retrieval of " + getPreviousRequest(); if (Logger.hasLoggers(model)) Logger.log(model, Logger.Stream.RETRIEVAL, msg); if (LOGGER.isDebugEnabled()) LOGGER.debug(msg); } } /* * clear the current buffer contents */ buffer.removeSourceChunk(buffer.getSourceChunk()); setBusy(buffer); /* * indexed retrievals must be enabled, lets just return the chunk */ if (request instanceof ChunkRequest) return ((ChunkRequest) request).getChunk(); ChunkTypeRequest ctRequest = (ChunkTypeRequest) request; return _retrievalModule.retrieveChunk(ctRequest); } protected void abortRequest(IRequest request, IActivationBuffer buffer, Object startValue) { setFree(buffer); super.abortRequest(request, buffer, startValue); } @SuppressWarnings("unchecked") @Override protected void finishRequest(IRequest request, IActivationBuffer buffer, Object startValue) { IChunk error = buffer.getModel().getDeclarativeModule().getErrorChunk(); IChunk result = error; boolean indexed = false; if (startValue instanceof IChunk) { result = (IChunk) startValue; indexed = true; } else try { result = ((Future<IChunk>) startValue).get(); } catch (InterruptedException ie) { // bail return; } catch (Exception e) { LOGGER.error("Failed to get future of retrieval request " + request, e); result = error; } if (indexed) buffer.addSourceChunk(result); // will implicitly reset state else { /* * now this is just the harvest of the result from the module. we still * need to calculate the retrieval time and post the event to actually * make it available */ double startTime = getCurrentTimedEvent().getStartTime(); /* * what would the retrieval time be? */ double retrievalTime = _retrievalModule.getRetrievalTimeEquation() .computeRetrievalTime(result); IModel model = buffer.getModel(); if (Logger.hasLoggers(model) || LOGGER.isDebugEnabled()) { String msg = "Will retrieve " + result + " in " + retrievalTime + " @ " + (startTime + retrievalTime); Logger.log(model, Logger.Stream.RETRIEVAL, msg); LOGGER.debug(msg); } ITimedEvent finish = new DelayedBufferInsertionTimedEvent(buffer, result, startTime, startTime + retrievalTime); model.getTimedEventQueue().enqueue(finish); setCurrentTimedEvent(finish); } } public boolean willAccept(IRequest request) { return request instanceof ChunkTypeRequest; } }