I'm using publisher/subscriber model to deliver a message in a round robin fashion. Here I'm using 2 consumers to process the request. I want to stop one consumer once it processes one request. How can I stop one consumer? If so the remaining request will go to other consumer. If consumer fails to send back then what happens to the (persistent)data? Will it be lost or will it be delivered to other consumer ?
public class Testing {
public static void main(String[] args) throws URISyntaxException, Exception {
BrokerService broker = BrokerFactory.createBroker(new URI(
"broker:(tcp://localhost:61616)"));
broker.start();
Connection connection = null;
try {
// Producer
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
"tcp://localhost:61616");
connection = connectionFactory.createConnection();
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue("customerQueue");
// Consumer
for (int i = 0; i < 2; i++) {
MessageConsumer consumer = session.createConsumer(queue);
if(i == 0)
{
consumer.setMessageListener(new ConsumerMessageListener("Consumer " + i));
}
consumer.setMessageListener(new TestingOnc("Consumer" + i));
}
broker.stop();
}
}
}
The producer call that I'm using
public synchronized static void createMQRequestForPoster(Long zoneId, List<String> postJobs, int priority) throws JMSException {
Connection connection = null;
try {
connection = factory.createConnection();
connection.start();
Session session = connection.createSession(false,
Session.CLIENT_ACKNOWLEDGE);
Destination dest = session
.createQueue(SMCConstants.ACTIVEMQ_POST_REQUEST);
MessageProducer producer = session.createProducer(dest);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
logger.info("List of jobs adding into poster queue: "+postJobs.size());
for(String str : postJobs) {
TextMessage message = session.createTextMessage();
JSONObject obj = new JSONObject();
obj.put("priority", priority);
obj.put("zoneId", zoneId);
obj.put("postJobs", str);
logger.debug(obj.toString());
message.setText(obj.toString());
message.setIntProperty(ActiveMQReqProcessor.REQ_TYPE, 0);
producer.send(message);
}
} catch (JMSException | JSONException e) {
logger.warn("Failed to add poster request to ActiveMq", e);
} finally {
if(connection != null)
connection.close();
}
}
}
am able to send and receive the message.
Related
I have a publisher for a topic in activeMq that in case of an exception pushes the TextMessage to a vector. I want to spawn a thread when the exception occurs and this thread should keep retrying to push the messages to the same topic. But there should only be one thread and not multiple threads in case of an exception.
private Vector<TextMessage> pendingQueue = new Vector<TextMessage>();
#Override
public void sendMessage(Object myMessage)
{
try
{
factory = new ActiveMQConnectionFactory(activeMQServerURL);
connection = factory.createConnection();
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
destination = session.createTopic(cmdTopicName);
producer = session.createProducer(destination);
message = session.createTextMessage();
message.setText(new Gson().toJson(myMessage));
producer.send(message);
}
catch (JMSException e)
{
pendingQueue.add(message);
runBackgroundDLQJobs();
}
}
public void runBackgroundDLQJobs()
{
bgThread.start();
}
And Run method of bgThread:
#Override
public void run()
{
while (pendingQueue.size() > 0)
{
try
{
int idx = 0;
while (idx < pendingQueue.size())
{
boolean sendDLQMessagesSuccess = sendDLQMessages(pendingQueue.get(idx));
if (sendDLQMessagesSuccess)
{
pendingQueue.remove(idx);
idx++;
}
else
{
Thread.sleep(5000);
}
}
}
catch (Exception e)
{
//DoSomething
}
}
}
I am new in JMS and want to create a basic MessageProducer who sends a message and MessageConsumer who receives the message asynchronously. When I run this code I get error message :
MessageProducer.java
package activemq.test;
import java.util.Date;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
public class MessageProducer{
javax.jms.MessageProducer producer = null;
Connection connection = null;
Session session = null;
public MessageProducer(){
try {
// Create a ConnectionFactory
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
// Create a Connection
connection = connectionFactory.createConnection();
connection.start();
// Create a Session
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Create the destination (Topic or Queue)
Destination destination = session.createQueue("TEST.FOO");
// Create a MessageProducer from the Session to the Topic or Queue
producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// Create a messages
String text = "Hello world! From: MessageProducer";
TextMessage message = session.createTextMessage(text);
// Tell the producer to send the message
System.out.println("Producer is going to send a message");
producer.send(message);
} catch (Exception e) {
System.out.println("Caught: " + e);
e.printStackTrace();
}
}
public void sendMessage(){
try
{
// Create a messages
String text = "Hello world! From: " + new Date();
TextMessage message = session.createTextMessage(text);
// Tell the producer to send the message
System.out.println("Sent message: "+ message.hashCode());
producer.send(message);
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void close(){
// Clean up
try {
session.close();
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
MessageConsumer.java
package activemq.test;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
public class MessageConsumer implements ExceptionListener{
Connection connection = null;
javax.jms.MessageConsumer consumer = null;
Session session = null;
public MessageConsumer(){
try {
// Create a ConnectionFactory
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
// Create a Connection
connection = connectionFactory.createConnection();
connection.start();
connection.setExceptionListener(this);
// Create a Session
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Create the destination (Topic or Queue)
Destination destination = session.createQueue("TEST.FOO");
// Create a MessageConsumer from the Session to the Topic or Queue
consumer = session.createConsumer(destination);
MessageListener listener = new MessageListener() {
public void onMessage(Message message) {
try {
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
System.out.println("Received message"
+ textMessage.getText() + "'");
}
} catch (JMSException e) {
System.out.println("Caught:" + e);
e.printStackTrace();
}
}
};
consumer.setMessageListener(listener);
} catch (Exception e) {
System.out.println("Caught: " + e);
e.printStackTrace();
}
}
#Override
public void onException(JMSException exception) {
System.out.println("JMS Exception occured. Shutting down client.");
}
public void close(){
// Clean up
try {
consumer.close();
session.close();
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
AppMain.java
public class AppMain {
public static void main(final String arg[]) throws Exception
{
MessageProducer msProducer = new MessageProducer();
msProducer.sendMessage();
msProducer.close();
MessageConsumer msConsumer = new MessageConsumer();
msConsumer.close();
}
}
When MessageConsumer is created, I get error message:
Caught: javax.jms.JMSException: AMQ119017: Queue jms.queue.TEST.FOO does not exist
javax.jms.JMSException: AMQ119017: Queue jms.queue.TEST.FOO does not exist
at org.apache.activemq.util.JMSExceptionSupport.create(JMSExceptionSupport.java:54)
at org.apache.activemq.ActiveMQConnection.syncSendPacket(ActiveMQConnection.java:1405)
at org.apache.activemq.ActiveMQSession.syncSendPacket(ActiveMQSession.java:1925)
at org.apache.activemq.ActiveMQMessageConsumer.<init>(ActiveMQMessageConsumer.java:275)
at org.apache.activemq.ActiveMQSession.createConsumer(ActiveMQSession.java:1157)
at org.apache.activemq.ActiveMQSession.createConsumer(ActiveMQSession.java:1101)
at org.apache.activemq.ActiveMQSession.createConsumer(ActiveMQSession.java:1014)
at org.apache.activemq.ActiveMQSession.createConsumer(ActiveMQSession.java:987)
at activemq.test.MessageConsumer.<init>(MessageConsumer.java:36)
at activemq.test.AppMain.main(AppMain.java:17)
Caused by: ActiveMQNonExistentQueueException[errorType=QUEUE_DOES_NOT_EXIST message=AMQ119017: Queue jms.queue.TEST.FOO does not exist]
at org.apache.activemq.core.server.impl.ServerSessionImpl.createConsumer(ServerSessionImpl.java:448)
at org.apache.activemq.core.protocol.openwire.amq.AMQServerSession.createConsumer(AMQServerSession.java:326)
at org.apache.activemq.core.protocol.openwire.amq.AMQConsumer.init(AMQConsumer.java:138)
at org.apache.activemq.core.protocol.openwire.amq.AMQSession.createConsumer(AMQSession.java:144)
at org.apache.activemq.core.protocol.openwire.OpenWireProtocolManager.addConsumer(OpenWireProtocolManager.java:544)
at org.apache.activemq.core.protocol.openwire.OpenWireConnection.processAddConsumer(OpenWireConnection.java:1118)
at org.apache.activemq.command.ConsumerInfo.visit(ConsumerInfo.java:347)
at org.apache.activemq.core.protocol.openwire.OpenWireConnection.bufferReceived(OpenWireConnection.java:272)
at org.apache.activemq.core.remoting.server.impl.RemotingServiceImpl$DelegatingBufferHandler.bufferReceived(RemotingServiceImpl.java:678)
at org.apache.activemq.core.remoting.impl.netty.ActiveMQChannelHandler.channelRead(ActiveMQChannelHandler.java:77)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:332)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:318)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:787)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:125)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:507)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:464)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:378)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:350)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
at java.lang.Thread.run(Thread.java:745)
Why I get this error when MessageConsumer is created, but don't get this error when MessageProducer is created.
I use ActiveMQServer as a broker:
Server.java
package activemq.test;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import org.apache.activemq.api.core.TransportConfiguration;
import org.apache.activemq.core.config.Configuration;
import org.apache.activemq.core.config.impl.ConfigurationImpl;
import org.apache.activemq.core.remoting.impl.netty.NettyAcceptorFactory;
import org.apache.activemq.core.server.ActiveMQServer;
import org.apache.activemq.core.server.ActiveMQServers;
public class Server {
public static void main(final String arg[]) throws Exception
{
try
{
// Step 1. Create the Configuration, and set the properties accordingly
Configuration configuration = new ConfigurationImpl();
//we only need this for the server lock file
configuration.setJournalDirectory("target/data/journal");
configuration.setPersistenceEnabled(false); // http://activemq.apache.org/what-is-the-difference-between-persistent-and-non-persistent-delivery.html
configuration.setSecurityEnabled(false); // http://activemq.apache.org/security.html
/**
* this map with configuration values is not necessary (it configures the default values).
* If you want to modify it to run the example in two different hosts, remember to also
* modify the client's Connector at {#link EmbeddedRemoteExample}.
*/
Map<String, Object> map = new HashMap<String, Object>();
map.put("host", "localhost");
map.put("port", 61616);
// https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/5/html/HornetQ_User_Guide/ch14s04.html
TransportConfiguration transpConf = new TransportConfiguration(NettyAcceptorFactory.class.getName(),map);
HashSet<TransportConfiguration> setTransp = new HashSet<TransportConfiguration>();
setTransp.add(transpConf);
configuration.setAcceptorConfigurations(setTransp); // https://github.com/apache/activemq-6/blob/master/activemq-server/src/main/java/org/apache/activemq/spi/core/remoting/Acceptor.java
// Step 2. Create and start the server
ActiveMQServer server = ActiveMQServers.newActiveMQServer(configuration);
server.start();
}
catch (Exception e)
{
e.printStackTrace();
throw e;
}
}
}
I think, in the producer, you are starting the connection before setting the destination.
Try it starting afterwards....
// Create a ConnectionFactory
ActiveMQConnectionFactory connectionFactory = new
ActiveMQConnectionFactory("tcp://localhost:61616");
// Create a Connection
connection = connectionFactory.createConnection();
// Create a Session
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Create the destination (Topic or Queue)
Destination destination = session.createQueue("TEST.FOO");
// Create a MessageProducer from the Session to the Topic or Queue
producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
connection.start();
// Create a messages
String text = "Hello world! From: MessageProducer";
TextMessage message = session.createTextMessage(text);
// Tell the producer to send the message
System.out.println("Producer is going to send a message");
producer.send(message);
On the other hand, for the consumer, I suggest to implement MessageConsumer (instead of the Exception).
Once implemented, in the constructor you can initiate the consumer
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(url);
connection = factory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Create the destination (Topic or Queue)
Destination destination = session.createQueue("TEST.FOO");
// Create a MessageConsumer from the Session to the Topic or Queue
consumer = session.createConsumer(destination).setMessageListener(this);
connection.start();
....
and then implement the onMessage method
public void onMessage(Message message) {
try {
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
System.out.println("Received message"
+ textMessage.getText() + "'");
}
} catch (JMSException e) {
System.out.println("Caught:" + e);
e.printStackTrace();
}
}
I'm trying develop aplication with comunication with JMS between C++ and Java.
I have a "server" with a broker in Java and i would like conect a c++ publisher/listner
How to i do this?
My classes im Java are:
"SERVER":
public class Queue {
private static ActiveMQConnectionFactory connectionFactory;
private static Destination destination;
private static boolean transacted = false;
private static Session session;
private static Connection connection;
public static void main(String[] args) throws Exception {
BrokerService broker = new BrokerService();
broker.setUseJmx(true);
broker.addConnector("tcp://localhost:61616");
broker.start();
Producer p=new Producer();
Consumer c= new Consumer();
connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,
ActiveMQConnection.DEFAULT_BROKER_URL);
connection = connectionFactory.createConnection();
connection.start();
session = connection
.createSession(transacted, Session.AUTO_ACKNOWLEDGE);
destination = session.createQueue("queue");
c.createConsumerAndReceiveAMessage(connection, connectionFactory,session,destination );
p.createProducerAndSendAMessage(destination,session);
broker.stop();
}
PRODUCER
public class Producer {
void createProducerAndSendAMessage(Destination destination,
Session session) throws JMSException {
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
Scanner sc=new Scanner(System.in);
String msg;
while(!(msg=sc.nextLine()).equals("exit") ){
TextMessage message = session.createTextMessage(msg);
System.out.println("Sending message " + message.getText());
producer.send(message);
}
}
CONSUMER:
public class Consumer {
public void createConsumerAndReceiveAMessage(Connection connection,
ActiveMQConnectionFactory connectionFactory, Session session,
Destination destination) throws JMSException, InterruptedException {
connection = connectionFactory.createConnection();
connection.start();
MessageConsumer consumer = session.createConsumer(destination);
MyConsumer myConsumer = new MyConsumer();
connection.setExceptionListener(myConsumer);
consumer.setMessageListener(myConsumer);
}
private static class MyConsumer implements MessageListener,
ExceptionListener {
synchronized public void onException(JMSException ex) {
System.out.println("JMS Exception occured. Shutting down client.");
System.exit(1);
}
public void onMessage(Message message) {
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
try {
System.out.println("Received message "
+ textMessage.getText());
} catch (JMSException ex) {
System.out.println("Error reading message " + ex);
}
} else {
System.out.println("Received " + message);
}
}
}
Regards
Have you looked at ActiveMQ-CPP? This is the ActiveMQ C++ client, in the main page for the project there is documentation, examples and tutorials.
I have a single threaded ActiveMQ consumer written in Java. All I'm trying to do is receive() a messsage from the queue, attempt to send it to a web service, and if it succeeds acknowledge() it. If the web service call fails, I want the message to stay on the queue and be resent after some timeout.
It's more or less working, except for the resending part: each time I restart my consumer, it gets one message for each that's still on the queue, but after failing to send them, the messages are never resent.
My code looks like:
public boolean init() throws JMSException, FileNotFoundException, IOException {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user, password, url);
RedeliveryPolicy policy = new RedeliveryPolicy();
policy.setInitialRedeliveryDelay(500);
policy.setBackOffMultiplier(2);
policy.setUseExponentialBackOff(true);
connectionFactory.setRedeliveryPolicy(policy);
connectionFactory.setUseRetroactiveConsumer(true); // ????
Connection connection = connectionFactory.createConnection();
connection.setExceptionListener(this);
connection.start();
session = connection.createSession(transacted, ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE);
destination = session.createQueue(subject); //???
consumer = session.createConsumer(destination);
//consumer.setMessageListener(this); // message listener had same behaviour
}
private void process() {
while(true) {
System.out.println("Waiting...");
try {
Message message = consumer.receive();
onMessage(message);
} catch (JMSException e) {
e.printStackTrace();
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void onMessage(Message message) {
System.out.println("onMessage");
messagesReceived++;
if (message instanceof TextMessage) {
try {
TextMessage txtMsg = (TextMessage) message;
String msg = txtMsg.getText();
if(!client.sendMessage(msg)) {
System.out.println("Webservice call failed. Keeping message");
//message.
} else {
message.acknowledge();
}
if (transacted) {
if ((messagesReceived % batch) == 0) {
System.out.println("Commiting transaction for last " + batch + " messages; messages so far = " + messagesReceived);
session.commit();
}
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}
I'm not currently using transactions (maybe I should be?).
I'm sure I'm missing something easy and will be slapping my forehead soon but I can't seem to figure out how this is supposed to work. Thanks!
EDIT: Can't answer this myself as not enough rep:
OK, after some more experimentation, it turns out transactions are the only way to do this. Here is the new code:
public boolean init() throws JMSException, FileNotFoundException, IOException {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user, password, url);
RedeliveryPolicy policy = new RedeliveryPolicy();
policy.setInitialRedeliveryDelay(1000L);
policy.setMaximumRedeliveries(RedeliveryPolicy.NO_MAXIMUM_REDELIVERIES);
connectionFactory.setRedeliveryPolicy(policy);
connectionFactory.setUseRetroactiveConsumer(true);
Connection connection = connectionFactory.createConnection();
connection.setExceptionListener(this);
connection.start();
session = connection.createSession(transacted, ActiveMQSession.CLIENT_ACKNOWLEDGE);
destination = session.createQueue(subject);
consumer = session.createConsumer(destination);
}
#Override
public void onMessage(Message message) {
System.out.println("onMessage");
messagesReceived++;
if (message instanceof TextMessage) {
try {
TextMessage txtMsg = (TextMessage) message;
String msg = txtMsg.getText();
if(client.sendMessage(msg)) {
if(transacted) {
System.out.println("Call succeeded - committing message");
session.commit();
}
//message.acknowledge();
} else {
if(transacted) {
System.out.println("Webservice call failed. Rolling back message");
session.rollback();
}
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}
Now, the message is being resent every 1000ms as specified in the Redelivery Policy.
Hope this helps someone else! :)
You don't have to use transactions, CLIENT_ACK/Session.recover() will work as well...
Messages are redelivered to a client when any of the following occurs:
A transacted session is used and rollback() is called.
A transacted session is closed before commit is called.
A session is using CLIENT_ACKNOWLEDGE and Session.recover() is called.
see http://activemq.apache.org/message-redelivery-and-dlq-handling.html
i'm using JMS for the first time. And i thought i have done everything right but when i send a message from a servlet it's not all the time consumed by the listner i don't know what's wrong sometime it works and sometimes it doesn't.
here's some of my code:
public void onMessage(Message message) {
try {
ObjectMessage objectMessage = (ObjectMessage) message;
OrdreDeTransfert ordreDeTransfert = (OrdreDeTransfert) objectMessage.getObject();
Long compte1Id = ordreDeTransfert.getIdSource();
Long compte2Id = ordreDeTransfert.getIdDestination();
int montant = ordreDeTransfert.getMontant();
gestionnaireDeCompteBancaire.transfert(compte1Id, compte2Id, montant);
} catch (JMSException ex) {
Logger.getLogger(transfertBancaireMDB.class.getName()).log(Level.SEVERE, null, ex);
}
in my servlet
private Message createJMSMessageForjmsOrdresTransfertBancaire(Session session, OrdreDeTransfert messageData) throws JMSException {
ObjectMessage tm = session.createObjectMessage(messageData);
tm.setJMSPriority(9);
return tm;
}
private void sendJMSMessageToOrdresTransfertBancaire(OrdreDeTransfert messageData) throws JMSException {
Connection connection = null;
Session session = null;
connection = loggingMessagesFactory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer messageProducer = session.createProducer(ordresTransfertBancaire);
messageProducer.setPriority(9);
messageProducer.send(createJMSMessageForjmsOrdresTransfertBancaire(session, messageData));
}