/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.bbg.replay;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import org.fudgemsg.FudgeMsg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.Lifecycle;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.TerminatableJob;
/**
*
*/
public class BloombergTicksReplayer implements Lifecycle {
/** Logger. */
private static Logger s_logger = LoggerFactory.getLogger(BloombergTicksReplayer.class);
private static final int DEFAULT_QUEUE_SIZE = 1000;
private final BloombergTickReceiver _bloombergTickReceiver;
private final String _rootDir;
private final BlockingQueue<FudgeMsg> _ticksQueue = new ArrayBlockingQueue<FudgeMsg>(DEFAULT_QUEUE_SIZE);
private final Mode _mode;
private final ZonedDateTime _startTime;
private final ZonedDateTime _endTime;
private final boolean _infiniteLoop;
private final Set<String> _securities;
private Thread _tickPlayerThread;
private TerminatableJob _ticksPlayerJob;
private Thread _ticksLoaderThread;
private TerminatableJob _ticksLoaderJob;
//exception thrown during replay
private Throwable _exception;
public BloombergTicksReplayer(Mode mode, String rootDir, BloombergTickReceiver bloombergTickReceiver, ZonedDateTime startTime, ZonedDateTime endTime) {
this(mode, rootDir, bloombergTickReceiver, startTime, endTime, false, Collections.<String>emptySet());
}
public BloombergTicksReplayer(Mode mode, String rootDir, BloombergTickReceiver bloombergTickReceiver, ZonedDateTime startTime, ZonedDateTime endTime, boolean infiniteLoop) {
this(mode, rootDir, bloombergTickReceiver, startTime, endTime, infiniteLoop, Collections.<String>emptySet());
}
public BloombergTicksReplayer(Mode mode, String rootDir, BloombergTickReceiver bloombergTickReceiver, ZonedDateTime startTime, ZonedDateTime endTime, Set<String> securities) {
this(mode, rootDir, bloombergTickReceiver, startTime, endTime, false, securities);
}
public BloombergTicksReplayer(Mode mode, String rootDir, BloombergTickReceiver bloombergTickReceiver, ZonedDateTime startTime, ZonedDateTime endTime, boolean infiniteLoop, Set<String> securities) {
ArgumentChecker.notNull(rootDir, "rootDir");
ArgumentChecker.notNull(bloombergTickReceiver, "tickHandler");
ArgumentChecker.notNull(mode, "mode");
ArgumentChecker.notNull(startTime, "startTime");
ArgumentChecker.notNull(endTime, "endTime");
ArgumentChecker.notNull(securities, "securities");
_mode = mode;
_rootDir = rootDir;
_bloombergTickReceiver = bloombergTickReceiver;
_startTime = startTime;
_endTime = endTime;
_infiniteLoop = infiniteLoop;
_securities = securities;
}
@Override
public synchronized boolean isRunning() {
s_logger.debug("isLoaderRunning {}", isLoaderRunning());
s_logger.debug("isPlayerRunning {}", isPlayerRunning());
return isLoaderRunning() && isPlayerRunning();
}
/**
* @return true if the player is running
*/
public boolean isPlayerRunning() {
return _tickPlayerThread != null && _tickPlayerThread.isAlive();
}
/**
* @return true if the loader is running
*/
public boolean isLoaderRunning() {
return _ticksLoaderThread != null && _ticksLoaderThread.isAlive();
}
@Override
public synchronized void start() {
startLoader();
//Wait for some ticks to process
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.interrupted();
s_logger.warn("interrupted from sleeping");
}
startPlayer();
}
/**
*
*/
private void startLoader() {
s_logger.info("starting ticksLoader-job");
TicksLoaderJob ticksLoaderJob = new TicksLoaderJob(_rootDir, _securities, _ticksQueue, _startTime, _endTime, _infiniteLoop);
_ticksLoaderJob = ticksLoaderJob;
Thread thread = new Thread(_ticksLoaderJob, "TicksLoader");
// thread.setDaemon(true);
thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
_exception = e;
s_logger.warn(e.getMessage(), e);
}
});
thread.start();
_ticksLoaderThread = thread;
}
/**
*
*/
private void startPlayer() {
s_logger.info("starting ticksPlayer-job");
TicksPlayerJob ticksPlayer = new TicksPlayerJob(_ticksQueue, _bloombergTickReceiver, _mode, _ticksLoaderThread);
_ticksPlayerJob = ticksPlayer;
Thread thread = new Thread(_ticksPlayerJob, "TicksPlayer");
// thread.setDaemon(true);
thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
_exception = e;
s_logger.warn(e.getMessage(), e);
}
});
thread.start();
_tickPlayerThread = thread;
}
@Override
public synchronized void stop() {
if (isLoaderRunning()) {
stopTerminatableJob(_ticksLoaderJob, _ticksLoaderThread);
}
if (isPlayerRunning()) {
stopTerminatableJob(_ticksPlayerJob, _tickPlayerThread);
}
}
private void stopTerminatableJob(TerminatableJob terminatableJob,
Thread thread) {
s_logger.debug("stopping {}", thread);
if (thread != null && thread.isAlive()) {
if (terminatableJob != null) {
terminatableJob.terminate();
}
try {
thread.join(1000); //wait for 1sec
} catch (InterruptedException e) {
Thread.interrupted();
s_logger.warn("Interrupted waiting for {} thread to finish", thread);
}
}
}
protected Throwable getException() {
return _exception;
}
/**
* An enumeration describing how to replay the ticks.
*/
public enum Mode {
/**
* Replay at the original latency.
*/
ORIGINAL_LATENCY,
/**
* Replay as fast as possible.
*/
AS_FAST_AS_POSSIBLE
}
}