I want to create a REST service to turn on the light. The architecture that I want to have is the following:
I would like to accomplish this using Spring Integration framework. I was thinking of something like:
Request : Inbound HTTP GW -> Outbound Websocket GW
Response: Inbound HTTP GW <- Inbound Websocket GW
The problem is that I don't know how to specify the websocket client. Any idea how to do it ?
For now, and based on the answers I have received this is the pseudo-code that provides the solution:
<!-- REST service to turn on the light -->
<int-http:inbound-gateway
supported-methods="POST"
request-channel="lightOnRequest"
reply-channel="lightOnResponse"
path="rest/lighton/{sessionId}">
<int-http:header name="{sessionId}" expression="{sessionId}"/>
</int-http:inbound-gateway>
<!-- We add a header SESSION_ID_HEADER to choose the websocket destination client -->
<int:header-enricher
input-channel="lightOnRequest"
output-channel="lightOnClientRequest">
<int:header
name="#{T(...SimpMessageHeaderAccessor).SESSION_ID_HEADER}"
expression="headers.sessionId"/>
<int:header-channels-to-string/>
</int:header-enricher>
<!-- Websocket out to client -->
<int-websocket:outbound-channel-adapter
channel="lightOnClientRequest"
container="serverWebSocketContainer" />
<!-- Response reception from the Websocket client -->
<int-websocket:inbound-channel-adapter
channel="lightOnClientResponse"
container="serverWebSocketContainer" />
<!-- The websocket client provides again the reply channel in the headers.
The bridge connects the response to the reply channel -->
<int:bridge input-channel="lightOnClientResponse"/>
Unfortunately, your question isn't clear. If your WebSocket stuff is based on the Spring Integration WEbSocket adapters, you have ServerWebSocketContainer
which has getSessions()
to return Map<String, WebSocketSession>
of connected client sessions. Hence you can expose to end-users via REST service.
When the client select one session and send an HTTP request you can simply forward that message with the SimpMessageHeaderAccessor.SESSION_ID_HEADER
to the <int-websocket:outbound-channel-adapter>
.
And yes, you can receive an acknowledgement using <int-websocket:inbound-channel-adapter>
and forward it to the REST response automatically. But to achieve that you should convert TemporaryReplyChannel
from the <int-http:inbound-gateway>
to String
using <header-channels-to-string>
on <header-enricher>
.
You Client WebSocket application must ensure to return those request headers with the replyChannel
, when it send acknowledgement to the session. With Spring Integration on that side everything should be transparent.
Let me know if I have missed something.
UPDATE
Good. Thanks for more info! Your config looks good. Some remarks: 1. No need to have reply-channel="lightOnResponse"
: HTTP Inbound Gateway waits for the reply from the TemporaryReplyChannel
very well. 2. Please, add <header-channels-to-string>
to your <header-enricher>
before forwarding to the WebSocket. 3. The <int-websocket:inbound-channel-adapter>
can just sends its inbound message to the simple bridge
: <bridge input-channel="lightOnClientResponse">
. In this case without output-channel
it delegate message to the replyChannel
from headers. Hence your HTTP Inbound Gateway will receive appropriate reply.