IBM MQ, Java and MQ MI and/or MQ HA

Sometimes you come across things that make you just scratch your head and say who the hell wrote this @#$% code. I’m not trying to say that I’m the world’s greatest programmer but some of the shit that the MQ/Java team writes just makes my head spin. They need to share what they’re smoking!

IBM’s line is that if you want MQ MI (Multi-Instance) or MQ HA (High Availability) support for Java applications then use JMS or use a CCDT file with your Java application (non-JMS).

Years ago, I heard about simply separating the IP addresses and/or hostnames with a comma (‘,’) in the HOST_NAME_PROPERTY property for a Hashtable or hostname field of MQEnvironment class. I thought I had tested it and it worked but clearly not.

So, this blog posting is on IBM MQ classes for Java (aka WebSphere MQ classes for Java) and the use of the non-default queue manager port of 1414 and MQ MI or MQ HA.

If your queue manager’s listener is on port 1414 and you have Java applications (non-JMS) using MQ MI or MQ HA then life for you is super easy and NOT complicated. Here’s a coding example:

Hashtable<String,Object> mqht = new Hashtable<String,Object>();
mqht.put(CMQC.CHANNEL_PROPERTY, "TEST.CHL");
mqht.put(CMQC.HOST_NAME_PROPERTY, "cw-serv01,cw-serv02");
mqht.put(CMQC.PORT_PROPERTY, new Integer(1414));
MQQueueManager qMgr = new MQQueueManager("MQA1", mqht);

Or you can simplify it to:

Hashtable<String,Object> mqht = new Hashtable<String,Object>();
mqht.put(CMQC.CHANNEL_PROPERTY, "TEST.CHL");
mqht.put(CMQC.HOST_NAME_PROPERTY, "cw-serv01,cw-serv02");
MQQueueManager qMgr = new MQQueueManager("MQA1", mqht);

So, what if your queue manager’s listener is NOT on port 1414 and you have Java applications (non-JMS) using MQ MI or MQ HA then life is really tricky but can be done if you are careful.

Note: IBM MQ classes for Java (non-JMS) does NOT support the Hashtable property of WMQ_CONNECTION_NAME_LIST (aka “connectionNameList”) like JMS, XMS or C#.

I’ll run through some examples. Here’s my setup:

– Queue Manager name: MQA1 Active/Passive setup
– Queue Manager listener port #: 5555
– HA servers: cw-serv01 and cw-serv02

MQA1 is currently running on cw-serv01.

In my Java program, if I do:

Hashtable<String,Object> mqht = new Hashtable<String,Object>();
mqht.put(CMQC.CHANNEL_PROPERTY, "TEST.CHL");
mqht.put(CMQC.HOST_NAME_PROPERTY, "cw-serv01,cw-serv02");
mqht.put(CMQC.PORT_PROPERTY, new Integer(5555));
MQQueueManager qMgr = new MQQueueManager("MQA1", mqht);

I get error:
com.ibm.mq.jmqi.JmqiException: CC=2;RC=2538;AMQ9204: Connection to host ‘cw-serv02(5555)’ rejected. [1=com.ibm.mq.jmqi.JmqiException[CC=2;RC=2538;AMQ9205: The host name supplied is not valid. [3=cw-serv02,4=TCP]],3=cw-serv02(5555),5=RemoteTCPConnection.resolveHostname]

Its like MQ client library skipped over the first hostname (cw-serv01). But no. It attempted the connection on port number 1414. Seriously. Even though, the PORT_PROPERTY property is correctly set to 5555.

If I do (reverse the order of the hostnames):

Hashtable<String,Object> mqht = new Hashtable<String,Object>();
mqht.put(CMQC.CHANNEL_PROPERTY, "TEST.CHL");
mqht.put(CMQC.HOST_NAME_PROPERTY, "cw-serv02,cw-serv01");
mqht.put(CMQC.PORT_PROPERTY, new Integer(5555));
MQQueueManager qMgr = new MQQueueManager("MQA1", mqht);

Then it works, but it takes about 3 seconds for the connection. Which makes sense since MQA1 is not running on cw-serv02. But note: it would have been trying port number 1414 rather than 5555, so it would have failed anyway.

Of course, IBM is deleting pretty much all useful information at developer works web site. Pretty damn sad! Anyway, Josh found a cached google page here from 2014 where someone was having an issue with MQ MI and a Java application using a CCDT file. With a little bit of deduction and testing, I discovered what the hell was going on under the covers. And it is really stupid.

So, what test did I do that started to shed light onto the situation. I removed the PORT_PROPERTY from the first test and I flipped the order of hostnames and I explicitly set port number in the HOST_NAME_PROPERTY field.

Hashtable<String,Object> mqht = new Hashtable<String,Object>();
mqht.put(CMQC.CHANNEL_PROPERTY, "TEST.CHL");
mqht.put(CMQC.HOST_NAME_PROPERTY, "cw-serv02(5555),cw-serv01(5555)");
MQQueueManager qMgr = new MQQueueManager("MQA1", mqht);

And I got the following error:
com.ibm.mq.jmqi.JmqiException: CC=2;RC=2538;AMQ9204: Connection to host ‘cw-serv01(5555)(1414)’ rejected. [1=com.ibm.mq.jmqi.JmqiException[CC=2;RC=2538;AMQ9205: The host name supplied is not valid. [3=cw-serv01(5555),4=TCP]],3=cw-serv01(5555)(1414),5=RemoteTCPConnection.parseConnectionName]

Notice how it says: cw-serv01(5555)(1414).

So, I did a whole bunch of testing changing:
– first value in the HOST_NAME_PROPERTY setting i.e. with & without port number
– second value in the HOST_NAME_PROPERTY setting i.e. with & without port number
– setting & not setting the PORT_PROPERTY value

So, what did I discover? Well, MQ MI and/or MQ HA is supported for Java applications (non-JMS) under the following very exact rules:

(1) The first hostname or IP address MUST have the port number explicitly set.
(2) The second hostname or IP address must NOT have the port number explicitly set.
(3) The PORT_PROPERTY property MUST be set to the correct value for the 2nd hostname or IP address.

Here is the correct way to set the information in the Hashtable for use with MQ MI and/or MQ HA:

Hashtable<String,Object> mqht = new Hashtable<String,Object>();
mqht.put(CMQC.CHANNEL_PROPERTY, "TEST.CHL");
mqht.put(CMQC.HOST_NAME_PROPERTY, "cw-serv01(5555),cw-serv02");
mqht.put(CMQC.PORT_PROPERTY, new Integer(5555));
MQQueueManager qMgr = new MQQueueManager("MQA1", mqht);

Ok, just to bake your noodle a little more, if you take the above working example and decide to remove the 2nd hostname, you would expect it to work, right?

Hashtable<String,Object> mqht = new Hashtable<String,Object>();
mqht.put(CMQC.CHANNEL_PROPERTY, "TEST.CHL");
mqht.put(CMQC.HOST_NAME_PROPERTY, "cw-serv01(5555)");
mqht.put(CMQC.PORT_PROPERTY, new Integer(5555));
MQQueueManager qMgr = new MQQueueManager("MQA1", mqht);

But no. You get the following error:
com.ibm.mq.jmqi.JmqiException: CC=2;RC=2538;AMQ9204: Connection to host ‘cw-serv01(5555)(5555)’ rejected. [1=com.ibm.mq.jmqi.JmqiException[CC=2;RC=2538;AMQ9205: The host name supplied is not valid. [3=cw-serv01(5555),4=TCP]],3=cw-serv01(5555)(5555),5=RemoteTCPConnection.parseConnectionName]

If you have only 1 hostname or IP address then you CANNOT explicitly set the port number in the HOST_NAME_PROPERTY property. You need to do the following:

Hashtable<String,Object> mqht = new Hashtable<String,Object>();
mqht.put(CMQC.CHANNEL_PROPERTY, "TEST.CHL");
mqht.put(CMQC.HOST_NAME_PROPERTY, "cw-serv01");
mqht.put(CMQC.PORT_PROPERTY, new Integer(5555));
MQQueueManager qMgr = new MQQueueManager("MQA1", mqht);

So, does your head hurt too? Who the #$@#% comes up with this shit?

Regards,
Roger Lacroix
Capitalware Inc.

This entry was posted in HPE NonStop, IBM i (OS/400), IBM MQ, IBM MQ Appliance, Java, Linux, macOS (Mac OS X), Programming, Raspberry Pi, Unix, Windows, z/OS.

Comments are closed.