package com.github.nkzawa.emitter; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentMap; /** * The event emitter which is ported from the JavaScript module. This class is thread-safe. * * @see https://github.com/component/emitter */ public class Emitter { private ConcurrentMap> callbacks = new ConcurrentHashMap>(); private ConcurrentMap onceCallbacks = new ConcurrentHashMap(); /** * Listens on the event. * @param event event name. * @param fn * @return a reference to to this object. */ public Emitter on(String event, Listener fn) { ConcurrentLinkedQueue callbacks = this.callbacks.get(event); if (callbacks == null) { callbacks = new ConcurrentLinkedQueue (); ConcurrentLinkedQueue _callbacks = this.callbacks.putIfAbsent(event, callbacks); if (_callbacks != null) { callbacks = _callbacks; } } callbacks.add(fn); return this; } /** * Adds a one time listener for the event. * * @param event * @param fn * @return a reference to to this object. */ public Emitter once(final String event, final Listener fn) { Listener on = new Listener() { @Override public void call(Object... args) { Emitter.this.off(event, this); fn.call(args); } }; this.onceCallbacks.put(fn, on); this.on(event, on); return this; } /** * Removes all registered listeners. * * @return a reference to to this object. */ public Emitter off() { this.callbacks.clear(); this.onceCallbacks.clear(); return this; } /** * Removes all listeners of the specified event. * * @param event * @return a reference to to this object. */ public Emitter off(String event) { ConcurrentLinkedQueue callbacks = this.callbacks.remove(event); if (callbacks != null) { for (Listener fn : callbacks) { this.onceCallbacks.remove(fn); } } return this; } /** * Removes the listener. * * @param event * @param fn * @return a reference to to this object. */ public Emitter off(String event, Listener fn) { ConcurrentLinkedQueue callbacks = this.callbacks.get(event); if (callbacks != null) { Listener off = this.onceCallbacks.remove(fn); callbacks.remove(off != null ? off : fn); } return this; } /** * Executes each of listeners with the given args. * * @param event * @param args * @return a reference to to this object. */ public Emitter emit(String event, Object... args) { ConcurrentLinkedQueue callbacks = this.callbacks.get(event); if (callbacks != null) { callbacks = new ConcurrentLinkedQueue(callbacks); for (Listener fn : callbacks) { fn.call(args); } } return this; } /** * Returns a list of listeners for the specified event. * * @param event * @return a reference to to this object. */ public List listeners(String event) { ConcurrentLinkedQueue callbacks = this.callbacks.get(event); return callbacks != null ? new ArrayList(callbacks) : new ArrayList(); } /** * Check if this emitter has listeners for the specified event. * * @param event * @return a reference to to this object. */ public boolean hasListeners(String event) { return !this.listeners(event).isEmpty(); } public static interface Listener { public void call(Object... args); } }