Get the stomp client used internally by Spring Broker Relay - spring

I'm trying to setup a broker relay in Spring with RabbitMQ being the broker. Things work as intended when all events originate from my browser, however, sometimes I have events generated on the server side dynamically. I want to send these too to RabbitMQ to take advantage of things like durable topics or TTL for messages. As far as my understanding goes, using SimpleMessagingTemplate.convertAndSend() and convertAndSendToUser both end up sending the event to the browser instead of broker.
As of now, I'm trying to create a new stomp client to rabbitmq and send events through that. But I can't help feel it to be a bit hacky. Is there a way to get a hold on the stomp client used by Spring and forward my messages easily? Or am I missing something here?
Any help is appreciated, thanks!

Took a while but turns out you don't need to get a hold of the internal stomp client (it's actually an internal TcpClient from Reactor Netty though) or anything like that. Following are the steps you need to do when you want a little bit of customization:
Spring uses #EnableWebSocketMessageBroker to configure the broker or you can extend DelegatingWebSocketMessageBrokerConfiguration. I ended up extending it, it makes little difference though.
In configureMessageBroker(MessageBrokerRegistry registry), use the registry and enable stomp relay and the important part: for the registry in the same method, add ChannelInterceptors. You can get the stomp command and process it as required. The idea is identical to Spring Intercetpors. Add the headers needed inside that.
final StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(message);
StompCommand command = headerAccessor.getCommand();
Then finally, recreate the message for sending.
MessageBuilder.createMessage(new byte[0], accessor.getMessageHeaders());
Lastly, you can test if things are actually going to RabbitMQ management console to observe if messages are actually being sent.

Related

What’s the difference between AbstractMessageSource and MessageProducerSupport in Spring Integration?

When developing inbound channel adapters, I couldn’t find any place that mentions the differences between AbstractMessageSource and MessageProducerSupport in Spring Integration. I’m asking this question in the context of reactive streams, so I’m actually looking at AbstractReactiveMessageSource, but I guess it doesn’t matter for my question. I also wonder whether MessageProducerSupport supports project reactor and doesn’t have an equivalent to AbstractReactiveMessageSource.
There is some documentation about these types of components: https://docs.spring.io/spring-integration/docs/current/reference/html/overview.html#finding-class-names-for-java-and-dsl-configuration
The inbound message flow side has its own components, which are divided into polling and listening behaviors.
So, the MessageProducerSupport is for those protocols which provide a listening callback for us. So, we can hook up into that, build message and produce it into a channel provided by the MessageProducer. So, it is self-eventing component which really has everything to listen to the source system and produce messages from the callback. This type of channel adapters called event-driven and samples of them are JMS, AMQP, HTTP, IMAP, Kinesis etc.
From here it is wrong to try to compare the MessageProducerSupport with an AbstractMessageSource because the are not relevant. The one you should look into is a SourcePollingChannelAdapter. Exactly this one is that kind of flow beginning endpoint which is similar to MessageProducerSupport. With only the problem that it is based on a periodic scheduled task to request for messages in the provided MessageSource. This type of component is for those protocols which don't provide listening callback, e.g. local file system, (S)FTP, JDBC, MongoDb, POP3, S3 etc.
You probable would expect something similar to MessageSource for the MessageProducer level, but there is not that kind of layer because everything single event-driven protocol has its own specifics, therefore we cannot extract some common abstraction like in case of polling protocols.
If your source system provides for you a reactive Publisher, you don't need to look into a SourcePollingChannelAdapter and MessageSource. You just need a MessageProducerSupport and call its subscribeToPublisher(Publisher<? extends Message<?>> publisher) from the start() implementation.
There is no need in the reactive implementation for the polling since Publisher is not pollable by itself it is event-driven. Although it has its own back-pressure specifics which is out of MessageProducerSupport scope.
There is also some explanation in this section of the doc: https://docs.spring.io/spring-integration/docs/current/reference/html/reactive-streams.html#source-polling-channel-adapter. And see a couple next paragraphs.

How should you handle the retry of sending a JMS message from your application to ActiveMQ if the ActiveMQ server is down?

So using JMS and ActiveMQ, I can be sure that my message sent from my Spring Boot application using JmsTemplate will reach it's destination application even if that destination application is down at the time I send the message to ActiveMQ. As when the destination application starts up, it grabs the message from the queue. Great!
However.
What happens if my Spring Boot application tries to send a JMS message to a queue on the ActiveMQ server, but the ActiveMQ server is down at that point or the network is down and I get a connection refused exception?
What is the recommended way to make sure my application keeps trying to re-sends the message to ActiveMQ until it is successful? Is this something I have to develop into my application myself? Are there any nifty Spring tools or annotations which do this for me? Any advice on best practice or how I should be handling this scenario?
You can try Spring-Retry. Has lots of fine grain controls for it:
http://www.baeldung.com/spring-retry
https://github.com/spring-projects/spring-retry
If it is critical that you don't lose this message, you will want to save it to some alternative persistent store (e.g. filesystem, local mq server) along with whatever retry code you come up with. But for those occasional network glitches or a very temporary mq shutdown/restart, Spring-Retry alone should do the trick.
Couple of approaches I can think of
1. You can set up another ActiveMq as fallback. In your code you don't have to do anything, just change your broker url from
activemq.broker.url=tcp://amq01.blah.blah.com:61616
to
activemq.broker.url=failover:(tcp://amq01.blah.blah.com:61616,tcp://amq02.blah.blah.com:61616)?randomize=false
The rest is automatically taken care of. i.e. when one of them is down, the messages are sent to other.
Another approach is to send to a internal queue (like seda, direct) when activemq is down and read from there.
Adding failover to the url is one appropriate way.
And another reasonable way is to making sure activemq always online , as activemq has the master-slave mode(http://activemq.apache.org/masterslave.html) to get high availability.

Spring-boot app displaying JMS messages on WebPage via WebSocket

I need a simple web-app in spring-boot that listens for messages on a JMS queue and when arriving it should appear on a webpage via WebSocket.
I have searched for examples and found several individual; either WebSocket or JMS which I have tested on their own but have not succeeded in wiring it together.
I have searched for an example but not found any and in my mind I think it should be pretty easy since it's a very basic requirement.
Do you know about any example with JMS and HTML display via WebSocket that you can share or can give some hints or help for me to solve it?
The Spring Integration comes to the rescue.
You can write <int-jms:message-driven-channel-adapter> to read messages from JMS queue and forward them to the <int-websocket:outbound-channel-adapter>. Where the last one just sends messages to the connected WebSocket session(s).
See these Spring Integration samples on the matter:
https://github.com/spring-projects/spring-integration-samples/tree/master/basic/jms
https://github.com/spring-projects/spring-integration-samples/tree/master/basic/web-sockets
UPDATE
To send the message to all subscribed WebSocket session you should do something like this:
<int:splitter input-channel="enricheMessage" output-channel="sendMessage" apply-sequence="false">
<int-groovy:script>
#serverWebSocketContainer.sessions.keySet().collect {
org.springframework.integration.support.MessageBuilder.withPayload(payload)
.copyHeaders(headers)
.setHeader('simpSessionId', it)
.build()
}
</int-groovy:script>
</int:splitter>
With this Groovy script I retrieve session ids from the serverWebSocketContainer (all those connected clients), iterate over them to build messages to send them over their websocket. And split finally, to send to the <int-websocket:outbound-channel-adapter> one by one.

Spring Integration : QueueChannel guarantee no data loss?

I want my system to guarantee there is no data loss even if the system is shutting down.
What this mean is that the system must not miss the request message. So, I will change the way that accept http reqeust. Now, I am using http gateway/webservice gateway in spring integration. But, This isn't receive the message even if the system dies. So, I want to add the queue between the http client and the http receiver. So, I want to use a queue channel. Here is the question.
① I have to install other queue program such as activemq or rabbitmq and have to connect to the queue channel in spring integration?
② and which one is the best combination with spring integration? I heard that rabbit mq is the best one.
please give me a elaborate explanation. thanks.
First of all you description isn't clear...
If you don't want to lose messages from the QueueChannel use some Persistence MessageStore, like JdbcChannelMessageStore:
http://docs.spring.io/spring-integration/docs/latest-ga/reference/html/system-management-chapter.html#message-store
From other side there are channel wrappers for the AMQP as well as for JMS:
http://docs.spring.io/spring-integration/docs/latest-ga/reference/html/amqp.html#d4e5846
http://docs.spring.io/spring-integration/docs/latest-ga/reference/html/jms.html#jms-channel
Which really provide the same persistence durability, fault tollerant options for your use-case.
Re. activemq VS rabbitmq. I can say by my own expiriance that the last one is better, by configuration, usage from Spring Integration (Spring AMQP is under the shell). And its performance is really better.
All other info you can find in the Internet.

Recover connection when using Spring JMSTemplate and ApacheMQ

//OVERVIEW//
I have a Java Swing Client that is pushing messages to a broker. For the producer, I am using the Spring SingleConnectionFactory:
org.springframework.jms.connection.SingleConnectionFactory
that is wrapped around an ActiveMQConnectionFactory:
org.apache.activemq.ActiveMQConnectionFactory
I am using the Spring JMSTemplate:
org.springframework.jms.core.JmsTemplate
to provide the mechanisms to send messages from the producer to the broker.
// PROBLEM //
Sometimes, the broker might go down, or the network might fail. When this happens, the only way I have been able to re-establish connection to the broker is to re-start the Swing application (producer) to re-initialize the components mentioned above.
Does anyone know how this might be done at run-time? Atempting to re-initialise beans at runtime sounds like a hack and I was wondering if there was a more elegant configuration option.
Thanks

Resources