/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.bbg.replay;
import static com.opengamma.bbg.replay.BloombergTick.BUID_KEY;
import static com.opengamma.bbg.replay.BloombergTick.RECEIVED_TS_KEY;
import static com.opengamma.bbg.replay.BloombergTickWriter.ALL_TICKS_FILENAME;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import org.fudgemsg.FudgeContext;
import org.fudgemsg.FudgeMsg;
import org.fudgemsg.wire.FudgeMsgReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.LocalDate;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.TerminatableJob;
import com.opengamma.util.time.DateUtils;
/**
*
*
* @author yomi
*/
public class TicksLoaderJob extends TerminatableJob {
/** Logger. */
private static final Logger s_logger = LoggerFactory.getLogger(TicksLoaderJob.class);
private static final FudgeContext s_fudgeContext = new FudgeContext();
private final String _rootDir;
private final Set<String> _securities;
private final BlockingQueue<FudgeMsg> _ticksQueue;
private final ZonedDateTime _startTime;
private final long _startTimeInEpochsMillis;
private final ZonedDateTime _endTime;
private final long _endTimeInEpochsMillis;
private final boolean _infiniteLoop;
private final List<String> _files = new ArrayList<String>();
public TicksLoaderJob(String rootDir, Set<String> securities,
BlockingQueue<FudgeMsg> ticksQueue, ZonedDateTime startTime, ZonedDateTime endTime, boolean infiniteLoop) {
ArgumentChecker.notNull(rootDir, "rootDir");
ArgumentChecker.notNull(securities, "securities");
ArgumentChecker.notNull(ticksQueue, "ticksQueue");
ArgumentChecker.notNull(startTime, "startTime");
ArgumentChecker.notNull(endTime, "endTime");
_rootDir = rootDir;
_securities = securities;
_ticksQueue = ticksQueue;
_startTime = startTime;
_startTimeInEpochsMillis = _startTime.toInstant().toEpochMilli();
_endTime = endTime;
_endTimeInEpochsMillis = _endTime.toInstant().toEpochMilli();
_infiniteLoop = infiniteLoop;
}
@Override
public void terminate() {
s_logger.debug("ticksLoader terminating...");
super.terminate();
}
/**
*
*/
private void sendTerminateMessage() {
try {
_ticksQueue.put(BloombergTickReplayUtils.getTerminateMessage());
} catch (InterruptedException e) {
Thread.interrupted();
s_logger.warn("interrupted while putting terminate message on queue");
}
}
@Override
protected void postRunCycle() {
sendTerminateMessage();
}
@Override
protected void runOneCycle() {
for (String fullPath : _files) {
if (fullPath == null) {
continue;
}
if (!loadTicks(fullPath)) {
// End already reached, so forget any remaining files
break;
}
}
if (!_infiniteLoop) {
terminate();
}
}
/**
* @param fullPath
* @return <code>true</code> if the end has been reached, <code>false</code> otherwise
*/
private boolean loadTicks(String fullPath) {
try {
FileInputStream fis = new FileInputStream(fullPath);
FudgeMsgReader reader = s_fudgeContext.createMessageReader(fis);
try {
while (reader.hasNext()) {
FudgeMsg message = reader.nextMessage();
String buid = message.getString(BUID_KEY);
if (afterEndTime(message)) {
return false;
}
boolean isRequestedSecurity = _securities.contains(buid) || _securities.isEmpty();
boolean isRequestedTime = withinRequestedTime(message);
if (isRequestedSecurity && isRequestedTime) {
try {
_ticksQueue.put(message);
} catch (InterruptedException e) {
Thread.interrupted();
s_logger.warn("interrupted waiting to write to ticks queue");
}
}
}
return true;
} finally {
try {
fis.close();
} catch (IOException e) {
s_logger.warn("cannot close {}", fullPath);
}
}
} catch (FileNotFoundException e) {
s_logger.warn("{} not found", fullPath);
throw new OpenGammaRuntimeException(fullPath + " not found", e);
}
}
/**
* @param message
* @return
*/
private boolean afterEndTime(FudgeMsg message) {
boolean result = false;
Long epochMillis = message.getLong(RECEIVED_TS_KEY);
if (epochMillis != null) {
result = epochMillis > _endTimeInEpochsMillis;
}
return result;
}
/**
* @param message
* @return
*/
private boolean withinRequestedTime(FudgeMsg message) {
boolean result = false;
Long epochMillis = message.getLong(RECEIVED_TS_KEY);
if (epochMillis != null) {
result = epochMillis >= _startTimeInEpochsMillis && epochMillis <= _endTimeInEpochsMillis;
}
return result;
}
@Override
protected void preStart() {
LocalDate startDate = _startTime.toLocalDate();
LocalDate endDate = _endTime.toLocalDate();
LocalDate current = endDate;
List<String> reverseOrder = new ArrayList<String>();
while (current.isAfter(startDate) || current.equals(startDate)) {
String fullPath = getFileNameFromDate(current);
File file = new File(fullPath);
if (file.exists()) {
reverseOrder.add(fullPath);
} else {
s_logger.warn("{} does not exists ", file);
}
current = DateUtils.previousWeekDay(current);
}
ListIterator<String> reverseIterator = reverseOrder.listIterator(reverseOrder.size());
while (reverseIterator.hasPrevious()) {
_files.add(reverseIterator.previous());
}
}
/**
* @param startDate
* @return
*/
private String getFileNameFromDate(LocalDate date) {
StringBuilder buf = new StringBuilder();
buf.append(_rootDir).append(File.separator).append(date.getYear()).append(File.separator);
int month = date.getMonthValue();
if (month < 10) {
buf.append("0").append(month);
} else {
buf.append(month);
}
buf.append(File.separator);
int dayOfMonth = date.getDayOfMonth();
if (dayOfMonth < 10) {
buf.append("0").append(dayOfMonth);
} else {
buf.append(dayOfMonth);
}
buf.append(File.separator).append(ALL_TICKS_FILENAME);
return buf.toString();
}
}