/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.engine.marketdata.historical; import java.io.Serializable; import java.util.Collection; import java.util.Objects; import java.util.Set; import com.google.common.collect.Sets; import com.opengamma.engine.ComputationTargetSpecification; import com.opengamma.engine.marketdata.AbstractMarketDataProvider; import com.opengamma.engine.marketdata.MarketDataListener; import com.opengamma.engine.marketdata.MarketDataPermissionProvider; import com.opengamma.engine.marketdata.MarketDataProvider; import com.opengamma.engine.marketdata.MarketDataSnapshot; import com.opengamma.engine.marketdata.availability.MarketDataAvailabilityFilter; import com.opengamma.engine.marketdata.availability.MarketDataAvailabilityProvider; import com.opengamma.engine.marketdata.availability.MarketDataNotSatisfiableException; import com.opengamma.engine.marketdata.availability.ProviderMarketDataAvailabilityFilter; import com.opengamma.engine.marketdata.spec.HistoricalShockMarketDataSpecification; import com.opengamma.engine.marketdata.spec.MarketDataSpecification; import com.opengamma.engine.value.ValueRequirement; import com.opengamma.engine.value.ValueSpecification; import com.opengamma.livedata.UserPrincipal; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.tuple.Triple; /** * Provider for market data derived from 3 underlying providers. This provider's values are derived by finding the * difference between values in the first two providers and applying it to the value from the third provider. * The change applied to the base value can be the proportional or absolute difference between the two other values. */ public class HistoricalShockMarketDataProvider extends AbstractMarketDataProvider { private final MarketDataProvider _historicalProvider1; private final MarketDataProvider _historicalProvider2; private final MarketDataProvider _baseProvider; private final MarketDataPermissionProvider _permissionProvider = new PermissionProvider(); public HistoricalShockMarketDataProvider(MarketDataProvider historicalProvider1, MarketDataProvider historicalProvider2, MarketDataProvider baseProvider) { ArgumentChecker.notNull(historicalProvider1, "historicalProvider1"); ArgumentChecker.notNull(historicalProvider2, "historicalProvider2"); ArgumentChecker.notNull(baseProvider, "baseProvider"); _historicalProvider1 = historicalProvider1; _historicalProvider2 = historicalProvider2; _baseProvider = baseProvider; Listener listener = new Listener(); historicalProvider1.addListener(listener); historicalProvider2.addListener(listener); baseProvider.addListener(listener); } @Override public void subscribe(ValueSpecification valueSpecification) { _historicalProvider1.subscribe(valueSpecification); _historicalProvider2.subscribe(valueSpecification); _baseProvider.subscribe(valueSpecification); } @Override public void subscribe(Set<ValueSpecification> valueSpecifications) { _historicalProvider1.subscribe(valueSpecifications); _historicalProvider2.subscribe(valueSpecifications); _baseProvider.subscribe(valueSpecifications); } @Override public void unsubscribe(ValueSpecification valueSpecification) { _historicalProvider1.unsubscribe(valueSpecification); _historicalProvider2.unsubscribe(valueSpecification); _baseProvider.unsubscribe(valueSpecification); } @Override public void unsubscribe(Set<ValueSpecification> valueSpecifications) { _historicalProvider1.unsubscribe(valueSpecifications); _historicalProvider2.unsubscribe(valueSpecifications); _baseProvider.unsubscribe(valueSpecifications); } @Override public MarketDataAvailabilityProvider getAvailabilityProvider(MarketDataSpecification marketDataSpec) { return new AvailabilityProvider((HistoricalShockMarketDataSpecification) marketDataSpec); } @Override public MarketDataPermissionProvider getPermissionProvider() { return _permissionProvider; } /** * Returns true if marketDataSpec is equal to this object. This method isn't used anyway so it's academic. * @param marketDataSpec describes the market data, not null * @return true if marketDataSpec is equal to this object */ @Override public boolean isCompatible(MarketDataSpecification marketDataSpec) { return equals(marketDataSpec); } @Override public HistoricalShockMarketDataSnapshot snapshot(MarketDataSpecification marketDataSpec) { if (!(marketDataSpec instanceof HistoricalShockMarketDataSpecification)) { throw new IllegalArgumentException("Market data spec not HistoricalShockMarketDataSpecification: " + marketDataSpec); } HistoricalShockMarketDataSpecification shockSpec = (HistoricalShockMarketDataSpecification) marketDataSpec; MarketDataSnapshot snapshot1 = _historicalProvider1.snapshot(shockSpec.getHistoricalSpecification1()); MarketDataSnapshot snapshot2 = _historicalProvider2.snapshot(shockSpec.getHistoricalSpecification2()); MarketDataSnapshot baseSnapshot = _baseProvider.snapshot(shockSpec.getBaseSpecification()); return new HistoricalShockMarketDataSnapshot(shockSpec.getShockType(), snapshot1, snapshot2, baseSnapshot); } @Override public int hashCode() { return Objects.hash(_historicalProvider1, _historicalProvider2, _baseProvider); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } final HistoricalShockMarketDataProvider other = (HistoricalShockMarketDataProvider) obj; return Objects.equals(this._historicalProvider1, other._historicalProvider1) && Objects.equals(this._historicalProvider2, other._historicalProvider2) && Objects.equals(this._baseProvider, other._baseProvider); } private class PermissionProvider implements MarketDataPermissionProvider { @Override public Set<ValueSpecification> checkMarketDataPermissions(UserPrincipal user, Set<ValueSpecification> specifications) { Set<ValueSpecification> failedSpecs1 = _historicalProvider1.getPermissionProvider().checkMarketDataPermissions(user, specifications); Set<ValueSpecification> failedSpecs2 = _historicalProvider2.getPermissionProvider().checkMarketDataPermissions(user, specifications); Set<ValueSpecification> failedSpecs3 = _baseProvider.getPermissionProvider().checkMarketDataPermissions(user, specifications); // if a value fails permission checking in any of the providers then it fails return Sets.union(Sets.union(failedSpecs1, failedSpecs2), failedSpecs3); } } private final class AvailabilityProvider implements MarketDataAvailabilityProvider { private final HistoricalShockMarketDataSpecification _marketDataSpec; private AvailabilityProvider(HistoricalShockMarketDataSpecification marketDataSpec) { ArgumentChecker.notNull(marketDataSpec, "marketDataSpecification"); _marketDataSpec = marketDataSpec; } @Override public ValueSpecification getAvailability(ComputationTargetSpecification targetSpec, Object target, ValueRequirement desiredValue) throws MarketDataNotSatisfiableException { ValueSpecification spec1 = _historicalProvider1.getAvailabilityProvider(_marketDataSpec.getHistoricalSpecification1()).getAvailability(targetSpec, target, desiredValue); ValueSpecification spec2 = _historicalProvider2.getAvailabilityProvider(_marketDataSpec.getHistoricalSpecification2()).getAvailability(targetSpec, target, desiredValue); ValueSpecification spec3 = _baseProvider.getAvailabilityProvider(_marketDataSpec.getBaseSpecification()).getAvailability(targetSpec, target, desiredValue); if (Objects.equals(spec1, spec2) && Objects.equals(spec2, spec3)) { return spec1; } else { return null; } } @Override public MarketDataAvailabilityFilter getAvailabilityFilter() { return new ProviderMarketDataAvailabilityFilter(this); } @Override public Serializable getAvailabilityHintKey() { return Triple.of(_historicalProvider1.getAvailabilityProvider(_marketDataSpec.getHistoricalSpecification1()).getAvailabilityHintKey(), _historicalProvider2.getAvailabilityProvider(_marketDataSpec.getHistoricalSpecification2()).getAvailabilityHintKey(), _baseProvider.getAvailabilityProvider(_marketDataSpec.getBaseSpecification()).getAvailabilityHintKey()); } } private class Listener implements MarketDataListener { @Override public void subscriptionsSucceeded(Collection<ValueSpecification> specifications) { HistoricalShockMarketDataProvider.this.subscriptionsSucceeded(specifications); } @Override public void subscriptionFailed(ValueSpecification specification, String msg) { HistoricalShockMarketDataProvider.this.subscriptionFailed(specification, msg); } @Override public void subscriptionStopped(ValueSpecification specification) { HistoricalShockMarketDataProvider.this.subscriptionStopped(specification); } @Override public void valuesChanged(Collection<ValueSpecification> specifications) { HistoricalShockMarketDataProvider.this.valuesChanged(specifications); } } }