Stephaneuh
Stephaneuh

Reputation: 31

Mainframe MQ to Standalone JMS in EBCDIC

From a Java app I'm trying to browse messages from a mainframe IBM MQ queue (EBCDIC messages). I need to browse messages, not consume them. Here is the code:

JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.WMQ_PROVIDER);
JmsConnectionFactory cf = ff.createConnectionFactory();

// Set properties
cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, host);
cf.setIntProperty(WMQConstants.WMQ_PORT, port);
cf.setStringProperty(WMQConstants.WMQ_CHANNEL, channel);
cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, qmgr);
cf.setIntProperty(WMQConstants.WMQ_RECEIVE_CONVERSION, WMQConstants.WMQ_RECEIVE_CONVERSION_QMGR);

QueueBrowser browser = context.createBrowser(context.createQueue("queue:///" + queueName  + "?targetClient=1"));
Enumeration enumeration = browser.getEnumeration();

while (enumeration.hasMoreElements()) {
    TextMessage messageInTheQueue = (TextMessage) enumeration.nextElement();
    System.out.println(messageInTheQueue);
    nbRecords++;
}

The result of System.out.println() looks like:

  JMSMessage class: jms_text
  JMSType:          null
  JMSDeliveryMode:  2
  JMSMessageID:     ID:c1d4d840d4d8e3c1e2f24040404040405e2432bd21aa1b02
  JMSTimestamp:     1579537307450
  JMSRedelivered:   false
    JMSXAppID:  
    JMSXDeliveryCount: 1
    JMSXUserID:    
    JMS_IBM_Character_Set: IBM037
    JMS_IBM_Encoding: 273
    JMS_IBM_Format: MQSTR   
    JMS_IBM_MsgType: 8
    JMS_IBM_PutApplType: 8
    JMS_IBM_PutDate: 20200120
    JMS_IBM_PutTime: 16214745
ÍÍÑÀ ...

I would like to convert this EBCDIC message ÍÍÑÀ ... to something readable (ASCII).

I tried to cast enumeration.nextElement() to JMSByteMessage but get this exception:

class com.ibm.msg.client.jms.internal.JmsTextMessageImpl cannot be cast to class com.ibm.jms.JMSBytesMessage

How could I do that?

Solution: Use the MQ classes for Java instead of the MQ JMS classes for Java:

byte[] strData = new byte[theMessage.getMessageLength()];
theMessage.readFully(strData, 0, theMessage.getMessageLength());

Some example here: https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.5.0/com.ibm.mq.dev.doc/q030840_.htm

Upvotes: 3

Views: 893

Answers (1)

root
root

Reputation: 362

Regarding the OP's original code, the following documentation states that receive conversion & CCSID are only valid for the MQDestination class: https://www.ibm.com/docs/en/ibm-mq/9.2?topic=reference-properties-mq-classes-jms-objects

Therefore this can be done with the IBM MQ Classes for JMS. You just have to do it in a more round-about fashion.

In order to make the QueueBrowser read EBCDIC formatted messages, you need to cast the JMS Queue to MQDestination, then set the receiveConversion & receiveCCSID, then when creating the browser, cast the MQDestination back to regular JMS Queue. Like so:

JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.WMQ_PROVIDER);
JmsConnectionFactory cf = ff.createConnectionFactory();

// Set properties
cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, host);
cf.setIntProperty(WMQConstants.WMQ_PORT, port);
cf.setStringProperty(WMQConstants.WMQ_CHANNEL, channel);
cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, qmgr);

JMSContext context = cf.createContext();
MQDestination targetQueue = (MQDestination) context.createQueue("queue:///" + queueName)
targetQueue.setReceiveCCSID(WMQConstants.CCSID_UTF8);
targetQueue.setReceiveConversion(WMQConstants.WMQ_RECEIVE_CONVERSION_QMGR);
targetQueue.setMessageBodyStyle(WMQConstants.WMQ_MESSAGE_BODY_MQ);
QueueBrowser browser = context.createBrowser((Queue) targetQueue);
Enumeration enumeration = browser.getEnumeration();

while (enumeration.hasMoreElements()) {
    TextMessage messageInTheQueue = (TextMessage) enumeration.nextElement();
    System.out.println(messageInTheQueue);
    nbRecords++;
}

You also don't need to use the JMS URI properties for setting the target client when doing it this way, as MQDestination has all the necessary getters/setters to modify loads of properties that would otherwise be done with a URI.

For more information on MQDestination, consult the following docs: https://www.ibm.com/docs/en/ibm-mq/9.2?topic=jms-mqdestination

Upvotes: 1

Related Questions