package org.marketcetera.photon.internal.module;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.lang.Validate;
import org.marketcetera.module.DataFlowID;
import org.marketcetera.module.SinkDataListener;
import org.marketcetera.photon.module.ISinkDataHandler;
import org.marketcetera.photon.module.ISinkDataManager;
import org.marketcetera.util.misc.ClassVersion;
/* $License$ */
/**
* Implementation of {@link ISinkDataManager}.
*
* @author <a href="mailto:will@marketcetera.com">Will Horn</a>
* @version $Id: SinkDataManager.java 16154 2012-07-14 16:34:05Z colin $
* @since 1.5.0
*/
@ClassVersion("$Id: SinkDataManager.java 16154 2012-07-14 16:34:05Z colin $")
public class SinkDataManager implements SinkDataListener, ISinkDataManager {
/**
* Manages the handlers, assuming about 10 types of sink data and only about 2 concurrent
* subscribing threads.
*/
private final ConcurrentMap<Class<?>, CopyOnWriteArraySet<ISinkDataHandler>> handlers =
new ConcurrentHashMap<Class<?>, CopyOnWriteArraySet<ISinkDataHandler>>(10, 0.75f, 2);
private final AtomicReference<ISinkDataHandler> defaultHandler =
new AtomicReference<ISinkDataHandler>();
@Override
public void register(ISinkDataHandler handler, Class<?>... classes) {
Validate.notNull(handler);
Validate.noNullElements(classes);
for (Class<?> clazz : classes) {
handlers.putIfAbsent(clazz, new CopyOnWriteArraySet<ISinkDataHandler>());
handlers.get(clazz).add(handler);
}
}
@Override
public void registerDefault(ISinkDataHandler handler) {
Validate.notNull(handler);
if (!defaultHandler.compareAndSet(null, handler)) {
throw new IllegalStateException();
}
}
@Override
public void unregister(ISinkDataHandler handler, Class<?>... classes) {
Validate.notNull(handler);
Validate.noNullElements(classes);
for (Class<?> clazz : classes) {
handlers.get(clazz).remove(handler);
}
}
@Override
public void unregister(ISinkDataHandler handler) {
Validate.notNull(handler);
for (Set<ISinkDataHandler> set : handlers.values()) {
set.remove(handler);
}
defaultHandler.compareAndSet(handler, null);
}
@Override
public void unregisterDefault(ISinkDataHandler handler) {
Validate.notNull(handler);
defaultHandler.compareAndSet(handler, null);
}
@Override
public void sendData(String source, Object data) {
receivedData(new DataFlowID(source), data);
}
@Override
public void receivedData(DataFlowID inFlowID, Object inData) {
boolean handled = false;
for (Map.Entry<Class<?>, CopyOnWriteArraySet<ISinkDataHandler>> entry : handlers.entrySet()) {
if (entry.getKey().isInstance(inData)) {
for (ISinkDataHandler handler : entry.getValue()) {
handled = true;
handler.receivedData(inFlowID, inData);
}
}
}
if (!handled) {
ISinkDataHandler def = defaultHandler.get();
if (def != null) {
def.receivedData(inFlowID, inData);
}
}
}
}