Package com.opengamma.engine.view.worker

Source Code of com.opengamma.engine.view.worker.SnapshottingViewExecutionDataProvider$CompositeAvailabilityProvider

/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.view.worker;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import org.threeten.bp.Duration;
import org.threeten.bp.Instant;

import com.google.common.collect.Lists;
import com.opengamma.engine.ComputationTargetSpecification;
import com.opengamma.engine.marketdata.MarketDataListener;
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.UnionMarketDataAvailability;
import com.opengamma.engine.marketdata.resolver.MarketDataProviderResolver;
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.Pair;

/**
* A source of market data that aggregates data from multiple underlying {@link MarketDataProvider}s. Each request for market data is handled by one of the underlying providers. When a subscription is
* made the underlying providers are checked in priority order until one of them is able to provide the data.
* <p>
* All notifications of market data updates and subscription changes are delivered to all listeners. Therefore instances of this class shouldn't be shared between multiple view processes.
*/
public class SnapshottingViewExecutionDataProvider extends ViewExecutionDataProvider {

  private final MarketDataAvailabilityProvider _availabilityProvider;
  private final CopyOnWriteArraySet<MarketDataListener> _listeners = new CopyOnWriteArraySet<MarketDataListener>();

  /**
   * @param user The user requesting the data, not null
   * @param specs Specifications of the underlying providers in priority order, not empty
   * @param resolver For resolving market data specifications into providers, not null
   * @throws IllegalArgumentException If any of the data providers in {@code specs} can't be resolved
   */
  public SnapshottingViewExecutionDataProvider(final UserPrincipal user,
      final List<MarketDataSpecification> specs,
      final MarketDataProviderResolver resolver) {
    super(user, specs, resolver);
    final MarketDataListener listener = new Listener();
    if (getSpecifications().size() == 1) {
      final MarketDataProvider provider = getProviders().get(0);
      provider.addListener(listener);
      _availabilityProvider = provider.getAvailabilityProvider(getSpecifications().get(0));
    } else {
      int index = 0;
      for (MarketDataProvider provider : getProviders()) {
        provider.addListener(new CompositeListener(index++, listener));
      }
      _availabilityProvider = new CompositeAvailabilityProvider(getProviders(), getSpecifications());
    }
  }

  /**
   * Adds a listener that will be notified of market data updates and subscription changes.
   *
   * @param listener The listener, not null
   */
  public void addListener(final MarketDataListener listener) {
    ArgumentChecker.notNull(listener, "listener");
    _listeners.add(listener);
  }

  /**
   * Removes a listener.
   *
   * @param listener The listener, not null
   */
  public void removeListener(final MarketDataListener listener) {
    _listeners.remove(listener);
  }

  /**
   * Sets up subscriptions for market data
   *
   * @param specifications The market data items, not null
   */
  public void subscribe(final Set<ValueSpecification> specifications) {
    ArgumentChecker.notNull(specifications, "specifications");
    final List<Set<ValueSpecification>> specificationsByProvider = partitionSpecificationsByProvider(getProviders().size(), specifications);
    for (int i = 0; i < specificationsByProvider.size(); i++) {
      final Set<ValueSpecification> subscribe = specificationsByProvider.get(i);
      if (!subscribe.isEmpty()) {
        getProviders().get(i).subscribe(subscribe);
      }
    }
  }

  /**
   * Unsubscribes from market data.
   *
   * @param specifications The subscriptions that should be removed, not null
   */
  public void unsubscribe(final Set<ValueSpecification> specifications) {
    ArgumentChecker.notNull(specifications, "requirements");
    final List<Set<ValueSpecification>> specificationsByProvider = partitionSpecificationsByProvider(getProviders().size(), specifications);
    for (int i = 0; i < specificationsByProvider.size(); i++) {
      final Set<ValueSpecification> unsubscribe = specificationsByProvider.get(i);
      if (!unsubscribe.isEmpty()) {
        getProviders().get(i).unsubscribe(unsubscribe);
      }
    }
  }

  /**
   * @return An availability provider backed by the availability providers of the underlying market data providers
   */
  public MarketDataAvailabilityProvider getAvailabilityProvider() {
    return _availabilityProvider;
  }

  /**
   * @return A snapshot of market data backed by snapshots from the underlying providers.
   */
  public MarketDataSnapshot snapshot() {
    final int providers = getProviders().size();
    if (providers == 1) {
      return getProviders().get(0).snapshot(getSpecifications().get(0));
    }
    final List<MarketDataSnapshot> snapshots = Lists.newArrayListWithCapacity(providers);
    for (int i = 0; i < providers; i++) {
      final MarketDataSnapshot snapshot = getProviders().get(i).snapshot(getSpecifications().get(i));
      snapshots.add(snapshot);
    }
    return new CompositeMarketDataSnapshot(snapshots, new ValueSpecificationProvider(providers));
  }

  public Duration getRealTimeDuration(final Instant fromInstant, final Instant toInstant) {
    return Duration.between(fromInstant, toInstant);
  }

  /**
   * Distributes the updates to the listeners.
   */
  private class Listener implements MarketDataListener {

    @Override
    public void subscriptionsSucceeded(Collection<ValueSpecification> valueSpecifications) {
      for (final MarketDataListener listener : _listeners) {
        listener.subscriptionsSucceeded(valueSpecifications);
      }
    }

    @Override
    public void subscriptionFailed(ValueSpecification valueSpecification, final String msg) {
      for (final MarketDataListener listener : _listeners) {
        listener.subscriptionFailed(valueSpecification, msg);
      }
    }

    @Override
    public void subscriptionStopped(ValueSpecification valueSpecification) {
      for (final MarketDataListener listener : _listeners) {
        listener.subscriptionStopped(valueSpecification);
      }
    }

    @Override
    public void valuesChanged(Collection<ValueSpecification> valueSpecifications) {
      for (final MarketDataListener listener : _listeners) {
        listener.valuesChanged(valueSpecifications);
      }
    }

  }

  /**
   * Listens for updates from the underlying providers and distributes them to the listeners.
   */
  private static class CompositeListener implements MarketDataListener {

    private final int _providerId;
    private final MarketDataListener _underlying;

    public CompositeListener(final int providerId, final MarketDataListener underlying) {
      _providerId = providerId;
      _underlying = underlying;
    }

    private ValueSpecification convertSpecification(final ValueSpecification valueSpecification) {
      return convertUnderlyingSpecification(_providerId, valueSpecification);
    }

    private Collection<ValueSpecification> convertSpecifications(final Collection<ValueSpecification> valueSpecifications) {
      final Collection<ValueSpecification> result = new ArrayList<ValueSpecification>(valueSpecifications.size());
      for (final ValueSpecification valueSpecification : valueSpecifications) {
        result.add(convertSpecification(valueSpecification));
      }
      return result;
    }

    @Override
    public void subscriptionsSucceeded(Collection<ValueSpecification> valueSpecifications) {
      _underlying.subscriptionsSucceeded(convertSpecifications(valueSpecifications));
    }

    @Override
    public void subscriptionFailed(ValueSpecification valueSpecification, final String msg) {
      _underlying.subscriptionFailed(convertSpecification(valueSpecification), msg);
    }

    @Override
    public void subscriptionStopped(ValueSpecification valueSpecification) {
      _underlying.subscriptionStopped(convertSpecification(valueSpecification));
    }

    @Override
    public void valuesChanged(Collection<ValueSpecification> valueSpecifications) {
      _underlying.valuesChanged(convertSpecifications(valueSpecifications));
    }

  }

  /**
   * {@link MarketDataAvailabilityProvider} that checks the underlying providers for availability. If the data is available from any underlying provider then it is available. If it isn't available but
   * is missing from any of the underlying providers then it is missing. Otherwise it is unavailable.
   */
  private static final class CompositeAvailabilityProvider implements MarketDataAvailabilityProvider {

    private final List<MarketDataAvailabilityProvider> _providers;
    private final Serializable _cacheHint;

    public CompositeAvailabilityProvider(final List<MarketDataProvider> providers, final List<MarketDataSpecification> specs) {
      _providers = new ArrayList<MarketDataAvailabilityProvider>(providers.size());
      final ArrayList<Serializable> cacheHints = new ArrayList<Serializable>(providers.size());
      for (int i = 0; i < providers.size(); i++) {
        final MarketDataAvailabilityProvider availabilityProvider = providers.get(i).getAvailabilityProvider(specs.get(i));
        _providers.add(availabilityProvider);
        cacheHints.add(availabilityProvider.getAvailabilityHintKey());
      }
      _cacheHint = cacheHints;
    }

    /**
     * @param desiredValue the market data requirement, not null
     * @return The satisfaction of the requirement from the underlying providers.
     */
    @Override
    public ValueSpecification getAvailability(final ComputationTargetSpecification targetSpec, final Object target, final ValueRequirement desiredValue) {
      MarketDataNotSatisfiableException missing = null;
      for (int i = 0; i < _providers.size(); i++) {
        final MarketDataAvailabilityProvider provider = _providers.get(i);
        try {
          final ValueSpecification underlying = provider.getAvailability(targetSpec, target, desiredValue);
          if (underlying != null) {
            return convertUnderlyingSpecification(i, underlying);
          }
        } catch (final MarketDataNotSatisfiableException e) {
          missing = e;
        }
      }
      if (missing != null) {
        throw missing;
      } else {
        return null;
      }
    }

    @Override
    public MarketDataAvailabilityFilter getAvailabilityFilter() {
      final List<MarketDataAvailabilityFilter> union = new ArrayList<MarketDataAvailabilityFilter>(_providers.size());
      for (MarketDataAvailabilityProvider provider : _providers) {
        union.add(provider.getAvailabilityFilter());
      }
      return new UnionMarketDataAvailability.Filter(union);
    }

    @Override
    public Serializable getAvailabilityHintKey() {
      return _cacheHint;
    }

  }

  /* package */static class ValueSpecificationProvider {

    private final int _numProviders;

    /* package */ValueSpecificationProvider(final int numProviders) {
      _numProviders = numProviders;
    }

    public Pair<Integer, ValueSpecification> getUnderlyingAndSpecification(final ValueSpecification specification) {
      return SnapshottingViewExecutionDataProvider.getProviderSpecification(specification);
    }

    public List<Set<ValueSpecification>> getUnderlyingSpecifications(final Set<ValueSpecification> specifications) {
      return SnapshottingViewExecutionDataProvider.partitionSpecificationsByProvider(_numProviders, specifications);
    }

    public ValueSpecification convertUnderlyingSpecification(final int providerId, final ValueSpecification specification) {
      return SnapshottingViewExecutionDataProvider.convertUnderlyingSpecification(providerId, specification);
    }

  }

}
TOP

Related Classes of com.opengamma.engine.view.worker.SnapshottingViewExecutionDataProvider$CompositeAvailabilityProvider

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.