Reputation: 364279
I'm trying to consume JMS messages send over WebSphere MQ (WebSphere MQ Server v7) by .NET application using .NET WMQ API. I'm using WebSphere MQ Client v7.5 and amqmdnet.dll version 7.5.0.0.
There is some very strange behavior when reading JMSDeliveryMode
property (Dlv
property from jms
RFH2 folder). The property value send by JMS application (servlet hosted in WebSphere Application Server v7) is set to Persistent
(2) but my .NET client always reads 1 (which means Non_persistent
). I need to read the correct value because my .NET application works as router/forwarder and it must forward message with correct configuration.
I tried to simulate JMS messages using RFHUtils. When I set delivery mode to 1 and send it to my .NET client it again reads 1 but if I also change persistence of MQ message in MQMD it reads 0. It looks like the value in JMSDeliveryMode
is not used at all and .NET client always reads value from Persistence
property but it is incorrect behavior! These two properties have different ranges of correct values:
JMSDeliveryMode
correct values (from jms.jar):
DeliveryMode.NON_PERSISTENT
DeliveryMode.PERSISTENT
Persistence
correct values (from amqmdnet.dll):
MQC.MQPER_NOT_PERSISTENT
MQC.MQPER_PERSISTENT
MQC.MQPER_PERSISTENCE_AS_Q_DEF
/ MQC.MQPER_PERSISTENCE_AS_TOPIC_DEF
Upvotes: 0
Views: 2228
Reputation: 15273
Values for Persistence in MQ .NET is correct and you can compare with cmqc.h
header file as both amqmdnet and C MQI are both MQ native APIs.
0 - MQC.MQPER_NOT_PERSISTENT
1 - MQC.MQPER_PERSISTENT
2 - MQC.MQPER_PERSISTENCE_AS_Q_DEF / MQC.MQPER_PERSISTENCE_AS_TOPIC_DEF
The jms.jar DeliveryMode enumeration has defined a different value. I would imagine MQ JMS implementation would internally handle this appropriately and set correct MQ specific values in MQMD and RFH2 properties.
Regarding your test using RFH2Util. Values set in MQMD tab and JMS could be different. You can set DeliveryMode to 1 in JMS tab and Persistent Msg to No
in MQMD tab. When a message is put, MQMD.Persistence will show up as 0
and JMSDeliveryMode will show up as 1. I confirmed this values by viewing message in MQ Explorer. The MQ .NET API is just giving you what it got from the message. As far as I know RFHUtil is a tool to set RFH properties. It simply sets/gets RFH properties. It does not have the intelligence of a MQ JMS implementation.
In my opinion "JMSxxxx" properties are best handled by a JMS implementation and not by a native implementation like MQ .NET.
Upvotes: 0
Reputation: 364279
It is again bug in IBM's amqmdnet.dll. After disassembling the library with .NET Reflector and checking the code responsible for reading JMS properties (GetJmsProperty
private method of MQMessage
class) I found this:
if (name.Equals("JMSDeliveryMode"))
{
// Properties never contain the property with such name!
if (this.properties.ContainsKey("JMSDeliveryMode"))
{
...
}
return this.Persistence; // Executes always
}
The problem is that properties
collection never contains any property with JMSDeliveryMode
as a key. properties
collection contains RFH2 headers in format RFH2Folder.RFH2PropertyName. The correct property name for JMSDeliveryMode
is jms.Dlv
! Interestingly GetJmsHeader
method reads all JMS properties and all other properties use correct RFH2 name when searching in properties collection!
The situation was even worse when I checked the reverse operation - private method SetJmsProperty
from MQMessage
class. Setting JMSDeliveryMode
contains this code:
else if (name.Equals("JMSDeliveryMode"))
{
if (value is int)
{
int num2 = Convert.ToInt32(value);
switch (num2)
{
// Non persistent JMS message creates persistent MQ message
case 1:
this.Persistence = 1;
break;
// Invalid value for JMS delivery mode
case 0:
this.Persistence = 0;
break;
// Great if I try to create persistent JMS message I will
// get MQRC_PERSISTENCE_ERROR exception!
default:
base.throwNewMQException(2, 0x7ff);
break;
}
queue.Enqueue(num2);
// Correct RFH2 identifier is used
this.properties.Add("jms.Dlv", queue);
}
else
{
base.throwNewMQException(2, 0x9a9);
}
}
So setting JMSDelivery
mode will either fire exception or set invalid persistence! Here is small test for reproducing the problem:
[Test]
public void PutAndGetMessageWithDeliveryMode() {
using (MQQueue queue = _queueManager.AccessQueue(TestQueue, MQC.MQOO_OUTPUT | MQC.MQOO_INPUT_AS_Q_DEF)) {
MQMessage message = new MQMessage();
message.SetInt4Property("JMSDeliveryMode", 2);
message.WriteString("some string");
message.Format = MQC.MQFMT_STRING;
queue.Put(message);
MQMessage readMessage = new MQMessage();
queue.Get(readMessage);
Assert.AreEqual(2, readMessage.GetInt4Property("JMSDeliveryMode"));
queue.Close();
}
}
Upvotes: 0