2 *******************************************************************************
\r
3 * Copyright (C) 2001-2009, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
7 package com.ibm.icu.impl;
\r
9 import java.util.ArrayList;
\r
10 import java.util.EventListener;
\r
11 import java.util.Iterator;
\r
12 import java.util.List;
\r
15 * <p>Abstract implementation of a notification facility. Clients add
\r
16 * EventListeners with addListener and remove them with removeListener.
\r
17 * Notifiers call notifyChanged when they wish to notify listeners.
\r
18 * This queues the listener list on the notification thread, which
\r
19 * eventually dequeues the list and calls notifyListener on each
\r
20 * listener in the list.</p>
\r
22 * <p>Subclasses override acceptsListener and notifyListener
\r
23 * to add type-safe notification. AcceptsListener should return
\r
24 * true if the listener is of the appropriate type; ICUNotifier
\r
25 * itself will ensure the listener is non-null and that the
\r
26 * identical listener is not already registered with the Notifier.
\r
27 * NotifyListener should cast the listener to the appropriate
\r
28 * type and call the appropriate method on the listener.
\r
30 public abstract class ICUNotifier {
\r
31 private final Object notifyLock = new Object();
\r
32 private NotifyThread notifyThread;
\r
33 private List<EventListener> listeners;
\r
36 * Add a listener to be notified when notifyChanged is called.
\r
37 * The listener must not be null. AcceptsListener must return
\r
38 * true for the listener. Attempts to concurrently
\r
39 * register the identical listener more than once will be
\r
40 * silently ignored.
\r
42 public void addListener(EventListener l) {
\r
44 throw new NullPointerException();
\r
47 if (acceptsListener(l)) {
\r
48 synchronized (notifyLock) {
\r
49 if (listeners == null) {
\r
50 listeners = new ArrayList<EventListener>();
\r
52 // identity equality check
\r
53 for (EventListener ll : listeners) {
\r
63 throw new IllegalStateException("Listener invalid for this notifier.");
\r
68 * Stop notifying this listener. The listener must
\r
69 * not be null. Attemps to remove a listener that is
\r
70 * not registered will be silently ignored.
\r
72 public void removeListener(EventListener l) {
\r
74 throw new NullPointerException();
\r
76 synchronized (notifyLock) {
\r
77 if (listeners != null) {
\r
78 // identity equality check
\r
79 Iterator<EventListener> iter = listeners.iterator();
\r
80 while (iter.hasNext()) {
\r
81 if (iter.next() == l) {
\r
83 if (listeners.size() == 0) {
\r
94 * Queue a notification on the notification thread for the current
\r
95 * listeners. When the thread unqueues the notification, notifyListener
\r
96 * is called on each listener from the notification thread.
\r
98 public void notifyChanged() {
\r
99 if (listeners != null) {
\r
100 synchronized (notifyLock) {
\r
101 if (listeners != null) {
\r
102 if (notifyThread == null) {
\r
103 notifyThread = new NotifyThread(this);
\r
104 notifyThread.setDaemon(true);
\r
105 notifyThread.start();
\r
107 notifyThread.queue(listeners.toArray(new EventListener[listeners.size()]));
\r
114 * The notification thread.
\r
116 private static class NotifyThread extends Thread {
\r
117 private final ICUNotifier notifier;
\r
118 private final List<EventListener[]> queue = new ArrayList<EventListener[]>();
\r
120 NotifyThread(ICUNotifier notifier) {
\r
121 this.notifier = notifier;
\r
125 * Queue the notification on the thread.
\r
127 public void queue(EventListener[] list) {
\r
128 synchronized (this) {
\r
135 * Wait for a notification to be queued, then notify all
\r
136 * listeners listed in the notification.
\r
138 public void run() {
\r
139 EventListener[] list;
\r
142 synchronized (this) {
\r
143 while (queue.isEmpty()) {
\r
146 list = queue.remove(0);
\r
149 for (int i = 0; i < list.length; ++i) {
\r
150 notifier.notifyListener(list[i]);
\r
153 catch (InterruptedException e) {
\r
160 * Subclasses implement this to return true if the listener is
\r
161 * of the appropriate type.
\r
163 protected abstract boolean acceptsListener(EventListener l);
\r
166 * Subclasses implement this to notify the listener.
\r
168 protected abstract void notifyListener(EventListener l);
\r