# FIXUtils.java

    /*
     *  Licensed to the Apache Software Foundation (ASF) under one
     *   or more contributor license agreements.  See the NOTICE file
     *  distributed with this work for additional information
     *  regarding copyright ownership.  The ASF licenses this file
     *  to you under the Apache License, Version 2.0 (the
     *  "License"); you may not use this file except in compliance
     *  with the License.  You may obtain a copy of the License at
     *
     *   http://www.apache.org/licenses/LICENSE-2.0
     *
     *  Unless required by applicable law or agreed to in writing,
     *  software distributed under the License is distributed on an
     *   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     *  KIND, either express or implied.  See the License for the
     *  specific language governing permissions and limitations
     *  under the License.
     */

    package org.apache.synapse.transport.fix;

    import org.apache.axiom.attachments.ByteArrayDataSource;
    import org.apache.axiom.om.OMElement;
    import org.apache.axiom.om.OMNamespace;
    import org.apache.axiom.soap.SOAPBody;
    import org.apache.axiom.soap.SOAPEnvelope;
    import org.apache.axiom.soap.SOAPFactory;
    import org.apache.axiom.soap.impl.llom.soap11.SOAP11Factory;
    import org.apache.axis2.AxisFault;
    import org.apache.axis2.context.MessageContext;
    import org.apache.axis2.transport.base.BaseUtils;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import quickfix.*;
    import quickfix.field.*;

    import javax.activation.DataHandler;
    import javax.activation.DataSource;
    import javax.xml.namespace.QName;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.net.SocketAddress;
    import java.util.*;

    public class FIXUtils {

        private static final Log log = LogFactory.getLog(FIXUtils.class);
        private static FIXUtils _instance = new FIXUtils();

        public static FIXUtils getInstance() {
            return _instance;
        }

        /**
         * FIX messages are non-XML. So convert them into XML using the AXIOM API.
         * Put the FIX message into an Axis2 MessageContext.The basic format of the
         * generated SOAP envelope;
         * <p/>
         * <soapEnvelope>
         * <soapBody>
         * <message>
         * <header> ....</header>
         * <body> .... </body>
         * <trailer> .... </trailer>
         * </message>
         * </soapBody>
         * </soapEnvelope>
         *
         * @param message   the FIX message
         * @param counter   application level sequence number of the message
         * @param sessionID the incoming session
         * @param msgCtx    the Axis2 MessageContext to hold the FIX message
         * @throws AxisFault the exception thrown when invalid soap envelopes are set to the msgCtx
         */
        public void setSOAPEnvelope(Message message, int counter, String sessionID,
                                    MessageContext msgCtx) throws AxisFault {

            if (log.isDebugEnabled()) {
                log.debug("Creating SOAP envelope for FIX message...");
            }

            SOAPFactory soapFactory = new SOAP11Factory();
            OMElement msg = soapFactory.createOMElement(FIXConstants.FIX_MESSAGE, null);
            msg.addAttribute(soapFactory.createOMAttribute(FIXConstants.FIX_MESSAGE_INCOMING_SESSION,
                    null, sessionID));
            msg.addAttribute(soapFactory.createOMAttribute
                    (FIXConstants.FIX_MESSAGE_COUNTER, null, String.valueOf(counter)));

            OMElement header = soapFactory.createOMElement(FIXConstants.FIX_HEADER, null);
            OMElement body = soapFactory.createOMElement(FIXConstants.FIX_BODY, null);
            OMElement trailer = soapFactory.createOMElement(FIXConstants.FIX_TRAILER, null);

            //process FIX header
            Iterator<Field<?>> iter = message.getHeader().iterator();
            if (iter != null) {
                while (iter.hasNext()) {
                    Field<?> field = iter.next();
                    OMElement msgField = soapFactory.createOMElement(FIXConstants.FIX_FIELD, null);
                    msgField.addAttribute(soapFactory.createOMAttribute(FIXConstants.FIX_FIELD_ID,
                            null, String.valueOf(field.getTag())));
                    Object value = field.getObject();

                    if (value instanceof byte[]) {
                        DataSource dataSource = new ByteArrayDataSource((byte[]) value);
                        DataHandler dataHandler = new DataHandler(dataSource);
                        String contentID = msgCtx.addAttachment(dataHandler);
                        OMElement binaryData = soapFactory.createOMElement(
                                FIXConstants.FIX_BINARY_FIELD, null);
                        String binaryCID = "cid:" + contentID;
                        binaryData.addAttribute(FIXConstants.FIX_MESSAGE_REFERENCE, binaryCID, null);
                        msgField.addChild(binaryData);
                    } else {
                        createOMText(soapFactory, msgField, value.toString());
                    }
                    header.addChild(msgField);
                }
            }
            //process FIX body
            convertFIXBodyToXML(message, body, soapFactory, msgCtx);

            //process FIX trailer
            iter = message.getTrailer().iterator();
            if (iter != null) {
                while (iter.hasNext()) {
                    Field<?> field = iter.next();
                    OMElement msgField = soapFactory.createOMElement(FIXConstants.FIX_FIELD, null);
                    msgField.addAttribute(soapFactory.
                            createOMAttribute(FIXConstants.FIX_FIELD_ID, null,
                            String.valueOf(field.getTag())));
                    Object value = field.getObject();

                    if (value instanceof byte[]) {
                        DataSource dataSource = new ByteArrayDataSource((byte[]) value);
                        DataHandler dataHandler = new DataHandler(dataSource);
                        String contentID = msgCtx.addAttachment(dataHandler);
                        OMElement binaryData = soapFactory.createOMElement(
                                FIXConstants.FIX_BINARY_FIELD, null);
                        String binaryCID = "cid:" + contentID;
                        binaryData.addAttribute(FIXConstants.FIX_MESSAGE_REFERENCE, binaryCID, null);
                        msgField.addChild(binaryData);
                    } else {
                        createOMText(soapFactory, msgField, value.toString());
                    }
                    trailer.addChild(msgField);
                }
            }

            msg.addChild(header);
            msg.addChild(body);
            msg.addChild(trailer);
            SOAPEnvelope envelope = soapFactory.getDefaultEnvelope();
            envelope.getBody().addChild(msg);
            msgCtx.setEnvelope(envelope);
        }

        /**
         * Constructs the XML infoset for the FIX message body
         *
         * @param message the FIX message
         * @param body the body element of the XML infoset
         * @param soapFactory the SOAP factory to create XML elements
         * @param msgCtx the Axis2 Message context
         * @throws AxisFault on error
         */
        private void convertFIXBodyToXML(FieldMap message, OMElement body, SOAPFactory soapFactory,
                                            MessageContext msgCtx) throws AxisFault{

            if (log.isDebugEnabled()) {
                log.debug("Generating FIX message body (Message ID: " + msgCtx.getMessageID() + ")");
            }

            Iterator<Field<?>> iter = message.iterator();
            if (iter != null) {
                 while (iter.hasNext()) {
                     Field<?> field = iter.next();
                     OMElement msgField = soapFactory.createOMElement(FIXConstants.FIX_FIELD, null);
                     msgField.addAttribute(soapFactory.
                             createOMAttribute(FIXConstants.FIX_FIELD_ID, null,
                             String.valueOf(field.getTag())));
                     Object value = field.getObject();

                     if (value instanceof byte[]) {
                         DataSource dataSource = new ByteArrayDataSource((byte[]) value);
                         DataHandler dataHandler = new DataHandler(dataSource);
                         String contentID = msgCtx.addAttachment(dataHandler);
                         OMElement binaryData = soapFactory.createOMElement(
                                 FIXConstants.FIX_BINARY_FIELD, null);
                         String binaryCID = "cid:" + contentID;
                         binaryData.addAttribute(FIXConstants.FIX_MESSAGE_REFERENCE, binaryCID, null);
                         msgField.addChild(binaryData);
                     } else {
                         createOMText(soapFactory, msgField, value.toString());
                     }

                     body.addChild(msgField);
                 }
            }

            //process FIX repeating groups
            Iterator<Integer> groupKeyItr = message.groupKeyIterator();
            if (groupKeyItr != null) {
                while (groupKeyItr.hasNext()) {
                    int groupKey =  groupKeyItr.next();
                    OMElement groupsField = soapFactory.createOMElement(FIXConstants.FIX_GROUPS,
                            null);
                    groupsField.addAttribute(FIXConstants.FIX_FIELD_ID,
                            String.valueOf(groupKey),null);
                    List<Group> groupList = message.getGroups(groupKey);
                    Iterator<Group> groupIterator = groupList.iterator();

                    while (groupIterator.hasNext()) {
                        Group msgGroup = groupIterator.next();
                        OMElement groupField = soapFactory.createOMElement(FIXConstants.FIX_GROUP, null);
                        // rec. call the method to process the repeating groups
                        convertFIXBodyToXML(msgGroup, groupField, soapFactory, msgCtx);
                        groupsField.addChild(groupField);
                    }
                    body.addChild(groupsField);
                }
            }
        }

        private void generateFIXBody(OMElement node, FieldMap message, MessageContext msgCtx,
                                     boolean withNs, String nsURI, String nsPrefix) throws IOException {

            Iterator bodyElements = node.getChildElements();
            while (bodyElements.hasNext()) {
                OMElement bodyNode = (OMElement) bodyElements.next();
                String nodeLocalName = bodyNode.getLocalName();

                //handle repeating groups
                if (nodeLocalName.equals(FIXConstants.FIX_GROUPS)){
                    int groupsKey = Integer.parseInt(bodyNode.getAttributeValue(
                            new QName(FIXConstants.FIX_FIELD_ID)));
                    Group group;
                    Iterator groupElements = bodyNode.getChildElements();
                    while (groupElements.hasNext()){
                        OMElement groupNode = (OMElement) groupElements.next();
                        Iterator groupFields = groupNode.getChildrenWithName(new QName(FIXConstants.FIX_FIELD));
                        List<Integer> idList = new ArrayList<Integer>();
                        while (groupFields.hasNext()) {
                            OMElement fieldNode = (OMElement) groupFields.next();
                            idList.add(Integer.parseInt(fieldNode.getAttributeValue(
                                    new QName(FIXConstants.FIX_FIELD_ID))));
                        }

                        int[] order = new int[idList.size()];
                        for (int i = 0; i < order.length; i++) {
                            order[i] = idList.get(i);
                        }

                        group = new Group(groupsKey, order[0], order);
                        generateFIXBody(groupNode, group, msgCtx, withNs, nsURI, nsPrefix);
                        message.addGroup(group);
                    }

                } else {
                    String tag;
                    if (withNs) {
                        tag = bodyNode.getAttributeValue(new QName(nsURI, FIXConstants.FIX_FIELD_ID,
                                nsPrefix));
                    } else {
                        tag = bodyNode.getAttributeValue(new QName(FIXConstants.FIX_FIELD_ID));
                    }

                     String value = null;
                     OMElement child = bodyNode.getFirstElement();
                     if (child != null) {
                         String href;
                         if (withNs) {
                             href = bodyNode.getFirstElement().
                                        getAttributeValue(new QName(nsURI, FIXConstants.FIX_FIELD_ID,
                                                nsPrefix)) ;
                         } else {
                             href = bodyNode.getFirstElement().
                                        getAttributeValue(new QName(FIXConstants.FIX_MESSAGE_REFERENCE));
                         }

                         if (href != null) {
                             DataHandler binaryDataHandler = msgCtx.getAttachment(href.substring(4));
                             ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                             binaryDataHandler.writeTo(outputStream);
                             value = new String(outputStream.toByteArray());
                         }
                    }
                    else {
                         value = bodyNode.getText();
                    }

                    if (value != null) {
                        message.setString(Integer.parseInt(tag), value);
                    }
                }
             }
        }

        /**
         * Extract the FIX message embedded in an Axis2 MessageContext
         *
         * @param msgCtx the Axis2 MessageContext
         * @return a FIX message
         * @throws java.io.IOException the exception thrown when handling erroneous binary content
         */
        public Message createFIXMessage(MessageContext msgCtx) throws IOException {
            if (log.isDebugEnabled()) {
                log.debug("Extracting FIX message from the message context (Message ID: " +
                        msgCtx.getMessageID() + ")");
            }

            boolean withNs = false;
            String nsPrefix = null;
            String nsURI = null;

            Message message = new Message();
            SOAPBody soapBody = msgCtx.getEnvelope().getBody();

            //find namespace information embedded in the FIX payload
            OMNamespace ns = getNamespaceOfFIXPayload(soapBody);
            if (ns != null) {
                withNs = true;
                nsPrefix = ns.getPrefix();
                nsURI = ns.getNamespaceURI();
            }

            OMElement messageNode;
            if (withNs) {
                messageNode = soapBody.getFirstChildWithName(new QName(nsURI, FIXConstants.FIX_MESSAGE,
                        nsPrefix));
            } else {
                messageNode = soapBody.getFirstChildWithName(new QName(FIXConstants.FIX_MESSAGE));
            }

            Iterator messageElements = messageNode.getChildElements();

            while (messageElements.hasNext()) {
                OMElement node = (OMElement) messageElements.next();
                //create FIX header
                if (node.getQName().getLocalPart().equals(FIXConstants.FIX_HEADER)) {
                    Iterator headerElements = node.getChildElements();
                    while (headerElements.hasNext()) {
                        OMElement headerNode = (OMElement) headerElements.next();
                        String tag;
                        if (withNs) {
                            tag = headerNode.getAttributeValue(new QName(nsURI,
                                    FIXConstants.FIX_FIELD_ID, nsPrefix));
                        } else {
                            tag = headerNode.getAttributeValue(new QName(FIXConstants.FIX_FIELD_ID));
                        }
                        String value = null;

                        OMElement child = headerNode.getFirstElement();
                        if (child != null) {
                            String href;
                            if (withNs) {
                                href = headerNode.getFirstElement().getAttributeValue(
                                        new QName(nsURI, FIXConstants.FIX_MESSAGE_REFERENCE, nsPrefix));
                            } else {
                                href = headerNode.getFirstElement().
                                    getAttributeValue(new QName(FIXConstants.FIX_MESSAGE_REFERENCE));
                            }

                            if (href != null) {
                                DataHandler binaryDataHandler = msgCtx.getAttachment(href.substring(4));
                                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                                binaryDataHandler.writeTo(outputStream);
                                value = new String(outputStream.toByteArray());
                            }
                        } else {
                            value = headerNode.getText();
                        }

                        if (value != null) {
                            message.getHeader().setString(Integer.parseInt(tag), value);
                        }
                    }

                } else if (node.getQName().getLocalPart().equals(FIXConstants.FIX_BODY)) {
                    //create FIX body
                    generateFIXBody(node, message, msgCtx, withNs, nsURI, nsPrefix);

                } else if (node.getQName().getLocalPart().equals(FIXConstants.FIX_TRAILER)) {
                    //create FIX trailer
                    Iterator trailerElements = node.getChildElements();
                    while (trailerElements.hasNext()) {
                        OMElement trailerNode = (OMElement) trailerElements.next();
                        String tag;
                        if (withNs) {
                            tag = trailerNode.getAttributeValue(new QName(nsURI,
                                    FIXConstants.FIX_FIELD_ID, nsPrefix));
                        } else {
                            tag = trailerNode.getAttributeValue(new QName(FIXConstants.FIX_FIELD_ID));
                        }
                        String value = null;

                        OMElement child = trailerNode.getFirstElement();
                        if (child != null) {
                            String href;
                            if (withNs) {
                                href = trailerNode.getFirstElement().getAttributeValue(
                                        new QName(nsURI, FIXConstants.FIX_FIELD_ID, nsPrefix));
                            } else {
                                 href = trailerNode.getFirstElement().
                                    getAttributeValue(new QName(FIXConstants.FIX_MESSAGE_REFERENCE));
                            }
                            if (href != null) {
                                DataHandler binaryDataHandler = msgCtx.getAttachment(href.substring(4));
                                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                                binaryDataHandler.writeTo(outputStream);
                                value = new String(outputStream.toByteArray());
                            }
                        } else {
                            value = trailerNode.getText();
                        }

                        if (value != null) {
                            message.getTrailer().setString(Integer.parseInt(tag), value);
                        }
                    }
                }
            }
            return message;
        }

        /**
         * Generate EPRs for the specified FIX service. A FIX end point can be uniquely
         * identified by a <host(IP), port> pair. Add some additional FIX session details
         * so the EPRs are more self descriptive.
         * A FIX EPR generated here looks like;
         * fix://10.100.1.80:9898?BeginString=FIX.4.4&SenderCompID=BANZAI&TargetCompID=EXEC&
         * SessionQualifier=mySession&Serviec=StockQuoteProxy
         *
         * @param acceptor    the SocketAcceptor associated with the service
         * @param serviceName the name of the service
         * @param ip          the IP address of the host
         * @return an array of EPRs for the specified service in String format
         */
        public static String[] generateEPRs(SocketAcceptor acceptor, String serviceName, String ip) {
            //Get all the addresses associated with the acceptor
            Map<SessionID, SocketAddress> socketAddresses = acceptor.getAcceptorAddresses();
            //Get all the sessions (SessionIDs) associated with the acceptor
            ArrayList<SessionID> sessions = acceptor.getSessions();
            String[] EPRList = new String[sessions.size()];

            //Generate an EPR for each session/socket address
            for (int i = 0; i < sessions.size(); i++) {
                SessionID sessionID = sessions.get(i);
                InetSocketAddress socketAddress = (InetSocketAddress) socketAddresses.get(sessionID);
                EPRList[i] = FIXConstants.FIX_PREFIX + ip + ":" + socketAddress.getPort() +
                        "?" + FIXConstants.BEGIN_STRING + "=" + sessionID.getBeginString() +
                        "&" + FIXConstants.SENDER_COMP_ID + "=" + sessionID.getTargetCompID() +
                        "&" + FIXConstants.TARGET_COMP_ID + "=" + sessionID.getSenderCompID();

                String sessionQualifier = sessionID.getSessionQualifier();
                if (sessionQualifier != null && !sessionQualifier.equals("")) {
                    EPRList[i] += "&" + FIXConstants.SESSION_QUALIFIER + "=" + sessionQualifier;
                }

                String senderSubID = sessionID.getSenderSubID();
                if (senderSubID != null && !senderSubID.equals("")) {
                    EPRList[i] += "&" + FIXConstants.SENDER_SUB_ID + "=" + senderSubID;
                }

                String targetSubID = sessionID.getTargetSubID();
                if (targetSubID != null && !targetSubID.equals("")) {
                    EPRList[i] += "&" + FIXConstants.TARGET_SUB_ID + "=" + targetSubID;
                }

                String senderLocationID = sessionID.getSenderLocationID();
                if (senderLocationID != null && !senderLocationID.equals("")) {
                    EPRList[i] += "&" + FIXConstants.SENDER_LOCATION_ID + "=" + senderLocationID;
                }

                String targetLocationID = sessionID.getTargetLocationID();
                if (targetLocationID != null && !targetLocationID.equals("")) {
                    EPRList[i] += "&" + FIXConstants.TARGET_LOCATION_ID + "=" + targetLocationID;
                }

                EPRList[i] += "&Service=" + serviceName;
            }
            return EPRList;
        }

        public static String[] getEPRs(SessionSettings settings) throws FieldConvertError, ConfigError {
            Iterator<SessionID> sessions = settings.sectionIterator();
            String[] EPRs = new String[settings.size()];
            int i = 0;
            while (sessions.hasNext()) {
                SessionID session = sessions.next();
                String EPR = FIXConstants.FIX_PREFIX;
                String paramValue;

                EPR += settings.getString(session, FIXConstants.SOCKET_CONNECT_HOST);
                EPR += ":" + settings.getString(session, FIXConstants.SOCKET_CONNECT_PORT);
                EPR += "?" + FIXConstants.BEGIN_STRING + "=";
                EPR += settings.getString(session, FIXConstants.BEGIN_STRING);
                EPR += "&" + FIXConstants.SENDER_COMP_ID + "=";
                EPR += settings.getString(session, FIXConstants.SENDER_COMP_ID);
                EPR += "&" + FIXConstants.TARGET_COMP_ID + "=";
                EPR += settings.getString(session, FIXConstants.TARGET_COMP_ID);

                try {
                    paramValue = settings.getString(session, FIXConstants.SENDER_SUB_ID);
                    if (paramValue != null) {
                       EPR += "&" + FIXConstants.SENDER_SUB_ID + "=";
                       EPR += paramValue;
                    }
                }
                catch (ConfigError ignore) { }

                try {
                    paramValue = settings.getString(session, FIXConstants.SENDER_LOCATION_ID);
                    if (paramValue != null) {
                       EPR += "&" + FIXConstants.SENDER_LOCATION_ID + "=";
                       EPR += paramValue;
                    }
                }
                catch (ConfigError ignore) { }

                try {
                    paramValue = settings.getString(session, FIXConstants.TARGET_SUB_ID);
                    if (paramValue != null) {
                       EPR += "&" + FIXConstants.TARGET_SUB_ID + "=";
                       EPR += paramValue;
                    }
                }
                catch (ConfigError ignore) { }

                try {
                    paramValue = settings.getString(session, FIXConstants.TARGET_LOCATION_ID);
                    if (paramValue != null) {
                       EPR += "&" + FIXConstants.TARGET_LOCATION_ID + "=";
                       EPR += paramValue;
                    }
                }
                catch (ConfigError ignore) { }

                EPRs[i] = EPR;
            }
            return EPRs;
        }

        /**
         * Compares two given FIX URL strings. The second URL is considered equal to the
         * first URL if all the properties in the first URL also exist in the second URL
         * and if they have equals values.
         *
         * @param url1 a FIX URL String
         * @param url2 a FIX URL String
         * @return a boolean value
         */
        public static boolean compareURLs(String url1, String url2) {
            if (!url1.substring(0, url1.indexOf("?")).equals(url2.substring(0, url2.indexOf("?")))) {
                 return false;
            } else {
                Hashtable<String,String> properties1 = BaseUtils.getEPRProperties(url1);
                Hashtable<String, String> properties2 = BaseUtils.getEPRProperties(url2);
                for (Map.Entry<String,String> entry : properties1.entrySet()) {
                    if (!properties2.containsKey(entry.getKey())) {
                        return false;
                    } else if (!properties1.get(entry.getKey()).equals(entry.getValue())) {
                        return false;
                    }
                }
            }
            return true;
        }

        /*
         * This is here because AXIOM does not support removing CDATA tags yet. Given a String embedded in
         * CDATA tags this method will return the String element only.
         *
         * @param str the String with CDATA tags
         * @return String with CDATA tags stripped
         *
        private static String removeCDATA(String str) {
            if (str.indexOf("<![CDATA[") != -1) {
                str = str.split("CDATA")[1].split("]></field>")[0];
    		    str= str.substring(1, str.length()-1);
    		    return str;
            } else {
                return str;
            }
        }*/

        /**
         * Extracts the fields related to message forwarding (third party routing) from
         * the FIX header.
         *
         * @param message the FIX message
         * @return a Map of forwarding parameters
         */
        public static Map<String, String> getMessageForwardingParameters(Message message) {

            Map<String, String> map = new HashMap<String, String>();
            String value = getHeaderFieldValue(message, BeginString.FIELD);
            map.put(FIXConstants.BEGIN_STRING, value);
            value = getHeaderFieldValue(message, SenderCompID.FIELD);
            map.put(FIXConstants.SENDER_COMP_ID, value);
            value = getHeaderFieldValue(message, SenderSubID.FIELD);
            map.put(FIXConstants.SENDER_SUB_ID, value);
            value = getHeaderFieldValue(message, SenderLocationID.FIELD);
            map.put(FIXConstants.SENDER_LOCATION_ID, value);
            value = getHeaderFieldValue(message, TargetCompID.FIELD);
            map.put(FIXConstants.TARGET_COMP_ID, value);
            value = getHeaderFieldValue(message, DeliverToCompID.FIELD);
            map.put(FIXConstants.DELIVER_TO_COMP_ID, value);
            value = getHeaderFieldValue(message, DeliverToSubID.FIELD);
            map.put(FIXConstants.DELIVER_TO_SUB_ID, value);
            value = getHeaderFieldValue(message, DeliverToLocationID.FIELD);
            map.put(FIXConstants.DELIVER_TO_LOCATION_ID, value);
            value = getHeaderFieldValue(message, OnBehalfOfCompID.FIELD);
            map.put(FIXConstants.ON_BEHALF_OF_COMP_ID, value);
            value = getHeaderFieldValue(message, OnBehalfOfSubID.FIELD);
            map.put(FIXConstants.ON_BEHALF_OF_SUB_ID, value);
            value = getHeaderFieldValue(message, OnBehalfOfLocationID.FIELD);
            map.put(FIXConstants.ON_BEHALF_OF_LOCATION_ID, value);
            return map;
        }

        private static String getHeaderFieldValue(Message message, int tag) {
            try {
                return message.getHeader().getString(tag);
            } catch (FieldNotFound fieldNotFound) {
                return null;
            }
        }

        /**
         * Extracts the name of the service which processed the message from the MessageContext
         *
         * @param msgCtx Axis2 MessageContext of a message
         * @return name of the AxisService
         * @throws org.apache.axis2.AxisFault on error
         */
        public static String getServiceName(MessageContext msgCtx) throws AxisFault {

            Object serviceParam = msgCtx.getProperty(FIXConstants.FIX_SERVICE_NAME);
            if (serviceParam != null) {
                String serviceName = serviceParam.toString();
                if (serviceName != null && !serviceName.equals("")) {
                    return serviceName;
                }
            }

            Map trpHeaders = (Map) msgCtx.getProperty(MessageContext.TRANSPORT_HEADERS);
            //try to get the service from the transport headers
            if (trpHeaders != null) {
                String serviceName = (String) trpHeaders.get(FIXConstants.FIX_MESSAGE_SERVICE);
                if (serviceName != null) {
                    return serviceName;
                }
            }
            throw new AxisFault("Unable to find a valid service for the message");
        }

        /**
         * Extracts the application type for the message from the message context
         *
         * @param msgCtx Axis2 Message Context
         * @return application type of the message
         */
        public static String getFixApplication(MessageContext msgCtx) {
            Map trpHeaders = (Map) msgCtx.getProperty(MessageContext.TRANSPORT_HEADERS);
            //try to get the application type from the transport headers
            String fixApplication = null;
            if (trpHeaders != null) {
                fixApplication = (String) trpHeaders.get(FIXConstants.FIX_MESSAGE_APPLICATION);
            }
            return fixApplication;
        }

        /**
         * Creates a Map of transport headers for a message
         *
         * @param serviceName    name of the service to which the message belongs to
         * @param fixApplication FIX application type
         * @return a Map of transport headers
         */
        public static Map<String, String> getTransportHeaders(String serviceName,
                                                              String fixApplication) {

            Map<String, String> trpHeaders = new HashMap<String, String>();
            trpHeaders.put(FIXConstants.FIX_MESSAGE_SERVICE, serviceName);
            trpHeaders.put(FIXConstants.FIX_MESSAGE_APPLICATION, fixApplication);
            return trpHeaders;
        }

        /**
         * Reads a FIX EPR and returns the host and port on a String array
         *
         * @param fixEPR a FIX EPR
         * @return an array of Strings containing addressing elements
         * @throws AxisFault on error
         */
        public static String[] getSocketAddressElements(String fixEPR) throws AxisFault {
            int propPos = fixEPR.indexOf("?");
            if (propPos != -1 && fixEPR.startsWith(FIXConstants.FIX_PREFIX)) {
                String address = fixEPR.substring(FIXConstants.FIX_PREFIX.length(), propPos);
                String[] socketAddressElemets = address.split(":");
                if (socketAddressElemets.length == 2) {
                    return socketAddressElemets;
                }
            }
            throw new AxisFault("Malformed FIX EPR: " + fixEPR);
        }

        /**
         * Reads the SOAP body of a message and attempts to retreive the application level
         * sequence number
         *
         * @param msgCtx Axis2 MessageContext
         * @return application level sequence number or -1
         */
        public static int getSequenceNumber(MessageContext msgCtx) {
            int seqNum;
            SOAPBody body = msgCtx.getEnvelope().getBody();
            OMNamespace ns = getNamespaceOfFIXPayload(body);
            if (ns == null) {
                OMElement messageNode = body.getFirstChildWithName(new QName(FIXConstants.FIX_MESSAGE));
                String value = messageNode.getAttributeValue(new QName(FIXConstants.FIX_MESSAGE_COUNTER));
                if (value != null) {
                    seqNum = Integer.parseInt(value);
                } else {
                    seqNum = -1;
                }
            }
            else {
                seqNum = getSequenceNumber(body, ns);
            }
            return seqNum;
        }

        /**
         * Reads the SOAP body of a message and attempts to retreive the application level
         * sequence number
         *
         * @param body Body of the SOAP message
         * @param ns Namespace
         * @return application level sequence number or -1
         */
        private static int getSequenceNumber(SOAPBody body, OMNamespace ns) {
            OMElement messageNode = body.getFirstChildWithName(new QName(ns.getNamespaceURI(),
                    FIXConstants.FIX_MESSAGE, ns.getPrefix()));
            String value = messageNode.getAttributeValue(new QName(ns.getNamespaceURI(),
                    FIXConstants.FIX_MESSAGE_COUNTER, ns.getPrefix()));
            if (value != null) {
                 return Integer.parseInt(value);
            } else {
                 return -1;
            }
        }

        /**
         * Reads the SOAP body of a message and attempts to retreive the session identifier string
         *
         * @param msgCtx Axis2 MessageContext
         * @return a String uniquely identifying a session or null
         */
        public static String getSourceSession(MessageContext msgCtx) {
            String srcSession;
            SOAPBody body = msgCtx.getEnvelope().getBody();
            OMNamespace ns = getNamespaceOfFIXPayload(body);
            if (ns == null) {
                OMElement messageNode = body.getFirstChildWithName(new QName(FIXConstants.FIX_MESSAGE));
                srcSession = messageNode.getAttributeValue(new QName(
                        FIXConstants.FIX_MESSAGE_INCOMING_SESSION));
            } else {
                srcSession = getSourceSession(body, ns);
            }
            return srcSession;
        }

        /**
         * Reads the SOAP body of a message and attempts to retreive the session identifier string
         * with a namesapce
         *
         * @param body Body of the SOAP message
         * @param ns Namespace
         * @return a String uniquely identifying a session or null
         */
        private static String getSourceSession(SOAPBody body, OMNamespace ns) {
               OMElement messageNode = body.getFirstChildWithName(new QName(ns.getNamespaceURI(),
                       FIXConstants.FIX_MESSAGE, ns.getPrefix()));
               return messageNode.getAttributeValue(new QName(ns.getNamespaceURI(),
                       FIXConstants.FIX_MESSAGE_INCOMING_SESSION, ns.getPrefix()));
        }

        /**
         * Creates a text node within a CDATA section selectively by looking at the enclosing text.
         * @param soapFactory
         * @param field
         * @param text
         */
        private static void createOMText(SOAPFactory soapFactory, OMElement field, String text) {
            if (text == null) {
                return;
            }
            if (text.indexOf('<') == -1 && text.indexOf('&') == -1) {
                soapFactory.createOMText(field, text);
            } else {
                soapFactory.createOMText(field, text, OMElement.CDATA_SECTION_NODE);
            }
        }

        /**
         * Read the FIX message payload and identify the namespace if exists
         *
         * @param fixBody FIX message payload
         * @return  namespace as a OMNamespace
         */
        public static OMNamespace getNamespaceOfFIXPayload(SOAPBody fixBody){
            return fixBody.getFirstElementNS();
        }
    }