org.exolab.castor.util.EventListenerList Maven / Gradle / Ivy
Show all versions of castor-xml Show documentation
/**
* Redistribution and use of this software and associated documentation ("Software"), with or
* without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright statements and notices. Redistributions
* must also contain a copy of this document.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided with
* the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
* without prior written permission of Intalio, Inc. For written permission, please contact
* [email protected].
*
* 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
* their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
* Intalio, Inc.
*
* 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Contribution(s):
*
* - Jeff Norris, [email protected] - Original Author
*
* $Id$
*/
package org.exolab.castor.util;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.EventListener;
/**
*
* This class is an efficient repository for EventListeners based on javax.swing.EventListenerList.
*
*
*
* This modification of javax.swing.EventListenerList retains the core functionality of that class
* but changes the basic API and adds a few more features, as summarized below:
*
*
*
* - javax.swing.EventListenerList requires all listeners to be added in conjunction with a class
* object that identified the type of the listener. This implementation's add methods simply take
* the listener object.
*
*
- The listener list returned from javax.swing.EventListenerList had to be iterated over in a
* cumbersome manner because the listeners were stored along with their Class objects in the array.
* Since listener classes are not stored in this listener list, the returned listener array can be
* iterated over normally (1 element at a time).
*
*
- The remove method in javax.swing.EventListenerList had return type "void". This
* implementation's remove method returns true if the specified listener was found in the listener
* array and false otherwise.
*
*
- This implementation adds {@link #add(EventListener, int)}, which allows the addition of a
* listener at a specific position in the array.
*
*
- The add and remove methods in this implementation throw IllegalArgumentExceptions when their
* arguments are null.
*
*
*
* As is the case with javax.swing.EventListenerList, this class provides multi-threaded safety
* through a copy-on-modify strategy. It is optimized to provide high performance when events are
* being fired, with slightly slower performance than the Collection API when listeners are being
* added and removed. Like its predecessor, this class will never return a null array from
* getListenerList.
*
*
*
* The most important thing to keep in mind when using this class is that the array returned by
* getListenerList is the actual internal array of this class and MUST NOT BE MODIFIED UNDER ANY
* CIRCUMSTANCES. Below is an example of how to use this class, borrowed (and slightly modified)
* from the javax.swing.EventListenerList documentation:
*
*
*
* Usage example: Say one is defining a class that sends out FooEvents, and one wants to allow users
* of the class to register FooListeners and receive notification when FooEvents occur. The
* following should be added to the class definition:
*
*
*
* EventListenerList listenerList = new EventListenerList();
* FooEvent fooEvent = null;
*
* public void addFooListener(FooListener l) {
* listenerList.add(l);
* }
*
* public void removeFooListener(FooListener l) {
* listenerList.remove(l);
* }
*
* // Notify all listeners that have registered interest for
* // notification on this event type. The event instance
* // is lazily created using the parameters passed into
* // the fire method.
*
* protected void fireFooXXX() {
* // Guaranteed to return a non-null array
* EventListener[] listeners = listenerList.getListenerList();
* // Process the listeners last to first, notifying
* // those that are interested in this event
* for (int i = 0; i < listeners.length; i++) {
* // Lazily create the event:
* if (fooEvent == null)
* fooEvent = new FooEvent(this);
* ((FooListener) listeners[i]).fooXXX(fooEvent);
* }
* }
*
*
*
* foo should be changed to the appropriate name, and fireFooXxx to the appropriate method name. One
* fire method should exist for each notification method in the FooListener interface.
*
*
*
* The authors of javax.swing.EventListenerList are Georges Saab, Hans Muller, and James Gosling.
*
*
* @author Jeff Norris
* @version $Revision$ $Date: 2005-12-13 14:58:48 -0700 (Tue, 13 Dec 2005) $
*/
public class EventListenerList implements Serializable {
/** SerialVersionUID */
private static final long serialVersionUID = 4472874989562384564L;
/**
* A null array to be shared by all empty listener lists
*/
private final static EventListener[] NULL_ARRAY = new EventListener[0];
/**
* The internal list of listeners that is returned from getListenerList
*/
protected transient EventListener[] listenerList = NULL_ARRAY;
/**
*
* Passes back the event listener list as an array of EventListeners.
*
*
*
* Note that for performance reasons, this implementation passes back the actual data structure in
* which the listener data is stored internally! This method is guaranteed to pass back a non-null
* array, so that no null-checking is required in fire methods. A zero-length array of Object will
* be returned if there are currently no listeners.
*
*
* WARNING!!! Absolutely NO modification of the data contained in this array should be made -- if
* any such manipulation is necessary, it should be done on a copy of the array returned rather
* than the array itself.
*/
public EventListener[] getListenerList() {
return listenerList;
}
/**
*
* Returns the total number of listeners in this listener list.
*
*
*/
public int getListenerCount() {
return listenerList.length;
}
/**
*
* Adds the listener to the end of the listener list.
*
*
* @param newListener the listener to be added
* @exception IllegalArgumentException if the specified newListener is null
*/
public synchronized void add(EventListener newListener) {
if (newListener == null)
throw new IllegalArgumentException("Listener to add must not be null.");
if (listenerList == NULL_ARRAY) {
// if this is the first listener added,
// initialize the lists
listenerList = new EventListener[] {newListener};
} else {
// Otherwise copy the array and add the new listener
int oldLength = listenerList.length;
EventListener[] tmp = new EventListener[oldLength + 1];
System.arraycopy(listenerList, 0, tmp, 0, oldLength);
tmp[oldLength] = newListener;
listenerList = tmp;
}
}
/**
*
* Adds the listener at the specified index in the listener list.
*
*
* @param newListener the listener to be added
* @exception IllegalArgumentException if the specified newListener is null, or the specified
* index is less than zero or greater than the length of the listener list array.
*/
public synchronized void add(EventListener newListener, int index) {
if (newListener == null)
throw new IllegalArgumentException("Listener to add must not be null.");
if ((index < 0) || (index > listenerList.length))
throw new IllegalArgumentException("Index to add listener (" + index
+ ") is out of bounds. List length is " + listenerList.length);
if (listenerList == NULL_ARRAY) {
// if this is the first listener added, initialize the lists
listenerList = new EventListener[] {newListener};
} else {
// Otherwise copy the array and add the new listener
int oldLength = listenerList.length;
EventListener[] tmp = new EventListener[oldLength + 1];
// Copy up to the index where the new listener should go
System.arraycopy(listenerList, 0, tmp, 0, index);
// Skip a cell and copy the rest of the list
System.arraycopy(listenerList, index, tmp, index + 1, oldLength - index);
// Insert the new listener
tmp[index] = newListener;
listenerList = tmp;
}
}
/**
* Removes the listener as a listener of the specified type.
*
* @param listenerToRemove the listener to be removed
* @exception IllegalArgumentException if the specified listener is null
*/
public synchronized boolean remove(EventListener listenerToRemove) {
if (listenerToRemove == null)
throw new IllegalArgumentException("Listener to remove must " + "not be null.");
// Is listenerToRemove on the list?
int index = -1;
for (int i = listenerList.length - 1; i >= 0; i--) {
if (listenerList[i].equals(listenerToRemove) == true) {
index = i;
break;
}
}
// If so, remove it
if (index != -1) {
EventListener[] tmp = new EventListener[listenerList.length - 1];
// Copy the list up to index
System.arraycopy(listenerList, 0, tmp, 0, index);
// Copy from one past the index, up to the end of tmp (which is
// one element shorter than the old list)
if (index < tmp.length)
System.arraycopy(listenerList, index + 1, tmp, index, tmp.length - index);
// set the listener array to the new array or null
listenerList = (tmp.length == 0) ? NULL_ARRAY : tmp;
return true;
}
return false;
}
// Serialization support.
private void writeObject(ObjectOutputStream s) throws IOException {
Object[] lList = listenerList;
s.defaultWriteObject();
// Save the non-null event listeners:
for (int i = 0; i < lList.length; i += 1) {
EventListener l = (EventListener) lList[i];
if ((l != null) && (l instanceof Serializable)) {
s.writeObject(l);
}
}
s.writeObject(null);
}
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
listenerList = NULL_ARRAY;
s.defaultReadObject();
EventListener listenerOrNull;
while (null != (listenerOrNull = (EventListener) s.readObject())) {
add(listenerOrNull);
}
}
/**
* Returns a string representation of the EventListenerList.
*/
public String toString() {
Object[] lList = listenerList;
String s = "EventListenerList: ";
s += lList.length + " listeners: ";
for (int i = 0; i < lList.length; i++) {
s += " listener " + lList[i + 1];
}
return s;
}
} // -- class: EventListenerList