Using Iguana to interface with IBM WebSphere MQ

Introduction

IBM WebSphere doesn’t really describe a single product but in fact a branding term that IBM applies to a whole range of middleware products that it has.  A lot of large corporations has a substantial installed base of WebSphere technology.  One important part of this is the queuing solution which is called IBM WebSphere MQ.

We have customers that are migrating away from WebSphere to Iguana. During these migrations it’s still helpful to feed in and out of the WebSphere MQs for the purposes of:

  • Taking feeds of existing interfaces.
  • Running Iguana interfaces in parallel with the legacy interfaces while doing testing.

For this reason we put together this simple guide on how to do it.

Prerequisites

This article assumes that an IBM WebSphere Server and Client have been installed on two different hosts which can communicate with each-other via TCP, and that both have been configured such that the client can can put a message onto a queue via a properly configured communication channel, and can get those messages back in the same manner. This process is outlined at length in the IBM WebSphere MQ Information Center documentation, available from IBM. We have used WebSphere MQ 7.5 for the examples in this article, but any recent release should work.

These examples assume the MQ Client is configured to use a specific MQ Server Channel via the CHANNELS stanza in the mqclient.ini file. The Translator script can be easily modified to use some other way for the client binaries to find a specific MQ channel queue.

The examples assume both the MQ Server and MQ Client are installed on Microsoft Windows, the same principles can be used on Linux or Unix systems.

Example

PUTting Messages

The following example demonstrates a simple way to “put” a message from Iguana into a WebSphere MQ message queue. The Translator script could be run in any Iguana channel context where we need to move incoming data on the Iguana queue to a WebSphere MQ queue. For example, an LLP Listener To Translator channel.

At the heart of the Translator script is a call [via popen()] that opens a file handle on the external binary “amqsputc”, which is shipped with WebSphere MQ. It then uses this file-handle to determine if the MQPUT was successful or not.

-- Simple example demonstrating using the IBM MQ WebSphere Client
-- amqsputc command to put Iguana message to a MQ WebSphere Server
-- message queue.

local MQ = require('MQ')

-- Returns a filename containing the message data, or
-- nil on failure. The caller should clean up the file.
local function makeInputFile(MessageData)
   local TmpDir = os.getenv('TEMP')
      or os.getenv('TMP')
      or os.getenv('TMPDIR')
      or 'C:TEMP'
   local FileName = TmpDir .. os.tmpname()

   local handle = io.open(FileName, "w")
   local success = handle:write(MessageData)

   if success ~= true then
      local ErrMsg = success or 'no error'
      iguana.logWarning('Error streaming MQ message data to input file: '
         .. ErrMsg)
      FileName = nil
   end

   handle:flush()
   handle:close()

   return FileName
end

-- The Data argument will contain the message to be processed.
function main(Data)
   -- We stream the Data to a tempfile and redirect that into STDIN
   -- of the command doing the MQPUT. We do this instead of opening
   -- the process for write so we can get any error codes back.
   local MessageFile = makeInputFile(Data)

   if MessageFile then
      local h = io.popen('"' .. MQ.Put .. '"' .. ' ' .. MQ.Args .. ' < ' .. MessageFile, 'r')

      -- Get back all the results.
      local success = nil
      if h then
         success = h:read("*a")
      end
      h:close()

      -- Cleanup the tempfile
      os.remove(MessageFile)

      print(success)
      -- If we got nil or an error reason code back from the command, this is an
      -- error and we should make sure the message is not processed.
      if not success or success:find('reason code') then
         local ErrMsg = success or 'no error'
         error('Error putting a message to ' .. MQ.Args .. ': ' .. ErrMsg, 2)
      end

   else
      -- Could not get a file to redirect to STDIN.
      error('Could not push message to ' .. MQ.Args, 2)
   end
end

This script depends on a shared MQ.lua module where system- and MQ-specific configuration is defined.

-- Common MQ settings for sample programs
local MQ = {}

MQ.Root = 'C:/Program Files (x86)/IBM/WebSphere MQ/bin/'

-- Unused here, but could be used to construct the MQSERVER
-- environment for passing into popen() if you don't, or can't,
-- use a channel via the client configuration file.
--[[
MQ.Channel = 'CHANNEL1'
MQ.ServerIP = '10.211.55.4'
MQ.ServerPort = '1415'
--]]

MQ.Queue = 'QUEUE1'
MQ.QueueManager = 'QUEUE.MANAGER.1'
MQ.Args = MQ.Queue .. ' ' .. MQ.QueueManager

MQ.Get = MQ.Root .. 'amqsgetc.exe'
MQ.Put = MQ.Root .. 'amqsputc.exe'

return MQ

The notion is that, as data comes in on the Iguana queue, the amqsputc process is started and the contents of the data are redirected to process standard in. Error conditions are detected by reading the output back from the process [or getting nil from popen()]. Such conditions will cause the script to throw an error and leave the message pending. We do this because we only want to mark the message as processed if we know it was successfully put to an MQ queue.

GETting Messages

The technique for getting messages from an WebSphere queue into Iguana is done in a similar manner, using the “amqsgetc” binary shipped with WebSphere MQ.

Note: The amqsgetc process fetches all messages from the MQ queue, returning them as delimited strings.

local MQ = require('MQ')

function main(Data)
   local h = io.popen('"' .. MQ.Get .. '" ' .. MQ.Args, 'r')

   if not h then
      iguana.logWarning('Could not open MQ Get process')
      return
   end

   -- For each line...
   for line in h:lines() do
      -- see if is a message line...
      if line:find('^message ') then 
         -- strip off the message delimiters.
         local s1 = line:gsub('^message <', '', 1)
         local s2 = s1:gsub('>$' , '', 1)

         queue.push{ data = s2 }
      end
   end

   h:close()
end

Note: The amqsgetc process is designed to poll for incoming messages for 15 seconds. So, any Translator script that invokes this process may not return in an instant manner if the MQ queue has more messages enqueued while it is running. A potential solution for this problem is to recompile the amgsgetc program (the source code is provided by IBM) to not poll for more messages.

You can still get high throughput by getting the messages off the queue in batches.

Conclusion

If you are migrating away from WebSphere you can still inter-operate with the platform easily using Iguana.

This makes it much easier to run systems in parallel and keep things running in your organization.

If you are interested in doing more with this please let us know, we’re happy to help.

Leave A Comment?