I'm working on something which could be described as custom WMQ message router/forwarder. At the moment I have some very confusing issue with processing JMS messages send over MQ. I'm able to receive message send from Java application over JMS (with MQ as transport) but I'm not able to send message to Java application listening on JMS endpoint.
I have a testing servlet and message driven bean - both hosted in WebSphere Application Server 7.0 (with WebSphere MQ 7.0 used for message transport). Servlet is able to communicate with the bean but if I put my forwarder between them (by reconfiguring the servlet to communicate with forwarder which will reconstruct messages and forward them to bean) the bean is not able to process the request. I have this error in WAS log:
[8/2/12 14:38:51:359 CEST] 00000031 SibMessage W [:] CWSJY0003W: JMSCC0110: An exception '
Message : java.lang.NullPointerException
Class : class java.lang.NullPointerException
Stack : com.ibm.msg.client.wmq.internal.messages.WMQMessageBase._parseMcdFolder(WMQMessageBase.java:445)
: com.ibm.msg.client.wmq.internal.messages.WMQReceiveMarshal.constructProviderMessageFromRFH2(WMQReceiveMarshal.java:341)
: com.ibm.msg.client.wmq.internal.messages.WMQReceiveMarshal.createProviderMessage(WMQReceiveMarshal.java:447)
: com.ibm.msg.client.wmq.internal.messages.WMQReceiveMarshal.exportProviderMessage(WMQReceiveMarshal.java:607)
: com.ibm.msg.client.wmq.internal.WMQConsumerShadow.getMsg(WMQConsumerShadow.java:1115)
: com.ibm.msg.client.wmq.internal.WMQSyncConsumerShadow.receive(WMQSyncConsumerShadow.java:334)
: com.ibm.msg.client.wmq.internal.WMQSession.loadMessageReference(WMQSession.java:1082)
: com.ibm.msg.client.jms.internal.JmsSessionImpl.consume(JmsSessionImpl.java:2847)
: com.ibm.msg.client.jms.internal.JmsSessionImpl.run(JmsSessionImpl.java:2549)
: com.ibm.mq.jms.MQSession.run(MQSession.java:860)
: com.ibm.mq.connector.inbound.WorkImpl.run(WorkImpl.java:172)
: com.ibm.ejs.j2c.work.WorkProxy.run(WorkProxy.java:399)
: com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1604)
[8/2/12 14:38:51:781 CEST] 00000031 SibMessage W [:] CWSJY0003W: MQJCA4004: Message delivery to an MDB 'XXX' failed with exception: 'null'
The message endpoint is automatically paused after this error.
I used RFHUtils to get messages send by both JMS and my app and compared them - there is no real difference in UI (except different delivery mode but that is another story) but when I saved messages to file and compared them I saw this difference (just first RFH2 folder):
Send by JMS directly:
<mcd><Msd>jms_text</Msd></mcd>
Send by my app:
<mcd><Msd dt="string" >jms_text</Msd></mcd>
All elements in RFH2 also contains type. Elements from jms
folder are in different order but according to exception the problem should be directly with mcd
folder. I'm not sure how to better diagnose the issue - I've tried to configure tracing for JMS but I don't know how to do that for WAS (I used WAS on Tuesday for the first time). Standard MQ trace doesn't provide any more information.
My .NET code (WMQ API using MQ Client 7.5 - amqmdnet.dll 7.5.0.0) is quite complex but it generally does:
Receiver
- Receive
MQMessage
message by standardGet
call onMQQueue
accessed withMQOO_INPUT_AS_Q_DEF
(no special get options) - Read all message headers from received
MQMessage
- Uses
GetPropertyNames("%")
to get names of all message properties - Uses
GetObjectProperty
to get values for every property - If message format is
MQSTR
reads body byReadString
otherwise byReadBytes
Sender
- Creates
MQMessage
- Sets all meaningful message headers from received
MQMessage
- for exampleMessageId
,ReplyToQueue
name and some other are not copied - new or correct values are used instead - Sets all properties from received
MQMessage
by usingSetObjectProperty
- this step contains some magic because .NET API is inconsistent and the type of value returned fromGetObjectProperty
is not always accepted bySetObjectProperty
- typically I receiveString
but I must passint
orlong
(examples: JmsDeliveryMode, JmsPriority or JmsTimestamp). This step also overrides destinations for JmsDestination and JmsReplyTo - Write body of the message either by
WriteString
orWriteBytes
Put
message toMQQueue
accessed withMQOO_OUTPUT
(no special put options)
I don't create RFH2 structure manually - I let MQ infrastructure to deal with it. So my question: How to create valid JMS message from .NET which will be accepted by message driven bean?
Note: I don't want to use IBM.XMS - this decision was made long time ago because of some article in IBM knowledge base describing pros and cons of both XMS and WMQ. I need to support both JMS and non-JMS messaging.