/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.sesame.marketdata;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.ImmutableMap;
import com.opengamma.core.marketdatasnapshot.CurveKey;
import com.opengamma.core.marketdatasnapshot.CurveSnapshot;
import com.opengamma.core.marketdatasnapshot.MarketDataSnapshotSource;
import com.opengamma.core.marketdatasnapshot.NamedSnapshot;
import com.opengamma.core.marketdatasnapshot.StructuredMarketDataSnapshot;
import com.opengamma.core.marketdatasnapshot.UnstructuredMarketDataSnapshot;
import com.opengamma.core.marketdatasnapshot.ValueSnapshot;
import com.opengamma.engine.marketdata.spec.UserMarketDataSpecification;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.result.FailureStatus;
import com.opengamma.util.result.Result;
/**
* Market data factory that creates a data source backed by a {@link StructuredMarketDataSnapshot}.
* <p>
* This acts an an adaptor between the old and new market data systems. This class is likely to be redundant
* after everything has migrated to use {@link MarketDataEnvironment}.
*/
public class SnapshotMarketDataFactory
implements MarketDataFactory<UserMarketDataSpecification> {
private final MarketDataSnapshotSource _snapshotSource;
/**
* @param snapshotSource for loading snapshots
*/
public SnapshotMarketDataFactory(MarketDataSnapshotSource snapshotSource) {
_snapshotSource = ArgumentChecker.notNull(snapshotSource, "snapshotSource");
}
@Override
public Class<UserMarketDataSpecification> getSpecificationType() {
return UserMarketDataSpecification.class;
}
@Override
public MarketDataSource create(UserMarketDataSpecification spec) {
NamedSnapshot snapshot = _snapshotSource.get(spec.getUserSnapshotId());
return new DataSource(flattenSnapshot((StructuredMarketDataSnapshot) snapshot));
}
/**
* Flattens a snapshot into a map of raw values. Handles raw data and curves, not surfaces or cubes.
*
* @param snapshot a snapshot
* @return the snapshot's raw data and curve data flattened into a map
*/
private static Map<MarketDataRequest, Object> flattenSnapshot(StructuredMarketDataSnapshot snapshot) {
Map<MarketDataRequest, Object> marketData = new HashMap<>();
marketData.putAll(extractSnapshotData(snapshot.getGlobalValues()));
for (Map.Entry<CurveKey, CurveSnapshot> curveEntry : snapshot.getCurves().entrySet()) {
UnstructuredMarketDataSnapshot curveValues = curveEntry.getValue().getValues();
marketData.putAll(extractSnapshotData(curveValues));
}
return marketData;
}
private static Map<MarketDataRequest, Object> extractSnapshotData(UnstructuredMarketDataSnapshot snapshot) {
Map<MarketDataRequest, Object> marketData = new HashMap<>();
for (ExternalIdBundle idBundle : snapshot.getTargets()) {
Map<String, ValueSnapshot> targetValues = snapshot.getTargetValues(idBundle);
for (Map.Entry<String, ValueSnapshot> targetValue : targetValues.entrySet()) {
FieldName fieldName = FieldName.of(targetValue.getKey());
ValueSnapshot value = targetValue.getValue();
// key by individual IDs, not bundles
for (ExternalId id : idBundle) {
MarketDataRequest request = MarketDataRequest.of(id.toBundle(), fieldName);
marketData.put(request, value.getMarketValue());
}
}
}
return marketData;
}
private static class DataSource implements MarketDataSource {
private final Map<MarketDataRequest, Object> _marketData;
private DataSource(Map<MarketDataRequest, Object> marketData) {
_marketData = marketData;
}
@Override
public Map<MarketDataRequest, Result<?>> get(Set<MarketDataRequest> requests) {
ImmutableMap.Builder<MarketDataRequest, Result<?>> builder = ImmutableMap.builder();
for (MarketDataRequest request : requests) {
for (ExternalId id : request.getId()) {
MarketDataRequest singleIdRequest = MarketDataRequest.of(id.toBundle(), request.getFieldName());
Object value = _marketData.get(singleIdRequest);
if (value != null) {
builder.put(request, Result.success(value));
break;
} else {
builder.put(request, Result.failure(FailureStatus.MISSING_DATA, "No data available for {}", request));
}
}
}
return builder.build();
}
}
}