KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > hivemind > util > EventListenerList


1 // Copyright 2004, 2005 The Apache Software Foundation
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15 package org.apache.hivemind.util;
16
17 import java.util.Iterator JavaDoc;
18
19 /**
20  * Convienience class for tracking a list of event listeners. Works efficiently
21  * (using a copy-on-write approach) to iterating through the listeners in
22  * the list even when the list of listeners may be modified.
23  *
24  * <p>
25  * EventListenerList <em>is</em> thread-safe.
26  *
27  * @author Howard Lewis Ship
28  */

29 public class EventListenerList
30 {
31     private static final int START_SIZE = 5;
32
33     private Object JavaDoc[] _listeners;
34     private int _count;
35     private int _iteratorCount;
36     private int _uid;
37
38     private class ListenerIterator implements Iterator JavaDoc
39     {
40         private Object JavaDoc[] _localListeners;
41         private int _localCount;
42         private int _localUid;
43         private int _pos;
44
45         private ListenerIterator()
46         {
47             _localListeners = _listeners;
48             _localCount = _count;
49             _localUid = _uid;
50         }
51
52         public boolean hasNext()
53         {
54             if (_pos >= _localCount)
55             {
56                 // If _listeners has not been recopied during the lifespan
57
// of this iterator, then knock the count down by one.
58

59                 adjustIteratorCount(_localUid);
60
61                 _localListeners = null;
62                 _localCount = 0;
63                 _localUid = -1;
64                 _pos = 0;
65
66                 return false;
67             }
68
69             return true;
70         }
71
72         public Object JavaDoc next()
73         {
74             return _localListeners[_pos++];
75         }
76
77         public void remove()
78         {
79             throw new UnsupportedOperationException JavaDoc();
80         }
81
82     }
83
84     /**
85      * Returns an Iterator used to find all the listeners previously added.
86      * The order in which listeners are returned is not guaranteed.
87      * Currently, you may not invoke <code>remove()</code> on the Iterator.
88      *
89      * <p>
90      * Invoking this method takes a "snapshot" of the current list of listeners.
91      * You may invoke {@link #addListener(Object)} or {@link #removeListener(Object)},
92      * but that won't affect the sequence of listeners returned by the Iterator.
93      */

94     public synchronized Iterator JavaDoc getListeners()
95     {
96         _iteratorCount++;
97
98         return new ListenerIterator();
99     }
100
101     /**
102      * Adds a new listener to the list of listeners. The same instance
103      * will may be added multiple times.
104      */

105     public synchronized void addListener(Object JavaDoc listener)
106     {
107         copyOnWrite(_count + 1);
108
109         _listeners[_count] = listener;
110
111         _count++;
112     }
113
114     /**
115      * Removes a listener from the list. Does nothing if the listener
116      * is not already in the list. Comparison is based on identity, not equality.
117      * If the listener is in the list multiple times, only a single
118      * instance is removed.
119      */

120     public synchronized void removeListener(Object JavaDoc listener)
121     {
122         for (int i = 0; i < _count; i++)
123         {
124             if (_listeners[i] == listener)
125             {
126                 removeListener(i);
127                 return;
128             }
129         }
130     }
131
132     private void removeListener(int index)
133     {
134         copyOnWrite(_count);
135
136         // Move the last listener in the list into the index to be removed.
137

138         _listeners[index] = _listeners[_count - 1];
139
140         // Null out the old position.
141

142         _listeners[_count - 1] = null;
143
144         _count--;
145     }
146
147     /**
148      * Copies the array before an update operation if necessary (because there
149      * is a known iterator for the current array, or because the
150      * array is not large enough).
151      */

152     private void copyOnWrite(int requiredSize)
153     {
154         int size = _listeners == null ? 0 : _listeners.length;
155
156         if (_iteratorCount > 0 || size < requiredSize)
157         {
158             int nominalSize = (size == 0) ? START_SIZE : 2 * size;
159
160             // Don't grow the array if we don't need to...
161
if (size >= requiredSize)
162             {
163                 nominalSize = size;
164             }
165
166             int newSize = Math.max(requiredSize, nominalSize);
167
168             Object JavaDoc[] newListeners = new Object JavaDoc[newSize];
169
170             if (_count > 0)
171                 System.arraycopy(_listeners, 0, newListeners, 0, _count);
172
173             _listeners = newListeners;
174
175             // No iterators on the *new* array
176
_iteratorCount = 0;
177             _uid++;
178         }
179     }
180
181     private synchronized void adjustIteratorCount(int iteratorUid)
182     {
183         if (_uid == iteratorUid)
184             _iteratorCount--;
185     }
186 }
187
Popular Tags