]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_2_1-src/src/com/ibm/icu/impl/ICUNotifier.java
icu4jsrc
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / icu / impl / ICUNotifier.java
1 /**\r
2  *******************************************************************************\r
3  * Copyright (C) 2001-2006, International Business Machines Corporation and    *\r
4  * others. All Rights Reserved.                                                *\r
5  *******************************************************************************\r
6  */\r
7 package com.ibm.icu.impl;\r
8 \r
9 import java.util.ArrayList;\r
10 import java.util.EventListener;\r
11 import java.util.Iterator;\r
12 import java.util.LinkedList;\r
13 import java.util.List;\r
14 \r
15 /**\r
16  * <p>Abstract implementation of a notification facility.  Clients add\r
17  * EventListeners with addListener and remove them with removeListener.\r
18  * Notifiers call notifyChanged when they wish to notify listeners.\r
19  * This queues the listener list on the notification thread, which\r
20  * eventually dequeues the list and calls notifyListener on each\r
21  * listener in the list.</p>\r
22  *\r
23  * <p>Subclasses override acceptsListener and notifyListener \r
24  * to add type-safe notification.  AcceptsListener should return\r
25  * true if the listener is of the appropriate type; ICUNotifier\r
26  * itself will ensure the listener is non-null and that the\r
27  * identical listener is not already registered with the Notifier.\r
28  * NotifyListener should cast the listener to the appropriate \r
29  * type and call the appropriate method on the listener.\r
30  */\r
31 public abstract class ICUNotifier {\r
32     private final Object notifyLock = new Object();\r
33     private NotifyThread notifyThread;\r
34     private List listeners;\r
35 \r
36     /**\r
37      * Add a listener to be notified when notifyChanged is called.\r
38      * The listener must not be null. AcceptsListener must return\r
39      * true for the listener.  Attempts to concurrently\r
40      * register the identical listener more than once will be\r
41      * silently ignored.  \r
42      */\r
43     public void addListener(EventListener l) {\r
44         if (l == null) {\r
45             throw new NullPointerException();\r
46         }\r
47 \r
48         if (acceptsListener(l)) {\r
49             synchronized (notifyLock) {\r
50                 if (listeners == null) {\r
51                     listeners = new ArrayList(5);\r
52                 } else {\r
53                     // identity equality check\r
54                     Iterator iter = listeners.iterator();\r
55                     while (iter.hasNext()) {\r
56                         if (iter.next() == l) {\r
57                             return;\r
58                         }\r
59                     }\r
60                 }\r
61 \r
62                 listeners.add(l);\r
63             }\r
64         } else {\r
65             throw new IllegalStateException("Listener invalid for this notifier.");\r
66         }\r
67     }\r
68 \r
69     /**\r
70      * Stop notifying this listener.  The listener must\r
71      * not be null.  Attemps to remove a listener that is\r
72      * not registered will be silently ignored.\r
73      */\r
74     public void removeListener(EventListener l) {\r
75         if (l == null) {\r
76             throw new NullPointerException();\r
77         }\r
78         synchronized (notifyLock) {\r
79             if (listeners != null) {\r
80                 // identity equality check\r
81                 Iterator iter = listeners.iterator();\r
82                 while (iter.hasNext()) {\r
83                     if (iter.next() == l) {\r
84                         iter.remove();\r
85                         if (listeners.size() == 0) {\r
86                             listeners = null;\r
87                         }\r
88                         return;\r
89                     }\r
90                 }\r
91             }\r
92         }\r
93     }\r
94 \r
95     /**\r
96      * Queue a notification on the notification thread for the current\r
97      * listeners.  When the thread unqueues the notification, notifyListener\r
98      * is called on each listener from the notification thread.\r
99      */\r
100     public void notifyChanged() {\r
101         if (listeners != null) {\r
102             synchronized (notifyLock) {\r
103                 if (listeners != null) {\r
104                     if (notifyThread == null) {\r
105                         notifyThread = new NotifyThread(this);\r
106                         notifyThread.setDaemon(true);\r
107                         notifyThread.start();\r
108                     }\r
109                     notifyThread.queue(listeners.toArray());\r
110                 }\r
111             }\r
112         }\r
113     }\r
114 \r
115     /**\r
116      * The notification thread.\r
117      */\r
118     private static class NotifyThread extends Thread {\r
119         private final ICUNotifier notifier;\r
120         private final List queue = new LinkedList();\r
121 \r
122         NotifyThread(ICUNotifier notifier) {\r
123             this.notifier = notifier;\r
124         }\r
125 \r
126         /**\r
127          * Queue the notification on the thread.\r
128          */\r
129         public void queue(Object[] list) {\r
130             synchronized (this) {\r
131                 queue.add(list);\r
132                 notify();\r
133             }\r
134         }\r
135 \r
136         /**\r
137          * Wait for a notification to be queued, then notify all\r
138          * listeners listed in the notification.\r
139          */\r
140         public void run() {\r
141             Object[] list;\r
142             while (true) {\r
143                 try {\r
144                     synchronized (this) {\r
145                         while (queue.isEmpty()) {\r
146                             wait();\r
147                         }\r
148                         list = (Object[])queue.remove(0);\r
149                     }\r
150 \r
151                     for (int i = 0; i < list.length; ++i) {\r
152                         notifier.notifyListener((EventListener)list[i]);\r
153                     }\r
154                 }\r
155                 catch (InterruptedException e) {\r
156                 }\r
157             }\r
158         }\r
159     }\r
160 \r
161     /**\r
162      * Subclasses implement this to return true if the listener is\r
163      * of the appropriate type.\r
164      */\r
165     protected abstract boolean acceptsListener(EventListener l);\r
166 \r
167     /**\r
168      * Subclasses implement this to notify the listener.\r
169      */\r
170     protected abstract void notifyListener(EventListener l);\r
171 }\r