org.bukkit.event.HandlerList Maven / Gradle / Ivy
package org.bukkit.event;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredListener;
import java.util.*;
import java.util.Map.Entry;
/**
* A list of event handlers, stored per-event. Based on lahwran's fevents.
*/
public class HandlerList {
/**
* List of all HandlerLists which have been created, for use in bakeAll()
*/
private static final ArrayList allLists = new ArrayList();
/**
* Dynamic handler lists. These are changed using register() and
* unregister() and are automatically baked to the handlers array any time
* they have changed.
*/
private final EnumMap> handlerslots;
/**
* Handler array. This field being an array is the key to this system's
* speed.
*/
private volatile RegisteredListener[] handlers = null;
/**
* Create a new handler list and initialize using EventPriority.
*
* The HandlerList is then added to meta-list for use in bakeAll()
*/
public HandlerList() {
handlerslots = new EnumMap>(EventPriority.class);
for (EventPriority o : EventPriority.values()) {
handlerslots.put(o, new ArrayList());
}
synchronized (allLists) {
allLists.add(this);
}
}
/**
* Bake all handler lists. Best used just after all normal event
* registration is complete, ie just after all plugins are loaded if
* you're using fevents in a plugin system.
*/
public static void bakeAll() {
synchronized (allLists) {
for (HandlerList h : allLists) {
h.bake();
}
}
}
/**
* Unregister all listeners from all handler lists.
*/
public static void unregisterAll() {
synchronized (allLists) {
for (HandlerList h : allLists) {
synchronized (h) {
for (List list : h.handlerslots.values()) {
list.clear();
}
h.handlers = null;
}
}
}
}
/**
* Unregister a specific plugin's listeners from all handler lists.
*
* @param plugin plugin to unregister
*/
public static void unregisterAll(Plugin plugin) {
synchronized (allLists) {
for (HandlerList h : allLists) {
h.unregister(plugin);
}
}
}
/**
* Unregister a specific listener from all handler lists.
*
* @param listener listener to unregister
*/
public static void unregisterAll(Listener listener) {
synchronized (allLists) {
for (HandlerList h : allLists) {
h.unregister(listener);
}
}
}
/**
* Get a specific plugin's registered listeners associated with this
* handler list
*
* @param plugin the plugin to get the listeners of
* @return the list of registered listeners
*/
public static ArrayList getRegisteredListeners(Plugin plugin) {
ArrayList listeners = new ArrayList();
synchronized (allLists) {
for (HandlerList h : allLists) {
synchronized (h) {
for (List list : h.handlerslots.values()) {
for (RegisteredListener listener : list) {
if (listener.getPlugin().equals(plugin)) {
listeners.add(listener);
}
}
}
}
}
}
return listeners;
}
/**
* Get a list of all handler lists for every event type
*
* @return the list of all handler lists
*/
@SuppressWarnings("unchecked")
public static ArrayList getHandlerLists() {
synchronized (allLists) {
return (ArrayList) allLists.clone();
}
}
/**
* Register a new listener in this handler list
*
* @param listener listener to register
*/
public synchronized void register(RegisteredListener listener) {
if (handlerslots.get(listener.getPriority()).contains(listener))
throw new IllegalStateException("This listener is already registered to priority " + listener.getPriority().toString());
handlers = null;
handlerslots.get(listener.getPriority()).add(listener);
}
/**
* Register a collection of new listeners in this handler list
*
* @param listeners listeners to register
*/
public void registerAll(Collection listeners) {
for (RegisteredListener listener : listeners) {
register(listener);
}
}
/**
* Remove a listener from a specific order slot
*
* @param listener listener to remove
*/
public synchronized void unregister(RegisteredListener listener) {
if (handlerslots.get(listener.getPriority()).remove(listener)) {
handlers = null;
}
}
/**
* Remove a specific plugin's listeners from this handler
*
* @param plugin plugin to remove
*/
public synchronized void unregister(Plugin plugin) {
boolean changed = false;
for (List list : handlerslots.values()) {
for (ListIterator i = list.listIterator(); i.hasNext(); ) {
if (i.next().getPlugin().equals(plugin)) {
i.remove();
changed = true;
}
}
}
if (changed) handlers = null;
}
/**
* Remove a specific listener from this handler
*
* @param listener listener to remove
*/
public synchronized void unregister(Listener listener) {
boolean changed = false;
for (List list : handlerslots.values()) {
for (ListIterator i = list.listIterator(); i.hasNext(); ) {
if (i.next().getListener().equals(listener)) {
i.remove();
changed = true;
}
}
}
if (changed) handlers = null;
}
/**
* Bake HashMap and ArrayLists to 2d array - does nothing if not necessary
*/
public synchronized void bake() {
if (handlers != null) return; // don't re-bake when still valid
List entries = new ArrayList();
for (Entry> entry : handlerslots.entrySet()) {
entries.addAll(entry.getValue());
}
handlers = entries.toArray(new RegisteredListener[entries.size()]);
}
/**
* Get the baked registered listeners associated with this handler list
*
* @return the array of registered listeners
*/
public RegisteredListener[] getRegisteredListeners() {
RegisteredListener[] handlers;
while ((handlers = this.handlers) == null) bake(); // This prevents fringe cases of returning null
return handlers;
}
}