I am trying to implement a simple client that downloads messages from a MQ server. The MQ server already exists, and I have no access to it.
In all examples that I found online, it is used the "createQueue()" method, as such:
MQQueueConnectionFactory cf = new MQQueueConnectionFactory();
// Config
cf.setHostName("localhost");
cf.setPort(1414);
cf.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
cf.setQueueManager("QM_thinkpad");
cf.setChannel("SYSTEM.DEF.SVRCONN");
MQQueueConnection connection = (MQQueueConnection) cf.createQueueConnection();
MQQueueSession session = (MQQueueSession) connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
MQQueue queue = (MQQueue) session.createQueue("queue:///Q1");
MQQueueSender sender = (MQQueueSender) session.createSender(queue);
MQQueueReceiver receiver = (MQQueueReceiver) session.createReceiver(queue);
...
JMSMessage receivedMessage = (JMSMessage) receiver.receive(10000);
However, in my case I don't want to create a Queue, I just want to use an existing remote queue. Or I am wrong? What should I do?
createQueue() does not actually create an MQ Queue. It just creates an identifier for the queue , which can be used for subsequent calls, such as, in your case, createReceiver.
Related
I am trying to integrate ActiveMQ within Tomcat. To that end, I used this tutorial (a little outdated, I know, but the best I found). I created a servlet that instantiates and starts a broker:
try {
broker = new BrokerService();
broker.addConnector("tcp://localhost:61616");
broker.start()
} catch (final Exception e) {
e.printStackTrace();
}
I then created a simple Hello World example with a single producer sending a persisted message to a queue and a consumer retrieving the message, which failed. Both, producer and consumer, were able to connect to ActiveMQ and the queue but the consumer did not receive any message. However, after restarting Tomcat (and consequently the broker), the consumer received the message previously sent. Any newly created messages were again stuck.
I tried some non-persisted messages, which all arrived as expected. When sending a combination of persisted and non-persisted messages, the non-persisted ones arrived immediately and the persisted ones required a restart.
This is my (very basic) code for the producer and consumer:
final ConnectionFactory conFactory = (ConnectionFactory) jndi.lookup("connectionFactory");
final Connection connection = conFactory.createConnection();
connection.start();
final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
final Destination destination = (Destination) jndi.lookup("MyQueue");
final MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
final TextMessage message = session.createTextMessage("Hello World!");
producer.send(message);
connection.close();
final ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
connectionFactory.setTrustAllPackages(true);
final Connection connection = connectionFactory.createConnection();
connection.start();
final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
final Destination destination = session.createQueue("APP.JMS.QUEUE");
final MessageConsumer consumer = session.createConsumer(destination);
final Message message = consumer.receive(1000);
System.out.println("Received: " + message);
consumer.close();
session.close();
connection.close();
I tried transacted, manual-acknowledge, and auto-acknowledge mode for the consumer. I also tried directly creating ConnectionFactory and Destination (as in the consumer code) as well as JNDI lookup (producer code). All yielded the same result.
I tried versions 5.15.12, 5.15.11, 5.14.5, 5.11.0 and 5.10.0.
Any pointers what I did wrong or where I can find a more recent tutorial? I am aware of the official docs regarding ActiveMQ and Tomcat but they seem to be missing the essential parts.
I am trying to create an application which keeps on checking the number of queues up and running in activemq.
And Any way to check whether queue's are working or not i.e. if corrupted and not able to process messages.
Kindly suggest how to do it.
Thanks in Advance.
You can try following code.
public static void main(String[] args) throws Exception
{
// get the initial context
InitialContext ctx = new InitialContext();
// lookup the queue object
Queue queue = (Queue) ctx.lookup("queue/queue0");
// lookup the queue connection factory
QueueConnectionFactory connFactory = (QueueConnectionFactory) ctx.
lookup("queue/connectionFactory");
// create a queue connection
QueueConnection queueConn = connFactory.createQueueConnection();
// create a queue session
QueueSession queueSession = queueConn.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
// create a queue browser
QueueBrowser queueBrowser = queueSession.createBrowser(queue);
// start the connection
queueConn.start();
// browse the messages
Enumeration e = queueBrowser.getEnumeration();
int numMsgs = 0;
// count number of messages
while (e.hasMoreElements()) {
Message message = (Message) e.nextElement();
numMsgs++;
}
System.out.println(queue + " has " + numMsgs + " messages");
// close the queue connection
queueConn.close();
}
You can ask for stats using the statistics plugin on the broker and the plain JMS api. I.e. to count the number of messages on FOO.BAR, send an empty message to ActiveMQ.Statistics.Destination.TEST.FOO and specify the replyTo header. In the response message, which is of typ MapMessage, you can find the message counter.
Another way is to browse only the first message of the queue using a simple queue browser (similar to the way praveen_programmer suggests) and check the timestamp of that message. If it's older than some threshold, you might have a problem with that consumer. I.e. no messages has been processed in the last hour/minute/day.
Yet another way is to use JMX, or preferably the jolokia REST/HTTP management api.
Just query the destination using http and you get a queue depth back:
To query the queue "q" on localhost, use the following api (you need to supply the user/password for the web console):
http://localhost:8161/api/jolokia/read/org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=q
Take a look at Advisory messages. You need to enable them in your config , but you can get a lot of useful about your current activemq instances info through simple JMS messaging. http://activemq.apache.org/advisory-message.html I was using them to highlight slow producer and consumer scenarios.
The use case is that I want to send some configuration info to the subscribers as soon as they connect.
InitialContext ic = new InitialContext();
TopicConnectionFactory cf = (TopicConnectionFactory)ic.lookup("java:comp/env/jms/xxx");
Topic topic = (Topic) ic.lookup("java:comp/env/jms/xxx");
TopicConnection conn = cf.createTopicConnection();
TopicSession session = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(topic);
You can do what you're looking for by consuming ActiveMQ's advisory messages, which will get published when (among other things) a consumer connects or disconnects.
I've created a synchronous QueueReceiver attached to a WebLogic queue.
doStuff() {
ctx = new InitialContext();
qconFactory = (QueueConnectionFactory) ctx.lookup(CONNECTION_FACTORY);
queue = (Queue) ctx.lookup(outputFromOrcSyncQueue);
queueConnection = qconFactory.createQueueConnection();
queueSession = queueConnection.createQueueSession(true, -1);
queueReceiver = queueSession.createReceiver(queue);
Message message = queueReceiver.receive();
...
}
true in queueSession creation it's is because the connection factory is transacted.
If i create a no transacted queueSession (by putting false) the result is that the queueReceiver seems to ignore the receive() method going through the doStuff method (same behaviour using receive(timeout), it does not wait before going through).
I've also had to enable Prefetch Mode for Synchronous Consumer on my connection factory (Client tab in WebLogic connection factory's configuration).
My problem is the receiver does not read any message sent to the queue.
I can see my messages on WebLogic console, I can even see my queueReceiver listening on the queue, but the queueReceiver seems to ignore them.
Alternatives ways I've tried:
Changing ACK type in queueSession creation (both sides, producer and consumer)
Commit the session on producer after send() and before close()
Thank you.
You forgot to call the start method on the QueueConnection:
queueConnection = qconFactory.createQueueConnection();
queueConnection.start();
queueSession = queueConnection.createQueueSession(true, -1);
As The JMS API Programming Model in the Java EE Tutorial helpfully says:
Before your application can consume messages, you must call the connection’s start method.
The JMS Message Consumers section makes it more clear:
Remember always to call the start method; forgetting to start the connection is one of the most common JMS programming errors.
There might be a stupid simple answer to this, but I'm trying to use ActiveMQ to pass messages between producers and consumers. I will have many producers and many consumers, but I want each message to be delivered only once among the consumers. This would seem to mean that I cannot use Topics, since they would deliver messages to all consumers who are listening, and I want only one Consumer to receive each message.
My problem is that I am able to receive messages, but the messages are not dequeued. So if I restart my consumer process, all of the messages are reprocessed. This answer seems pertinent but does not seem to apply since I can't create durable queue consumers, only durable topic consumers (unless I'm missing something in the API docs).
My code is as follows.
TopicConnectionFactory factory = new ActiveMQConnectionFactory(props.getProperty("mq.url"));
Connection conn = factory.createConnection();
Session session = conn.createSession(true, Session.CLIENT_ACKNOWLEDGE);
Queue queue = session.createQueue(props.getProperty("mq.source_queue"));
conn.start();
MessageConsumer consumer = session.createConsumer(queue);
Then later on
Message msg = consumer.receive();
msg.acknowledge();
if (!(msg instanceof TextMessage)) continue;
String msgStr = ((TextMessage)msg).getText();
This is my current code. I have tried with Session.AUTO_ACKNOWLEDGE and without msg.acknowledge(). Any working permutation of this code seems to retrieve the messages, but when I restart my consumer, all of the messages get received again, even if they have been received prior to the restart.
You created the session as a transacted Session and therefore need to call, session.commit if you want to inform the broker that all messages are now consumed and don't need to be redelivered. If you don't set the first argument to createSession to true then the Ack mode is respected otherwise its ignored, one of the oddities of the JMS API I'm afraid. If you do this:
ConnectionFactory factory = new ActiveMQConnectionFactory(props.getProperty("mq.url"));
Connection conn = factory.createConnection();
Session session = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
Queue queue = session.createQueue(props.getProperty("mq.source_queue"));
conn.start();
MessageConsumer consumer = session.createConsumer(queue);
Then this would work:
Message msg = consumer.receive();
msg.acknowledge();
Otherwise you need to do:
Message msg = consumer.receive();
session.commit();
But keep in mind that for a single message transactions don't really make sense to client ack with no transaction is a better option.