KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > runtime > ListenerList


1 /*******************************************************************************
2  * Copyright (c) 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.runtime;
12
13 /**
14  * Internal class to maintain a list of listeners. This class is a thread safe
15  * list that is optimized for frequent reads and infrequent writes. Copy on write
16  * is used to ensure readers can access the list without synchronization overhead.
17  * Readers are given access to the underlying array data structure for reading,
18  * with the trust that they will not modify the underlying array.
19  * <p>
20  * N.B.: This class is similar to other ListenerLists available throughout
21  * Eclipse code base, except this implementation allows the client to compare
22  * listeners using either equality or identity.
23  * </p>
24  * @since 3.0
25  */

26 public class ListenerList {
27
28     /**
29      * The empty array singleton instance.
30      */

31     private static final Object JavaDoc[] EmptyArray = new Object JavaDoc[0];
32     /**
33      * Mode constant (value 0) indicating that listeners should be compared
34      * using equality.
35      */

36     public static final int EQUALITY = 0;
37     /**
38      * Mode constant (value 1) indicating that listeners should be compared
39      * using identity.
40      */

41     public static final int IDENTITY = 1;
42     
43     /**
44      * Indicates the comparison mode used to determine if two
45      * listeners are equivalent
46      */

47     private final int compareMode;
48
49     /**
50      * The list of listeners. Initially <code>null</code> but initialized
51      * to an array of size capacity the first time a listener is added.
52      * Maintains invariant: listeners != null
53      */

54     private volatile Object JavaDoc[] listeners = EmptyArray;
55
56     /**
57      * Creates a listener list.
58      */

59     public ListenerList() {
60         this(EQUALITY);
61     }
62
63     /**
64      * Creates a listener list using the provided comparison mode.
65      */

66     public ListenerList(int mode) {
67         this.compareMode = mode;
68     }
69
70     /**
71      * Adds the given listener to this list. Has no effect if an equal
72      * listener is already registered.
73      *<p>
74      * This method is synchronized to protect against multiple threads
75      * adding or removing listeners concurrently. This does not block
76      * concurrent readers.
77      *
78      * @param listener the listener to add
79      */

80     public synchronized void add(Object JavaDoc listener) {
81         if (listener == null)
82             throw new IllegalArgumentException JavaDoc();
83         // check for duplicates
84
final int oldSize = listeners.length;
85         for (int i = 0; i < oldSize; ++i)
86             if (same(listener, listeners[i]))
87                 return;
88         // Thread safety: create new array to avoid affecting concurrent readers
89
Object JavaDoc[] newListeners = new Object JavaDoc[oldSize+1];
90         System.arraycopy(listeners, 0, newListeners, 0, oldSize);
91         newListeners[oldSize] = listener;
92         //atomic assignment
93
this.listeners = newListeners;
94     }
95
96     /**
97      * Returns an array containing all the registered listeners.
98      * The resulting array is unaffected by subsequent adds or removes.
99      * If there are no listeners registered, the result is an empty array
100      * singleton instance (no garbage is created).
101      * Use this method when notifying listeners, so that any modifications
102      * to the listener list during the notification will have no effect on
103      * the notification itself.
104      * <p>
105      * Note: callers must not modify the returned array.
106      *
107      * @return the list of registered listeners
108      */

109     public Object JavaDoc[] getListeners() {
110         return listeners;
111     }
112
113     /**
114      * Returns whether this listener list is empty.
115      *
116      * @return <code>true</code> if there are no registered listeners, and
117      * <code>false</code> otherwise
118      */

119     public boolean isEmpty() {
120         return listeners.length == 0;
121     }
122
123     /**
124      * Removes the given listener from this list. Has no effect if an
125      * identical listener was not already registered.
126      * <p>
127      * This method is synchronized to protect against multiple threads
128      * adding or removing listeners concurrently. This does not block
129      * concurrent readers.
130      *
131      * @param listener the listener
132      */

133     public synchronized void remove(Object JavaDoc listener) {
134         if (listener == null)
135             throw new IllegalArgumentException JavaDoc();
136         int oldSize = listeners.length;
137         for (int i = 0; i < oldSize; ++i) {
138             if (same(listener, listeners[i])) {
139                 if (oldSize == 1) {
140                     listeners = EmptyArray;
141                 } else {
142                     // Thread safety: create new array to avoid affecting concurrent readers
143
Object JavaDoc[] newListeners = new Object JavaDoc[oldSize-1];
144                     System.arraycopy(listeners, 0, newListeners, 0, i);
145                     System.arraycopy(listeners, i+1, newListeners, i, oldSize-i-1);
146                     //atomic assignment to field
147
this.listeners = newListeners;
148                 }
149                 return;
150             }
151         }
152     }
153
154     /**
155      * Returns <code>true</code> if the two listeners are the
156      * same based on the specified comparison mode, and <code>false</code>
157      * otherwise.
158      */

159     private boolean same(Object JavaDoc listener1, Object JavaDoc listener2) {
160         return compareMode == IDENTITY ? listener1 == listener2 : listener1.equals(listener2);
161     }
162
163     /**
164      * Returns the number of registered listeners.
165      *
166      * @return the number of registered listeners
167      */

168     public int size() {
169         return listeners.length;
170     }
171 }
172
Popular Tags