I wrote a client to read segmented message sent via MQ but getting error message. Below code work perfectly fine but it read single message at time, Application has to concatenate the segmented message which is not what I wanted
public void getMessage(){
try {
MQEnvironment.hostname = "";
MQEnvironment.channel = "";
MQEnvironment.port = ;
MQQueueManager QMgr = new MQQueueManager("MQManager");
MQGetMessageOptions gmo = new MQGetMessageOptions();
gmo.options = MQConstants.MQOO_INPUT_AS_Q_DEF|
MQConstants.MQGMO_WAIT|
MQConstants.MQGMO_ALL_SEGMENTS_AVAILABLE|
MQConstants.MQGMO_LOGICAL_ORDER;
gmo.matchOptions = MQConstants.MQMO_NONE;
gmo.waitInterval = MQConstants.MQWI_UNLIMITED;
MQMessage message = new MQMessage();
MQQueue queue = QMgr.accessQueue("QName",
gmo.options);
while(true){
queue.get(message, gmo);
int dataLength = message.getDataLength();
System.out.println(message.readStringOfCharLength(dataLength));
message.clearMessage();
}
} catch (Exception e) {
e.printStackTrace();
}
}
When I added MQGMO_SYNCPOINT to options, it fails with com.ibm.mq.MQException: MQJE001: Completion Code '2', Reason '2046'.
Not sure why this fails, if I can atleast get this to work, I will be able to commit after safely processing all segmented message in the application.
public void getMessage(){
try {
MQEnvironment.hostname = "";
MQEnvironment.channel = "";
MQEnvironment.port = ;
MQQueueManager QMgr = new MQQueueManager("MQManager");
MQGetMessageOptions gmo = new MQGetMessageOptions();
gmo.options = MQConstants.MQOO_INPUT_AS_Q_DEF|
MQConstants.MQGMO_WAIT|
MQConstants.MQGMO_ALL_SEGMENTS_AVAILABLE|
MQConstants.MQGMO_LOGICAL_ORDER|
MQConstants.MQGMO_SYNCPOINT;
gmo.matchOptions = MQConstants.MQMO_NONE;
gmo.waitInterval = MQConstants.MQWI_UNLIMITED;
MQMessage message = new MQMessage();
MQQueue queue = QMgr.accessQueue("QName",
gmo.options);
while(true){
queue.get(message, gmo);
int dataLength = message.getDataLength();
System.out.println(message.readStringOfCharLength(dataLength));
QMgr.commit();
message.clearMessage();
}
} catch (Exception e) {
e.printStackTrace();
}
}
When I try to read segmented message as a single message; it fails with
com.ibm.mq.MQException: MQJE001: Completion Code '2', Reason '2046'.
I would appreciate if some could help solve this issue; I am not really sure what is wrong with the below code. This is my preferred way to read the segmented message.
public void getMessage(){
try {
MQEnvironment.hostname = "";
MQEnvironment.channel = "";
MQEnvironment.port = ;
MQQueueManager QMgr = new MQQueueManager("MQManager");
MQGetMessageOptions gmo = new MQGetMessageOptions();
gmo.options = MQConstants.MQOO_INPUT_AS_Q_DEF|
MQConstants.MQGMO_WAIT|
MQConstants.MQGMO_COMPLETE_MSG;
gmo.matchOptions = MQConstants.MQMO_NONE;
gmo.waitInterval = MQConstants.MQWI_UNLIMITED;
MQMessage message = new MQMessage();
MQQueue queue = QMgr.accessQueue("QName",
gmo.options);
while(true){
queue.get(message, gmo);
int dataLength = message.getDataLength();
System.out.println(message.readStringOfCharLength(dataLength));
message.clearMessage();
}
} catch (Exception e) {
e.printStackTrace();
}
}
The issue is that you are using gmo.options as the open options for the accessQueue method and the get message options for the get. You are mixing both open options and get message options into this field.
Each option is represented by a bit in the options field. When you use that field as the open options the bits are being interpreted by MQ as open options even if you specify get message options, conversely when you use the field as the get message options they are being interpreted by MQ as get message options.
Lets look at the values of each option you are specifying in the your samples represented as hex along with the equivalent open or get option based on the value:
MQOO_INPUT_AS_Q_DEF 0x00000001
MQGMO_WAIT 0x00000001
MQOO_INPUT_SHARED 0x00000002
MQGMO_SYNCPOINT 0x00000002
MQOO_RESOLVE_NAMES 0x00010000
MQGMO_COMPLETE_MSG 0x00010000
MQOO_BIND_NOT_FIXED 0x00008000
MQGMO_LOGICAL_ORDER 0x00008000
MQOO_RESOLVE_LOCAL_Q 0x00040000
MQOO_RESOLVE_LOCAL_TOPIC 0x00040000
MQGMO_ALL_SEGMENTS_AVAILABLE 0x00040000
Because you are incorrectly using this as open options with QMgr.accessQueue("QName",gmo.options); MQ is interpreting this in unexpected ways.
For your first "working" example, the open options would be interpreted as specified below, these specific open options together would not cause any problems for local queues, this is why it is "working" even though it is not correct:
MQOO_INPUT_AS_Q_DEF 0x00000001
MQOO_INPUT_AS_Q_DEF 0x00000001 //MQGMO_WAIT
MQOO_RESOLVE_LOCAL_Q 0x00040000 //MQGMO_ALL_SEGMENTS_AVAILABLE
MQOO_RESOLVE_LOCAL_TOPIC 0x00040000 //MQGMO_ALL_SEGMENTS_AVAILABLE
MQOO_BIND_NOT_FIXED 0x00008000 //MQGMO_LOGICAL_ORDER
In your second example that fails with 2046 (MQRC_OPTIONS_ERROR) it is because the options are being interpreted as specified below. You cannot have MQOO_INPUT_AS_Q_DEF and MQOO_INPUT_SHARED together in the open options, this causes the 2046:
MQOO_INPUT_AS_Q_DEF 0x00000001
MQOO_INPUT_AS_Q_DEF 0x00000001 //MQGMO_WAIT
MQOO_RESOLVE_LOCAL_Q 0x00040000 //MQGMO_ALL_SEGMENTS_AVAILABLE
MQOO_RESOLVE_LOCAL_TOPIC 0x00040000 //MQGMO_ALL_SEGMENTS_AVAILABLE
MQOO_BIND_NOT_FIXED 0x00008000 //MQGMO_LOGICAL_ORDER
MQOO_INPUT_SHARED 0x00000002 //MQGMO_SYNCPOINT
In your third example that fails with 2046 (MQRC_OPTIONS_ERROR) it is because the options are being interpreted as specified below. MQOO_RESOLVE_NAMES is documented as valid only in the MQ C++ APIs, this causes the 2046:
MQOO_INPUT_AS_Q_DEF 0x00000001
MQOO_INPUT_AS_Q_DEF 0x00000001 //MQGMO_WAIT
MQOO_RESOLVE_NAMES 0x00010000 //MQGMO_COMPLETE_MSG
Using the MQOO_INPUT_AS_Q_DEF as a get message option is not causing any issues because it has the same value as MQGMO_WAIT which you already have in each of your examples, having this is not changing the behavior of the get message options.
MQGMO_WAIT 0x00000001 //MQOO_INPUT_AS_Q_DEF
MQGMO_WAIT 0x00000001
The following based on your second and third examples should work:
public void getMessage(){
try {
MQEnvironment.hostname = "";
MQEnvironment.channel = "";
MQEnvironment.port = ;
MQQueueManager QMgr = new MQQueueManager("MQManager");
// Set up the options on the queue we wish to open
int openOptions = MQConstants.MQOO_INPUT_AS_Q_DEF;
MQGetMessageOptions gmo = new MQGetMessageOptions();
gmo.options = MQConstants.MQGMO_WAIT|
MQConstants.MQGMO_ALL_SEGMENTS_AVAILABLE|
MQConstants.MQGMO_LOGICAL_ORDER|
MQConstants.MQGMO_SYNCPOINT|
MQConstants.MQGMO_COMPLETE_MSG;
gmo.matchOptions = MQConstants.MQMO_NONE;
gmo.waitInterval = MQConstants.MQWI_UNLIMITED;
MQMessage message = new MQMessage();
MQQueue queue = QMgr.accessQueue("QName", openOptions);
while(true){
queue.get(message, gmo);
int dataLength = message.getDataLength();
System.out.println(message.readStringOfCharLength(dataLength));
QMgr.commit();
message.clearMessage();
}
} catch (Exception e) {
e.printStackTrace();
}
}
If you run the mqrc utility that comes with full MQ client installs you can find out what the error code translates to:
$mqrc 2046
2046 0x000007fe MQRC_OPTIONS_ERROR
Related
I am wring custom java code to read messages from Websphere MQ (version 8) and read all the headers from the MQ message.
When I use the MQHeaderList to parse all the headers the list size is 0:
MQMessage message = new MQMessage();
queue.get(message, getOptions);
DataInput in = new DataInputStream (new ByteArrayInputStream (b));
MQHeaderList headersfoundlist = null;
headersfoundlist = new MQHeaderList (in);
System.out.println("headersfoundlist size: " + headersfoundlist.size());
However, I read only a specific MQRFH2 it works
MQMessage message = new MQMessage();
queue.get(message, getOptions);
DataInput in = new DataInputStream (new ByteArrayInputStream (b));
MQRFH2 rfh2 = new MQRFH2(in);
Element usrfolder = rfh2.getFolder("usr", false);
System.out.println("usr folder" + usrfolder);
How can I parse all the headers of the MQ Message?
DataInput in = new DataInputStream (new ByteArrayInputStream (b));
What's that about? Not sure why you want to do that.
It should just be:
MQMessage message = new MQMessage();
queue.get(message, getOptions);
MQHeaderList headersfoundlist = new MQHeaderList(message);
System.out.println("headersfoundlist size: " + headersfoundlist.size());
Read more here.
Update:
#anshu's comment about it not working, well, I've always found MQHeaderList class to be very buggy. Hence, that is why I don't use it.
Also, 99.99% messages in MQ will only ever have 1 embedded MQ header (i.e. MQRFH2). Note: A JMS message == MQRFH2 message. The only case where you will find 2 embedded MQ headers are for messages on the Dead Letter Queue.
i.e.
{MQDLH}{MQRFH2}{message payload}
Is there a real need for your application to process multiple embedded MQ headers? Is your application putting/getting JMS messages (aka MQRFH2 messages)?
If so then you should do something like the following:
queue.get(receiveMsg, gmo);
if (CMQC.MQFMT_RF_HEADER_2.equals(receiveMsg.format))
{
receiveMsg.seek(0);
MQRFH2 rfh2 = new MQRFH2(receiveMsg);
int strucLen = rfh2.getStrucLength();
int encoding = rfh2.getEncoding();
int CCSID = rfh2.getCodedCharSetId();
String format= rfh2.getFormat();
int flags = rfh2.getFlags();
int nameValueCCSID = rfh2.getNameValueCCSID();
String[] folderStrings = rfh2.getFolderStrings();
for (String folder : folderStrings)
System.out.println.logger("Folder: "+folder);
if (CMQC.MQFMT_STRING.equals(format))
{
String msgStr = receiveMsg.readStringOfByteLength(receiveMsg.getDataLength());
System.out.println.logger("Data: "+msgStr);
}
else if (CMQC.MQFMT_NONE.equals(format))
{
byte[] b = new byte[receiveMsg.getDataLength()];
receiveMsg.readFully(b);
System.out.println.logger("Data: "+new String(b));
}
}
else if ( (CMQC.MQFMT_STRING.equals(receiveMsg.format)) ||
(CMQC.MQFMT_NONE.equals(receiveMsg.format)) )
{
Enumeration<String> props = receiveMsg.getPropertyNames("%");
if (props != null)
{
System.out.println.logger("Named Properties:");
while (props.hasMoreElements())
{
String propName = props.nextElement();
Object o = receiveMsg.getObjectProperty(propName);
System.out.println.logger(" Name="+propName+" : Value="+o);
}
}
if (CMQC.MQFMT_STRING.equals(receiveMsg.format))
{
String msgStr = receiveMsg.readStringOfByteLength(receiveMsg.getMessageLength());
System.out.println.logger("Data: "+msgStr);
}
else
{
byte[] b = new byte[receiveMsg.getMessageLength()];
receiveMsg.readFully(b);
System.out.println.logger("Data: "+new String(b));
}
}
else
{
byte[] b = new byte[receiveMsg.getMessageLength()];
receiveMsg.readFully(b);
System.out.println.logger("Data: "+new String(b));
}
I found the mistake in my code. I have a few more steps before reading the headers. It was moving the cursor in message buffer to the end.
I added message.setDataOffset(0); before reading headers and it worked.
I am developing a test script to put a message onto a queue using IBM MQ API 8.0. I am using JMeter 3.1 and Beanshell Sampler for this (see code below).
The problem I am having is setting the "Encoding" field in the MQ headers. I've tried different methods as per API documentation, but nothing worked for me.
Has anyone faced this issue?
Thanks in advance!
Code below:
try {
MQEnvironment.hostname = _hostname;
MQEnvironment.channel = _channel;
MQEnvironment.port = _port;
MQEnvironment.userID = "";
MQEnvironment.password = "";
log.info("Using queue manager: " + _qMgr);
MQQueueManager _queueManager = new MQQueueManager(_qMgr);
int openOptions = CMQC.MQOO_OUTPUT + CMQC.MQOO_FAIL_IF_QUIESCING + CMQC.MQOO_INQUIRE + CMQC.MQOO_BROWSE
+ CMQC.MQOO_SET_IDENTITY_CONTEXT;
log.info("Using queue: " + _queueName + ", openOptions: " + openOptions);
MQQueue queue = _queueManager.accessQueue(_queueName, openOptions);
log.info("Building message...");
MQMessage sendmsg = new MQMessage();
sendmsg.clearMessage();
// Set MQ MD Headers
sendmsg.messageType = CMQC.MQMT_DATAGRAM;
sendmsg.replyToQueueName = _queueName;
sendmsg.replyToQueueManagerName = _qMgr;
sendmsg.userId = MQuserId;
sendmsg.setStringProperty("BAH_FR", fromBIC); // from /AppHdr/Fr/FIId/FinInstnId/BICFI
sendmsg.setStringProperty("BAH_TO", toBIC); // from /AppHdr/To/FIId/FinInstnId/BICFI
sendmsg.setStringProperty("BAH_MSGDEFIDR", "pacs.008.001.05"); // from /AppHdr/MsgDefIdr
sendmsg.setStringProperty("BAH_BIZSVC", "cus.clear.01-" + bizSvc); // from /AppHdr/BizSvcr
sendmsg.setStringProperty("BAH_PRTY", "NORM"); // priority
sendmsg.setStringProperty("userId", MQuserId); // user Id
sendmsg.setStringProperty("ConnectorId", connectorId);
sendmsg.setStringProperty("Roles", roleId);
MQPutMessageOptions pmo = new MQPutMessageOptions(); // accept the defaults, same as MQPMO_DEFAULT constant
pmo.options = CMQC.MQOO_SET_IDENTITY_CONTEXT; // set identity context by userId
// Build message
String msg = "<NS1> .... </NS1>";
// MQRFH2 Headers
sendmsg.format = CMQC.MQFMT_STRING;
//sendmsg.encoding = CMQC.MQENC_INTEGER_NORMAL | CMQC.MQENC_DECIMAL_NORMAL | CMQC.MQENC_FLOAT_IEEE_NORMAL;
sendmsg.encoding = 546; // encoding - 546 Windows/Linux
sendmsg.messageId = msgID.getBytes();
sendmsg.correlationId = CMQC.MQCI_NONE;
sendmsg.writeString(msg);
String messageIdBefore = new String(sendmsg.messageId, "UTF-8");
log.info("Before put, messageId=[" + messageIdBefore + "]");
int depthBefore = queue.getCurrentDepth();
log.info("Queue Depth=" + depthBefore);
log.info("Putting message on " + _queueName + ".... ");
queue.put(sendmsg, pmo);
int depthAfter = queue.getCurrentDepth();
log.info("Queue Depth=" + depthAfter);
log.info("**** Done");
String messageIdAfter = new String(sendmsg.messageId, "UTF-8");
log.info("After put, messageId=[" + messageIdAfter + "]");
log.info("Closing connection...");
} catch (Exception e) {
log.info("\\nFAILURE - Exception\\n");
StringWriter errors = new StringWriter();
e.printStackTrace(new PrintWriter(errors));
log.error(errors.toString());
}
I think you are over thinking the problem. If you are not doing some sort of weird manual character/data conversion then you should be using:
sendmsg.encoding = MQC.MQENC_NATIVE;
public string WriteMsg(string strInputMsg)
{
string strReturn = "";
try
{
MQQueue queue = null;
MQQueueManager QueueManagerName = null ;
QueueManagerName = new MQQueueManager("GRBAAQM");
queue = QueueManagerName.AccessQueue(QueueName, MQC.MQOO_OUTPUT
+ MQC.MQOO_FAIL_IF_QUIESCING);
message = strInputMsg;
queueMessage = new MQMessage();
queueMessage.WriteString(message);
queueMessage.Format = MQC.MQFMT_STRING;
queuePutMessageOptions = new MQPutMessageOptions();
queue.Put(queueMessage, queuePutMessageOptions);
strReturn = "Message sent to the queue successfully";
}
catch (MQException MQexp)
{
strReturn = "Exception: " + MQexp.Message;
}
catch (Exception exp)
{
strReturn = "Exception: " + exp.Message;
}
return strReturn;
}
public string ReadMsg()
{
String strReturn = "";
try
{
MQQueue queue = null;
MQQueueManager QueueManagerName = null;
QueueManagerName = new MQQueueManager("GRBAAQM");
queue = QueueManagerName.AccessQueue(QueueName, MQC.MQOO_INPUT_AS_Q_DEF +
MQC.MQOO_FAIL_IF_QUIESCING);
queueMessage = new MQMessage();
queueMessage.Format = MQC.MQFMT_STRING;
queueGetMessageOptions = new MQGetMessageOptions();
queue.Get(queueMessage, queueGetMessageOptions);
strReturn =
queueMessage.ReadString(queueMessage.MessageLength);
}
catch (MQException MQexp)
{
strReturn = "Exception : " + MQexp.Message;
}
catch (Exception exp)
{
strReturn = "Exception: " + exp.Message;
}
return strReturn;
}
These two methods in this program helps us to read the messages from queue and displays but how to insert this feature while reading message FROM queue, read only if the message count has reached 10.
Why do you care how many messages are in the queue? MQ is NOT a database. If a message is in the queue then it should be processed. If you need to group messages together then have the sender use MQ's message grouping feature.
Did you read about MQ triggering? A program can be triggered (started) based on a triggering event. i.e. Trigger-first, trigger-every & trigger-depth.
I have created Simple JMS Client and Receiver Program. I have used JDk1.7 and activeMQ 5.10.0.My Sender code is executing with particlur message
MessageProducer mp= session.createProducer(destinatin);
Message message = session.createTextMessage("Hi Welcome to ActiveMQ Example");
mp.send(message);
System.out.println("Message Has Sent");
and
Receiver code My Reciver Code is this one where it is not printing anything.
and after some time it gives me error of connection timeout.Could you find out where I am creating mistake...
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://Name-PC:61616");
//connectin creation
Connection con = connectionFactory.createConnection();
Session session = con.createSession(false,Session.AUTO_ACKNOWLEDGE);
Destination dest= new ActiveMQQueue("Test1.Queue");
MessageConsumer Consumer = session.createConsumer(dest);
Message message = Consumer .receive();
System.out.println("End of Message1");
TextMessage text = (TextMessage) message;
System.out.println("Message" +text.getText());
System.out.println("End of Message");
In http://localhost:8161/admin/queues.jsp it is showing content on
Name Test1.Queue, Number Of Pending Messages =1, Number Of Consumers=1 Messages Enqueued =1,but Messages Dequeued not showing anything
You need to start the connection.
This groovy code works for me:
factory = new ActiveMQConnectionFactory("tcp://tpmint:61616");
dest = new ActiveMQQueue("foo.bar");
conn = null;
session = null;
consumer = null;
try {
conn = factory.createConnection();
println "Connected: $conn";
session = conn.createSession(false,Session.AUTO_ACKNOWLEDGE);
println "Session: $session";
consumer = session.createConsumer(dest);
println "Consumer: $consumer";
conn.start();
msg = consumer.receive(1000);
if(msg==null) println "Timeout";
else println "Msg:$msg";
} finally {
if(consumer!=null) try { consumer.close(); println "Consumer Closed";} catch (e) {}
if(session!=null) try { session.close(); println "Session Closed";} catch (e) {}
if(conn!=null) try { conn.close(); println "Connection Closed"; } catch (e) {e.printStackTrace(System.err);}
}
Output:
Connected: ActiveMQConnection {id=ID:tpmint-51137-1445798087365-0:8,clientId=null,started=false}
Session: ActiveMQSession {id=ID:tpmint-51137-1445798087365-0:8:1,started=false}
Consumer: ActiveMQMessageConsumer { value=ID:tpmint-51137-1445798087365-0:8:1:1, started=false }
Msg:ActiveMQTextMessage {commandId = 7, responseRequired = false, messageId = ID:tpmint-58446-1445793097761-4:2:1:1:3, originalDestination = null, originalTransactionId = null, producerId = ID:tpmint-58446-1445793097761-4:2:1:1, destination = queue://foo.bar, transactionId = null, expiration = 0, timestamp = 1445798905534, arrival = 0, brokerInTime = 1445798905534, brokerOutTime = 1445802982704, correlationId = , replyTo = null, persistent = false, type = , priority = 0, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = null, marshalledProperties = org.apache.activemq.util.ByteSequence#5346e84e, dataStructure = null, redeliveryCounter = 2, size = 0, properties = {JMSXMessageCounter=1}, readOnlyProperties = true, readOnlyBody = true, droppable = false, text = hey hey}
Consumer Closed
Session Closed
Connection Closed
I am fairly new to MQMessage broker. In my project, I want to send an xml message. Every thing is ok but when message get larger than 500 bytes, My code send broken message to the Queue. what I am doing is
//queueManager has been initialized in the class constructor and connected to a channel.
public MQResponse WriteMsg(string QueueName, string strInputMsg)
{
MQResponse response = new MQResponse();
try
{
queue = queueManager.AccessQueue(QueueName,
MQC.MQOO_OUTPUT + MQC.MQOO_FAIL_IF_QUIESCING );
queueMessage = new MQMessage();
queueMessage.DataOffset = 0;
//queueMessage.MessageLength = 2000000;
queueMessage.ResizeBuffer(6 * strInputMsg.Length);
queueMessage.WriteString(strInputMsg);
queueMessage.Format = MQC.MQFMT_STRING;
queuePutMessageOptions = new MQPutMessageOptions();
queue.Put(queueMessage, queuePutMessageOptions);
response.Message = "Message sent to the queue successfully";
response.Status=MQResponseStatus.WriteSuccessful;
}
catch (MQException MQexp)
{
response.Message = "Exception: " + MQexp.Message;
response.Status=MQResponseStatus.WriteFail;
response.CatchedException=MQexp;
}
catch (Exception exp)
{
response.Message = "Exception: " + exp.Message;
response.Status=MQResponseStatus.WriteFail;
response.CatchedException=exp;
}
return response;
}
I guess queueMessage should be initialized correctly so that we able to send whole message.
First of all how did you determine that the message is broken? Did you try to receive the sent message and compared with the original message or you viewed the message using MQExplorer or some other means. MQExplorer by default displays first 1000 bytes of the message. To view more you need to change the Max data bytes displayed setting in Window/Preferences/Messages panel.
WebSphere MQ can handle messages of size as large as 100 MB.
Regarding your code snippet above: The few lines of code is enough to build and send a message.
queueMessage = new MQMessage();
queueMessage.Format = MQC.MQFMT_STRING;
queueMessage.WriteString(strInputMsg);
queuePutMessageOptions = new MQPutMessageOptions();
queue.Put(queueMessage, queuePutMessageOptions);