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.
Related
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.
I want to build a simple consumer program (in java) to get all messages stocked in an ActiveMQ subject.
I have a producer which send TextMessage in the queue.
But I don't know how to start to write my consumer for retrieving old messages and wait for new one.
If you have an example, thanks!
This is my Producer: http://pastebin.com/uRy9D8mY
This is my Consumer: http://pastebin.com/bZh4r66e
When I run my producer before my consumer, then run the consumer, I got nothing.
When I run my consumer then my producer, I add 72 messages in the queue but my consumer got only 24 message...
I suggest reading this tutorial (as does Apache ActiveMQ) SUN Jms tutorial
There are many ways to write JMS/ActiveMQ programs, using various frameworks such as Spring, or by using plain java.
Essentially, write a listener class like this:
public class MyListener implements MessageListener{
public void onMessage(Message message){
// Read and handle message here.
}
}
Since you already are producing message, I assume you have connection up and running.
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
consumer = session.createConsumer("MyQueue");
listener = new MyListener ();
consumer.setMessageListener(listener);
connection.start();
// At this point, messages should arrive from the queue to your listener.
Then there are some error handling code not included in this example, but you should be able to figure it out with the help of the tutorial and JMS documentation.
Using the code given below you can read all the messages en-queued in the queue.
In this code the while loop is an unending loop it will iterate all
the messages in the queue.
Once there is no messages in the queue it will wait for 5 seconds then automatically stops the connection and breaks
the loop.
If you required an unending consumer which will read all the messages whenever newly added to the queue, then remove the else part, so the program will not terminate.
ConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
Connection con = factory.createConnection();
Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue("tmp_queue2");
MessageConsumer consumer = session.createConsumer(queue);
con.start();
while (true) {
Message msg = consumer.receive(5000);
if (msg instanceof TextMessage) {
TextMessage tm = (TextMessage) msg;
System.out.println(tm.getText());
}
else{
System.out.println("Queue Empty");
con.stop();
break;
}
}
Hope this consumer program will helps people who were new to ActiveMQ.
We have a javax.ejb.TimedObject which queues messages to an MDB like so...
ctx = new InitialContext();
QueueConnectionFactory qCF = (QueueConnectionFactory) ctx
.lookup("java:comp/env/jms/queueconnfactory");
Queue q = (Queue) ctx.lookup("java:comp/env/jms/queue");
conn = qCF.createQueueConnection();
session = conn.createQueueSession(true,
Session.AUTO_ACKNOWLEDGE);
QueueSender sender = session.createSender(q);
TextMessage txtMsg = session.createTextMessage();
txtMsg.setLongProperty(JobMonitorUtil.JOB_REFERENCE_ID, filingId);
txtMsg.setLongProperty(JobMonitorUtil.JOB_ID, jobId);
txtMsg.setLongProperty(JobMonitorUtil.JOB_RUN_SID, jobRunSId);
sender.send(txtMsg);
session.close();
conn.close();
When I debug this (on Weblogic 10.3.1.0) I step over the sender.sent(txtMsg) line and I expect my onMessage breakpoint to be hit almost instantaneously. It doesn't hit my breakpoint until I let the ejbTimeout run (actually when I step out of TimerImpl.timerExpired). The message queue is on the same server which generates the messages.
To me it seems odd.
Aren't MDB messages sent asyncronously?
Could this be a configuration problem or is this how it's supposed to work?
You created a transactional session. JMS messages are not sent out until transaction is committed (otherwise rollback wouldn't be possible -- message has reached the remote system already).
The transaction is committed when you call session.close().
Solution would be (for example) to create a non-transactional session:
session = conn.createQueueSession(false,Session.AUTO_ACKNOWLEDGE);