/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.marketdata.live;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.Instant;
import com.opengamma.engine.marketdata.AbstractMarketDataSnapshot;
import com.opengamma.engine.marketdata.InMemoryLKVMarketDataSnapshot;
import com.opengamma.engine.marketdata.MarketDataListener;
import com.opengamma.engine.marketdata.MarketDataSnapshot;
import com.opengamma.engine.value.ValueSpecification;
import com.opengamma.id.UniqueId;
/**
* A {@link MarketDataSnapshot} for live data.
*/
public class LiveMarketDataSnapshot extends AbstractMarketDataSnapshot {
private static final Logger s_logger = LoggerFactory.getLogger(LiveMarketDataSnapshot.class);
private final InMemoryLKVMarketDataSnapshot _underlyingSnapshot;
private final LiveMarketDataProvider _liveMarketDataProvider;
public LiveMarketDataSnapshot(final InMemoryLKVMarketDataSnapshot underlyingSnapshot,
final LiveMarketDataProvider liveMarketDataProvider) {
_underlyingSnapshot = underlyingSnapshot;
_liveMarketDataProvider = liveMarketDataProvider;
}
@Override
public UniqueId getUniqueId() {
return UniqueId.of(MARKET_DATA_SNAPSHOT_ID_SCHEME, "LiveMarketDataSnapshot:" + getSnapshotTime());
}
@Override
public Instant getSnapshotTimeIndication() {
return _underlyingSnapshot.getSnapshotTimeIndication();
}
@Override
public void init() {
_underlyingSnapshot.init();
}
@Override
public void init(final Set<ValueSpecification> values, final long timeout, final TimeUnit unit) {
if (values != null && !values.isEmpty()) {
final Set<ValueSpecification> unavailable = Collections
.newSetFromMap(new ConcurrentHashMap<ValueSpecification, Boolean>());
unavailable.addAll(values);
final CountDownLatch awaitingValuesLatch = new CountDownLatch(1);
final MarketDataListener listener = new MarketDataListener() {
@Override
public void subscriptionsSucceeded(final Collection<ValueSpecification> valueSpecifications) {
}
@Override
public void subscriptionFailed(final ValueSpecification valueSpecification, final String msg) {
}
@Override
public void subscriptionStopped(final ValueSpecification valueSpecification) {
}
@Override
public void valuesChanged(final Collection<ValueSpecification> valueSpecifications) {
unavailable.removeAll(valueSpecifications);
if (unavailable.isEmpty()) {
awaitingValuesLatch.countDown();
}
}
};
_liveMarketDataProvider.addListener(listener);
try {
_underlyingSnapshot.init(); // TODO We need something to query, but snapshotting twice is a bit overkill
for (final ValueSpecification value : values) {
if (_underlyingSnapshot.query(value) != null) {
unavailable.remove(value);
} else if (_liveMarketDataProvider.isActive(value)) { //PLAT-1429
unavailable.remove(value);
}
}
if (!unavailable.isEmpty()) {
try {
if (!awaitingValuesLatch.await(timeout, unit)) {
s_logger.warn(MessageFormat.format(
"Timed out while waiting {0} {1} for required values to become available: {2}", timeout, unit,
unavailable));
}
} catch (final InterruptedException e) {
s_logger.warn(MessageFormat.format(
"Interrupted while waiting for required values to become available: {0}", unavailable), e);
}
}
} finally {
_liveMarketDataProvider.removeListener(listener);
}
}
_underlyingSnapshot.init(values, timeout, unit);
}
@Override
public boolean isInitialized() {
return _underlyingSnapshot.isInitialized();
}
@Override
public boolean isEmpty() {
assertInitialized();
return _underlyingSnapshot.isEmpty();
}
@Override
public Instant getSnapshotTime() {
return _underlyingSnapshot.getSnapshotTime();
}
@Override
public Object query(final ValueSpecification value) {
//TODO: return useful error message if failed
return _underlyingSnapshot.query(value);
}
}