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    
008    import javax.ws.rs.WebApplicationException;
009    
010    import java.util.ArrayList;
011    import java.util.HashMap;
012    import java.util.List;
013    import java.util.Map;
014    
015    
016    
017    class 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        private DeepaMehtaService dms;
027    
028        // ---------------------------------------------------------------------------------------------------- Constructors
029    
030        EventManager(DeepaMehtaService dms) {
031            this.dms = dms;
032            // Note: actually the class CoreEvent does not need to be instantiated as it contains only statics.
033            // But if not instantiated OSGi apparently does not load the class at all.
034            new CoreEvent();
035        }
036    
037        // ----------------------------------------------------------------------------------------- Package Private Methods
038    
039        void addListener(DeepaMehtaEvent event, EventListener listener) {
040            List<EventListener> listeners = getListeners(event);
041            if (listeners == null) {
042                listeners = new ArrayList();
043                putListeners(event, listeners);
044            }
045            listeners.add(listener);
046        }
047    
048        void removeListener(DeepaMehtaEvent event, EventListener listener) {
049            List<EventListener> listeners = getListeners(event);
050            if (!listeners.remove(listener)) {
051                throw new RuntimeException("Removing " + listener + " from " +
052                    event + " event listeners failed: not found in " + listeners);
053            }
054        }
055    
056        // ---
057    
058        void fireEvent(DeepaMehtaEvent event, Object... params) {
059            List<EventListener> listeners = getListeners(event);
060            if (listeners != null) {
061                for (EventListener listener : listeners) {
062                    deliverEvent(listener, event, params);
063                }
064            }
065        }
066    
067        // ---
068    
069        /**
070         * Checks weather the given plugin is a listener for the given event, and if so, delivers the event to the plugin.
071         * Otherwise nothing is performed.
072         */
073        void deliverEvent(PluginImpl plugin, DeepaMehtaEvent event, Object... params) {
074            PluginContext pluginContext = plugin.getContext();
075            if (!isListener(pluginContext, event)) {
076                return;
077            }
078            //
079            deliverEvent((EventListener) pluginContext, event, params);
080        }
081    
082        /**
083         * Convenience method to check weather the specified plugin is a listener for the given event, and if so,
084         * delivers the event to the plugin. Otherwise nothing is performed.
085         */
086        void deliverEvent(String pluginUri, DeepaMehtaEvent event, Object... params) {
087            deliverEvent((PluginImpl) dms.getPlugin(pluginUri), event, params);
088        }
089    
090        // ------------------------------------------------------------------------------------------------- Private Methods
091    
092        private void deliverEvent(EventListener listener, DeepaMehtaEvent event, Object... params) {
093            try {
094                event.deliver(listener, params);
095            } catch (WebApplicationException e) {
096                // Note: a WebApplicationException thrown by a event listener must reach Jersey. So we re-throw here.
097                // This allow plugins to produce specific HTTP responses by throwing a WebApplicationException.
098                // Consider the Caching plugin: it produces a possible 304 (Not Modified) response this way.
099                throw e;
100            } catch (Exception e) {
101                throw new RuntimeException("Processing event " + event + " by " + listener + " failed", e);
102            }
103        }
104    
105        // ---
106    
107        /**
108         * Returns true if the given plugin is a listener for the given event.
109         */
110        private boolean isListener(PluginContext pluginContext, DeepaMehtaEvent event) {
111            return event.getListenerInterface().isAssignableFrom(pluginContext.getClass());
112        }
113    
114        // ---
115    
116        private List<EventListener> getListeners(DeepaMehtaEvent event) {
117            return listenerRegistry.get(event.getClass().getName());
118        }
119    
120        private void putListeners(DeepaMehtaEvent event, List<EventListener> listeners) {
121            listenerRegistry.put(event.getClass().getName(), listeners);
122        }
123    }