0
votes

I know spring integration has TcpInboundGateway and ByteArrayStxEtxSerializer to handle data coming through TCP port.

ByteArrayStxEtxSerializer works great if the TCP server needs to read all the data sent from the client and then processes it. (request and response model) I am using single-use=false so that multiple requests can be processed in the same connection.

For example if the client sends 0x02AAPL0x03 then Server can send the AAPL price.

My TCP Server is working if the client sends 0x02AAPL0x030x02GOOG0x03. It sends the price of AAPL and GOOG price.

Sometimes clients send LRC (Longitudinal Redundancy Check) after ETX (0x03). If the client sends LRC, I would like to read and check the checksum.

My client request can be 0x02AAPL0x030x1E0x02GOOG0x03 . Note LRC is 0x1E in this case.

I know ByteArrayStxEtxSerializer deserializer can be customized to read the bytes sent by the client. is there any way to read ahead to look for LRC? If there is no LRC then read marker should be put back to 0x02 so that data can be processed by the deserializer in the normal way.

Please suggest on how to deal with optional LRC.

Here is my spring configuration:

<int-ip:tcp-connection-factory id="crLfServer"
        type="server"
        port="${availableServerSocket}"
        single-use="false"
        so-timeout="10000"
        using-nio="false" 
        serializer="connectionSerializeDeserialize"
        deserializer="connectionSerializeDeserialize"
        so-linger="2000"/>

    <bean id="connectionSerializeDeserialize" class="org.springframework.integration.ip.tcp.serializer.ByteArrayStxEtxSerializer"/>

    <int-ip:tcp-inbound-gateway id="gatewayCrLf"
        connection-factory="crLfServer"
        request-channel="serverBytes2StringChannel"
        error-channel="errorChannel"
        reply-timeout="10000"/> <!-- reply-timeout works on inbound-gateway -->

    <int:channel id="toSA" />

    <int:service-activator input-channel="toSA"
        ref="myService"
        method="prepare"/>

    <int:object-to-string-transformer id="serverBytes2String"
        input-channel="serverBytes2StringChannel"
        output-channel="toSA"/>

    <int:transformer id="errorHandler"
        input-channel="errorChannel"
        expression="payload.failedMessage.payload + ':' + payload.cause.message"/>

Thanks

1

1 Answers

0
votes

You would need to somehow wrap the input stream in a PushbackInputStream.

There are currently no hooks in the framework to do that; I'll think about how we could provide such extensibility in a future release.

In the meantime, one solution would be to write a stateful deserializer that maintains a ConcurrentHashMap, keyed by the InputStream argument, with the map value being a PushbackInputStream wrapper. You would need to implement ApplicationListener<TcpConnectionCloseEvent> so you could clear out the map entry when the socket is closed.