KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ibm > icu > impl > ICUNotifier


1 /**
2  *******************************************************************************
3  * Copyright (C) 2001-2006, International Business Machines Corporation and *
4  * others. All Rights Reserved. *
5  *******************************************************************************
6  */

7 package com.ibm.icu.impl;
8
9 import java.util.ArrayList JavaDoc;
10 import java.util.EventListener JavaDoc;
11 import java.util.Iterator JavaDoc;
12 import java.util.LinkedList JavaDoc;
13 import java.util.List JavaDoc;
14
15 /**
16  * <p>Abstract implementation of a notification facility. Clients add
17  * EventListeners with addListener and remove them with removeListener.
18  * Notifiers call notifyChanged when they wish to notify listeners.
19  * This queues the listener list on the notification thread, which
20  * eventually dequeues the list and calls notifyListener on each
21  * listener in the list.</p>
22  *
23  * <p>Subclasses override acceptsListener and notifyListener
24  * to add type-safe notification. AcceptsListener should return
25  * true if the listener is of the appropriate type; ICUNotifier
26  * itself will ensure the listener is non-null and that the
27  * identical listener is not already registered with the Notifier.
28  * NotifyListener should cast the listener to the appropriate
29  * type and call the appropriate method on the listener.
30  */

31 public abstract class ICUNotifier {
32     private final Object JavaDoc notifyLock = new Object JavaDoc();
33     private NotifyThread notifyThread;
34     private List JavaDoc listeners;
35
36     /**
37      * Add a listener to be notified when notifyChanged is called.
38      * The listener must not be null. AcceptsListener must return
39      * true for the listener. Attempts to concurrently
40      * register the identical listener more than once will be
41      * silently ignored.
42      */

43     public void addListener(EventListener JavaDoc l) {
44         if (l == null) {
45             throw new NullPointerException JavaDoc();
46         }
47
48         if (acceptsListener(l)) {
49             synchronized (notifyLock) {
50                 if (listeners == null) {
51                     listeners = new ArrayList JavaDoc(5);
52                 } else {
53                     // identity equality check
54
Iterator JavaDoc iter = listeners.iterator();
55                     while (iter.hasNext()) {
56                         if (iter.next() == l) {
57                             return;
58                         }
59                     }
60                 }
61
62                 listeners.add(l);
63             }
64         } else {
65             throw new IllegalStateException JavaDoc("Listener invalid for this notifier.");
66         }
67     }
68
69     /**
70      * Stop notifying this listener. The listener must
71      * not be null. Attemps to remove a listener that is
72      * not registered will be silently ignored.
73      */

74     public void removeListener(EventListener JavaDoc l) {
75         if (l == null) {
76             throw new NullPointerException JavaDoc();
77         }
78         synchronized (notifyLock) {
79             if (listeners != null) {
80                 // identity equality check
81
Iterator JavaDoc iter = listeners.iterator();
82                 while (iter.hasNext()) {
83                     if (iter.next() == l) {
84                         iter.remove();
85                         if (listeners.size() == 0) {
86                             listeners = null;
87                         }
88                         return;
89                     }
90                 }
91             }
92         }
93     }
94
95     /**
96      * Queue a notification on the notification thread for the current
97      * listeners. When the thread unqueues the notification, notifyListener
98      * is called on each listener from the notification thread.
99      */

100     public void notifyChanged() {
101         if (listeners != null) {
102             synchronized (notifyLock) {
103                 if (listeners != null) {
104                     if (notifyThread == null) {
105                         notifyThread = new NotifyThread(this);
106                         notifyThread.setDaemon(true);
107                         notifyThread.start();
108                     }
109                     notifyThread.queue(listeners.toArray());
110                 }
111             }
112         }
113     }
114
115     /**
116      * The notification thread.
117      */

118     private static class NotifyThread extends Thread JavaDoc {
119         private final ICUNotifier notifier;
120         private final List JavaDoc queue = new LinkedList JavaDoc();
121
122         NotifyThread(ICUNotifier notifier) {
123             this.notifier = notifier;
124         }
125
126         /**
127          * Queue the notification on the thread.
128          */

129         public void queue(Object JavaDoc[] list) {
130             synchronized (this) {
131                 queue.add(list);
132                 notify();
133             }
134         }
135
136         /**
137          * Wait for a notification to be queued, then notify all
138          * listeners listed in the notification.
139          */

140         public void run() {
141             Object JavaDoc[] list;
142             while (true) {
143                 try {
144                     synchronized (this) {
145                         while (queue.isEmpty()) {
146                             wait();
147                         }
148                         list = (Object JavaDoc[])queue.remove(0);
149                     }
150
151                     for (int i = 0; i < list.length; ++i) {
152                         notifier.notifyListener((EventListener JavaDoc)list[i]);
153                     }
154                 }
155                 catch (InterruptedException JavaDoc e) {
156                 }
157             }
158         }
159     }
160
161     /**
162      * Subclasses implement this to return true if the listener is
163      * of the appropriate type.
164      */

165     protected abstract boolean acceptsListener(EventListener JavaDoc l);
166
167     /**
168      * Subclasses implement this to notify the listener.
169      */

170     protected abstract void notifyListener(EventListener JavaDoc l);
171 }
172
Popular Tags