JMS 应用程序无法读取 PL1 应用程序创建的 MQ 消息
JMS application can't read MQ Messages created by PL1 application
我在使用 Websphere MQ 和 JMS 时遇到了一个奇怪的问题。
有一个 PL1 应用程序将消息放入队列中,该队列由我的 java 应用程序(运行 in tomcat)读取。
问题是,一旦 PL1 应用程序将消息放入队列,java 应用程序就无法再从该队列中读取任何内容——就好像队列中没有任何消息一样。
另一方面,MQ 浏览器显示消息确实存在。队列管理员还告诉我,当我尝试获取消息时,他看不到队列中有任何错误。
我尝试使用侦听器从 java tomcat 应用程序读取消息,还尝试使用自定义 class 通过 JMS QueueBrowser 读取消息。两种方法都行不通。例如,对于 QueueBrowser,我什至在调用 QueueBrowser.getEnumeration 方法时都没有出现异常。
有趣的是,当队列再次清空时,本地 java 测试应用程序(而不是 PL1 应用程序)将消息放入队列中,它们可以被 java tomcat 申请。
一旦 PL1 应用程序再次添加一条消息,所有消息对于 java tomat 应用程序都不再可见 => 即使是那些已由本地 java 测试应用程序添加并且之前有效的消息。
有一件重要的事情要说:PL1 应用程序正在通过 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)。
我想这就是问题的某种原因。
如果队列的设置 "PROPCTL" 设置为 "NONE"(而不是 "COMPAT"),java 应用程序可以从 PL1 读取消息,但消息属性不可见。
我们想使用这些消息属性,但这就是为什么这不是我们的选择。我们还尝试了 PROPCTL 的其他可能选项,但也没有用。
我可以从 java 客户端做些什么吗? Websphere MQ classes for java 是否有我可以尝试的任何可能设置?
Websphere MQ 版本: 8
Websphere MQ classes for java version (com.ibm.mq.allclient): 9.0.4.0
编辑
这是 java 客户端通过 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();
}
}
这里是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>
如前所述 - 此示例仅在队列中没有由 PL1 发送且包含 MQHRF2 格式的消息属性的消息时才有效。否则枚举为空。
The PL1 application is setting message properties via MQHRF2. I
suppose that that's somehow the reasons for the issues.
MQRFH2 结构相当复杂而且不是很简单。我猜测创建 PL/1 程序的人没有正确创建 MQRFH2 结构,因此,您的 Java/JMS 应用程序将无法识别它。
告诉你的 PL/1 程序员去下载 Jsmqput C 程序 https://capitalware.com/mq_code_c.html 它展示了如何正确创建 MQRFH2 结构。需要注意的大项目是所有文件夹必须对齐到 4 字节边界(用空格填充)。
我在使用 Websphere MQ 和 JMS 时遇到了一个奇怪的问题。 有一个 PL1 应用程序将消息放入队列中,该队列由我的 java 应用程序(运行 in tomcat)读取。 问题是,一旦 PL1 应用程序将消息放入队列,java 应用程序就无法再从该队列中读取任何内容——就好像队列中没有任何消息一样。 另一方面,MQ 浏览器显示消息确实存在。队列管理员还告诉我,当我尝试获取消息时,他看不到队列中有任何错误。
我尝试使用侦听器从 java tomcat 应用程序读取消息,还尝试使用自定义 class 通过 JMS QueueBrowser 读取消息。两种方法都行不通。例如,对于 QueueBrowser,我什至在调用 QueueBrowser.getEnumeration 方法时都没有出现异常。
有趣的是,当队列再次清空时,本地 java 测试应用程序(而不是 PL1 应用程序)将消息放入队列中,它们可以被 java tomcat 申请。 一旦 PL1 应用程序再次添加一条消息,所有消息对于 java tomat 应用程序都不再可见 => 即使是那些已由本地 java 测试应用程序添加并且之前有效的消息。
有一件重要的事情要说:PL1 应用程序正在通过 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)。
我想这就是问题的某种原因。 如果队列的设置 "PROPCTL" 设置为 "NONE"(而不是 "COMPAT"),java 应用程序可以从 PL1 读取消息,但消息属性不可见。 我们想使用这些消息属性,但这就是为什么这不是我们的选择。我们还尝试了 PROPCTL 的其他可能选项,但也没有用。
我可以从 java 客户端做些什么吗? Websphere MQ classes for java 是否有我可以尝试的任何可能设置?
Websphere MQ 版本: 8
Websphere MQ classes for java version (com.ibm.mq.allclient): 9.0.4.0
编辑
这是 java 客户端通过 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();
}
}
这里是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>
如前所述 - 此示例仅在队列中没有由 PL1 发送且包含 MQHRF2 格式的消息属性的消息时才有效。否则枚举为空。
The PL1 application is setting message properties via MQHRF2. I suppose that that's somehow the reasons for the issues.
MQRFH2 结构相当复杂而且不是很简单。我猜测创建 PL/1 程序的人没有正确创建 MQRFH2 结构,因此,您的 Java/JMS 应用程序将无法识别它。
告诉你的 PL/1 程序员去下载 Jsmqput C 程序 https://capitalware.com/mq_code_c.html 它展示了如何正确创建 MQRFH2 结构。需要注意的大项目是所有文件夹必须对齐到 4 字节边界(用空格填充)。