package com.workshare.msnos.soup.threading;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class is an asynchronous multicaster, allows you to send asynchronous
* notifications to an arbitrary number of listeners, managed by this It's
* thread safe, it uses internally an Executor to deliver notifications, but you
* can provide your own instance.
* An option for synchronous dispatching is also available trough a separate
* list of listeners which is invoked without using the executor
*
*
* To use it, you need to extend this class and provide an implementation of the
* dispatch(L listener, M message) method - it should be straightforward.
*
* @author bossola
*
* @param <L>
* The listener class
* @param <M>
* The message class (the argument to notify)
*/
public abstract class Multicaster<L, M> {
private static final Logger log = LoggerFactory.getLogger(Multicaster.class);
public static final Executor THREADPOOL = ExecutorServices.newFixedDaemonThreadPool(Integer.getInteger("msnos.multicaster.threads.num", 5));
private List<L> syncListeners = new CopyOnWriteArrayList<L>();
private List<L> asyncListeners = new CopyOnWriteArrayList<L>();
private Executor asyncExecutor;
public Multicaster() {
this(THREADPOOL);
}
public Multicaster(Executor executor) {
this.asyncExecutor = executor;
}
public L addListener(L listener) {
asyncListeners.add(listener);
return listener;
}
public L addSynchronousListener(L listener) {
syncListeners.add(listener);
return listener;
}
public boolean removeListener(L listener) {
return asyncListeners.remove(listener);
}
public boolean removeSynchronousListener(L listener) {
return syncListeners.remove(listener);
}
public void dispatch(final M message) {
if (log.isTraceEnabled()) {
ThreadPoolExecutor pool = (ThreadPoolExecutor) asyncExecutor;
int active = pool.getActiveCount();
int queued = pool.getQueue().size();
long total = pool.getTaskCount();
log.trace(String.format("%d %d %d\n", active, queued, total));
}
notifySync(message);
notifyAsync(message);
}
private void notifySync(final M message) {
for (final L listener : syncListeners) {
dispatch(listener, message);
}
}
private void notifyAsync(final M message) {
for (final L listener : asyncListeners) {
asyncExecutor.execute(new Runnable() {
@Override
public void run() {
dispatch(listener, message);
}
});
}
}
protected abstract void dispatch(L listener, M message);
}