com.kauridev.lunarbase.EventManager Maven / Gradle / Ivy
Show all versions of lunar-base Show documentation
/*
* This file is part of the lunar-base package.
*
* Copyright (c) 2014 Eric Fritz
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.kauridev.lunarbase;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* An event dispatcher which maintains a registry of listeners. When an event is dispatched, all
* listeners subscribed to that event are notified.
*
* @author Eric Fritz
*/
public class EventManager
{
/**
* A mapping of listeners indexed by event type.
*/
private Map>, ListenerCollection>> listeners = new HashMap<>();
/**
* Subscribe a listener to an event.
*
* @param type The type of event.
* @param listener The listener.
*/
public void addListener(Class extends Event> type, L listener) {
addListener(type, listener, 0);
}
/**
* Subscribe a listener to an event.
*
* @param type The type of event.
* @param listener The listener.
* @param priority The priority.
*/
public void addListener(Class extends Event> type, L listener, int priority) {
getListeners(type).add(listener, priority);
}
/**
* Unsubscribe a listener from an event.
*
* @param type The type of event.
* @param listener The listener.
*/
public void removeListener(Class extends Event> type, L listener) {
getListeners(type).remove(listener);
}
/**
* Call {@link Event#notify(Object)} for every subscribed listener.
*
* All listeners will be notified in relation to their priority (higher priorities are notified
* first). Listeners with the same priority will be notified in an undefined order.
*
* If an event returns a different event instance, that instance will be used to notify the
* remaining listeners. The listeners that have already been notified will not be re-notified.
* If an event returns null, no remaining listeners will be notified of any event.
*
* @param event The event to dispatch.
*/
public void dispatch(Event event) {
for (L listener : getListeners(event)) {
event = event.notify(listener);
if (event == null) {
break;
}
}
}
/**
* Returns all listeners subscribed to an event.
*
* @param event The event.
*
* @return A list of listeners.
*/
@SuppressWarnings("unchecked")
private ListenerCollection getListeners(Event event) {
return getListeners((Class extends Event>) event.getClass());
}
/**
* Returns all listeners subscribed to an event type.
*
* @param type The type of event.
*
* @return A list of listeners.
*/
@SuppressWarnings("unchecked")
private ListenerCollection getListeners(Class extends Event> type) {
if (!listeners.containsKey(type)) {
listeners.put(type, new ListenerCollection());
}
return (ListenerCollection) listeners.get(type);
}
/**
* A collection of listeners ordered by their registered priority.
*
* @param The type of listener within this collection.
*/
private static class ListenerCollection implements Iterable
{
private List listeners = new ArrayList<>();
private List priorities = new ArrayList<>();
public void add(L listener, int priority) {
int index = Collections.binarySearch(priorities, priority, Collections.reverseOrder());
if (index < 0) {
index = ~index;
}
listeners.add(index, listener);
priorities.add(index, priority);
}
public void remove(L listener) {
int index = listeners.indexOf(listener);
if (index != -1) {
listeners.remove(index);
priorities.remove(index);
}
}
@Override
public Iterator iterator() {
return listeners.iterator();
}
}
}