001package systems.dmx.core.impl; 002 003import systems.dmx.core.osgi.PluginContext; 004import systems.dmx.core.service.DMXEvent; 005import systems.dmx.core.service.EventListener; 006import systems.dmx.core.service.accesscontrol.AccessControlException; 007 008import javax.ws.rs.WebApplicationException; 009 010import java.util.ArrayList; 011import java.util.HashMap; 012import java.util.List; 013import java.util.Map; 014 015 016 017class EventManager { 018 019 // ---------------------------------------------------------------------------------------------- Instance Variables 020 021 /** 022 * The registered event listeners (key: event class name, value: event listeners). 023 */ 024 private Map<String, List<EventListener>> listenerRegistry = new HashMap(); 025 026 // ---------------------------------------------------------------------------------------------------- Constructors 027 028 EventManager() { 029 // Note: actually the class CoreEvent does not need to be instantiated as it contains only statics. 030 // But if not instantiated OSGi apparently does not load the class at all. 031 new CoreEvent(); 032 } 033 034 // ----------------------------------------------------------------------------------------- Package Private Methods 035 036 void addListener(DMXEvent event, EventListener listener) { 037 List<EventListener> listeners = getListeners(event); 038 if (listeners == null) { 039 listeners = new ArrayList(); 040 putListeners(event, listeners); 041 } 042 listeners.add(listener); 043 } 044 045 void removeListener(DMXEvent event, EventListener listener) { 046 List<EventListener> listeners = getListeners(event); 047 if (!listeners.remove(listener)) { 048 throw new RuntimeException("Removing " + listener + " from " + 049 event + " event listeners failed: not found in " + listeners); 050 } 051 } 052 053 // --- 054 055 void fireEvent(DMXEvent event, Object... params) { 056 List<EventListener> listeners = getListeners(event); 057 if (listeners != null) { 058 for (EventListener listener : listeners) { 059 dispatchEvent(listener, event, params); 060 } 061 } 062 } 063 064 // --- 065 066 /** 067 * Delivers an event to a particular plugin. 068 * If the plugin is not a listener for that event nothing is performed. 069 */ 070 void dispatchEvent(PluginImpl plugin, DMXEvent event, Object... params) { 071 PluginContext pluginContext = plugin.getContext(); 072 if (!isListener(pluginContext, event)) { 073 return; 074 } 075 // 076 dispatchEvent((EventListener) pluginContext, event, params); 077 } 078 079 // ------------------------------------------------------------------------------------------------- Private Methods 080 081 private void dispatchEvent(EventListener listener, DMXEvent event, Object... params) { 082 try { 083 event.dispatch(listener, params); 084 } catch (WebApplicationException e) { 085 // Note: a WebApplicationException thrown by a event listener must reach Jersey. So we re-throw here. 086 // This allow plugins to produce specific HTTP responses by throwing a WebApplicationException. 087 // Consider the Caching plugin: it produces a possible 304 (Not Modified) response this way. 088 throw e; 089 } catch (AccessControlException e) { 090 // Note: an AccessControlException thrown by a event listener must reach the caller in order to 091 // recover. 092 throw e; 093 } catch (Throwable e) { 094 // Note: here we also catch errors like NoSuchMethodError or AbstractMethodError. 095 // These occur when plugins are not yet adapted to changed Core API. 096 throw new RuntimeException("An error occurred in the " + event.getListenerInterface().getSimpleName() + 097 " of " + listener, e); 098 } 099 } 100 101 // --- 102 103 /** 104 * Returns true if the given plugin is a listener for the given event. 105 */ 106 private boolean isListener(PluginContext pluginContext, DMXEvent event) { 107 return event.getListenerInterface().isAssignableFrom(pluginContext.getClass()); 108 } 109 110 // --- 111 112 private List<EventListener> getListeners(DMXEvent event) { 113 return listenerRegistry.get(event.getClass().getName()); 114 } 115 116 private void putListeners(DMXEvent event, List<EventListener> listeners) { 117 listenerRegistry.put(event.getClass().getName(), listeners); 118 } 119}