View Javadoc
1   package org.esigate.events;
2   
3   import java.util.ArrayList;
4   import java.util.HashMap;
5   import java.util.List;
6   import java.util.Map;
7   
8   import org.slf4j.Logger;
9   import org.slf4j.LoggerFactory;
10  
11  /**
12   * The event manager.
13   * <p>
14   * Listener can register and unregister to specific events.
15   * <p>
16   * Events can be fired and propagated to listeners.
17   * <p>
18   * The following events are supported :
19   * <p>
20   * Proxy events : ESIGate process an incoming request (ESIGate configured as a proxy).
21   * <uL>
22   * <li>{@link EventManager#EVENT_PROXY_PRE} : before processing an incoming request.</li>
23   * <li>{@link EventManager#EVENT_PROXY_POST} : after processing an incoming request.</li>
24   * </ul>
25   * <p>
26   * Fragment events : A fragment is required for inclusion (esi:include). ESIGate will try to use its cache or fallback
27   * to an http call to the remote backend.
28   * 
29   * <ul>
30   * <li>{@link EventManager#EVENT_FRAGMENT_PRE} : before retrieving a fragment.</li>
31   * <li>{@link EventManager#EVENT_FRAGMENT_POST} : after retrieving a fragment.</li>
32   * </ul>
33   * <p>
34   * Fetch events : An HTTP call is made to a remote backend.
35   * <ul>
36   * <li>{@link EventManager#EVENT_FETCH_PRE} : before creating the HTTP call.</li>
37   * <li>{@link EventManager#EVENT_FETCH_POST} : after we receive the response.</li>
38   * </ul>
39   * <p>
40   * Render events : Renderers are applied to the current page. This event can be used to inject additional renderers.
41   * <ul>
42   * <li>{@link EventManager#EVENT_RENDER_PRE} : before applying renderers</li>
43   * <li>{@link EventManager#EVENT_RENDER_POST} : after applying renderers</li>
44   * </ul>
45   * <p>
46   * Encoding event : response is read using the charset declared by HTTP headers.
47   * <ul>
48   * <li>{@link EventManager#EVENT_READ_ENTITY} : after reading response using the default encoding</li>
49   * </ul>
50   * 
51   * @author Nicolas Richeton
52   */
53  public class EventManager {
54  
55      public static final EventDefinition EVENT_FRAGMENT_PRE = new EventDefinition("org.esigate.fragment-pre",
56              EventDefinition.TYPE_DEFAULT);
57      public static final EventDefinition EVENT_FRAGMENT_POST = new EventDefinition("org.esigate.fragment-post",
58              EventDefinition.TYPE_POST);
59  
60      public static final EventDefinition EVENT_FETCH_PRE = new EventDefinition("org.esigate.fetch-pre",
61              EventDefinition.TYPE_DEFAULT);
62      public static final EventDefinition EVENT_FETCH_POST = new EventDefinition("org.esigate.fetch-post",
63              EventDefinition.TYPE_POST);
64  
65      public static final EventDefinition EVENT_PROXY_PRE = new EventDefinition("org.esigate.proxy-pre",
66              EventDefinition.TYPE_DEFAULT);
67      public static final EventDefinition EVENT_PROXY_POST = new EventDefinition("org.esigate.proxy-post",
68              EventDefinition.TYPE_POST);
69  
70      public static final EventDefinition EVENT_RENDER_PRE = new EventDefinition("org.esigate.render-pre",
71              EventDefinition.TYPE_DEFAULT);
72      public static final EventDefinition EVENT_RENDER_POST = new EventDefinition("org.esigate.render-post",
73              EventDefinition.TYPE_POST);
74  
75      public static final EventDefinition EVENT_READ_ENTITY = new EventDefinition("org.esigate.readEntity.",
76              EventDefinition.TYPE_DEFAULT);
77  
78      public static final EventDefinition EVENT_HTTP_BUILDER_INITIALIZATION = new EventDefinition(
79              "org.esigate.httpBuilderInitialization.", EventDefinition.TYPE_POST);
80  
81      private static final Logger LOG = LoggerFactory.getLogger(EventManager.class);
82  
83      private final String driverId;
84  
85      public EventManager(String driverId) {
86          this.driverId = driverId;
87      }
88  
89      /**
90       * Listener mappings. This saves times when an event is fired.
91       */
92      private Map<EventDefinition, List<IEventListener>> listeners = new HashMap<>();
93      /**
94       * Post events are stored in reverse order. This allows an extension to enclose the whole processing.
95       */
96      private Map<EventDefinition, List<IEventListener>> listenersPost = new HashMap<>();
97  
98      private void register(Map<EventDefinition, List<IEventListener>> listenerMappings, EventDefinition eventDefinition,
99              IEventListener listener, boolean reverseOrder) {
100         List<IEventListener> eventListeners = listenerMappings.get(eventDefinition);
101 
102         // Create listener list for this event
103         if (eventListeners == null) {
104             eventListeners = new ArrayList<>();
105             listenerMappings.put(eventDefinition, eventListeners);
106         }
107         if (!eventListeners.contains(listener)) {
108             // Add listener
109             if (reverseOrder) {
110                 eventListeners.add(eventListeners.size(), listener);
111             } else {
112                 eventListeners.add(listener);
113             }
114 
115             if (LOG.isInfoEnabled()) {
116                 LOG.info("Registered {} on event {}/{}", listener.getClass().getName(), driverId, eventDefinition);
117             }
118         }
119     }
120 
121     /**
122      * Start listening to an event.
123      * 
124      * @param eventDefinition
125      * @param listener
126      */
127     public void register(EventDefinition eventDefinition, IEventListener listener) {
128         if (eventDefinition.getType() == EventDefinition.TYPE_POST) {
129             register(listenersPost, eventDefinition, listener, true);
130         } else {
131             register(listeners, eventDefinition, listener, false);
132         }
133     }
134 
135     /**
136      * Fire a new event and run all the listeners.
137      * 
138      * @param eventDefinition
139      * @param eventDetails
140      */
141     public void fire(EventDefinition eventDefinition, Event eventDetails) {
142         if (eventDefinition.getType() == EventDefinition.TYPE_POST) {
143             fire(listenersPost, eventDefinition, eventDetails);
144         } else {
145             fire(listeners, eventDefinition, eventDetails);
146         }
147     }
148 
149     private void fire(Map<EventDefinition, List<IEventListener>> listenerMappings, EventDefinition eventDefinition,
150             Event eventDetails) {
151         List<IEventListener> eventListeners = listenerMappings.get(eventDefinition);
152 
153         // No listeners at all for this event
154         if (eventListeners == null) {
155             return;
156         }
157 
158         // Loop on listeners
159         for (IEventListener el : eventListeners) {
160             if (LOG.isDebugEnabled()) {
161                 LOG.debug("Running {} on event {}/{}", el, driverId, eventDefinition);
162             }
163 
164             if (!el.event(eventDefinition, eventDetails)) {
165                 return;
166             }
167         }
168 
169     }
170 
171     /**
172      * Stop listening to an event.
173      * 
174      * @param eventDefinition
175      * @param eventListener
176      */
177     public void unregister(EventDefinition eventDefinition, IEventListener eventListener) {
178         if (eventDefinition.getType() == EventDefinition.TYPE_POST) {
179             unregister(listenersPost, eventDefinition, eventListener);
180         } else {
181             unregister(listeners, eventDefinition, eventListener);
182         }
183     }
184 
185     private void unregister(Map<EventDefinition, List<IEventListener>> listenerMappings,
186             EventDefinition eventDefinition, IEventListener listener) {
187 
188         List<IEventListener> eventListeners = listenerMappings.get(eventDefinition);
189 
190         // Not listeners at all for this event
191         if (eventListeners == null) {
192             return;
193         }
194 
195         boolean removed = eventListeners.remove(listener);
196 
197         if (LOG.isInfoEnabled() && removed) {
198             LOG.info("Unregistered {} on event {}/{}", listener.getClass().getName(), driverId, eventDefinition);
199         }
200     }
201 }