What is the difference between channel vs. broker vs. destination in Spring websocket?
I recently started working with a websocket and from what I understood:
registry.addEndpoint("/wsocket/") adds a websocket endpoint which is solely used when clients wants to connect to the websocket service:
this.client.configure({
brokerURL: `ws://localhost:9022/wsocket`,
onConnect: () => {
this.client.subscribe('/quote/fb', message => {
console.log(message);
});
}
});
this.client.activate();
config.enableSimpleBroker("/quote") enables a channel/broker, letting clients to subscribe to it and receive messages published/sent over it. Clients are able to subscribe to any /quote/* on the server.
config.setApplicationDestinationPrefixes("/app") sets the application prefix, which clients use to send message directly to the app and not through the broker.
Is my understanding correct?
I think your understanding is correct .
Broker
A message broker acts as an intermediary platform when it comes to processing communication between two applications. In the context of spring websocket :
When you use Spring’s STOMP support, the Spring WebSocket application acts as the STOMP broker to clients. Messages are routed to #Controller message-handling methods or to a simple in-memory broker that keeps track of subscriptions and broadcasts messages to subscribed users. You can also configure Spring to work with a dedicated STOMP broker (such as RabbitMQ, ActiveMQ, and others) for the actual broadcasting of messages. In that case, Spring maintains TCP connections to the broker, relays messages to it, and passes messages from it down to connected WebSocket clients.
Channel
It can be thought of as a logical segregation of messages in one or both directions. For example, there can be three channels. One for request(incoming to the server), second one for response(outgoing from the server) and third one for error (outgoing from the server).
Destination
It can be thought of another level of hierarchical nesting for a channel. I find this image helpful to understand it :
https://docs.spring.io/spring/docs/5.1.3.BUILD-SNAPSHOT/spring-framework-reference/images/message-flow-simple-broker.png
[![enter image description here][1]][1]
Clients can use the SEND or SUBSCRIBE commands to send or subscribe for messages, along with a destination header that describes what the message is about and who should receive it. This enables a simple publish-subscribe mechanism that you can use to send messages through the broker to other connected clients or to send messages to the server to request that some work be performed.
I find Spring documentation on this topic to be very helpful : https://docs.spring.io/spring/docs/5.1.3.BUILD-SNAPSHOT/spring-framework-reference/web.html#websocket-stomp-handle-simple-broker .
Related
I want to run a Java based message broker that will route messages to web clients. Web client connections are handled on our server using our custom Java websocket code, which authenticates users against the user database.
I think my server side websocket handler code would connect to ActiveMQ and perform subscription management via AQMP.
I have a specific requirement however:
route messages for a topic specifically to one or more web clients
Note that I don't need to retain messages if a client is not connected. Messages are being used to inform the web client applications of actions they need to take.
I'm considering ActiveMQ but I was hoping people with experience of the product could clarify if it supports this requirement?
If ActiveMQ isn't the best option, could you recommend something else?
Thanks
Yes, ActiveMQ is a great choice for this.
As far as specific approach goes, it depends on your data model and message flow.
You have several options, including:
Produce and consume to a topic-per-client
a. Messages for Client ABC go to topic://CLIENTS.ABC, for Client XYZ go to topic://CLIENTS.XYZ, and the subscribers connect accordingly.
Produce a message with a header and use a consumer-side selector (aka 'filters' in AMQP) to filter messages on a per-client basis. (abc client subscribes to-- ClientId = ABC, xyz client subscribe to-- ClientId = XYZ)
When using WebSockets, you might also look to STOMP which is text-based protocol. (Just depends on your programming language and available libraries that you had in mind)
I have multiple instances using Spring Boot WebSocket (created following the first half of Spring's guide). I need them to connect to other instances at specific hostnames and ports and to be able to send messages over the websocket connection using STOMP protocol.
How can I connect to my other services over websocket?
How can I send messages using the STOMP protocol (preferably using the same marshalling/unmarshalling magic I get with received messages)?
Things that don't answer my question:
I have read Spring: send message to websocket clients and Sending message to specific user on Spring Websocket but these and other questions seem to all assume that a client has already initiated a connection and that there are users and topics established. This is not my use case as my services are both server AND client.
I am not using a cluster and I am not sharing sessions across instances as in Spring Websocket in a tomcat cluster
I have found some resources that cast some light on how to accomplish this:
http://www.baeldung.com/websockets-api-java-spring-client
https://www.sitepoint.com/implementing-spring-websocket-server-and-client/#javaspringchatclient
http://useof.org/java-open-source/org.springframework.messaging.simp.stomp.StompSessionHandler
number 3 is at least a complete implementation but is unfortunately devoid of comments to explain what's going on.
Is there any way to get notification from server whenever it is on?
my requirement is when ever ActiveMQ is on a piece of code will run automatically
in ActiveMQ is there is no load on startup
Create a publisher in your language of choice that periodically sends a test message to ActiveMQ.
Create a subscriber in your language of choice that receives the test messages and notifies you via your mechanism of choice that it has successfully received a test message.
The Apache ActiveMQ broker supports discovery with IP multicast.
Applications can use discovery for JMS clients to auto-detect a Message Broker to connect to.
This could also be used to monitor a broker's status, using Java MultiCast support.
To invoke a piece of code when the broker is started, you can perhaps base it off either an embedded Camel route or broker interceptor. The idea being that when the broker is started, so will these components and thus allows them to issue whatever sort of notification you require.
I am considering an architecture where I have clients that are intermittently connected to a network. I would like to store messages created on these clients in a JMS queue when the network is not available and have these forwarded to a central message broker when the clients are on the network. (The user has control over the network, e.g. dialing in, so it's not an intermittent connection like with a mobile phone.)
Are there any JMS implementations that provide this feature?
You can embed an activeMQ broker into your application
http://activemq.apache.org/how-do-i-embed-a-broker-inside-a-connection.html
Then, I suppose (did not test) that you could use ActiveMQ features which allow you to dispatch messages accross a net of brokers, using the discovery of brokers feature,
http://activemq.apache.org/clustering.html
or simply by adding a queue consumer server side, then dispatching through other brokers through this consumer.
Hope it helps.
The Glassfish Open Message Queue can be embedded (or run stand-alone) in version 4.4 (Support the ability for a broker to run "in process" with any client.). It is very light-weight, and will support other client languages over the STOMP protocol in version 4.4 - besides Java and C. - https://mq.dev.java.net/4.4.html
One of our products implements the following one-way web service structure:
Server <--------------------- Middleware <---------------- Client
SOAP over JMS (queue) SOAP over HTTP
In this model, clients send SOAP messages over HTTP to our middleware (Progress SonicMQ). The messages get pushed into JMS queues by SonicMQ and our server fetches them from there. However, as you can see, the server does not send a response to the client (asynchronous JMS).
We would like to implement a response-channel to this model. The often suggested solution is to create a temporary replyTo-queue (on the fly) in the middleware, allowing server to send a response to that queue. Then, client can fetch the response and the replyTo-queue is closed. This sounds convenient enough, but unfortunately our clients operate over plain HTTP and not over JMS, so their clients can not easily set up replyTo queues.
One approach to achieving a response channel in such hybrid HTTP/JMS SOAP model would be to configure the middleware to open the replyTo queue on each succesful SOAP receive, append the replyTo-queue and sender information to the SOAP message and push the message to the queue, where it would be fetched by the server. After receiving and processing the message, the server could send a response to the indicated replyTo-queue in the middleware. Finally, the middleware would send the response (SOAP) over HTTP back to the original client by using the data from the SOAP message (the data that was inserted there in the middleware procedures when the request was first received).
While propably possible, this sounds kind of a hacky. So the question is: any cleaner ways of achieving such request/response model on our case? The server end has been implemented in Java.
The solution:
Progress SonicMQ supports "Content Reply Send" HTTP Acceptor, which allows to easily send JMS reply. The Content Reply Send acceptor works in a following way:
Acceptor receives the HTTP message a client sent
Acceptor creates a temporary JMS queue
Acceptor builds up a JMS message, containing the HTTP body, and adds the temporary queue's identification to the newly created JMS message
Acceptor pushes the JMS message into its destination queue (not the temporary queue)
Acceptor starts consuming the temporary reply-To queue
When client fetches message from original destination queue, it contains the set reply-To queue identification
Client consumes message
Client sends reply to the reply-To queue
Acceptor receives message from the queue
Acceptor sends message as HTTP to the client that originally sent the HTTP message
Should consumer ("server" in our case) fail and not send reply causing timeout, Sonic's HTTP Acceptor sends an HTTP message to the client indicating the timeout. This is a very standard feature in SonicMQ. I suppose it exists in other products as well.
This allows using standard SOAP over JMS (see skaffman's answer) in the "server" end avoids any custom programming in the middleware.
I still see some problems in the JMS model though, but this is definitely an improvement.
Update 2009-11-05:
After researching this issue even more, it turns out my suspicion against HTTP<-->middleware<-->JMS has been relevant.
There are a few critical problems in this model. Synchronous-asynchronous model with middleware simply isn't convenient. Either have both ends implement JMS connection (which should rock) or go with HTTP in both ends. Mixing them results only in headaches. Of these two, SOAP-over-HTTP is simpler and better supported than SOAP-over-JMS.
Once more: if you are designing this kind of a system... DON'T.
I don't think your suggested solution is hack at all, I think that's the right solution. You have the client-middle layer with a synchronous protocol, and then the middle-server layer using an asynchronous layer, to which you have to add a reply path in order to satisfy the synchronous semantics. That's what middleware is for. Remember that that JMS provides explicit support for temporary reply-to queues, you won't need to mess with the payload at all.
A more left-field possibility is the leverage the fact that SOAP 1.2 was designed with JMS in mind, and so you could use web service layer between middleware and server layer which does SOAP-over-JMS. That means you can keep SOAP from end-to-end, with the middleware changing only the transport.
The only web service stack that I know of that supports JMS transport is Spring Web Services, where the process and development is documented here. This would also give you the opportunity to port your SOAP layer to Spring-WS, which kicks ass :)
Why not add a link to a page that lets users check to see when a response is ready, a la a Fed Ex tracker ID? Give your users the tracker ID when they send the request.
This would fit into the HTTP request/response idiom, and your users would still know that the request is "fire and forget".