Message Driven Bean does not receive messages - java

I'm trying to implement a service which listens to a topic to receive messages sent to that topic. The code is quite simple:
#MessageDriven(mappedName="jms/TEST", activationConfig={
#ActivationConfigProperty(propertyName="destinationType",propertyValue="javax.jms.Topic"),
#ActivationConfigProperty(propertyName="subscriptionName",propertyValue="TEST")
})
public class MessageListener implements MessageListener {
private static final Logger logger = Logger.getLogger(MessageListener.class);
#Override
public void onMessage(Message arg0) {
logger.info("Receiving " + arg0);
}
}
The listener is deployed on Glassfish. In Glassfish, I also add an Admin Object Resource:
JNDI Name: jms/TEST
Resource Adaptor: jmsra
Resource Type: javax.jms.Topic
Class Name: com.sun.messaging.Topic
Name: TEST
Physical Name: TEST
I have another service, also in Glassfish, sending messages to topic TEST. However, my listener doesn't receive any messages at all. I create another service listening to the same topic without using Message Driven Bean and am able to receive, i.e. a message is sent without any problem. I wonder if I do anything wrong with my bean.
L

Related

How can I route messages from a single RabbitMQ queue to separate methods?

I've got a Spring Boot application. I've been designing microservices and these microservices communicate with each other via RabbitMQ. There is a channel service for directing my messages to related microservices. You can see the picture below.
My channel and microservices picture
Channel is directing messages to microservice 1, but microservice 1 should get my message to a specific method, for example, getById() method or createAThing() method.
How can I route my message to the related listener method?
Here is my code that consumes queue:
#RabbitListener(queues = "my-single-queue")
public void createObjectByMessage(Message message) {
// Create object with message
}
#RabbitListener(queues = "my-single-queue")
public void getByIdByMessage(Message message) {
// Get object with message ID
}
Or, how can I consume the message from the same queue but using a different routing key? I have no config class. I'm using #RabbitListener annotation.

Capture MQ down event from Spring JMS

Does Default Message Listener Container of Spring have any method like ErrorHandler where I can Capture MQ down Event.
I can get following logs from spring but need to report when MQ is down.
o.s.j.l.DefaultMessageListenerContainer : Setup of JMS message listener invoker failed for destination
o.s.j.l.DefaultMessageListenerContainer : Successfully refreshed JMS Connection
How can I achieve this?
Finally I solved my issue by overrding refreshConnectionUntilSuccessful of DefaultMessageListenerContainer as below:
public class MessageListenerContainer extends DefaultMessageListenerContainer {
#Override protected void refreshConnectionUntilSuccessful() {
super.refreshConnectionUntilSuccessful();
// Your own implementation goes here like sending an email
logger.error(MessageListenerContainer.class, new Exception("MQ CONNECTION LOST"));
}}

How to work with rabbitTemplate receiveAndReply

I have just started experimenting with Spring and rabbitMQ.
I would like to create a microsevice infrastructure with rabbit and spring,
I have been following Spring boot tutorial
But it is very simplistic. As well I am looking at the documentation (springs, Rabbit) for how to create an RPC, i understand the Rabbits approach, but i would like to leverage Spring template to save me the boilerplate.
I just cant seem to understand where to register the reciveAndReplay callback at.
I tried doing this:
sending
System.out.println("Sending message...");
Object convertSendAndReceive = rabbitTemplate.convertSendAndReceive("spring-boot", "send and recive: sent");
System.out.println("GOT " + convertSendAndReceive); //is null
receiving
#Component
public class Receiver {
#Autowired
RabbitTemplate rabbitTemplate;
public void receiveMessage(String message) {
this.rabbitTemplate.receiveAndReply("spring-boot", (Message)->{
return "return this statement";
});
}
}
But its not a big surprise this doesn't work the message is received but nothing comes back. I assume that this needs to be registered somewhere in the factory/template at the bean creation level but i don't seem to understand where and sadly the documentation is unclear.
First, please use the Spring AMQP Documentation.
You would generally use a SimpleMessageListenerContainer wired with a POJO listener for RPC.
The template receiveAndReply method is intended for "scheduled" server-side RPC - i.e. only receive (and reply) when you want to, rather than whenever a message arrives in the queue. It does not block waiting for a message.
If you want to use receiveAndReply(), there's a test case that illustrates it.
EDIT:
This code...
this.template.convertAndSend(ROUTE, "test");
sends a message to the queue.
This code...
this.template.setQueue(ROUTE);
boolean received = this.template.receiveAndReply(new ReceiveAndReplyMessageCallback() {
#Override
public Message handle(Message message) {
message.getMessageProperties().setHeader("foo", "bar");
return message;
}
});
Receives a message and from that queue; adds a header and returns the same messsage to the reply queue. received will be false if there was no message to receive (and reply to).
This code:
Message receive = this.template.receive();
receives the reply.
This test is a bit contrived because the reply is sent to the same queue as the request. We can't use sendAndReceive() on the client side in this test because the thread would block waiting for the reply (and we need to execute the receiveAndReply()).
Another test in that class has a more realistic example where it does the sendAndReceive()s on different threads and the receiveAndReply()s on the main thread.
Note that that test uses a listener container on the client side for replies; that is generally no longer needed since the rabbit broker now supports direct reply-to.
receiveAndReply() was added for symmetry - in most cases, people use a listener container and listener adapter for server-side RPC.

Push Message from ActiveMQ to Spring Controller

I'm using Spring MVC, ActiveMQ and WebSocket(via sock.js and stomp.js) to build a real-time data delivery application.
As we know, when a producer(another desktop application) push a message to ActiveMQ, and the onMessage() method will catch it.
public class MessageReceiver implements MessageListener {
public void onMessage(Message message) {
System.out.println(message);
// How to push the message to a Controller in Spring?
}
}
Most of the tutorials just print the message to the console.
I have another controller called WebSocketController:
#Controller
public class WebSocketController {
#SubscribeMapping("/getRealTimeResult.action/{submissionId}")
public Message getRealTimeResultAction(
#DestinationVariable long submissionId) {
return new Message("Message content from onMessage() method");
}
}
I want to push the message received in onMessage() method to the getRealTimeResultAction() method. Can you tell me how to do it?
I know that the ActiveMQ can communicate with the browser using stomp via the port 61613.
I don't want to do this because I think the MQ should be transparent to the user. Also I need to do some authorization in the WebSocketController.
Generally speaking an #Controller with #SubscribeMapping and #MessageMapping methods can handle subscriptions and messages from STOMP clients connected over WebSocket.
From your description it's not clear what you're trying to do. Was the message pushed to ActiveMQ via STOMP from a browser client or was it produced by some other back-end JMS client? Also the MessageReceiver receives an actual message while the #Controller method has an #SubscribeMapping method for handling a subscription from a STOMP client. It's not clear what you're trying to do. Please provide more information so I can provide a better answer.

spring websockets: sending a message to an offline user - messages not enqueued in message broker

I have a webapp with spring and websockets using a message broker (activemq).
here is my config class:
#Configuration
#EnableWebSocketMessageBroker
#EnableScheduling
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableStompBrokerRelay("/topic","/queue/");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/hello").withSockJS();
}
}
I have a scheduled task that constantly pushing messages to the username "StanTheMan" :
#Scheduled(fixedDelay = 1000)
public void sendGreetings() {
HelloMessage hello = new HelloMessage();
hello.setContent("timeStamp:" + System.currentTimeMillis());
String queueMapping = "/queue/greetings";
template.convertAndSendToUser(
"DannyD",
queueMapping,
hello);
}
Currently, if the user is NOT connected via a websocket to the server - all the messages for him are not being en-queued for him, they simply discarded. whenever he connects - fresh messages are being en-queued for him.
Is it possible for me to "convertAndSendToUser" a message to an offline user in any way? i would like to en-queue messages with an expired time for offline users to be later on pushed when they are connecting again and the expired time wasn't over.
how can i achieve that? Obviously using a real message broker (activemq) supposed to help achieving that, but how?
Thanks!
Indeed this feature can only be used to send messages to a (presently) connected user.
We plan to provide better ways to track failed messages (see SPR-10891). In the meantime as a workaround you could inject the UserSessionRegistry into your #Scheduled component and check if the getSessionIds methods returns a non-empty Set. That would indicate the user is connected.
One alternative may be to use your own convention for a queue name that each user can subscribe to (probably based on their user name or something else that's unique enough) in order to receive persistent messages. The ActiveMQ STOMP page has a section on persistent messages and expiration times.
This is a default behavior for message brokers.
And you haven't setup the ActiveMQ broker as your default broker so Spring is setting up a in-memory broker.
To achieve what you want setup/give your details of activeMQ to your spring websocket message broker. As Spring doesn't provide these settings, you have to do all the persistence settings at the ActiveMQ side. .
To setup ActiveMQ for spring websocket message broker you also need to enable stomp and use this:
registry.enableStompBrokerRelay("/topic").setRelayHost("hostName").setRelayPort("00000");
For more information checkout:
http://docs.spring.io/spring/docs/4.0.0.RELEASE/javadoc-api/org/springframework/messaging/simp/config/StompBrokerRelayRegistration.html

Categories