ibm-messaging / mq-jms-spring

Components to assist MQ JMS integration with Spring frameworks
Apache License 2.0
190 stars 102 forks source link

Reading MQ messages in code with MQRFH2 message format in EBCDIC character set #32

Closed JakesIV closed 5 years ago

JakesIV commented 5 years ago

ibmmq-jms-spring version(s): 2.1.2 Java version (including vendor and platform). 1.8 Windows 10 SpringBoot 2.1.6

I have an issue when reading messages of the queue which is in EBCDIC format. I can see they get handled by MQPoison class and then get backed out to the DLQ. The rest in the queue that is string gets processed successfully.

The error I see when debugging is com.ibm.msg.client.jms.DetailedJMSException: JMSCMQ1000: Failed to create JMS message. The wrong message type or properties were specified when creating a base message with messageID = '414D5120514D31202020202020202020FD7E425D200805ED' and correlationID = '000000000000000000000000000000000000000000000000'. Check the linked IBM MQ exception reason and completion code for more information and check the log file for detailed message contents.

Nothing else gest written to the Springboot application log.

< @Component public class JMSConsumer { Logger log = LoggerFactory.getLogger(JMSConsumer.class);

@JmsListener(destination = "INPUT.QUEUE")
public void onAuditMessage(final Message receivedMessage) {
    BytesMessage bytesMessage = (BytesMessage) receivedMessage;
    byte[] bytesreceived;
    try {
        bytesreceived = new byte[(int) bytesMessage.getBodyLength()];
        bytesMessage.readBytes(bytesreceived);
        // convert to MQMessage then to PCFMessage
        MQMessage mqMsg = new MQMessage();
        mqMsg.write(bytesreceived);
        mqMsg.encoding = receivedMessage.getIntProperty(WMQConstants.JMS_IBM_ENCODING);
        mqMsg.format = receivedMessage.getStringProperty(WMQConstants.JMS_IBM_FORMAT);
        String codePage = receivedMessage.getStringProperty(WMQConstants.JMS_IBM_CHARACTER_SET);

        mqMsg.seek(0);
        log.info("message len " + Integer.toString(mqMsg.getMessageLength()));
        log.info("message encoding " + Integer.toString(mqMsg.encoding));
        log.info("message format " + mqMsg.format);
        log.info("message type " + Integer.toString(mqMsg.messageType));
        log.info("message code page " + codePage);

        try {
            log.info("message content:  " + mqMsg.readStringOfByteLength(mqMsg.getMessageLength()));
        } catch (Exception e) {
            log.info("No message content : " + e.getMessage());
        }

    } catch (JMSException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

}

}

ibmmqmet commented 5 years ago

I suspect the problem is that you are trying to treat a message with an RFH2 as a bytesmessage. When reading a message that a browse (eg amqsbcg) may show as having an RFH2, the JMS code is probably converting that header to properties (they are interchangable) and then the returned message is actually of whatever format was indicated in the RFH2 header - which could well be MQFMT_STR and hence a JMS textMessage not a bytesmessage. The RFH2 contents are then available via getProperty calls instead. You can print the class name of receivedMessage before doing the cast to check that. And it's always good to use if (receivedMessage instanceof ...) before casting as well.

JakesIV commented 5 years ago

But it its not even getting to my code to print anything, its failing way before that. I see the detail messages says. I know the format is sound as we have been processing the message with IIB9 for years. Could it be the custom user attributes. I seem to have read somewhere that JMS don't like that. com.ibm.msg.client.jms.DetailedMessageFormatException: JMSCMQ1050: The MQRFH2 header has an incorrect format. Received a message with a badly formed MQRFH2 header. Ensure that any non-JMS applications building messages with MQRFH2 headers create well-formed MQRFH2 headers.

I have traced it and this is the java trace Thread [DefaultMessageListenerContainer-1] (Suspended (exception DetailedJMSException)) WMQReceiveMarshal.constructProviderMessageFromRFH2(int) line: 444
WMQReceiveMarshal.constructProviderMessageFromProperties(int) line: 166 WMQReceiveMarshal.createProviderMessage(boolean) line: 477
WMQReceiveMarshal.exportProviderMessage(boolean) line: 639
WMQPoison$PoisonMessage.(WMQPoison, MQMD, ByteBuffer[]) line: 1866
WMQPoison$PoisonMessage.(WMQPoison, MQMD, ByteBuffer[], WMQPoison$1) line: 1806
WMQPoison.handlePoisonMessage(MQMD, ByteBuffer[], MQGMO) line: 325
WMQSyncConsumerShadow(WMQConsumerShadow).getMsg(WMQGMO, int, boolean, Pint, Pint) line: 1878
WMQSyncConsumerShadow.receiveInternal(long) line: 230
WMQSyncConsumerShadow(WMQConsumerShadow).receive(long) line: 1466
WMQMessageConsumer.receive(long) line: 674
JmsQueueReceiverImpl(JmsMessageConsumerImpl).receiveInboundMessage(long) line: 1073 JmsQueueReceiverImpl(JmsMessageConsumerImpl).receive(long) line: 691
MQQueueReceiver(MQMessageConsumer).receive(long) line: 209
DefaultMessageListenerContainer(JmsDestinationAccessor).receiveFromConsumer(MessageConsumer, long) line: 132
DefaultMessageListenerContainer(AbstractPollingMessageListenerContainer).receiveMessage(MessageConsumer) line: 418
DefaultMessageListenerContainer(AbstractPollingMessageListenerContainer).doReceiveAndExecute(Object, Session, MessageConsumer, TransactionStatus) line: 303 DefaultMessageListenerContainer(AbstractPollingMessageListenerContainer).receiveAndExecute(Object, Session, MessageConsumer) line: 257
DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener() line: 1189 DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop() line: 1179 DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run() line: 1076
Thread.run() line: 748

ibmmqmet commented 5 years ago

A full trace might give more detailed error information (though that can be extremely verbose and hard to decipher). You said you've got some custom user attributes in the RFH2. Are those in the folder or are you trying to use an alternative folder? How was the RFH2 constructed? IIB does not use the Java classes for parsing these messages, so it's possible your messages do not fit into the JMS constraints. Only the known folders are permitted - usr, jms, mcd, mqext, mqps - in JMS messages.

The output from amqsbcg might also help to ensure the message looks OK.

JakesIV commented 5 years ago

The custom fields are in usr but that is not the problem. it's working fine when the message saved comes from a non ZOS environment. It only fails on the ZOS messages coming from IMS and its copybooks.

ibmmqmet commented 5 years ago

Since this sounds like it's something being done in the MQ JMS classes, you may need to open a support ticket to get it investigated by the service team. Trace and a browse of the offending message are likely to be needed.

JakesIV commented 5 years ago

I was thinking the same thing. I think I will do that. thanks