Package com.opengamma.livedata.cogda.server

Source Code of com.opengamma.livedata.cogda.server.CogdaDataDistributor

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

import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.fudgemsg.FudgeMsg;
import org.fudgemsg.mapping.FudgeSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.Lifecycle;

import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;
import com.opengamma.id.ExternalId;
import com.opengamma.livedata.LiveDataSpecification;
import com.opengamma.livedata.LiveDataValueUpdateBean;
import com.opengamma.livedata.LiveDataValueUpdateBeanFudgeBuilder;
import com.opengamma.livedata.normalization.NormalizationRuleSet;
import com.opengamma.livedata.server.FieldHistoryStore;
import com.opengamma.livedata.server.LastKnownValueStore;
import com.opengamma.livedata.server.LastKnownValueStoreProvider;
import com.opengamma.transport.FudgeMessageSender;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.metric.MetricProducer;

/**
* Listens to a channel of raw data updates, normalizes, writes to the LKV store, and then
* publishes all value updates (for the normalized results) to a different channel
* for detection by the data servers.
* <p/>
* It has three ways that the list of active subscriptions can be built:
* <ol>
*   <li>You can just wait for updates to come through. Whenever an update is received
*       where there is not a distribution order, one will be built.</li>
*   <li>By scanning the LKV store on startup.</li>
*   <li>You can explicitly add them (perhaps via startup configuration)
*       via calls to {@link #addDistribution(String)}.</li>
* </ol>
* <p/>
* In general, if not bootstrapping for the first time, the first and second ways should be
* sufficient.
*/
public abstract class CogdaDataDistributor implements Lifecycle, MetricProducer {
  private static final Logger s_logger = LoggerFactory.getLogger(CogdaDataDistributor.class);
  // Constructor injectors:
  private final String _externalIdScheme;
  private final LastKnownValueStoreProvider _lastKnownValueStoreProvider;
  private final Map<String, NormalizationRuleSet> _normalization;
 
  // TODO kirk 2012-08-13 -- Have support for multiple senders, one per normalization
  // rule. Otherwise there's way too much filtering. But that's a second-order effect.
  private FudgeMessageSender _normalizedMessageSender;
 
  // Internal state:
  private final ConcurrentMap<LiveDataSpecification, LastKnownValueStore> _valueStores =
      new ConcurrentHashMap<LiveDataSpecification, LastKnownValueStore>();
  private final ConcurrentMap<LiveDataSpecification, FieldHistoryStore> _normalizationState =
      new ConcurrentHashMap<LiveDataSpecification, FieldHistoryStore>();
 
  // Metrics:
  private Meter _tickMeter = new Meter();
 
  public CogdaDataDistributor(
      String externalIdScheme,
      LastKnownValueStoreProvider lastKnownValueStoreProvider,
      String... normalizationSchemes) {
    ArgumentChecker.notNull(externalIdScheme, "externalIdScheme");
    ArgumentChecker.notNull(lastKnownValueStoreProvider, "lastKnownValueStoreProvider");
   
    _externalIdScheme = externalIdScheme;
    _lastKnownValueStoreProvider = lastKnownValueStoreProvider;
    _normalization = Collections.unmodifiableMap(constructNormalizationRules(normalizationSchemes));
  }
 
  @Override
  public synchronized void registerMetrics(MetricRegistry summaryRegistry, MetricRegistry detailedRegistry, String namePrefix) {
    _tickMeter = summaryRegistry.meter(namePrefix + ".ticks");
  }

  /**
   * Gets the externalIdScheme.
   * @return the externalIdScheme
   */
  public String getExternalIdScheme() {
    return _externalIdScheme;
  }

  /**
   * Gets the normalizedMessageSender.
   * @return the normalizedMessageSender
   */
  public FudgeMessageSender getNormalizedMessageSender() {
    return _normalizedMessageSender;
  }

  /**
   * Sets the normalizedMessageSender.
   * @param normalizedMessageSender  the normalizedMessageSender
   */
  public void setNormalizedMessageSender(FudgeMessageSender normalizedMessageSender) {
    _normalizedMessageSender = normalizedMessageSender;
  }

  /**
   * @param normalizationSchemes
   * @return
   */
  private Map<String, NormalizationRuleSet> constructNormalizationRules(String[] normalizationSchemes) {
    Map<String, NormalizationRuleSet> normalization = new TreeMap<String, NormalizationRuleSet>();
    for (String normalizationScheme : normalizationSchemes) {
      normalization.put(normalizationScheme, constructNormalizationRuleSet(normalizationScheme));
    }
    return normalization;
  }

  /**
   * @param normalizationScheme name of the scheme to be generated.
   * @return                    the rule set for that scheme.
   */
  protected abstract NormalizationRuleSet constructNormalizationRuleSet(String normalizationScheme);

  public void addDistribution(String uniqueIdentifier) {
    for (String normalizationScheme : _normalization.keySet()) {
      ensureLastKnownValueStore(ExternalId.of(_externalIdScheme, uniqueIdentifier), normalizationScheme);
    }
   
  }

  @Override
  public void start() {
    scanAllKeys();
  }

  @Override
  public void stop() {
  }

  @Override
  public boolean isRunning() {
    return false;
  }

  /**
   *
   */
  protected void scanAllKeys() {
    Set<String> allIdentifiers = null;
    try {
      allIdentifiers = _lastKnownValueStoreProvider.getAllIdentifiers(_externalIdScheme);
    } catch (UnsupportedOperationException uoe) {
      return;
    }
   
    for (String id: allIdentifiers) {
      for (String normalizationScheme : _normalization.keySet()) {
        ensureLastKnownValueStore(ExternalId.of(_externalIdScheme, id), normalizationScheme);
      }
    }
  }
 
  /**
   * Prepare the LKV store for the given specification and populate the normalization
   * state.
   *
   * @param id identifier for which to create store
   * @param normalizationScheme normalization scheme of store
   * @return The value store
   */
  protected LastKnownValueStore ensureLastKnownValueStore(ExternalId id, String normalizationScheme) {
    LastKnownValueStore lkvStore = _lastKnownValueStoreProvider.newInstance(id, normalizationScheme);
    LiveDataSpecification ldspec = new LiveDataSpecification(normalizationScheme, id);
    if (_valueStores.putIfAbsent(ldspec, lkvStore) == null) {
      s_logger.debug("Created new LKV store and history state for {}", ldspec);
      // We actually did the creation. Also create the field history map.
      FieldHistoryStore historyStore = new FieldHistoryStore(lkvStore.getFields());
      _normalizationState.put(ldspec, historyStore);
      return lkvStore;
    }
    return _valueStores.get(ldspec);
  }

  /**
   * Received raw, unnormalized values.
   * Will apply normalization, store results in the LKV store, and then rebroadcast
   * the normalized values.
   *
   * @param uniqueId  the identifier for the updates
   * @param fields    updated fields
   */
  public void updateReceived(String uniqueId, FudgeMsg fields) {
    updateReceived(ExternalId.of(_externalIdScheme, uniqueId), fields);
  }

  /**
   * Received raw, unnormalized values.
   * Will apply normalization, store results in the LKV store, and then rebroadcast
   * the normalized values.
   *
   * @param id     the identifier for the updates
   * @param fields updated fields
   */
  public void updateReceived(ExternalId id, FudgeMsg fields) {
    _tickMeter.mark();
    // Iterate over all normalization schemes.
    for (Map.Entry<String, NormalizationRuleSet> normalizationEntry : _normalization.entrySet()) {
      LiveDataSpecification ldspec = new LiveDataSpecification(normalizationEntry.getKey(), id);
      LastKnownValueStore lkvStore = ensureLastKnownValueStore(id, normalizationEntry.getKey());
     
      NormalizationRuleSet ruleSet = normalizationEntry.getValue();
      FudgeMsg normalizedFields = ruleSet.getNormalizedMessage(fields, id.getValue(), _normalizationState.get(ldspec));
     
      // If nothing to update, this returns null.
      if ((normalizedFields != null) && !normalizedFields.isEmpty()) {
        // update the LKV store
        lkvStore.updateFields(normalizedFields);
       
        // Blast them out.
        distributeNormalizedUpdate(ldspec, normalizedFields);
      }
    }
  }

  /**
   * Distribute results, after normalization and LKV storage, to downstream channels.
   *
   * @param ldspec           Specification of the data
   * @param normalizedFields Fully normalized field data for that specification
   */
  protected void distributeNormalizedUpdate(LiveDataSpecification ldspec, FudgeMsg normalizedFields) {
    if (getNormalizedMessageSender() == null) {
      // Nothing to do here.
      return;
    }
    FudgeSerializer serializer = new FudgeSerializer(getNormalizedMessageSender().getFudgeContext());
    LiveDataValueUpdateBean updateBean = new LiveDataValueUpdateBean(0, ldspec, normalizedFields);
    FudgeMsg msg = LiveDataValueUpdateBeanFudgeBuilder.toFudgeMsg(serializer, updateBean);
    getNormalizedMessageSender().send(msg);
  }
 
}
TOP

Related Classes of com.opengamma.livedata.cogda.server.CogdaDataDistributor

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.