package org.jactr.core.buffer.delegate; /* * default logging */ import java.util.Collection; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jactr.core.buffer.BufferUtilities; import org.jactr.core.buffer.IActivationBuffer; import org.jactr.core.chunk.IChunk; import org.jactr.core.chunk.ISymbolicChunk; import org.jactr.core.chunk.IllegalChunkStateException; import org.jactr.core.production.request.ChunkRequest; import org.jactr.core.production.request.IRequest; import org.jactr.core.slot.IMutableSlot; import org.jactr.core.slot.ISlot; /** * takes a chunk pattern and if the chunk is already encoded, copies it, before * inserting into the buffer via * {@link IActivationBuffer#addSourceChunk(org.jactr.core.chunk.IChunk)}. If the * chunk is encoded and there are slots to be modified, the chunk will * automatically be copied.<br/> * <br/> * This is used when you have a buffer that accepts new chunk insertions * directly and immediately (like goal). As opposed to a delayed request that * takes some amount of time (beyond the current cycle). * * @author harrison */ public class AddChunkRequestDelegate extends AsynchronousRequestDelegate { /** * Logger definition */ static private final transient Log LOGGER = LogFactory .getLog(AddChunkRequestDelegate.class); private boolean _copyEncodedChunks = true; private boolean _delayCopies = true; /** * default is to copy encoded chunks */ public AddChunkRequestDelegate() { this(true); } public AddChunkRequestDelegate(boolean copyEncodedChunks) throws IllegalArgumentException { _copyEncodedChunks = copyEncodedChunks; } public boolean willAccept(IRequest request) { return request instanceof ChunkRequest; } public void setDelayCopiesEnabled(boolean enable) { _delayCopies = enable; } public boolean shouldDelayCopies() { return _delayCopies; } @Override protected boolean isValid(IRequest request, IActivationBuffer buffer) throws IllegalArgumentException { if (!(request instanceof ChunkRequest)) throw new IllegalArgumentException("Request must be ChunkRequest"); ChunkRequest cRequest = (ChunkRequest) request; IChunk chunk = cRequest.getChunk(); ISymbolicChunk sChunk = chunk.getSymbolicChunk(); Collection<? extends ISlot> slots = cRequest.getSlots(); for (ISlot slot : slots) { boolean valid = false; try { valid = null != sChunk.getSlot(slot.getName()); } catch (IllegalChunkStateException icse) { } if (!valid) throw new IllegalArgumentException("No slot named " + slot.getName() + " available in " + chunk); } return true; } @Override protected Object startRequest(IRequest request, IActivationBuffer buffer, double requestTime) { ChunkRequest cRequest = (ChunkRequest) request; IChunk originalChunk = cRequest.getChunk(); Future<IChunk> copiedChunk = null; if (shouldCopy(originalChunk)) { if (shouldDelayCopies()) return null; if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("copying %s", originalChunk)); copiedChunk = buffer.getModel().getDeclarativeModule() .copyChunk(originalChunk); } else if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("Using original %s", originalChunk)); if (copiedChunk != null) return copiedChunk; return CompletableFuture.completedFuture(originalChunk); } protected boolean shouldCopy(IChunk chunk) { if (!_copyEncodedChunks) return false; if (chunk.isEncoded()) return true; Collection<IActivationBuffer> buffers = BufferUtilities .getContainingBuffers(chunk, true); // more than (possibly this) buffer contains this chunk, should copy if (buffers.size() > 1) return true; // the containing buffer isnt us if (buffers.size() == 1 && !buffers.contains(this)) return true; return false; } @SuppressWarnings("unchecked") @Override protected void finishRequest(IRequest request, IActivationBuffer buffer, Object startValue) { ChunkRequest cRequest = (ChunkRequest) request; CompletableFuture<IChunk> future = null; // startValue is either a completableFuture, or null. if (startValue == null) { IChunk original = cRequest.getChunk(); // null value, we are doing a delayed copy if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("delayed copy %s", original)); future = buffer.getModel().getDeclarativeModule().copyChunk(original); } else future = (CompletableFuture<IChunk>) startValue; future.thenAccept((c) -> { modifyChunk(c, cRequest); buffer.addSourceChunk(c); }); } protected void modifyChunk(IChunk toAdd, ChunkRequest request) { Collection<? extends ISlot> slots = request.getSlots(); try { toAdd.getWriteLock().lock(); ISymbolicChunk sChunk = toAdd.getSymbolicChunk(); for (ISlot slot : slots) ((IMutableSlot) sChunk.getSlot(slot.getName())).setValue(slot .getValue()); } finally { toAdd.getWriteLock().unlock(); } } }