/*******************************************************************************
* Copyright (c) 2004, 2008 John Krasnay and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* John Krasnay - initial API and implementation
*******************************************************************************/
package net.sf.vex.core;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EventObject;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* A collection of listener objects. The main point of this class is the
* fireEvent method, which takes care of the
* tedium of iterating over the collection and catching exceptions generated
* by listeners.
*/
public class ListenerList {
/**
* Class constructor.
* @param listenerClass Class of the listener interface.
* @param eventClass Class of the event objects passed to methods in the
* listener interface.
*/
public ListenerList(Class listenerClass, Class eventClass) {
this.listenerClass = listenerClass;
this.methodParams = new Class[] { eventClass };
}
/**
* Adds a listener to the list. Rejects listeners that are not subclasses
* of the listener class passed to the constructor.
* @param listener Listener to be added.
*/
public void add(Object listener) {
if (!listenerClass.isInstance(listener)) {
this.handleException(new IllegalArgumentException("" + listener + " is not an instance of " + listenerClass));
}
this.listeners.add(listener);
}
/**
* Calls the given method on each registered listener. Any exception
* thrown from one of the called methods is passed to handleException, as
* is any introspection error, e.g. if the given method doesn't exist.
*
* @param methodName Listener method to call.
* @param event Event to be passed to each call.
*/
public void fireEvent(String methodName, EventObject event) {
Method method = (Method) this.methods.get(methodName);
if (method == null) {
try {
method = listenerClass.getMethod(methodName, methodParams);
this.methods.put(methodName, method);
} catch (Exception e) {
this.handleException(e);
return;
}
}
Object[] args = new Object[] { event };
for (Iterator it = this.listeners.iterator(); it.hasNext();) {
Object listener = it.next();
try {
method.invoke(listener, args);
} catch (Exception ex) {
this.handleException(ex);
}
}
}
/**
* Called from fireEvent whenever a called listener method throws an
* exception, or if there is a problem looking up the listener method
* by reflection. By default, simply prints the stack trace to stdout.
* Clients may override this method to provide a more suitable
* implementation.
* @param ex Exception thrown by the listener method.
*/
public void handleException(Exception ex) {
ex.printStackTrace();
}
/**
* Removes a listener from the list.
* @param listener Listener to remove.
*/
public void remove(Object listener) {
this.listeners.remove(listener);
}
//====================================================== PRIVATE
private Class listenerClass;
private Class[] methodParams;
private Collection listeners = new ArrayList();
// map methodName => Method object
private Map methods = new HashMap();
}