/* * $Id: ApplicationEventDispatcher.java,v 1.2 2010-11-29 15:42:24 illetsch Exp $ * © 3kraft GmbH & Co KG 2009 */ package com.dreikraft.events; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.SwingUtilities; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Dispatches events on the swing event queue. * * @author jan_solo * @author $Author: illetsch $ * @version $Revision: 1.2 $ */ public class ApplicationEventDispatcher { private static final Log log = LogFactory.getLog( ApplicationEventDispatcher.class); private static final String HANDLER_METHOD_PREFIX = "handle"; private static final ApplicationEventDispatcher dispatcher = new ApplicationEventDispatcher(); private Map<Class<? extends ApplicationEvent>, List<ApplicationEventEnabled>> eventTypeReceivers; // Private constructor prevents instantiation from other classes private ApplicationEventDispatcher() { eventTypeReceivers = Collections.synchronizedMap( new HashMap<Class<? extends ApplicationEvent>, List<ApplicationEventEnabled>>()); } /** * Returns a singleton instance. * * @return a singleton Dispatcher instance */ public static ApplicationEventDispatcher getInstance() { return dispatcher; } /** * Registers an ApplicationEvent with a handler. The handler must implement * the ApplicationEventEnabled interface. * * @param appEventType an application event type class * @param eventHandler the handler */ public void registerApplicationEventHandler( final Class<? extends ApplicationEvent> appEventType, final ApplicationEventEnabled eventHandler) { // lookup handlers for given event type List<ApplicationEventEnabled> handlers = eventTypeReceivers.get( appEventType); if (handlers == null) { handlers = Collections.synchronizedList( new ArrayList<ApplicationEventEnabled>()); eventTypeReceivers.put(appEventType, handlers); } // add handler, if not already added if (!handlers.contains(eventHandler)) { handlers.add(eventHandler); } } /** * Deregisters a handler for given event type. * * @param appEventType an application event type class * @param eventHandler the handler */ public void deregisterApplicationEventHandler( final Class<? extends ApplicationEvent> appEventType, final ApplicationEventEnabled eventHandler) { // lookup handlers for given event type List<ApplicationEventEnabled> handlers = eventTypeReceivers.get( appEventType); if (handlers == null) { handlers = Collections.synchronizedList( new ArrayList<ApplicationEventEnabled>()); eventTypeReceivers.put(appEventType, handlers); } if (handlers.contains(eventHandler)) { handlers.remove(eventHandler); } } /** * Dispatches events on all registered handlers.The handler method will be be * invoked with SwingUtilities.invokeLater(). This guarantees that view * updates will be processed correctly (eg. the progressbar). * * @param appEvent the application event to dispatch */ public void dispatchGUIEvent(final ApplicationEvent appEvent) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { dispatchEvent(appEvent); } }); } /** * The event will be dispatched directly from whatever thread you currently in. * Typically will be called from awt event thread to avoid synchronization * issues. * * Invoke this method if you need to recieve exceptions during processing of * the current event. * * @param appEvent the application event stopped */ public void dispatchEvent(final ApplicationEvent appEvent) { log.debug("dispatching event: " + appEvent); final List<? extends ApplicationEventEnabled> handlers = eventTypeReceivers. get(appEvent.getClass()); if (handlers != null) { synchronized (handlers) { for (final ApplicationEventEnabled handler : handlers) { try { final Method handlerMethod = handler.getClass().getMethod( HANDLER_METHOD_PREFIX, appEvent.getClass()); handlerMethod.invoke(handler, appEvent); } catch (InvocationTargetException ex) { final Throwable t = ex.getCause(); if (t instanceof CancelEventException) { log.info(appEvent + " cancelled"); throw (CancelEventException) t; } else { final String msg = new StringBuffer("failed to dispatch event " + appEvent + " to handler " + handler.getClass()).toString(); log.error(msg, ex); } } catch (IllegalAccessException ex) { final String msg = new StringBuffer("failed to dispatch event " + appEvent + " to handler " + handler.getClass()).toString(); log.error(msg, ex); } catch (IllegalArgumentException ex) { final String msg = new StringBuffer("failed to dispatch event " + appEvent + " to handler " + handler.getClass()).toString(); log.error(msg, ex); } catch (NoSuchMethodException ex) { final String msg = new StringBuffer("failed to dispatch event " + appEvent + " to handler " + handler.getClass()).toString(); log.error(msg, ex); } catch (SecurityException ex) { final String msg = new StringBuffer("failed to dispatch event " + appEvent + " to handler " + handler.getClass()).toString(); log.error(msg, ex); } } } } } /** * This is a singleton. * * @return * @throws CloneNotSupportedException */ @Override public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } }