Updated source and target adpater documentation.

This commit is contained in:
Mark Fisher
2008-05-23 00:38:03 +00:00
parent 2e984dbb3b
commit 99cdb7a8fc
2 changed files with 78 additions and 78 deletions

View File

@@ -6,14 +6,25 @@
<section id="adapters-intro">
<title>Introduction</title>
<para>
Channel Adapters are the components responsible for interacting with external systems or other components that
are external to the messaging system. As the name implies, the interaction consists of adapting the external
system or component to send-to and/or receive-from a <interfacename>MessageChannel</interfacename>. Within
Spring Integration, there is a distinction between <emphasis>source adapters</emphasis> and <emphasis>target
adapters</emphasis>. In the 1.0 Milestone 3 release, Spring Integration includes source and target adapters
for JMS, RMI, Files, Streams, Spring's HttpInvoker and Spring ApplicationEvents. A source adapter for FTP is
Spring Integration provides a number of implementations of the <interfacename>Source</interfacename> and
<interfacename>Target</interfacename> interfaces that serve as adapters for interacting with external
systems or components that are not part of the messaging system. Configuring these source and target
implementations within <classname>SourceEndpoints</classname> and <classname>TargetEndpoints</classname>
provides an implementation of the <emphasis>Channel Adapter</emphasis> pattern. Essentially, the external
system or component sends-to and/or receives-from a <interfacename>MessageChannel</interfacename>. In the
1.0 Milestone 4 release, Spring Integration includes source and target implementations for JMS, RMI,
Files, Streams, Spring's HttpInvoker and Spring ApplicationEvents. A source adapter for FTP is
also available as well as target adapters for sending e-mail and invoking Web Services.
</para>
<para>
Adapters that allow the external system to perform request-reply operations across Spring Integration
<interfacename>MessageChannels</interfacename> are actually examples of the <emphasis>Messaging Gateway</emphasis>
pattern. Therefore, those implementations are typically called "gateways". For example, Spring Integration
provides a <classname>JmsSource</classname> that is <emphasis>polled by</emphasis> the bus-managed
scheduler, but it also provides a <classname>JmsGateway</classname>. The gateway differs from the source in
that it is an <emphasis>event-driven consumer</emphasis> rather than a <emphasis>polling consumer</emphasis>,
and it is capable of waiting for reply messages.
</para>
<para>
All of these adapters are discussed in this section. However, namespace support is provided for many of them
and is typically the most convenient option for configuration. For examples, see
@@ -24,48 +35,39 @@
<section id="adapters-jms">
<title>JMS Adapters</title>
<para>
Spring Integration provides two adapters for accepting JMS messages:
<classname>JmsPollingSourceAdapter</classname> and <classname>JmsMessageDrivenSourceAdapter</classname>.
The former uses Spring's <classname>JmsTemplate</classname> to receive based on a polling period. The latter
configures and delegates to an instance of Spring's <classname>DefaultMessageListenerContainer</classname>.
Spring Integration provides two adapters for accepting JMS messages (as mentioned above):
<classname>JmsSource</classname> and <classname>JmsGateway</classname>. The former uses Spring's
<classname>JmsTemplate</classname> to receive based on a polling period. The latter configures and delegates to
an instance of Spring's <classname>DefaultMessageListenerContainer</classname>.
</para>
<para>
The <classname>JmsPollingSourceAdapter</classname> requires a reference to either a single
<classname>JmsTemplate</classname> instance or both <interfacename>ConnectionFactory</interfacename> and
<interfacename>Destination</interfacename> (a 'destinationName' can be provided in place of the 'destination'
reference). The <classname>JmsPollingSourceAdapter</classname> also requires a 'channel' property that should be
a reference to a <interfacename>MessageChannel</interfacename> instance. The adapter accepts additional
properties such as: period, initialDelay, maxMessagesPerTask, and sendTimeout. The following example defines a
JMS source adapter that polls every 5 seconds and then sends to the "exampleChannel":
<programlisting language="xml"><![CDATA[<bean class="org.springframework.integration.adapter.jms.JmsPollingSourceAdapter">
The <classname>JmsSource</classname> requires a reference to either a single <classname>JmsTemplate</classname>
instance or both <interfacename>ConnectionFactory</interfacename> and <interfacename>Destination</interfacename>
(a 'destinationName' can be provided in place of the 'destination' reference). The <classname>JmsSource</classname>
can then be referenced from a <classname>SourceEndpoint</classname> that connects the source to a
<interfacename>MessageChannel</interfacename> instance. The following example defines a JMS source with
a <classname>JmsTemplate</classname> as a constructor-argument.
<programlisting language="xml"><![CDATA[<bean id="jmsSource" class="org.springframework.integration.adapter.jms.JmsSource">
<constructor-arg ref="jmsTemplate"/>
<property name="channel" ref="exampleChannel"/>
<property name="period" value="5000"/>
</bean>]]></programlisting>
</para>
<para>
In most cases, Spring Integration's message-driven JMS adapter is more appropriate since it delegates to a
<interfacename>MessageListener</interfacename> container and supports dynamically adjusting concurrent
consumers. The <classname>JmsMessageDrivenSourceAdapter</classname> requires references to a
<interfacename>MessageChannel</interfacename>, a <interfacename>ConnectionFactory</interfacename>, and a
<interfacename>Destination</interfacename> (or 'destinationName'). The following example defines a JMS
message-driven source adapter that receives from the JMS queue called "exampleQueue" and then sends to
the Spring Integration channel named "exampleChannel":
<programlisting language="xml"><![CDATA[<bean class="org.springframework.integration.adapter.jms.JmsMessageDrivenSourceAdapter">
In most cases, Spring Integration's message-driven <classname>JmsGateway</classname> is more appropriate since it
delegates to a <interfacename>MessageListener</interfacename> container, supports dynamically adjusting
concurrent consumers, and can also handle replies. The <classname>JmsGateway</classname> requires references to
a <interfacename>ConnectionFactory</interfacename>, and a <interfacename>Destination</interfacename> (or
'destinationName'). The following example defines a <classname>JmsGateway</classname> that receives from the JMS
queue called "exampleQueue". Note that the 'expectReply' property has been set to 'true' (it is 'false' by
default):
<programlisting language="xml"><![CDATA[<bean class="org.springframework.integration.adapter.jms.JmsGateway">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destinationName" value="exampleQueue"/>
<property name="channel" ref="exampleChannel"/>
<property name="expectReply" value="true"/>
</bean>]]></programlisting>
</para>
<para>
For both source adapter types, Spring's <interfacename>MessageConverter</interfacename> strategy is used to
convert the JMS message into a plain Java object, and then Spring Integration's
<interfacename>MessageMapper</interfacename> strategy is used to convert from the plain object to a
<interfacename>Message</interfacename>.
</para>
<para>
The <classname>JmsTargetAdapter</classname> is a <interfacename>MessageHandler</interfacename> implementation
that is capable of mapping Spring Integration <interfacename>Messages</interfacename> to JMS messages and then
The <classname>JmsTarget</classname> implements the <interfacename>Target</interfacename> interface
and is capable of mapping Spring Integration <interfacename>Messages</interfacename> to JMS messages and then
sending to a JMS destination. It requires either a 'jmsTemplate' reference or both 'connectionFactory' and
'destination' references (again, the 'destinationName' may be provided in place of the 'destination). In
<xref linkend="namespace-adapters"/>, you will see how to configure a JMS target adapter with Spring
@@ -116,13 +118,13 @@ RmiTargetAdapter rmiTargetAdapter = new RmiTargetAdapter(url);
<section id="adapters-file">
<title>File Adapters</title>
<para>
The <classname>FileSourceAdapter</classname> extends the generic <classname>PollingSourceAdapter</classname>
(just as the polling JMS adapter does). It requires the following constructor arguments:
<programlisting language="java">public FileSourceAdapter(File directory, MessageChannel channel, int period)</programlisting>
Optional properties include 'initialDelay' and 'maxMessagesPerTask'.
The <classname>FileSource</classname> requires the directory as a constructor argument:
<programlisting language="java">public FileSource(File directory)</programlisting>
It can then be connected to a <interfacename>MessageChannel</interfacename> when referenced from
a <classname>SourceEndpoint</classname>.
</para>
<para>
The <classname>FileTargetAdapter</classname> constructor only requires the 'directory' argument. The target
The <classname>FileTarget</classname> constructor also requires the 'directory' argument. The target
adapter also accepts an implementation of the <interfacename>FileNameGenerator</interfacename> strategy that
defines the following method: <programlisting language="java">String generateFileName(Message message)</programlisting>
</para>
@@ -130,9 +132,9 @@ RmiTargetAdapter rmiTargetAdapter = new RmiTargetAdapter(url);
<section id="adapters-ftp">
<title>FTP Adapters</title>
<para>
To poll a directory with FTP, configure an instance of <classname>FtpSourceAdapter</classname>. The adapter
expects a number of properties for connecting to the FTP server (as shown below) as well as the
'channel' and the 'period' for polling. For example, the following adapter would poll every 30 seconds:
To poll a directory with FTP, configure an instance of <classname>FtpSource</classname> and then connect
it to a channel by configuring a <classname>SourceEndpoint</classname>. The <classname>FtpSource</classname>
expects a number of properties for connecting to the FTP server as shown below.
<programlisting language="xml"><![CDATA[<bean id="ftpSource"
class="org.springframework.integration.adapter.ftp.FtpSourceAdapter">
<property name="host" value="example.org"/>
@@ -140,8 +142,6 @@ RmiTargetAdapter rmiTargetAdapter = new RmiTargetAdapter(url);
<property name="password" value="somepassword"/>
<property name="localWorkingDirectory" value="/some/path"/>
<property name="remoteWorkingDirectory" value="/some/path"/>
<property name="channel" ref="someChannel"/>
<property name="period" value="30000"/>
</bean>]]></programlisting>
</para>
</section>
@@ -149,7 +149,7 @@ RmiTargetAdapter rmiTargetAdapter = new RmiTargetAdapter(url);
<title>Mail Adapters</title>
<para>
Spring Integration currently provides support for <emphasis>outbound</emphasis> email only with the
<classname>MailTargetAdapter</classname>. This adapter delegates to a configured instance of Spring's
<classname>MailTarget</classname>. This adapter delegates to a configured instance of Spring's
<interfacename>JavaMailSender</interfacename>, and its various mapping strategies use Spring's
<interfacename>MailMessage</interfacename> abstraction. By default text-based mails are created when
the handled message has a String-based payload. If the message payload is a byte array, then that will
@@ -194,10 +194,10 @@ MailAttributeKeys.REPLY_TO</programlisting>
marshallingAdapter = new MarshallingWebServiceTargetAdapter(uri, marshaller);
</programlisting>
As with the other target adapters, this can then be referenced from a <classname>MessageEndpoint</classname>
that is subscribed to a channel. The endpoint is then responsible for passing the response to the proper
channel. It will first check for a <emphasis>returnAddress</emphasis> on the original message's header, and it
will fallback to the endpoint's own default output channel.
Either adapter can then be referenced from a <classname>HandlerEndpoint</classname> that is subscribed to a
<interfacename>MessageChannel</interfacename>. The endpoint is then responsible for passing the response to the
proper reply channel. It will first check for an "output-channel" on the endpoint itself and will fallback to a
<emphasis>returnAddress</emphasis> on the original message's header.
</para>
<para>
For more detail on the inner workings, see the Spring Web Services reference guide's chapter covering
@@ -209,21 +209,22 @@ marshallingAdapter = new MarshallingWebServiceTargetAdapter(uri, marshaller);
<section id="adapters-stream">
<title>Stream Adapters</title>
<para>
Spring Integration also provides adapters for streams. Both <classname>ByteStreamSourceAdapter</classname> and
<classname>CharacterStreamSourceAdapter</classname> extend the <classname>PolllingSourceAdapter</classname> so
that the polling period can be configured, and the Message Bus can automatically detect and schedule them. The
byte stream version requires an <classname>InputStream</classname>, and the character stream version requires a
<classname>Reader</classname> as the single constructor argument. The
<classname>ByteStreamSourceAdapter</classname> also accepts the 'bytesPerMessage' property to determine how many
bytes it will attempt to read into each <interfacename>Message</interfacename>.
Spring Integration also provides adapters for streams. Both <classname>ByteStreamSource</classname> and
<classname>CharacterStreamSource</classname> implement the <interfacename>Source</interfacename> interface. By
configuring one of these within a <classname>SourceEndpoint</classname>, the polling period can be configured,
and the Message Bus can automatically detect and schedule them. The byte stream version requires an
<classname>InputStream</classname>, and the character stream version requires a <classname>Reader</classname> as
the single constructor argument. The <classname>ByteStreamSource</classname> also accepts the 'bytesPerMessage'
property to determine how many bytes it will attempt to read into each <interfacename>Message</interfacename>.
</para>
<para>
For target streams, there are also two implementations: <classname>ByteStreamTargetAdapter</classname> and
<classname>CharacterStreamTargetAdapter</classname>. Each requires a single constructor argument -
For target streams, there are also two implementations: <classname>ByteStreamTarget</classname> and
<classname>CharacterStreamTarget</classname>. Each requires a single constructor argument -
<classname>OutputStream</classname> for byte streams or <classname>Writer</classname> for character streams,
and each provides a second constructor that adds the optional 'bufferSize' property. Since both of these
ultimately implement the <interfacename>MessageHandler</interfacename> interface, they can be referenced from an
endpoint configuration as will be described in more detail in <xref linkend="namespace-endpoint"/>.
ultimately implement the <interfacename>Target</interfacename> interface, they can be referenced from a
<classname>TargetEndpoint</classname> configuration as will be described in more detail in
<xref linkend="namespace-endpoint"/>.
</para>
</section>
<section id="adapters-applicationevents">
@@ -231,18 +232,17 @@ marshallingAdapter = new MarshallingWebServiceTargetAdapter(uri, marshaller);
<para>
Spring <classname>ApplicationEvents</classname> can also be integrated as either a source or target for Spring
Integration message channels. To receive the events and send to a channel, simply define an instance of Spring
Integration's <classname>ApplicationEventSourceAdapter</classname> (as with all source adapters, if a
<classname>MessageBus</classname> is defined, it will automatically detect the event source adapter). The
<classname>ApplicationEventSourceAdapter</classname> implements Spring's
<interfacename>ApplicationListener</interfacename> interface. By default it will pass all received events as
Spring Integration Messages. To limit based on the type of event, configure the list of event types that you
want to receive with the 'eventTypes' property.
Integration's <classname>ApplicationEventSource</classname> (as with all source implementations, this can then
be configured within a <classname>SourceEndpoint</classname> and automatically detected by the message bus). The
<classname>ApplicationEventSource</classname> also implements Spring's <interfacename>ApplicationListener</interfacename>
interface. By default it will pass all received events as Spring Integration Messages. To limit based on the type
of event, configure the list of event types that you want to receive with the 'eventTypes' property.
</para>
<para>
To send Spring <classname>ApplicationEvents</classname>, register an instance of the
<classname>ApplicationEventTargetAdapter</classname> class as the handler of an endpoint (such configuration
will be described in detail in <xref linkend="namespace-endpoint"/>). This adapter implements Spring's
<interfacename>ApplicationEventPublisherAware</interfacename> interface and thus acts as a bridge between
<classname>ApplicationEventTarget</classname> class as the 'target' of a <classname>TargetEndpoint</classname>
(such configuration will be described in detail in <xref linkend="namespace-endpoint"/>). This target also implements
Spring's <interfacename>ApplicationEventPublisherAware</interfacename> interface and thus acts as a bridge between
Spring Integration <classname>Messages</classname> and <classname>ApplicationEvents</classname>.
</para>
</section>

View File

@@ -89,8 +89,8 @@ public class DrinkRouter {
<programlisting language="java"><![CDATA[@Component
public class Barista {
private long hotDrinkDelay = 1000;
private long coldDrinkDelay = 700;
private long hotDrinkDelay = 2000;
private long coldDrinkDelay = 1000;
private AtomicInteger hotDrinkCounter = new AtomicInteger();
private AtomicInteger coldDrinkCounter = new AtomicInteger();
@@ -160,9 +160,9 @@ public class Barista {
</para>
<para>
When you run cafeDemo, you will see that all 100 cold drinks are prepared in roughly the same amount of time as
only 70 of the hot drinks. This is to be expected based on their respective delays of 700 and 1000 milliseconds.
only 50 of the hot drinks. This is to be expected based on their respective delays of 1000 and 2000 milliseconds.
However, by configuring the endpoint concurrency, you can dramatically change the results. For example, on my
machine, the following single modification causes all 100 hot drinks to be prepared before the 4th cold drink is
machine, the following single modification causes all 100 hot drinks to be prepared before the 5th cold drink is
ready:
<programlisting language="xml"><![CDATA[<handler-endpoint input-channel="coldDrinks" handler="barista" method="prepareColdDrink"/>
@@ -174,8 +174,8 @@ public class Barista {
In addition to experimenting with the 'concurrency' settings, you can also try adding the 'schedule' sub-element
as described in <xref linkend="namespace-endpoint"/>. Additionally, you can experiment with the channel's
configuration, such as adding a 'dispatcher-policy' as described in <xref linkend="namespace-channel"/>. If you
want to explore the sample in more detail, the source JAR is available in the "dist" directory:
'spring-integration-samples-sources-1.0.0.M3.jar'.
want to explore the sample in more detail, the source JAR is available in the "src" directory:
'org.springframework.integration.samples-sources-1.0.0.M4.jar'.
</para>
</section>
</chapter>