# FIXMessageBuilder.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.message;

    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.Reader;
    import java.util.Iterator;
    import java.util.List;

    import javax.activation.DataHandler;
    import javax.activation.DataSource;

    import org.apache.axiom.attachments.ByteArrayDataSource;
    import org.apache.axiom.om.OMElement;
    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.Constants;
    import org.apache.axis2.builder.Builder;
    import org.apache.axis2.context.MessageContext;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;

    import quickfix.DataDictionary;
    import quickfix.DefaultDataDictionaryProvider;
    import quickfix.FieldMap;
    import quickfix.Group;
    import quickfix.InvalidMessage;
    import quickfix.MessageUtils;
    import quickfix.field.BeginString;

    /**
     * Fix message builder prepares a payload based on the incoming raw fix message
     * read from the
     * destination,the implementation only focusing the building the message
     * context, there will be
     * limitations such as when build message there wont be fix session attribute
     * involved and the assumption
     * is that the fix client and executor has the responsibilities of managing fix
     * session accordingly
     *
     */
    public class FIXMessageBuilder implements Builder {

    	private static final Log log = LogFactory.getLog(FIXMessageBuilder.class);

    	public OMElement processDocument(InputStream inputStream, String contentType, MessageContext messageContext) throws AxisFault {
    		Reader reader = null;
    		StringBuilder messageString = new StringBuilder();
    		quickfix.Message message = null;
    		try {
    			String charSetEncoding = (String) messageContext.getProperty(Constants.Configuration.CHARACTER_SET_ENCODING);
    			if (charSetEncoding == null) {
    				charSetEncoding = MessageContext.DEFAULT_CHAR_SET_ENCODING;
    			}
    			reader = new InputStreamReader(inputStream, charSetEncoding);
    			try {
    				int data = reader.read();
    				while (data != -1) {
    					char dataChar = (char) data;
    					data = reader.read();
    					messageString.append(dataChar);
    				}
    			} catch (Exception e) {
    				// TODO Auto-generated catch block
    				log.error("Error In creating FIX SOAP envelope ...", e);
    				throw new AxisFault(e.getMessage());
    			}

    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			log.error("Error In creating FIX SOAP envelope ...", e);
    			throw new AxisFault(e.getMessage());
    		}

    		try {
    			DefaultDataDictionaryProvider dataDictionary = new DefaultDataDictionaryProvider();
    			String beginString = MessageUtils.getStringField(messageString.toString(), BeginString.FIELD);
    			DataDictionary dataDic = dataDictionary.getSessionDataDictionary(beginString);
    			message = new quickfix.Message(messageString.toString(), null, false);
    		} catch (InvalidMessage e) {
    			// TODO Auto-generated catch block
    			log.error("Error In creating FIX SOAP envelope ...", e);
    			throw new AxisFault(e.getMessage());
    		}

    		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, ""));
    		msg.addAttribute(soapFactory.createOMAttribute(FIXConstants.FIX_MESSAGE_COUNTER, null, String.valueOf("-1")));

    		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<quickfix.Field<?>> iter = message.getHeader().iterator();
    		if (iter != null) {
    			while (iter.hasNext()) {
    				quickfix.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 = messageContext.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 {
    					soapFactory.createOMText(msgField, value.toString(), OMElement.CDATA_SECTION_NODE);
    				}
    				header.addChild(msgField);
    			}
    		}
    		// process FIX body
    		convertFIXBodyToXML(message, body, soapFactory, messageContext);

    		// process FIX trailer
    		iter = message.getTrailer().iterator();
    		if (iter != null) {
    			while (iter.hasNext()) {
    				quickfix.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 = messageContext.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 {
    					soapFactory.createOMText(msgField, value.toString(), OMElement.CDATA_SECTION_NODE);
    				}
    				trailer.addChild(msgField);
    			}
    		}

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

    		return msg;
    	}

    	/**
    	 * 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<quickfix.Field<?>> iter = message.iterator();
    		if (iter != null) {
    			while (iter.hasNext()) {
    				quickfix.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 {
    					soapFactory.createOMText(msgField, value.toString(), OMElement.CDATA_SECTION_NODE);
    				}

    				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);
    			}
    		}
    	}

    }