/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.livedata.firehose;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.Lifecycle;
import com.opengamma.util.ArgumentChecker;
/**
* The primary class that holds the state for a live running chunking process.
* Unlike other classes in this hierarchy, a chunker is defined as a process that
* continuously runs to process records in a thread compliant fashion, rather than
* a pull-through fashion (which might be useful in a testing context).
*
* @param <TRecord> The type of the actual record that will be processed.
*/
public class FireHoseRecordProcessor<TRecord> implements Lifecycle {
private static final Logger s_logger = LoggerFactory.getLogger(FireHoseRecordProcessor.class);
/**
* The non-blocking size of the internal queue.
* The actual size here was chosen without any particular rationale, and
* may not be correct.
*/
public static final int QUEUE_CAPACITY = 5000;
/**
* Added to the queue when the end of the input stream has been reached.
*/
public static final Object EOF_INDICATOR = new Object();
// --------------------------------------------------------------------------
// INJECTED HELPERS
// --------------------------------------------------------------------------
private final InputStreamFactory _inputStreamFactory;
private final RecordStream.Factory<TRecord> _recordStreamFactory;
private final RecordProcessor<TRecord> _recordProcessor;
// --------------------------------------------------------------------------
// RUNNING STATE
// --------------------------------------------------------------------------
private final BlockingQueue<Object> _queue = new LinkedBlockingQueue<Object>(QUEUE_CAPACITY);
private final RecordConsumptionJob _recordConsumptionJob;
private final RecordProcessingJob _recordProcessingJob;
private Thread _recordConsumptionThread;
private Thread _recordDispatchThread;
public FireHoseRecordProcessor(
InputStreamFactory inputStreamFactory,
RecordStream.Factory<TRecord> recordStreamFactory,
RecordProcessor<TRecord> recordProcessor) {
ArgumentChecker.notNull(inputStreamFactory, "inputStreamFactory");
ArgumentChecker.notNull(recordStreamFactory, "recordStreamFactory");
ArgumentChecker.notNull(recordProcessor, "recordProcessor");
_inputStreamFactory = inputStreamFactory;
_recordStreamFactory = recordStreamFactory;
_recordProcessor = recordProcessor;
_recordConsumptionJob = new RecordConsumptionJob(_inputStreamFactory, _recordStreamFactory, _queue);
_recordProcessingJob = new RecordProcessingJob(_queue, _recordProcessor);
}
protected RecordStream.Factory<TRecord> getRecordStreamFactory() {
return _recordStreamFactory;
}
// --------------------------------------------------------------------------
// SPRING LIFECYCLE METHODS
// --------------------------------------------------------------------------
@Override
public synchronized void start() {
if (isRunning()) {
return;
}
_recordConsumptionThread = new Thread(_recordConsumptionJob, "FireHoseRecordProcessor Consumption");
// Is this the right value?
_recordConsumptionThread.setDaemon(false);
_recordConsumptionThread.start();
_recordDispatchThread = new Thread(_recordProcessingJob, "FireHoseRecordProcessor Dispatch");
// Is this the right value?
_recordDispatchThread.setDaemon(false);
_recordDispatchThread.start();
}
@Override
public synchronized void stop() {
try {
_recordConsumptionJob.terminate();
_recordConsumptionThread.join(10000L);
} catch (InterruptedException e) {
Thread.interrupted();
s_logger.warn("Interrupted while killing record consumption thread", e);
}
_recordConsumptionThread = null;
try {
_recordProcessingJob.terminate();
_recordDispatchThread.join(10000L);
} catch (InterruptedException e) {
Thread.interrupted();
s_logger.warn("Interrupted while killing record processing/dispatch thread", e);
}
_recordDispatchThread = null;
}
@Override
public synchronized boolean isRunning() {
if ((_recordConsumptionThread != null)
&& _recordConsumptionThread.isAlive()
&& (_recordDispatchThread != null)
&& _recordDispatchThread.isAlive()) {
return true;
}
return false;
}
}