LANG-580: Add Event Support Utilities

Applying documentation patch "commons-lang-event-support-docs.patch" from Michael Wooten.

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@978864 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
James W. Carman 2010-07-24 12:49:38 +00:00
parent b1ba66c46e
commit 9a40cd0194

View File

@ -17,56 +17,88 @@
package org.apache.commons.lang3.event; package org.apache.commons.lang3.event;
import org.apache.commons.lang3.Validate;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; 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.
*
* <p/> * <p/>
* To use this class, suppose you want to support ActionEvents. You would do: * To use this class, suppose you want to support ActionEvents. You would do:
* <pre> * <code><pre>
* public class MyActionEventSource * public class MyActionEventSource
* { * {
* private EventListenerSupport<ActionListener> actionListeners = EventListenerSupport.create(ActionListener.class); * private EventListenerSupport<ActionListener> actionListeners =
* <p/> * EventListenerSupport.create(ActionListener.class);
*
* public void someMethodThatFiresAction() * public void someMethodThatFiresAction()
* { * {
* ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "somethingCool"); * ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "somethingCool");
* actionListeners.fire().actionPerformed(e); * actionListeners.fire().actionPerformed(e);
* } * }
* } * }
* </pre> * </pre></code>
* *
* @param <L> The event listener type * @param <L> the type of event listener that is supported by this proxy.
* *
* @since 3.0 * @since 3.0
* @version $Id$ * @version $Id$
*/ */
public class EventListenerSupport<L> public class EventListenerSupport<L>
{ {
/**
* 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<L> listeners = new CopyOnWriteArrayList<L>(); private final List<L> listeners = new CopyOnWriteArrayList<L>();
/**
* The proxy representing the collection of listeners. Calls to this proxy
* object will sent to all registered listeners.
*/
private final L proxy; 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 * @param listenerInterface the type of listener interface that will receive
* @return an EventListenerSupport object which supports the specified listener type * events posted using this class.
*
* @return an EventListenerSupport object which supports the specified
* listener type.
*
* @throws NullPointerException if <code>listenerInterface</code> is
* <code>null</code>.
* @throws IllegalArgumentException if <code>listenerInterface</code> is
* not an interface.
*/ */
public static <T> EventListenerSupport<T> create(Class<T> listenerType) public static <T> EventListenerSupport<T> create(Class<T> listenerInterface)
{ {
return new EventListenerSupport<T>(listenerType); return new EventListenerSupport<T>(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 <code>listenerInterface</code> is
* <code>null</code>.
* @throws IllegalArgumentException if <code>listenerInterface</code> is
* not an interface.
*/ */
public EventListenerSupport(Class<L> listenerInterface) public EventListenerSupport(Class<L> listenerInterface)
{ {
@ -74,25 +106,37 @@ public EventListenerSupport(Class<L> listenerInterface)
} }
/** /**
* Creates an EventListenerSupport object which supports the provided listener interface using the specified * Creates an EventListenerSupport object which supports the provided
* class loader to create the JDK dynamic proxy. * listener interface using the specified class loader to create the JDK
* dynamic proxy.
* *
* @param listenerInterface the listener interface * @param listenerInterface the listener interface.
* @param classLoader the class loader * @param classLoader the class loader.
*
* @throws NullPointerException if <code>listenerInterface</code> or
* <code>classLoader</code> is <code>null</code>.
* @throws IllegalArgumentException if <code>listenerInterface</code> is
* not an interface.
*/ */
public EventListenerSupport(Class<L> listenerInterface, ClassLoader classLoader) public EventListenerSupport(Class<L> listenerInterface, ClassLoader classLoader)
{ {
Validate.notNull(listenerInterface, "Listener interface cannot be null."); Validate.notNull(listenerInterface, "Listener interface cannot be null.");
Validate.notNull(classLoader, "ClassLoader cannot be null."); Validate.notNull(classLoader, "ClassLoader cannot be null.");
Validate.isTrue(listenerInterface.isInterface(), "Class {0} is not an interface", listenerInterface.getName()); Validate.isTrue(listenerInterface.isInterface(),
proxy = listenerInterface.cast(Proxy.newProxyInstance(classLoader, new Class[]{listenerInterface}, "Class {0} is not an interface",
listenerInterface.getName());
proxy = listenerInterface.cast(Proxy.newProxyInstance(classLoader,
new Class[]{listenerInterface},
new ProxyInvocationHandler())); 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() public L fire()
{ {
@ -106,7 +150,10 @@ public L fire()
/** /**
* Registers an event listener. * Registers an event listener.
* *
* @param listener the event listener * @param listener the event listener (may not be <code>null</code>).
*
* @throws NullPointerException if <code>listener</code> is
* <code>null</code>.
*/ */
public void addListener(L listener) public void addListener(L listener)
{ {
@ -117,9 +164,9 @@ public void addListener(L listener)
/** /**
* Returns the number of registered listeners. * 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(); return listeners.size();
} }
@ -127,7 +174,10 @@ public int getListenerCount()
/** /**
* Unregisters an event listener. * Unregisters an event listener.
* *
* @param listener the event listener * @param listener the event listener (may not be <code>null</code>).
*
* @throws NullPointerException if <code>listener</code> is
* <code>null</code>.
*/ */
public void removeListener(L listener) public void removeListener(L listener)
{ {
@ -140,7 +190,18 @@ public void removeListener(L listener)
*/ */
private class ProxyInvocationHandler implements InvocationHandler 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) for (L listener : listeners)
{ {