2 *******************************************************************************
\r
3 * Copyright (C) 2001-2006, 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.LinkedList;
\r
13 import java.util.List;
\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
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
31 public abstract class ICUNotifier {
\r
32 private final Object notifyLock = new Object();
\r
33 private NotifyThread notifyThread;
\r
34 private List listeners;
\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
43 public void addListener(EventListener l) {
\r
45 throw new NullPointerException();
\r
48 if (acceptsListener(l)) {
\r
49 synchronized (notifyLock) {
\r
50 if (listeners == null) {
\r
51 listeners = new ArrayList(5);
\r
53 // identity equality check
\r
54 Iterator iter = listeners.iterator();
\r
55 while (iter.hasNext()) {
\r
56 if (iter.next() == l) {
\r
65 throw new IllegalStateException("Listener invalid for this notifier.");
\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
74 public void removeListener(EventListener l) {
\r
76 throw new NullPointerException();
\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
85 if (listeners.size() == 0) {
\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
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
109 notifyThread.queue(listeners.toArray());
\r
116 * The notification thread.
\r
118 private static class NotifyThread extends Thread {
\r
119 private final ICUNotifier notifier;
\r
120 private final List queue = new LinkedList();
\r
122 NotifyThread(ICUNotifier notifier) {
\r
123 this.notifier = notifier;
\r
127 * Queue the notification on the thread.
\r
129 public void queue(Object[] list) {
\r
130 synchronized (this) {
\r
137 * Wait for a notification to be queued, then notify all
\r
138 * listeners listed in the notification.
\r
140 public void run() {
\r
144 synchronized (this) {
\r
145 while (queue.isEmpty()) {
\r
148 list = (Object[])queue.remove(0);
\r
151 for (int i = 0; i < list.length; ++i) {
\r
152 notifier.notifyListener((EventListener)list[i]);
\r
155 catch (InterruptedException e) {
\r
162 * Subclasses implement this to return true if the listener is
\r
163 * of the appropriate type.
\r
165 protected abstract boolean acceptsListener(EventListener l);
\r
168 * Subclasses implement this to notify the listener.
\r
170 protected abstract void notifyListener(EventListener l);
\r