package org.gfix.parser;
public class ValidatingValidator implements FixMessageValidator
{
public static final int FIX_VERSION = 8;
public static final String FIX_VERSION_VALUE = "FIX";
public static final int FIX_MESSAGE_LENTGH = 9;
public static final int FIX_MESSAGE_TYPE = 35;
public static final int FIX_CHECK_SUM = 10;
private static final Rule[] firstTagRules = new Rule[]{
new Tag8MustBeFirstRule(),
new Tag9MustBeSecondRule(),
new Tag35MustBeThirdRule()
};
private int length;
boolean startedMessage;
private int numberOfTagsSeen;
private int bytesSeen;
private int sumOfBytesSeen;
private ValidatingValidator(){init();}
@Override
public FixParseFault validate(int tag, String contents)
{
// generate the checksum
if(tag != FIX_CHECK_SUM)
{
// the tag itself
for(byte b : String.valueOf(tag).getBytes())
{
sumOfBytesSeen += b;
}
sumOfBytesSeen += FixParser.FIX_CONTENT;
for(byte b : String.valueOf(contents).getBytes())
{
sumOfBytesSeen += b;
}
// the delimiter
sumOfBytesSeen += FixParser.FIX_DELIMITER;
}
if(numberOfTagsSeen < firstTagRules.length)
{
FixParseFault fault = firstTagRules[numberOfTagsSeen].validate(tag, contents);
if(fault != null)
{
return fault;
}
}
numberOfTagsSeen++;
switch(tag)
{
case FIX_VERSION:
{
if(startedMessage)
{
return new FixParseFault(tag,"Fix version already supplied",
-1,contents,FixParseFault.Serverity.ERROR);
}
startedMessage = true;
if(contents == null || contents.length() == 0)
{
return new FixParseFault(tag,"Fix version must be supplied",
-1,contents,FixParseFault.Serverity.ERROR);
}
else if(!contents.startsWith(FIX_VERSION_VALUE))
{
return new FixParseFault(tag,"Fix version does not start with fix",
-1,contents,FixParseFault.Serverity.WARNING);
}
break;
}
case FIX_MESSAGE_LENTGH:
{
if(length!= -1)
{
return new FixParseFault(tag,"Message length already supplied",
-1,contents,FixParseFault.Serverity.ERROR);
}
try
{
length = Integer.valueOf(contents);
}
catch(NumberFormatException nfe)
{
return new FixParseFault(tag,"Message length supplied was not a number",
-1,contents,FixParseFault.Serverity.ERROR);
}
break;
}
case FIX_CHECK_SUM:
{
//first check the length against the claimed length
if(bytesSeen != length)
{
return new FixParseFault(tag,"Message length supplied was not a correct",
-1,contents,FixParseFault.Serverity.ERROR);
}
// check the checksum
int calculated = sumOfBytesSeen % 256;
try
{
int givenChecksum = Integer.valueOf(contents);
init();
if(calculated != givenChecksum)
{
return new FixParseFault(tag,"Message checksum supplied was not a the same as the calculated: " + calculated,
-1,contents,FixParseFault.Serverity.ERROR);
}
}
catch(NumberFormatException nfe)
{
return new FixParseFault(tag,"Message checksum supplied was not a number",
-1,contents,FixParseFault.Serverity.ERROR);
}
// this message is done reset the sucker;
init();
break;
}
default:
bytesSeen += String.valueOf(tag).getBytes().length + contents.getBytes().length + 2;
break;
}
return null;
}
private void init()
{
length = -1;
startedMessage = false;
numberOfTagsSeen = 0;
bytesSeen = 0;
sumOfBytesSeen = 0;
}
private static interface Rule
{
FixParseFault validate(int tag, String contents);
}
private static class Tag8MustBeFirstRule implements Rule
{
public FixParseFault validate(int tag, String contents)
{
if( tag != FIX_VERSION)
{
return new FixParseFault(tag,"Fix messages must start with 8=",
-1,contents,FixParseFault.Serverity.ERROR);
}
return null;
}
}
private static class Tag9MustBeSecondRule implements Rule
{
public FixParseFault validate(int tag, String contents)
{
if( tag != FIX_MESSAGE_LENTGH)
{
return new FixParseFault(tag,"Fix messages must contain 9=XX as the second tag",
-1,contents,FixParseFault.Serverity.WARNING);
}
return null;
}
}
private static class Tag35MustBeThirdRule implements Rule
{
public FixParseFault validate(int tag, String contents)
{
if( tag != FIX_MESSAGE_TYPE)
{
return new FixParseFault(tag,"Fix messages must contain 35=XX as the third tag",
-1,contents,FixParseFault.Serverity.WARNING);
}
return null;
}
}
public static class Factory implements FixMessageValidatorFactory
{
public FixMessageValidator getFixMessageValidator()
{
return new ValidatingValidator();
}
}
}
|