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 }