package org.jactr.extensions.cached.procedural.internal; /* * default logging */ import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jactr.core.buffer.IActivationBuffer; import org.jactr.core.model.IModel; import org.jactr.core.model.event.IModelListener; import org.jactr.core.model.event.ModelEvent; import org.jactr.core.model.event.ModelListenerAdaptor; import org.jactr.core.slot.INotifyingSlotContainer; import org.jactr.extensions.cached.procedural.listeners.BufferListener; import org.jactr.extensions.cached.procedural.listeners.SlotListener; /** * central point for the listeners used to track the buffers and the chunk * contents. * * @author harrison */ public class ListenerHub { /** * Logger definition */ static private final transient Log LOGGER = LogFactory .getLog(ListenerHub.class); private final Map<String, BufferListener> _bufferListeners; private final Map<INotifyingSlotContainer, SlotListener> _slotListeners; private final IModelListener _modelListener; private final IModel _model; private final ReentrantReadWriteLock _lock = new ReentrantReadWriteLock(); public ListenerHub(IModel model) { _model = model; _modelListener = new ModelListenerAdaptor() { @Override public void bufferInstalled(ModelEvent me) { _bufferListeners.put(me.getBuffer().getName().toLowerCase(), new BufferListener(me.getBuffer())); } /* * at the end of each cycle, check the slot listeners for any that are * unused, and clear (non-Javadoc) * @see * org.jactr.core.model.event.ModelListenerAdaptor#cycleStopped(org.jactr * .core.model.event.ModelEvent) */ @Override public void cycleStopped(ModelEvent me) { checkForEmptyListeners(); } }; _bufferListeners = new TreeMap<String, BufferListener>(); _slotListeners = new HashMap<INotifyingSlotContainer, SlotListener>(); /** * buffer listeners are permanent installations */ for (IActivationBuffer buffer : model.getActivationBuffers()) _bufferListeners.put(buffer.getName().toLowerCase(), new BufferListener( buffer)); _model.addListener(_modelListener, null); } public void dispose() { _model.removeListener(_modelListener); try { _lock.writeLock().lock(); // detach everyone for (BufferListener listener : _bufferListeners.values()) listener.dispose(); _bufferListeners.clear(); for (SlotListener listener : _slotListeners.values()) listener.dispose(); _slotListeners.clear(); } finally { _lock.writeLock().unlock(); } } public BufferListener getBufferListener(String bufferName) { try { _lock.readLock().lock(); return _bufferListeners.get(bufferName.toLowerCase()); } finally { _lock.readLock().unlock(); } } public SlotListener getSlotListener(INotifyingSlotContainer container) { try { _lock.writeLock().lock(); SlotListener sl = _slotListeners.get(container); if (sl == null) { if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("No slot listener registered for %s, doing so now", container)); sl = new SlotListener(container); _slotListeners.put(container, sl); } return sl; } finally { _lock.writeLock().unlock(); } } /** * find any unused slot listeerns and remove. */ protected void checkForEmptyListeners() { try { _lock.writeLock().lock(); Iterator<SlotListener> listeners = _slotListeners.values().iterator(); while (listeners.hasNext()) { SlotListener listener = listeners.next(); if (listener.isEmpty()) { if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format( "Slot listener for %s is empty, removing", listener.getContainer())); // do cleanup outside of lock? listener.dispose(); listeners.remove(); } } } finally { _lock.writeLock().unlock(); } } }