package com.onaro.util; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.EventListener; import java.util.EventObject; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; /** * A utility handling distribution of events to the listeners. */ public class ListenerList { /** * Map of lists of listeners indexed by the listener type. */ private Map, List> listeners = new HashMap, List>(); /** * Map of FireEvent instances indexed by listener type. Shared * between all instance of the ListenerList. */ private final static Map,FireEvent> firers = new HashMap,FireEvent>(); /** * Adds a listener. * * @param listenerClass type of this listener is * @param listener the listener */ public void addListener(Class listenerClass, L listener) { @SuppressWarnings("unchecked") List listenerList = (List) listeners.get(listenerClass); if (listenerList == null) { listenerList = new LinkedList(); listeners.put(listenerClass, listenerList); } listenerList.add(listener); } /** * Removes a listener. * * @param listenerClass type of this listener * @param listener the listener */ public void removeListener(Class listenerClass, L listener) { @SuppressWarnings("unchecked") List listenerList = (List) listeners.get(listenerClass); if (listenerList != null) { listenerList.remove(listener); } } /** * Check if the listener list has any listeners registered for the given listener type * @param type of the listener class to check * @param listenerClass type of the listener class to check * @return true if there are any listeners registered with the type, false otherwise */ public boolean hasListeners(Class listenerClass) { @SuppressWarnings("unchecked") List listenerList = (List) listeners.get(listenerClass); return listenerList != null && !listenerList.isEmpty(); } /** * Fire an event. * * @param listenerClass type of listener's to fire the event to. * @param event the event */ public void fireEvent(Class listenerClass, E event) { BugWorkAround(listenerClass); if (listeners.size() == 0) return; assert EventListener.class.isAssignableFrom(listenerClass) : "Not an EventListener: " + listenerClass; //$NON-NLS-1$ @SuppressWarnings("unchecked") FireEvent firer = (FireEvent) firers.get(listenerClass); assert firer != null : "No firer is specified for " + listenerClass; //$NON-NLS-1$ @SuppressWarnings("unchecked") List listenerList = (List) listeners.get(listenerClass); if (listenerList != null) { for (L listener : listenerList) { firer.fire(listener, event); } } } // TODO: JDK 1.5 , loading of class doesn't initialize its static until first use // because of that the approach of creating a static variable in interface and expecting that by loading // it will initialize FAILED !!!, // the BugWorkAround method work around this problem by explicitly call the static variable and by that force // its initialization // we need to change the way this is works // OMRI private void BugWorkAround(Class listenerClass) { try { // since we are doing obfuscation we do not know the name of the field all we need it to find a field that is // static and access it. Field[] fields = listenerClass.getFields(); for (int i = 0; i < fields.length; i++) { Field field = fields[i]; boolean accessed = false; if (Modifier.isStatic(field.getModifiers()) && Modifier.isProtected(field.getModifiers()) == false && Modifier.isPrivate(field.getModifiers()) == false) { field.get(null); accessed = true; break; } assert accessed == false: "couldn't find modifier that is static and accessible"; //$NON-NLS-1$ } // Field f=listenerClass.getField("firer"); // Object o=f.get(null); } catch (IllegalAccessException e) { assert false: "IllegalAccessException" + e.getMessage(); //$NON-NLS-1$ } } /** * Adds a FireEvent firing an event for the specified listener. * * @param listenerClass the type of the listener * @param firer the FireEvent instance */ public static void addFireEvent(Class listenerClass, FireEvent firer) { synchronized (firers) { firers.put(listenerClass, firer); } } /** * Removes a FireEvent. * * @param listenerClass the type of the listener */ public static void removeFireEvent(Class listenerClass) { synchronized (firers) { firers.remove(listenerClass); } } /** * Define the interface needed to implemented by event firers which fire * specific events to specific listeners. */ public interface FireEvent { public void fire(L listener, E event); } }