Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 33 additions & 15 deletions quickfixj-core/src/main/java/quickfix/DataDictionary.java
Original file line number Diff line number Diff line change
Expand Up @@ -518,11 +518,6 @@ public void setAllowUnknownMessageFields(boolean allowUnknownFields) {
private void copyFrom(DataDictionary rhs) {
hasVersion = rhs.hasVersion;
beginString = rhs.beginString;
checkFieldsOutOfOrder = rhs.checkFieldsOutOfOrder;
checkFieldsHaveValues = rhs.checkFieldsHaveValues;
checkUserDefinedFields = rhs.checkUserDefinedFields;
checkUnorderedGroupFields = rhs.checkUnorderedGroupFields;
allowUnknownMessageFields = rhs.allowUnknownMessageFields;

copyMap(messageFields, rhs.messageFields);
copyMap(requiredFields, rhs.requiredFields);
Expand All @@ -533,8 +528,14 @@ private void copyFrom(DataDictionary rhs) {
copyMap(fieldNames, rhs.fieldNames);
copyMap(names, rhs.names);
copyMap(valueNames, rhs.valueNames);
copyMap(groups, rhs.groups);
copyGroups(groups, rhs.groups);
copyMap(components, rhs.components);

setCheckFieldsOutOfOrder(rhs.checkFieldsOutOfOrder);
setCheckFieldsHaveValues(rhs.checkFieldsHaveValues);
setCheckUserDefinedFields(rhs.checkUserDefinedFields);
setCheckUnorderedGroupFields(rhs.checkUnorderedGroupFields);
setAllowUnknownMessageFields(rhs.allowUnknownMessageFields);
}

@SuppressWarnings("unchecked")
Expand All @@ -558,13 +559,26 @@ private static <K, V> void copyMap(Map<K, V> lhs, Map<K, V> rhs) {
}
}

/** copy groups including their data dictionaries and validation settings
*
* @param lhs target
* @param rhs source
*/
private static void copyGroups(Map<IntStringPair, GroupInfo> lhs, Map<IntStringPair, GroupInfo> rhs) {
lhs.clear();
for (Map.Entry<IntStringPair, GroupInfo> entry : rhs.entrySet()) {
GroupInfo value = new GroupInfo(entry.getValue().getDelimiterField(), new DataDictionary(entry.getValue().getDataDictionary()));
lhs.put(entry.getKey(), value);
}
}

private static <V> void copyCollection(Collection<V> lhs, Collection<V> rhs) {
lhs.clear();
lhs.addAll(rhs);
}

/**
* Validate a mesasge, including the header and trailer fields.
* Validate a message, including the header and trailer fields.
*
* @param message the message
* @throws IncorrectTagValue if a field value is not valid
Expand Down Expand Up @@ -674,23 +688,27 @@ void checkValidTagNumber(Field<?> field) {
void checkField(Field<?> field, String msgType, boolean message) {
// use different validation for groups and messages
boolean messageField = message ? isMsgField(msgType, field.getField()) : fields.contains(field.getField());
boolean fail;

if (field.getField() < USER_DEFINED_TAG_MIN) {
fail = !messageField && !allowUnknownMessageFields;
} else {
fail = !messageField && checkUserDefinedFields;
}
boolean fail = checkFieldFailure(field.getField(), messageField);

if (fail) {
if (fields.contains(field.getTag())) {
if (fields.contains(field.getField())) {
throw new FieldException(SessionRejectReason.TAG_NOT_DEFINED_FOR_THIS_MESSAGE_TYPE, field.getField());
} else {
throw new FieldException(SessionRejectReason.INVALID_TAG_NUMBER, field.getField());
}
}
}

boolean checkFieldFailure(int field, boolean messageField) {
boolean fail;
if (field < USER_DEFINED_TAG_MIN) {
fail = !messageField && !allowUnknownMessageFields;
} else {
fail = !messageField && checkUserDefinedFields;
}
return fail;
}

private void checkValidFormat(StringField field) throws IncorrectDataFormat {
FieldType fieldType = getFieldType(field.getTag());
if (fieldType == null) {
Expand Down
35 changes: 24 additions & 11 deletions quickfixj-core/src/main/java/quickfix/Message.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ public class Message extends FieldMap {
protected Header header = new Header();
protected Trailer trailer = new Trailer();

// @GuardedBy("this")
private FieldException exception;
private volatile FieldException exception;

public Message() {
// empty
Expand Down Expand Up @@ -510,7 +509,7 @@ && isNextField(dd, header, BodyLength.FIELD)
header.setField(field);

if (dd != null && dd.isGroup(DataDictionary.HEADER_ID, field.getField())) {
parseGroup(DataDictionary.HEADER_ID, field, dd, header);
parseGroup(DataDictionary.HEADER_ID, field, dd, header, doValidation);
}

field = extractField(dd, header);
Expand Down Expand Up @@ -549,7 +548,7 @@ private void parseBody(DataDictionary dd, boolean doValidation) throws InvalidMe
setField(header, field);
// Group case
if (dd != null && dd.isGroup(DataDictionary.HEADER_ID, field.getField())) {
parseGroup(DataDictionary.HEADER_ID, field, dd, header);
parseGroup(DataDictionary.HEADER_ID, field, dd, header, doValidation);
}
if (doValidation && dd != null && dd.isCheckFieldsOutOfOrder())
throw new FieldException(SessionRejectReason.TAG_SPECIFIED_OUT_OF_REQUIRED_ORDER,
Expand All @@ -558,7 +557,7 @@ private void parseBody(DataDictionary dd, boolean doValidation) throws InvalidMe
setField(this, field);
// Group case
if (dd != null && dd.isGroup(getMsgType(), field.getField())) {
parseGroup(getMsgType(), field, dd, this);
parseGroup(getMsgType(), field, dd, this, doValidation);
}
}

Expand All @@ -573,7 +572,7 @@ private void setField(FieldMap fields, StringField field) {
fields.setField(field);
}

private void parseGroup(String msgType, StringField field, DataDictionary dd, FieldMap parent)
private void parseGroup(String msgType, StringField field, DataDictionary dd, FieldMap parent, boolean doValidation)
throws InvalidMessage {
final DataDictionary.GroupInfo rg = dd.getGroup(msgType, field.getField());
final DataDictionary groupDataDictionary = rg.getDataDictionary();
Expand Down Expand Up @@ -603,14 +602,14 @@ private void parseGroup(String msgType, StringField field, DataDictionary dd, Fi
previousOffset = -1;
// QFJ-742
if (groupDataDictionary.isGroup(msgType, tag)) {
parseGroup(msgType, field, groupDataDictionary, group);
parseGroup(msgType, field, groupDataDictionary, group, doValidation);
}
} else if (groupDataDictionary.isGroup(msgType, tag)) {
if (!firstFieldFound) {
throw new InvalidMessage("The group " + groupCountTag
+ " must set the delimiter field " + firstField + " in " + messageData);
}
parseGroup(msgType, field, groupDataDictionary, group);
parseGroup(msgType, field, groupDataDictionary, group, doValidation);
} else if (groupDataDictionary.isField(tag)) {
if (!firstFieldFound) {
throw new FieldException(
Expand All @@ -629,6 +628,20 @@ private void parseGroup(String msgType, StringField field, DataDictionary dd, Fi
}
group.setField(field);
} else {
// QFJ-169/QFJ-791: handle unknown repeating group fields in the body
if (!(DataDictionary.HEADER_ID.equals(msgType))) {
if (!isTrailerField(tag) && !dd.isMsgField(msgType, tag)) {
if (doValidation) {
boolean fail = dd.checkFieldFailure(tag, false);
if (fail) {
throw new FieldException(
SessionRejectReason.TAG_NOT_DEFINED_FOR_THIS_MESSAGE_TYPE, tag);
}
}
group.setField(field);
continue;
}
}
pushBack(field);
inGroupParse = false;
}
Expand Down Expand Up @@ -790,11 +803,11 @@ private StringField extractField(DataDictionary dataDictionary, FieldMap fields)
*
* @return flag indicating whether the message has a valid structure
*/
synchronized boolean hasValidStructure() {
boolean hasValidStructure() {
return exception == null;
}

public synchronized FieldException getException() {
public FieldException getException() {
return exception;
}

Expand All @@ -804,7 +817,7 @@ public synchronized FieldException getException() {
*
* @return the first invalid tag
*/
synchronized int getInvalidTag() {
int getInvalidTag() {
return exception != null ? exception.getField() : 0;
}

Expand Down
11 changes: 11 additions & 0 deletions quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import quickfix.field.MsgSeqNum;
import quickfix.field.MsgType;
import quickfix.field.NoHops;
import quickfix.field.NoPartyIDs;
import quickfix.field.NoRelatedSym;
import quickfix.field.OrdType;
import quickfix.field.OrderQty;
Expand Down Expand Up @@ -476,6 +477,16 @@ public void testCopy() throws Exception {
assertEquals(ddCopy.isCheckUnorderedGroupFields(),dataDictionary.isCheckUnorderedGroupFields());
assertEquals(ddCopy.isCheckUserDefinedFields(),dataDictionary.isCheckUserDefinedFields());

DataDictionary.GroupInfo groupFromDDCopy = ddCopy.getGroup(NewOrderSingle.MSGTYPE, NoPartyIDs.FIELD);
assertTrue(groupFromDDCopy.getDataDictionary().isAllowUnknownMessageFields());
// set to false on ORIGINAL DD
dataDictionary.setAllowUnknownMessageFields(false);
assertFalse(dataDictionary.isAllowUnknownMessageFields());
assertFalse(dataDictionary.getGroup(NewOrderSingle.MSGTYPE, NoPartyIDs.FIELD).getDataDictionary().isAllowUnknownMessageFields());
// should be still true on COPIED DD and its group
assertTrue(ddCopy.isAllowUnknownMessageFields());
groupFromDDCopy = ddCopy.getGroup(NewOrderSingle.MSGTYPE, NoPartyIDs.FIELD);
assertTrue(groupFromDDCopy.getDataDictionary().isAllowUnknownMessageFields());
}

/**
Expand Down
Loading