Skip to content

Commit

Permalink
Provide methods in DataDictionary to get service and extension pack. (
Browse files Browse the repository at this point in the history
#383)

 - added basic support for FIX.Latest major version
  • Loading branch information
chrjohn committed Apr 20, 2021
1 parent 395cac3 commit 39909fe
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 11 deletions.
97 changes: 89 additions & 8 deletions quickfixj-core/src/main/java/quickfix/DataDictionary.java
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ private static Supplier<DocumentBuilderFactory> createDocumentBuilderFactorySupp
private boolean checkUnorderedGroupFields = true;
private boolean allowUnknownMessageFields = false;
private String beginString;
private String fullVersion;
private String majorVersion;
private int minorVersion;
private int extensionPack;
private int servicePack;
private final Map<String, Set<Integer>> messageFields = new HashMap<>();
private final Map<String, Set<Integer>> requiredFields = new HashMap<>();
private final Set<String> messages = new HashSet<>();
Expand Down Expand Up @@ -171,14 +176,57 @@ private void setVersion(String beginString) {
}

/**
* Get the FIX version associated with this dictionary.
*
* Get the FIX major/minor version associated with this dictionary.
* E.g. FIX.5.0
* @return the FIX version
*/
public String getVersion() {
return beginString;
}

private void setFullVersion(String fullVersion) {
this.fullVersion = fullVersion;
}

/**
* Get the FIX major/minor/SP/EP version associated with this dictionary.
* E.g. FIX.5.0.SP2_EP260
* @return the full FIX version
*/
public String getFullVersion() {
return fullVersion;
}

/**
* @return the ExtensionPack (EP), 0 if it is undefined.
*/
public int getExtensionPack() {
return extensionPack;
}

/**
* @return the ServicePack (SP), 0 if it is undefined.
*/
public int getServicePack() {
return servicePack;
}

/**
* @return the minor FIX version, 0 if it is undefined.
*/
public int getMinorVersion() {
return minorVersion;
}

/**
* NOTE: this is of type String to cover the "Latest" case.
*
* @return the major FIX version
*/
public String getMajorVersion() {
return majorVersion;
}

private void addField(int field) {
fields.add(field);
}
Expand Down Expand Up @@ -568,6 +616,11 @@ public void setAllowUnknownMessageFields(boolean allowUnknownFields) {
private void copyFrom(DataDictionary rhs) {
hasVersion = rhs.hasVersion;
beginString = rhs.beginString;
fullVersion = rhs.fullVersion;
majorVersion = rhs.majorVersion;
minorVersion = rhs.minorVersion;
extensionPack = rhs.extensionPack;
servicePack = rhs.servicePack;

copyMap(messageFields, rhs.messageFields);
copyMap(requiredFields, rhs.requiredFields);
Expand Down Expand Up @@ -939,16 +992,35 @@ private void load(InputStream inputStream, DocumentBuilderFactory factory) throw
throw new ConfigError("major attribute not found on <fix>");
}

if (!documentElement.hasAttribute("minor")) {
throw new ConfigError("minor attribute not found on <fix>");
}
majorVersion = documentElement.getAttribute("major");
minorVersion = getIntegerAttributeIfDefined(documentElement, "minor");
servicePack = getIntegerAttributeIfDefined(documentElement, "servicepack");
extensionPack = getIntegerAttributeIfDefined(documentElement, "extensionpack");

final String dictionaryType = documentElement.hasAttribute("type") ? documentElement
.getAttribute("type") : FIX_PREFIX;

setVersion(dictionaryType + "." + documentElement.getAttribute("major") + "."
+ documentElement.getAttribute("minor"));

if (FixVersions.LATEST.equals(majorVersion)) {
String version = dictionaryType + "." + majorVersion;
setVersion(version);
String fullVersion = version;
if (extensionPack > 0) {
fullVersion = fullVersion + "_EP" + extensionPack;
}
setFullVersion(fullVersion);
} else {
String version = dictionaryType + "." + majorVersion + "." + minorVersion;
setVersion(version);
String fullVersion = version;
if (servicePack > 0) {
fullVersion = fullVersion + "SP" + servicePack;
}
if (extensionPack > 0) {
fullVersion = fullVersion + "_EP" + extensionPack;
}
setFullVersion(fullVersion);
}

// Index Components
final NodeList componentsNode = documentElement.getElementsByTagName("components");
if (componentsNode.getLength() > 0) {
Expand Down Expand Up @@ -1082,6 +1154,15 @@ private void load(InputStream inputStream, DocumentBuilderFactory factory) throw
calculateOrderedFields();
}

private int getIntegerAttributeIfDefined(final Element documentElement, final String attribute) throws ConfigError {
try {
return documentElement.hasAttribute(attribute)
? Integer.valueOf(documentElement.getAttribute(attribute)) : 0;
} catch (NumberFormatException e) {
throw new ConfigError("Attribute " + attribute + " could not be parsed as Integer.", e);
}
}

public int getNumMessageCategories() {
return messageCategory.size();
}
Expand Down
7 changes: 5 additions & 2 deletions quickfixj-core/src/main/java/quickfix/FixVersions.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,15 @@ public interface FixVersions {
String BEGINSTRING_FIX43 = "FIX.4.3";
String BEGINSTRING_FIX44 = "FIX.4.4";

/**
* FIX 5.0 does not have a begin string.
/*
* FIX 5.0+ does not have a begin string.
*/
String FIX50 = "FIX.5.0";
String FIX50SP1 = "FIX.5.0SP1";
String FIX50SP2 = "FIX.5.0SP2";

String LATEST = "Latest";
String FIXLATEST = "FIX." + LATEST;

// FIXT.x.x support

Expand Down
83 changes: 82 additions & 1 deletion quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,7 @@ protected void execute() throws Throwable {
// If bodyOnly is true, the correct data dictionary is not checked.
dd.validate(newSingle, true);
}

// QF C++ treats the string argument as a filename although it's
// named 'url'. QFJ string argument can be either but this test
// ensures the DD works correctly with a regular file path.
Expand Down Expand Up @@ -1412,6 +1412,87 @@ public void shouldFailToLoadDictionaryWhenExternalDTDisDisabled() {
assertEquals("External DTD: Failed to read external DTD 'mathml.dtd', because 'http' access is not allowed due to restriction set by the accessExternalDTD property.", e.getCause().getCause().getMessage());
}
}

/**
* For FIX.Latest a minor version is not required.
*/
@Test
public void testMissingMinorVersion() throws Exception {
String data = "";
data += "<fix major=\"5\">";
data = getCommonDataDictionaryString(data);

DataDictionary dataDictionary = new DataDictionary(new ByteArrayInputStream(data.getBytes()));
assertEquals(0, dataDictionary.getMinorVersion());
}

@Test
public void testFixLatestMajorVersion() throws Exception {
String data = "";
data += "<fix major=\"Latest\">";
data = getCommonDataDictionaryString(data);

DataDictionary dataDictionary = new DataDictionary(new ByteArrayInputStream(data.getBytes()));
assertEquals(0, dataDictionary.getMinorVersion());
assertEquals("FIX.Latest", dataDictionary.getFullVersion());
}

@Test
public void testFixLatestMajorVersionAndEP() throws Exception {
String data = "";
data += "<fix major=\"Latest\" extensionpack=\"260\">";
data = getCommonDataDictionaryString(data);

DataDictionary dataDictionary = new DataDictionary(new ByteArrayInputStream(data.getBytes()));
assertEquals(0, dataDictionary.getMinorVersion());
assertEquals("FIX.Latest_EP260", dataDictionary.getFullVersion());
}

@Test
public void testSP() throws Exception {
String data = "";
data += "<fix major=\"5\" minor=\"0\" servicepack=\"2\">";
data = getCommonDataDictionaryString(data);

DataDictionary dataDictionary = new DataDictionary(new ByteArrayInputStream(data.getBytes()));
assertEquals(0, dataDictionary.getMinorVersion());
assertEquals("FIX.5.0", dataDictionary.getVersion());
assertEquals("FIX.5.0SP2", dataDictionary.getFullVersion());
}

@Test
public void testEPAndSP() throws Exception {
String data = "";
data += "<fix major=\"5\" minor=\"0\" extensionpack=\"260\" servicepack=\"2\">";
data = getCommonDataDictionaryString(data);

DataDictionary dataDictionary = new DataDictionary(new ByteArrayInputStream(data.getBytes()));
assertEquals(0, dataDictionary.getMinorVersion());
assertEquals("FIX.5.0", dataDictionary.getVersion());
assertEquals("FIX.5.0SP2_EP260", dataDictionary.getFullVersion());
}

private String getCommonDataDictionaryString(String data) {
data += " <header>";
data += " <field name=\"BeginString\" required=\"Y\"/>";
data += " </header>";
data += " <trailer>";
data += " <field name=\"CheckSum\" required=\"Y\"/>";
data += " </trailer>";
data += " <fields>";
data += " <field number=\"8\" name=\"BeginString\" type=\"STRING\"/>";
data += " <field number=\"10\" name=\"CheckSum\" type=\"STRING\"/>";
data += " <field number=\"112\" name=\"TestReqID\" type=\"STRING\"/>";
data += " </fields>";
data += " <messages>";
data += " <message name=\"Heartbeat\" msgtype=\"0\" msgcat=\"admin\">";
data += " <field name=\"TestReqID\" required=\"N\"/>";
data += " </message>";
data += " </messages>";
data += "</fix>";
return data;
}


//
// Group Validation Tests in RepeatingGroupTest
Expand Down

0 comments on commit 39909fe

Please sign in to comment.