Skip to content

How to Send message from an on premise IBM MQ to Azure Service Bus queue

shashikanthraot edited this page Jan 10, 2016 · 1 revision

IBM® MQ is a robust messaging middle-ware that facilitates the integration of diverse applications and business data across multiple platforms, ranging from mainframe to desktops. For more details on IBM MQ please see here. IBM MQ provides a rich set of interfaces to develop applications in a language of your choice. The languages include C, C# and Java among others.

Azure Service Bus is a cloud based messaging service offering from Microsoft that facilitates connecting applications and service running on cloud, on-premise. Fore more details on Azure Service Bus please see here

How about connecting IBM MQ running on-premise and Azure Service Bus?

This article describes a simple way for applications connected to IBM MQ to publish messages to Microsoft Azure Service Bus for consumptions by application connected to Azure Service Bus.

The diagram below describes the architecture of the solution.

The key component in this solution is the Windows application developed using IBM Message Service Client (XMS .NET) which acts as a bridge between IBM MQ and Azure Service Bus. This component deploys a message listener to receive messages from a IBM MQ queue, turn them into Azure Service Bus message and send them to Azure Service Bus. The Windows application is developed using Microsoft .NET Framework v4.5.

This article assumes that the reader has knowledge of setting up IBM MQ and Microsoft Azure Service Bus and hence focuses on the XMS .NET bridge component.

The bridge component first establishes connection to Azure Service Bus and opens a queue. If the queue does not exist, the bridge creates it. Here is the sample code.

    /// <summary>
    /// Create service bus queue
    /// </summary>
    private QueueClient azureCreateServiceBusQueue()
    {
        QueueClient azureQueueClient = null;

        string connectionString = null;
        try
        {
            // Read the Azure Service Bus endpoint connection string from App.config file.
            var appSettings = ConfigurationManager.AppSettings;
            connectionString = appSettings["Microsoft.ServiceBus.ConnectionString"];

            // Create namespace on the Azure Service Bus using the endpoint.
            var namespaceManager =
                NamespaceManager.CreateFromConnectionString(connectionString);
            
            // Check if the queue exists. 
            if (!namespaceManager.QueueExists("ibmmqazurelinkq"))
            {
                // Queue does not exist. So create a new one.
                QueueDescription qd = new QueueDescription("ibmmqazurelinkq");
                // Default queue size 5 GB
                qd.MaxSizeInMegabytes = 5120;
                qd.DefaultMessageTimeToLive = System.TimeSpan.MaxValue;
                namespaceManager.CreateQueue(qd);
            }
            // Create a Azure Service Bus queue client so that we can send messages.
            azureQueueClient = QueueClient.CreateFromConnectionString(connectionString, "ibmmqazurelinkq");
        }
        catch (Exception ex)
        {
            Console.Write(ex);
        }
        return azureQueueClient;
    }

The bridge then establishes connection to IBM MQ queue manager, creates a consumer and sets up a message listener to consume message asynchronously. Here is the sample code.

    /// <summary>
    /// Setup connection to MQ queue manager using XMS .NET
    /// </summary>
    private void ibmmqSetupConnection()
    {
        XMSFactoryFactory factoryFactory;
        IConnectionFactory cf;
        IDestination destination;
        IMessageConsumer consumerAsync;
        MessageListener messageListener;
        // Get an instance of factory.
        factoryFactory = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ);

        // Create WMQ Connection Factory.
        cf = factoryFactory.CreateConnectionFactory();

        // Set the properties
        cf.SetStringProperty(XMSC.WMQ_HOST_NAME, "host.ibm.com");
        cf.SetIntProperty(XMSC.WMQ_PORT, 1414);
        cf.SetStringProperty(XMSC.WMQ_CHANNEL, "QM.SVRCONN");
        cf.SetIntProperty(XMSC.WMQ_CONNECTION_MODE, XMSC.WMQ_CM_CLIENT);
        cf.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, "QM1");
        cf.SetStringProperty(XMSC.USERID, "myuserid");
        cf.SetStringProperty(XMSC.PASSWORD, "passw0rd");

        // Create connection.
        connectionWMQ = cf.CreateConnection();
        // Create session with client acknowledge so that we can acknowledge 
        // only if message is sent to Azure Service Bus queue
        sessionWMQ = connectionWMQ.CreateSession(false, AcknowledgeMode.ClientAcknowledge);
        // Create destination
        destination = sessionWMQ.CreateQueue("INPUTQ");
        // Create consumer
        consumerAsync = sessionWMQ.CreateConsumer(destination);

        // Setup a message listener and assign it to consumer
        messageListener = new MessageListener(OnMessageCallback);
        consumerAsync.MessageListener = messageListener;

        // Start the connection to receive messages.
        connectionWMQ.Start();

        // Wait for messages till a key is pressed by user
        Console.ReadKey();

        // Cleanup
        consumerAsync.Close();
        destination.Dispose();
        sessionWMQ.Dispose();
        connectionWMQ.Close();
    }

The message listener gets invoked to deliver messages to application. The message listener then sends MQ JMS message to Azure Service Bus queue. If the message is successfully sent to Azure Service Bus, the listener calls message.Acknowledge() method to remove the message from IBM MQ queue. Here is the sample code.

    /// <summary>
    /// Callback method which is invoked whenever a new message arrives.
    /// </summary>
    /// <param name="message">The message which has just arrived.</param> 
    private void OnMessageCallback(IMessage message)
    {
        try
        {
            // Send the received message to Azure Service Bus
            azureSendMessage(message);
            // If sent successfully, then remove it from MQ queue 
            message.Acknowledge();
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception caught in OnMessageCallback: {0}", ex);
        }
    } // end OnMessageCallback

Once the message is received, the listener converts the MQ JMS message into _BrokeredMessage _ which is then sent to Azure Service Bus queue. Here is the sample code. The sample assumes the incoming messages are text messages. The code can be changed or extended to handle other types of JMS messages.

    /// <summary>
    /// Sends a MQ JMS message to Azure Service Bus
    /// </summary>
    /// <param name="mqJmsMessage"></param>
    private void azureSendMessage(IMessage mqJmsMessage)
    {
        if (azureQueueClient != null)
        {
            // Map the incoming message to a ITextMessage.
            ITextMessage textMessage = (ITextMessage)mqJmsMessage;

            // Create message object for Azure Service Bus using the message
            // body of IBM MQ message.
            BrokeredMessage message = new BrokeredMessage(textMessage.Text);

            // A value of 0 for JMSExpiration in IBM MQ means the message never expires.
            // But in case of Azure Service Bus, TimeToLive (or Expiry) must be a positive
            // value. Hence if JMSExpiration is 0, we let Azure Service Bus queue to set
            // TimeToLive to DefaultMessageTimeToLive.
            if (mqJmsMessage.JMSExpiration > 0)
            {
                message.TimeToLive = new TimeSpan(mqJmsMessage.JMSExpiration);
            }

            // Set the correlation id
            message.CorrelationId = mqJmsMessage.JMSCorrelationID;
            
            // As the MQ message is of type ITextMessage, so we set content type as Text
            message.ContentType = "Text";

            // Set Azure message as persistent if incoming MQ message is also persistent
            message.ForcePersistence = mqJmsMessage.JMSDeliveryMode == DeliveryMode.Persistent ? true : false;
            
            // Set reply to destination as the provided by IBM MQ message.
            message.ReplyTo = (mqJmsMessage.JMSReplyTo != null) ? mqJmsMessage.JMSReplyTo.Name : null;
            
            // Get all other properties from MQ JMS message and set them as custom properties in
            // Azure Service Bus message
            IEnumerator mqJmsProps = mqJmsMessage.PropertyNames;
            while (mqJmsProps.MoveNext())
            {
                String curPropName = (String)mqJmsProps.Current;
                // We assume that all properties are of type String.
                message.Properties[curPropName] = mqJmsMessage.GetStringProperty(curPropName);
            }

            // Send message to the Azure Service Bus queue.
            azureQueueClient.Send(message);
        }
    }