2009/04/15 - Apache HiveMind has been retired.

For more information, please explore the Attic.

Clover coverage report - Code Coverage for hivemind release 1.2.1
Coverage timestamp: Fri Feb 10 2006 16:33:43 PST
file stats: LOC: 186   Methods: 10
NCLOC: 97   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
EventListenerList.java 100% 100% 100% 100%
coverage
 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;
 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[] _listeners;
 34    private int _count;
 35    private int _iteratorCount;
 36    private int _uid;
 37   
 38    private class ListenerIterator implements Iterator
 39    {
 40    private Object[] _localListeners;
 41    private int _localCount;
 42    private int _localUid;
 43    private int _pos;
 44   
 45  12156 private ListenerIterator()
 46    {
 47  12156 _localListeners = _listeners;
 48  12156 _localCount = _count;
 49  12156 _localUid = _uid;
 50    }
 51   
 52  30542 public boolean hasNext()
 53    {
 54  30542 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  12055 adjustIteratorCount(_localUid);
 60   
 61  12055 _localListeners = null;
 62  12055 _localCount = 0;
 63  12055 _localUid = -1;
 64  12055 _pos = 0;
 65   
 66  12055 return false;
 67    }
 68   
 69  18487 return true;
 70    }
 71   
 72  18502 public Object next()
 73    {
 74  18502 return _localListeners[_pos++];
 75    }
 76   
 77  1 public void remove()
 78    {
 79  1 throw new UnsupportedOperationException();
 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  12156 public synchronized Iterator getListeners()
 95    {
 96  12156 _iteratorCount++;
 97   
 98  12156 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  19921 public synchronized void addListener(Object listener)
 106    {
 107  19931 copyOnWrite(_count + 1);
 108   
 109  19886 _listeners[_count] = listener;
 110   
 111  19904 _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  103 public synchronized void removeListener(Object listener)
 121    {
 122  103 for (int i = 0; i < _count; i++)
 123    {
 124  137 if (_listeners[i] == listener)
 125    {
 126  102 removeListener(i);
 127  102 return;
 128    }
 129    }
 130    }
 131   
 132  102 private void removeListener(int index)
 133    {
 134  102 copyOnWrite(_count);
 135   
 136    // Move the last listener in the list into the index to be removed.
 137   
 138  102 _listeners[index] = _listeners[_count - 1];
 139   
 140    // Null out the old position.
 141   
 142  102 _listeners[_count - 1] = null;
 143   
 144  102 _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  20030 private void copyOnWrite(int requiredSize)
 153    {
 154  20024 int size = _listeners == null ? 0 : _listeners.length;
 155   
 156  20027 if (_iteratorCount > 0 || size < requiredSize)
 157    {
 158  12533 int nominalSize = (size == 0) ? START_SIZE : 2 * size;
 159   
 160    // Don't grow the array if we don't need to...
 161  12533 if (size >= requiredSize)
 162    {
 163  101 nominalSize = size;
 164    }
 165   
 166  12533 int newSize = Math.max(requiredSize, nominalSize);
 167   
 168  12533 Object[] newListeners = new Object[newSize];
 169   
 170  12534 if (_count > 0)
 171  357 System.arraycopy(_listeners, 0, newListeners, 0, _count);
 172   
 173  12518 _listeners = newListeners;
 174   
 175    // No iterators on the *new* array
 176  12535 _iteratorCount = 0;
 177  12535 _uid++;
 178    }
 179    }
 180   
 181  12055 private synchronized void adjustIteratorCount(int iteratorUid)
 182    {
 183  12055 if (_uid == iteratorUid)
 184  12053 _iteratorCount--;
 185    }
 186    }