/**
* 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.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.opengamma.util.result.FailureStatus;
import com.opengamma.util.result.Result;
/**
* Market data source that gets data from multiple underlying sources.
*/
public class CompositeMarketDataSource implements MarketDataSource {
private final List<MarketDataSource> _dataSources;
/**
* @param dataSources the underlying data sources that provide the data
*/
public CompositeMarketDataSource(List<MarketDataSource> dataSources) {
_dataSources = ImmutableList.copyOf(dataSources);
}
@Override
public Map<MarketDataRequest, Result<?>> get(Set<MarketDataRequest> requests) {
ImmutableMap.Builder<MarketDataRequest, Result<?>> dataBuilder = ImmutableMap.builder();
Set<MarketDataRequest> outstandingRequests = requests;
for (MarketDataSource dataSource : _dataSources) {
Map<MarketDataRequest, Result<?>> data = dataSource.get(outstandingRequests);
PartitionedResults results = new PartitionedResults(data);
dataBuilder.putAll(results._available);
outstandingRequests = results._unavailable;
}
for (MarketDataRequest unavailable : outstandingRequests) {
// we're not using the failure status from the result because there's no way of knowing whether it's relevant.
// the failure status that we have is the result from the last source, and there's nothing to say that that's
// the source where it should have been available. if the data isn't available the user knows it isn't
// available from any of the sources. the user is also in the best position to know which source should be
// able to provide the data. this class doesn't have any way of knowing that
dataBuilder.put(unavailable, Result.failure(FailureStatus.MISSING_DATA, "No data available for {}", unavailable));
}
return dataBuilder.build();
}
/**
* Helper class to divide the results into successes and failures
*/
private static class PartitionedResults {
/** Data that was successfully requested from the data source. */
private final Map<MarketDataRequest, Result<?>> _available;
/** Requests for that that weren't satisfied. */
private final Set<MarketDataRequest> _unavailable;
private PartitionedResults(Map<MarketDataRequest, Result<?>> allData) {
Set<MarketDataRequest> unavailable = new HashSet<>();
Map<MarketDataRequest, Result<?>> data = new HashMap<>();
for (Map.Entry<MarketDataRequest, Result<?>> entry : allData.entrySet()) {
MarketDataRequest request = entry.getKey();
Result<?> result = entry.getValue();
if (result.isSuccess()) {
data.put(request, result);
} else {
unavailable.add(request);
}
}
_available = data;
_unavailable = unavailable;
}
}
}