javaspring-bootibm-mq

Send PCFMessage with JMS


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?


Solution

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