On message not invoked jms - java

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));
}

Related

How to stop/kill consumer once it read the data?

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.

How to implement the JMS Asynchronous Message Receiver

To receive Jboss JMS messsage, I have written the JMS Asynchronous Message Receiver
See below code
public class QueueReceive implements MessageListener
{
public final static String JNDI_FACTORY="org.jnp.interfaces.NamingContextFactory";
public final static String JMS_FACTORY="ConnectionFactory";
public final static String QUEUE="/queue/requestQueue";
private QueueConnectionFactory qconFactory;
private QueueConnection qcon;
private QueueSession qsession;
private QueueReceiver qreceiver;
private Queue queue;
private boolean quit = false;
public void onMessage(Message msg)
{
try {
System.out.println("onMessage");
String msgText;
if (msg instanceof TextMessage) {
msgText = ((TextMessage)msg).getText();
} else {
msgText = msg.toString();
}
System.out.println("Message Received: "+ msgText );
if (msgText.equalsIgnoreCase("quit")) {
synchronized(this) {
quit = true;
this.notifyAll(); // Notify main thread to quit
}
}
} catch (JMSException jmse) {
System.err.println("An exception occurred: "+jmse.getMessage());
}
}
public void init(Context ctx, String queueName)
throws NamingException, JMSException
{
qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);
qcon = qconFactory.createQueueConnection();
qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
queue = (Queue) ctx.lookup(queueName);
qreceiver = qsession.createReceiver(queue);
qreceiver.setMessageListener(this);
qcon.start();
}
public void close()throws JMSException
{
qreceiver.close();
qsession.close();
qcon.close();
}
public static void main(String[] args) throws Exception {
InitialContext ic = getInitialContext("jnp://host:port");
QueueReceive qr = new QueueReceive();
System.out.println("Ready to initialize");
qr.init(ic, QUEUE);
System.out.println("JMS Ready To Receive Messages (To quit, send a \"quit\" message).");
// qr.onMessage(qr.qreceiver.receive());
System.out.println("Message Receivd");
// Wait until a "quit" message has been received.
synchronized(qr) {
while (!qr.quit) {
try {
qr.wait();
} catch (InterruptedException ie) {}
}
}
qr.close();
}
private static InitialContext getInitialContext(String url)
throws NamingException
{
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
env.put(Context.PROVIDER_URL, url);
return new InitialContext(env);
}
}
When I run java program, it will not call the onMessage method directly, Please help me how to received the JMS message.
From this code I am able to ping the JMS messenger and unable to read the message?

Connect C++ to ActiveMQ broker

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.

Glassfish & JMS: Why do published messages not arrive at subscribers?

I have a Glassfish 3.1.2 server running on a remote machine (JDK 1.6.0_30). The following code is the stand-alone client running in a Java SE environment, connecting to the JMS using a JNDI lookup. The client is publisher and subscriber at the same time.
I created the JMS connection pool and topic as follows:
./asadmin create-jms-resource --restype javax.jms.ConnectionFactory jms/TopicConnectionFactory
./asadmin create-jms-resource --restype javax.jms.Topic jms/TopicUpdate
I start two instances of this client. The messages seem to be delivered - no errors - but the messages do not arrive at the subscribers ...
What I am doing wrong ?
Any help appreciated - many thanks in advance!
public class JMS implements MessageListener {
private TopicConnectionFactory factory;
private TopicConnection connection;
private Topic topic;
private void subscribe() {
try {
System.setProperty("org.omg.CORBA.ORBInitialHost", "192.168.1.6");
System.setProperty("org.omg.CORBA.ORBInitialPort", "3700");
InitialContext ctx = new InitialContext();
factory = (TopicConnectionFactory)ctx.lookup("jms/TopicConnectionFactory");
topic = (Topic)ctx.lookup("jms/TopicUpdate");
connection = factory.createTopicConnection();
TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
TopicSubscriber subscriber = session.createSubscriber(topic);
subscriber.setMessageListener(this);
connection.start();
while(true) {
Thread.sleep(5000);
sendMessage();
}
} catch (InterruptedException ex) {
Logger.getLogger(JMS.class.getName()).log(Level.SEVERE, null, ex);
} catch (NamingException ex) {
Logger.getLogger(JMS.class.getName()).log(Level.SEVERE, null, ex);
} catch (JMSException ex) {
Logger.getLogger(JMS.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void sendMessage() {
try {
TopicSession session = connection.createTopicSession(true, Session.AUTO_ACKNOWLEDGE);
TopicPublisher publisher = session.createPublisher(topic);
TextMessage message = session.createTextMessage();
message.setText("Message from client.");
publisher.send(message);
session.close();
System.out.println("Message sent.");
} catch (JMSException ex) {
Logger.getLogger(JMS.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void onMessage(Message msg) {
System.out.println("Message received.");
}
public JMS() {
subscribe();
}
public static void main(String[] args) {
new JMS();
}
}
When you use true as the first argument when creating a session, the acknowledge mode is ignored and you're assumed to be transacted. try it with the first argument as false.
Just so it's clear, modify this line of code:
TopicSession session = connection.createTopicSession(true, Session.AUTO_ACKNOWLEDGE);
to be :
TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
In your send message method.
It's good idea to have publisher and subscriber different.I
Here is code how to subscribe using Spring JMS template.
public class MsgReader implements
SessionAwareMessageListener<Message> {
#Override
public void onMessage(Message message, Session session) throws JMSException {
if (message instanceof TextMessage) {
try {
System.out.println(((TextMessage) message).getText());
} catch (JMSException ex) {
throw new RuntimeException(ex);
}
} else {
throw new IllegalArgumentException(
"Message must be of type TextMessage");
}
}
}
Spring Bean file.
Finally load beans.
public class SpringJMSTest {
/**
* #param args
*/
public static void main(String[] args) {
ApplicationContext context = new FileSystemXmlApplicationContext(new String[]{"/resource/consumerBean.xml"});
}
}
Now you will start receiving messages in console.

Can't get ActiveMQ to resend my messages

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

Categories

Resources