diff options
Diffstat (limited to 'src/main/java/org/bukkit/event')
-rw-r--r-- | src/main/java/org/bukkit/event/Event.java | 35 | ||||
-rw-r--r-- | src/main/java/org/bukkit/event/HandlerList.java | 67 |
2 files changed, 78 insertions, 24 deletions
diff --git a/src/main/java/org/bukkit/event/Event.java b/src/main/java/org/bukkit/event/Event.java index 92351af2..273e5b26 100644 --- a/src/main/java/org/bukkit/event/Event.java +++ b/src/main/java/org/bukkit/event/Event.java @@ -5,6 +5,23 @@ package org.bukkit.event; */ public abstract class Event { private String name; + private final boolean async; + + /** + * The default constructor is defined for cleaner code. + * This constructor assumes the event is synchronous. + */ + public Event() { + this(false); + } + + /** + * This constructor is used to explicitly declare an event as synchronous or asynchronous. + * @param isAsync true indicates the event will fire asynchronously. false by default + */ + public Event(boolean isAsync) { + this.async = isAsync; + } /** * @return Name of this event @@ -18,6 +35,24 @@ public abstract class Event { public abstract HandlerList getHandlers(); + /** + * Any custom event that should not by synchronized with other events must use the specific constructor. + * These are the caveats of using an asynchronous event: + * <li>The event is never fired from inside code triggered by a synchronous event. + * Attempting to do so results in an {@link java.lang.IllegalStateException}.</li> + * <li>However, asynchronous event handlers may fire synchronous or asynchronous events</li> + * <li>The event may be fired multiple times simultaneously and in any order.</li> + * <li>Any newly registered or unregistered handler is ignored after an event starts execution.</li> + * <li>The handlers for this event may block for any length of time.</li> + * <li>Some implementations may selectively declare a specific event use as asynchronous. + * This behavior should be clearly defined.</li> + * <li>Asynchronous calls are not calculated in the plugin timing system.</li> + * @return false by default, true if the event fires asynchronously + */ + public final boolean isAsynchronous() { + return async; + } + public enum Result { /** diff --git a/src/main/java/org/bukkit/event/HandlerList.java b/src/main/java/org/bukkit/event/HandlerList.java index f48d942f..b0014119 100644 --- a/src/main/java/org/bukkit/event/HandlerList.java +++ b/src/main/java/org/bukkit/event/HandlerList.java @@ -13,7 +13,7 @@ public class HandlerList { /** * Handler array. This field being an array is the key to this system's speed. */ - private RegisteredListener[] handlers = null; + private volatile RegisteredListener[] handlers = null; /** * Dynamic handler lists. These are changed using register() and @@ -33,8 +33,10 @@ public class HandlerList { * you're using fevents in a plugin system. */ public static void bakeAll() { - for (HandlerList h : allLists) { - h.bake(); + synchronized (allLists) { + for (HandlerList h : allLists) { + h.bake(); + } } } @@ -42,11 +44,15 @@ public class HandlerList { * Unregister all listeners from all handler lists. */ public static void unregisterAll() { - for (HandlerList h : allLists) { - for (List<RegisteredListener> list : h.handlerslots.values()) { - list.clear(); + synchronized (allLists) { + for (HandlerList h : allLists) { + synchronized (h) { + for (List<RegisteredListener> list : h.handlerslots.values()) { + list.clear(); + } + h.handlers = null; + } } - h.handlers = null; } } @@ -56,8 +62,10 @@ public class HandlerList { * @param plugin plugin to unregister */ public static void unregisterAll(Plugin plugin) { - for (HandlerList h : allLists) { - h.unregister(plugin); + synchronized (allLists) { + for (HandlerList h : allLists) { + h.unregister(plugin); + } } } @@ -67,8 +75,10 @@ public class HandlerList { * @param listener listener to unregister */ public static void unregisterAll(Listener listener) { - for (HandlerList h : allLists) { - h.unregister(listener); + synchronized (allLists) { + for (HandlerList h : allLists) { + h.unregister(listener); + } } } @@ -81,7 +91,9 @@ public class HandlerList { for (EventPriority o : EventPriority.values()) { handlerslots.put(o, new ArrayList<RegisteredListener>()); } - allLists.add(this); + synchronized (allLists) { + allLists.add(this); + } } /** @@ -89,7 +101,7 @@ public class HandlerList { * * @param listener listener to register */ - public void register(RegisteredListener listener) { + 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; @@ -112,7 +124,7 @@ public class HandlerList { * * @param listener listener to remove */ - public void unregister(RegisteredListener listener) { + public synchronized void unregister(RegisteredListener listener) { if (handlerslots.get(listener.getPriority()).remove(listener)) { handlers = null; } @@ -123,7 +135,7 @@ public class HandlerList { * * @param plugin plugin to remove */ - public void unregister(Plugin plugin) { + public synchronized void unregister(Plugin plugin) { boolean changed = false; for (List<RegisteredListener> list : handlerslots.values()) { for (ListIterator<RegisteredListener> i = list.listIterator(); i.hasNext();) { @@ -141,7 +153,7 @@ public class HandlerList { * * @param listener listener to remove */ - public void unregister(Listener listener) { + public synchronized void unregister(Listener listener) { boolean changed = false; for (List<RegisteredListener> list : handlerslots.values()) { for (ListIterator<RegisteredListener> i = list.listIterator(); i.hasNext();) { @@ -157,7 +169,7 @@ public class HandlerList { /** * Bake HashMap and ArrayLists to 2d array - does nothing if not necessary */ - public void bake() { + public synchronized void bake() { if (handlers != null) return; // don't re-bake when still valid List<RegisteredListener> entries = new ArrayList<RegisteredListener>(); for (Entry<EventPriority, ArrayList<RegisteredListener>> entry : handlerslots.entrySet()) { @@ -172,7 +184,8 @@ public class HandlerList { * @return the array of registered listeners */ public RegisteredListener[] getRegisteredListeners() { - bake(); + RegisteredListener[] handlers; + while ((handlers = this.handlers) == null) bake(); // This prevents fringe cases of returning null return handlers; } @@ -185,11 +198,15 @@ public class HandlerList { */ public static ArrayList<RegisteredListener> getRegisteredListeners(Plugin plugin) { ArrayList<RegisteredListener> listeners = new ArrayList<RegisteredListener>(); - for (HandlerList h : allLists) { - for (List<RegisteredListener> list : h.handlerslots.values()) { - for (RegisteredListener listener : list) { - if (listener.getPlugin().equals(plugin)) { - listeners.add(listener); + synchronized (allLists) { + for (HandlerList h : allLists) { + synchronized (h) { + for (List<RegisteredListener> list : h.handlerslots.values()) { + for (RegisteredListener listener : list) { + if (listener.getPlugin().equals(plugin)) { + listeners.add(listener); + } + } } } } @@ -204,6 +221,8 @@ public class HandlerList { */ @SuppressWarnings("unchecked") public static ArrayList<HandlerList> getHandlerLists() { - return (ArrayList<HandlerList>) allLists.clone(); + synchronized (allLists) { + return (ArrayList<HandlerList>) allLists.clone(); + } } } |