diff --git a/src/main/java/org/apache/commons/lang3/event/EventListenerSupport.java b/src/main/java/org/apache/commons/lang3/event/EventListenerSupport.java index ce5b2f359..69da3d6bc 100644 --- a/src/main/java/org/apache/commons/lang3/event/EventListenerSupport.java +++ b/src/main/java/org/apache/commons/lang3/event/EventListenerSupport.java @@ -17,56 +17,88 @@ package org.apache.commons.lang3.event; -import org.apache.commons.lang3.Validate; - import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import org.apache.commons.lang3.Validate; + /** - * An EventListenerSupport object can be used to manage a list of event listeners of a particular type. + * An EventListenerSupport object can be used to manage a list of event + * listeners of a particular type. The class provides + * {@link #addListener(Object)} and {@link #removeListener(Object)} methods + * for registering listeners, as well as a {@link #fire()} method for firing + * events to the listeners. + * *

* To use this class, suppose you want to support ActionEvents. You would do: - *

+ * 
  * public class MyActionEventSource
  * {
- *   private EventListenerSupport actionListeners = EventListenerSupport.create(ActionListener.class);
- * 

+ * private EventListenerSupport actionListeners = + * EventListenerSupport.create(ActionListener.class); + * * public void someMethodThatFiresAction() * { * ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "somethingCool"); * actionListeners.fire().actionPerformed(e); * } * } - *

+ *
* - * @param The event listener type + * @param the type of event listener that is supported by this proxy. * * @since 3.0 * @version $Id$ */ public class EventListenerSupport { + /** + * The list used to hold the registered listeners. This list is + * intentionally a thread-safe copy-on-write-array so that traversals over + * the list of listeners will be atomic. + */ private final List listeners = new CopyOnWriteArrayList(); + + /** + * The proxy representing the collection of listeners. Calls to this proxy + * object will sent to all registered listeners. + */ private final L proxy; /** - * Creates an EventListenerSupport object which supports the specified listener type. + * Creates an EventListenerSupport object which supports the specified + * listener type. * - * @param listenerType the listener type - * @return an EventListenerSupport object which supports the specified listener type + * @param listenerInterface the type of listener interface that will receive + * events posted using this class. + * + * @return an EventListenerSupport object which supports the specified + * listener type. + * + * @throws NullPointerException if listenerInterface is + * null. + * @throws IllegalArgumentException if listenerInterface is + * not an interface. */ - public static EventListenerSupport create(Class listenerType) + public static EventListenerSupport create(Class listenerInterface) { - return new EventListenerSupport(listenerType); + return new EventListenerSupport(listenerInterface); } /** - * Creates an EventListenerSupport object which supports the provided listener interface. + * Creates an EventListenerSupport object which supports the provided + * listener interface. * - * @param listenerInterface the listener interface + * @param listenerInterface the type of listener interface that will receive + * events posted using this class. + * + * @throws NullPointerException if listenerInterface is + * null. + * @throws IllegalArgumentException if listenerInterface is + * not an interface. */ public EventListenerSupport(Class listenerInterface) { @@ -74,25 +106,37 @@ public EventListenerSupport(Class listenerInterface) } /** - * Creates an EventListenerSupport object which supports the provided listener interface using the specified - * class loader to create the JDK dynamic proxy. + * Creates an EventListenerSupport object which supports the provided + * listener interface using the specified class loader to create the JDK + * dynamic proxy. * - * @param listenerInterface the listener interface - * @param classLoader the class loader + * @param listenerInterface the listener interface. + * @param classLoader the class loader. + * + * @throws NullPointerException if listenerInterface or + * classLoader is null. + * @throws IllegalArgumentException if listenerInterface is + * not an interface. */ public EventListenerSupport(Class listenerInterface, ClassLoader classLoader) { Validate.notNull(listenerInterface, "Listener interface cannot be null."); Validate.notNull(classLoader, "ClassLoader cannot be null."); - Validate.isTrue(listenerInterface.isInterface(), "Class {0} is not an interface", listenerInterface.getName()); - proxy = listenerInterface.cast(Proxy.newProxyInstance(classLoader, new Class[]{listenerInterface}, + Validate.isTrue(listenerInterface.isInterface(), + "Class {0} is not an interface", + listenerInterface.getName()); + proxy = listenerInterface.cast(Proxy.newProxyInstance(classLoader, + new Class[]{listenerInterface}, new ProxyInvocationHandler())); } /** - * Returns a proxy object which can be used to call listener methods on all of the registered event listeners. + * Returns a proxy object which can be used to call listener methods on all + * of the registered event listeners. All calls made to this proxy will be + * forwarded to all registered listeners. * - * @return a proxy object which can be used to call listener methods on all of the registered event listeners + * @return a proxy object which can be used to call listener methods on all + * of the registered event listeners */ public L fire() { @@ -106,7 +150,10 @@ public L fire() /** * Registers an event listener. * - * @param listener the event listener + * @param listener the event listener (may not be null). + * + * @throws NullPointerException if listener is + * null. */ public void addListener(L listener) { @@ -117,9 +164,9 @@ public void addListener(L listener) /** * Returns the number of registered listeners. * - * @return the number of registered listeners + * @return the number of registered listeners. */ - public int getListenerCount() + int getListenerCount() { return listeners.size(); } @@ -127,7 +174,10 @@ public int getListenerCount() /** * Unregisters an event listener. * - * @param listener the event listener + * @param listener the event listener (may not be null). + * + * @throws NullPointerException if listener is + * null. */ public void removeListener(L listener) { @@ -140,7 +190,18 @@ public void removeListener(L listener) */ private class ProxyInvocationHandler implements InvocationHandler { - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + /** + * Propagates the method call to all registered listeners in place of + * the proxy listener object. + * + * @param proxy the proxy object representing a listener on which the + * invocation was called. + * @param method the listener method that will be called on all of the + * listeners. + * @param args event arguments to propogate to the listeners. + */ + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { for (L listener : listeners) {