Skip to content

QFJ Type Safe messaging

Baoying Wang edited this page Nov 23, 2017 · 1 revision

What's type safe messaging?

As mentioned in http://www.quickfixj.org/quickfixj/usermanual/1.6.4/usage/sending_messages.html and http://www.quickfixj.org/quickfixj/usermanual/1.6.4/usage/receiving_messages.html, QFJ support several levels message sending/receiving.

  • Least type safe - use FIX tag number directly
Message message = new Message();
e.g. message.getStringFiled(41);
e.g. message.setField(41, "uniqID_01010xxx");
  • More type safe - use type safe field class
Message message = new Message();
e.g. message.getField(new ClOrdID());
e.g. message.setField(new OrigClOrdID("uniqID_01010xxx"));
  • Most type safe - use type safe message class See the sample code at sending_messages.html and receiving_messages.html Although it is recommended by QFJ official document, many constraints here. Please read below sections. I personally don't recommend it, if you use multi dictionaries.

note: to use #2 - type safe field class, or #3 type safe message class, you have to translate the FIX dictionary to java class

How to apply 2. More type safe - use type safe field class

  1. translate the related FIX dictionary into java source file note: every platform will adjust the standard FIX dictionary, to meet their business requirements, e.g. add more fields, add more enum values, etc. note: different package names have to used for each dictionary. Same FIX version for different platformant means different dictionary, because they will adjust the standard dictionary separately. E.g. for BARX FIX 4.4, TradeWeb FIX 4.4, TRTN 5.0SP1, you have to generate them into different package, e.g. barx.fix44, tradeweb.fix44, trtn.fix50sp1.

  2. use them as the above sample code. This is straight forward.

Don't apply A dictionary field class, to B dictionary, e.g.

Message barxNewOrderSingle = new Message()l
barxNewOrderSingle.set(new tradeweb.fix44.fields.ClientOrderID("abcd_0x0x0x")); // don't do that although it could work most of the time.

Above could also work, because most of the time, same tag number are used cross dictonaries. They just have some(small number) customized fields on each platform. But such usage will cause our source code in a mess.

note: please just use default message factory during setup Initiator and Acceptor.

How to apply 3. Most type safe - use type safe message class

  1. translate the related FIX dictionary into java source file see the comments in 1. translate the related FIX dictionary into java source file

  2. when setup the SocketInitiator/SocketAcceptor, use the generated MessageFactory, rather than quickfix.DefaultMessageFactory If you are going to support multi dictionaries, you have to re-consider whether " type safe message class" should be used. Because, you have to setup their own ScocketInitiator/SocketAcceptor for each dictionary. You should consider thread model, too.

  • what's SocketInitiator/SocketAcceptor? Refer the qfjtutorial.begin.*. Each FIX session will belong to a SocketInitoator or SocketAcceptor.
  • you will meet problem when apply FIX 5.0(+) type safe message. Because the generated message factory does NOT cover the FIXT1.1 messages(e.g. Logon, Heartbeat, TestRequest etc). Below I have introduced how to fix it.

Q&A - how to to apply FIX 5.0(+) type safe message

If you hope to use type safe message, you have to apply the related messge factory(e.g. quickfix.fix50sp1.MessageFactory) It could work for 4.X, but not for 5.0 and later. Because since 5.0, the FXT1.1 is separated into a standlone dictionary file.

You could use below sample code to define a CompositeMessageFactory for your application to merge FXT1.1 message factory.

If you use the 5.0(or later) messageFactory(e.g. new quickfix.fix50sp1.MessageFactory()) only, you will meet below error.

20170922-08:35:08.680: Error accessing message fields
quickfix.FieldNotFound: Field [35] was not found in message.
    at quickfix.FieldMap.getField(FieldMap.java:197)
    at quickfix.FieldMap.getString(FieldMap.java:211)
    at quickfix.Session.sendRaw(Session.java:2405)
    at quickfix.Session.generateLogon(Session.java:2386)
    at quickfix.Session.nextLogon(Session.java:2058)
    at quickfix.Session.next(Session.java:968)
    at quickfix.Session.next(Session.java:1109)
    at quickfix.mina.SingleThreadedEventHandlingStrategy$SessionMessageEvent.processMessage(SingleThreadedEventHandlingStrategy.java:148)
    at quickfix.mina.SingleThreadedEventHandlingStrategy.block(SingleThreadedEventHandlingStrategy.java:90)
    at quickfix.mina.SingleThreadedEventHandlingStrategy$1.run(SingleThreadedEventHandlingStrategy.java:129)
    at java.lang.Thread.run(Thread.java:745)

The root cause is the "A" is not in the list of quickfix.fix50sp1.MessageFactory.create(string, string) Note: no such problem for FIX4.2, 4.4. Because they have "A" in their factory. It is related with the splitting of Transportation dictionray and Application dictionary since 5.0.

MessageFactory message50SP1Factory = new quickfix.fix50sp1.MessageFactory();
MessageFactory messageFXT11Factory = new quickfix.fixt11.MessageFactory();
MessageFactory messageFactory = new CompositeMessageFactory(message50SP1Factory, messageFXT11Factory);
SocketAcceptor accptor = new SocketAcceptor(application, storeFactory, settings, logFactory, messageFactory);
    static class CompositeMessageFactory implements MessageFactory {
        MessageFactory _f1;
        MessageFactory _f2;
        CompositeMessageFactory(MessageFactory f1, MessageFactory f2) {
            _f1 = f1;
            _f2 = f2;
        }
        @Override
        public Message create(String beginString, String msgType) {
            Message m = _f1.create(beginString, msgType);
            if (m == null || !m.getHeader().isSetField(35)) {
                m = _f2.create(beginString, msgType);
            }
            return m;
        }
        @Override
        public Group create(String beginString, String msgType, int correspondingFieldID) {
            Group m = _f1.create(beginString, msgType, correspondingFieldID);
            if (m == null) {
                m = _f2.create(beginString, msgType, correspondingFieldID);
            }
            return m;
        }
    } 

Clone this wiki locally