001: /*
002: * Copyright (C) 2004 NNL Technology AB
003: * Visit www.infonode.net for information about InfoNode(R)
004: * products and how to contact NNL Technology AB.
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
019: * MA 02111-1307, USA.
020: */
021:
022: // $Id: Signal.java,v 1.3 2005/12/04 13:46:04 jesper Exp $
023: package net.infonode.util.signal;
024:
025: import net.infonode.util.collection.CopyOnWriteArrayList;
026: import net.infonode.util.collection.EmptyIterator;
027:
028: import java.lang.ref.ReferenceQueue;
029: import java.lang.ref.WeakReference;
030: import java.util.Collection;
031: import java.util.Iterator;
032:
033: /**
034: * @author $Author: jesper $
035: * @version $Revision: 1.3 $
036: */
037: public class Signal {
038: private static class WeakListener extends WeakReference implements
039: SignalListener {
040: private SignalHookImpl hook;
041:
042: protected WeakListener(SignalListener listener,
043: ReferenceQueue q, SignalHookImpl hook) {
044: super (listener, q);
045: this .hook = hook;
046: }
047:
048: public void remove() {
049: hook.removeWeak(this );
050: }
051:
052: public void signalEmitted(Signal signal, Object object) {
053: SignalListener l = (SignalListener) get();
054:
055: if (l != null)
056: l.signalEmitted(signal, object);
057: }
058: }
059:
060: private class SignalHookImpl implements SignalHook {
061: public void add(SignalListener listener) {
062: addListener(listener);
063: }
064:
065: public void addWeak(SignalListener listener) {
066: addListener(new WeakListener(listener, refQueue, this ));
067: }
068:
069: public boolean remove(SignalListener listener) {
070: return removeListener(listener);
071: }
072:
073: public void removeWeak(WeakListener ref) {
074: removeWeakListener(ref);
075: }
076: }
077:
078: private static ReferenceQueue refQueue = new ReferenceQueue();
079:
080: static {
081: Thread thread = new Thread(new Runnable() {
082: public void run() {
083: try {
084: while (true) {
085: ((WeakListener) refQueue.remove()).remove();
086: }
087: } catch (InterruptedException e) {
088: }
089: }
090: });
091: thread.setDaemon(true);
092: thread.start();
093: }
094:
095: private boolean reverseNotifyOrder;
096: private CopyOnWriteArrayList listeners;
097: private SignalHookImpl signalHook = new SignalHookImpl();
098:
099: public Signal() {
100: this (true);
101: }
102:
103: public Signal(boolean reverseNotifyOrder) {
104: this .reverseNotifyOrder = reverseNotifyOrder;
105: }
106:
107: protected void firstListenerAdded() {
108: }
109:
110: protected void lastListenerRemoved() {
111: }
112:
113: public synchronized void addListener(SignalListener listener) {
114: if (listeners == null)
115: listeners = new CopyOnWriteArrayList(2);
116:
117: listeners.add(listener);
118:
119: if (listeners.size() == 1)
120: firstListenerAdded();
121: }
122:
123: public synchronized boolean removeListener(SignalListener listener) {
124: if (listeners != null) {
125: for (int i = 0; i < listeners.size(); i++) {
126: Object o = listeners.get(i);
127:
128: if (o == listener
129: || (o instanceof WeakListener && ((WeakListener) o)
130: .get() == listener)) {
131: removeListener(i);
132: return true;
133: }
134: }
135: }
136:
137: return false;
138: }
139:
140: protected synchronized void removeWeakListener(WeakListener listener) {
141: if (listeners != null) {
142: for (int i = 0; i < listeners.size(); i++) {
143: Object o = listeners.get(i);
144:
145: if (o == listener) {
146: removeListener(i);
147: break;
148: }
149: }
150: }
151: }
152:
153: protected synchronized void removeListener(int index) {
154: listeners.remove(index);
155:
156: if (listeners.size() == 0) {
157: listeners = null;
158: lastListenerRemoved();
159: }
160: }
161:
162: public synchronized boolean hasListeners() {
163: return listeners != null && listeners.size() > 0;
164: }
165:
166: public synchronized Iterator iterator() {
167: return listeners == null ? EmptyIterator.INSTANCE : listeners
168: .iterator();
169: }
170:
171: public SignalHook getHook() {
172: return signalHook;
173: }
174:
175: public synchronized void emit(Object object) {
176: Object[] e;
177: int size;
178:
179: synchronized (this ) {
180: if (listeners == null)
181: return;
182:
183: e = listeners.getElements();
184: size = listeners.size();
185: }
186:
187: if (reverseNotifyOrder) {
188: for (int i = size - 1; i >= 0; i--)
189: ((SignalListener) e[i]).signalEmitted(this , object);
190: } else {
191: for (int i = 0; i < size; i++)
192: ((SignalListener) e[i]).signalEmitted(this , object);
193: }
194: }
195:
196: public void removeListeners(Collection toRemove) {
197: listeners.removeAll(toRemove);
198: }
199:
200: }
|