OpenMQ and JMX - Is it possible to query for messages? - java

I am able to query for queues by invoking a GET_DESTINATIONS operation using JMX. With that I will receive the queue info (attributes).
I would like now to query the messages that are stored in this queue, is that possible? Could someone give me some direction?
I have already tried using this code
ConnectionFactory connectionFactory = new
com.sun.messaging.QueueConnectionFactory();
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue myQueue = session.createQueue(string);
QueueBrowser browser = session.createBrowser(myQueue);
Enumeration msgs = browser.getEnumeration();
if (!msgs.hasMoreElements()) {
System.out.println("No messages in queue");
} else {
while (msgs.hasMoreElements()) {
Message tempMsg = (Message) msgs.nextElement();
System.out.println("Message: " + tempMsg);
}
}
connection.close();
But for some reason O can't access the same queue as using JMX. I didn't made any research on that because I want to use JMX as the access standard.
I am still trying to find any JMX operation that could help me, but I am not finding anything that could help me.
Could you please give me some hints what can I look for?
thank you,
Oscar
Edit: just to let you know: I don't want to consume the queues, I want a similar behavior to the Browser, in which I can read the messages without removing them from the queue.

QueueBrowser browser = null;
try{
Queue myQueue = session.createQueue(getName());
//Create the browser and session to be able to iterate
browser = session.createBrowser(myQueue);
Enumeration msgs = browser.getEnumeration();
This code will give you the messages, then just iterate through it and you can get get infos about the message and its content

Related

JMSCode to send and receive messages one by one using Database

After I went to multiple sites and learned JMS I wrote a JMS standalone client to read messages from a database and send them one by one. I also want to receive message one by one message and then update the database.
I need to send a message to a queue and the other application using standard JMS which will consume a TextMessage and whose body will be read as an ISO-8859-1 string. Also they will similarly send reply as a TextMessage.
I wrote a for loop to read the message one by one from the DB.
I am new to JMS so could you please correct me whether my below code works properly to read and send messages to a queue and receive and update the DB. Is there any thing I need to change in the JMS Type or any thing I need to correct. Does the for loop work fine?
/*MQ Configuration*/
MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
mqQueueConnectionFactory.setHostName(url);
mqQueueConnectionFactory.setChannel(channel);//communications link
mqQueueConnectionFactory.setPort(port);
mqQueueConnectionFactory.setQueueManager(qmgr);//service provider
mqQueueConnectionFactory.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
/*Create Connection */
QueueConnection queueConnection = mqQueueConnectionFactory.createQueueConnection();
queueConnection.start();
/*Create session */
QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
/*Create response queue */
// Queue queue = queueSession.createQueue("QUEUE.RESPONSE");
int messageCount = 0;
Queue queue = queueSession.createQueue(replytoQueueName);
QueueSender queueSender = null;
QueueReceiver queueReceiver=null;
for (Testbean testBean : testbeanList) {
String testMessage = testBean.getMessage();
/*Create text message */
textMessage = queueSession.createTextMessage(testMessage);
logger.info("Text messages sent: " + messageCount);
textMessage.setJMSReplyTo(queue);
textMessage.setJMSType("mcd://xmlns");//message type
textMessage.setJMSExpiration(2*1000);//message expiration
textMessage.setJMSDeliveryMode(DeliveryMode.PERSISTENT); //message delivery mode either persistent or non-persistemnt
/*Create sender queue */
// QueueSender queueSender = queueSession.createSender(queueSession.createQueue("QUEUE.REQEST"));
queueSender = queueSession.createSender(queueSession.createQueue(outputQName));
queueSender.setTimeToLive(2*1000);
queueSender.send(textMessage);
/*After sending a message we get message id */
System.out.println("after sending a message we get message id "+ textMessage.getJMSMessageID());
String jmsCorrelationID = " JMSCorrelationID = '" + textMessage.getJMSMessageID() + "'";
/*Within the session we have to create queue reciver */
queueReceiver = queueSession.createReceiver(queue,jmsCorrelationID);
/*Receive the message from*/
Message message = queueReceiver.receive(60*1000);
// String responseMsg = ((TextMessage) message).getText();
byte[] by = ((TextMessage) message).getText().getBytes("ISO-8859-1");
logger.info(new String(by));
String responseMsg = new String(by,"UTF-8");
testDAO rmdao = new testDAO();
rmdao.updateTest(responseMsg, jmsCorrelationID);
messageCount += 1;
}
queueSender.close();
queueReceiver.close();
queueSession.close();
queueConnection.close();
Couple of things:
I would create your QueueSender and the Queue object its sending messages to outside the for loop since they don't appear to be changing.
Without the corresponding consumer code it's ultimately impossible to tell if the selector will work or not, but not invoking setCorrelationID() on the message you send looks a bit strange to me. Using the provider-assigned message ID may be a common pattern with IBM MQ request/reply applications, but the general pattern for using a correlation ID is to invoke setJMSCorrelationID() on the sent message. This makes the code more clear and also allows the application to directly control the uniqueness of the correlation ID. This is potentially important for application portability (e.g. if you migrated from IBM MQ to a different JMS provider) since different JMS providers use styles/formats of message ID specific to their particular implementation. Also, regarding the message ID the JMS spec states, "The exact scope of uniqueness is provider defined," which in my opinion is not a strong enough guarantee of uniqueness especially when using something like java.util.UUID.randomUUID().toString() is so simple.
You should ensure that you're using an XA transaction for both the JMS & database work so that they are atomic.
Close your JMS resources in a finally block.

How to set Persistence to JMS client?

I set up a connection with Weblogic IBM Webpsphere MQ through JMS with using a secure channel using SSL.
My application on Weblogic received message from MQ.
Sending answer to reply queue.
The response header is present MQMD, it fills java. In parameter Persistence JMS send value "1". Other system need to received value "0" at Persistence. How to set this parameter to java?
I guess that parameter is javax.jms.deliverymode. But how to set it i don't know.
Anyway thank you for help.
The corresponding property on JMS is the delivery mode (Int parameter to be set) to set Persistent and non persistent messages.
You can refer this URL from IBM for details
You should try like this:
public String sendMessage(ConnectionFactory connectionFactory,
Destination destination,
Destination jmsReplyTo,
CorrelationType correlationType,
CallOptions<String> callOptions,
String rqUid,
JMSAbstract transport) throws JMSException {
Connection connection = null;
Session session = null;
MessageProducer producer = null;
try {
connection = connectionFactory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
producer = session.createProducer(destination);
// Set JMS DeliverMode (1/2)
producer.setDeliveryMode(1);
// create message
Message message = createTextMessage(session, jmsReplyTo, correlationType, callOptions, rqUid, transport);
// send message
producer.send(message);
return correlationType.getCorrelationId(message);
} finally {
closeResource(connection, session, null, producer, rqUid);
}
}
It`s just a java example. Also you can set persistence flag in Queue configuration in IBM WebSphere. I mean MQQueue have method setPersistence. If you using IBM java objects in your project, you can set persistence by calling that method:
MQQueue mqQueue = new MQQueue("QueueName");
mqQueue.setPersistence(1);
I The answer of 0x5a4d is ok but better to use this like IBM best practices
//Persistentmode = 1
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
//Persistentmode = 2
producer.setDeliveryMode(DeliveryMode.PERSISTENT);

How to search for a particular message in JMS queue

I am sending some messages to a JMS queue. What are the possible ways to search for a particular message in a queue to consume?
I tried out in the following way: I am setting the JMSCorrelationID while sending a message to the queue:
public void createDQueue(String queuename, String json, Integer userid) {
try {
QueueSession.AUTO_ACKNOWLEDGE );
Queue queue = session.createQueue(queuename);
ObjectMessage objectMessage = session.createObjectMessage();
objectMessage.setJMSCorrelationID(String.valueOf(userid));
objectMessage.setObject(json);
session.createSender(queue).send(objectMessage);
session.close();
connection.close();
}catch(Exception e){
e.printStackTrace();
}
}
In the consumer code I want to get that particular message based on the JMSCorrelationID. I am not able to get that particular message. Can you suggest a solution?
public void getSpecificMessage(String queuename, Integer userid) {
try {
QueueConnectionFactory connectionFactory = new ActiveMQConnectionFactory( "tcp://localhost:61616");
((ActiveMQConnectionFactory) connectionFactory).setUseAsyncSend(true);
QueueConnection connection = connectionFactory.createQueueConnection();
connection.start();
QueueSession session = connection.createQueueSession( false,
QueueSession.AUTO_ACKNOWLEDGE );
String id = String.valueOf(userid);
Queue queue = session.createQueue(queuename);
QueueReceiver receiver = session.createReceiver(queue, "JMSCorrelationID="+id);
Message message = receiver.receive();
} catch (JMSException e) {
e.printStackTrace();
}
}
Your first problem is that you are trying to think about the message broker as a database, you must always remember this sage piece of advice, "A message broker is not a database".
There are certain limits on how deep a consumer or Queue browser can go into a destination before the broker will not page in more messages from disk, so you need to check your depth and see if its large than you maxPageSize setting and adjust as needed, but remember that messages paged in remain in memory until consumed.
Just wrap the id value in single quotes
"JMSCorrelationID='"+id+"'"
This functionality is not recommended to be used , there are lot more complications as explained by Tim , but if you want to obsolutely work with it make the change
You can search messages using the MeessageID of a message. This would be fast as messaging providers index messages on message id. There are other way to search based on CorrelationId, meta data etc.
But please remember the primary objective of using a messaging provider is to connect applications in a time independent manner. The receiving application must get messages as soon as possible. If messages are piling up in a queue, it indicates a problem that must be addressed.

Does JMS QueueBrowser getEnumeration requires Connection Start

I want to know if its required to call JMS Connection start() before we do QueueBrowser browse(). Could not find anything in javadoc about start() as a pre-op to browse() and each vendor samples for browse seems to be different. Some of them calls while other’s don’t.
I ask this as ActiveMQ does not browse messages if I don’t perform start().
ConnectionFactory factory = new ActiveMQConnectionFactory("tcp://**:**");
Connection connection = factory.createConnection();
connection.start();
Session session = connection.createSession(false, 1);
TextMessage message = session.createTextMessage();
message.setText("This is a sample message");
Queue dest = new ActiveMQQueue("Sample");
MessageProducer producer = session.createProducer(dest);
producer.send(message);
QueueBrowser browser = session.createBrowser(dest);
Enumeration<Message> messages = browser.getEnumeration();
/* Iteration code here
* If connection.start() is'nt called, no element in returned collection
* If connection.start() is called, the returned collection contains
* queue elements.
*/
..
Could not find java doc talking anything specific to start before peek on the queue. Any idea ?
Yes, Connection.Start() is required. QueueBrowser is similar to MessageConsumer with only difference being QueueBrowser does not remove message from JMS provider. Without application calling Connection.Start method JMS provider will not deliver messages.

JMS client does not receive messages

I am using Glassfish JMS.
I am able to add messages to a queue.
I can see the messages using the QueueBrowser object.
However the MessageConsumer (nor the QueueReceiver) cannot receice any message and return null.
Message expiration is set to 0 and I remember to open the connection.
Any ideas?
Here is the code:
Session session = null;
Connection conn = null;
try
{
InitialContext jndi = new InitialContext();
ConnectionFactory qFactory = (ConnectionFactory)jndi.
lookup("myConnectionFactory");
conn = qFactory.createConnection();
conn.start();
Queue queue = (Queue)jndi.lookup("myQueueName");
session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
QueueReceiver mc = ((QueueSession)session).createReceiver(queue);
Object m = mc.receive(2000);
//m is NULL!
QueueBrowser browser = session.createBrowser(queue);
for(Enumeration e = browser.getEnumeration(); e.hasMoreElements(); )
{
//there are many messages here...
}
That would be good to have the client code.
Similar thing happened to me when not properly committing/closing the connection on the sender side. The message would be visible when using the admin console, however, not available yet to the MDB.
Hope it helps.
Does this code run in the appserver? If it does, I'd obtain the required objects via annotations, and for a message receiver I'd use a MDB.
If this is a piece of standalone code, I had a hell of a time getting a JNDI based client working, I reverted to using the "raw" Java API.
I witnessed the same behavior happening after the first session commit, meaning that before the messages where received correctly. In my case the issue was that I was re-creating the receiver while keeping the same session.
As pointed out in this article:
Creating temporary destinations, consumers, producers and connections
are all synchronous request-response operations with the broker and so
should be avoided for processing each request as it results in lots of
chat with the JMS broker.
The solution was as simple as reusing the same receiver.

Categories