Clover coverage report - Code Coverage for hivemind release 1.1-beta-2
Coverage timestamp: Tue Jun 28 2005 10:28:23 EDT
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  959 private ListenerIterator()
 46    {
 47  959 _localListeners = _listeners;
 48  959 _localCount = _count;
 49  959 _localUid = _uid;
 50    }
 51   
 52  2551 public boolean hasNext()
 53    {
 54  2551 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  858 adjustIteratorCount(_localUid);
 60   
 61  858 _localListeners = null;
 62  858 _localCount = 0;
 63  858 _localUid = -1;
 64  858 _pos = 0;
 65   
 66  858 return false;
 67    }
 68   
 69  1693 return true;
 70    }
 71   
 72  1708 public Object next()
 73    {
 74  1708 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  959 public synchronized Iterator getListeners()
 95    {
 96  959 _iteratorCount++;
 97   
 98  959 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  2409 public synchronized void addListener(Object listener)
 106    {
 107  2409 copyOnWrite(_count + 1);
 108   
 109  2409 _listeners[_count] = listener;
 110   
 111  2409 _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  509 public synchronized void removeListener(Object listener)
 121    {
 122  509 for (int i = 0; i < _count; i++)
 123    {
 124  904 if (_listeners[i] == listener)
 125    {
 126  508 removeListener(i);
 127  508 return;
 128    }
 129    }
 130    }
 131   
 132  508 private void removeListener(int index)
 133    {
 134  508 copyOnWrite(_count);
 135   
 136    // Move the last listener in the list into the index to be removed.
 137   
 138  508 _listeners[index] = _listeners[_count - 1];
 139   
 140    // Null out the old position.
 141   
 142  508 _listeners[_count - 1] = null;
 143   
 144  508 _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  2917 private void copyOnWrite(int requiredSize)
 153    {
 154  2917 int size = _listeners == null ? 0 : _listeners.length;
 155   
 156  2917 if (_iteratorCount > 0 || size < requiredSize)
 157    {
 158  1016 int nominalSize = (size == 0) ? START_SIZE : 2 * size;
 159   
 160    // Don't grow the array if we don't need to...
 161  1016 if (size >= requiredSize)
 162    {
 163  507 nominalSize = size;
 164    }
 165   
 166  1016 int newSize = Math.max(requiredSize, nominalSize);
 167   
 168  1016 Object[] newListeners = new Object[newSize];
 169   
 170  1016 if (_count > 0)
 171  761 System.arraycopy(_listeners, 0, newListeners, 0, _count);
 172   
 173  1016 _listeners = newListeners;
 174   
 175    // No iterators on the *new* array
 176  1016 _iteratorCount = 0;
 177  1016 _uid++;
 178    }
 179    }
 180   
 181  858 private synchronized void adjustIteratorCount(int iteratorUid)
 182    {
 183  858 if (_uid == iteratorUid)
 184  450 _iteratorCount--;
 185    }
 186    }