0
votes

I have a weird problem with Websphere MQ and JMS. There is a PL1 application that puts messages into a queue which are read by my java application (running in tomcat). The problem is that as soon as the PL1 application puts a message in the queue, the java application can't read anything from that queue anymore - as if there weren't any messages in the queue. The MQ Browser on the other hand shows that the messages are indeed there. The queue administrator also tells me that he can't see any errors on the queue by the time I try to fetch the messages.

I've tried to read the messages from the java tomcat application with a listener and also with a custom class reading the messages via the JMS QueueBrowser. Neither way works. For the QueueBrowser for example I even don't get an exception while calling the QueueBrowser.getEnumeration Method.

The funny thing is when the queue is emptied again and a local java test application (and not the PL1 application) puts messages in the queue they can be read by the java tomcat application. As soon as the PL1 application adds a message again all the messages aren't visable anymore for the java tomat application => even those that have been added by the local java test application and worked before.

One important thing to say: The PL1 application is setting message properties on the message handle via MQSETMP:

Use the MQSETMP call to set or modify a property of a message handle.
Syntax

MQSETMP (Hconn, Hmsg, SetPropOpts, Name, PropDesc, Type, ValueLength, Value, Compcode, Reason)

https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_8.0.0/com.ibm.mq.ref.dev.doc/q101910_.htm).

I suppose that that's somehow the reasons for the issues. If the setting "PROPCTL" of the queue is set to "NONE" (instead of "COMPAT") the java application can read the messages from PL1 but the message properties aren't visible. We want to use those message properties though that's why this is not an option for us. We also tried the other possible options for PROPCTL which also didn't work.

Is there anything I can do maybe from the java client side? Are there any possible settings for Websphere MQ classes for java that I can try out?

Websphere MQ-Version: 8

Websphere MQ classes for java version (com.ibm.mq.allclient): 9.0.4.0

Edit

This is a minimal example of the java client fetching the messages via QueueBrowser:

package jmsminimal;

import java.util.Date;
import java.util.Enumeration;

import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.QueueBrowser;
import javax.jms.Session;
import javax.jms.TextMessage;

import com.ibm.mq.jms.JMSC;
import com.ibm.mq.jms.MQQueueConnectionFactory;

public class JMSTest {

    public static void main(String[] args) throws JMSException {

        String hostname = "hostname";
        String channel = "channelname";
        int port = 1414;
        String queueMgr = "queuemgrname";
        String queueName = "queuename";
        String username = "username";
        String password = "";

        MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
        mqQueueConnectionFactory.setHostName(hostname);
        mqQueueConnectionFactory.setChannel(channel);
        mqQueueConnectionFactory.setPort(port);
        mqQueueConnectionFactory.setQueueManager(queueMgr);
        mqQueueConnectionFactory.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);

        Connection connection = mqQueueConnectionFactory.createConnection(username, password);

        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Queue queue = session.createQueue(queueName);
        QueueBrowser browser = session.createBrowser(queue);

        connection.start();

        Enumeration entriesEnum = browser.getEnumeration();

        while (entriesEnum.hasMoreElements()) {

            Message message = (Message) entriesEnum.nextElement();
            TextMessage textMessage = (TextMessage) message;

            System.out.println("*********************************************************");
            System.out.println("JMSMessageID: " + textMessage.getJMSMessageID());
            System.out.println("JMSCorrelationID: " + textMessage.getJMSCorrelationID());
            System.out.println("JMSTimestamp: " + new Date(textMessage.getJMSTimestamp()).toString());

            System.out.println("\nProperties:");
            Enumeration propertiesEnum = textMessage.getPropertyNames();
            while (propertiesEnum.hasMoreElements()) {
                String propertyKey = (String) propertiesEnum.nextElement();
                String propertyValue = textMessage.getObjectProperty(propertyKey).toString();
                System.out.println(propertyKey + "=" + propertyValue);
            }

            System.out.println("\nText: \n" + textMessage.getText());

            System.out.println("*********************************************************\n");

        }

        connection.close();
        session.close();

    }

}

Here the pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example.jms</groupId>
    <artifactId>jmsminimal</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>javax.jms</groupId>
            <artifactId>jms</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>com.ibm.mq</groupId>
            <artifactId>com.ibm.mq.allclient</artifactId>
            <version>9.0.4.0</version>
        </dependency>
    </dependencies>
</project>

As said earlier - this example works only when there are no messages in the queue which are sent by PL1 and contain message properties in the MQHRF2 format. Otherwise the enumeration is empty.

1
can you provide mvp which recreates your issue?user902383
How are the RFH2 headers being generated by the PL1 application? If they are "manually" generating them, then the format could be incorrect? I seem to recall that you need to ensure there is blank space padding in place when generated manually. Do other APIs read the RFH2 header? There are some sample c programs that come with the client and one of those should display the properties.JoshMc
I updated the description - the PL1 developer is using MQSETMP to set the message properties, so the header is not created manually.JanTheGun
Try using a IBM provided sample to read the message, this is written in C. For example: /opt/mqm/samp/bin/amqsbcg SYSTEM.DEFAULT.LOCAL.QUEUE TESTQM 1 (the 1 at the end tells it to format and print the properties). To generate a message with properties use the sample amqsstm SYSTEM.DEFAULT.LOCAL.QUEUE TESTQM, this uses the C MQSETMP function. It will ask for name value pairs for the properties once done press enter for blank property and it will ask for a message text. This lets you know if it is a java specific problem.JoshMc

1 Answers

0
votes

The PL1 application is setting message properties via MQHRF2. I suppose that that's somehow the reasons for the issues.

The MQRFH2 structure is rather complex and not very straight forward. I'm guessing that whoever created the PL/1 program did not correctly create the MQRFH2 strucuture, hence, your Java/JMS application will not recognize it.

Tell your PL/1 programmer to go and download Jsmqput C program from https://capitalware.com/mq_code_c.html It shows how to correctly create an MQRFH2 structure. The big items to note are that all folders MUST align to a 4-byte boundary (pad with blanks).