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