Package com.opengamma.livedata.server.distribution

Source Code of com.opengamma.livedata.server.distribution.JmsSender

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

import java.util.concurrent.Semaphore;

import javax.jms.BytesMessage;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;

import org.fudgemsg.FudgeContext;
import org.fudgemsg.FudgeMsg;
import org.fudgemsg.mapping.FudgeSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.core.MessageCreator;

import com.opengamma.livedata.LiveDataValueUpdateBean;
import com.opengamma.livedata.LiveDataValueUpdateBeanFudgeBuilder;
import com.opengamma.livedata.server.DistributionSpecification;
import com.opengamma.livedata.server.FieldHistoryStore;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.jms.JmsConnector;

/**
* This {@link MarketDataSender} sends market data to JMS.
* <p>
* When the sender loses connection to JMS, it starts building a
* cumulative delta of changes. This cumulative delta is published when
* the sender reconnects.
*/
public class JmsSender implements MarketDataSender {

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

  /**
   * The JMS connector.
   */
  private final JmsConnector _jmsConnector;
  /**
   * The Fudge context.
   */
  private final FudgeContext _fudgeContext;
  /**
   * The distributor.
   */
  private final MarketDataDistributor _distributor;
  /**
   * The field value history.
   */
  private final FieldHistoryStore _cumulativeDelta = new FieldHistoryStore();
  /**
   * The last sequence number.
   */
  private long _lastSequenceNumber;
  /**
   * Whether the sender is interrupted.
   */
  private volatile boolean _interrupted;
  /**
   * The internal lock.
   */
  private final Semaphore _lock = new Semaphore(1);

  /**
   * Creates an instance.
   *
   * @param jmsConnector  the JMS connector, not null
   * @param distributor  the distributor, not null
   * @param fudgeContext  the Fudge context, not null
   */
  public JmsSender(JmsConnector jmsConnector, MarketDataDistributor distributor, FudgeContext fudgeContext) {
    ArgumentChecker.notNull(jmsConnector, "jmsConnector");
    ArgumentChecker.notNull(distributor, "Market data distributor");
    ArgumentChecker.notNull(fudgeContext, "fudgeContext");
    _jmsConnector = jmsConnector;
    _fudgeContext = fudgeContext;
    _distributor = distributor;
  }

  //-------------------------------------------------------------------------
  @Override
  public MarketDataDistributor getDistributor() {
    return _distributor;
  }

  //-------------------------------------------------------------------------
  @Override
  public void sendMarketData(LiveDataValueUpdateBean data) {
    _lock.acquireUninterruptibly();
    try {
      _cumulativeDelta.liveDataReceived(data.getFields());
      _lastSequenceNumber = data.getSequenceNumber();
     
      if (_interrupted) {
        s_logger.debug("{}: Interrupted - not sending message", this);
        return;
      }
     
      send();
    } finally {
      _lock.release();
    }
  }

  private void send() {
    DistributionSpecification distributionSpec = getDistributor().getDistributionSpec();
   
    LiveDataValueUpdateBean liveDataValueUpdateBean = new LiveDataValueUpdateBean(
        _lastSequenceNumber,
        distributionSpec.getFullyQualifiedLiveDataSpecification(),
        _cumulativeDelta.getLastKnownValues());
    s_logger.debug("{}: Sending Live Data update {}", this, liveDataValueUpdateBean);
   
    FudgeMsg fudgeMsg = LiveDataValueUpdateBeanFudgeBuilder.toFudgeMsg(new FudgeSerializer(_fudgeContext), liveDataValueUpdateBean);
    String destinationName = distributionSpec.getJmsTopic();
    final byte[] bytes = _fudgeContext.toByteArray(fudgeMsg);
   
    _jmsConnector.getJmsTemplateTopic().send(destinationName, new MessageCreator() {
      @Override
      public Message createMessage(Session session) throws JMSException {
        // TODO kirk 2009-10-30 -- We want to put stuff in the properties as well I think.
        BytesMessage bytesMessage = session.createBytesMessage();
        bytesMessage.writeBytes(bytes);
        return bytesMessage;
      }
    });
   
    _cumulativeDelta.clear();
  }

  //-------------------------------------------------------------------------
  /**
   * Checks if the sender is interrupted.
   *
   * @return true if interrupted
   */
  public boolean isInterrupted() {
    return _interrupted;
  }

  /**
   * Indicates that the transport was interrupted, setting the flag.
   */
  public void transportInterrupted() {
    s_logger.error("Transport interrupted {}", this);
    _interrupted = true;
  }

  /**
   * Marks the sender as active again to stop batching up pending messages, and triggers a send
   * if a send is not already active. Note that it is not safe to call this method from the JMS
   * invoked transportResume message. For example ActiveMQ holds a lock to do an initial 'send'
   * and then gains a lock for the failover while another thread holds the lock for the failover
   * as it calls the notifications so sending will cause deadlock.
   */
  public void transportResumed() {
    s_logger.info("Transport resumed {}", this);
    _interrupted = false;
    // tryAcquire() is used to avoid re-entry to the send method if a sendMarketData is already
    // active as that will hold the semaphore.
    if (_lock.tryAcquire()) {
      try {
        if (!_cumulativeDelta.isEmpty()) {
          send();
        }
      } catch (RuntimeException e) {
        s_logger.error("transportResumed() failed", e);
      } finally {
        _lock.release();
      }
    }
  }

  @Override
  public String toString() {
    return "JmsSender[" + _distributor.getDistributionSpec().toString() "]";   
  }

}
TOP

Related Classes of com.opengamma.livedata.server.distribution.JmsSender

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.