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
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 Transformers to convert the byte array payloads to Strings.
You can execute this sample simply via Maven:
$ mvn clean package exec:java
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:
http://www.springintegration.org/
=========================================================
Detect open server socket...using port 5680
Waiting for server to accept connections...running.
Please enter some text and press <enter>:
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.
$ mvn clean package exec:java -DavailableServerSocket=7777
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 <your_port>
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) orControl+]
(Mac) followed byq
orquit
.
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.
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.
<int:channel id="toSA" datatype="java.lang.String" />
You can run the example by executing JUnit test TcpClientServerDemoWithConversionServiceTest.
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:
<int-ip:tcp-connection-factory id="…"
…
serializer=""
deserializer=""/>
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
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 <stx>
control character and terminated by the <etx>
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.
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.