XI JMS Adapter and IBM Websphere MQ: FAQ
1) My JMS adapter channel is unable to connect to Websphere MQ.
Answer: You need to ensure that the correct Websphere MQ JMS libraries have been bundled in your SAP Library aii_af_jmsproviderlib.sda (releases 3.0/7.0) or aii_adapter_lib.sda (releases 7.1) deployed on your PI/XI server. Please check Note: 747601
2) My aii_af_jmsproviderlib.sda (3.0/7.0) / aii_adapter_lib (7.1) contains the correct MQ jars. But my channel is still unable to connect to Websphere MQ.
Answer: Please compare the error text in the channel monitoring screen with the following error messages and follow the suggestion given in their corresponding troubleshooting tip. In case the error text in the channel monitoring is truncated (due to limited space), please activate logging (described in Section 4 of the SAP 856346) and check the relevant traces in the trace file.
The error messages below are those that are produced by the Websphere MQ JMS driver. For a comprehensive listing of such messages and error codes, please check the IBM Websphere MQ Information Center. (Please navigate to this for your Websphere QM release from the IBM Websphere MQ Library page at http://www-306.ibm.com/software/integration/wmq/library/). Please navigate to the topic "API Completion codes and reason codes" within the book "Messages" inside the information center.
javax.jms.JMSException: MQJMS200X: failed to create MQQueueManager for '<host>:<QueueManagerName>'
com.ibm.mq.MQException: MQJE001: An MQException occurred: Completion Code 2, Reason 2058
MQJE036: Queue manager rejected connection attempt
This usually indicates that your queue manager name was incorrect.
Error Message: javax.jms.JMSException: MQJMS2005: failed to create MQQueueManager for '<Host>:<QueueManagerName>'
com.ibm.mq.MQException: MQJE001: An MQException occurred: Completion Code 2, Reason 2009
MQJE016: MQ queue manager closed channel immediately during connect
Closure reason = 2009
Tip: This usually indicates that your channel name was incorrect of that you did not specify a channel of type SVRCONNN (server connection) in the channel field on your JMS channel configuration.
com.ibm.mq.MQException: MQJE001: An MQException occurred: Completion Code 2, Reason 2195
MQJE018: Protocol error - unexpected segment type received
Tip: This usually indicates that your queue manager is down.
3) I have MQ message properties that are of significance. How do I get this data into XI? How do I get this data out of XI?
Answer: Please first read the answer to the same question in Note 856346.
Websphere MQ has the limitation that its support for message properties is complete ONLY in JMS compliant mode. MQ has two modes - legacy/native mode and a JMS compliant mode. The difference between these two modes lies in the presence of an extra MQ message header - the MQRFH2 header - that is present in JMS compliant messages. (Please see references). Without this header, an MQ message cannot support custom JMS message properties. Without this header, the values of standard JMS headers such as the JMSCorrelationID are contained in 24 bit arrays as opposed to strings of arbitrary length in JMS compliant messages.
If you wish to transfer the values of custom JMS message properties , then you need to check that you are using the "JMS compliant" setting in your channel configuration and also ensure that your external application can support and exchange JMS compliant messages.
If your external application is a legacy/mainframe application, the chances are that it would not support JMS compliant messages, and hence you would probably be restricted to the "Websphere MQ" mode (the legacy mode) setting.
4) How do I achieve message correlation for Websphere MQ? / My sync-async/async-sync bridge does not appear to function for Websphere MQ.
Answer: Please first read the answer to the same question in Note 856346.
Message correlation with Websphere MQ fundamentally involves a number of assumptions on the MQ side all of which need to be satisfied in order for it to work fine.
There are 2 modes in which MQ operates - the legacy mode (which shows up as 'Websphere MQ' mode in your channel configuration) and the JMS compliant mode.
These two modes are mainly distinguished by
a) the presence of an extra header MQRFH2 in the MQ Message
b) Identifier lengths and format
a) The MQRFH2 header which is present only in JMS compliant messages is used to carry JMS additional message properties/headers. For example, you could define a message property 'PurchaseOrderId' of type String and set its value in a JMS mesage.
b) In native mode, identifier lengths are 24 bit in size and formats are stricly byte arrays. Now, this obviously causes a problem in mapping XI identifiers to MQ identifiers - because XI identifiers are strings and are 32 bit in size. In JMS compliant mode, identifier lengths are unbounded in size and can be of various types- strings, integers, bytes, etc.
Usually if you are communicating with some legacy application (present on a mainframe environment), MQ operates in legacy mode - i.e., it exchanges MQ Messages without the MQRFH2 header. Your MQ administrator or legacy application developer/maintainer would be the best person to ask about this.
Lets consider correlation in the JMS compliant case, before moving to the more complicated MQ native mode case.
In the JMS compliant case, correlation is fairly simple. One just needs to configure the receiver JMS channel to send out a JMS message with the value of some JMS header (usually the 'JMScorrelationID') to the value of some XI message header (usually the 'XIConversationID' or 'XIMessageID'). Let us say that this value is 'c'. The receiver JMS channel will process the XI message, convert it to a JMS message and put it on some request queue, say 'q1'. Your application will then pick it from this queue, process the message (do some business operation) and put the response message in a reply queue, say 'q2'.
Axiom for JMS compliant message correlation: It is assumed that your application will _not_ modify the value of the 'JMSCorrelationId' in any way while doing so, i.e. the value 'c' should be retained as the JMSCorrelationID of the response message.
Now, one can configure the sender JMS communication channel to retrives messages from the reply queue 'q2'. And one can specify that the 'XIConversationID' should be set to the 'JMSCorrelationID'. So, when the reply JMS message is picked up from q2 and transformed into an XI message, its 'XIConversationID' header is set to the value 'c'.
Lets now consider correlation in the MQ native mode case. Lets assume you have configured the JMS sender channel to put request messages into a JMS queue 'q1' and to set the 'JMSCorrelationID' to the 'XIConversationID'. For native mode, we cannot simply copy the value of the 'XIconversationID' header of the XI message into the 'JMScorrelationID' of the JMS message. This is because of restriction b) mentioned earlier. The 'XIConversationId' is a 32 bit string and the 'JMSCorrelationID' in MQ native mode is a 24 bit array.
So, how do we achieve correlation? We store a mapping between the the value 'c' and the 'JMSMessageID' of the request JMS message that is finally sent out and put in 'q1'. The 'JMSMessageID' of a message in native mode is a 24 bit unique value that is generated by MQ. Lets say this value is 'x'. So, in a database table we have a row of the form:
ID1 | ID2
'c' | 'x' <---- Row 'N'
The above mapping is enabled by checking 'Store JMSCorrelationID of request' in the JMS sender channel. (We use MessageIDMapper from the XI API to achieve this in the code)
The above mapping is enabled by checking 'Store JMSCorrelationID of request' in the JMS sender channel.
Axiom for MQ native message correlation: We assume that in native mode all legacy applications _obey_ the standard MQ protocol. The standard MQ protocol for a legacy application is that the 'JMSMessageID' of a request message is copied into the 'JMSCorrelationID' of the response message. What this means for us is that, for an JMS/MQ message picked up from the request queue 'q1', the value of its 'JMSMessageID' which is 'x' should be copied into the 'JMSCorrelationID' of the response which is put into response queue 'q2'.
For native correlation, the receiver channel should be configured to pick up messages from the response queue 'q2' _and_ should have the line 'Set XIConversationID to Stored JMSCorrelationID of request'. When a message is picked from 'q2', the value of its 'JMSCorrelationID' is looked at. This should be 'x'. The adapter looks at the database table, searches for a row with the value 'x', and sees Row 'N', and picks up the mapped value 'c'. This value 'c' is the "Stored JMSCorrelationID of request". So the XIConversationID is set to this value.
The HOW-To guide on "Howto Correlate JMS" omits these obtuse details details for the sake of simplicity and takes the safe route of always advising the user to enable the "Store" options as described above. Unfortunately, this is not necessary for the "JMS compliant mode" and can cause confusion if you are actually using your JMSCorrelationID for other purposes.
5) Does the JMS adapter support the facilities offered by the MQ headers 'ReplyToQMgr' and 'ReplyToQ'?
Answer: No, the adapter doesn't directly support these provider specific headers. However, the adapter does support the semantics of 'JMSReplyTo', which can be used to achieve the same function for JMS compliant messages. Your 'JMSReplyTo' destination would be of the form:
queue://<ReplyToQMgr>/<ReplyToQ>. Please see "Mapping JMS messages onto WebSphere MQ messages" and "How to create queue manager and reply-to aliases" in references.
6) My MQ message contain special characters like ö,ä etc/line endings/packed decimals. The JMS adapter is messing up with these characters.
Answer:Please confirm that that you have messages of type 'TextMessage' and not 'ByteMessage' on the queue from which the sender adapter is picking up messages. You can confirm the message type by using a utility like 'rfh2util' (part of the Websphere MQ utility programs pack), and checking the 'MQMD.Format' field. This should have 'MQSTR' within in.
If you are sending messages of type 'ByteMessage' (for which the 'MQMD.Format' field is generally set to 'NONE' or is empty) then you need to ensure that the byte sequence is UTF-8 encoded - since the JMS adapter assumes this encoding for all ByteMessage's.
If you are sending 'TextMessages' and you still observe decoding issues (special characters/newlines/numerics) getting messed up or errors being thrown, then this indicates that the CCSID specified in the underlying MQMessage does not match the actual encoding of the message payload. (i.e. MQMD.CodedCharSetId is not the _actual_ encoding of the payload). The root cause for this can be due to a wide variety of reasons.
7) I have JMS byte messages on a queue. I have a JMS sender channel that retrieves these messages. However, the corresponding XI/PI messages all have empty payloads!
This occurs when the when byte stream marker position is not set to the end of the stream for these messages. For JMS byte messages, the JMS adapter retrieves the content using the JMS API method 'readBytes()'. If the stream marker is set to the end of the stream, then the payload of the XI message would be empty.
The root cause of such an issue is highly dependent on your scenario.
For example, one of the many ways in which this situation could occur - You have a loader program/utility that constructs a byte message and that component does not call 'reset()' on the message object to reposition the byte stream marker position to the beginning of the payload.
1) J2EE JMS Adapter: Frequently Asked Questions (FAQ)
SAP Note 856346
2) The IBM Websphere MQ Library: http://www-306.ibm.com/software/integration/wmq/library/
3) The MQRFH2 header in Websphere MQ 6.0
4) How-to Guide: How to Correlate JMS
The guide is available from SDN (https://www.sdn.sap.com) under the navigation hierarchy:
SAP Netweaver > Process Integration > How-to Guides.> Exchange Infrastructure
5) Mapping JMS messages onto WebSphere MQ messages
6) How to write ReplytoQmgr using JMS API ?
7) How to create queue manager and reply-to aliases