package org.hypergraphdb.event; import java.util.HashMap; import java.util.List; import java.util.Map; import org.hypergraphdb.HyperGraph; import org.hypergraphdb.transaction.TxList; import org.hypergraphdb.transaction.TxMap; import org.hypergraphdb.transaction.VBox; public class HGDefaultEventManager implements HGEventManager { private HyperGraph graph; private Map<Class<?>, List<HGListener>> listenerMap = null; private List<HGListener> getListeners(Class<?> eventType, boolean addIfMissing) { if (listenerMap == null) { if (addIfMissing) { initListenerMap(); } else { return null; } } List<HGListener> listeners = listenerMap.get(eventType); if (listeners == null && addIfMissing) { listeners = new TxList<HGListener>(graph.getTransactionManager()); listenerMap.put(eventType, listeners); } return listeners; } public HGDefaultEventManager() { } public HGDefaultEventManager(HyperGraph graph) { this.graph = graph; } public void initListenerMap() { listenerMap = new TxMap<Class<?>, List<HGListener>>(graph.getTransactionManager(), new HashMap<Class<?>, VBox<List<HGListener>>>()); } public <T extends HGEvent> void addListener(Class<T> eventType, HGListener listener) { getListeners(eventType, true).add(listener); } public <T extends HGEvent> void removeListener(Class<T> eventType, HGListener listener) { List<HGListener> listeners = getListeners(eventType, false); if (listeners != null) { listeners.remove(listener); } } public HGListener.Result dispatch(HyperGraph hg, HGEvent event) { if (listenerMap == null || listenerMap.isEmpty()) // avoid looping through the class hierarchy cause it's expensive return HGListener.Result.ok; for (Class<?> clazz = event.getClass(); clazz != null && HGEvent.class != clazz; clazz = clazz.getSuperclass()) { List<HGListener> listeners = listenerMap.get(clazz); if (listeners == null) continue; for (HGListener l : listeners) // type safety warning OK, we are explicitly passing a correctly typed event. switch (l.handle(hg, event)) { case ok: continue; case cancel: return HGListener.Result.cancel; } } // should we also invoke listener bound to HGEvent.class itself? return HGListener.Result.ok; } public void clear() { if (listenerMap != null) listenerMap.clear(); } public void setHyperGraph(HyperGraph graph) { this.graph = graph; } public HyperGraph getHyperGraph() { return this.graph; } }