All Downloads are FREE. Search and download functionalities are using the official Maven repository.

rinde.sim.event.EventDispatcher Maven / Gradle / Ivy

There is a newer version: 4.4.6
Show newest version
/**
 * 
 */
package rinde.sim.event;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Sets.newHashSet;
import static java.util.Arrays.asList;

import java.util.HashSet;
import java.util.Set;

import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;

/**
 * Basic event dispatcher for easily dispatching {@link Event}s to
 * {@link Listener}s. It provides methods for dispatching events and removing
 * and adding of listeners.
 * @author Rinde van Lon 
 */
public class EventDispatcher implements EventAPI {

    /**
     * A map of event types to registered {@link Listener}s.
     */
    protected final Multimap, Listener> listeners;

    /**
     * The set of event types that this event dispatcher supports.
     */
    protected final Set> supportedTypes;

    /**
     * The 'public' api of this dispatcher. Public in this context means API
     * that is intended for users of the dispatcher, that is, classes
     * that want to be notified of events.
     */
    protected final PublicEventAPI publicAPI;

    /**
     * Creates a new {@link EventDispatcher} instance which is capable of
     * dispatching any {@link Event} with a type attribute that is
     * one of eventTypes.
     * @param supportedEventTypes The types of events this EventDispatcher
     *            supports.
     */
    public EventDispatcher(Set> supportedEventTypes) {
        checkArgument(supportedEventTypes != null, "event types can not be null");
        listeners = LinkedHashMultimap.create();
        supportedTypes = newHashSet(supportedEventTypes);
        publicAPI = new PublicEventAPI(this);
    }

    /**
     * Creates a new {@link EventDispatcher} instance which is capable of
     * dispatching any {@link Event} with a type attribute that is
     * one of eventTypes.
     * @param supportedEventTypes The types of events this EventDispatcher
     *            supports.
     */
    public EventDispatcher(Enum... supportedEventTypes) {
        this(new HashSet>(asList(supportedEventTypes)));
    }

    /**
     * Dispatch an event. Notifies all listeners that are listening for this
     * type of event.
     * @param e The event to be dispatched, only events with a supported type
     *            can be dispatched.
     */
    public void dispatchEvent(Event e) {
        if (e == null) {
            throw new IllegalArgumentException("event can not be null");
        }
        checkArgument(supportedTypes.contains(e.getEventType()), "Cannot dispatch an event of type %s since it was not registered at this dispatcher.", e
                .getEventType());
        for (final Listener l : listeners.get(e.getEventType())) {
            l.handleEvent(e);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void addListener(Listener listener, Enum... eventTypes) {
        checkArgument(eventTypes != null, "event types can not be null");
        addListener(listener, newHashSet(eventTypes), eventTypes.length == 0);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void addListener(Listener listener, Set> eventTypes) {
        addListener(listener, eventTypes, false);
    }

    /**
     * Adds the specified listener. From now on, the specified listener will be
     * notified of events with one of the eventTypes. If
     * eventTypes is empty, the listener will be notified of no
     * events. If all is true the value for
     * eventTypes is ignored and the listener is registered for
     * all events. Otherwise, if all is false
     * the listener is only registered for the event types in
     * eventTypes.
     * @param listener The listener to register.
     * @param eventTypes The event types to listen to.
     * @param all Indicates whether eventTypes is used or if the
     *            listener is registered to all event types.
     */
    protected void addListener(Listener listener, Set> eventTypes,
            boolean all) {
        checkArgument(listener != null, "listener can not be null");
        if (eventTypes == null) {
            throw new IllegalArgumentException("event types can not be null");
        }
        final Set> theTypes = all ? supportedTypes : eventTypes;
        for (final Enum eventType : theTypes) {
            checkArgument(eventType != null, "event type can not be null");
            checkArgument(supportedTypes.contains(eventType), "A listener for type %s is not allowed.", eventType);
            listeners.put(eventType, listener);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void removeListener(Listener listener, Enum... eventTypes) {
        removeListener(listener, newHashSet(eventTypes));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void removeListener(Listener listener, Set> eventTypes) {
        checkArgument(listener != null, "listener can not be null");
        if (eventTypes == null) {
            throw new IllegalArgumentException("event types can not be null");
        }

        if (eventTypes.isEmpty()) {
            // remove all
            // store keys in intermediate set to avoid concurrent modifications
            final Set> keys = new HashSet>(listeners.keySet());
            for (final Enum eventType : keys) {
                if (listeners.containsEntry(eventType, listener)) {
                    removeListener(listener, eventType);
                }
            }
        } else {
            for (final Enum eventType : eventTypes) {
                checkArgument(eventType != null, "event type can not be null");
                checkArgument(containsListener(listener, eventType), "The listener %s for the type %s cannot be removed because it does not exist.", listener, eventType);
                listeners.remove(eventType, listener);
            }
        }

    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean containsListener(Listener listener, Enum eventType) {
        return listeners.containsEntry(eventType, listener);
    }

    /**
     * This method returns the public {@link EventAPI} instance associated to
     * this {@link EventDispatcher}. This instance can be made publicly
     * available to classes outside the scope of the events. Through this
     * instance listeners can be added and removed to this
     * {@link EventDispatcher}.
     * @return A wrapper for {@link EventDispatcher}, only shows the methods
     *         which should be allowed to be called outside of the dispatcher's
     *         parent.
     */
    public EventAPI getPublicEventAPI() {
        return publicAPI;
    }

    class PublicEventAPI implements EventAPI {

        private final EventDispatcher ref;

        public PublicEventAPI(EventDispatcher ed) {
            ref = ed;
        }

        @Override
        public void addListener(Listener l, Enum... eventTypes) {
            ref.addListener(l, eventTypes);
        }

        @Override
        public void addListener(Listener listener, Set> eventTypes) {
            ref.addListener(listener, eventTypes);
        }

        @Override
        public void removeListener(Listener l, Enum... eventTypes) {
            ref.removeListener(l, eventTypes);
        }

        @Override
        public void removeListener(Listener listener, Set> eventTypes) {
            ref.removeListener(listener, eventTypes);
        }

        @Override
        public boolean containsListener(Listener l, Enum eventType) {
            return ref.containsListener(l, eventType);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy