KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > osgi > framework > eventmgr > EventListeners


1 /*******************************************************************************
2  * Copyright (c) 2003, 2005 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
12 package org.eclipse.osgi.framework.eventmgr;
13
14 /**
15  * This class manages a list of listeners.
16  * Listeners may be added or removed as necessary.
17  * @since 3.1
18  */

19 public class EventListeners {
20     /**
21      * The empty array singleton instance, returned by getListeners()
22      * when size == 0.
23      */

24     private static final ListElement[] emptyArray = new ListElement[0];
25
26     /**
27      * The initial capacity of the list. Always >= 1.
28      */

29     private final int initialCapacity;
30
31     /**
32      * The list of elements. Initially <code>null</code> but initialized
33      * to an array of size initialCapacity the first time an element is added.
34      * Maintains invariants:
35      * list != null IFF size != 0
36      * list[size] == null
37      * for all i < size: list[i] != null
38      * Access to this field must be protected by a synchronized region.
39      */

40     private ListElement[] list = null;
41
42     /**
43      * The current number of elements.
44      * Maintains invariant: 0 <= size <= list.length.
45      * Access to this field must be protected by a synchronized region.
46      */

47     private int size = 0;
48
49     /**
50      * If true and about to modify the list,
51      * then the list must be copied first.
52      * Access to this field must be protected by a synchronized region.
53      */

54     private boolean copyOnWrite = false;
55
56     /**
57      * Creates a listener list with an initial capacity of 10.
58      *
59      */

60     public EventListeners() {
61         this(10);
62     }
63
64     /**
65      * Creates a listener list with the given initial capacity.
66      *
67      * @param capacity The number of listeners which this list can initially
68      * accept without growing its internal representation; must be at
69      * least 1
70      * @throws IllegalArgumentException If capacity is less than 1.
71      */

72     public EventListeners(int capacity) {
73         if (capacity < 1)
74             throw new IllegalArgumentException JavaDoc();
75         this.initialCapacity = capacity;
76     }
77
78     /**
79      * Add a listener to the list.
80      * If a listener object is already in the list, then it is replaced.
81      *
82      * @param listener This is the listener object to be added to the list.
83      * @param listenerObject This is an optional listener-specific object.
84      * This object will be passed to the EventDispatcher along with the listener
85      * when the listener is to be called. This may be null
86      * @throws IllegalArgumentException If listener is null.
87      */

88     public synchronized void addListener(Object JavaDoc listener, Object JavaDoc listenerObject) {
89         if (listener == null) {
90             throw new IllegalArgumentException JavaDoc();
91         }
92
93         if (size == 0) {
94             list = new ListElement[initialCapacity];
95         }
96         else {
97             // copy array if necessary
98
if (copyOnWrite) {
99                 copyList(size);
100                 copyOnWrite = false;
101             }
102
103             // check for duplicates using identity
104
for (int i = 0; i < size; i++) {
105                 if (list[i].primary == listener) {
106                     list[i] = new ListElement(listener, listenerObject); /* use the most recent companion */
107                     return;
108                 }
109             }
110
111             // grow array if necessary
112
// This wont recopy list if copy on write occured above since that
113
// would have grown the list.
114
if (size == list.length) {
115                 copyList(size);
116             }
117         }
118
119         list[size] = new ListElement(listener, listenerObject);
120         size++;
121     }
122
123     /**
124      * Remove a listener from the list.
125      *
126      * @param listener This is the listener object to be removed from the list.
127      * @throws IllegalArgumentException If listener is null.
128      */

129     public synchronized void removeListener(Object JavaDoc listener) {
130         if (listener == null) {
131             throw new IllegalArgumentException JavaDoc();
132         }
133
134         for (int i = 0; i < size; i++) {
135             if (list[i].primary == listener) {
136                 size--;
137                 if (size == 0) {
138                     list = null; /* invariant: list must be null iff size is zero */
139                     return;
140                 }
141                 if (copyOnWrite) {
142                     copyList(i);
143                     copyOnWrite = false;
144                 }
145                 else {
146                     System.arraycopy(list, i + 1, list, i, size - i);
147                     list[size] = null; /* invariant: end of list must be null */
148                 }
149                 return;
150             }
151         }
152     }
153
154     /**
155      * Remove all listeners from the list.
156      */

157     public synchronized void removeAllListeners() {
158         /* invariant: list must be null iff size is zero */
159         list = null;
160         size = 0;
161     }
162
163     /**
164      * Return the list of (listener, listenerObject) pairs.
165      * Package private method.
166      * The array may be longer than the number of pairs in the array.
167      * The end of the pairs is signalled by a null element or
168      * end of array.
169      * This array must not be modified by anyone and should not be
170      * exposed outside of this package.
171      * To reduce memory allocations, the internal array is shared
172      * with the rest of this package. However an array returned by this method
173      * must not be modified in anyway.
174      *
175      * @return A shared array that must not be modified by anyone.
176      */

177     synchronized ListElement[] getListeners() {
178         if (size == 0) {
179             return emptyArray;
180         }
181         copyOnWrite = true;
182         return list;
183     }
184     
185     /**
186      * Copy the array.
187      * @param i Index of element to remove from array. Must be equal to size to
188      * copy entire array.
189      * @throws IndexOutOfBoundsException If i < 0 or i > size.
190      */

191     private void copyList(int i) {
192         if (i > size) {
193             throw new IndexOutOfBoundsException JavaDoc();
194         }
195         int capacity = (size * 3) / 2 + 1;
196         if (capacity < initialCapacity) {
197             capacity = initialCapacity;
198         }
199         ListElement[] newList = new ListElement[capacity];
200         System.arraycopy(list, 0, newList, 0, i);
201         if (i < size) {
202             System.arraycopy(list, i + 1, newList, i, size - i);
203         }
204         list = newList;
205     }
206
207     /**
208      * ListElement is a package private class. This class
209      * represents a primary object (e.g. listener) and its companion object.
210      * ListElements are stored in EventListeners.
211      * ListElements are immutable.
212      */

213     static class ListElement {
214         /**
215          * Primary object.
216          */

217         final Object JavaDoc primary;
218
219         /**
220          * Companion object.
221          */

222         final Object JavaDoc companion;
223
224         /**
225          * Constructor for ElementList element
226          * @param primary Primary object in element. Used for uniqueness.
227          * @param companion Companion object stored with primary object.
228          */

229         ListElement(final Object JavaDoc primary, final Object JavaDoc companion) {
230             this.primary = primary;
231             this.companion = companion;
232         }
233     }
234 }
235
Popular Tags