使用JMS调用IBM MQ时主机返回2110 MQRC格式错误,请求代码校验
问题描述
因IBM系统迁移,原使用的连接池管理器已不再受支持,我正在寻找替代的消息发送方案。现将原有MQ消息发送代码转换为JMS代码,但不确定转换格式是否正确,测试时主机端返回2110 MQRC FORMAT ERROR,请帮忙校验转换是否准确。
原有MQ代码
MQMessage reqMsg = new MQMessage(); reqMsg.messageId = CMQC.MQMI_NONE; reqMsg.correlationId = CMQC.MQCI_NEW_SESSION; reqMsg.userId = racfUserid; reqMsg.characterSet = CHARSET_IBM500; reqMsg.persistence = persistence; // ---- create request message String result = ""; byte blanks[] = new byte[8]; for (int i=0; i<blanks.length; i++) blanks[i] = (byte)' '; reqMsg.clearMessage(); // ---- write MQCIH reqMsg.writeString ("CIH "); // MQCHAR4 StrucId; reqMsg.writeInt (2); // MQLONG Version; reqMsg.writeInt (180); // MQLONG StrucLength; reqMsg.writeInt (reqMsg.encoding); // MQLONG Encoding; MQPutMessageOptions pmo = new MQPutMessageOptions(); pmo.options = CMQC.MQPMO_NEW_MSG_ID | CMQC.MQPMO_SET_IDENTITY_CONTEXT | CMQC.MQPMO_FAIL_IF_QUIESCING; requestQueue.put (reqMsg, pmo);
转换后的JMS代码
Hashtable<String, String> environment = new Hashtable<String, String>(); environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory"); Context context = new InitialContext(environment); ConnectionFactory connectionFactory = (ConnectionFactory) context .lookup("name"); Destination requestQueue = (Destination) context .lookup(requestQueueName); Connection connection = connectionFactory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Destination replyQueue = (Destination) context .lookup(replyToQueueName); context.close(); MessageProducer producer = session.createProducer(requestQueue); BytesMessage message = session.createBytesMessage(); message.setJMSMessageID(MQConstants.MQMI_NONE.toString()); message.setJMSCorrelationIDAsBytes(MQConstants.MQCI_NEW_SESSION); message.setJMSReplyTo(replyQueue); message.setStringProperty("JMS_IBM_MQMD_UserIdentifier", racfUserid); message.setIntProperty("JMS_IBM_MQMD_CodedCharSetId", byte blanks[] = new byte[8]; for (int i = 0; i < blanks.length; i++) blanks[i] = (byte) ' '; // Construct the CIH header as a byte array ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); DataOutputStream outData = new DataOutputStream(outBytes); outData.writeBytes("CIH "); // MQCHAR strucId outData.writeInt(2); // MQLONG version outData.writeInt(180); // MQLONG strucLength outData.writeInt(messageEncoding); // MQLONG encoding outData.writeInt(CHARSET_IBM500); // MQLONG CodedCharSetId; StringBuffer pgmName = new StringBuffer(progName); for (int i = pgmName.length(); i < 8; i++) pgmName.append(' '); outData.writeBytes(pgmName.substring(0, 8)); outData.writeBytes(commArea); byte[] cihRequestMessage = outBytes.toByteArray(); message.writeBytes(cihRequestMessage); producer.send(message); MessageConsumer consumer = session.createConsumer(replyQueue); Message replyMessage = consumer.receive(replyTimeout * 1000);
问题排查与修正建议
以下是转换代码中存在的几个关键问题,这些可能是导致2110 MQRC FORMAT ERROR的原因:
1. 未完成的代码行
JMS代码中这一行未完成,缺少属性值:
message.setIntProperty("JMS_IBM_MQMD_CodedCharSetId",
需补充为:
message.setIntProperty("JMS_IBM_MQMD_CodedCharSetId", CHARSET_IBM500);
2. CIH结构长度不匹配
原MQ代码中设置CIH的StrucLength为180字节,但JMS代码中额外写入了CodedCharSetId、程序名(pgmName)和commArea,导致实际生成的CIH结构长度远超180字节。主机端会校验结构长度,不匹配就会触发格式错误。
需严格按照原MQ代码的CIH写入逻辑,仅写入原代码中的四个字段:StrucId、Version、StrucLength、Encoding,不要额外添加其他字段。
3. 消息ID设置错误
原MQ代码中reqMsg.messageId = CMQC.MQMI_NONE是让MQ自动生成新消息ID,对应JMS中不需要手动设置JMSMessageID(默认由系统生成)。当前代码中用字符串设置的方式错误,应改为字节数组方式,或者直接省略(因为MQPMO_NEW_MSG_ID对应JMS默认行为):
// 错误写法 message.setJMSMessageID(MQConstants.MQMI_NONE.toString()); // 正确写法(可选,实际可省略) message.setJMSMessageIDAsBytes(MQConstants.MQMI_NONE);
4. 缺失持久化设置
原MQ代码设置了reqMsg.persistence = persistence,但JMS代码中未对应设置消息的持久化模式,需补充:
int jmsDeliveryMode = (persistence == CMQC.MQPER_PERSISTENT) ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT; message.setJMSDeliveryMode(jmsDeliveryMode);
5. 身份上下文未设置
原MQ代码中PMO包含CMQC.MQPMO_SET_IDENTITY_CONTEXT选项,该选项会将消息的身份上下文设置为当前用户,JMS中需对应设置属性:
message.setStringProperty("JMS_IBM_MQMD_IdentityContext", racfUserid);
6. 编码值一致性问题
原MQ代码中使用reqMsg.encoding(MQ消息的默认编码),JMS代码中的messageEncoding需确保与原代码的reqMsg.encoding值一致,建议直接使用CMQC.MQENC_NATIVE或原代码对应的编码常量。
内容的提问来源于stack exchange,提问作者Sheela

