TCP Sample ========== This is the place to get started with the Samples for *Spring Integration's* support for the the [Transmission Control Protocol][] (TCP). The sample demonstrates a simple message flow represented by the diagram below: Gateway (SimpleGateway) -> Channel -> TcpOutboundGateway -> <==Socket==> -> TcpInboundGateway -> Channel -> ServiceActivator (EchoService) The *EchoService* class returns a response which the *Inbound Gateway* sends back over the socket to the *Outbound Gateway* and the result is returned to the client that invoked the original **SimpleGateway** method. Several variations of the sample are provided: * Client-Server Demo with explicit Transformers (Sample also provides [Telnet][] connectivity) * Client-Server Demo with ConversionService * Serializer Demo * Using the Stx-Etx [Serializer][]/[Deserializer][] * Using a Custom [Serializer][]/[Deserializer][] * Annotation based client-server Demo (JUnit test only) ### Client-Server Demo The Client-Server Demo illustrates the use of a *Gateway* as an entry point into the integration flow. The message generated by the *Gateway* is sent over *TCP* by the *Outbound Gateway* to the *Inbound Gateway*. In turn the *Inbound Gateway* sends the message to an echo service (Class *EchoService*) and the echoed response comes back over *TCP*. The demo uses explicit *Transformer*s to convert the *byte array* payloads to *Strings*. You can execute this sample simply via Gradle: $ gradlew :tcp-client-server:run Alternatively, you can also execute the **Main** method in class *org.springframework.integration.samples.tcpclientserver.Main*. In both cases you should see the following console output: ========================================================= Welcome to the Spring Integration TCP-Client-Server Sample! For more information please visit: https://www.springsource.org/spring-integration/ ========================================================= Detect open server socket...using port 5680 Waiting for server to accept connections...running. Please enter some text and press : Note: - Entering FAIL will create an exception - Entering q will quit the application --> Please also check out the other samples, that are provided as JUnit tests. --> You can also connect to the server on port '5680' using Telnet. hello echo:hello q Exiting application...bye. The respective open server socket it dynamically selected. Alternatively, you can also customize the port by providing an additional system property at startup e.g. $ gradlew :tcp-client-server:run -DavailableServerSocket=7777 #### Connect via Telnet The configured *Inbound Gateway* processes [CRLF][] (Carriage Return + Line Feed) delimited messages using the default [ByteArrayCrLfSerializer][]. This means that the *Inbound Gateway* works works fine as a very simple [Telnet][] server! Just start up the sample and connect to the used port: $ telnet localhost Each time you hit enter you should see your input echoed back, preceded by 'echo:' $ telnet localhost 11111 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hello world! echo:Hello world! Test echo:Test ^] telnet> quit Connection closed. > In order to quit the Telnet session, press `Ctrl+]` (Windows) or `Control+]` (Mac) followed by `q` or `quit`. The test case also demonstrates error handling on an *Inbound Gateway* using direct channels. If the payload is 'FAIL', the *EchoService* throws an exception. The *Gateway* is configured with an **error-channel** attribute. Messages sent to that channel are consumed by a *Transformer* that concatenates the inbound message payload with the message text from the thrown exception, returning **FAIL:Failure Demonstration** over the *TCP* socket. This can also be demonstrated with the Telnet client: telnet 127.0.0.1 5679 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. hello echo:hello FAIL FAIL:Failure Demonstration Hello World echo:Hello World ^] telnet> quit Connection closed. ### Client-Server Demo with ConversionService This demo is similar to the previous demo. However, instead of using explicit *Transformers*, this version shows how Spring's [Conversion Service][] can be used to convert the *byte array* payloads to Strings. This demo also uses a *Gateway* as an entry point into the integration flow. The message generated by the *Gateway* is sent over *TCP* by the *Outbound Gateway* to the *Inbound Gateway*. In return, the *Inbound Gateway* sends the message to the echo service and the echoed response comes back over *TCP* and is returned to the test case for verification. > Please note the channel's *dataType* attribute. This attribute which will trigger the *conversion service*. You can run the example by executing JUnit test **TcpClientServerDemoWithConversionServiceTest**. ### Serializer Demo A third option exists for converting a stream of bytes to a domain object or message payload. You can hook up a different [Serializer][]/[Deserializer][] at the connection factory: This will apply the conversions right when the stream comes in to the *Gateway* and right when it goes out. Two examples (JUnit Tests) are provided: * **TcpServerConnectionDeserializeTest** for using a simple (comes with Spring) Stx/Etx [Serializer][]/[Deserializer][]. * **TcpServerCustomSerializerTest** for creating and using your own serializers #### Stx-Etx Serializer Demo The Stx-Etx Serializer Demo shows an example of using the *Stx/Etx stream framing serializer* ([ByteArrayStxEtxSerializer][]) that is included with *Spring Integration*. This serializer reads data in an *InputStream* to a *byte array*. The data must be prefixed with the `` [control character][] and terminated by the `` [control character][]. We can be confident that the streams are properly handled because we explicitly send a stream with the Stx/Etx frame and the beginning and end of the actual content and the Server is configured to be able to handle the frame. In the asserts, we assert that the payload, once it reaches a component (in this case, the message listener we create and attach to the *incomingServerChannel*), does not have any of the Stx/Etx bytes. You can run the example by executing JUnit test **TcpServerConnectionDeserializeTest**. #### Using Custom Serializers Some use cases may dictate you needing to create your own stream handling serializers and deserializers. This sample shows a custom [Serializer][]/[Deserializer][] being used with the Java socket API on the front end (client) and the Spring Integration TCP inbound gateway with the custom serializer/deserializers. You can run the example by executing JUnit test **TcpServerCustomSerializerTest**. #### Annotation-based Configuration A simple client server test using entirely annotation-based configuration is shown in **TcpClientServerAnnotationDemoTest**. [ByteArrayCrLfSerializer]: https://docs.spring.io/spring-integration/api/org/springframework/integration/ip/tcp/serializer/ByteArrayCrLfSerializer.html [ByteArrayStxEtxSerializer]: https://docs.spring.io/spring-integration/api/org/springframework/integration/ip/tcp/serializer/ByteArrayStxEtxSerializer.html [control character]: https://en.wikipedia.org/wiki/Control_character [Conversion Service]: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/convert/ConversionService.html [CRLF]: https://en.wikipedia.org/wiki/Newline [Deserializer]: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/serializer/Deserializer.html [Serializer]: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/serializer/Serializer.html [Telnet]: https://en.wikipedia.org/wiki/Telnet [Transmission Control Protocol]: https://en.wikipedia.org/wiki/Transmission_Control_Protocol