Files
spring-integration/src/reference/docbook/ip.xml

2069 lines
95 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="ip"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>TCP and UDP Support</title>
<para>
Spring Integration provides Channel Adapters for receiving and sending messages over internet protocols. Both UDP
(User Datagram Protocol)
and TCP (Transmission Control Protocol) adapters are provided. Each adapter provides for one-way communication
over the underlying protocol.
In addition, simple inbound and outbound tcp gateways are provided. These are used when two-way communication is
needed.
</para>
<section id="ip-intro">
<title>Introduction</title>
<para>
Two flavors each of UDP inbound and outbound channel adapters are provided <classname>UnicastSendingMessageHandler</classname>
sends a datagram packet to a single destination. <classname>UnicastReceivingChannelAdapter</classname> receives
incoming datagram packets. <classname>MulticastSendingMessageHandler</classname> sends (broadcasts) datagram packets to
a multicast address. <classname>MulticastReceivingChannelAdapter</classname> receives incoming datagram packets
by joining to a multicast address.
</para>
<para>
TCP inbound and outbound channel adapters are provided <classname>TcpSendingMessageHandler</classname>
sends messages over TCP. <classname>TcpReceivingChannelAdapter</classname> receives messages over TCP.
</para>
<para>
An inbound TCP gateway is provided; this allows for simple request/response processing. While
the gateway can support any number of connections, each connection can only process serially. The thread
that reads from the socket waits for, and sends, the response before reading again. If the connection factory
is configured for single use connections, the connection is closed after the socket times out.
</para>
<para>
An outbound TCP gateway is provided; this allows for simple request/response processing.
If the associated connection factory is configured for single use connections, a new connection is
immediately created for each new request. Otherwise, if the connection is in use,
the calling thread blocks on the connection until either a response is received or a timeout
or I/O error occurs.
</para>
<para>
The TCP and UDP inbound channel adapters, and the TCP inbound gateway, support the "error-channel" attribute.
This provides the same basic functionality as described in <xref linkend="gateway-proxy"/>.
</para>
</section>
<section id="udp-adapters">
<title>UDP Adapters</title>
<para>
<programlisting language="xml"><![CDATA[<int-ip:udp-outbound-channel-adapter id="udpOut"
host="somehost"
port="11111"
multicast="false"
channel="exampleChannel"/>]]></programlisting>
A simple UDP outbound channel adapter.
<tip>
When setting multicast to true, provide the multicast address in the host
attribute.
</tip>
</para>
<para>
UDP is an efficient, but unreliable protocol. Two attributes are added to improve reliability. When check-length is
set to true, the adapter precedes the message data with a length field (4 bytes in network byte order). This enables
the receiving side to verify the length of the packet received. If a receiving system uses a buffer that is too
short the contain the packet, the packet can be truncated. The length header provides a mechanism to detect this.
</para>
<para>
<programlisting language="xml"><![CDATA[<int-ip:udp-outbound-channel-adapter id="udpOut"
host="somehost"
port="11111"
multicast="false"
check-length="true"
channel="exampleChannel"/>]]></programlisting>
An outbound channel adapter that adds length checking to the datagram packets.
<tip>
The recipient of the packet must also be configured to expect a length to precede the
actual data. For a Spring Integration UDP inbound channel adapter, set its
<classname>check-length</classname> attribute.
</tip>
</para>
<para>
The second reliability improvement allows an application-level acknowledgment protocol to be used. The receiver
must send an acknowledgment to the sender within a specified time.
</para>
<para>
<programlisting language="xml"><![CDATA[<int-ip:udp-outbound-channel-adapter id="udpOut"
host="somehost"
port="11111"
multicast="false"
check-length="true"
acknowledge="true"
ack-host="thishost"
ack-port="22222"
ack-timeout="10000"
channel="exampleChannel"/>]]></programlisting>
An outbound channel adapter that adds length checking to the datagram packets and waits for an acknowledgment.
<tip>
Setting acknowledge to true implies the recipient of the packet can interpret the header added to the packet
containing acknowledgment data (host and port). Most likely, the recipient will be a Spring Integration inbound
channel adapter.
</tip>
<tip>
When multicast is true, an additional attribute min-acks-for-success specifies
how many acknowledgments must be received within the ack-timeout.
</tip>
</para>
<para>
For even more reliable networking, TCP can be used.
</para>
<para>
<programlisting language="xml"><![CDATA[<int-ip:udp-inbound-channel-adapter id="udpReceiver"
channel="udpOutChannel"
port="11111"
receive-buffer-size="500"
multicast="false"
check-length="true"/>]]></programlisting>
A basic unicast inbound udp channel adapter.
</para>
<para>
<programlisting language="xml"><![CDATA[<int-ip:udp-inbound-channel-adapter id="udpReceiver"
channel="udpOutChannel"
port="11111"
receive-buffer-size="500"
multicast="true"
multicast-address="225.6.7.8"
check-length="true"/>]]></programlisting>
A basic multicast inbound udp channel adapter.
</para>
<para>
By default, reverse DNS lookups are done on inbound packets to convert IP addresses to
hostnames for use in message headers.
In environments where DNS is not configured, this can cause delays.
This default behavior can be overridden by setting the <literal>lookup-host</literal>
attribute to "false".
</para>
</section>
<section id="connection-factories">
<title>TCP Connection Factories</title>
<para>
For TCP, the configuration of the underlying connection is provided using a
Connection Factory. Two types of connection factory are provided; a
client connection factory and a server connection factory. Client connection
factories are used to establish outgoing connections; Server connection factories
listen for incoming connections.
</para>
<para>
A client connection factory is used
by an outbound channel adapter but a reference to a client connection factory
can also be provided to an inbound channel adapter and that adapter will receive
any incoming messages received on connections created by the outbound adapter.
</para>
<para>
A server connection factory is used by an inbound channel adapter or gateway (in fact
the connection factory will not function without one). A reference to a server
connection factory can also be provided to an outbound adapter; that adapter
can then be used to send replies to incoming messages to the same connection.
<tip>
<para>Reply messages will only be routed to the connection if the reply contains
the header ip_connection_id that was inserted into the original message by
the connection factory.</para></tip>
<tip>
<para>
This is the extent of message correlation performed when sharing connection
factories between inbound and outbound adapters. Such sharing allows for
asynchronous two-way communication over TCP. By default, only payload information is
transferred using TCP; therefore any message correlation must be performed
by downstream components such as aggregators or other endpoints. Support for
transferring selected headers was introduced in version 3.0.
For more information refer to <xref linkend="ip-correlation" />.
</para>
</tip>
</para>
<para>
A maximum of one adapter of each type may be given a reference to a connection
factory.
</para>
<para>
Connection factories using <classname>java.net.Socket</classname> and
<classname>java.nio.channel.SocketChannel</classname> are provided.
</para>
<para>
<programlisting language="xml"><![CDATA[<int-ip:tcp-connection-factory id="server"
type="server"
port="1234"/>]]></programlisting>
A simple server connection factory that uses <classname>java.net.Socket</classname>
connections.
</para>
<para>
<programlisting language="xml"><![CDATA[<int-ip:tcp-connection-factory id="server"
type="server"
port="1234"
using-nio="true"/>]]></programlisting>
A simple server connection factory that uses <classname>java.nio.channel.SocketChannel</classname>
connections.
</para>
<para>
<programlisting language="xml"><![CDATA[<int-ip:tcp-connection-factory id="client"
type="client"
host="localhost"
port="1234"
single-use="true"
so-timeout="10000"/>]]></programlisting>
A client connection factory that uses <classname>java.net.Socket</classname>
connections and creates a new connection for each message.
</para>
<para>
<programlisting language="xml"><![CDATA[<int-ip:tcp-connection-factory id="client"
type="client"
host="localhost"
port="1234"
single-use="true"
so-timeout="10000"
using-nio=true/>]]></programlisting>
A client connection factory that uses <classname>java.nio.channel.Socket</classname>
connections and creates a new connection for each message.
</para>
<para>
TCP is a streaming protocol; this means that some structure has to be provided to data
transported over TCP, so the receiver can demarcate the data into discrete messages.
Connection factories are configured to use (de)serializers to convert between the message
payload and the bits that are sent over TCP. This is accomplished by providing a
deserializer and serializer for inbound and outbound messages respectively.
A number of standard (de)serializers are provided.
</para>
<para>
The <classname>ByteArrayCrlfSerializer</classname>,
converts a byte array to a stream of bytes followed by carriage
return and linefeed characters (\r\n). This is the default (de)serializer and can be used with
telnet as a client, for example.
</para>
<para>
The <classname>ByteArraySingleTerminatorSerializer</classname>,
converts a byte array to a stream of bytes followed by a single termination
character (default 0x00).
</para>
<para>
The <classname>ByteArrayLfSerializer</classname>,
converts a byte array to a stream of bytes followed by a single linefeed
character (0x0a).
</para>
<para>
The <classname>ByteArrayStxEtxSerializer</classname>,
converts a byte array to a stream of bytes preceded by an STX (0x02) and
followed by an ETX (0x03).
</para>
<para>
The <classname>ByteArrayLengthHeaderSerializer</classname>,
converts a byte array to a stream of bytes preceded by a binary
length in network byte order (big endian). This a very efficient deserializer
because it does not have to parse every byte looking for a termination
character sequence. It can also be used for payloads containing binary data;
the above serializers only support text in the payload. The default size of
the length header is 4 bytes (Integer), allowing for messages up to 2**31-1
bytes. However, the length header can be a single byte (unsigned) for
messages up to 255 bytes, or an unsigned short (2 bytes) for messages up to
2**16 bytes. If you need any other format for the header, you can subclass
this class and provide implementations for the readHeader and writeHeader
methods. The absolute maximum data size supported is 2**31-1 bytes.
</para>
<para>
The <classname>ByteArrayRawSerializer</classname>,
converts a byte array to a stream of bytes and adds no additional message
demarcation data; with this (de)serializer, the end of a message is indicated
by the client closing the socket in an orderly fashion. When using this serializer,
message reception will hang until the client closes the socket, or a timeout occurs;
a timeout will NOT result in a message. When this serializer is being used, and the client
is a Spring Integration application, the client must use a connection factory that is
configured with single-use=true - this causes the adapter to close the socket after sending
the message; the serializer will not, itself, close the connection. This serializer
should only be used with connection factories used by channel adapters (not gateways), and the
connection factories should be used by either an inbound or outbound adapter, and not both.
</para>
<para>
Each of these is a subclass of
<classname>AbstractByteArraySerializer</classname> which implements both
<classname>org.springframework.core.serializer.Serializer</classname> and
<classname>org.springframework.core.serializer.Deserializer</classname>.
For backwards compatibility, connections using any subclass of
<classname>AbstractByteArraySerializer</classname> for serialization
will also accept a String which will be converted to a byte array first.
Each of these (de)serializers converts an input stream containing the
corresponding format to a byte array payload.
</para>
<para>
To avoid memory exhaustion due to a badly behaved client (one that does not adhere to
the protocol of the configured serializer), these serializers impose a maximum message
size. If the size is exceeded by an incoming message, an exception will be thrown.
The default maximum message size is 2048 bytes, and can be increased by setting the
<classname>maxMessageSize</classname> property. If you are using the default (de)serializer
and wish to increase the maximum message size, you must declare it as an explicit bean
with the property set and configure the connection factory to use that bean.
</para>
<para>
The <classname>MapJsonSerializer</classname> uses a Jackson
<classname>ObjectMapper</classname> to convert between a <interfacename>Map</interfacename>
and JSON. This can be used in conjunction with a <classname>MessageConvertingTcpMessageMapper
</classname> and a <classname>MapMessageConverter</classname>
to transfer selected headers and the payload in a JSON format.
<note>
The Jackson <classname>ObjectMapper</classname> cannot demarcate messages in the stream.
Therefore, the <classname>MapJsonSerializer</classname> needs to delegate to another
(de)serializer to handle message demarcation. By default, a
<classname>ByteArrayLfSerializer</classname> is used, resulting in messages with the
format <code>&lt;json&gt;&lt;LF&gt;</code> on the wire, but you can configure it to
use others instead.
</note>
</para>
<para>
The final standard serializer is
<classname>org.springframework.core.serializer.DefaultSerializer</classname> which can be
used to convert Serializable objects using java serialization.
<classname>org.springframework.core.serializer.DefaultDeserializer</classname> is provided for
inbound deserialization of streams containing Serializable objects.
</para>
<para>
To implement a custom (de)serializer pair, implement the
<classname>org.springframework.core.serializer.Deserializer</classname> and
<classname>org.springframework.core.serializer.Serializer</classname> interfaces.
</para>
<para>
If you do not wish to use
the default (de)serializer (<classname>ByteArrayCrLfSerializer</classname>), you must supply
<classname>serializer</classname> and
<classname>deserializer</classname> attributes on the connection factory (example below).
</para>
<para>
<programlisting language="xml"><![CDATA[<bean id="javaSerializer"
class="org.springframework.core.serializer.DefaultSerializer" />
<bean id="javaDeserializer"
class="org.springframework.core.serializer.DefaultDeserializer" />
<int-ip:tcp-connection-factory id="server"
type="server"
port="1234"
deserializer="javaDeserializer"
serializer="javaSerializer"/>]]></programlisting>
A server connection factory that uses <classname>java.net.Socket</classname>
connections and uses Java serialization on the wire.
</para>
<para>
For full details of the attributes available on connection factories, see the
reference at the end of this section.
</para>
<para>
By default, reverse DNS lookups are done on inbound packets to convert IP addresses to
hostnames for use in message headers.
In environments where DNS is not configured, this can cause connection delays.
This default behavior can be overridden by setting the <literal>lookup-host</literal>
attribute to "false".
</para>
<note>
<para>
It is possible to modify the creation of and/or attributes of sockets - see
<xref linkend="ssl-tls"/>. As is noted there, such modifications are possible whether
or not SSL is being used.
</para>
</note>
<section id="caching-cf">
<title>TCP Caching Client Connection Factory</title>
<para>
As noted above, TCP sockets cam be 'single-use' (one request/response)
or shared. Shared sockets do not perform well with outbound gateways,
in high-volume environments,
because the socket can only process one request/response at a time.
</para>
<para>
To improve performance, users could use collaborating channel adapters
instead of gateways, but that requires application-level message
correlation. See <xref linkend="ip-correlation" />for more information.
</para>
<para>
Spring Integration 2.2 introduced a caching client connection factory,
where a pool of shared sockets is used, allowing a gateway to
process multiple concurrent requests with a pool of shared
connections.
</para>
</section>
<section id="failover-cf">
<title>TCP Failover Client Connection Factory</title>
<para>
It is now possible to configure a TCP connection factory that
supports failover to one or more other servers. When sending
a message, the factory will iterate over all its configured
factories until either the message can be sent, or no connection
can be found. Initially, the first factory in the configured
list is used; if a connection subsequently fails the next
factory will become the current factory.
</para>
<para>
<programlisting language="xml"><![CDATA[<bean id="failCF" class="o.s.i.ip.tcp.connection.FailoverClientConnectionFactory">
<constructor-arg>
<list>
<ref bean="clientFactory1"/>
<ref bean="clientFactory2"/>
</list>
</constructor-arg>
</bean>]]></programlisting>
</para>
<para>
<note>When using the failover connection factory, the singleUse property must be consistent between
the factory itself and the list of factories it is configured to use.
</note>
</para>
</section>
</section>
<section id="ip-interceptors">
<title>TCP Connection Interceptors</title>
<para>
Connection factories can be configured with a reference to a
<classname>TcpConnectionInterceptorFactoryChain</classname>. Interceptors can be used
to add behavior to connections, such as negotiation, security, and other setup.
No interceptors are currently provided by the framework but, for an example,
see the <classname>InterceptedSharedConnectionTests</classname> in the source
repository.
</para>
<para>
The <classname>HelloWorldInterceptor</classname> used in the test case works as follows:
</para>
<para>
When configured with a client connection factory,
when the first message is sent over a connection that is intercepted, the interceptor
sends 'Hello' over the connection, and expects to receive 'world!'. When that occurs,
the negotiation is complete and the original message is sent; further messages
that use the same connection are sent without any additional negotiation.
</para>
<para>
When configured with a server connection factory, the interceptor requires the first
message to be 'Hello' and, if it is, returns 'world!'. Otherwise it throws an exception causing
the connection to be closed.
</para>
<para>
All <classname>TcpConnection</classname> methods are intercepted.
Interceptor instances are created for each connection by an interceptor factory.
If an interceptor is stateful, the factory should create a new instance for each connection;
if there is no state, the same interceptor can wrap each connection. Interceptor
factories are added to the configuration of an interceptor factory chain, which is provided
to a connection factory using the <classname>interceptor-factory</classname> attribute.
Interceptors must extend <classname>TcpConnectionInterceptorSupport</classname>;
factories
must implement the <classname>TcpConnectionInterceptorFactory</classname> interface.
<classname>TcpConnectionInterceptorSupport</classname> is provided
with passthrough methods; by extending this class, you only need to implement those
methods you wish to intercept.
</para>
<para>
<programlisting language="xml"><![CDATA[<bean id="helloWorldInterceptorFactory"
class="o.s.i.ip.tcp.connection.TcpConnectionInterceptorFactoryChain">
<property name="interceptors">
<array>
<bean class="o.s.i.ip.tcp.connection.HelloWorldInterceptorFactory"/>
</array>
</property>
</bean>
<int-ip:tcp-connection-factory id="server"
type="server"
port="12345"
using-nio="true"
single-use="true"
interceptor-factory-chain="helloWorldInterceptorFactory"/>
<int-ip:tcp-connection-factory id="client"
type="client"
host="localhost"
port="12345"
single-use="true"
so-timeout="100000"
using-nio="true"
interceptor-factory-chain="helloWorldInterceptorFactory"/>]]></programlisting>
Configuring a connection interceptor factory chain.
</para>
</section>
<section id="tcp-events">
<title>TCP Connection Events</title>
<para>
Beginning with version 3.0, changes to <interfacename>TcpConnection</interfacename>s
are reported by <classname>TcpConnectionEvent</classname>s. <classname>TcpConnectionEvent</classname>
is a subclass of <classname>ApplicationEvent</classname> and thus can
be received by any <interfacename>ApplicationListener</interfacename> defined in
the <interfacename>ApplicationContext</interfacename>.
</para>
<para>
For convenience, a <code>&lt;int-ip:tcp-connection-event-inbound-channel-adapter/&gt;</code>
is provided. This adapter will receive all <classname>TcpConnectionEvent</classname>s (by
default), and send them to its <code>channel</code>. The adapter accepts an <code>event-type</code>
attribute, which is a list of class names for events that should be sent. This can be used
if an application subclasses <classname>TcpConnectionEvent</classname> for some reason, and wishes
to only receive those events. Omitting this attribute will mean that all
<classname>TcpConnectionEvent</classname>s will be sent. You can also use this to limit which
<classname>TcpConnectionEvent</classname>s you are interested in (
<classname>TcpConnectionOpenEvent</classname>, <classname>TcpConnectionCloseEvent</classname>,
or <classname>TcpConnectionExceptionEvent</classname>).
</para>
<para>
<classname>TcpConnectionEvents</classname> have the following properties:
<itemizedlist>
<listitem><code>connectionId</code> - the connection identifier which can be used in a message header
to send data to the connection</listitem>
<listitem><code>connectionFactoryName</code> - the bean name of the connection factory the connection belongs to</listitem>
<listitem><code>throwable</code> - the <classname>Throwable</classname> (for <classname>TcpConnectionExceptionEvent</classname> events only)</listitem>
<listitem><code>source</code> - the <interfacename>TcpConnection</interfacename>; this can be
used, for example, to determine the remote IP Address with <code>getHostAddress()</code> (cast required)
</listitem>
</itemizedlist>
</para>
<para>
In addition, since <emphasis>version 4.0</emphasis> the standard deserializers discussed in
<xref linkend="connection-factories"/> now emit <classname>TcpDeserializationExceptionEvent</classname>s
when problems are encountered decoding the data stream. These events contain the exception, the
buffer that was in the process of being built, and an offset into the buffer (if available) at the
point the exception occurred. Applications can use a normal <interfacename>ApplicationListener</interfacename>,
or see <xref linkend="applicationevent-inbound"/>, to capture these events, allowing analysis of the problem.
</para>
</section>
<section id="tcp-adapters">
<title>TCP Adapters</title>
<para>
TCP inbound and outbound channel adapters that utilize the above connection
factories are provided. These adapters have attributes
<classname>connection-factory</classname> and <classname>channel</classname>.
The channel attribute specifies the channel on which messages arrive at an
outbound adapter and on which messages are placed by an inbound adapter.
The connection-factory attribute indicates which connection factory is to be used to
manage connections for the adapter. While both inbound and outbound adapters
can share a connection factory, server connection factories are always 'owned'
by an inbound adapter; client connection factories are always 'owned' by an
outbound adapter. One, and only one, adapter of each type may get a reference
to a connection factory.
</para>
<para>
<programlisting language="xml"><![CDATA[<bean id="javaSerializer"
class="org.springframework.core.serializer.DefaultSerializer"/>
<bean id="javaDeserializer"
class="org.springframework.core.serializer.DefaultDeserializer"/>
<int-ip:tcp-connection-factory id="server"
type="server"
port="1234"
deserializer="javaDeserializer"
serializer="javaSerializer"
using-nio="true"
single-use="true"/>
<int-ip:tcp-connection-factory id="client"
type="client"
host="localhost"
port="#{server.port}"
single-use="true"
so-timeout="10000"
deserializer="javaDeserializer"
serializer="javaSerializer"/>
<int:channel id="input" />
<int:channel id="replies">
<int:queue/>
</int:channel>
<int-ip:tcp-outbound-channel-adapter id="outboundClient"
channel="input"
connection-factory="client"/>
<int-ip:tcp-inbound-channel-adapter id="inboundClient"
channel="replies"
connection-factory="client"/>
<int-ip:tcp-inbound-channel-adapter id="inboundServer"
channel="loop"
connection-factory="server"/>
<int-ip:tcp-outbound-channel-adapter id="outboundServer"
channel="loop"
connection-factory="server"/>
<int:channel id="loop"/>]]></programlisting>
In this configuration, messages arriving in channel 'input'
are serialized over connections created by 'client' received
at the server and placed on channel 'loop'. Since 'loop' is
the input channel for 'outboundServer' the message is simply
looped back over the same connection and received by
'inboundClient' and deposited in channel 'replies'. Java
serialization is used on the wire.
</para>
<para>
Normally, inbound adapters use a type="server" connection
factory, which listens for incoming connection requests.
In some cases, it is desirable to establish the connection
in reverse, whereby the inbound adapter connects to an
external server and then waits for inbound messages on that
connection.
</para>
<para>
This topology is supported by using <emphasis>client-mode="true"</emphasis>
on the inbound adapter. In this case, the connection factory must
be of type 'client' and must have <emphasis>single-use</emphasis>
set to false.
</para>
<para>
Two additional attributes are used to support this mechanism:
<emphasis>retry-interval</emphasis> specifies (in milliseconds)
how often the framework will attempt to reconnect after a
connection failure. <emphasis>scheduler</emphasis> is used to
supply a <classname>TaskScheduler</classname> used to
schedule the connection attempts, and to test that the connection is
still active.
</para>
<para>
For an outbound adapter, the connection is normally established
when the first message is sent. <emphasis>client-mode="true"</emphasis>
on an outbound adapter will cause the connection to be established
when the adapter is started. Adapters are automatically started
by default. Again, the connection factory must be of type client
and have <emphasis>single-use</emphasis> set to false and
<emphasis>retry-interval</emphasis> and
<emphasis>scheduler</emphasis> are also supported. If a connection
fails, it will be re-established either by the scheduler or
when the next message is sent.
</para>
<para>
For both inbound and outbound,
if the adapter is started, you may force the adapter to establish
a connection by sending a &lt;control-bus /&gt; command:
<classname>@adapter_id.retryConnection()</classname> and examine the
current state with <classname>@adapter_id.isConnected()</classname>.
</para>
</section>
<section id="tcp-gateways">
<title>TCP Gateways</title>
<para>
The inbound TCP gateway <classname>TcpInboundGateway</classname>
and outbound TCP gateway <classname>TcpOutboundGateway</classname>
use a server and client connection factory respectively. Each connection
can process a single request/response at a time.
</para>
<para>
The inbound gateway, after constructing a message with the incoming payload and sending
it to the requestChannel, waits for a response and sends the payload
from the response message by writing it to the connection.
</para>
<para>
<note>
<para>
For the inbound gateway, care must be taken to retain, or populate, the
<emphasis>ip_connectionId</emphasis> header because it is used to
correlate the message to a connection. Messages that originate at the
gateway will automatically have the header set. If the reply is
constructed as a new message, you will need to set the header. The
header value can be captured from the incoming message.
</para>
</note>
</para>
<para>
As with inbound adapters, inbound gateways normally use a
type="server" connection
factory, which listens for incoming connection requests.
In some cases, it is desirable to establish the connection
in reverse, whereby the inbound gateway connects to an
external server and then waits for, and replies to, inbound
messages on that connection.
</para>
<para>
This topology is supported by using <emphasis>client-mode="true"</emphasis>
on the inbound gateway. In this case, the connection factory must
be of type 'client' and must have <emphasis>single-use</emphasis>
set to false.
</para>
<para>
Two additional attributes are used to support this mechanism:
<emphasis>retry-interval</emphasis> specifies (in milliseconds)
how often the framework will attempt to reconnect after a
connection failure. <emphasis>scheduler</emphasis> is used to
supply a <classname>TaskScheduler</classname> used to
schedule the connection attempts, and to test that the connection is
still active.
</para>
<para>
If the gateway is started, you may force the gateway to establish
a connection by sending a &lt;control-bus /&gt; command:
<classname>@adapter_id.retryConnection()</classname> and examine the
current state with <classname>@adapter_id.isConnected()</classname>.
</para>
<para>
The outbound gateway, after sending a message over the connection, waits for a response and
constructs a response message and puts in on the reply channel.
Communications over the connections are single-threaded. Users should be aware that only one
message can be handled at a time and, if another thread attempts to send
a message before the current response has been received, it will block until
any previous requests are complete (or time out).
If, however, the client connection factory is configured for single-use connections
each new request gets its own connection and is processed immediately.
</para>
<para>
<programlisting language="xml"><![CDATA[
<int-ip:tcp-inbound-gateway id="inGateway"
request-channel="tcpChannel"
reply-channel="replyChannel"
connection-factory="cfServer"
reply-timeout="10000"/>]]></programlisting>
A simple inbound TCP gateway; if a connection factory configured with the default
(de)serializer is used, messages will be \r\n delimited data and the gateway can be
used by a simple client such as telnet.
</para>
<para>
<programlisting language="xml"><![CDATA[
<int-ip:tcp-outbound-gateway id="outGateway"
request-channel="tcpChannel"
reply-channel="replyChannel"
connection-factory="cfClient"
request-timeout="10000"
remote-timeout="10000"/>]]></programlisting>
A simple outbound TCP gateway.
</para>
</section>
<section id="ip-correlation">
<title>TCP Message Correlation</title>
<section>
<title>Overview</title>
<para>
One goal of the IP Endpoints is to provide communication with systems other
than another Spring Integration application. For this reason, only
message payloads are sent and received, by default. Since 3.0, headers can
be transferred, using JSON, Java serialization, or with custom
<interfacename>Serializer</interfacename>s and
<interfacename>Deserializer</interfacename>s; see <xref linkend="ip-headers"/>
for more information.
No message correlation is provided by the framework,
except when using the gateways, or collaborating channel adapters on the
server side. In the paragraphs below we discuss the various
correlation techniques available to applications. In most cases, this
requires specific application-level correlation of messages, even when
message payloads contain some natural correlation data (such as an order
number).
</para>
</section>
<section>
<title>Gateways</title>
<para>
The gateways will automatically correlate messages. However, an outbound
gateway should only be used for relatively low-volume use.
When the connection factory is configured for a single shared connection
to be used for all message pairs ('single-use="false"'),
only one message can be processed at a time.
A new message will have to wait until the reply to the previous message has
been received.
When a connection factory is configured for each new message to use a new connection
('single-use="true"'), the above restriction does not apply.
While this may give higher throughput
than a shared connection environment, it comes with the overhead of opening
and closing a new connection for each message pair.
</para>
<para>
Therefore, for high-volume messages, consider using a collaborating pair of
channel adapters. However, you will need to provide collaboration logic.
</para>
<para>
Another solution, introduced in Spring Integration 2.2, is to use a
<classname>CachingClientConnectionFactory</classname>, which allows
the use of a pool of shared connections.
</para>
</section>
<section>
<title>Collaborating Outbound and Inbound Channel Adapters</title>
<para>
To achieve high-volume throughput (avoiding the pitfalls of using gateways
as mentioned above) you may consider configuring a pair of collaborating
outbound and inbound channel adapters.
Collaborating adapters can also be used (server-side or client-side) for
totally asynchronous communication (rather than with request/reply semantics).
On the server side, message
correlation is automatically handled by the adapters because the inbound
adapter adds a header allowing the outbound adapter to determine which
connection to use to send the reply message.
</para>
<para>
<note>
<para>
On the server side, care must be taken to populate the
<emphasis>ip_connectionId</emphasis> header because it is used to
correlate the message to a connection. Messages that originate at the
inbound adapter will automatically have the header set. If you wish to
construct other messages to send, you will need to set the header. The
header value can be captured from an incoming message.
</para>
</note>
</para>
<para>
On the client side,
the application will have to provide its own correlation logic, if needed.
This can be done in a number of ways.
</para>
<para>
If the message payload has some natural correlation data, such as a
transaction id or an order number, AND there is no need to retain any
information (such as a reply channel header) from the original outbound message,
the correlation is simple and would done at the application level in any case.
</para>
<para>
If the message payload has some natural correlation data, such as a
transaction id or an order number, but there is a need to retain some
information (such as a reply channel header) from the original outbound message,
you may need to retain a copy of the original outbound message (perhaps
by using a publish-subscribe channel) and use an aggregator to recombine
the necessary data.
</para>
<para>
For either of the previous two paragraphs, if the payload has no natural
correlation data, you may need to provide a transformer upstream of the
outbound channel adapter to enhance the payload with such data. Such a
transformer may transform the original payload to a new object containing
both the original payload and some subset of the message headers. Of course,
live objects (such as reply channels) from the headers can not be
included in the transformed payload.
</para>
<para>
If such a strategy is chosen you will need to ensure the connection factory
has an appropriate serializer/deserializer pair to handle such a payload,
such as the <classname>DefaultSerializer/Deserializer</classname> which use java
serialization, or a custom serializer and deserializer.
The <classname>ByteArray*Serializer</classname> options
mentioned in <xref linkend="connection-factories" />,
including the default <classname>ByteArrayCrLfSerializer</classname>,
do not support such payloads,
unless the transformed payload is a <classname>String</classname> or
<classname>byte[]</classname>,
</para>
<para>
<note>
<para>
Before the 2.2 release,
when a <emphasis>client</emphasis> connection factory was used by
collaborating channel
adapters, the <emphasis>so-timeout</emphasis> attribute defaulted
to the default reply timeout (10 seconds). This meant that if
no data were received by the inbound adapter for this period of
time, the socket was closed.
</para>
<para>
This default behavior was not appropriate in a truly asynchronous
environment, so it now defaults to an infinite timeout.
You can reinstate the previous default behavior by setting the
<emphasis>so-timeout</emphasis> attribute on the client connection
factory to 10000 milliseconds.
</para>
</note>
</para>
</section>
<section id="ip-headers">
<title>Transferring Headers</title>
<para>
TCP is a streaming protocol; <interfacename>Serializers</interfacename> and
<interfacename>Deserializers</interfacename> are used to demarcate messages
within the stream. Prior to 3.0, only message payloads (String or byte[])
could be transferred over
TCP. Beginning with 3.0, you can now transfer selected headers as well as the
payload. It is important to understand, though, that "live" objects, such
as the <code>replyChannel</code> header cannot be serialized.
</para>
<para>
Sending header information over TCP requires some additional configuration.
</para>
<para>
The first step is to provide the <classname>ConnectionFactory</classname>
with a <classname>MessageConvertingTcpMessageMapper</classname> using the
<code>mapper</code> attribute. This mapper delegates to any
<interfacename>MessageConverter</interfacename> implementation to convert
the message to/from some object that can be (de)serialized by the
configured <code>serializer</code> and <code>deserializer</code>.
</para>
<para>
A <classname>MapMessageConverter</classname> is provided, which allows the
specification of a list of headers that will be added to a
<interfacename>Map</interfacename> object, along with the payload.
The generated Map has two entries: <code>payload</code> and
<code>headers</code>. The <code>headers</code> entry is itself a
<interfacename>Map</interfacename> containing the selected headers.
</para>
<para>
The second step is to provide a (de)serializer that can convert between
a <interfacename>Map</interfacename> and some wire format. This can
be a custom <interfacename>(de)Serializer</interfacename>, which would
typically be needed if the peer system is not a Spring Integration
application.
</para>
<para>
A <classname>MapJsonSerializer</classname> is provided that will
convert a Map to/from JSON. This uses a Spring Integration
<classname>JsonObjectMapper</classname> to perform this function. You
can provide a custom <classname>JsonObjectMapper</classname> if needed.
By default, the serializer inserts a linefeed
<code>0x0a</code> character between objects.
See the JavaDocs for more information.
</para>
<note>
At the time of writing, the <classname>JsonObjectMapper</classname>
uses whichever version of <code>Jackson</code> is on the classpath.
</note>
<para>
You can also use standard Java serialization of the Map, using
the <classname>DefaultSerializer</classname> and
<classname>DefaultDeserializer</classname>.
</para>
<para>
The following example shows the configuration of a connection
factory that transfers the <code>correlationId</code>,
<code>sequenceNumber</code>, and <code>sequenceSize</code>
headers using JSON.
</para>
<programlisting language="xml"><![CDATA[<int-ip:tcp-connection-factory id="client"
type="client"
host="localhost"
port="12345"
mapper="mapper"
serializer="jsonSerializer"
deserializer="jsonSerializer"/>
<bean id="mapper"
class="o.sf.integration.ip.tcp.connection.MessageConvertingTcpMessageMapper">
<constructor-arg name="messageConverter">
<bean class="o.sf.integration.support.converter.MapMessageConverter">
<property name="headerNames">
<list>
<value>correlationId</value>
<value>sequenceNumber</value>
<value>sequenceSize</value>
</list>
</property>
</bean>
</constructor-arg>
</bean>
<bean id="jsonSerializer" class="o.sf.integration.ip.tcp.serializer.MapJsonSerializer" />
]]></programlisting>
<para>
A message sent with the above configuration, with payload 'foo' would appear on the wire like so:
</para>
<programlisting language="xml"><![CDATA[
{"headers":{"correlationId":"bar","sequenceSize":5,"sequenceNumber":1},"payload":"foo"}]]></programlisting>
</section>
</section>
<section id="note_nio">
<title>A Note About NIO</title>
<para>
Using NIO (see <classname>using-nio</classname> in
<xref linkend="ip-endpoint-reference" />)
avoids dedicating a thread to read from each socket. For a small number
of sockets, you will likely find that <emphasis>not</emphasis> using NIO,
together with an async handoff (e.g. to a <classname>QueueChannel</classname>),
will perform as well as, or better than, using NIO.
</para>
<para>
Consider using NIO when handling a large number of connections. However, the use
of NIO has some other ramifications. A pool of threads (in the task executor) is
shared across all the sockets; each incoming message is assembled and sent to the
configured channel as a separate unit of work on a thread selected from that pool.
Two sequential
messages arriving on the <emphasis>same</emphasis> socket <emphasis>might</emphasis>
be processed by different threads. This means that the order in which the messages are
sent to the channel is indeterminate; the strict ordering of the messages arriving on the
socket is not maintained.
</para>
<para>
For some applications, this is not an issue; for others it is. If strict ordering
is required, consider setting <classname>using-nio</classname> to false
and using async handoff.
</para>
<para>
Alternatively, you may choose to insert a resequencer downstream of the inbound endpoint to
return the messages to their proper sequence. Set <emphasis>apply-sequence</emphasis>
to true on the connection factory, and messages arriving on a TCP connection will
have <emphasis>sequenceNumber</emphasis> and <emphasis>correlationId</emphasis> headers
set. The resequencer uses these headers to return the messages to their proper
sequence.
</para>
<para><emphasis>Pool Size</emphasis></para>
<para>
The pool size attribute is no longer used; previously, it specified the size
of the default thread pool when a task-executor was not specified. It was also
used to set the connection backlog on server sockets. The first function is
no longer needed (see below); the second function is replaced by the
<emphasis>backlog</emphasis> attribute.
</para>
<para>
Previously, when using a fixed thread pool task executor (which was the default), with NIO, it
was possible to get a deadlock and processing would stop. The problem occurred when
a buffer was full, a thread reading from the socket was trying to add more data
to the buffer, and there were no threads available to make space in the buffer.
This only occurred with a very small pool size, but it could be possible under
extreme conditions. Since 2.2, two changes have eliminated this problem. First,
the default task executor is a cached thread pool executor. Second, deadlock
detection logic has been added such that if thread starvation occurs, instead of
deadlocking, an exception is thrown, thus releasing the deadlocked resources.
</para>
<important>
Now that the default task executor is unbounded, it is possible that an out of
memory condition might occur with high rates of incoming messages, if message
processing takes extended time. If your application exhibits this type of
behavior, you are advised to use a pooled task executor with an appropriate
pool size, but see the next section.
</important>
<section>
<title>Thread Pool Task Executor with CALLER_RUNS Policy</title>
<para>
There are some important considerations when using a fixed thread pool with
the <classname>CallerRunsPolicy</classname> (<code>CALLER_RUNS</code> when
using the <code>&lt;task/&gt;</code> namespace) and the queue capacity is small.
</para>
<para>
The following does not apply if you are not using a fixed thread pool.
</para>
<para>
With NIO connections there are 3 distinct task types; the IO Selector processing
is performed on one dedicated thread - detecting events, accepting new connections,
and dispatching the IO read operations to other threads, using the task
executor. When an IO reader thread (to which the read operation is dispatched)
reads data, it hands off to another thread
to assemble the incoming message; large messages may take several reads to complete.
These "assembler" threads can block waiting for data. When a new read event
occurs, the reader determines if this socket already has an assembler and
runs a new one if not. When the assembly process is complete, the assembler
thread is returned to the pool.
</para>
<para>
This can cause a deadlock when the pool is exhausted and the CALLER_RUNS
rejection policy is in use, and the task queue is full.
When the pool is empty and there is no room in the queue, the IO selector thread
receives an <code>OP_READ</code> event and dispatches the read using the
executor; the queue is full, so the selector thread itself starts the
read process; now, it detects that there is not an assembler for this
socket and, before it does the read, fires off an assembler; again, the
queue is full, and the selector thread becomes the assembler. The assembler
is now blocked awaiting the data to be read, which will never happen.
The connection factory is now deadlocked because the selector thread
can't handle new events.
</para>
<para>
We must avoid the selector (or reader) threads performing the
assembly task to avoid this deadlock. It is desirable to use seperate
pools for the IO and assembly operations.
</para>
<para>
The framework provides a
<classname>CompositeExecutor</classname>, which allows the configuration
of two distinct executors; one for performing IO operations, and
one for message assembly. In this environment, an IO thread can never
become an assembler thread, and the deadlock cannot occur.
</para>
<para>
In addition, the task executors should be configured to use a
<classname>AbortPolicy</classname> (ABORT when using <code>&lt;task&gt;</code>).
When an IO cannot be completed, it is deferred for a short time and
retried continually until it can be completed and an assembler
allocated. By default, the delay is 100ms but it can be changed using the
<code>readDelay</code> property on the connection factory (<code>read-delay</code>
when configuring with the XML namespace).
</para>
<para>
Example configuration of the composite executor is shown below.
</para>
<programlisting language="java"><![CDATA[@Bean
private CompositeExecutor compositeExecutor() {
ThreadPoolTaskExecutor ioExec = new ThreadPoolTaskExecutor();
ioExec.setCorePoolSize(4);
ioExec.setMaxPoolSize(10);
ioExec.setQueueCapacity(0);
ioExec.setThreadNamePrefix("io-");
ioExec.setRejectedExecutionHandler(new AbortPolicy());
ioExec.initialize();
ThreadPoolTaskExecutor assemblerExec = new ThreadPoolTaskExecutor();
assemblerExec.setCorePoolSize(4);
assemblerExec.setMaxPoolSize(10);
assemblerExec.setQueueCapacity(0);
assemblerExec.setThreadNamePrefix("assembler-");
assemblerExec.setRejectedExecutionHandler(new AbortPolicy());
assemblerExec.initialize();
return new CompositeExecutor(ioExec, assemblerExec);
}]]></programlisting>
<programlisting language="xml"><![CDATA[<bean id="myTaskExecutor" class="org.springframework.integration.util.CompositeExecutor">
<constructor-arg ref="io"/>
<constructor-arg ref="assembler"/>
</bean>
<task:executor id="io" pool-size="4-10" queue-capacity="0" rejection-policy="ABORT" />
<task:executor id="assembler" pool-size="4-10" queue-capacity="0" rejection-policy="ABORT" />]]></programlisting>
<programlisting language="xml"><![CDATA[<bean id="myTaskExecutor" class="org.springframework.integration.util.CompositeExecutor">
<constructor-arg>
<bean class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="threadNamePrefix" value="io-" />
<property name="corePoolSize" value="4" />
<property name="maxPoolSize" value="8" />
<property name="queueCapacity" value="0" />
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor.AbortPolicy" />
</property>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="threadNamePrefix" value="assembler-" />
<property name="corePoolSize" value="4" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="0" />
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor.AbortPolicy" />
</property>
</bean>
</constructor-arg>
</bean>]]></programlisting>
</section>
</section>
<section id="ssl-tls">
<title>SSL/TLS Support</title>
<section>
<title>Overview</title>
<para>
Secure Sockets Layer/Transport Layer Security is supported. When using NIO, the JDK 5+
<classname>SSLEngine</classname> feature is used to handle handshaking after the
connection is established. When not using NIO, standard
<classname>SSLSocketFactory</classname> and <classname>SSLServerSocketFactory</classname> objects are
used to create connections. A number of strategy interfaces are provided to allow
significant customization; default implementations of these interfaces provide for
the simplest way to get started with secure communications.
</para>
</section>
<section>
<title>Getting Started</title>
<para>
Regardless of whether NIO is being used, you need to configure the
<classname>ssl-context-support</classname> attribute on the connection factory.
This attribute references a &lt;bean/&gt; definition that describes the location
and passwords for the required key stores.
</para>
<para>
SSL/TLS peers require two keystores each; a keystore containing private/public key
pairs identifying the peer; a truststore, containing the public keys for peers that
are trusted. See the documentation for the <classname>keytool</classname> utility
provided with the JDK. The essential steps are
</para>
<para>
<orderedlist>
<listitem><para>Create a new key pair and store in a keystore.</para></listitem>
<listitem><para>Export the public key.</para></listitem>
<listitem><para>Import the public key into the peer's truststore.</para></listitem>
</orderedlist>
</para>
<para>
Repeat for the other peer.
</para>
<note>
<para>
It is common in test cases to use the same key stores on both peers, but this should
be avoided for production.
</para>
</note>
<para>
After establishing the key stores, the next step is to indicate their locations to the
<classname>TcpSSLContextSupport</classname> bean, and provide a reference to that bean
to the connection factory.
</para>
<para><programlisting language="xml"><![CDATA[<bean id="sslContextSupport"
class="o.sf.integration.ip.tcp.connection.support.DefaultTcpSSLContextSupport">
<constructor-arg value="client.ks"/>
<constructor-arg value="client.truststore.ks"/>
<constructor-arg value="secret"/>
<constructor-arg value="secret"/>
</bean>
<ip:tcp-connection-factory id="clientFactory"
type="client"
host="localhost"
port="1234"
ssl-context-support="sslContextSupport"]]></programlisting>
</para>
<para>
The <classname>DefaulTcpSSLContextSupport</classname> class also has an optional
'protocol' property, which can be 'SSL' or 'TLS' (default).
</para>
<para>
The keystore file names (first two constructor arguments) use the Spring <classname>Resource</classname>
abstraction; by default the files will be located on the classpath, but this can be overridden by using
the <classname>file:</classname> prefix, to find the files on the filesystem instead.
</para>
</section>
<section>
<title>Advanced Techniques</title>
<para>
In many cases, the configuration described above is all that is needed to enable secure
communication over TCP/IP. However, a number of strategy interfaces are provided to
allow customization and modification of socket factories and sockets.
</para>
<para>
<itemizedlist>
<listitem><para><classname>TcpSSLContextSupport</classname></para></listitem>
<listitem><para><classname>TcpSocketFactorySupport</classname></para></listitem>
<listitem><para><classname>TcpSocketSupport</classname></para></listitem>
</itemizedlist>
</para>
<para><programlisting language="java"><![CDATA[public interface TcpSSLContextSupport {
SSLContext getSSLContext() throws Exception;
}]]></programlisting>
</para>
<para>
Implementations of this interface are responsible for creating an SSLContext.
The sole implementation provided by the framework is the
<classname>DefaultTcpSSLContextSupport</classname> described above. If you require
different behavior, implement this interface and provide the connection factory with
a reference to a bean of your class' implementation.
</para>
<para><programlisting language="java"><![CDATA[public interface TcpSocketFactorySupport {
ServerSocketFactory getServerSocketFactory();
SocketFactory getSocketFactory();
}
]]></programlisting>
</para>
<para>
Implementations of this interface are responsible for obtaining references to
<classname>ServerSocketFactory</classname> and <classname>SocketFactory</classname>.
Two implementations are provided; the first is <classname>DefaultTcpNetSocketFactorySupport</classname>
for non-SSL sockets (when no 'ssl-context-support' attribute is defined); this simply
uses the JDK's default factories. The second implementation is
<classname>DefaultTcpNetSSLSocketFactorySupport</classname>; this is used, by default,
when an 'ssl-context-support' attribute is defined; it uses the <classname>SSLContext</classname>
created by that bean to create the socket factories.
</para>
<note>
<para>
This interface only applies if <classname>using-nio</classname> is "false"; socket factories
are not used by NIO.
</para>
</note>
<para><programlisting language="java"><![CDATA[public interface TcpSocketSupport {
void postProcessServerSocket(ServerSocket serverSocket);
void postProcessSocket(Socket socket);
]]></programlisting>
</para>
<para>
Implementations of this interface can modify sockets after they are created, and after
all configured attributes have been applied, but before the sockets are used. This applies
whether or not NIO is being used. For example,
you could use an implementation of this interface to modify the supported cipher suites on
an SSL socket, or you could add a listener that gets notified after SSL handshaking is
complete. The sole implementation provided by the framework is the
<classname>DefaultTcpSocketSupport</classname> which does not modify the sockets in
any way
</para>
<para>
To supply your own implementation of <classname>TcpSocketFactorySupport</classname> or
<classname>TcpSocketSupport</classname>, provide the connection factory with references to
beans of your custom type using the <classname>socket-factory-support</classname> and
<classname>socket-support</classname> attributes, respectively.
</para>
</section>
</section>
<section id="ip-endpoint-reference">
<title>IP Configuration Attributes</title>
<para>
<table id="connection-factory-attributes">
<title>Connection Factory Attributes</title>
<tgroup cols="5">
<colspec align="left" />
<colspec colnum="1" colname="col1" colwidth="1*"/>
<colspec colnum="2" colname="col2" colwidth="0.4*" align="center"/>
<colspec colnum="3" colname="col3" colwidth="0.4*" align="center"/>
<colspec colnum="4" colname="col4" colwidth="1*"/>
<colspec colnum="5" colname="col5" colwidth="2*"/>
<thead>
<row>
<entry align="center">Attribute Name</entry>
<entry align="center">Client?</entry>
<entry align="center">Server?</entry>
<entry align="center">Allowed Values</entry>
<entry align="center">Attribute Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>type</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry>client, server</entry>
<entry>Determines whether the connection factory is a client or server.</entry>
</row>
<row>
<entry>host</entry>
<entry>Y</entry>
<entry>N</entry>
<entry></entry>
<entry>The host name or ip address of the destination.</entry>
</row>
<row>
<entry>port</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry></entry>
<entry>The port.</entry>
</row>
<row>
<entry>serializer</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry></entry>
<entry>An implementation of <classname>Serializer</classname> used to serialize
the payload. Defaults to <classname>ByteArrayCrLfSerializer</classname></entry>
</row>
<row>
<entry>deserializer</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry></entry>
<entry>An implementation of <classname>Deserializer</classname> used to deserialize
the payload. Defaults to <classname>ByteArrayCrLfSerializer</classname></entry>
</row>
<row>
<entry>using-nio</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry>true, false</entry>
<entry>Whether or not connection uses NIO. Refer to the java.nio
package for more information.
See <xref linkend="note_nio" />.
Default false.</entry>
</row>
<row>
<entry>using-direct-buffers</entry>
<entry>Y</entry>
<entry>N</entry>
<entry>true, false</entry>
<entry>When using NIO, whether or not the connection uses direct buffers.
Refer to <classname>java.nio.ByteBuffer</classname> documentation for
more information. Must be false if using-nio is false. </entry>
</row>
<row>
<entry>apply-sequence</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry>true, false</entry>
<entry>When using NIO, it may be necessary to resequence messages. When this
attribute is set to true, <emphasis>correlationId</emphasis> and
<emphasis>sequenceNumber</emphasis> headers will be added to
received messages.
See <xref linkend="note_nio" />.
Default false.</entry>
</row>
<row>
<entry>so-timeout</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry></entry>
<entry>Defaults to 0 (infinity), except for
server connection factories with single-use="true".
In that case, it
defaults to the default reply timeout (10 seconds).
</entry>
</row>
<row>
<entry>so-send-buffer-size</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry></entry>
<entry>See <classname>java.net.Socket. setSendBufferSize()</classname>.
</entry>
</row>
<row>
<entry>so-receive-buffer- size</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry></entry>
<entry>See <classname>java.net.Socket. setReceiveBufferSize()</classname>.
</entry>
</row>
<row>
<entry>so-keep-alive</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry>true, false</entry>
<entry>See <classname>java.net.Socket. setKeepAlive()</classname>.</entry>
</row>
<row>
<entry>so-linger</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry></entry>
<entry>Sets linger to true with supplied value.
See <classname>java.net.Socket. setSoLinger()</classname>.</entry>
</row>
<row>
<entry>so-tcp-no-delay</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry>true, false</entry>
<entry>See <classname>java.net.Socket. setTcpNoDelay()</classname>.</entry>
</row>
<row>
<entry>so-traffic-class</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry></entry>
<entry>See <classname>java.net.Socket. setTrafficClass()</classname>.</entry>
</row>
<row>
<entry>local-address</entry>
<entry>N</entry>
<entry>Y</entry>
<entry></entry>
<entry>On a multi-homed system, specifies an IP address
for the interface to which the socket will be bound.
</entry>
</row>
<row>
<entry>task-executor</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry></entry>
<entry>
Specifies a specific Executor to be used for socket handling. If not supplied, an internal
cached thread executor will be used. Needed on some platforms that require the use of specific
task executors such as a WorkManagerTaskExecutor.</entry>
</row>
<row>
<entry>single-use</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry>true, false</entry>
<entry>Specifies whether a connection can be used for multiple messages.
If true, a new connection will be used for each message.</entry>
</row>
<row>
<entry>pool-size</entry>
<entry>N</entry>
<entry>N</entry>
<entry></entry>
<entry>This attribute is no longer used. For backward
compatibility, it sets the backlog but users should
use backlog to specify the
connection backlog in server factories</entry>
</row>
<row>
<entry>backlog</entry>
<entry>N</entry>
<entry>Y</entry>
<entry></entry>
<entry>Sets the connection backlog for server factories.</entry>
</row>
<row>
<entry>lookup-host</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry>true, false</entry>
<entry>
Specifies whether reverse lookups are done on IP addresses to convert to host names
for use in message headers. If false, the IP address is used instead. Defaults to true.
</entry>
</row>
<row>
<entry>interceptor-factory-chain</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry></entry>
<entry>See <xref linkend="ip-interceptors"/> </entry>
</row>
<row>
<entry>ssl-context-support</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry></entry>
<entry>See <xref linkend="ssl-tls"/> </entry>
</row>
<row>
<entry>socket-factory-support</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry></entry>
<entry>See <xref linkend="ssl-tls"/> </entry>
</row>
<row>
<entry>socket-support</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry></entry>
<entry>See <xref linkend="ssl-tls"/> </entry>
</row>
<row>
<entry>read-delay</entry>
<entry>Y</entry>
<entry>Y</entry>
<entry>long &gt; 0</entry>
<entry>The delay (in milliseconds) before retrying a read after the previous attempt
failed due to insufficient threads. Default 100.
Only applies if <code>using-nio</code> is <code>true</code>.</entry>
</row>
</tbody>
</tgroup>
</table>
<table id="ip-ib-adapter-attributes">
<title>UDP Inbound Channel Adapter Attributes</title>
<tgroup cols="3">
<colspec align="left" />
<colspec colnum="1" colname="col1" colwidth="1*"/>
<colspec colnum="2" colname="col4" colwidth="1*"/>
<colspec colnum="3" colname="col5" colwidth="2*"/>
<thead>
<row>
<entry align="center">Attribute Name</entry>
<entry align="center">Allowed Values</entry>
<entry align="center">Attribute Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>port</entry>
<entry></entry>
<entry>The port on which the adapter listens.</entry>
</row>
<row>
<entry>multicast</entry>
<entry>true, false</entry>
<entry>Whether or not the udp adapter uses multicast.</entry>
</row>
<row>
<entry>multicast-address</entry>
<entry></entry>
<entry>When multicast is true, the multicast address to which the adapter
joins.</entry>
</row>
<row>
<entry>pool-size</entry>
<entry></entry>
<entry>Specifies the concurrency. Specifies how many packets can
be handled concurrently.
It only applies if task-executor is not configured.
Defaults to 5.</entry>
</row>
<row>
<entry>task-executor</entry>
<entry></entry>
<entry>
Specifies a specific Executor to be used for socket handling. If not supplied, an internal
pooled executor will be used. Needed on some platforms that require the use of specific
task executors such as a WorkManagerTaskExecutor. See pool-size for thread
requirements.</entry>
</row>
<row>
<entry>receive-buffer-size</entry>
<entry></entry>
<entry>The size of the buffer used to receive DatagramPackets.
Usually set to the MTU size. If a smaller buffer is used than the
size of the sent packet, truncation can occur. This can be detected
by means of the check-length attribute..</entry>
</row>
<row>
<entry>check-length</entry>
<entry>true, false</entry>
<entry>Whether or not a udp adapter expects a data length field in the
packet received. Used to detect packet truncation.</entry>
</row>
<row>
<entry>so-timeout</entry>
<entry></entry>
<entry>See <classname>java.net.DatagramSocket</classname>
setSoTimeout() methods for more information.</entry>
</row>
<row>
<entry>so-send-buffer-size</entry>
<entry></entry>
<entry>Used for udp acknowledgment packets. See <classname>java.net.DatagramSocket</classname>
setSendBufferSize() methods for more information.</entry>
</row>
<row>
<entry>so-receive-buffer- size</entry>
<entry></entry>
<entry>See <classname>java.net.DatagramSocket</classname>
setReceiveBufferSize() for more information.</entry>
</row>
<row>
<entry>local-address</entry>
<entry></entry>
<entry>On a multi-homed system, specifies an IP address
for the interface to which the socket will be bound.</entry>
</row>
<row>
<entry>error-channel</entry>
<entry></entry>
<entry>If an Exception is thrown by a downstream
component, the MessagingException message containing the exception
and failed message is sent to this channel.</entry>
</row>
<row>
<entry>lookup-host</entry>
<entry>true, false</entry>
<entry>
Specifies whether reverse lookups are done on IP addresses to convert to host names
for use in message headers. If false, the IP address is used instead. Defaults to true.
</entry>
</row>
</tbody>
</tgroup>
</table>
<table id="ip-ob-adapter-attributes">
<title>UDP Outbound Channel Adapter Attributes</title>
<tgroup cols="3">
<colspec align="left" />
<colspec colnum="1" colname="col1" colwidth="1*"/>
<colspec colnum="2" colname="col4" colwidth="1*"/>
<colspec colnum="3" colname="col5" colwidth="2*"/>
<thead>
<row>
<entry align="center">Attribute Name</entry>
<entry align="center">Allowed Values</entry>
<entry align="center">Attribute Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>host</entry>
<entry></entry>
<entry>The host name or ip address of the destination. For multicast udp
adapters, the multicast address.</entry>
</row>
<row>
<entry>port</entry>
<entry></entry>
<entry>The port on the destination.</entry>
</row>
<row>
<entry>multicast</entry>
<entry>true, false</entry>
<entry>Whether or not the udp adapter uses multicast.</entry>
</row>
<row>
<entry>acknowledge</entry>
<entry>true, false</entry>
<entry>Whether or not a udp adapter requires an acknowledgment from the destination.
when enabled, requires setting the following 4 attributes.</entry>
</row>
<row>
<entry>ack-host</entry>
<entry></entry>
<entry>When acknowledge is true, indicates the host or ip address to which the
acknowledgment should be sent. Usually the current host, but may be
different, for example when Network Address Transaction (NAT) is
being used.</entry>
</row>
<row>
<entry>ack-port</entry>
<entry></entry>
<entry>When acknowledge is true, indicates the port to which the
acknowledgment should be sent. The adapter listens on this port for
acknowledgments.</entry>
</row>
<row>
<entry>ack-timeout</entry>
<entry></entry>
<entry>When acknowledge is true, indicates the time in milliseconds that the
adapter will wait for an acknowledgment. If an acknowledgment is not
received in time, the adapter will throw an exception.</entry>
</row>
<row>
<entry>min-acks-for- success</entry>
<entry></entry>
<entry>Defaults to 1. For multicast adapters, you can set this to a larger
value, requiring acknowledgments from multiple destinations.</entry>
</row>
<row>
<entry>check-length</entry>
<entry>true, false</entry>
<entry>Whether or not a udp adapter includes a data length field in the
packet sent to the destination.</entry>
</row>
<row>
<entry>time-to-live</entry>
<entry></entry>
<entry>For multicast adapters, specifies the time to live attribute for
the <classname>MulticastSocket</classname>; controls the scope
of the multicasts. Refer to the Java API
documentation for more information.</entry>
</row>
<row>
<entry>so-timeout</entry>
<entry></entry>
<entry>See <classname>java.net.DatagramSocket</classname>
setSoTimeout() methods for more information.</entry>
</row>
<row>
<entry>so-send-buffer-size</entry>
<entry></entry>
<entry>See <classname>java.net.DatagramSocket</classname>
setSendBufferSize() methods for more information.</entry>
</row>
<row>
<entry>so-receive-buffer- size</entry>
<entry></entry>
<entry>Used for udp acknowledgment packets. See <classname>java.net.DatagramSocket</classname>
setReceiveBufferSize() methods for more information.</entry>
</row>
<row>
<entry>local-address</entry>
<entry></entry>
<entry>On a multi-homed system, for the UDP adapter, specifies an IP address
for the interface to which the socket will be bound for reply messages.
For a multicast adapter it is also used to determine which interface
the multicast packets will be sent over.</entry>
</row>
<row>
<entry>task-executor</entry>
<entry></entry>
<entry>
Specifies a specific Executor to be used for acknowledgment handling. If not supplied, an internal
single threaded executor will be used. Needed on some platforms that require the use of specific
task executors such as a WorkManagerTaskExecutor. One thread will be dedicated to handling
acknowledgments (if the acknowledge option is true).</entry>
</row>
</tbody>
</tgroup>
</table>
<table id="tcp-ib-adapter-attributes">
<title>TCP Inbound Channel Adapter Attributes</title>
<tgroup cols="3">
<colspec align="left" />
<colspec colnum="1" colname="col1" colwidth="1*"/>
<colspec colnum="2" colname="col2" colwidth="1*"/>
<colspec colnum="3" colname="col3" colwidth="3*"/>
<thead>
<row>
<entry align="center">Attribute Name</entry>
<entry align="left">Allowed Values</entry>
<entry align="center">Attribute Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>channel</entry>
<entry></entry>
<entry>The channel to which inbound messages will be sent.</entry>
</row>
<row>
<entry>connection-factory</entry>
<entry></entry>
<entry>If the connection factory has a type 'server', the factory is 'owned'
by this adapter. If it has a type 'client', it is 'owned' by an
outbound channel adapter and this adapter will receive any
incoming messages on the connection created by the
outbound adapter.</entry>
</row>
<row>
<entry>error-channel</entry>
<entry></entry>
<entry>If an Exception is thrown by a downstream
component, the MessagingException message containing the exception
and failed message is sent to this channel.</entry>
</row>
<row>
<entry>client-mode</entry>
<entry>true, false</entry>
<entry>
When true, the inbound adapter will act as a client, with respect to establishing
the connection and then receive incoming messages on that connection. Default = false.
Also see <emphasis>retry-interval</emphasis> and <emphasis>scheduler</emphasis>.
The connection factory must be of type 'client' and have <emphasis>single-use</emphasis>
set to false.
</entry>
</row>
<row>
<entry>retry-interval</entry>
<entry></entry>
<entry>
When in <emphasis>client-mode</emphasis>, specifies the number of milliseconds
to wait between connection attempts, or after a connection failure. Default 60,000
(60 seconds).
</entry>
</row>
<row>
<entry>scheduler</entry>
<entry>true, false</entry>
<entry>
Specifies a <classname>TaskScheduler</classname> to use for managing the
<emphasis>client-mode</emphasis> connection. Defaults to a
<classname>ThreadPoolTaskScheduler</classname> with a pool size of `.
</entry>
</row>
</tbody>
</tgroup>
</table>
<table id="tcp-ob-adapter-attributes">
<title>TCP Outbound Channel Adapter Attributes</title>
<tgroup cols="3">
<colspec align="left" />
<colspec colnum="1" colname="col1" colwidth="1*"/>
<colspec colnum="2" colname="col2" colwidth="1*"/>
<colspec colnum="3" colname="col3" colwidth="3*"/>
<thead>
<row>
<entry align="center">Attribute Name</entry>
<entry align="left">Allowed Values</entry>
<entry align="center">Attribute Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>channel</entry>
<entry></entry>
<entry>The channel on which outbound messages arrive.</entry>
</row>
<row>
<entry>connection-factory</entry>
<entry></entry>
<entry>If the connection factory has a type 'client', the factory is
'owned' by this adapter. If it has a type 'server', it is 'owned'
by an inbound channel adapter and this adapter will attempt
to correlate messages to the connection on which an
original inbound message was received. </entry>
</row>
<row>
<entry>client-mode</entry>
<entry>true, false</entry>
<entry>
When true, the outbound adapter will attempt to establish the connection as
soon as it is started. When false, the connection is established when
the first message is sent. Default = false.
Also see <emphasis>retry-interval</emphasis> and <emphasis>scheduler</emphasis>.
The connection factory must be of type 'client' and have <emphasis>single-use</emphasis>
set to false.
</entry>
</row>
<row>
<entry>retry-interval</entry>
<entry></entry>
<entry>
When in <emphasis>client-mode</emphasis>, specifies the number of milliseconds
to wait between connection attempts, or after a connection failure. Default 60,000
(60 seconds).
</entry>
</row>
<row>
<entry>scheduler</entry>
<entry>true, false</entry>
<entry>
Specifies a <classname>TaskScheduler</classname> to use for managing the
<emphasis>client-mode</emphasis> connection. Defaults to a
<classname>ThreadPoolTaskScheduler</classname> with a pool size of `.
</entry>
</row>
</tbody>
</tgroup>
</table>
<table id="tcp-ib-gateway-attributes">
<title>TCP Inbound Gateway Attributes</title>
<tgroup cols="3">
<colspec align="left" />
<colspec colnum="1" colname="col1" colwidth="1*"/>
<colspec colnum="2" colname="col2" colwidth="1*"/>
<colspec colnum="3" colname="col3" colwidth="3*"/>
<thead>
<row>
<entry align="center">Attribute Name</entry>
<entry align="left">Allowed Values</entry>
<entry align="center">Attribute Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>connection-factory</entry>
<entry></entry>
<entry>The connection factory must be of type server. </entry>
</row>
<row>
<entry>request-channel</entry>
<entry></entry>
<entry>The channel to which incoming messages will be sent.</entry>
</row>
<row>
<entry>reply-channel</entry>
<entry></entry>
<entry>The channel on which reply messages may arrive. Usually replies will
arrive on a temporary reply channel added to the inbound message
header</entry>
</row>
<row>
<entry>reply-timeout</entry>
<entry></entry>
<entry>The time in milliseconds for which the gateway will wait for a reply.
Default 1000 (1 second).</entry>
</row>
<row>
<entry>error-channel</entry>
<entry></entry>
<entry>If an Exception is thrown by a downstream
component, the MessagingException message containing the exception
and failed message is sent to this channel;
any reply from that flow will then be returned as a response by
the gateway.</entry>
</row>
<row>
<entry>client-mode</entry>
<entry>true, false</entry>
<entry>
When true, the inbound gateway will act as a client, with respect to establishing
the connection and then receive (and reply to) incoming messages on that connection.
Default = false.
Also see <emphasis>retry-interval</emphasis> and <emphasis>scheduler</emphasis>.
The connection factory must be of type 'client' and have <emphasis>single-use</emphasis>
set to false.
</entry>
</row>
<row>
<entry>retry-interval</entry>
<entry></entry>
<entry>
When in <emphasis>client-mode</emphasis>, specifies the number of milliseconds
to wait between connection attempts, or after a connection failure. Default 60,000
(60 seconds).
</entry>
</row>
<row>
<entry>scheduler</entry>
<entry>true, false</entry>
<entry>
Specifies a <classname>TaskScheduler</classname> to use for managing the
<emphasis>client-mode</emphasis> connection. Defaults to a
<classname>ThreadPoolTaskScheduler</classname> with a pool size of `.
</entry>
</row>
</tbody>
</tgroup>
</table>
<table id="tcp-ob-gateway-attributes">
<title>TCP Outbound Gateway Attributes</title>
<tgroup cols="3">
<colspec align="left" />
<colspec colnum="1" colname="col1" colwidth="1*"/>
<colspec colnum="2" colname="col2" colwidth="1*"/>
<colspec colnum="3" colname="col3" colwidth="3*"/>
<thead>
<row>
<entry align="center">Attribute Name</entry>
<entry align="left">Allowed Values</entry>
<entry align="center">Attribute Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>connection-factory</entry>
<entry></entry>
<entry>The connection factory must be of type client. </entry>
</row>
<row>
<entry>request-channel</entry>
<entry></entry>
<entry>The channel on which outgoing messages will arrive.</entry>
</row>
<row>
<entry>reply-channel</entry>
<entry></entry>
<entry>Optional. The channel to which reply messages may be sent if the
original outbound message did not contain a reply channel header.
</entry>
</row>
<row>
<entry>remote-timeout</entry>
<entry></entry>
<entry>The time in milliseconds for which the gateway will wait for a reply from the
remote system.
Default: Same value as reply-timeout, if specified, or 10000 (10 seconds) otherwise.</entry>
</row>
<row>
<entry>request-timeout</entry>
<entry></entry>
<entry>If a single-use connection factory is not being used, The time in milliseconds
for which the gateway will wait to get access to the shared connection.</entry>
</row>
<row>
<entry>reply-timeout</entry>
<entry></entry>
<entry>The time in milliseconds for which the gateway will wait when sending the reply
to the reply-channel. Only applies if the reply-channel might block, such as a
bounded QueueChannel that is currently full.</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
</section>
<section id="ip-msg-headers">
<title>IP Message Headers</title>
<para>
The following <code>MessageHeader</code>s are used by this module:
</para>
<table id="ip-msg-headers-tbl">
<tgroup cols="3">
<colspec align="left" />
<colspec colnum="1" colname="col1" colwidth="1*"/>
<colspec colnum="2" colname="col2" colwidth="1*"/>
<colspec colnum="3" colname="col3"/>
<thead>
<row>
<entry align="center">Header Name</entry>
<entry align="center">IpHeaders Constant</entry>
<entry align="left">Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>ip_hostname</entry>
<entry>HOSTNAME</entry>
<entry>
The host name from which a TCP message or UDP packet was received. If
<code>lookupHost</code> is <code>false</code>, this will contain the ip address.
</entry>
</row>
<row>
<entry>ip_address</entry>
<entry>IP_ADDRESS</entry>
<entry>The ip address from which a TCP message or UDP packet was received.</entry>
</row>
<row>
<entry>ip_port</entry>
<entry>PORT</entry>
<entry>The remote port for a UDP packet.</entry>
</row>
<row>
<entry>ip_ackTo</entry>
<entry>ACKADDRESS</entry>
<entry>
The remote ip address to which UDP application-level acks will be sent. The
framework includes acknowledgment information in the data packet.
</entry>
</row>
<row>
<entry>ip_ackId</entry>
<entry>ACK_ID</entry>
<entry>
A correlation id for UDP application-level acks. The
framework includes acknowledgment information in the data packet.
</entry>
</row>
<row>
<entry>ip_tcp_remotePort</entry>
<entry>REMOTE_PORT</entry>
<entry>The remote port for a UDP packet.</entry>
</row>
<row>
<entry>ip_connectionId</entry>
<entry>CONNECTION_ID</entry>
<entry>
A unique identifier for a TCP connection; set by the framework for
inbound messages; when sending to a server-side inbound
channel adapter, or replying to an inbound gateway, this header is
required so the endpoint can determine which connection to send
the message to.
</entry>
</row>
<row>
<entry>ip_actualConnectionId</entry>
<entry>ACTUAL_CONNECTION_ID</entry>
<entry>
For information only - when using a cached or failover client connection
factory, contains the actual underlying connection id.
</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
</chapter>