I am using JMS via IBM MQ. My sender code:
#Autowired
private JmsTemplate jmsTemplate;
public void sendPHRq(String msg) {
jmsTemplate.send(AntiFraudRq, session -> {
Message message = session.createTextMessage(msg);
LOGGER.info("1" + message.getJMSCorrelationID());
LOGGER.info("2" + message.getJMSMessageID());
return message;
});
}
But in my log I can see only such record:
1null
2null
How can I get my messageid? Because I'm listening reply queue with another listeners, and shouldn't take their messages.
You can get JMSMessageID after message is sent.
It will be generated by MQ JMS right before sending the message.
Related
I have embedded ActiveMQ broker configured in Spring with websocket support (using STOMP).
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketMqConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/topic");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/messaging")
.setAllowedOrigins("*")
.withSockJS();
}
#Bean(initMethod = "start", destroyMethod = "stop")
public BrokerService brokerService() throws Exception {
PersistenceAdapter persistenceAdapter = getPersistenceAdapter();
BrokerService brokerService = new BrokerService();
brokerService.setPersistent(true);
brokerService.setDeleteAllMessagesOnStartup(true);
brokerService.setUseJmx(false);
brokerService.setBrokerName("broker");
brokerService.addConnector("stomp://localhost:61613");
return borkerService;
}
In my JavaScript client I subscribe to topic:
var successHandler = function() {
stompClient.subscribe('/topic/test', function(not) {
pushNotification(not);
}, {'id': clientId, 'activemq.subscriptionName': clientId});
};
var socket = new SockJS('/messaging');
var stompClient = Stomp.over(socket);
stompClient.connect({'client-id': clientId}, successHandler, failureHandler);
And I am using backend service to feed this topic:
#Autowired
private SimpMessagingTemplate messagingTemplate;
messagingTemplate.convertAndSend("/topic/test", event);
And here are my questions:
When I send message to topic, but client haven't been subscribed yet, why messages are not persisted (I suppose that after client subscribe, he should be notified about missed messages)?
If client disconnect from topic, every message is persisted, is there any mean to restrict number of persisted messages, time or size of KahaDB's log files?
Messages sent to a Topic are not persisted unless the client has created a durable Topic subscription previously and the message is sent with the persistent flag set. To create a durable subscription add the headers as specified in the ActiveMQ STOMP documentation.
Once you start using durable Topic subscriptions then yes message can accumulate in the KahaDB store at which point you can configure the store usage limits to control size.
Using Java/Spring to interact with a WebSphere MQ and trying to send a message to it, Spring keeps adding the following header information to it:
RFH Ì ¸MQSTR ¸ <mcd><Msd>jms_text</Msd></mcd> <jms><Dst>queue:///MY.QUEUE.INFORMATION.TEST</Dst><Rto>queue:///MY.QUEUE.INFORMATION.TEST</Rto><Tms>123456789</Tms><Dlv>2</Dlv></jms>BEGINNING_OF_MY_PAYLOAD
How would I remove everything and only send my payload? One could refer to my payload in the snippet above as BEGINNING_OF_MY_PAYLOAD.
Here's the function I'm using:
public void sendMessage(final String text) {
this.jmsTemplate.send(new MessageCreator() {
#Override
public Message createMessage(Session session) throws JMSException {
Message message = session.createTextMessage(text);
destination = session.createQueue("MY.QUEUE.INFORMATION.TEST");
springJmsConsumer.setDestination(destination);
message.setJMSReplyTo(destination);
return message;
}
});
}
Figured it out. Anytime we want to remove headers from our Spring JMS message being sent out to a WebSphere MQ, always use the following:
this.jmsTemplate.convertAndSend("queue:///YOUR.QUEUE.NAME.HERE?targetClient=1", text);
So now my function looks like:
public void send(String text) {
this.jmsTemplate.convertAndSend("queue:///MY.QUEUE.INFORMATION.TEST?targetClient=1", text);
}
I want to use ActiveMQ within Spring Boot app as embedded server. To setup ActiveMQ I used following tutorial: Spring Boot. Messaging with JMS. My app will be the broker and the consumer. There are multiple threads creating messages like this:
#Autowired
private JmsTemplate jmsTemplate;
.......
MessageCreator messageCreator = session -> session.createObjectMessage(transactionNotificationData);
jmsTemplate.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
jmsTemplate.send(QUEUE, messageCreator);
I have another class with following method:
#JmsListener(destination = QUEUE)
public void receive(Message message) throws IOException {
brokerService.getPersistenceAdapter();
try {
if (message instanceof ObjectMessage) {
ObjectMessage objMessage = (ObjectMessage) message;
NotificationData notification = (NotificationData) objMessage.getObject();
LOG.info("Received <" + notification.notification + ">");
...... do some stuff ........
// message.acknowledge();
}
} catch (JMSException e) {
e.printStackTrace();
}
During the tests I can see the messages are produced and consumed.
As you can see message.acknowledge() is commented. So I expect the message will be redelivered after rerun of my app. However it doesn't happen.
Message Acknowledgement is automatically handled by the container and it executes after the onMessage() is successfully executed,(receive() in your case),
so even when you comment message.acknowledge(); , container on its own sends the acknowledgement
you can have a look at following link for more reference
Acknowledgement from Consumer in ActiveMQ
Hope this helps!
Good luck!
Have Apache Camel simple message route from folder to ActiveMQ topic:
//Create context to create endpoint, routes, processor within context scope
CamelContext context = new DefaultCamelContext();
//Create endpoint route
context.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception
{
from("file:data/outbox").to("activemq:topic:Vadim_Topic");
//from("activemq:topic:TEST").to.to("file:data/outbox");
}
});
context.start();
Thread.sleep(5000);
context.stop();
}
And JMS implementation if Topic Consumer:
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
try {
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//connection.setClientID("12345");
connection.start();
Topic topic = session.createTopic("Vadim_Topic");
MessageConsumer messageConsumer = session.createConsumer(topic);
MessageListener messageListener = new MessageListener() {
public void onMessage(Message message) {
TextMessage textMessage = (TextMessage) message;
try {
System.out.println("Received message: " + textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
};
messageConsumer.setMessageListener(messageListener);
} catch (Exception e) {
e.printStackTrace();
}
Can't understand why is my consumer can't recieve messages sent by Camel route??
I guess thet problem is then I need to subscribe my JMS Consumer on messages sent by Camel?
How can I do this if this is the case?
Camel not only allows you to send messages to a topic, it can also very easily read messages from a topic and send it to one of your POJOs.
A route that reads from your topic and sends the messages to a POJO would look like this:
from("activemq:topic:Vadim_Topic").bean(ExampleBean.class);
Camel will figure out which method to call on the POJO depending on the type of message it received, and the available method signatures. See this page for details on using POJO's in camel routes: https://camel.apache.org/bean.html
I'm using Spring JMS and ActiveMQ to send message from a sender to multiple listeners using ActiveMQ Topic (publish/subscribe). So far all listeners can receive message from the sender. But I want to add a functionality that when a particular listener, say listener1, gets the message, listener1 will send a receipt confirmation to the sender. I followed the comment in my old post and created a TemporaryQueue in the sender and used ReplyTo in the sender and receiver to get the confirmation message from the listener to the sender.
My sender class is:
public class CustomerStatusSender {
private JmsTemplate jmsTemplate;
private Topic topic;
public void setJmsTemplate(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
public void setTopic(Topic topic) {
this.topic = topic;
}
public void simpleSend(final String customerStatusMessage) {
jmsTemplate.send(topic, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
TextMessage message = session.createTextMessage("hello world");
message.setStringProperty("content", customerStatusMessage);
message.setIntProperty("count", 10);
//send acknowledge request to a listener via a tempQueue
Destination tempQueue = session.createTemporaryQueue();
message.setJMSCorrelationID("replyMessage");
message.setJMSReplyTo(tempQueue);
return message;
}
});
}
}
The sender creates a TemporaryQueue for the listener to send back the confirmation message. Then in one of the listeners, I have the following code to send the confirmation message back to the sender:
public class CustomerStatusListener implements SessionAwareMessageListener<Message> {
public void onMessage(Message message, Session session) {
if (message instanceof TextMessage) {
try {
System.out.println("Subscriber 1 got you! The message is: "
+ message.getStringProperty("content"));
//create a receipt confirmation message and send it back to the sender
Message response = session.createMessage();
response.setJMSCorrelationID(message.getJMSCorrelationID());
response.setBooleanProperty("Ack", true);
TemporaryQueue tempQueue = (TemporaryQueue) message.getJMSReplyTo();
MessageProducer producer = session.createProducer(tempQueue);
producer.send(tempQueue, response);
} catch (JMSException ex) {
throw new RuntimeException(ex);
}
} else {
throw new IllegalArgumentException(
"Message must be of type TextMessage");
}
}
}
However, I found that the following line in the Listener class throws an error:
TemporaryQueue tempQueue = (TemporaryQueue) message.getJMSReplyTo();
MessageProducer producer = session.createProducer(tempQueue);
The exception error says:
The destination temp-queue://ID:xyz-1385491-1:2:1 does not exist.
So what's wrong here? I assume that tempQueue created by the sender is available for the listener in the same JMS session. Why the tempQueue object after calling message.getJMSReplyTo() does not return a valid TemporaryQueue?
The other question is: How do I receive the confirmation message in the sender? Should I implements MessageListener interface in the sender in order to receive the confirmation from the listener? Or should I just call receive() method to receive it synchronously?
Thanks for any suggestions!
If you are using spring-jms, why not just use a MessageListenerAdapter as your listener? - he will take care of the replyTo stuff and your listener can be a simple POJO.
In any case, you don't need to cast it to a Tempoarary queue; it's just a destination as far as the listener is concerned.
Checkout the MessageListenerAdapter` javadocs.
Also, you need to create a consumer on the temp queue on the sending side, to receive the reply. If the sending connection is closed, the temp queue will go away.
I ended up using a separate JMS Queue to send the acknowledge message from the listener-1 to the sender. For some reason, the temporaryQueue created by ActiveMQ is not available during the JMS session.