8

What is the most efficient way in Quickfix/n 1.4 to extract the message type as defined here: http://www.fixprotocol.org/FIXimate3.0/en/FIX.5.0SP2/messages_sorted_by_type.html

I currently use var msgType = Message.GetMsgType(message.ToString()); which results in "A" for a Logon message. Is there a better way? I try to determine the message type within ToAdmin(...) in order to catch an outgoing Logon request message so I can add the username and password.

I would love to do it through MessageCracker but so far I have not found a way to implement a catch-all-remaining message types in case I have not implemented all OnMessage overloads. (Please see related question: Quickfix, Is there a "catch-all" method OnMessage to handle incoming messages not handled by overloaded methods?).

Thanks

Community
  • 1
  • 1
Matt
  • 7,004
  • 11
  • 71
  • 117
  • This is premature optimization. Make it work first. Put off performance investigations until you know you need it. – Grant Birchmeier Jul 31 '13 at 12:56
  • Sorry, my comment was overly blunt. What I meant to say was that if you have performance issues, this little string parsing thing is not likely to be your primary cause. Don't worry about optimizing things until you have evidence that it's a problem. – Grant Birchmeier Jul 31 '13 at 13:46
  • This is entirely unrelated to performance. I need to check whether the outgoing message is a logon in order to add username and password. – Matt Jul 31 '13 at 14:26
  • I guess I interpreted your use of "efficient" to mean performance. My bad. – Grant Birchmeier Jul 31 '13 at 14:44
  • No worries maybe the term "efficient" was misleading. Thanks for your answer – Matt Jul 31 '13 at 14:46

3 Answers3

7

Not your title question, but a key part of it:

I try to determine the message type within ToAdmin(...) in order to catch an outgoing Logon request message so I can add the username and password.

Here's a blob of code that pretty much nails it (taken from this post to the QF/n mailing list):

    public void ToAdmin(Message message, SessionID sessionID)
    {
        // Check message type
        if (message.Header.GetField(Tags.MsgType) == MsgType.LOGON)
        {
            // Yes it is logon message
            // Check if local variables YourUserName and YourPassword are set
            if (!string.IsNullOrEmpty(YourUserName) && !string.IsNullOrEmpty(YourPassword))
            {
                // Add Username and Password fields to logon message
                ((Logon) message).Set(new Username(YourUserName));
                ((Logon) message).Set(new Password(YourPassword));
            }
        }
    }
Grant Birchmeier
  • 17,809
  • 11
  • 63
  • 98
  • 1
    Perfect. Exactly what I was looking for. I was unaware of the Tag class. Thanks a lot. – Matt Jul 31 '13 at 14:28
2

Here is another approach using the idea I've mentioned in the other post. It's actually very simple to split the Crack method in two methods and have OnMessageTo and OnMessageFrom handlers. The modified implementation of the MessageCracker helper class above is aware about the message direction, though certainly can be improved.

In your Application, implement like this (not complete code):

public class MyFixApplication: DirectedMessageCracker, Application
{
...

public void FromAdmin(Message msg, SessionID sessionId)
{
    CrackFrom(msg, sessionId);
}

public void ToAdmin(Message msg, SessionID sessionId)
{
    CrackTo(msg, sessionId);
}

public void OnMessageTo(Logon msg, SessionID sessionId)
{
    //Treat the outgoing message, set user, password, etc
}

public void OnMessageFrom(Allocation msg, SessionID sessionId)
{
    //Treat the incoming Allocation message
}
...and so on

And the modified MessageCracker:

using System;
using System.Collections.Generic;
using System.Reflection;

namespace QuickFix
{
    /// <summary>
    /// Helper class for delegating message types for various FIX versions to
    /// type-safe OnMessage methods, supports handling of incoming and outgoing messages separatelly
    /// </summary>
    public abstract class DirectedMessageCracker
    {
        private readonly Dictionary<Type, MethodInfo> _toHandlerMethods = new Dictionary<Type, MethodInfo>();
        private readonly Dictionary<Type, MethodInfo> _fromHandlerMethods = new Dictionary<Type, MethodInfo>();

        protected DirectedMessageCracker()
        {
            Initialize(this);
        }

        private void Initialize(Object messageHandler)
        {
            var handlerType = messageHandler.GetType();

            var methods = handlerType.GetMethods();
            foreach (var m in methods)
            {
                if (IsToHandlerMethod(m))
                    _toHandlerMethods[m.GetParameters()[0].ParameterType] = m;
                else if (IsFromHandlerMethod(m))
                    _fromHandlerMethods[m.GetParameters()[0].ParameterType] = m;
            }
        }

        static public bool IsToHandlerMethod(MethodInfo m)
        {
            return IsHandlerMethod("OnMessageTo", m);
        }

        static public bool IsFromHandlerMethod(MethodInfo m)
        {
            return IsHandlerMethod("OnMessageFrom", m);
        }

        static public bool IsHandlerMethod(string searchMethodName, MethodInfo m) 
        {
            return (m.IsPublic
                && m.Name.StartsWith(searchMethodName)
                && m.GetParameters().Length == 2
                && m.GetParameters()[0].ParameterType.IsSubclassOf(typeof(Message))
                && typeof(SessionID).IsAssignableFrom(m.GetParameters()[1].ParameterType)
                && m.ReturnType == typeof(void));
        }

        /// <summary>
        /// Process ("crack") a FIX message and call the registered handlers for that type, if any
        /// </summary>
        /// <param name="handlerMethods"></param>
        /// <param name="message"></param>
        /// <param name="sessionID"></param>
        private void Crack(IDictionary<Type, MethodInfo> handlerMethods, Message message, SessionID sessionID)
        {
            var messageType = message.GetType();
            MethodInfo handler;

            if (handlerMethods.TryGetValue(messageType, out handler))
                handler.Invoke(this, new object[] { message, sessionID });
            else
                throw new UnsupportedMessageType();
        }

        /// <summary>
        /// Process ("crack") an INCOMING FIX message and call the registered handlers for that type, if any
        /// </summary>
        /// <param name="message"></param>
        /// <param name="sessionID"></param>
        public void CrackFrom(Message message, SessionID sessionID)
        {
            Crack(_fromHandlerMethods, message, sessionID);
        }

        /// <summary>
        /// Process ("crack") an OUTGOING FIX message and call the registered handlers for that type, if any
        /// </summary>
        /// <param name="message"></param>
        /// <param name="sessionID"></param>
        public void CrackTo(Message message, SessionID sessionID)
        {
            Crack(_toHandlerMethods, message, sessionID);
        }
    }
}

You can also skip the crack instead of throwing an exception in case of you don't want to implement all possible message handlers by just removing the throw new UnsupportedMessageType(); from the crack method.

Another idea is to split cracking Admin/App messages.

Community
  • 1
  • 1
natenho
  • 5,231
  • 4
  • 27
  • 52
  • Thanks a lot for the idea. However, I put the whole thought of using MessageCracker on hold because the builder currently seems unable to create code for the added xml data dictionary custom message types. Without it I cannot use MessageCracker either and rather just build the messages myself. Still playing around with it but so far it does not look as if the message methods are correctly added to the respective FIXxx namespace. – Matt Aug 02 '13 at 06:23
1

In this case you could just do this inside ToAdmin:

var logonMessage = msg as Logon;
if (logonMessage != null)
{
    //Treat the logon message as you want
}

Or use the MessageCracker as explained in the other answer that you mentioned.

Hope it helps.

Community
  • 1
  • 1
natenho
  • 5,231
  • 4
  • 27
  • 52