package org.jactr.modules.pm.common.memory.map; /* * default logging */ import java.util.Collections; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import javolution.util.FastSet; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.commonreality.identifier.IIdentifier; import org.commonreality.object.IAfferentObject; import org.commonreality.object.delta.IObjectDelta; import org.jactr.core.chunk.IChunk; import org.jactr.core.event.ACTREventDispatcher; import org.jactr.core.production.request.ChunkTypeRequest; import org.jactr.core.runtime.ACTRRuntime; import org.jactr.core.slot.BasicSlot; import org.jactr.core.slot.ISlot; import org.jactr.modules.pm.common.memory.IPerceptualMemory; public abstract class AbstractFeatureMap<T> implements IFeatureMap<T> { /** * Logger definition */ static private final transient Log LOGGER = LogFactory .getLog(AbstractFeatureMap.class); @SuppressWarnings("unchecked") private ACTREventDispatcher<IFeatureMap, IFeatureMapListener> _dispatcher = new ACTREventDispatcher<IFeatureMap, IFeatureMapListener>(); private IPerceptualMemory _memory; private final String _crPropertyName; private final String _requestSlotName; private Lock _lock = new ReentrantLock(); public AbstractFeatureMap(String requestSlotName, String crPropertyName) { _crPropertyName = crPropertyName; _requestSlotName = requestSlotName; } protected String getRelevantSlotName() { return _requestSlotName; } protected String getRelevantPropertyName() { return _crPropertyName; } public void addListener(IFeatureMapListener listener, Executor executor) { _dispatcher.addListener(listener, executor); } public void removeListener(IFeatureMapListener listener) { _dispatcher.removeListener(listener); } protected boolean hasListeners() { return _dispatcher.hasListeners(); } protected void dispatch(FeatureMapEvent event) { _dispatcher.fire(event); } public void setPerceptualMemory(IPerceptualMemory memory) { _memory = memory; } public IPerceptualMemory getPerceptualMemory() { return _memory; } protected Lock getLock() { return _lock; } abstract protected void clearInternal(); final public void clear() { _lock.lock(); try { clearInternal(); } finally { _lock.unlock(); } } public void dispose() { clear(); } public void fillSlotValues(ChunkTypeRequest mutableRequest, IIdentifier identifier, IChunk encodedChunk, ChunkTypeRequest originalSearchRequest) { String slotName = getRelevantSlotName(); if (slotName == null) return; T value = getCurrentValue(identifier); if (value != null) mutableRequest.addSlot(new BasicSlot(slotName, value)); else if (LOGGER.isWarnEnabled()) LOGGER.warn("No " + slotName + " information for " + identifier); } final public T getInformation(IIdentifier identifier) { _lock.lock(); try { return getCurrentValue(identifier); } finally { _lock.unlock(); } } final public void getCandidateRealObjects(ChunkTypeRequest request, Set<IIdentifier> container) { _lock.lock(); try { getCandidates(request, container); } finally { _lock.unlock(); } } /** * is {@link #getRelevantSlotName()} is not null, this will check to see if * the request contains that slot name. * * @param request * @return * @see org.jactr.modules.pm.common.memory.map.IFeatureMap#isInterestedIn(org.jactr.core.production.request.ChunkTypeRequest) */ public boolean isInterestedIn(ChunkTypeRequest request) { if (_requestSlotName != null) for (ISlot slot : request.getSlots()) if (slot.getName().equalsIgnoreCase(_requestSlotName)) return true; return _requestSlotName == null; } final public void afferentObjectAdded(IAfferentObject object) { IIdentifier identifier = object.getIdentifier(); T data = extractInformation(object); _lock.lock(); try { addInformation(identifier, data); } finally { _lock.unlock(); } if (data != null) { objectAdded(object, data); if (hasListeners()) dispatch(new FeatureMapEvent(this, ACTRRuntime.getRuntime().getClock( getPerceptualMemory().getModule().getModel()).getTime(), FeatureMapEvent.Type.ADDED, Collections.singleton(identifier))); } } /** * call back after object information has been added, assuming data was not * null * * @param object * @param data */ protected void objectAdded(IAfferentObject object, T data) { if (LOGGER.isDebugEnabled()) LOGGER.debug(this + " Added " + object.getIdentifier() + " = " + data); } final public void afferentObjectRemoved(IAfferentObject object) { IIdentifier identifier = object.getIdentifier(); T data = null; _lock.lock(); try { data = removeInformation(identifier); } finally { _lock.unlock(); } if (data != null) { objectRemoved(object, data); if (hasListeners()) dispatch(new FeatureMapEvent(this, ACTRRuntime.getRuntime().getClock( getPerceptualMemory().getModule().getModel()).getTime(), FeatureMapEvent.Type.REMOVED, Collections.singleton(identifier))); } } /** * callback * * @param object * @param data */ protected void objectRemoved(IAfferentObject object, T data) { if (LOGGER.isDebugEnabled()) LOGGER.debug(this + " Removed " + object.getIdentifier() + " = " + data); } final public void afferentObjectUpdated(IAfferentObject object, IObjectDelta delta) { // relevant property did not change if (_crPropertyName != null && !delta.getChangedProperties().contains(_crPropertyName)) return; IIdentifier identifier = object.getIdentifier(); T data = extractInformation(object); T oldData = null; _lock.lock(); try { oldData = removeInformation(identifier); addInformation(identifier, data); } finally { _lock.unlock(); } objectUpdated(object, oldData, data); if (data != null && !data.equals(oldData) && hasListeners()) dispatch(new FeatureMapEvent(this, ACTRRuntime.getRuntime().getClock( getPerceptualMemory().getModule().getModel()).getTime(), FeatureMapEvent.Type.UPDATED, Collections.singleton(identifier))); } protected void objectUpdated(IAfferentObject object, T oldData, T newData) { if (LOGGER.isDebugEnabled()) LOGGER.debug(this+" Updated "+object.getIdentifier()+" "+oldData+" "+newData); } abstract protected T getCurrentValue(IIdentifier identifier); abstract protected T extractInformation(IAfferentObject afferentObject); abstract protected T removeInformation(IIdentifier identifier); abstract protected void addInformation(IIdentifier identifier, T data); abstract protected void getCandidates(ChunkTypeRequest request, Set<IIdentifier> results); }