/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.bbg.livedata;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.fudgemsg.FudgeContext;
import org.fudgemsg.mapping.FudgeSerializer;
import org.fudgemsg.wire.FudgeMsgWriter;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.bbg.referencedata.ReferenceData;
import com.opengamma.bbg.referencedata.ReferenceDataProvider;
import com.opengamma.bbg.referencedata.ReferenceDataProviderGetRequest;
import com.opengamma.bbg.referencedata.ReferenceDataProviderGetResult;
import com.opengamma.bbg.referencedata.impl.AbstractReferenceDataProvider;
import com.opengamma.util.ArgumentChecker;
/**
* Decorates a reference data provider, storing the data to a flat file.
* <p>
* The request and response data is written to the file incrementally.
* The intention is for this decorator to be used for a period while certain reference data
* requests are made, such as when a view starts being processed. Subsequently the data file
* can replace the 'real' source of reference data for the same requests.
* The file is stored using Fudge.
* See {@link LoggedReferenceDataProvider} for a reference data provider that reads the file.
*/
public class LoggingReferenceDataProvider extends AbstractReferenceDataProvider {
/**
* The underlying reference data provider.
*/
private final ReferenceDataProvider _underlying;
/**
* The store of data already written to file.
*/
private final ConcurrentMap<String, Set<String>> _alreadyLogged = new ConcurrentHashMap<String, Set<String>>();
/**
* The Fudge context.
*/
private final FudgeContext _fudgeContext;
/**
* The Fudge message writer.
*/
private final FudgeMsgWriter _fudgeMsgWriter;
/**
* Creates an instance.
*
* @param underlying the underlying reference data provider, not null
* @param fudgeContext the Fudge context, not null
* @param outputFile the file to write to, not null
*/
public LoggingReferenceDataProvider(ReferenceDataProvider underlying, FudgeContext fudgeContext, File outputFile) {
ArgumentChecker.notNull(underlying, "underlying");
ArgumentChecker.notNull(fudgeContext, "fudgeContext");
ArgumentChecker.notNull(outputFile, "outputFile");
_underlying = underlying;
_fudgeContext = fudgeContext;
try {
FileOutputStream fos = new FileOutputStream(outputFile);
BufferedOutputStream bos = new BufferedOutputStream(fos, 4096);
_fudgeMsgWriter = fudgeContext.createMessageWriter(bos);
} catch (FileNotFoundException ex) {
throw new OpenGammaRuntimeException("Cannot open " + outputFile + " for writing");
}
}
//-------------------------------------------------------------------------
@Override
protected ReferenceDataProviderGetResult doBulkGet(ReferenceDataProviderGetRequest request) {
ReferenceDataProviderGetResult result = _underlying.getReferenceData(request);
processResult(result, request.getFields());
return result;
}
private void processResult(ReferenceDataProviderGetResult result, Set<String> fields) {
for (ReferenceData refData : result.getReferenceData()) {
String identifier = refData.getIdentifier();
Set<String> freshFieldsLogged = new HashSet<String>();
Set<String> fieldsLogged = _alreadyLogged.putIfAbsent(identifier, freshFieldsLogged);
if (fieldsLogged == null) {
fieldsLogged = freshFieldsLogged;
}
synchronized (fieldsLogged) {
for (String field : fields) {
if (fieldsLogged.contains(field) == false) {
Object value = refData.getFieldValues().getValue(field);
log(identifier, field, value);
}
}
}
}
}
private void log(String securityKey, String field, Object value) {
LoggedReferenceData loggedReferenceData = new LoggedReferenceData(securityKey, field, value);
_fudgeMsgWriter.writeMessage(loggedReferenceData.toFudgeMsg(new FudgeSerializer(_fudgeContext)));
_fudgeMsgWriter.flush();
}
}