package org.marketcetera.quickfix;
import java.util.ArrayList;
import java.util.List;
import org.marketcetera.core.CoreException;
import org.marketcetera.marketdata.DataRequestTranslator;
import org.marketcetera.trade.Equity;
import org.marketcetera.util.log.SLF4JLoggerProxy;
import org.marketcetera.util.misc.ClassVersion;
import quickfix.FieldNotFound;
import quickfix.Group;
import quickfix.Message;
import quickfix.field.MsgType;
import quickfix.field.NoRelatedSym;
import quickfix.field.NoUnderlyings;
import quickfix.field.SecurityType;
import quickfix.field.SubscriptionRequestType;
import quickfix.field.Symbol;
import quickfix.field.UnderlyingSymbol;
/**
* Common routines for {@link DataRequestTranslator} implementations.
*
* <p>This class hierarchy translates <em>QuickFIX</em> messages to
* other formats. This class specifically provides common routines to
* parse a <em>QuickFIX</em> message.
*
* @author <a href="mailto:colin@marketcetera.com">Colin DuPlantis</a>
* @version $Id: AbstractMessageTranslator.java 16841 2014-02-20 19:59:04Z colin $
* @since 0.5.0
*/
@ClassVersion("$Id: AbstractMessageTranslator.java 16841 2014-02-20 19:59:04Z colin $")
public abstract class AbstractMessageTranslator<T>
{
/**
* Indicates what FIX version to use
*/
public static final FIXVersion sMessageVersion = FIXVersion.FIX44;
/**
* Indicates what FIX factory to use
*/
public static final FIXMessageFactory sMessageFactory = sMessageVersion.getMessageFactory();
/**
* Gets the <code>Symbol</code> specified in the given <code>Group</code>.
*
* @param inGroup a <code>Group</code> value
* @return an <code>Equity</code> value containing the symbol
* @throws CoreException if the symbol could not be extracted
*/
public static Equity getSymbol(Group inGroup)
throws CoreException
{
String securityType;
try {
securityType = inGroup.getString(SecurityType.FIELD);
} catch (FieldNotFound e) {
securityType = SecurityType.COMMON_STOCK;
}
Equity symbol;
try {
if(SecurityType.OPTION.equals(securityType) &&
inGroup.isSetField(NoUnderlyings.FIELD)) {
Group underlyingGroup = sMessageFactory.createGroup(MsgType.MARKET_DATA_REQUEST,
NoUnderlyings.FIELD);
inGroup.getGroup(1,
underlyingGroup);
symbol = new Equity(underlyingGroup.getString(UnderlyingSymbol.FIELD));
} else {
symbol = new Equity(inGroup.getString(Symbol.FIELD));
}
} catch (FieldNotFound e) {
throw new CoreException(e,
org.marketcetera.marketdata.Messages.ERROR_MARKET_DATA_FEED_CANNOT_FIND_SYMBOL);
}
return symbol;
}
/**
* Get all the {@link Group} objects associated with the given <code>Message</code>.
*
* @param inMessage a <code>Message</code> value
* @return a <code>List<Group></code> value
* @throws CoreException
*/
public static List<Group> getGroups(Message inMessage)
throws CoreException
{
int totalSymbols = AbstractMessageTranslator.determineTotalSymbols(inMessage);
List<Group> groups = new ArrayList<Group>();
// the message header is valid, make a best effort to parse each group, discarding as few as possible
for (int symbolCounter=1;symbolCounter<=totalSymbols;symbolCounter++) {
try {
Group relatedSymGroup = sMessageFactory.createGroup(MsgType.MARKET_DATA_REQUEST,
NoRelatedSym.FIELD);
inMessage.getGroup(symbolCounter,
relatedSymGroup);
// relatedSymGroup is a chunk in the message that encapsulates the Symbol
// securityType now holds a description of the symbol (fix tag 167)
groups.add(relatedSymGroup);
} catch (Throwable e) {
SLF4JLoggerProxy.debug(AbstractMessageTranslator.class, e, Messages.GROUP_NUMBER_COULD_NOT_TRANSLATE.getText(symbolCounter));
}
}
return groups;
}
/**
* Retrieves the subscription type from the given message.
*
* @param inMessage a <code>Message</code> value
* @return a <code>char</code> value
*/
public static char determineSubscriptionRequestType(Message inMessage)
{
try {
return inMessage.getChar(SubscriptionRequestType.FIELD);
} catch (FieldNotFound e) {
org.marketcetera.marketdata.Messages.WARNING_MARKET_DATA_FEED_CANNOT_DETERMINE_SUBSCRIPTION.warn(AbstractMessageTranslator.class, e);
return SubscriptionRequestType.SNAPSHOT;
}
}
/**
* Retrieves the total number of symbols in the given message.
*
* @param inMessage a <code>Message</code> value
* @return an <code>int</code> value
* @throws CoreException if the number of symbols could not be determined
*/
public static int determineTotalSymbols(Message inMessage)
throws CoreException
{
try {
return inMessage.getInt(NoRelatedSym.FIELD);
} catch (FieldNotFound e) {
throw new CoreException(e);
}
}
}