EventManager.java
package org.esigate.events;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The event manager.
* <p>
* Listener can register and unregister to specific events.
* <p>
* Events can be fired and propagated to listeners.
* <p>
* The following events are supported :
* <p>
* Proxy events : ESIGate process an incoming request (ESIGate configured as a proxy).
* <uL>
* <li>{@link EventManager#EVENT_PROXY_PRE} : before processing an incoming request.</li>
* <li>{@link EventManager#EVENT_PROXY_POST} : after processing an incoming request.</li>
* </ul>
* <p>
* Fragment events : A fragment is required for inclusion (esi:include). ESIGate will try to use its cache or fallback
* to an http call to the remote backend.
*
* <ul>
* <li>{@link EventManager#EVENT_FRAGMENT_PRE} : before retrieving a fragment.</li>
* <li>{@link EventManager#EVENT_FRAGMENT_POST} : after retrieving a fragment.</li>
* </ul>
* <p>
* Fetch events : An HTTP call is made to a remote backend.
* <ul>
* <li>{@link EventManager#EVENT_FETCH_PRE} : before creating the HTTP call.</li>
* <li>{@link EventManager#EVENT_FETCH_POST} : after we receive the response.</li>
* </ul>
* <p>
* Render events : Renderers are applied to the current page. This event can be used to inject additional renderers.
* <ul>
* <li>{@link EventManager#EVENT_RENDER_PRE} : before applying renderers</li>
* <li>{@link EventManager#EVENT_RENDER_POST} : after applying renderers</li>
* </ul>
* <p>
* Encoding event : response is read using the charset declared by HTTP headers.
* <ul>
* <li>{@link EventManager#EVENT_READ_ENTITY} : after reading response using the default encoding</li>
* </ul>
*
* @author Nicolas Richeton
*/
public class EventManager {
public static final EventDefinition EVENT_FRAGMENT_PRE = new EventDefinition("org.esigate.fragment-pre",
EventDefinition.TYPE_DEFAULT);
public static final EventDefinition EVENT_FRAGMENT_POST = new EventDefinition("org.esigate.fragment-post",
EventDefinition.TYPE_POST);
public static final EventDefinition EVENT_FETCH_PRE = new EventDefinition("org.esigate.fetch-pre",
EventDefinition.TYPE_DEFAULT);
public static final EventDefinition EVENT_FETCH_POST = new EventDefinition("org.esigate.fetch-post",
EventDefinition.TYPE_POST);
public static final EventDefinition EVENT_PROXY_PRE = new EventDefinition("org.esigate.proxy-pre",
EventDefinition.TYPE_DEFAULT);
public static final EventDefinition EVENT_PROXY_POST = new EventDefinition("org.esigate.proxy-post",
EventDefinition.TYPE_POST);
public static final EventDefinition EVENT_RENDER_PRE = new EventDefinition("org.esigate.render-pre",
EventDefinition.TYPE_DEFAULT);
public static final EventDefinition EVENT_RENDER_POST = new EventDefinition("org.esigate.render-post",
EventDefinition.TYPE_POST);
public static final EventDefinition EVENT_READ_ENTITY = new EventDefinition("org.esigate.readEntity.",
EventDefinition.TYPE_DEFAULT);
public static final EventDefinition EVENT_HTTP_BUILDER_INITIALIZATION = new EventDefinition(
"org.esigate.httpBuilderInitialization.", EventDefinition.TYPE_POST);
private static final Logger LOG = LoggerFactory.getLogger(EventManager.class);
private final String driverId;
public EventManager(String driverId) {
this.driverId = driverId;
}
/**
* Listener mappings. This saves times when an event is fired.
*/
private Map<EventDefinition, List<IEventListener>> listeners = new HashMap<>();
/**
* Post events are stored in reverse order. This allows an extension to enclose the whole processing.
*/
private Map<EventDefinition, List<IEventListener>> listenersPost = new HashMap<>();
private void register(Map<EventDefinition, List<IEventListener>> listenerMappings, EventDefinition eventDefinition,
IEventListener listener, boolean reverseOrder) {
List<IEventListener> eventListeners = listenerMappings.get(eventDefinition);
// Create listener list for this event
if (eventListeners == null) {
eventListeners = new ArrayList<>();
listenerMappings.put(eventDefinition, eventListeners);
}
if (!eventListeners.contains(listener)) {
// Add listener
if (reverseOrder) {
eventListeners.add(eventListeners.size(), listener);
} else {
eventListeners.add(listener);
}
if (LOG.isInfoEnabled()) {
LOG.info("Registered {} on event {}/{}", listener.getClass().getName(), driverId, eventDefinition);
}
}
}
/**
* Start listening to an event.
*
* @param eventDefinition
* @param listener
*/
public void register(EventDefinition eventDefinition, IEventListener listener) {
if (eventDefinition.getType() == EventDefinition.TYPE_POST) {
register(listenersPost, eventDefinition, listener, true);
} else {
register(listeners, eventDefinition, listener, false);
}
}
/**
* Fire a new event and run all the listeners.
*
* @param eventDefinition
* @param eventDetails
*/
public void fire(EventDefinition eventDefinition, Event eventDetails) {
if (eventDefinition.getType() == EventDefinition.TYPE_POST) {
fire(listenersPost, eventDefinition, eventDetails);
} else {
fire(listeners, eventDefinition, eventDetails);
}
}
private void fire(Map<EventDefinition, List<IEventListener>> listenerMappings, EventDefinition eventDefinition,
Event eventDetails) {
List<IEventListener> eventListeners = listenerMappings.get(eventDefinition);
// No listeners at all for this event
if (eventListeners == null) {
return;
}
// Loop on listeners
for (IEventListener el : eventListeners) {
if (LOG.isDebugEnabled()) {
LOG.debug("Running {} on event {}/{}", el, driverId, eventDefinition);
}
if (!el.event(eventDefinition, eventDetails)) {
return;
}
}
}
/**
* Stop listening to an event.
*
* @param eventDefinition
* @param eventListener
*/
public void unregister(EventDefinition eventDefinition, IEventListener eventListener) {
if (eventDefinition.getType() == EventDefinition.TYPE_POST) {
unregister(listenersPost, eventDefinition, eventListener);
} else {
unregister(listeners, eventDefinition, eventListener);
}
}
private void unregister(Map<EventDefinition, List<IEventListener>> listenerMappings,
EventDefinition eventDefinition, IEventListener listener) {
List<IEventListener> eventListeners = listenerMappings.get(eventDefinition);
// Not listeners at all for this event
if (eventListeners == null) {
return;
}
boolean removed = eventListeners.remove(listener);
if (LOG.isInfoEnabled() && removed) {
LOG.info("Unregistered {} on event {}/{}", listener.getClass().getName(), driverId, eventDefinition);
}
}
}