There is API for Repeating Group in FIX Antenna Java 2.14. It allows to create, remove and modify Repeating Groups and their entries.
To use the Repeating Group API, you can pass the FIXFieldList instance to static method RawFIXUtil.indexRepeatingGroup. There are four implementations of this method:
public static FIXFieldList indexRepeatingGroup(FIXFieldList msg, FIXVersion version, String msgType, boolean validation)
public static FIXFieldList indexRepeatingGroup(FIXFieldList msg, FIXVersion version, String msgType)
public static FIXFieldList indexRepeatingGroup(FIXFieldList msg, boolean validation)
public static FIXFieldList indexRepeatingGroup(FIXFieldList msg)
All methods return the passed message. If you try to work with Repeating Group API without calling RawFIXUtil.indexRepeatingGroup, method indexRepeatingGroup(FIXFieldList msg) will be implicitly called, so you get indexed message with turned off validation.
There is two class for working with Repeating Group through api: RepeatingGroup and RepeatingGroup.Entry. RepeatingGroup contains methods for managing entries of Repeating Group. Entry contains methods for managing tags in concrete entry of RepeatingGroup and sub groups. By default, FIX Antenna uses instances of RepeatingGroup and RepeatingGroup.Entry from internal pool to reduce garbage production.
The first thing that you should know about RepeatingGroup API is pooling. Remember simple rule: if you got RepeatingGroup or Entry instance by calling method, that returns instance of group or entry, then there is no need in group.release()/entry.release - all groups and entries will come back to pool after call msg.releaseInstance. In other case, if you get group or entry buy explicit call RepeatingGroupPool.getEntry()/getRepeatingGroup() you should explicitly return group/entry object to pool by release method call.
There are two ways to get Repeating Group from indexed message:
FIXFieldList msg = RawFIXUtil.getFIXFieldList(executionReport.getBytes()); msg = RawFIXUtil.indexRepeatingGroup(msg, true); RepeatingGroup group = msg.getRepeatingGroup(FIX43.ExecutionReport.NoLegs); //Leading tag of Repeating Group //Some operations msg.releaseInstance();
FIXFieldList msg = RawFIXUtil.getFIXFieldList(executionReport.getBytes()); msg = RawFIXUtil.indexRepeatingGroup(msg, true); RepeatingGroup group = RepeatingGroupPool.getRepeatingGroup(); // Or new RepeatingGroup() or something else msg.getRepeatingGroup(FIX43.ExecutionReport.NoLegs, group); // Leading tag of Repeating Group //Some operations group.release();
If you try to get non-existent group, you get exception (if you call void method) or null value (if you call method which returns RepeatingGroup instance). There are safe methods (getOrAddRepeatingGroup()) which adds repeating group if it's doesn't exist.
After you get RepeatingGroup instance, you can get entries of this group. There are also two ways to get it:
FIXFieldList msg = RawFIXUtil.getFIXFieldList(executionReport.getBytes()); msg = RawFIXUtil.indexRepeatingGroup(msg, true); RepeatingGroup group = msg.getRepeatingGroup(FIX43.ExecutionReport.NoLegs); //Leading tag of Repeating Group RepeatingGroup.Entry entry = group.getEntry(0); //Number of entry in group //Some operations msg.releaseInstance();
FIXFieldList msg = RawFIXUtil.getFIXFieldList(executionReport.getBytes()); msg = RawFIXUtil.indexRepeatingGroup(msg, true); RepeatingGroup group = RepeatingGroupPool.getRepeatingGroup(); // Or new RepeatingGroup() or something else RepeatingGroup.Entry entry = RepeatingGroupPool.getEntry(); msg.getRepeatingGroup(FIX43.ExecutionReport.NoLegs, group); // Leading tag of Repeating Group group.getEntry(0, entry); //Number of entry in group //Some operations entry.release(); group.release();
You can get nested group using method Entry.getGroup():
FIXFieldList msg = RawFIXUtil.getFIXFieldList(executionReport.getBytes()); msg = RawFIXUtil.indexRepeatingGroup(msg, true); RepeatingGroup group = RepeatingGroupPool.getRepeatingGroup(); // Or new RepeatingGroup() or something else RepeatingGroup.Entry entry = RepeatingGroupPool.getEntry(); msg.getRepeatingGroup(FIX43.ExecutionReport.NoLegs, group); // Leading tag of Repeating Group group.getEntry(0, entry); //Number of entry in group RepeatingGroup subGroup = entry.getGroup(FIX43.ExecutionReport.InstrumentLeg.NoLegSecurityAltID); //Some operations entry.release(); msg.releaseInstance();
To create Repeating Group is used method addRepeatingGroupAtIndex:
FIXFieldList msg = RawFIXUtil.getFIXFieldList(executionReport.getBytes()); msg = RawFIXUtil.indexRepeatingGroup(msg, true); int repeatingGroupIndex = 20; //Index in message int leadingTag = FIX43.ExecutionReport.NoLegs; //Leading tag for group boolean validation = true; //Turn on validation RepeatingGroup group = msg.addRepeatingGroupAtIndex(repeatingGroupIndex, leadingTag, validation); //Some operations msg.releaseInstance();
Parameter repeatingGroupIndex is index of leading tag in FIX message. First tag have index = 0. Parameter validation enables or disables validation of group. Information about validation is below. Also you can add nested group to entry:
FIXFieldList msg = RawFIXUtil.getFIXFieldList(executionReport.getBytes()); msg = RawFIXUtil.indexRepeatingGroup(msg, true); RepeatingGroup group = RepeatingGroupPool.getRepeatingGroup(); // Or new RepeatingGroup() or something else RepeatingGroup.Entry entry = RepeatingGroupPool.getEntry(); msg.getRepeatingGroup(FIX43.ExecutionReport.NoLegs, group); // Leading tag of Repeating Group group.getEntry(0, entry); //Number of entry in group int leadingTag = FIX43.ExecutionReport.InstrumentLeg.NoLegSecurityAltID; boolean validation = true; RepeatingGroup subGroup = entry.addRepeatingGroup(FIX43.ExecutionReport.InstrumentLeg.NoLegSecurityAltID, validation); //Some operations entry.release(); group.release(); msg.releaseInstance();
Parameter 'validation' is optional for creating repeating group. In case if it is ommited, its value will be inherited from parent group.
To create new Entry is used method addEntry():
FIXFieldList msg = RawFIXUtil.getFIXFieldList(executionReport.getBytes()); msg = RawFIXUtil.indexRepeatingGroup(msg, true); RepeatingGroup group = RepeatingGroupPool.getRepeatingGroup(); // Or new RepeatingGroup() or something else RepeatingGroup.Entry entry = RepeatingGroupPool.getEntry(); msg.getRepeatingGroup(FIX43.ExecutionReport.NoLegs, group); // Leading tag of Repeating Group //Add at end Entry entry1 = group.addEntry() //Add at index. First index = 0 Entry entry2 = group.addEntry(1); entry.release(); group.release(); msg.releaseInstance();
If you pass index greater than current group size or less than zero, you will get IndexOutOfBoundsException.
There are few methods to remove entry from group:
group.remove(index); //remove entry by index entry.remove(); //remove current entry, but doesn't return it in pool group.remove(entry); //remove passed entry, but doesn't return it in pool
Leading tag of group is fully self-maintaining. You can't update it directly. Leading tag doesn't appear in message, until group is empty. Also, when group becomes empty, leading tag is removed from message.
FIXFieldList msg = new FIXFieldList(); msg.set(8, "FIX.4.4"); msg.set(35, "8"); msg.set(10, 123); RepeatingGroup group = msg.addRepeatingGroupAtIndex(555, 2); System.out.println(msg.toPrintableString()); //8=FIX.4.4 | 35=8 | 10=123 group is empty, so it doesn't show in message RepeatingGroup.Entry entry1 = msg.addEntry(); RepeatingGroup.Entry entry2 = msg.addEntry(); System.out.println(msg.toPrintableString()); //8=FIX.4.4 | 35=8 | 10=123 group have two entries now, but all entry is empty, so group still doesn't show in message System.out.println(group.getSize()); // Prints 2, method getSize returns number of all groups - empty and non empty System.out.println(group.getLeadingTagValue()); // Prints 0 entry1.addTag(600, "TBD"); System.out.println(msg.toPrintableString()); //8=FIX.4.4 | 35=8 | 555=1 | 600=TBD | 10=123 group appear in message. System.out.println(group.getSize()); // Prints 2 System.out.println(group.getLeadingTagValue()); // Prints 1 entry.removeTag(600); System.out.println(msg.toPrintableString()); //8=FIX.4.4 | 35=8 | 10=123 group is removed from message because there is no non-empty entries System.out.println(group.getSize()); // Prints 2, method getSize returns number of all groups - empty and non empty System.out.println(group.getLeadingTagValue()); // Prints 0
When we add two or more groups at the same place in message, the behavior is the same as when we add two tags in the same place in message:
FIXFieldList msg = new FIXFieldList(); msg.set(8, "FIX.4.4"); msg.set(35, "8"); msg.set(10, 123); RepeatingGroup group555 = msg.addRepeatingGroupAtIndex(555, 2); RepeatingGroup group454 = msg.addRepeatingGroupAtIndex(454, 2); //group 555 will appear right after group 454 group555.addEntry().addTag(600, "TBD"); System.out.println(msg.toPrintableString()); //8=FIX.4.4 | 35=8 | 555=1 | 600=TBD | 10=123 group454.addEntry().addTag(455, 5); System.out.println(msg.toPrintableString()); //8=FIX.4.4 | 35=8 | 454=1 | 455=5 | 555=1 | 600=TBD | 10=123 RepeatingGroup group = msg.addRepeatingGroup(555, 2);
Nested repeating groups also have self-maintained leading tags.
When we add two nested groups one by one, they will appear in the order of adding:
RepeatingGroup.Entry entry = group555.addEntry(); entry.addTag(600, "TBD"); RepeatingGroup group604 = entry.addRepeatingGroup(604); RepeatingGroup group539 = entry.addRepeatingGroup(539); System.out.println(msg.toPrintableString()); //8=FIX.4.4 | 35=8 | 454=1 | 455=5 | 555=1 | 600=TBD | 10=123 sub groups 604 and 539 is empty, so they doesn't show group539.addTag(524, "524val"); System.out.println(msg.toPrintableString()); //8=FIX.4.4 | 35=8 | 454=1 | 455=5 | 555=1 | 600=TBD | 525=1 | 524=524val | 10=123 group604.addTag(605, "605val"); System.out.println(msg.toPrintableString()); //8=FIX.4.4 | 35=8 | 454=1 | 455=5 | 555=1 | 600=TBD | 604=1 | 605=605val | 525=1 | 524=524val | 10=123
All methods, which works with index inside entry, like removeTagAtIndex, getTagValueAsXXXAtIndex doesn't work with empty groups:
RepeatingGroup.Entry entry = group555.addEntry(); entry.addTag(600, "TBD"); RepeatingGroup group604 = entry.addRepeatingGroup(604); entry.removeTagAtIndex(1); //returns false, because there is no any real tag at index 1 inside entry.
There is common interface for FIXFieldList and RepeatingGroup.Entry for add, get, update, remove operations on tags in entry:
TagList entry = group.getEntry(0);
entry.addTag(tag, tagValue);
entry.updateValue(tag, tagValue, missingTagHandling);
entry.removeTag(tag);
entry.getTagValueAsString(tag);
//And others
Validation of repeating groups is available during initial indexing of Repeating Group and during modification of Repeating Group.
During indexing there are such validations:
During modification of Repeating group there are such validations:
It is possible to copy repeating group and entry to other message or group. To copy repeating group from one FIX message to another, use method FIXFieldList.copyRepeatingGroup:
RepeatingGroup srcGroup = srcMsg.getRepeatingGroup(232);
RepeatingGroup copiedGroup = dstMsg.copyRepeatingGroup(srcGroup, 9); // group for copy and index where group will be inserted
To copy entry of repeating group to other group, use method RepeatingGroup.copyEntry:
RepeatingGroup groupForCopy = srcMsg.getRepeatingGroup(454); RepeatingGroup.Entry entryForCopy = groupForCopy.getEntry(1); RepeatingGroup targetGroup = dstMsg.getRepeatingGroup(454);
Entries can be copied to the same message or to another message.
To copy nested repeating group, use method Entry.copyRepeatingGroup:
RepeatingGroup groupForCopy = srcMsg.getRepeatingGroup(555).getEntry(0).getRepeatingGroup(539); RepeatingGroup.Entry targetEntry = dstMsg.getRepeatingGroup(555).getEntry(0); RepeatingGroup copiedGroup = targetEntry.copyRepeatingGroup(groupForCopy);
You can insert nested group in any entry or even in root of message without limitation
If you created FIXFieldList message from pool, call of releaseInstance() will return all RG instances and message itself to corresponding pools. In other case you should call method invalidateRepeatingGroupIndex() at the end of the work with Repeating Group API. Also, don't forget to call methods release() for RepeatingGroup.Entry and RepeatingGroup if you got it from pool explicitly.