Get notified when a JMS message is consumed - java

Is there a way to get notified when a JMS Message is consumed from a JMS queue? Like a listener or notification?
Thanks

I assume you are using ActiveMQ since you tagged the question with it.
You can register for an advisory notification when a message is consumed by a client. See the docs for advisories and the one you're looking for is ActiveMQ.Advisory.MessageConsumed.Queue.
===== Update =====
Oh, errr.. you're using Joram, not ActiveMQ. It's not as simple, but you could use a client side interceptor which will return an acknowledgement message back to a queue or a topic which you would then listen on. The interface looks like this:
public interface MessageInterceptor {
public void handle(javax.jms.Message pMessage, javax.jms.Session pSession);
}
See chapter 3.5. Message interceptors of the latest Joram doc PDF.
You could also use a interceptor_out server side interceptor.

No the JMS API doesnt provide any way to message delivery notification options. This will have to be done at the application level.

Related

Azure Service bus with AMQP - how to specify the session ID

I am trying to send messages to Service bus using AMQP QPID java library
I am getting this error:
"SessionId needs to be set for all brokered messages to a Partitioned
Topic that supports Ordering"
My topic has "Enforce Message ordering" turned on (this is way i get this error i guess)
When using the Azure Service bus java library (and not AMQP) i have this function :
this.entity.setSessionId(...);
When using the AMQP library i do not see an option to set the session ID on the message i want to send
Note that if i un-check the option "Enforce Message ordering" the message will be sent successfully
This is my code
private boolean sendServiceBusMsg(MessageProducer sender,Session sendSession) {
try {
// generate message
BytesMessage createBytesMessage = (BytesMessage)sendSession.createBytesMessage();
createBytesMessage.setStringProperty(CAMPAIGN_ID, campaignKey);
createBytesMessage.setJMSMessageID("ID:" + bm.getMessageId());
createBytesMessage.setContentType(Symbol.getSymbol("application/octet-stream"));
/*message is the actual data i send / not seen here*/
createBytesMessage.writeBytes(message.toByteArray());
sender.send(createBytesMessage);
} catch (JMSException e) {
}
The SessionId property is mapped to AMQP message properties.group-id. The Qpid JMS client should map it to JMSXGroupID property, so try the following,
createBytesMessage.setStringProperty("JMSXGroupID", "session-1");
As you guessed, there is a similar SO thread Azure Service Bus topics partitioning verified that to disable the feature Enforce Message Ordering via set SupportOrdering with false can solve the issue, but it can't be done via Azure Service Bus Java library because the property supportsOrdering is privated now.
And you can try to set property Group as #XinChen said using AMQP, as the content below from here.
Service Bus Sessions, also called 'Groups' in the AMQP 1.0 protocol, are unbounded sequences of related messages. ServiceBus guarantees ordering of messages in a session.
Hope it helps.

Paho-Mqtt Publish from callback messageArrived()

I have an application using MQTT implemented with the paho-mqtt-1.0.2 and I am using ActiveMQ as the broker. I have a class implementing the MqttCallback, what I am wondering is why does the client hang
#Override
messageArrived(...)
do work
mqtt.publish(TOPIC,PAYLOAD,2,false) <- here
I want to send a "response" message to the broker for the next step of the work to be done. Similar to this, I read in the docs for that callback function
It is possible to send a new message within an implementation of this callback (for example, a response to this message), but the implementation must not disconnect the client, as it will be impossible to send an acknowledgment for the message being processed, and a deadlock will occur.
Has anyone out there tried doing the above and get it to work?
I also tried using the MqttAsyncClient and that ended up with
"Error too many publishes in progress" leading to undelivered messages.
I know how to get around this issue, I'm not looking for workaround; I'm looking for receiving and publishing on the thread where messageArrived() gets executed.
Happy Hunting!

RabbitMQ: How to specify the queue to publish to?

RabbitMQ's Channel#basicConsume method gives us the following arguments:
channel.basicConsume(queueName, autoAck, consumerTag, noLocal,
exclusive, arguments, callback);
Giving us the ability to tell RabbitMQ exactly which queue we want to consume from.
But Channel#basicPublish has no such equivalency:
channel.basicPublish(exchangeName, routingKey, mandatory, immediateFlag,
basicProperties, messageAsBytes);
Why can't I specify the queue to publish to here?!? How do I get a Channel publishing to, say, a queue named logging? Thanks in advance!
To expand on #Tien Nguyen's answer, there is a "cheat" in RabbitMQ that effectively lets you publish directly to a queue. Each queue is automatically bound to the AMQP default exchange, with the queue's name as the routing key. The default exchange is also known as the "nameless exchange" - ie its name is the empty string. So if you publish to the exchange named "" with routing key equal to your queue's name, the message will go to just that queue. It is going through an exchange as #John said, it's just not one that you need to declare or bind yourself.
I don't have the Java client handy to try this code, but it should work.
channel.basicPublish("", myQueueName, false, false, null, myMessageAsBytes);
That said, this is mostly contrary to the spirit of how RabbitMQ works. For normal application flow you should declare and bind exchanges. But for exceptional cases the "cheat" can be useful. For example, I believe this is how the Rabbit Admin Console allows you to manually publish messages to a queue without all the ceremony of creating and binding exchanges.
Basically queues can be binded to an exchange based on routingKeys.
Assume that you have 3 different publishers.
Publisher1 sending message to exchange with routingKey "events"
Publisher2 sending message to exchange with routingKey "tasks"
Publisher3 sending message to exchange with routingKey "jobs"
You can have a consumer that consumes only messages with specific routhingKey.
For example in order to have a consumer for "events" messages you declare like this
channel.queueBind(queueName, exchangeName, "events");
If you want to consume all the messages coming to the exchange you give the routing as '#'
So in short what i can say is,
1. Messages will be published to an exchange.
2. Queues will be bound to exchange based on routingKeys.
3. RabbitMQ will forward messages with matching routing keys to the corresponding queues.
Please see the tutorial - http://www.rabbitmq.com/tutorials/tutorial-three-java.html
The core idea in the messaging model in RabbitMQ is that the producer never sends any messages directly to a queue. Actually, quite often the producer doesn't even know if a message will be delivered to any queue at all. Instead, the producer can only send messages to an exchange
please try this:
channel.basicPublish("", yourQueueName, null,
message.getBytes((Charset.forName("UTF-8"))));
It worked for my project.

how to delay JMS message in spring on weblogic 10.3 server

I want to delay message delivery by certain time which will be different for each message.
I referred weblogic 10.3 WLMessage documentation which recommends using javax.jms.Message.getIntProperty("JMS_BEA_DeliveryTime").
However I'm unable to figure out how do I set JMS_BEA_DeliveryTime as INTEGER. I was expecting it to be long.
I'm unable to find out any documentation about this attribute JMS_BEA_DeliveryTime to undesratand how to set and use it. Can anybody give example about how to set the desired delivery time or link to documenation of use of this attribute.
My code looks like typical use of Spring JMS template:
jmsTemplate.send(destination, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
TextMessage message = session.createTextMessage(textMessage);
return message;
}
});
I was wondering if it is possible to set header for delivery time before returning message.
Good article with examples of delaying delivery for different JMS providers, include WL.
Well there is this page which states
JMS Delivery Time: The earliest absolute time at which
a message can be delivered to a consumer.
It should be trivial to set with Message.setIntProperty(...), there is not much mention as to what the time actually constitutes though, although I did find this article which suggests milliseconds from now.
Hope that helps.

How to send Message to particular Receiver using JMS Queue

Is it possible to send message to particular receiver using JMS Queue(HornetQ)?
Among so many receivers, I want certain message to be received by receiver which
are running on Linux OS.
Every suggestion is appriciated.
Thanks.
You can set a message property using Message.setObjectProperty(String, Object) and then have your consumers select the messages they are interested in using Session.createConsumer(Destination, String)
Sender example:
Message message = session.createMessage();
message.setObjectProperty("OS", "LINUX");
producer.send(message);
Receiver example:
MessageConsumer consumer = session.createConsumer(destination, "OS = 'LINUX'");
//Use consumer to receive messages.
The receiver in the example will ignore (they will go to some other receiver) all messages that do not match the selector. In this case all message where the 'OS' property is not 'LINUX' will be ignored by this consumer.
You can set properties of JMS message: http://download.oracle.com/javaee/1.4/api/javax/jms/TextMessage.html and filter messages at client side.
For example,
message.setStringProperty("TARGET_OS", "LINUX") - at sender
http://www.mkyong.com/java/how-to-detect-os-in-java-systemgetpropertyosname/ - detect OS at receivers and filter messages with correct TARGET_OS property
You can use JMS selectors on the consumer side to look for messages that fit specific criteria.
Not sure if I am missing something, you could keep things simple by having multiple queues - specific to each platform, then the linux based consumers can listen to the linux specific queue alone. Now your challenge probably will be to route the messages to the appropriate queue from the producer side, that should be fairly easy if the routing is based on some attribute of the message?

Categories

Resources