/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.livedata.client;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.opengamma.livedata.LiveDataListener;
import com.opengamma.livedata.LiveDataSpecification;
import com.opengamma.livedata.LiveDataValueUpdateBean;
/**
* A stand-alone class which distributes live data values to all subscribed listeners.
* <p>
* This is separate from all live data client instances as it needs to be compact to be able to have efficient concurrency.
*/
public class ValueDistributor {
/**
* The map of specification to listeners.
*/
private final ConcurrentMap<LiveDataSpecification, Set<LiveDataListener>> _listenersBySpec =
new ConcurrentHashMap<LiveDataSpecification, Set<LiveDataListener>>();
/**
* Gets the current specifications.
*
* @return the specifications, not null
*/
public Set<LiveDataSpecification> getActiveSpecifications() {
return new HashSet<LiveDataSpecification>(_listenersBySpec.keySet());
}
/**
* Gets the number of current specifications.
*
* @return the number of current specifications.
*/
public int getActiveSpecificationCount() {
return _listenersBySpec.size();
}
/**
* Adds a listener.
*
* @param fullyQualifiedSpecification the fully qualified specification, not null
* @param listener the listener
*/
public void addListener(LiveDataSpecification fullyQualifiedSpecification, LiveDataListener listener) {
Set<LiveDataListener> freshListeners = new HashSet<LiveDataListener>();
Set<LiveDataListener> actualListeners = _listenersBySpec.putIfAbsent(fullyQualifiedSpecification, freshListeners);
if (actualListeners == null) {
actualListeners = freshListeners;
}
synchronized (actualListeners) {
actualListeners.add(listener);
}
}
/**
* Removes a listener.
*
* @param fullyQualifiedSpecification the fully qualified specification, not null
* @param listener the listener
* @return true iff there are still active listeners
*/
public boolean removeListener(LiveDataSpecification fullyQualifiedSpecification, LiveDataListener listener) {
Set<LiveDataListener> actualListeners = _listenersBySpec.get(fullyQualifiedSpecification);
if (actualListeners == null) {
return false;
}
synchronized (actualListeners) {
actualListeners.remove(listener);
if (actualListeners.isEmpty()) {
boolean removed = _listenersBySpec.remove(fullyQualifiedSpecification, actualListeners);
if (removed) {
return false;
} else {
// Someone else added a new one in addListener.
return true;
}
} else {
return true;
}
}
}
// TODO kirk 2009-09-29 -- This should be handed an executor service to
// invoke the updates asynchronously.
public void notifyListeners(LiveDataValueUpdateBean updateBean) {
Set<LiveDataListener> listeners = _listenersBySpec.get(updateBean.getSpecification());
if (listeners == null) {
return;
}
for (LiveDataListener listener : listeners) {
listener.valueUpdate(updateBean);
}
}
}