001: /*
002: * Copyright 2001-2006 C:1 Financial Services GmbH
003: *
004: * This software is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License Version 2.1, as published by the Free Software Foundation.
007: *
008: * This software is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
011: * Lesser General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public
014: * License along with this library; if not, write to the Free Software
015: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
016: */
017:
018: package de.finix.contelligent.client.event;
019:
020: import java.lang.ref.WeakReference;
021: import java.security.AccessController;
022: import java.security.PrivilegedAction;
023: import java.util.ArrayList;
024: import java.util.Collection;
025: import java.util.Iterator;
026: import java.util.logging.Level;
027: import java.util.logging.Logger;
028:
029: import javax.security.auth.Subject;
030: import javax.swing.SwingUtilities;
031:
032: /**
033: * <em>singleton</em>: Dispatches all related incoming
034: * {@link ContelligentEvents} to all listeners in AWT-Event-Queue. Adding and
035: * removing listeners is thread-safe.
036: */
037: public abstract class ContelligentEventDispatcher {
038:
039: public final static boolean DOES_USE_SWING = true;
040:
041: public final static boolean DOES_NOT_USE_SWING = false;
042:
043: private static Logger logger = Logger
044: .getLogger(ContelligentEventDispatcher.class.getName());
045:
046: private Collection<ListenerEntry> eventListeners = new ArrayList<ListenerEntry>(
047: 100);
048:
049: public void clear() {
050: synchronized (eventListeners) {
051: eventListeners = new ArrayList<ListenerEntry>(100);
052: }
053: }
054:
055: /**
056: * Dispatches event to the registered listeners in AWT-event-queue. It
057: * blocks until all event is dispatched.
058: *
059: * @param event
060: * {@link ContelligentEvent} to dispatch.
061: */
062: protected void addEvent(ContelligentEvent event) {
063: logger.log(Level.FINE, "added event: " + event);
064:
065: ArrayList<ListenerEntry> eventListenersClone;
066: synchronized (eventListeners) {
067: eventListenersClone = new ArrayList<ListenerEntry>(
068: eventListeners);
069: }
070:
071: for (Iterator i = eventListenersClone.iterator(); i.hasNext();) {
072: ListenerEntry entry = (ListenerEntry) i.next();
073: // if weak refernece got invalid, drop listener
074: if (entry.weakListener.get() == null) {
075: removeListener(entry);
076: } else {
077: dispatchEvent(event, entry);
078: }
079: }
080: }
081:
082: /**
083: * Dispatches events to the registered listeners in AWT-event-queue. It
084: * blocks until all events are dispatched.
085: *
086: * @param events
087: * collection of all {@link ContelligentEvent}s to dispatch.
088: */
089: protected void addEvents(final Collection events) {
090: logger.log(Level.FINE, "added events: " + events);
091: if (events.size() == 0)
092: return;
093:
094: ArrayList<ListenerEntry> eventListenersClone;
095: synchronized (eventListeners) {
096: eventListenersClone = new ArrayList<ListenerEntry>(
097: eventListeners);
098: }
099:
100: for (Iterator i = eventListenersClone.iterator(); i.hasNext();) {
101: ListenerEntry entry = (ListenerEntry) i.next();
102: // if weak refernece got invalid, drop listener
103: if (entry.weakListener.get() == null) {
104: removeListener(entry);
105: } else {
106: dispatchEvents(events, entry);
107: }
108: }
109: }
110:
111: /**
112: * Adds the given listener to the list of registered listeners.
113: * <em>WARNING</em>: As this is only remembered as a weak reference be
114: * sure to have a hard reference to it, as otherwise it will be gc'ed.
115: */
116: protected void addListener(ContelligentEventListener listener,
117: Class listenerType, boolean usesSwing) {
118: removeNullListeners();
119: synchronized (eventListeners) {
120: // be sure not to register a listener (with same type) twice, as
121: // this might result to display errors
122: for (Iterator i = eventListeners.iterator(); i.hasNext();) {
123: ListenerEntry entry = (ListenerEntry) i.next();
124: if (entry.weakListener.get() == listener
125: && entry.listenerType == listenerType)
126: return;
127: }
128: ListenerEntry entry = new ListenerEntry(listener,
129: listenerType, usesSwing);
130: eventListeners.add(entry);
131: logger.log(Level.FINE, "added listener: " + entry
132: + "(currently " + eventListeners.size()
133: + " listeners registered)");
134: // System.out.println("added listener: " + entry + "(currently " +
135: // eventListeners.size() + " listeners registered)" );
136: }
137: }
138:
139: /**
140: * Removes the given listener from the list of registered listeners.
141: *
142: * @param listener
143: * listener to be removed
144: */
145: protected void removeListener(ContelligentEventListener listener,
146: Class listenerType) {
147: removeNullListeners();
148: synchronized (eventListeners) {
149: for (Iterator i = eventListeners.iterator(); i.hasNext();) {
150: ListenerEntry entry = (ListenerEntry) i.next();
151: if (entry.weakListener.get() == listener
152: && entry.listenerType == listenerType) {
153: i.remove();
154: logger.log(Level.FINE, "Removed listener "
155: + listener);
156: }
157: }
158: }
159: }
160:
161: private void removeNullListeners() {
162: synchronized (eventListeners) {
163: for (Iterator i = eventListeners.iterator(); i.hasNext();) {
164: ListenerEntry entry = (ListenerEntry) i.next();
165: if (entry.weakListener.get() == null) {
166: i.remove();
167: // System.out.println("Removed null listener: "+entry);
168: logger.log(Level.FINE, "Removed null listener: "
169: + entry);
170: }
171: }
172: }
173: }
174:
175: private void removeListener(ListenerEntry ref) {
176: removeNullListeners();
177: synchronized (eventListeners) {
178: eventListeners.remove(ref);
179: }
180: }
181:
182: private void dispatchEvents(final Collection events,
183: final ListenerEntry entry) {
184: if (entry.usesSwing && !SwingUtilities.isEventDispatchThread()) {
185: final Subject derivedSubject = Subject
186: .getSubject(AccessController.getContext());
187: SwingUtilities.invokeLater(new Runnable() {
188: public void run() {
189: Subject.doAs(derivedSubject,
190: new PrivilegedAction() {
191: public Object run() {
192: dispatchEvents(events, entry);
193: return null;
194: }
195: });
196:
197: }
198: });
199: } else {
200: notifyListener(events, entry);
201: }
202: }
203:
204: private void dispatchEvent(final ContelligentEvent event,
205: final ListenerEntry entry) {
206: if (entry.usesSwing && !SwingUtilities.isEventDispatchThread()) {
207: final Subject derivedSubject = Subject
208: .getSubject(AccessController.getContext());
209: SwingUtilities.invokeLater(new Runnable() {
210:
211: public void run() {
212: Subject.doAs(derivedSubject,
213: new PrivilegedAction() {
214: public Object run() {
215: dispatchEvent(event, entry);
216: return null;
217: }
218: });
219: }
220: });
221: } else {
222: notifyListener(event, entry);
223: }
224: }
225:
226: private void notifyListener(Collection events, ListenerEntry entry) {
227: for (Iterator j = events.iterator(); j.hasNext();) {
228: ContelligentEvent event = (ContelligentEvent) j.next();
229: ContelligentEventListener listener = (ContelligentEventListener) entry.weakListener
230: .get();
231: if (listener != null) {
232: notifyListener(event, listener, entry.listenerType);
233: }
234: }
235: }
236:
237: private void notifyListener(ContelligentEvent event,
238: ListenerEntry entry) {
239: ContelligentEventListener listener = (ContelligentEventListener) entry.weakListener
240: .get();
241: if (listener != null) {
242: notifyListener(event, listener, entry.listenerType);
243: }
244: }
245:
246: protected abstract void notifyListener(ContelligentEvent event,
247: ContelligentEventListener listener, Class listenerType);
248:
249: private final static class ListenerEntry {
250:
251: public WeakReference<ContelligentEventListener> weakListener;
252:
253: public Class listenerType;
254:
255: public boolean usesSwing;
256:
257: public ListenerEntry(ContelligentEventListener listener,
258: Class listenerType, boolean usesSwing) {
259: this .weakListener = new WeakReference<ContelligentEventListener>(
260: listener);
261: this .listenerType = listenerType;
262: this .usesSwing = usesSwing;
263: }
264:
265: public String toString() {
266: return weakListener.get() + ": " + listenerType + " ("
267: + (usesSwing ? "swing)" : "no-swing)");
268: }
269:
270: public boolean equals(Object o) {
271: return (o instanceof ListenerEntry
272: && ((ListenerEntry) o).listenerType
273: .equals(listenerType) && ((ListenerEntry) o).weakListener
274: .get().equals(weakListener.get()));
275: }
276:
277: public int hashCode() {
278: return -1;
279: }
280:
281: }
282: }
|