There is a FIX Engine requirement that session listener can't perform time-consuming task. This sample shows how to use message queue and single thread to perform time-consuming tasks outside session listener. This approach is also known as “Producer-Consumer design pattern”.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | import biz.onixs.fix.dictionary.Version; import biz.onixs.fix.engine.Engine; import biz.onixs.fix.engine.Session; import biz.onixs.fix.parser.Group; import biz.onixs.fix.parser.Message; import biz.onixs.fix.tag.FIX50; import biz.onixs.fix.tag.Tag; import biz.onixs.util.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class MessageQueueRunner implements Session.InboundApplicationMessageListener { private static final Logger LOG = LoggerFactory.getLogger(MessageQueueRunner. class ); private static final int MSG_NUM = 5 ; private final BlockingQueue<Message> messageQueue = new LinkedBlockingQueue<>(); private final MessageProcessor messageProcessor = new MessageProcessor(messageQueue); public void run() { Engine.init(- 1 ); messageProcessor.start(); // Emulating inbound application message event LOG.info( "Messages to process: " + MSG_NUM); for ( int i = 0 ; MSG_NUM > i; i++) { final Message message = createDemoMessage(i); final Session.InboundApplicationMessageArgs args = new Session.InboundApplicationMessageArgs(message); onInboundApplicationMessage( this , args); } Utils.waitForEnterToTerminateApp(); messageProcessor.stop(); Engine.getInstance().shutdown(); } @Override public void onInboundApplicationMessage( final Object sender, final Session.InboundApplicationMessageArgs args) { try { messageQueue.put(args.getMsg()); } catch ( final InterruptedException e) { LOG.error( "Error adding message to processing queue: {}" , args.getMsg(), e); } } private static Message createDemoMessage( final int i) { final Message newsMessage = Message.create(FIX50.MsgType.News, Version.FIX50); newsMessage.set(Tag.Headline, "Headline " + i); final Group linesOfTextGrp = newsMessage.setGroup(Tag.LinesOfText, 1 ); linesOfTextGrp.set(Tag.Text, 0 , "Text " + i); return newsMessage; } public static void main( final String[] args) { try { final MessageQueueRunner messageQueueRunner = new MessageQueueRunner(); messageQueueRunner.run(); } catch ( final Throwable throwable) { LOG.error(throwable.getMessage(), throwable); } } } |
The following class is used in the sample:
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | import biz.onixs.fix.parser.Message; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.BlockingQueue; public class MessageProcessor implements Runnable { private static final Logger LOG = LoggerFactory.getLogger(MessageProcessor. class ); private static final long PROCESSING_PAUSE = 1L; private final BlockingQueue<Message> messageQueue; private Thread thread = null ; private boolean running = true ; public MessageProcessor( final BlockingQueue<Message> messageQueue) { this .messageQueue = messageQueue; } public void start() { thread = new Thread( this , "MessageProcessor" ); thread.start(); } public void stop() { running = false ; if (!thread.isInterrupted()) { thread.interrupt(); } } public void run() { LOG.info( "MessageProcessor thread started." ); while (running) { LOG.info( "MessageProcessor is checking for messages..." ); try { final Message message = messageQueue.take(); if (running) { process(message); } } catch ( final InterruptedException ignored) { } } LOG.info( "MessageProcessor thread stopped." ); } private static void process( final Message message) throws InterruptedException { LOG.info( "Processing message for {} secs: {}" , PROCESSING_PAUSE, message); Thread.sleep(PROCESSING_PAUSE * 1000L); // time-consuming logic goes here LOG.info( "Processed." ); } } |
There is a FIX Engine requirement that session listener can't perform time-consuming task.This sample shows how to use standard thread pool to perform time-consuming tasks outside session listener.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | import biz.onixs.fix.dictionary.Version; import biz.onixs.fix.engine.Engine; import biz.onixs.fix.engine.Session; import biz.onixs.fix.parser.Group; import biz.onixs.fix.parser.Message; import biz.onixs.fix.tag.FIX50; import biz.onixs.fix.tag.Tag; import biz.onixs.util.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ExecutorRunner implements Session.InboundApplicationMessageListener { private static final Logger LOG = LoggerFactory.getLogger(ExecutorRunner. class ); private static final int MSG_NUM = 5 ; private static final int THREAD_POOL_SIZE = 2 ; private final ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE); public void run() { Engine.init(- 1 ); // Emulating inbound application message event LOG.info( "Messages to process: " + MSG_NUM); for ( int i = 0 ; 5 > i; i++) { final Message message = createDemoMessage(i); final Session.InboundApplicationMessageArgs args = new Session.InboundApplicationMessageArgs(message); onInboundApplicationMessage( this , args); } Utils.waitForEnterToTerminateApp(); executorService.shutdownNow(); Engine.getInstance().shutdown(); } @Override public void onInboundApplicationMessage( final Object sender, final Session.InboundApplicationMessageArgs args) { executorService.submit( new MessageProcessingTask(args.getMsg())); } private static Message createDemoMessage( final int i) { final Message newsMessage = Message.create(FIX50.MsgType.News, Version.FIX50); newsMessage.set(Tag.Headline, "Headline " + i); final Group linesOfTextGrp = newsMessage.setGroup(Tag.LinesOfText, 1 ); linesOfTextGrp.set(Tag.Text, 0 , "Text " + i); return newsMessage; } public static void main( final String[] args) { try { final ExecutorRunner executorRunner = new ExecutorRunner(); executorRunner.run(); } catch ( final Throwable throwable) { LOG.error(throwable.getMessage(), throwable); } } } |
The following class is used in the sample:
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | import biz.onixs.fix.parser.Message; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MessageProcessingTask implements Runnable { private static final Logger LOG = LoggerFactory.getLogger(MessageProcessingTask. class ); private static final int PROCESSING_PAUSE = 1 ; private final Message message; public MessageProcessingTask( final Message message) { this .message = message; } public void run() { LOG.info( "{}: processing message for {} secs: {}" , Thread.currentThread(), PROCESSING_PAUSE, message); // time-consuming logic goes here try { Thread.sleep(( long ) (PROCESSING_PAUSE * 1000 )); LOG.info( "{}: message processed." , Thread.currentThread()); } catch ( final InterruptedException ignored) { } } } |
This sample app demonstrates how to access FIX messages in file session storage.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | import biz.onixs.fix.dictionary.Version; import biz.onixs.fix.engine.Engine; import biz.onixs.fix.engine.EngineSettings; import biz.onixs.fix.engine.SessionId; import biz.onixs.fix.engine.storage.SessionStorage; import biz.onixs.fix.engine.storage.StorageRepository; import biz.onixs.fix.engine.storage.StorageRepositoryManager; import biz.onixs.fix.parser.FixMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class StorageReader { private static final Logger LOG = LoggerFactory.getLogger(StorageReader. class ); private final Version fixVersion = Version.FIX40; public static void main( final String[] args) { final StorageReader storageReader = new StorageReader(); storageReader.run(); } private void run() { try { final EngineSettings engineSettings = new EngineSettings(); engineSettings.setStorageFolder( "conf/sample/storage" ); Engine.init(engineSettings); final StorageRepositoryManager storageRepositoryManager = Engine.getInstance().getStorageRepositoryManager(); final StorageRepository storageRepository = storageRepositoryManager.getFileStorageRepository(); final SessionId sessionId = new SessionId( "BuySide" , "SellSide" , fixVersion); LOG.info( "sessionId={}" , sessionId); final SessionStorage sessionStorage = storageRepository.create(sessionId, false ); LOG.info( "sessionStorage.getId()='{}'" , sessionStorage.getId()); processStorage(sessionStorage); sessionStorage.close( false ); } catch ( final RuntimeException e) { LOG.error(e.getMessage().replace( "\r" , "\\r" ), e); } finally { if (Engine.isInited()) Engine.getInstance().shutdown(); } } private static void processStorage( final SessionStorage sessionStorage) { LOG.info( "Getting outgoing messages..." ); final long outSeqNum = sessionStorage.getOutSeqNum(); if (0L == outSeqNum) { LOG.info( "No outgoing messages found in the storage." ); } else { final List<FixMessage> msgs = sessionStorage.getOutboundMessages(1L, outSeqNum); for ( final FixMessage msg : msgs) { processMessage(msg); } } } private static void processMessage( final FixMessage message) { LOG.info( "message='{}'" , message); } } |
This sample app demonstrates how to iterate over all Message fields.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | import biz.onixs.fix.dictionary.Version; import biz.onixs.fix.engine.Engine; import biz.onixs.fix.parser.Field; import biz.onixs.fix.parser.FixBlock; import biz.onixs.fix.parser.Group; import biz.onixs.fix.parser.GroupInstance; import biz.onixs.fix.parser.Message; import biz.onixs.fix.tag.FIX50; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MessageFieldsIteration { private static final Logger LOG = LoggerFactory.getLogger(MessageFieldsIteration. class ); private void run() { Engine.init(- 1 ); final Message msg = createMessageWithNestedRepeatingGroups(); iterateOverMessageFields(msg); Engine.getInstance().shutdown(); } private void iterateOverMessageFields( final Message msg) { iterateOverFixBlockFields(msg, "" ); } private void iterateOverFixBlockFields( final FixBlock fixBlock, final String prefix) { for ( final Field fld : fixBlock) { LOG.info( "{}{}" + '=' + "{}" , prefix, fld.getTag(), fld.get()); if (fixBlock.hasGroup(fld.getTag())) { final Group group = fixBlock.getGroup(fld.getTag()); iterateOverGroupInstances(group, prefix); } } } private void iterateOverGroupInstances( final Group group, final String prefix) { for ( final GroupInstance grpInstance : group) { iterateOverFixBlockFields(grpInstance, prefix + " " ); } } private static Message createMessageWithNestedRepeatingGroups() { final Message msg = Message.create(FIX50.MsgType.NewOrderSingle, Version.FIX50); final int CustomTag = 10000 ; msg.set(CustomTag, "CustomTag" ); // Create the repeating group. final Group partiesGroup = msg.setGroup(FIX50.Tag.NoPartyIDs, 3 ); // Set the given field in all group instances of the repeating group. int i = 0 ; for ( final GroupInstance grpInstance : partiesGroup ) { grpInstance.set(FIX50.Tag.PartyID, "value" + i++); } // Create the nested repeating group. final Group partiesSubGroup = partiesGroup.setGroup(FIX50.Tag.NoPartySubIDs, 0 , 6 ); // Set the given field in all group instances of the nested repeating group. i = 0 ; for ( final GroupInstance grpInstance : partiesSubGroup) { grpInstance.set(FIX50.Tag.PartySubID, "value" + i++); } // LOG.info( "Message with nested repeating group: {}" , msg); // return msg; } public static void main( final String[] args) { try { LOG.info( "Message Fields Iteration" ); LOG.info( "The application is starting..." ); final MessageFieldsIteration iteration = new MessageFieldsIteration(); iteration.run(); } catch ( final Throwable throwable) { LOG.error(throwable.getMessage(), throwable); } finally { LOG.info( "The application is stopped." ); } } } |
This sample app demonstrates how to convert Fix message to JSON or XML format.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | import biz.onixs.fix.dictionary.Version; import biz.onixs.fix.engine.Engine; import biz.onixs.fix.fixml.Utils; import biz.onixs.fix.parser.Message; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; public class ConverterRunner { private static final Logger LOG = LoggerFactory.getLogger(ConverterRunner. class ); public void run() throws IOException { Engine.init(); // final String inFixFile = "sample.converter/MarketDataRequest.txt" ; LOG.info( "Loading FIX message from file: {}" , inFixFile); final Message inFixMessage = Utils.readFixMessage(inFixFile); LOG.info( "Input FIX message: \n{}" , inFixMessage); // final MessageToJSONConverter fix2Json = new MessageToJSONConverter(Version.FIX44); final String jsonMessage = fix2Json.apply(inFixMessage); LOG.info( "Output converted JSON message: {}{}" , System.lineSeparator(), jsonMessage); LOG.info( "Output converted out of box JSON message: {}{}" , System.lineSeparator(), inFixMessage.toJson()); // final MessageToXMLConverter fix2Xml = new MessageToXMLConverter(Version.FIX44); final String xmlMessage = fix2Xml.apply(inFixMessage); LOG.info( "Output converted XML message: {}{}" , System.lineSeparator(), xmlMessage); LOG.info( "Output converted out of box XML message: {}{}" , System.lineSeparator(), inFixMessage.toXml()); // Engine.getInstance().shutdown(); } public static void main( final String[] args) { try { final ConverterRunner converterRunner = new ConverterRunner(); converterRunner.run(); } catch ( final Throwable throwable) { LOG.error(throwable.getMessage(), throwable); } } } |
The following classes are used in the sample:
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | import biz.onixs.fix.dictionary.ContainerDefinition; import biz.onixs.fix.dictionary.Dictionary; import biz.onixs.fix.dictionary.DictionaryManager; import biz.onixs.fix.dictionary.FieldDefinition; import biz.onixs.fix.dictionary.GroupDefinition; import biz.onixs.fix.dictionary.MessageDefinition; import biz.onixs.fix.dictionary.Version; import biz.onixs.fix.parser.Field; import biz.onixs.fix.parser.FixBlock; import biz.onixs.fix.parser.Group; import biz.onixs.fix.parser.GroupInstance; import biz.onixs.fix.parser.Message; import biz.onixs.util.ValuePtr; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.function.Function; public class MessageToJSONConverter implements Function<Message, String> { private static final String PREFIX = " " ; private static final String SPACES = System.lineSeparator() + " \t" ; //List of the Header tags according to the FIX5.0SP2 specification private static final Integer[] header = { 8 , 9 , 35 , 49 , 56 , 115 , 128 , 90 , 91 , 34 , 50 , 142 , 57 , 143 , 116 , 144 , 129 , 145 , 43 , 97 , 52 , 122 , 212 , 213 , 347 , 369 , 1128 , 1129 , 1156 , 627 , 628 , 629 , 630 }; private static final Collection<Integer> headerTags = new HashSet<>(Arrays.asList(header)); //List of the Trailer tags according to the FIX5.0SP2 specification private static final Integer[] trailer = { 93 , 89 , 10 }; private static final Collection<Integer> trailerTags = new HashSet<>(Arrays.asList(trailer)); private final Dictionary dictionary; MessageToJSONConverter( final Version fixVersion) { dictionary = DictionaryManager.getDictionary(fixVersion); } public static String info() { return "Info" ; } @Override public String apply( final Message message) { final StringBuilder strBdr = new StringBuilder(); final MessageDefinition msgDef = dictionary.get( new ValuePtr(message.getType())); messageToJson(message, msgDef, strBdr); return strBdr.toString(); } private static StringBuilder deleteLastCommaIfPresent( final StringBuilder bdr) { for ( int i = bdr.length() - 1 ; 0 <= i; i--) { final char c = bdr.charAt(i); if ( 0 > SPACES.indexOf(c)) { if ( ',' == c) { return bdr.deleteCharAt(i); } else { break ; } } } return bdr; } private static void messageToJson( final FixBlock msg, final MessageDefinition def, final StringBuilder strBdr) { final StringBuilder headerBdr = new StringBuilder(PREFIX + "\"Header\": {" + System.lineSeparator()); final StringBuilder bodyBdr = new StringBuilder(PREFIX + "\"Body\": {" + System.lineSeparator()); final StringBuilder trailerBdr = new StringBuilder(PREFIX + "\"Trailer\": {" + System.lineSeparator()); for ( final Field fld : msg) { final int tag = fld.getTag(); final StringBuilder curBdr = headerTags.contains(tag) ? headerBdr : (trailerTags.contains(tag) ? trailerBdr : bodyBdr); fieldToJson(msg, def, fld, curBdr, PREFIX); curBdr.append( "," ).append(System.lineSeparator()); } deleteLastCommaIfPresent(headerBdr).append(PREFIX).append( "}," ).append(System.lineSeparator()); deleteLastCommaIfPresent(bodyBdr).append(PREFIX).append( "}," ).append(System.lineSeparator()); deleteLastCommaIfPresent(trailerBdr).append(PREFIX).append( "}" ).append(System.lineSeparator()); strBdr.append( "{" ).append(System.lineSeparator()); strBdr.append(headerBdr); strBdr.append(bodyBdr); strBdr.append(trailerBdr); strBdr.append( "}" ); } private static void fixBlockToJson( final FixBlock fixBlk, final ContainerDefinition def, final StringBuilder strBdr, final String prefix) { strBdr.append(prefix).append( "{" ).append(System.lineSeparator()); for ( final Iterator<Field> iterator = fixBlk.iterator(); iterator.hasNext(); ) { final Field fld = iterator.next(); fieldToJson(fixBlk, def, fld, strBdr, prefix); trailingComma(strBdr, iterator.hasNext()); } strBdr.append(prefix).append( "}" ); } private static void fieldToJson( final FixBlock fixBlk, final ContainerDefinition def, final Field fld, final StringBuilder strBdr, final String prefix) { final int tag = fld.getTag(); final FieldDefinition fldDef = def.getFieldByTag(tag); if (fldDef.isGroupDefined()) { final Group grp = fixBlk.getGroup(tag); if ( null != grp) { groupToJson(grp, fldDef, strBdr, prefix + PREFIX); } } else { final String name = getFieldName(fldDef); final String value = fld.get(); strBdr.append(prefix).append(PREFIX).append( "\"" ).append(name).append( "\": \"" ).append(value).append( "\"" ); } } private static void groupToJson( final Iterable<GroupInstance> grp, final FieldDefinition leadingFldDef, final StringBuilder strBdr, final String prefix) { final String name = getFieldName(leadingFldDef); strBdr.append(prefix).append( "\"" ).append(name).append( "\": [" ).append(System.lineSeparator()); final GroupDefinition grpDef = leadingFldDef.getGroupDefinition(); for ( final Iterator<GroupInstance> it = grp.iterator(); it.hasNext(); ) { final GroupInstance grpInst = it.next(); fixBlockToJson(grpInst, grpDef, strBdr, prefix); trailingComma(strBdr, it.hasNext()); } strBdr.append(prefix).append( "]" ); } private static void trailingComma( final StringBuilder strBdr, final boolean isCommaRequired) { if (isCommaRequired) { strBdr.append( "," ); } strBdr.append(System.lineSeparator()); } private static String getFieldName( final FieldDefinition def) { return ( null != def.getTagNameBytes()) ? new String(def.getTagNameBytes(), StandardCharsets.UTF_8) : "undefined" ; } } |
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | import biz.onixs.fix.dictionary.ContainerDefinition; import biz.onixs.fix.dictionary.Dictionary; import biz.onixs.fix.dictionary.DictionaryManager; import biz.onixs.fix.dictionary.FieldDefinition; import biz.onixs.fix.dictionary.GroupDefinition; import biz.onixs.fix.dictionary.MessageDefinition; import biz.onixs.fix.dictionary.Version; import biz.onixs.fix.parser.Field; import biz.onixs.fix.parser.FixBlock; import biz.onixs.fix.parser.Group; import biz.onixs.fix.parser.GroupInstance; import biz.onixs.fix.parser.Message; import biz.onixs.util.ValuePtr; import java.nio.charset.StandardCharsets; import java.util.function.Function; public class MessageToXMLConverter implements Function<Message, String> { private static final String PREFIX = " " ; private final Dictionary dictionary; MessageToXMLConverter( final Version fixVersion) { dictionary = DictionaryManager.getDictionary(fixVersion); } @Override public String apply( final Message message) { final StringBuilder strBdr = new StringBuilder( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" ); strBdr.append(System.lineSeparator()).append(System.lineSeparator()); strBdr.append( "<XML>" ).append(System.lineSeparator()); final MessageDefinition msgDef = dictionary.get( new ValuePtr(message.getType())); strBdr.append(PREFIX).append( "<message name=\"" ).append(msgDef.getMsgName()).append( "\"/>" ); strBdr.append(System.lineSeparator()); fixBlock2xml(message, msgDef, strBdr, PREFIX + PREFIX); strBdr.append(PREFIX).append( "</message>" ).append(System.lineSeparator()); strBdr.append( "</XML>" ); return strBdr.toString(); } private static void fixBlock2xml( final FixBlock fixBlk, final ContainerDefinition def, final StringBuilder strBdr, final String prefix) { for ( final Field fld : fixBlk) { final int tag = fld.getTag(); final FieldDefinition fldDef = def.getFieldByTag(tag); if (fldDef.isGroupDefined()) { final Group grp = fixBlk.getGroup(tag); if ( null != grp) { group2xml(grp, fldDef, strBdr, prefix); } } else { final String name = getFieldName(fldDef); final String value = fld.get(); strBdr.append(prefix).append( "<field name=\"" ).append(name).append( "\" tag=\"" ).append(tag) .append( "\" value=\"" ).append(value).append( "\"/>" ).append(System.lineSeparator()); } } } private static void group2xml( final Group grp, final FieldDefinition leadingFldDef, final StringBuilder strBdr, final String prefix) { final String name = getFieldName(leadingFldDef); final int tag = leadingFldDef.getTag(); final int numberOfInstances = grp.getNumberOfInstances(); strBdr.append(prefix).append( "<group name=\"" ).append(name).append( "\" tag=\"" ).append(tag) .append( "\" numberofinstances=\"" ).append(numberOfInstances) .append( "\">" ).append(System.lineSeparator()); final GroupDefinition grpDef = leadingFldDef.getGroupDefinition(); int index = 0 ; for ( final GroupInstance grpInst : grp) { groupInstance2xml(grpInst, index++, grpDef, strBdr, prefix + PREFIX); } strBdr.append(prefix).append( "</group>" ).append(System.lineSeparator()); } private static void groupInstance2xml( final FixBlock grpInst, final int index, final ContainerDefinition def, final StringBuilder strBdr, final String prefix) { strBdr.append(prefix).append( "<instance index=\"" ).append(index).append( "\">" ).append(System.lineSeparator()); fixBlock2xml(grpInst, def, strBdr, prefix + PREFIX); strBdr.append(prefix).append( "</instance>" ).append(System.lineSeparator()); } private static String getFieldName( final FieldDefinition def) { return ( null != def.getTagNameBytes()) ? new String(def.getTagNameBytes(), StandardCharsets.UTF_8) : Integer.toString(def.getTag()); } } |