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.ImmutableSet;
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 ImmutableSet> 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) {
    listeners = LinkedHashMultimap.create();
    supportedTypes = ImmutableSet.copyOf(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) {
    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) {
    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) {
    final Set> theTypes = all ? supportedTypes : eventTypes;
    for (final Enum eventType : theTypes) {
      checkArgument(eventType != null, "event type to add 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) {
    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 to remove 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;
  }

  static class PublicEventAPI implements EventAPI {
    private final EventDispatcher ref;

    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