001: /*
002: * All content copyright (c) 2003-2007 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.util.event;
006:
007: import java.io.Serializable;
008: import java.util.ArrayList;
009: import java.util.Collections;
010: import java.util.Iterator;
011: import java.util.LinkedList;
012: import java.util.List;
013:
014: /**
015: * Generic Event/Listener implementation.
016: * <p>
017: * USAGE:
018: * </p>
019: *
020: * <pre>
021: * class Worker implements Runnable {
022: *
023: * private final EventMulticaster updateObserver;
024: *
025: * private void doWork() {
026: * if (stateChanged()) updateObserver.fireUpdateEvent();
027: *
028: * ...
029: *
030: * public void addWorkEventListener(UpdateEventListener listener) {
031: * updateObserver.addListener(listener);
032: *
033: * ...
034: *
035: * class Master {
036: *
037: * private void delegateTask() {
038: * Worker worker = new Worker();
039: * worker.addWorkEventListener(new UpdateEventListener() {
040: * public void handleUpdate(Object data) {
041: * System.out.println(data);
042: * }
043: * });
044: *
045: * ...
046: * </pre>
047: */
048: public final class EventMulticaster implements Serializable {
049:
050: private transient UpdateEventListener eventListener;
051: private transient EventQueue queue;
052: private transient Thread dispatchThread;
053: private volatile boolean dispatchInterrupted;
054:
055: public synchronized void enableDispatchThread() {
056: this .eventListener = null;
057: this .queue = new EventQueue();
058: this .dispatchThread = new Thread() {
059: public void run() {
060: QueueEvent event = null;
061: try {
062: while (true) {
063: event = queue.take();
064: event.listener.handleUpdate(event.data);
065: }
066: } catch (InterruptedException e) {
067: dispatchInterrupted = true;
068: }
069: }
070: };
071: dispatchThread.setDaemon(true);
072: dispatchThread.start();
073: }
074:
075: public void fireUpdateEvent() {
076: fireUpdateEvent(null);
077: }
078:
079: public synchronized void fireUpdateEvent(UpdateEvent data) {
080: if (dispatchInterrupted)
081: throw new IllegalStateException();
082: if (eventListener != null
083: && (data == null || eventListener != data.source)) {
084: if (queue == null)
085: eventListener.handleUpdate(data);
086: else {
087: QueueEvent event = new QueueEvent();
088: event.listener = eventListener;
089: event.data = data;
090: queue.offer(event);
091: }
092: }
093: }
094:
095: public synchronized void addListener(UpdateEventListener listener) {
096: if (eventListener == null) {
097: eventListener = listener;
098: } else if (eventListener instanceof BroadcastListener) {
099: ((BroadcastListener) eventListener).add(listener);
100: } else {
101: BroadcastListener broadcast = new BroadcastListener();
102: broadcast.add(eventListener);
103: broadcast.add(listener);
104: eventListener = broadcast;
105: }
106: }
107:
108: public synchronized boolean removeListener(
109: UpdateEventListener listener) {
110: if (eventListener instanceof EventMulticaster.BroadcastListener) {
111: BroadcastListener broadcast = (BroadcastListener) eventListener;
112: if (!broadcast.remove(listener))
113: return false;
114: if (broadcast.size() == 1)
115: eventListener = broadcast.pop();
116: return true;
117: } else {
118: if (eventListener != listener)
119: return false;
120: eventListener = null;
121: return true;
122: }
123: }
124:
125: // --------------------------------------------------------------------------------
126:
127: private class BroadcastListener implements UpdateEventListener,
128: Serializable {
129:
130: private List listeners = Collections
131: .synchronizedList(new ArrayList());
132:
133: public void handleUpdate(UpdateEvent data) {
134: for (Iterator iter = listeners.iterator(); iter.hasNext();) {
135: UpdateEventListener listener = (UpdateEventListener) iter
136: .next();
137: if (listener == data.source)
138: continue;
139: if (queue == null)
140: listener.handleUpdate(data);
141: else {
142: QueueEvent event = new QueueEvent();
143: event.listener = listener;
144: event.data = data;
145: queue.offer(event);
146: }
147: }
148: }
149:
150: private void add(UpdateEventListener listener) {
151: listeners.add(listener);
152: }
153:
154: private boolean remove(UpdateEventListener listener) {
155: return listeners.remove(listener);
156: }
157:
158: private int size() {
159: return listeners.size();
160: }
161:
162: private UpdateEventListener pop() {
163: return (UpdateEventListener) listeners.iterator().next();
164: }
165: }
166:
167: // --------------------------------------------------------------------------------
168:
169: private class QueueEvent implements Serializable {
170: private UpdateEventListener listener;
171: private UpdateEvent data;
172: }
173:
174: // --------------------------------------------------------------------------------
175:
176: private class EventQueue implements Serializable {
177:
178: private final List list = new LinkedList();
179:
180: private void offer(QueueEvent val) {
181: if (val == null)
182: throw new NullPointerException();
183: synchronized (list) {
184: list.add(val);
185: list.notify();
186: }
187: }
188:
189: private QueueEvent take() throws InterruptedException {
190: synchronized (list) {
191: while (list.size() == 0) {
192: list.wait();
193: }
194: return (QueueEvent) list.remove(0);
195: }
196: }
197: }
198: }
|