Package com.opengamma.livedata.server

Source Code of com.opengamma.livedata.server.Subscription

/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.livedata.server;

import java.util.Collection;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

import org.fudgemsg.FudgeMsg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.opengamma.livedata.LiveDataSpecification;
import com.opengamma.livedata.server.distribution.MarketDataDistributor;
import com.opengamma.livedata.server.distribution.MarketDataSenderFactory;
import com.opengamma.util.ArgumentChecker;

/**
* A record of a market data subscription currently active on a server.
*/
public class Subscription {

  /** Logger. */
  private static final Logger s_logger = LoggerFactory.getLogger(Subscription.class);

  /**
   * The unique ID that was subscribed to, specific to the market data provider, such as Bloomberg/Reuters.
   */
  private final String _securityUniqueId;
  /**
   * Controls how the data from this subscription will be sent.
   */
  private final MarketDataSenderFactory _marketDataSenderFactory;
  /**
   * A lock to enforce that live data is handled in a serialized and thus safe & ordered fashion.
   */
  private final ReentrantLock _liveDataSerializationLock = new ReentrantLock();
  /**
   * The data from this subscription can be distributed to clients in multiple formats,
   * therefore we need multiple market data distributors.
   * NOTE: this is a concurrent map for speedy reads
   * <p>
   */
  private final ConcurrentHashMap<DistributionSpecification, MarketDataDistributor> _distributors = new ConcurrentHashMap<DistributionSpecification, MarketDataDistributor>();
  /**
   * The handle to the underlying subscription, specific to the market data provider, such as Bloomberg/Reuters.
   * May be null if the subscription is not currently active.
   */
  private volatile Object _handle;
  /**
   * History of ticks received from the underlying market data API, in its native format.
   */
  private final FieldHistoryStore _history = new FieldHistoryStore();
  /**
   * The creation instant.
   */
  private final Date _creationTime;
  /**
   * The provider of last known value stores.
   */
  private final LastKnownValueStoreProvider _lkvStoreProvider;

  /**
   * Creates an instance.
   *
   * @param securityUniqueId  the security unique ID, specific to the market data provider, not null
   * @param marketDataSenderFactory  the factory that will create market data distributors for this subscription, not null
   * @param lkvStoreProvider  the factory for last known value stores, not null
   */
  public Subscription(String securityUniqueId, MarketDataSenderFactory marketDataSenderFactory, LastKnownValueStoreProvider lkvStoreProvider) {
    ArgumentChecker.notNull(securityUniqueId, "securityUniqueId");
    ArgumentChecker.notNull(marketDataSenderFactory, "marketDataSenderFactory");
    ArgumentChecker.notNull(lkvStoreProvider, "lkvStoreProvider");
    _securityUniqueId = securityUniqueId;
    _marketDataSenderFactory = marketDataSenderFactory;
    _creationTime = new Date();
    _lkvStoreProvider = lkvStoreProvider;
  }

  //-------------------------------------------------------------------------
  /**
   * Gets the opaque handle to the underlying subscription, specific to the market data provider.
   *
   * @return the opaque handle, null if the subscription is not currently active
   */
  public Object getHandle() {
    return _handle;
  }

  /**
   * Sets the opaque handle to the underlying subscription, specific to the market data provider.
   *
   * @param handle  the opaque handle, null if the subscription is not currently active
   */
  public void setHandle(Object handle) {
    _handle = handle;
  }

  /**
   * Gets the creation instant.
   *
   * @return the creation instant, not null
   */
  public Date getCreationTime() {
    return _creationTime;
  }

  /**
   * Gets the unique ID that was subscribed to, specific to the market data provider.
   *
   * @return the market data provider unique ID, not null
   */
  public String getSecurityUniqueId() {
    return _securityUniqueId;
  }

  /**
   * Gets the factory used to create distributors.
   *
   * @return the factory, not null
   */
  public MarketDataSenderFactory getMarketDataSenderFactory() {
    return _marketDataSenderFactory;
  }

  //-------------------------------------------------------------------------
  /**
   * Gets the set of distribution specifications.
   *
   * @return a modifiable copy of the specifications, not null
   */
  public Set<DistributionSpecification> getDistributionSpecifications() {
    return _distributors.keySet();
  }

  /**
   * Gets the set of distributors.
   *
   * @return a modifiable copy of the distributors, not null
   */
  public Collection<MarketDataDistributor> getDistributors() {
    return _distributors.values();
  }

  /**
   * Gets a specific distributor by distribution specification.
   *
   * @param distributionSpec  the specification to find
   * @return the distributor, null if not found
   */
  public MarketDataDistributor getMarketDataDistributor(DistributionSpecification distributionSpec) {
    return _distributors.get(distributionSpec);
  }

  /**
   * Gets a specific distributor by specification.
   *
   * @param fullyQualifiedSpec  the specification to find
   * @return the distributor, null if not found
   */
  public MarketDataDistributor getMarketDataDistributor(LiveDataSpecification fullyQualifiedSpec) {
    for (MarketDataDistributor distributor : getDistributors()) {
      if (distributor.getDistributionSpec().getFullyQualifiedLiveDataSpecification().equals(fullyQualifiedSpec)) {
        return distributor;
      }
    }
    return null;
  }

  /**
   * Gets the provider of last known value stores.
   *
   * @return the provider of last known value stores, not null
   */
  public LastKnownValueStoreProvider getLkvStoreProvider() {
    return _lkvStoreProvider;
  }

  //-------------------------------------------------------------------------
  /**
   * Tells this subscription to start distributing market data in the given format.
   * Only creates a new distribution if it doesn't already exist.
   *
   * @param spec  the format to use
   * @param persistent  whether the distributor should be persistent (survive a server restart)
   * @return the created/modified {@code MarketDataDistributor}
   */
  /*package*/ MarketDataDistributor createDistributor(DistributionSpecification spec, boolean persistent) {
    MarketDataDistributor distributor = getMarketDataDistributor(spec);
    if (distributor == null) {
      distributor = new MarketDataDistributor(spec, this, getMarketDataSenderFactory(), persistent, getLkvStoreProvider());
      MarketDataDistributor previous = _distributors.putIfAbsent(spec, distributor);
      if (previous == null) {
        s_logger.info("Added {} to {}", distributor, this);
      } else {
        s_logger.debug("Lost race to create distributor {} to {}", previous, this);
        distributor = previous;
      }
    }
    // Might be necessary to make the distributor persistent. We
    // never turn it back from persistent to non-persistent, however.
    if (!distributor.isPersistent() && persistent) {
      distributor.setPersistent(persistent);
      s_logger.info("Made {} persistent", distributor);
    }
    return distributor;
  }

  /*package*/ void removeDistributor(MarketDataDistributor distributor) {
    removeDistributor(distributor.getDistributionSpec());
  }

  /*package*/ void removeDistributor(DistributionSpecification spec) {
    MarketDataDistributor removed = _distributors.remove(spec);
    if (removed != null) {
      s_logger.info("Removed {} from {}", removed, this);     
    } else {
      s_logger.info("Removed distribution spec {} from {} (no-op)", spec, this);
    }
  }

  /*package*/ void removeAllDistributors() {
    s_logger.info("Removed {} from {}", _distributors, this);
    _distributors.clear();
  }

  /*package*/ void initialSnapshotReceived(FudgeMsg liveDataFields) {
    _liveDataSerializationLock.lock();
    try {
      _history.liveDataReceived(liveDataFields);

      for (MarketDataDistributor distributor : getDistributors()) {
        distributor.updateFieldHistory(liveDataFields);
      }
    } finally {
      _liveDataSerializationLock.unlock();
    }
  }

  /*package*/ void liveDataReceived(FudgeMsg liveDataFields) {
    _liveDataSerializationLock.lock();
    try {
      _history.liveDataReceived(liveDataFields);

      for (MarketDataDistributor distributor : getDistributors()) {
        distributor.distributeLiveData(liveDataFields);
      }
    } finally {
      _liveDataSerializationLock.unlock();
    }
  }

  //-------------------------------------------------------------------------
  /**
   * Gets the history.
   *
   * @return a modifiable copy of the history, not null
   */
  public FieldHistoryStore getLiveDataHistory() {
    _liveDataSerializationLock.lock();
    try {
      return new FieldHistoryStore(_history);
    } finally {
      _liveDataSerializationLock.unlock();
    }
  }

  /**
   * Checks if the subscription is active.
   *
   * @return true if active
   */
  public boolean isActive() {
    return getHandle() != null;
  }

  //-------------------------------------------------------------------------
  @Override
  public String toString() {
    return "Subscription[" + _securityUniqueId + "]";
  }
}
TOP

Related Classes of com.opengamma.livedata.server.Subscription

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.