Spring integration connecting inbound HTTP gateway

2019-08-03 04:13发布

问题:

I want to create a REST service to turn on the light. The architecture that I want to have is the following:

  • Many embedded system each is connected to one light instance
  • Each embedded system has a websocket client, that connects to my server
  • My server holds a REST service that allows webclients to choose one light instance, and turn it on
  • The REST service would have a parameter to specify a reference for one light instance, connected to the system and send the message to websocket client, wait for an acknowledgement message from the client, and return the REST answer

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"/>

回答1:

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.