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