com.day.util.ListenerList Maven / Gradle / Ivy
/*
* $Id: ListenerList.java 12397 2004-08-30 06:35:44Z fmeschbe $
*
* Copyright (c) 1997-2003 Day Management AG
* Barfuesserplatz 6, 4001 Basel, Switzerland
* All Rights Reserved.
*
* This software is the confidential and proprietary information of
* Day Management AG, ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Day.
*/
package com.day.util;
import java.util.List;
import java.util.ArrayList;
import java.lang.reflect.Array;
/**
* The ListenerList
class provides a utility to maintain lists of
* registered listeners. It is fairly lightweight and should not impose to
* much memory overhead.
*
* Use the {@link #getListeners()} method when notifying listeners. Note that
* no garbage is created if no listeners are registered. The recommended code
* sequence for notifying all registered listeners of say,
* FooListener.eventHappened
, is:
*
* Object[] listeners = myListenerList.getListeners();
* for (int i = 0; i < listeners.length; ++i) {
* ((FooListener) listeners[i]).eventHappened(event);
* }
*
*
* @author fmeschbe
* @version $Revision: 1.3 $, $Date: 2004-08-30 08:35:44 +0200 (Mon, 30 Aug 2004) $
* @audience wad
* @since iguana
*/
public class ListenerList {
/** The list of listeners registered with this listener list. */
private List listenerList = new ArrayList(0);
/**
* The listener list as an object array. This array provides a static view
* of the listener list. This array is created on demand by the
* {@link #getListeners()} method and removed by the
* {@link #addListener(Object)} and {@link #removeListener(Object)} methods
* to force recreation on the next access.
*/
private Object[] listeners;
/**
* Creates an instance of this listener list class.
*/
public ListenerList() {}
/**
* Adds a listener to the list of listeners if it is not yet registered in
* the list.
*
* @param listener The listener to add to the list. If null
* nothing is done.
*
* @return true
if the listener has been added to the list
*/
public boolean addListener(Object listener) {
// ignore if null
if (listener != null) {
synchronized(listenerList) {
if (!listenerList.contains(listener)) {
listenerList.add(listener);
listeners = null;
return true;
}
}
}
// fall back
return false;
}
/**
* Removes a listener from the list of listeners if it is contained.
*
* @param listener The listener to remove from the list. If
* null
nothing is done.
*
* @return true
if the listener has been added to the list
*/
public boolean removeListener(Object listener) {
// ignore if null
if (listener != null) {
synchronized(listenerList) {
int index = listenerList.indexOf(listener);
if (index >= 0) {
listenerList.remove(index);
listeners = null;
return true;
}
}
}
// fallback
return false;
}
/**
* Clears the list of registered listeners.
*/
public void clear() {
synchronized(listenerList) {
listeners = null;
listenerList.clear();
}
}
/**
* Returns the number of currently registered listeners.
*/
public int size() {
return listenerList.size();
}
/**
* Returns the list of registered listeners. Note that this method returns
* the same array for two subsequent calls if no listeners have been added
* or removed in the mean time. This also means, that callers of this method
* MUST NOT modify the array returned.
*/
public Object[] getListeners() {
/**
* This construct might theoretically assign the listeners list multiple
* times in a multi-threading environment. This should not be too much
* of a problem as this only imposes some performance penalty but no
* functionality issues.
*/
if (listeners == null) {
synchronized(listenerList) {
listeners = listenerList.toArray();
}
}
return listeners;
}
/**
* Returns the list of registered listeners in an array of the reqeusted
* runtime type. Note that this method returns the same array for two
* subsequent calls if no listeners have been added or removed in the mean
* time and if the element type of is assignment compatible. This also
* means, that callers of this method MUST NOT modify the array returned.
*
* @param requestedType The runtime type of the components of the array to
* return.
*
* @throws ArrayStoreException if the runtime type is not a supertype of
* the runtime type of every element in this list.
*/
public Object[] getListeners(Class requestedType) {
synchronized (listenerList) {
// if the list is already defined, check component runtime type
if (listeners != null) {
Class currentType = listeners.getClass().getComponentType();
if (requestedType.isAssignableFrom(currentType)) {
return listeners;
}
}
// if here, the array is undefined or of the wrong type
Object[] dest = (Object[]) Array.newInstance(requestedType, size());
listeners = listenerList.toArray(dest);
return listeners;
}
}
}