/*
The MIT License (MIT)
Copyright (c) 2013 Naoyuki Kanezawa
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and as
sociated documentation files (the "Software"), to deal in the Software without restriction, includin
g without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subj
ect to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NO
T LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABI
LITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WIT
H THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(The MIT License)
Copyright (c) 2011 Guillermo Rauch <guillermo@learnboost.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and as
sociated documentation files (the 'Software'), to deal in the Software without restriction, includin
g without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subj
ect to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NO
T LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABI
LITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WIT
H THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* This is a modified version of the EventEmitter found as part of nkzawa's engine.io-client library
* https://github.com/nkzawa/engine.io-client.java
*
* The only difference is that it uses generics (T... args) rather than (Object... args)
*/
package com.rackspacecloud.blueflood.eventemitter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Future;
/**
* The event emitter which is ported from the JavaScript module. This class is thread-safe.
*
* @see <a href="https://github.com/component/emitter">https://github.com/component/emitter</a>
*/
public class Emitter<T> {
private ConcurrentMap<String, ConcurrentLinkedQueue<Listener>> callbacks
= new ConcurrentHashMap<String, ConcurrentLinkedQueue<Listener>>();
private ConcurrentMap<Listener, Listener> onceCallbacks = new ConcurrentHashMap<Listener, Listener>();
/**
* Listens on the event.
* @param event event name.
* @param fn
* @return a reference to this object.
*/
public Emitter on(String event, Listener fn) {
ConcurrentLinkedQueue<Listener> callbacks = this.callbacks.get(event);
if (callbacks == null) {
callbacks = new ConcurrentLinkedQueue<Listener>();
ConcurrentLinkedQueue<Listener> _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 an event name.
* @param fn
* @return a reference to this object.
*/
public Emitter once(final String event, final Listener<T> fn) {
Listener on = new Listener<T>() {
@Override
public void call(T... 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 this object.
*/
public Emitter off() {
this.callbacks.clear();
this.onceCallbacks.clear();
return this;
}
/**
* Removes all listeners of the specified event.
*
* @param event an event name.
* @return a reference to this object.
*/
public Emitter off(String event) {
ConcurrentLinkedQueue<Listener> callbacks = this.callbacks.remove(event);
if (callbacks != null) {
for (Listener fn : callbacks) {
this.onceCallbacks.remove(fn);
}
}
return this;
}
/**
* Removes the listener.
*
* @param event an event name.
* @param fn
* @return a reference to this object.
*/
public Emitter off(String event, Listener fn) {
ConcurrentLinkedQueue<Listener> 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 an event name.
* @param args
* @return a reference to this object.
*/
public Future emit(String event, T... args) {
ConcurrentLinkedQueue<Listener> callbacks = this.callbacks.get(event);
if (callbacks != null) {
callbacks = new ConcurrentLinkedQueue<Listener>(callbacks);
for (Listener fn : callbacks) {
fn.call(args);
}
}
return null;
}
/**
* Returns a list of listeners for the specified event.
*
* @param event an event name.
* @return a reference to this object.
*/
public List<Listener> listeners(String event) {
ConcurrentLinkedQueue<Listener> callbacks = this.callbacks.get(event);
return callbacks != null ?
new ArrayList<Listener>(callbacks) : new ArrayList<Listener>();
}
/**
* Check if this emitter has listeners for the specified event.
*
* @param event an event name.
* @return a reference to this object.
*/
public boolean hasListeners(String event) {
return !this.listeners(event).isEmpty();
}
public static interface Listener<T> {
public void call(T... args);
}
}