KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > foxtrot > utils > EventListenerProxy


1 /**
2  * Copyright (c) 2003-2005, Simone Bordet
3  * All rights reserved.
4  *
5  * This software is distributable under the BSD license.
6  * See the terms of the BSD license in the documentation provided with this software.
7  */

8
9 package foxtrot.utils;
10
11 import java.lang.reflect.InvocationHandler JavaDoc;
12 import java.lang.reflect.Method JavaDoc;
13 import java.lang.reflect.Proxy JavaDoc;
14 import java.util.EventListener JavaDoc;
15
16 /**
17  * This class wraps an EventListener subclass (and thus any AWT/Swing event listener such as
18  * <code>ActionListener</code>s, <code>MouseListener</code>s and so on) making sure that if
19  * a wrapped listener is executing, another wrapped listener (even of different type) it is
20  * not executed.
21  * <br>
22  * For example, if a user clicks very quickly on a button, it may trigger the execution of
23  * the associated listener more than once. When the listener contains Foxtrot code, the
24  * second click event is dequeued by Foxtrot and processed again, invoking the listener
25  * again. Using this class to wrap the listener avoids this problem: the second event will
26  * be dequeued and processed by Foxtrot as before, but the wrapped listener will not be
27  * called.
28  * <br>
29  * Example Usage:
30  * <pre>
31  * final JButton apply = new JButton("Apply");
32  * apply.addActionListener((ActionListener)EventListenerProxy.create(ActionListener.class, new ActionListener()
33  * {
34  * public void actionPerformed(ActionEvent e)
35  * {
36  * apply.setEnabled(false);
37  * Worker.post(new Job()
38  * {
39  * public Object run()
40  * {
41  * // Lenghty apply code
42  * }
43  * });
44  * }
45  * }));
46  *
47  * JButton cancel = new JButton("Cancel");
48  * cancel.addActionListener((ActionListener)EventListenerProxy.create(ActionListener.class, new ActionListener()
49  * {
50  * public void actionPerformed(ActionEvent e)
51  * {
52  * // For example, dispose a dialog
53  * }
54  * }));
55  * </pre>
56  * Without using EventListenerProxy, when a user clicks on the apply button and immediately
57  * after on the cancel button, it happens that apply's button listener is executed; in there,
58  * usage of Foxtrot's Worker will dequeue and execute the event associated to the cancel
59  * button click, that will - for example - dispose the dialog <strong>before</strong> the
60  * apply operation is finished. <br />
61  * When using EventListenerProxy instead, the second event - the cancel button click - will
62  * not be executed: the event will be processed without invoking the wrapped listener. <br />
63  * The overhead in the code is to change plain listeners:
64  * <pre>
65  * button.addActionListener(new ActionListener() {...});
66  * </pre>
67  * to this:
68  * <pre>
69  * button.addActionListener((ActionListener)EventListenerProxy.create(ActionListener.class, new ActionListener() {...}));
70  * </pre>
71  * @version $Revision: 1.3 $
72  */

73 public class EventListenerProxy implements InvocationHandler JavaDoc
74 {
75    /**
76     * This flag signals the fact that the wrapped listener is in execution.
77     * It is static since event listeners are never processed in parallel,
78     * but one after the other in the Event Dispatch Thread.
79     * Only after one listener finishes another one can execute.
80     */

81    private static boolean working;
82
83    private EventListener JavaDoc listener;
84
85    /**
86     * Creates an instance that wraps the given listener
87     */

88    protected EventListenerProxy(EventListener JavaDoc listener)
89    {
90       if (listener == null) throw new NullPointerException JavaDoc("EventListener cannot be null");
91       this.listener = listener;
92    }
93
94    /**
95     * Creates a proxy for the given listener. <br>
96     * The listener must implement the given listener interface
97     * @param listenerInterface The interface used to create the proxy
98     * @param listener The listener to proxy
99     * @return A proxy for the given listener
100     * @throws NullPointerException When the interface or the listener is null
101     * @throws IllegalArgumentException When the listener does not implement the interface
102     */

103    public static EventListener JavaDoc create(Class JavaDoc listenerInterface, EventListener JavaDoc listener)
104    {
105       if (!listenerInterface.isInstance(listener)) throw new IllegalArgumentException JavaDoc("EventListener " + listener + " must implement " + listenerInterface.getName());
106       return (EventListener JavaDoc)Proxy.newProxyInstance(listenerInterface.getClassLoader(), new Class JavaDoc[]{listenerInterface}, new EventListenerProxy(listener));
107    }
108
109    public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args) throws Throwable JavaDoc
110    {
111       if (working) return null;
112
113       try
114       {
115          working = true;
116          return method.invoke(listener, args);
117       }
118       finally
119       {
120          working = false;
121       }
122    }
123 }
124
Popular Tags