I'm trying to write an application to query the statistics of the IBM MQ queues in Spring Boot.
To do so, I'm using
<dependency>
<groupId>com.ibm.mq</groupId>
<artifactId>mq-jms-spring-boot-starter</artifactId>
<version>3.5.3</version>
</dependency>
and, by following this documentation https://www.ibm.com/docs/en/ibm-mq/9.4.x?topic=package-using-mq-classes-jms, I wrote the following demo code
Queue inputQueue = jmsTemplate.execute(session -> {
var queue = session.createQueue("SYSTEM.ADMIN.COMMAND.QUEUE");
((MQQueue) queue).setIntProperty(WMQConstants.WMQ_MESSAGE_BODY, WMQConstants.WMQ_MESSAGE_BODY_MQ);
((MQQueue) queue).setMQMDWriteEnabled(true);
return queue;
});
try {
BytesMessage msg = (BytesMessage) jmsTemplate.sendAndReceive(inputQueue, ActuatorExtConfig::build);
var bytes = new byte[(int) msg.getBodyLength()];
var bais = new ByteArrayInputStream(bytes);
var dis = new DataInputStream(bais);
var out = new PCFMessage(dis);
out.getParameterValue(CMQCFC.MQCACF_Q_NAMES);
System.out.println(out);
} catch (Exception ex) {
ex.printStackTrace();
}
private static Message build(Session session) {
PCFMessage request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_Q_NAMES);
request.addParameter(CMQC.MQCA_Q_NAME, "*");
var baos = new ByteArrayOutputStream();
try (baos; var das = new DataOutputStream(baos)) {
request.write(das);
baos.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
var m = session.createBytesMessage();
m.setJMSPriority(-1);
m.setJMSDeliveryMode(DeliveryMode.NON_PERSISTENT);
m.writeBytes(baos.toByteArray());
m.setIntProperty(WMQConstants.JMS_IBM_MQMD_MSGTYPE, 1);
m.setIntProperty(WMQConstants.JMS_IBM_MQMD_FEEDBACK, 0);
m.setIntProperty(WMQConstants.JMS_IBM_MQMD_PERSISTENCE, CMQC.MQPER_NOT_PERSISTENT);
m.setIntProperty(WMQConstants.JMS_IBM_MQMD_EXPIRY, 300);
m.setIntProperty(WMQConstants.JMS_IBM_MQMD_REPORT, CMQC.MQRO_PASS_CORREL_ID);
m.setIntProperty(WMQConstants.JMS_IBM_MQMD_ENCODING, CMQC.MQENC_NATIVE);
m.setIntProperty(WMQConstants.JMS_IBM_MQMD_CODEDCHARSETID, 1208);
m.setIntProperty(WMQConstants.JMS_IBM_MQMD_PRIORITY, -1);
m.setStringProperty(WMQConstants.JMS_IBM_MQMD_FORMAT, CMQC.MQFMT_ADMIN);
return m;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
but the response I get back is basically empty
PCFMessage:
MQCFH (com.ibm.mq.headers.internal.store.ByteStore [encoding: 0x00000111, ccsid: 0, size: 36] @56757931)
MQLONG Type: 0 (0x00000000)
MQLONG StrucLength: 0 (0x00000000)
MQLONG Version: 0 (0x00000000)
MQLONG Command: 0 (0x00000000)
MQLONG MsgSeqNumber: 0 (0x00000000)
MQLONG Control: 0 (0x00000000)
MQLONG CompCode: 0 (0x00000000)
MQLONG Reason: 0 (0x00000000)
MQLONG ParameterCount: 0 (0x00000000)
while the same query, executed with the PCFMessageAgent like below
System.setProperty("java.library.path", "/opt/mqm/java/lib64");
System.setProperty("javax.net.ssl.trustStore", props.getJks().getTrustStore());
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", Boolean.FALSE.toString());
MQEnvironment.hostname = "my-host";
MQEnvironment.port = 15003;
MQEnvironment.channel = props.getChannel();
MQEnvironment.sslCipherSuite = props.getSslCipherSpec();
MQEnvironment.userID = props.getUser();
MQEnvironment.password = props.getPassword();
try {
var queueManager = new MQQueueManager(props.getQueueManager());
PCFMessageAgent agent = new PCFMessageAgent(queueManager);
PCFMessage request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_Q_NAMES);
request.addParameter(CMQC.MQCA_Q_NAME, "*");
PCFMessage[] responses = agent.send(request);
System.out.println(responses[0]);
queueManager.close();
} catch (Exception e) {
e.printStackTrace();
}
returns the correct response (the list of the available queues in this case).
What am I missing so that it could work also with JMS?
In the end, the issue was caused by an encoding and/or format mismatch between the IBM MQ server and the JMS client machine.
Changing the parsing of the response as follows fixed the issue:
BytesMessage msg = (BytesMessage) jmsTemplate.sendAndReceive(inputQueue, ActuatorExtConfig::build);
byte[] bytes = new byte[(int) msg.getBodyLength()];
msg.readBytes(bytes);
MQMessage mqMsg = new MQMessage();
mqMsg.write(bytes);
mqMsg.encoding = msg.getIntProperty(WMQConstants.JMS_IBM_ENCODING);
mqMsg.format = msg.getStringProperty(WMQConstants.JMS_IBM_FORMAT);
mqMsg.seek(0);
var out = new PCFMessage(mqMsg);