/* * $Id$ * * Copyright (c) 2010 by Joel Uckelman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License (LGPL) as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, copies are available * at http://www.opensource.org. */ package VASSAL.tools.concurrent.listener; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; /** * A class to provide support for {@link EventListener}s. * * @author Joel Uckelman * @since 3.2.0 */ public class DefaultMultiEventListenerSupport implements MultiEventListenerSupport { protected final ConcurrentMap<Class<?>,List<EventListener<?>>> listeners = new ConcurrentHashMap<Class<?>,List<EventListener<?>>>(); protected final Object src; /** * Creates a <code>DefaultMultiEventListenerSupport</code>. * * @param src the source of events */ public DefaultMultiEventListenerSupport(Object src) { this.src = src; } /** {@inheritDoc} */ public <T> void addEventListener(Class<T> c, EventListener<? super T> l) { // ensure that a listener list exists for class c listeners.putIfAbsent(c, new CopyOnWriteArrayList<EventListener<?>>()); // add the listener to the list for every supertype of c for (Map.Entry<Class<?>,List<EventListener<?>>> e : listeners.entrySet()) { final Class<?> other = e.getKey(); if (c.isAssignableFrom(other)) { e.getValue().add(l); } } } /** {@inheritDoc} */ public <T> void removeEventListener(Class<T> c, EventListener<? super T> l) { // add the listener to the list for every supertype of c for (Map.Entry<Class<?>,List<EventListener<?>>> e : listeners.entrySet()) { final Class<?> other = e.getKey(); if (c.isAssignableFrom(other)) { e.getValue().remove(l); } } } /** {@inheritDoc} */ public boolean hasEventListeners(Class<?> c) { // check for listeners for every supertype of c for (Map.Entry<Class<?>,List<EventListener<?>>> e : listeners.entrySet()) { final Class<?> other = e.getKey(); if (other.isAssignableFrom(c)) { if (!e.getValue().isEmpty()) { return true; } } } return false; } /** {@inheritDoc} */ @SuppressWarnings("unchecked") public <T> List<EventListener<? super T>> getEventListeners(Class<T> c) { final List<EventListener<? super T>> list = new ArrayList<EventListener<? super T>>(); // make a list of all listeners for every supertype of c for (Map.Entry<Class<?>,List<EventListener<?>>> e : listeners.entrySet()) { final Class<?> other = e.getKey(); if (other.isAssignableFrom(c)) { list.addAll((List) e.getValue()); } } return list; } /** {@inheritDoc} */ @SuppressWarnings("unchecked") public void notify(Object event) { final Class<?> c = event.getClass(); List<EventListener<?>> list = listeners.get(c); if (list == null) list = registerType(c); for (EventListener l : list) { l.receive(src, c.cast(event)); } } protected List<EventListener<?>> registerType(Class<?> c) { // ensure that a listener list exists for class c listeners.putIfAbsent(c, new CopyOnWriteArrayList<EventListener<?>>()); final Set<EventListener<?>> lset = new HashSet<EventListener<?>>(); // make a set of all listeners for every supertype of c for (Map.Entry<Class<?>,List<EventListener<?>>> e : listeners.entrySet()) { final Class<?> other = e.getKey(); if (other.isAssignableFrom(c)) { lset.addAll(e.getValue()); } } final List<EventListener<?>> list = listeners.get(c); list.addAll(lset); return list; } }