proof read reference guide

This commit is contained in:
David Turanski
2010-11-19 15:32:11 -05:00
parent 8a8835eaa1
commit 1886ea3fb1
9 changed files with 370 additions and 367 deletions

View File

@@ -8,13 +8,13 @@
<para>Basically a mirror-image of the Splitter, the Aggregator is a type
of Message Handler that receives multiple Messages and combines them into
a single Message. In fact, Aggregators are often downstream consumers in a
a single Message. In fact, an Aggregator is often a downstream consumer in a
pipeline that includes a Splitter.</para>
<para>Technically, the Aggregator is more complex than a Splitter, because
it is required to maintain state (the Messages to be aggregated), to
decide when the complete group of Messages is available. In order to do
this it requires a MessageStore</para>
it is stateful as it must hold the Messages to be aggregated and determine
when the complete group of Messages is ready to be aggregated. In order to do
this it requires a <interfacename>MessageStore</interfacename>.</para>
</section>
<section id="aggregator-functionality">
@@ -23,24 +23,24 @@
<para>The Aggregator combines a group of related messages, by correlating
and storing them, until the group is deemed complete. At that point, the
Aggregator will create a single message by processing the whole group, and
will send that aggregated message as output.</para>
will send the aggregated message as output.</para>
<para>An main aspect of implementing an Aggregator is providing the logic
that has to be executed when the aggregation (creation of a single message
out of many) takes place. The other two aspects are correlation and
<para>Implementing an Aggregator requires providing the logic
to perform the aggregation (i.e., the creation of a single message
from many). Two related concepts are correlation and
release</para>
<para>In Spring Integration, the grouping of the messages for aggregation
(correlation) is done by default based on their CORRELATION_ID message
header (i.e. the messages with the same CORRELATION_ID will be grouped
together). However, this can be customized, and the users can opt for
other ways of specifying how the messages should be grouped together, by
using a CorrelationStrategy (see below).</para>
<para>Correlation determines how messages are grouped for aggregation.
In Spring Integration correlation is done by default based on the CORRELATION_ID message
header. Messages with the same CORRELATION_ID will be grouped
together. However, the correlation strategy may be customized to allow
other ways of specifying how the messages should be grouped together by
implementing a <interfacename>CorrelationStrategy</interfacename> (see below).</para>
<para>To determine whether or not a group of messages may be processed, a
ReleaseStrategy is consulted. The default release strategy for aggregator
will release groups that have all messages from the sequence, but this can
be entirely customized</para>
<para>To determine the state in which a group of messages may be processed, a
<interfacename>ReleaseStrategy</interfacename> is consulted.
The default release strategy for Aggregator will release groups when all
messages included in the sequence are present but this may be customized.</para>
</section>
<section id="aggregator-api">
@@ -50,20 +50,20 @@
<itemizedlist>
<listitem>
<para>The interface <code>MessageGroupProcessor</code> and related
base class <code>AbstractAggregatingMessageGroupProcessor</code> and
<para>The interface <interfacename>MessageGroupProcessor</interfacename> and related
base class <classname>AbstractAggregatingMessageGroupProcessor</classname> and
its subclass
<code>MethodInvokingAggregatingMessageGroupProcessor</code></para>
<classname>MethodInvokingAggregatingMessageGroupProcessor</classname></para>
</listitem>
<listitem>
<para>The <code>ReleaseStrategy</code> interface and its default
implementation <code>SequenceSizeReleaseStrategy</code></para>
<para>The <interfacename>ReleaseStrategy</interfacename> interface and its default
implementation <classname>SequenceSizeReleaseStrategy</classname></para>
</listitem>
<listitem>
<para>The <code>CorrelationStrategy</code> interface and its default
implementation <code>HeaderAttributeCorrelationStrategy</code></para>
<para>The <interfacename>CorrelationStrategy</interfacename> interface and its default
implementation <classname>HeaderAttributeCorrelationStrategy</classname></para>
</listitem>
</itemizedlist>
@@ -74,8 +74,8 @@
<para>The <code>CorrelatingMessageHandler</code> is a
<code>MessageHandler</code> implementation, encapsulating the common
<para>The <classname>CorrelatingMessageHandler</classname> is a
<interfacename>MessageHandler</interfacename> implementation, encapsulating the common
functionalities of an Aggregator (and other correlating use cases),
which are: <itemizedlist>
<listitem>
@@ -83,33 +83,32 @@
</listitem>
<listitem>
<para>maintaining those messages in a MessageStore until the group
may be released</para>
<para>maintaining those messages in a <interfacename>MessageStore</interfacename> until the group
can be released</para>
</listitem>
<listitem>
<para>deciding when the group is in fact may be released</para>
<para>deciding when the group can be released</para>
</listitem>
<listitem>
<para>processing the released group into a single aggregated
message</para>
<para>aggregating the released group into a single message</para>
</listitem>
<listitem>
<para>recognizing and responding to an expired group</para>
</listitem>
</itemizedlist> The responsibility of deciding how the messages should
be grouped together is delegated to a <code>CorrelationStrategy</code>
be grouped together is delegated to a <interfacename>CorrelationStrategy</interfacename>
instance. The responsibility of deciding whether the message group can
be released is delegated to a <code>ReleaseStrategy</code>
be released is delegated to a <interfacename>ReleaseStrategy</interfacename>
instance.</para>
<para>Here is a brief highlight of the base
<code>AbstractAggregatingMessageGroupProcessor</code> (the
responsibility of implementing the aggregateMessages method is left to
<classname>AbstractAggregatingMessageGroupProcessor</classname> (the
responsibility of implementing the <code>aggregateMessages</code> method is left to
the developer):</para>
@@ -125,74 +124,72 @@
}]]></programlisting>
The CorrelationStrategy is owned by the
The <interfacename>CorrelationStrategy</interfacename> is owned by the
<code>CorrelatingMessageHandler</code>
<classname>CorrelatingMessageHandler</classname>
and it has a default value based on the correlation ID message header:
and it has a default value based on the CORRELATION_ID message header:
<programlisting language="java"><![CDATA[private volatile CorrelationStrategy correlationStrategy =
new HeaderAttributeCorrelationStrategy(MessageHeaders.CORRELATION_ID);]]></programlisting>
<programlisting language="java"><![CDATA[
public CorrelatingMessageHandler(MessageGroupProcessor processor, MessageGroupStore store,
CorrelationStrategy correlationStrategy, ReleaseStrategy releaseStrategy) {
...
this.correlationStrategy = correlationStrategy == null ?
new HeaderAttributeCorrelationStrategy(MessageHeaders.CORRELATION_ID) : correlationStrategy;
this.releaseStrategy = releaseStrategy == null ? new SequenceSizeReleaseStrategy() : releaseStrategy;
...
}
]]></programlisting>
<para>When appropriate, the simplest option is the
<code>DefaultAggregatingMessageGroupProcessor</code>. It creates a
<classname>DefaultAggregatingMessageGroupProcessor</classname>. It creates a
single Message whose payload is a List of the payloads received for a
given group. It uses the default <code>CorrelationStrategy</code> and
<code>CompletionStrategy</code> as shown above. This works well for
simple Scatter Gather implementations with either a Splitter, Publish
given group. This works well for simple Scatter Gather implementations with either a Splitter, Publish
Subscribe Channel, or Recipient List Router upstream.</para>
<note>
<para>When using a Publish Subscribe Channel or Recipient List Router
in this type of scenario, be sure to enable the flag to
<emphasis>apply-sequence</emphasis>. That will add the necessary
headers (correlation id, sequence number and sequence size). That
<code>apply-sequence</code>. That will add the necessary
headers (CORRELATION_ID, SEQUENCE_NUMBER and SEQUENCE_SIZE). That
behavior is enabled by default for Splitters in Spring Integration,
but it is not enabled for the Publish Subscribe Channel or Recipient
List Router because those components may be used in a variety of
contexts where those headers are not necessary.</para>
contexts in which these headers are not necessary.</para>
</note>
<para>When implementing a specific aggregator object for an application,
a developer can extend
<code>AbstractAggregatingMessageGroupProcessor</code> and implement the
<code>aggregatePayloads</code> method. However, there are better suited
(which reads, less coupled to the API) solutions for implementing the
aggregation logic, which can be configured easily either through XML or
through annotations.</para>
<para>In general, any ordinary Java class (i.e. POJO) can implement the
aggregation algorithm. For doing so, it must provide a method that
accepts as an argument a single java.util.List (parametrized lists are
supported as well). This method will be invoked for aggregating
messages, as follows:</para>
<classname>AbstractAggregatingMessageGroupProcessor</classname> and implement the
<code>aggregatePayloads</code> method. However, there are better solutions, less
coupled to the API, for implementing the aggregation logic which can be configured easily
either through XML or through annotations.</para>
<para>In general, any POJO can implement the
aggregation algorithm if it provide a method that
accepts a single <interfacename>java.util.List</interfacename> as an argument
(parametrized lists are supported as well). This method will be invoked for aggregating
messages as follows:</para>
<itemizedlist>
<listitem>
<para>if the argument is a parametrized java.util.List, and the
parameter type is assignable to Message, then the whole list of
messages accumulated for aggregation will be sent to the
aggregator</para>
<para>if the argument is a <interfacename>java.util.List&lt;T&gt;</interfacename>, and the
parameter type T is assignable to <interfacename>Message</interfacename>, then the whole list of
messages accumulated for aggregation will be sent to the aggregator</para>
</listitem>
<listitem>
<para>if the argument is a non-parametrized java.util.List or the
parameter type is not assignable to Message, then the method will
<para>if the argument is a non-parametrized <interfacename>java.util.List</interfacename> or the
parameter type is not assignable to <interfacename>Message</interfacename>, then the method will
receive the payloads of the accumulated messages</para>
</listitem>
<listitem>
<para>if the return type is not assignable to Message, then it will
<para>if the return type is not assignable to <interfacename>Message</interfacename>, then it will
be treated as the payload for a Message that will be created
automatically by the framework.</para>
</listitem>
@@ -204,7 +201,7 @@
<para>In the interest of code simplicity, and promoting best practices
such as low coupling, testability, etc., the preferred way of
implementing the aggregation logic is through a POJO, and using the
XML or annotation support for setting it up in the application.</para>
XML or annotation support for configuring it in the application.</para>
</note>
@@ -213,7 +210,7 @@
<section>
<title>ReleaseStrategy</title>
<para>The <code>ReleaseStrategy</code> interface is defined as
<para>The <interfacename>ReleaseStrategy</interfacename> interface is defined as
follows:</para>
<programlisting language="java"><![CDATA[public interface ReleaseStrategy {
@@ -222,23 +219,23 @@
}]]></programlisting>
<para>In general, any ordinary Java class (i.e. POJO) can implement the
completion decision mechanism. For doing so, it must provide a method
that accepts as an argument a single java.util.List (parametrized lists
<para>In general, any POJO can implement the
completion decision logic if provide a method
that a single <interfacename>java.util.List</interfacename> as an argument (parametrized lists
are supported as well), and returns a boolean value. This method will be
invoked after the arrival of a new message, to decide whether the group
is complete or not, as follows:</para>
<itemizedlist>
<listitem>
<para>if the argument is a parametrized java.util.List, and the
parameter type is assignable to Message, then the whole list of
<para>if the argument is a <interfacename>java.util.List&lt;T&gt;</interfacename>, and the
parameter type T is assignable to <interfacename>Message</interfacename>, then the whole list of
messages accumulated in the group will be sent to the method</para>
</listitem>
<listitem>
<para>if the argument is a non-parametrized java.util.List or the
parameter type is not assignable to Message, then the method will
<para>if the argument is a non-parametrized <interfacename>java.util.List</interfacename> or the
parameter type is not assignable to <interfacename>Message</interfacename>, then the method will
receive the payloads of the accumulated messages</para>
</listitem>
@@ -253,14 +250,14 @@
again. If the group is also complete (i.e. if all messages from a
sequence have arrived or if there is no sequence defined) then the group
is removed from the message store. Partial sequences can be released, in
which case the next time the <code>ReleaseStrategy</code> is called it
which case the next time the <interfacename>ReleaseStrategy</interfacename> is called it
will be presented with a group containing marked messages (already
processed) and unmarked messages (a potential new partial
sequence)</para>
<para>Spring Integration provides an out-of-the box implementation for
<code>ReleaseStrategy</code>, the
<code>SequenceSizeReleaseStrategy</code>. This implementation uses the
<interfacename>ReleaseStrategy</interfacename>, the
<classname>SequenceSizeReleaseStrategy</classname>. This implementation uses the
SEQUENCE_NUMBER and SEQUENCE_SIZE of the arriving messages for deciding
when a message group is complete and ready to be aggregated. As shown
above, it is also the default strategy.</para>
@@ -269,7 +266,7 @@
<section>
<title>CorrelationStrategy</title>
<para>The <code>CorrelationStrategy</code> interface is defined as
<para>The <interfacename>CorrelationStrategy</interfacename> interface is defined as
follows:</para>
<programlisting language="java"><![CDATA[public interface CorrelationStrategy {
@@ -278,24 +275,24 @@
}]]></programlisting>
<para>The method shall return an Object which represents the correlation
<para>The method returns an Object which represents the correlation
key used for grouping messages together. The key must satisfy the
criteria used for a key in a Map with respect to the implementation of
equals() and hashCode().</para>
<para>In general, any ordinary Java class (i.e. POJO) can implement the
correlation decision mechanism, and the rules for mapping a message to a
<para>In general, any POJO can implement the
correlation logic, and the rules for mapping a message to a
method's argument (or arguments) are the same as for a
<code>ServiceActivator</code> (including support for @Header
<interfacename>ServiceActivator</interfacename> (including support for @Header
annotations). The method must return a value, and the value must not be
<code>null</code>.</para>
<para>Spring Integration provides an out-of-the box implementation for
<code>CorrelationStrategy</code>, the
<code>HeaderAttributeCorrelationStrategy</code>. This implementation
<interfacename>CorrelationStrategy</interfacename>, the
<classname>HeaderAttributeCorrelationStrategy</classname>. This implementation
returns the value of one of the message headers (whose name is specified
by a constructor argument) as the correlation key. By default, the
correlation strategy is a HeaderAttributeCorrelationStrategy returning
correlation strategy is a <classname>HeaderAttributeCorrelationStrategy</classname> returning
the value of the CORRELATION_ID header attribute.</para>
</section>
</section>
@@ -350,7 +347,7 @@
<calloutlist>
<callout arearefs="aggxml01">
<para>The id of the aggregator is
<emphasis>optional</emphasis>.</para>
<emphasis>0ptional</emphasis>.</para>
</callout>
<callout arearefs="aggxml02">
@@ -359,51 +356,50 @@
</callout>
<callout arearefs="aggxml03">
<para>The channel where aggregator will receive messages from
<para>The channel from which where aggregator will receive messages.
<emphasis>Required</emphasis>.</para>
</callout>
<callout arearefs="aggxml04">
<para>The channel where the aggregator will send the aggregation
<para>The channel to which the aggregator will send the aggregation
results. <emphasis>Optional (because incoming messages can specify a
reply channel themselves via 'replyChannel' Message Header)</emphasis>.</para>
</callout>
<callout arearefs="aggxml05">
<para>The channel where the aggregator will send the messages that
<para>The channel to which the aggregator will send the messages that
timed out (if <code>send-partial-results-on-expiry</code> is
<emphasis>false</emphasis>). <emphasis>Optional</emphasis>.</para>
</callout>
<callout arearefs="aggxml06">
<para>A reference to a <code>MessageGroupStore</code> that can be used
<para>A reference to a <code>MessageGroupStore</code> used
to store groups of messages under their correlation key until they are
complete. <emphasis>Optional</emphasis> with default a volatile
complete. <emphasis>Optional</emphasis>, by default a volatile
in-memory store.</para>
</callout>
<callout arearefs="aggxml07">
<para>Order of this aggregator in when more then one aggregator is subscribig to the same DirectChannel
(use for load balancing purposes)
<para>Order of this aggregator in when more then one aggregator is subscribing to the same DirectChannel
(use for load balancing purposes).
<emphasis>Optional</emphasis>.</para>
</callout>
<callout arearefs="aggxml08">
<para>Tells if partially aggregated messages should be released when their storage time had expired
(see MessageGroupStore.expireMessageGroups(long))
<para>Indicates if partially aggregated messages should be released when their storage time has expired
(see <code>MessageGroupStore.expireMessageGroups(long)</code>).
<emphasis>Optional</emphasis>.</para>
</callout>
<callout arearefs="aggxml09">
<para>The timeout for sending the aggregated messages to the output or
<para>The timeout interval for sending the aggregated messages to the output or
reply channel. <emphasis>Optional</emphasis>.</para>
</callout>
<callout arearefs="aggxml10">
<para>A reference to a bean that implements the decision algorithm as
to whether a given message group is complete. The bean can be an
implementation of the CorrelationStrategy interface or a POJO. In the
latter case the correlation-strategy-method attribute must be defined
<callout arearefs="aggxml10">
<para>A reference to a bean that implements the message correlation (grouping)
algorithm. The bean can be an implementation of the <interfacename>CorrelationStrategy</interfacename>
interface or a POJO. In the latter case the correlation-strategy-method attribute must be defined
as well. <emphasis>Optional (by default, the aggregator will use
sequence size) </emphasis>.</para>
</callout>
@@ -415,13 +411,12 @@
restrictions (requires <code>correlation-strategy</code> to be
present).</emphasis></para>
</callout>
<callout arearefs="aggxml12">
<para>A reference to a bean defined in the application context. The bean must implement the aggregation logic
as described above.<emphasis>Optional (by default the list of aggregated Messages will become a
payload of the output message).</emphasis></para>
as described above.<emphasis>Optional (by default the list of aggregated Messages will become a
payload of the output message).</emphasis></para>
</callout>
<callout arearefs="aggxml13">
<para>A method defined on the bean referenced by <code>ref</code>,
that implements the message aggregation
@@ -430,7 +425,7 @@
<callout arearefs="aggxml14">
<para>A reference to a bean that implements the release strategy.
The bean can be an implementation of the <classname>ReleaseStrategy</classname> interface
The bean can be an implementation of the <interfacename>ReleaseStrategy</interfacename> interface
or a POJO. In the latter case the release-strategy-method
attribute must be defined as well. <emphasis>Optional (by default, the
aggregator will use the correlation id header attribute)
@@ -447,11 +442,11 @@
</calloutlist>
<para>Using a "ref" attribute is generally recommended if a custom
aggregator handler implementation can be reused in other
<para>Using a <code>ref</code> attribute is generally recommended if a custom
aggregator handler implementation my be referenced in other
<code>&lt;aggregator&gt;</code> definitions. However if a custom
aggregator handler implementation should be scoped to a concrete
definition of the <code>&lt;aggregator&gt;</code>, you can use an inner
aggregator implementation should be scoped to a single
definition of the <code>&lt;aggregator&gt;</code>, use an inner
bean definition (starting with version 1.0.3) for custom aggregator
handlers within the <code>&lt;aggregator&gt;</code> element:
<programlisting language="xml"><![CDATA[<aggregator input-channel="input" method="sum" output-channel="output">
@@ -459,7 +454,7 @@
</aggregator>]]></programlisting></para>
<note>
<para>Using both a "ref" attribute and an inner bean definition in the
<para>Using both a <code>ref</code> attribute and an inner bean definition in the
same <code>&lt;aggregator&gt;</code> configuration is not allowed, as it
creates an ambiguous condition. In such cases, an Exception will be
thrown.</para>
@@ -523,8 +518,9 @@
</para>
<para>
Since Spring Integration 2.0, the <emphasis>release strategy</emphasis> may be handled with SpEL (http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html)
which would be recommend if the logic behind such <emphasis>release strategy</emphasis> is relatively simple.
Since Spring Integration 2.0, the <emphasis>release strategy</emphasis> may be handled with
<ulink url="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html">SpEL</ulink>
which is recommended if the logic behind such <emphasis>release strategy</emphasis> is relatively simple.
Let's say you have a legacy component which was designed to receive an array of objects. We know that default release
strategy will assemble all aggregated messages in the List. So now we have two problems. First we need to extract individual
messages form such list, extract payload of each message and assemble them into the array of objects (see code below)
@@ -544,9 +540,9 @@
output-channel="replyChannel"
expression="#this.![payload].toArray()"/>]]></programlisting>
In the above configuration we are using <emphasis>Collection Projection</emphasis> expression
(http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html#d0e12113) to
assemble a new collection from the payloads of all messages in the list and then transforming it to an Array, thus
In the above configuration we are using a <ulink
url="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html#d0e12113">Collection Projection</ulink> expression
to assemble a new collection from the payloads of all messages in the list and then transforming it to an Array, thus
achieving the same result as the java code above.
</para>
@@ -557,7 +553,7 @@
<para>
Instead of defining a bean for custom <classname>CorrelationStrategy</classname> via <code>correlation-strategy</code>
attribute you can implement your simple correlation logic via SpEL expression and configure it via
<code>correlation-strategy-ecpression</code> attribute.
<code>correlation-strategy-expression</code> attribute.
</para>
<para>
For example:
@@ -568,7 +564,7 @@
which is going to be used to correlate messages.
</para>
<para>
And when it comes to <classname>ReleaseStrategy</classname> you can implement your release logic via
And when it comes to <interfacename>ReleaseStrategy</interfacename> you can implement your release logic via
SpEL expression as well and configure it via <code>release-strategy-expression</code> attribute.
</para>
<para>
@@ -576,7 +572,7 @@
<programlisting language="xml"><![CDATA[release-strategy-expression="payload.size() > 5"]]></programlisting>
In this example the root of SpEL Evaluation Context is <classname>MessageGroup</classname> and you simply stating
In this example the root of SpEL Evaluation Context is <interfacename>MessageGroup</interfacename> and you simply stating
that as soon as there are more then 5 messages in this group release the group.
</para>
</section>
@@ -649,18 +645,18 @@
stateful pattern that requires decisions to be made based on a group of
messages that have arrived over a period of time, all with the same
correlation key. The design of the interfaces in the stateful patterns
(e.g. <classname>ReleaseStrategy</classname>) is driven by the principle
(e.g. <interfacename>ReleaseStrategy</interfacename>) is driven by the principle
that the components (framework and user) should be to remain stateless.
All state is carried by the <classname>MessageGroup</classname> and its
All state is carried by the <interfacename>MessageGroup</interfacename> and its
management is delegated to the
<classname>MessageGroupStore</classname>.</para>
<interfacename>MessageGroupStore</interfacename>.</para>
<para>The <classname>MessageGroupStore</classname> accumulates state
information in <classname>MessageGroups</classname>, potentially forever.
So to prevent stale state from hanging around, and for volatile stores to
provide a hook for cleaning up when the application shots down, the
<classname>MessageGroupStore</classname> allows the user to register
callbacks to apply to <classname>MessageGroups</classname> when they
<para>The <interfacename>MessageGroupStore</interfacename> accumulates state
information in <interfacename>MessageGroups</interfacename>, potentially forever.
So to prevent stale messages from lingering, and for volatile stores to
provide a hook for cleaning up when the application shuts down, the
<interfacename>MessageGroupStore</interfacename> allows the user to register
callbacks to apply to its <interfacename>MessageGroups</interfacename> when they
expire. The interface is very straighforward:</para>
<programlisting><![CDATA[public interface MessageGroupCallback {
@@ -673,7 +669,7 @@
so it can manage the persistent state (e.g. by removing the group from the
store entirely).</para>
<para>The MessageGroupStore maintains a list of these callbacks which it
<para>The <interfacename>MessageGroupStore</interfacename> maintains a list of these callbacks which it
applies when asked to all messages whose timestamp is earlier than a time
supplied as a parameter:</para>
@@ -682,7 +678,7 @@
int expireMessageGroups(long timeout);
}]]></programlisting>
<para>The expireMessageGroups method can be called with a timeout value:
<para>The <code>expireMessageGroups</code> method can be called with a timeout value:
any message older than the current time minus this value will be expired,
and have the callbacks applied. Thus it is the user of the store that
defines what is meant by message group "expiry".</para>
@@ -700,7 +696,7 @@
<task:scheduled ref="reaper" method="run" fixed-rate="10000"/>
</task:scheduled-tasks>]]></programlisting>
<para>The reaper is a Runnable, and all that is happening is that the
<para>The reaper is a <interfacename>Runnable</interfacename>, and all that is happening is that the
message group store's expire method is being called in the sample above
once every 10 seconds. In addition to the reaper, the expiry callbacks are
invoked when the application shuts down via a lifecycle callback in the

View File

@@ -13,11 +13,11 @@
progression. For example, it is fairly common to provide a Transformer before other components. Similarly, when
providing a <emphasis>Filter</emphasis> before some other component in a chain, you are essentially creating a
<ulink url="http://www.eaipatterns.com/MessageSelector.html">Selective Consumer</ulink>. In either case, the
chain only requires a single input-channel and a single output-channel as opposed to the configuration of
channels for each individual component.
chain only requires a single <code>input-channel</code> and a single <code>output-channel</code> eliminating
the need to define channels for each individual component.
<tip>
Spring Integration's <emphasis>Filter</emphasis> provides a boolean property 'throwExceptionOnRejection'. When
providing multiple Selective Consumers on the same point-to-point channel with different acceptance criteria,
Spring Integration's <interfacename>Filter</interfacename> provides a boolean property <methodname>throwExceptionOnRejection</methodname>.
When providing multiple Selective Consumers on the same point-to-point channel with different acceptance criteria,
this value should be set to 'true' (the default is false) so that the dispatcher will know that the Message was
rejected and as a result will attempt to pass the Message on to other subscribers. If the Exception were not
thrown, then it would appear to the dispatcher as if the Message had been passed on successfully even though
@@ -36,7 +36,7 @@
handler only needs an output channel if the outputChannel on the MessageHandlerChain is set.
<note>
<para>
As with other endpoints, the output-channel is optional. If there is a reply Message at the end of the
As with other endpoints, the <code>output-channel</code> is optional. If there is a reply Message at the end of the
chain, the output-channel takes precedence, but if not available, the chain handler will check for a
reply channel header on the inbound Message.
</para>
@@ -52,8 +52,8 @@
<section id="chain-namespace">
<title>Configuring Chain</title>
<para>
The &lt;chain&gt; element provides an 'input-channel' attribute, and if the last element in the chain is capable
of producing reply messages (optional), it also supports an 'output-channel' attribute. The sub-elements are then
The &lt;chain&gt; element provides an <code>input-channel</code> attribute, and if the last element in the chain is capable
of producing reply messages (optional), it also supports an <code>output-channel</code> attribute. The sub-elements are then
filters, transformers, splitters, and service-activators. The last element may also be a router.
<programlisting language="xml"><![CDATA[ <chain input-channel="input" output-channel="output">
<filter ref="someSelector" throw-exception-on-rejection="true"/>
@@ -65,15 +65,15 @@
</para>
<para>
The &lt;header-enricher&gt; element used in the above example will set a message header with name "foo" and
value "bar" on the message. A header enricher is a specialization of Transformer that touches only header
values. You could obtain the same result by implementing a MessageHandler that did the header modifications
value "bar" on the message. A header enricher is a specialization of <interfacename>Transformer</interfacename>
that touches only header values. You could obtain the same result by implementing a MessageHandler that did the header modifications
and wiring that as a bean.
</para>
<para>
Some time you need to make a nested call to another chain from within the chain and then come
Sometimes you need to make a nested call to another chain from within the chain and then come
back and continue execution within the original chain.
To accomplish this you can utilize Messaging Gateway by including light-configuration via &lt;gateway&gt; element.
To accomplish this you can utilize Messaging Gateway by including a light configured &lt;gateway&gt; element.
For example:
<programlisting language="xml"><![CDATA[ <si:chain id="main-chain" input-channel="inputA" output-channel="inputB">
<si:header-enricher>
@@ -105,9 +105,10 @@
In the above example the <emphasis>nested-chain-a</emphasis> will be called at the end of <emphasis>main-chain</emphasis> processing by the 'gateway' element
configured there. While in <emphasis>nested-chain-a</emphasis> a call to a <emphasis>nested-chain-b</emphasis> will be made after header enrichment and then it will
come back to finish execution in <emphasis>nested-chain-b</emphasis> finally getting back to the <emphasis>main-chain</emphasis>.
When light version of &lt;gateway&gt; element is defined in the chain SI will construct an instance <classname>SimpleMessagingGateway</classname>
(no need to provide 'service-interface' configuration) which will take the message in its current state and will place it on the channel defined via 'request-channel' attribute.
Upon processing <classname>Message</classname> will be returned to the gateway and continue its journey within the current chain.
When the light version of &lt;gateway&gt; element is defined in the chain SI will construct an instance <classname>SimpleMessagingGateway</classname>
(no need to provide a <code>service-interface</code> attribute) which will take the message in its current state and will place it on the channel defined via
the <code>request-channel</code> attribute.
Upon processing <interfacename>Message</interfacename> will be returned to the gateway and continue its journey within the current chain.
</para>
</section>

View File

@@ -373,12 +373,12 @@ public Message<?> receive(final PollableChannel<?> channel) { ... }]]></programl
<section id="channel-configuration">
<title>Configuring Message Channels</title>
<para>
To create a Message Channel instance, you can use the 'channel' element:
To create a Message Channel instance, you can use the &lt;channel/&gt; element:
<programlisting language="xml">&lt;channel id="exampleChannel"/&gt;</programlisting>
</para>
<para>
The default channel type is <emphasis>Point to Point</emphasis>. To create a
<emphasis>Publish Subscribe</emphasis> channel, use the "publish-subscribe-channel" element:
<emphasis>Publish Subscribe</emphasis> channel, use the &lt;publish-subscribe-channel/&gt; element:
<programlisting language="xml">&lt;publish-subscribe-channel id="exampleChannel"/&gt;</programlisting>
</para>
<para>
@@ -393,11 +393,11 @@ public Message<?> receive(final PollableChannel<?> channel) { ... }]]></programl
<programlisting language="xml"><![CDATA[<channel id="stringOrNumberChannel" datatype="java.lang.String,java.lang.Number"/>]]></programlisting>
</para>
<para>
When using the "channel" element without any sub-elements, it will create a <classname>DirectChannel</classname>
When using the &lt;channel/&gt; element without any sub-elements, it will create a <classname>DirectChannel</classname>
instance (a <interfacename>SubscribableChannel</interfacename>).
</para>
<para>
However, you can alternatively provide a variety of "queue" sub-elements to create any of
However, you can alternatively provide a variety of &lt;queue/&gt; sub-elements to create any of
the pollable channel types (as described in
<xref linkend="channel-implementations"/>). Examples of each are shown below.
</para>
@@ -425,7 +425,7 @@ public Message<?> receive(final PollableChannel<?> channel) { ... }]]></programl
<section id="channel-configuration-queuechannel">
<title>QueueChannel Configuration</title>
<para>
To create a <classname>QueueChannel</classname>, use the "queue" sub-element.
To create a <classname>QueueChannel</classname>, use the &lt;queue/&gt; sub-element.
You may specify the channel's capacity:
<programlisting language="xml">&lt;channel id="queueChannel"&gt;
&lt;queue capacity="25"/&gt;
@@ -440,8 +440,8 @@ public Message<?> receive(final PollableChannel<?> channel) { ... }]]></programl
<section id="channel-configuration-pubsubchannel">
<title>PublishSubscribeChannel Configuration</title>
<para>
To create a <classname>PublishSubscribeChannel</classname>, use the "publish-subscribe-channel" element.
When using this element, you can also specify the "task-executor" used for publishing
To create a <classname>PublishSubscribeChannel</classname>, use the &lt;publish-subscribe-channel/&gt; element.
When using this element, you can also specify the <code>task-executor</code> used for publishing
Messages (if none is specified it simply publishes in the sender's thread):
<programlisting language="xml">&lt;publish-subscribe-channel id="pubsubChannel" task-executor="someExecutor"/&gt;</programlisting>
If you are providing a <emphasis>Resequencer</emphasis> or <emphasis>Aggregator</emphasis> downstream
@@ -452,7 +452,7 @@ public Message<?> receive(final PollableChannel<?> channel) { ... }]]></programl
have sequence-number header values ranging from 1 to 5.
<programlisting language="xml">&lt;publish-subscribe-channel id="pubsubChannel" apply-sequence="true"/&gt;</programlisting>
<note>
The 'apply-sequence' value is <code>false</code> by default so that a Publish Subscribe Channel
The <code>apply-sequence</code> value is <code>false</code> by default so that a Publish Subscribe Channel
can send the exact same Message instances to multiple outbound channels. Since Spring Integration
enforces immutability of the payload and header references, the channel creates new Message
instances with the same payload reference but different header values when the flag is set to
@@ -464,7 +464,7 @@ public Message<?> receive(final PollableChannel<?> channel) { ... }]]></programl
<title>ExecutorChannel</title>
<para>
To create an <classname>ExecutorChannel</classname>, add the &lt;dispatcher&gt; sub-element along
with a 'task-executor' attribute. Its value can reference any <interfacename>TaskExecutor</interfacename>
with a <code>task-executor</code> attribute. Its value can reference any <interfacename>TaskExecutor</interfacename>
within the context. For example, this enables configuration of a thread-pool for dispatching messages
to subscribed handlers. As mentioned above, this does break the "single-threaded" execution context
between sender and receiver so that any active transaction context will not be shared by the invocation
@@ -475,7 +475,7 @@ public Message<?> receive(final PollableChannel<?> channel) { ... }]]></programl
</channel>]]></programlisting>
</para>
<note>
The "load-balancer" and "failover" options are also both available on the dispatcher sub-element
The <code>load-balancer</code> and <code>failover</code> options are also both available on the &lt;dispatcher/&gt; sub-element
as described above in <xref linkend="channel-configuration-directchannel"/>. The same defaults
apply as well. So, the channel will have a round-robin load-balancing strategy with failover
enabled unless explicit configuration is provided for one or both of those attributes.
@@ -487,14 +487,14 @@ public Message<?> receive(final PollableChannel<?> channel) { ... }]]></programl
<section id="channel-configuration-prioritychannel">
<title>PriorityChannel Configuration</title>
<para>
To create a <classname>PriorityChannel</classname>, use the "priority-queue" sub-element:
To create a <classname>PriorityChannel</classname>, use the &lt;priority-queue/&gt; sub-element:
<programlisting language="xml"><![CDATA[<channel id="priorityChannel">
<priority-queue capacity="20"/>
</channel>]]></programlisting>
By default, the channel will consult the <classname>MessagePriority</classname> header of the
message. However, a custom <interfacename>Comparator</interfacename> reference may be
provided instead. Also, note that the <classname>PriorityChannel</classname> (like the other types)
does support the "datatype" attribute. As with the QueueChannel, it also supports a "capacity" attribute.
does support the <code>datatype</code> attribute. As with the QueueChannel, it also supports a <code>capacity</code> attribute.
The following example demonstrates all of these:
<programlisting language="xml"><![CDATA[<channel id="priorityChannel" datatype="example.Widget">
<priority-queue comparator="widgetComparator"
@@ -528,8 +528,8 @@ public Message<?> receive(final PollableChannel<?> channel) { ... }]]></programl
<title>Channel Interceptor Configuration</title>
<para>
Message channels may also have interceptors as described in <xref linkend="channel-interceptors"/>. The
&lt;interceptors&gt; sub-element can be added within &lt;channel&gt; (or the more specific element
types). Provide the "ref" attribute to reference any Spring-managed object that implements the
&lt;interceptors/&gt; sub-element can be added within &lt;channel/&gt; (or the more specific element
types). Provide the <code>ref</code> attribute to reference any Spring-managed object that implements the
<interfacename>ChannelInterceptor</interfacename> interface:
<programlisting language="xml"><![CDATA[<channel id="exampleChannel">
]]><emphasis><![CDATA[<interceptors>
@@ -544,11 +544,11 @@ public Message<?> receive(final PollableChannel<?> channel) { ... }]]></programl
<section id="global-channel-configuration-interceptors">
<title>Global Channel Interceptor Configuration</title>
<para>
Channel Interceptors allow you for a clean and concise way of applying cross-cutting behavior per individual channel.
But what if the same behavior should be applied on multiple channels, configuring the same set of interceptors for
each channel <emphasis>would not be</emphasis> the most efficient way. The better way would be to configure interceptors globally and apply
them on multiple channels in one shot. Spring Integration provides capabilities to configure <emphasis>Global Interceptors</emphasis>
and apply them on multiple channels.
Channel Interceptors provide a clean and concise way of applying cross-cutting behavior per individual channel.
If the same behavior should be applied on multiple channels, configuring the same set of interceptors for
each channel <emphasis>would not be</emphasis> the most efficient way. To avoid repeated configuration, use global interceptors and apply
them to multiple channels. Spring Integration provides <emphasis>Global Interceptors</emphasis> to accomplish this.
Look at the example below:
<programlisting language="xml"><![CDATA[<int:channel-interceptor pattern="input*, bar*, foo" order="3">
<bean class="foo.barSampleInterceptor"/>
@@ -557,8 +557,8 @@ public Message<?> receive(final PollableChannel<?> channel) { ... }]]></programl
<programlisting language="xml"><![CDATA[<int:channel-interceptor ref="myInterceptor" pattern="input*, bar*, foo" order="3"/>
<bean id="myInterceptor" class="foo.barSampleInterceptor"/>]]></programlisting>
&lt;channel-interceptor&gt; element allows you to define a global interceptor which will be applied on all
channels that match patterns defined via <emphasis>pattern</emphasis> attribute. In the above case the global interceptor will be applied on
&lt;channel-interceptor/&gt; element allows you to define a global interceptor which will be applied on all
channels that match patterns defined via <code>pattern</code> attribute. In the above case the global interceptor will be applied on
'foo' channel and all other channels that begin with 'bar' and 'input'.
The <emphasis>order</emphasis> attribute allows you to manage the place where this interceptor will be injected.
For example, channel 'inputChannel' could have individual interceptors configured locally (see below):
@@ -567,18 +567,19 @@ public Message<?> receive(final PollableChannel<?> channel) { ... }]]></programl
<int:wire-tap channel="logger"/> 
</int:interceptors>
</int:channel>]]></programlisting>
The reasonable question would be how global interceptor will be injected in relation to other interceptors
configured locally or through other global interceptor definitions? Current implementation provides
a very simple and clever mechanism of handling this. Positive number in the <emphasis>order</emphasis> attribute will ensure interceptor injection
after existing interceptors and negative number will ensure that such interceptors injected before.
This means that in the above example global interceptor will be injected <emphasis>AFTER</emphasis> (since its order is greater then 0)
'wire-tap' interceptor configured locally. If there was another global interceptor with matching <emphasis>pattern</emphasis> their
order would be determined based on who's got the higher or lower value in <emphasis>order</emphasis> attribute.
To inject global interceptor <emphasis>BEFORE</emphasis> the existing interceptors use negative value for the <emphasis>order</emphasis> attribute.
A reasonable question is how will a global interceptor be injected in relation to other interceptors
configured locally or through other global interceptor definitions? The current implementation provides
a very simple and clever mechanism for defining the order of interceptor execution.
A positive number in the <code>order</code> attribute will ensure interceptor injection
after any existing interceptors and negative number will ensure that interceptor is injected before.
This means that in the above example global interceptor will be injected <emphasis>AFTER</emphasis> (since its order is greater then 0)
the 'wire-tap' interceptor configured locally. If there was another global interceptor with matching <code>pattern</code> its
order would be determined by comparing the values of the <code>order</code> attribute.
To inject global interceptor <emphasis>BEFORE</emphasis> the existing interceptors use a negative value for the <code>order</code> attribute.
</para>
<note>
Note that <emphasis>order</emphasis> and <emphasis>pattern</emphasis> attributes are optional. The default value for <emphasis>order</emphasis>
will be 0 and for <emphasis>pattern</emphasis> is '*'
Note that <code>order</code> and <code>pattern</code> attributes are optional. The default value for <code>order</code>
will be 0 and for <code>pattern</code> is '*'
</note>
</section>
@@ -586,8 +587,8 @@ public Message<?> receive(final PollableChannel<?> channel) { ... }]]></programl
<title>Wire Tap</title>
<para>
As mentioned above, Spring Integration provides a simple <emphasis>Wire Tap</emphasis> interceptor out of
the box. You can configure a <emphasis>Wire Tap</emphasis> on any channel within an 'interceptors' element.
This is especially useful for debugging, and can be used in conjunction with Spring Integration's logging
the box. You can configure a <emphasis>Wire Tap</emphasis> on any channel within an &lt;interceptors/&gt; element.
This is especially useful for debugging, and can be used in conjunction with Spring Integration's logging
Channel Adapter as follows: <programlisting language="xml"><![CDATA[ <channel id="in">
<interceptors>
<wire-tap channel="logger"/>
@@ -596,9 +597,9 @@ public Message<?> receive(final PollableChannel<?> channel) { ... }]]></programl
<logging-channel-adapter id="logger" level="DEBUG"/>]]></programlisting>
<tip>
The 'logging-channel-adapter' also accepts a boolean attribute: <emphasis>'log-full-message'</emphasis>.
That is <emphasis>false</emphasis> by default so that only the payload is logged. Setting that to
<emphasis>true</emphasis> enables logging of all headers in addition to the payload.
The 'logging-channel-adapter' also accepts a boolean attribute: <code>log-full-message</code>.
That is <code>false</code> by default so that only the payload is logged. Setting that to
<code>true</code> enables logging of all headers in addition to the payload.
</tip>
</para>

View File

@@ -7,17 +7,17 @@
<title>Introduction</title>
<para>
Message Filters are used to decide whether a Message should be passed along or dropped based on some criteria
such as a Message Header value or even content within the Message itself. Therefore, a Message Filter is similar
such as a Message Header value or Message content itself. Therefore, a Message Filter is similar
to a router, except that for each Message received from the filter's input channel, that same Message may or may
not be sent to the filter's output channel. Unlike the router, it makes no decision regarding
<emphasis>which</emphasis> Message Channel to send to but only decides <emphasis>whether</emphasis> to send.
<emphasis>which</emphasis> Message Channel to send the Message to but only decides <emphasis>whether</emphasis> to send.
<note>
As you will see momentarily, the Filter does also support a discard channel, so in certain cases it
As you will see momentarily, the Filter also supports a discard channel, so in certain cases it
<emphasis>can</emphasis> play the role of a very simple router (or "switch") based on a boolean condition.
</note>
</para>
<para>
In Spring Integration, a Message Filter may be configured as a Message Endpoint that delegates to some
In Spring Integration, a Message Filter may be configured as a Message Endpoint that delegates to an
implementation of the <interfacename>MessageSelector</interfacename> interface. That interface is itself quite
simple: <programlisting language="java"><![CDATA[ public interface MessageSelector {
@@ -27,23 +27,24 @@
The <classname>MessageFilter</classname> constructor accepts a selector instance:
<programlisting language="java"><![CDATA[ MessageFilter filter = new MessageFilter(someSelector);]]></programlisting>
</para>
In combination with the namespace and SpEL very powerful filters can be configured with very little java code.
In combination with the namespace and SpEL, very powerful filters can be configured with very little java code.
</section>
<section id="filter-namespace">
<title>Configuring Filter</title>
<para>
The &lt;filter&gt; element is used to create a Message-selecting endpoint. In addition to "input-channel"
and "output-channel" attributes, it requires a "ref". The "ref" may point to a MessageSelector implementation:
The &lt;filter&gt; element is used to create a Message-selecting endpoint. In addition to "<code>input-channel</code>
and <code>output-channel</code> attributes, it requires a <code>ref</code>. The <code>ref</code> may point to a
<interfacename>MessageSelector</interfacename> implementation:
<programlisting language="xml"><![CDATA[ <filter input-channel="input" ref="selector" output-channel="output"/>
<bean id="selector" class="example.MessageSelectorImpl"/>]]></programlisting>
</para>
<para>
Alternatively, the "method" attribute can be added at which point the "ref" may refer to any object.
Alternatively, the <code>method</code> attribute can be added at which point the <code>ref</code> may refer to any object.
The referenced method may expect either the <interfacename>Message</interfacename> type or the payload type of
inbound Messages. The return value of the method must be a boolean value. Any time the method returns 'true',
the Message <emphasis>will</emphasis> be passed along to the output-channel.
inbound Messages. The method must return a boolean value. If the method returns 'true',
the Message <emphasis>will</emphasis> be sent to the output-channel.
<programlisting language="xml"><![CDATA[ <filter input-channel="input" output-channel="output"
ref="exampleObject" method="someBooleanReturningMethod"/>
@@ -51,25 +52,25 @@
</para>
<para>
If the selector or adapted POJO method returns <code>false</code>, there are a few settings that control the
fate of the rejected Message. By default (if configured like the example above), the rejected Messages will
be silently dropped. If rejection should instead indicate an error condition, then set the
'throw-exception-on-rejection' flag to <code>true</code>:
handling of the rejected Message. By default (if configured like the example above), rejected Messages will
be silently dropped. If rejection should instead result in an error condition, then set the
<code>throw-exception-on-rejection</code> attribute to <code>true</code>:
<programlisting language="xml"><![CDATA[ <filter input-channel="input" ref="selector"
output-channel="output" throw-exception-on-rejection="true"/> ]]></programlisting>
If you want the rejected messages to go to a specific channel, provide that reference as the 'discard-channel':
If you want rejected messages to be routed to a specific channel, provide that reference as the <code>discard-channel</code>:
<programlisting language="xml"><![CDATA[ <filter input-channel="input" ref="selector"
output-channel="output" discard-channel="rejectedMessages"/> ]]></programlisting>
</para>
<note>
A common usage for Message Filters is in conjunction with a Publish Subscribe Channel. Many filter endpoints may
be subscribed to the same channel, and they decide whether or not to pass the Message for the next endpoint which
Message Filters are commonly used in conjunction with a Publish Subscribe Channel. Many filter endpoints may
be subscribed to the same channel, and they decide whether or not to pass the Message to the next endpoint which
could be any of the supported types (e.g. Service Activator). This provides a <emphasis>reactive</emphasis>
alternative to the more <emphasis>proactive</emphasis> approach of using a Message Router with a single
Point-to-Point input channel and multiple output channels.
</note>
<para>
Using a "ref" attribute is generally recommended if the custom filter implementation can be reused in other
<code>&lt;filter&gt;</code> definitions. However if the custom filter implementation should be scoped to a
Using a <code>ref</code> attribute is generally recommended if the custom filter implementation is referenced in other
<code>&lt;filter&gt;</code> definitions. However if the custom filter implementation is scoped to a
single <code>&lt;filter&gt;</code> element, provide an inner bean definition:
<programlisting language="xml"><![CDATA[<filter method="someMethod" input-channel="inChannel" output-channel="outChannel">
<beans:bean class="org.foo.MyCustomFilter"/>
@@ -77,15 +78,15 @@
</para>
<note>
<para>
Using both the "ref" attribute and an inner handler definition in the same <code>&lt;filter&gt;</code> configuration
is not allowed, as it creates an ambiguous condition, and it will therefore result in an Exception being thrown.
Using both the <code>ref</code> attribute and an inner handler definition in the same <code>&lt;filter&gt;</code> configuration
is not allowed, as it creates an ambiguous condition, and an Exception will be thrown.
</para>
</note>
<para>
With the introduction of SpEL Spring Integration has added the <code>expression</code> attribute to the filter
With the introduction of SpEL, Spring Integration added the <code>expression</code> attribute to the filter
element. It can be used to avoid Java entirely for simple filters.
<programlisting language="xml">
<![CDATA[ <filter input-channel="input" expression="payload.equals(nonsense)"/>]]>
<![CDATA[<filter input-channel="input" expression="payload.equals(nonsense)"/>]]>
</programlisting>
The string passed as the expression attribute will be evaluated as a SpEL expression in the context of the message.
If it is needed to include the result of an expression in the scope of the application context you can use the
@@ -94,7 +95,7 @@
SpEL reference documentation
</ulink>.
<programlisting language="xml">
<![CDATA[ <filter input-channel="input" expression="payload.matches(#{filterPatterns.nonsensePattern})"/>]]>
<![CDATA[<filter input-channel="input" expression="payload.matches(#{filterPatterns.nonsensePattern})"/>]]>
</programlisting>
If the Expression itself needs to be dynamic, then an 'expression' sub-element may be used. That provides a level of
indirection for resolving the Expression by its key from an ExpressionSource. That is a strategy interface that you
@@ -102,9 +103,10 @@
a "resource bundle" and can check for modifications after a given number of seconds. All of this is demonstrated in
the following configuration sample where the Expression could be reloaded within one minute if the underlying file
had been modified. If the ExpressionSource bean is named "expressionSource", then it is not necessary to provide the
"source" attribute on the &lt;expression&gt; element, but in this case it's shown for completeness.
<code>source</code> attribute on the &lt;expression&gt; element, but in this case it's shown for completeness.
<programlisting language="xml">
<![CDATA[ <filter input-channel="input" output-channel="output">
<![CDATA[
<filter input-channel="input" output-channel="output">
<expression key="filterPatterns.example" source="myExpressions"/>
</filter>
@@ -121,7 +123,7 @@
<![CDATA[ filterPatterns.example=payload > 100
]]></programlisting>
<note>All of the examples that use "expression" as an attribute or sub-element can also be applied within
<note>All of the examples that use <code>expression</code> as an attribute or sub-element can also be applied within
transformer, router, splitter, service-activator, and header-enricher elements. Of course, the semantics/role
of the given component type would affect the interpretation of the evaluation result in the same way that the
return or a method-invocation would be interpreted. For example, an expression can return Strings that are

View File

@@ -53,6 +53,10 @@
<firstname>Josh</firstname>
<surname>Long</surname>
</author>
<author>
<firstname>David</firstname>
<surname>Turanski</surname>
</author>
</authorgroup>
<legalnotice><para>© SpringSource Inc., 2010</para></legalnotice>

View File

@@ -59,12 +59,12 @@
</callout>
<callout arearefs="resxml3-co" id="resxml3">
<para>The channel where the resequencer will send the reordered
<para>The channel to which the resequencer will send the reordered
messages. <emphasis>Optional</emphasis>.</para>
</callout>
<callout arearefs="resxml4-co" id="resxml4">
<para>The channel where the resequencer will send the messages that
<para>The channel to which the resequencer will send the messages that
timed out (if <code>send-partial-result-on-timeout</code> is
<emphasis>false)</emphasis>. <emphasis>Optional</emphasis>.</para>
</callout>
@@ -76,9 +76,9 @@
available, or only after the whole message group arrives.
<emphasis>Optional (false by default)</emphasis>.</para>
If this flag is not specified (so a complete sequence is defined by the sequence headers) then it can make sense to provide a custom
If this flag is not specified (so a complete sequence is defined by the sequence headers) then it may make sense to provide a custom
<code>Comparator</code>
<interfacename>Comparator</interfacename>
to be used to order the messages when sending (use the XML attribute
@@ -94,7 +94,7 @@
(also a reference to another bean definition, either a POJO or a
<code>ReleaseStrategy</code>
<interfacename>ReleaseStrategy</interfacename>
).
</callout>

View File

@@ -9,7 +9,7 @@
Since content-based routing often requires some domain-specific logic, most use-cases will require
Spring Integration's options for delegating to POJOs using the XML namespace support and/or Annotations.
Both of these are discussed below, but first we present a couple implementations that are available
out-of-the-box since they fulfill generic, but common, requirements.
out-of-the-box since they fulfill common requirements.
</para>
<section id="router-implementations-payloadtyperouter">
<title>PayloadTypeRouter</title>
@@ -29,7 +29,7 @@
Configuration of <classname>PayloadTypeRouter</classname> is also supported via the namespace provided by Spring Integration (see <xref linkend="configuration-namespace"/>),
which essentially simplifies configuration by combining <code>&lt;router/&gt;</code> configuration and its corresponding implementation defined using <code>&lt;bean/&gt;</code> element
into a single and more concise configuration element.
The example below demonstrates <classname>PayloadTypeRouter</classname> configuration which is equivalent to the one above using Spring Integration's namespace support:
The example below demonstrates a <classname>PayloadTypeRouter</classname> configuration which is equivalent to the one above using Spring Integration's namespace support:
</para>
<para>
<programlisting language="xml"><![CDATA[<payload-type-router input-channel="routingChannel">
@@ -65,14 +65,12 @@
</header-value-router>]]></programlisting>
</para>
<para>
Obviously during the resolution process this router may encounter resolution failures, thus resulting in
exception. If you want to suppress such resolution failures and send all messages to the
default output channel (i.e., identified with <code>default-output-channel</code> attribute) you may do so by setting
<code>ignore-channel-name-resolution-failures</code> to true. This particular attribute may sound confusing when compared with
the <code>default-output-channel</code>. So just to clarify, the <code>default-output-channel</code> handles messages where routing
information can not be determined. However, in the above scenario route has determined successfully but the
resolution of that route failed and that is why we need an extra attribute to let Spring Integration know that it is
OK to suppress resolution failures and treat such route as undetermined thus routing messages to the <code>default-output-channel</code>
During the resolution process this router may encounter channel resolution failures, causing an
exception. If you want to suppress such exceptions and send unresolved messages to the default output channel
(identified with the <code>default-output-channel</code> attribute) set <code>ignore-channel-name-resolution-failures</code> to true.
Normally, messages for which the header value is not explicitly mapped to a channel will be sent to the <code>default-output-channel</code>.
However, in cases where the header value is mapped to a channel name but the channel cannot be resolved, setting <code>ignore-channel-name-resolution-failures</code>
attribute to true will result in routing such messages to the <code>default-output-channel</code>.
</para>
<para> <emphasis>2. Configuration where mapping of header values to channel names
@@ -82,9 +80,9 @@
</para>
<note>
The two router implementations shown above share some common properties, such as "defaultOutputChannel" and "resolutionRequired".
If "resolutionRequired" is set to "true", and the router is unable to determine a target channel (e.g. there is
no matching payload for a PayloadTypeRouter and no "defaultOutputChannel" has been specified), then an Exception
The two router implementations shown above share some common attributes, such as <code>default-output-channel</code> and <code>resolution-required</code>.
If <code>resolution-required</code> is set to true, and the router is unable to determine a target channel (e.g. there is
no matching payload for a PayloadTypeRouter and no <code>default-output-channel</code> has been specified), then an Exception
will be thrown.
</note>
</section>
@@ -94,7 +92,7 @@
<section id="router-implementations-recipientlistrouter">
<title>RecipientListRouter</title>
<para>
A <classname>RecipientListRouter</classname> will send each received Message to a statically-defined
A <classname>RecipientListRouter</classname> will send each received Message to a statically defined
list of Message Channels:
<programlisting language="xml"><![CDATA[<bean id="recipientListRouter" class="org.springframework.integration.router.RecipientListRouter">
<property name="channels">
@@ -108,8 +106,8 @@
</para>
</section>
<para>
Configuration for <classname>RecipientListRouter</classname> is also supported via namespace support provided by Spring Integration (see <xref linkend="configuration-namespace"/>).
The example below demonstrates namespace-based configuration of <classname>RecipientListRouter</classname> and all the supported attributes using Spring Integration namespace support:
Spring Integration also provides namespace support for <classname>RecipientListRouter</classname> configuration (see <xref linkend="configuration-namespace"/>)
as the example below demonstrates.
</para>
<para>
<programlisting language="xml"><![CDATA[<recipient-list-router id="customRouter" input-channel="routingChannel"
@@ -121,20 +119,20 @@
</recipient-list-router>]]></programlisting>
</para>
<note>
The 'apply-sequence' flag here has the same affect as it does for a publish-subscribe-channel,
and like publish-subscribe-channel it is disabled by default on the recipient-list-router. Refer to
The 'apply-sequence' flag here has the same effect as it does for a publish-subscribe-channel,
and like publish-subscribe-channel, it is disabled by default on the recipient-list-router. Refer to
<xref linkend="channel-configuration-pubsubchannel"/> for more information.
</note>
<para>
Another convenient option to configure Recipient List Router is to use Spring Expression Language (SpEL) support
Another convenient option to configure <classname>RecipientListRouter</classname> is to use Spring Expression Language (SpEL) support
<programlisting language="xml"><![CDATA[<int:recipient-list-router id="customRouter" input-channel="routingChannel">
<int:recipient channel="channel1" selector-expression="payload.equals('foo')"/>
<int:recipient channel="channel2" selector-expression="headers.contains('bar')"/>
</int:recipient-list-router>]]></programlisting>
In the above configuration a SpEL expression identified by <code>selector-expression</code> attribute will be evaluated to determine if this recipient
In the above configuration a SpEL expression identified by the <code>selector-expression</code> attribute will be evaluated to determine if this recipient
should be included in the recipient list for a given input Message. The evaluation result of the expression must be a boolean. If this
attribute is not defined, the channel will always be among the list of recipients.
</para>
@@ -146,9 +144,9 @@
<section>
<title>Configuring Router with XML</title>
<para>
The "router" element provides a simple way to connect a router to an input channel, and also accepts the
optional default output channel. The "ref" may provide the bean name of a custom Router implementation
(extending AbstractMessageRouter):
The "router" element provides a simple way to connect a router to an input channel and also accepts the
optional <code>default-output-channel</code> attribute. The <code>ref</code> attribute references the bean name of a custom Router implementation
(extending <classname>AbstractMessageRouter</classname>):
<programlisting language="xml"><![CDATA[<router ref="payloadTypeRouter" input-channel="input1" default-output-channel="defaultOutput1"/>
<router ref="recipientListRouter" input-channel="input2" default-output-channel="defaultOutput2"/>
@@ -157,31 +155,31 @@
<beans:bean id="customRouterBean class="org.foo.MyCustomRouter"/>]]></programlisting>
Alternatively, the "ref" may point to a simple Object that contains the @Router annotation (see below), or the
"ref" may be combined with an explicit "method" name. When specifying a "method", the same behavior applies as
Alternatively, <code>ref</code> may point to a simple POJO that contains the @Router annotation (see below), or the
<code>ref</code> may be combined with an explicit <code>method</code> name. Specifying a <code>method</code> applies the same behavior
described in the @Router annotation section below.
<programlisting language="xml"><![CDATA[<router input-channel="input" ref="somePojo" method="someMethod"/>]]></programlisting>
Using a "ref" attribute is generally recommended if the custom router implementation can be reused in other
Using a <code>ref</code> attribute is generally recommended if the custom router implementation is referenced in other
<code>&lt;router&gt;</code> definitions. However if the custom router implementation should be scoped to a
concrete definition of the <code>&lt;router&gt;</code>, you can provide an inner bean definition:
single definition of the <code>&lt;router&gt;</code>, you may provide an inner bean definition:
<programlisting language="xml"><![CDATA[<router method="someMethod" input-channel="input3" default-output-channel="defaultOutput3">
<beans:bean class="org.foo.MyCustomRouter"/>
</router>]]></programlisting>
</para>
<note>
<para>
Using both the "ref" attribute and an inner handler definition in the same <code>&lt;router&gt;</code> configuration
is not allowed, as it creates an ambiguous condition and will result in an Exception being thrown.
Using both the <code>ref</code> attribute and an inner handler definition in the same <code>&lt;router&gt;</code> configuration
is not allowed, as it creates an ambiguous condition, and an Exception will be thrown.
</para>
</note>
<para>
<emphasis>Routers and Spring Expression Language (SpEL)</emphasis>
</para>
<para>
Some times the routing logic may be simple and writing a separate class for it and configuring it as a bean may seem
like an overkill. Since Spring Integration 2.0 we offer an alternative where you can now use SpEL
(http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html)
to implement simple computations that otherwise were implemented in a custom POJO router.
Sometimes the routing logic may be simple and writing a separate class for it and configuring it as a bean may seem
like overkill. Since Spring Integration 2.0 we offer an alternative where you can now use
<ulink url="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.htm">SpEL</ulink>
to implement simple computations that previously required a custom POJO router.
<programlisting language="xml"><![CDATA[<int:router input-channel="inChannel" expression="payload + 'Channel'"/>]]></programlisting>
In the above configuration the result channel will be computed by the SpEL expression which simply concatenates the value
@@ -189,28 +187,28 @@
</para>
<para>
Another value of SpEL when it comes to configuring routers is that expression can actually return a <classname>Collection</classname>,
thus making every <code>&lt;router&gt;</code> a <emphasis>Recipient List Router</emphasis>. Whenever expression returns
multiple channel values Message will be forwarded to all such channels.
Another value of SpEL for configuring routers is that an expression can actually return a <classname>Collection</classname>,
effectively making every <code>&lt;router&gt;</code> a <emphasis>Recipient List Router</emphasis>. Whenever the expression returns
multiple channel values the Message will be forwarded to each channel.
<programlisting language="xml"><![CDATA[<int:router input-channel="inChannel" expression="headers.channels"/>]]></programlisting>
In the above configuration lets assume that you have a message header with the name 'channels' and the value being the
List of channel names. Now, message will be sent to all channels in this list.
In the above configuration, if the Message includes a header with the name 'channels' the value of which is a
<classname>List</classname> of channel names then the Message will be sent to each channel in the list.
You ,ay also fine <emphasis>Collection Projection</emphasis> and <emphasis>Collection Selection</emphasis>
expressions usefull to select multiple channels.
See (http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html#d0e12084)
You may also find <emphasis>Collection Projection</emphasis> and <emphasis>Collection Selection</emphasis>
expressions useful to select multiple channels.
See <ulink url="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html#d0e12084">"http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html#d0e12084"</ulink>
</para>
</section>
<section id="router-annotation">
<title>Configuring Router with Annotations</title>
<para>
When using the <interfacename>@Router</interfacename> annotation, the annotated method can return either the
<interfacename>MessageChannel</interfacename> or <classname>String</classname> type. In the case of the latter,
the endpoint will resolve the channel name as it does for the default output. Additionally, the method can return
either a single value or a collection. When a collection is returned, the reply message will be sent to multiple
When using <interfacename>@Router</interfacename> to annotate a method, the method may return either a
<interfacename>MessageChannel</interfacename> or <classname>String</classname> type. In the latter case,
the endpoint will resolve the channel name as it does for the default output channel. Additionally, the method may return
either a single value or a collection. If a collection is returned, the reply message will be sent to multiple
channels. To summarize, the following method signatures are all valid.
<programlisting language="java">@Router
public MessageChannel route(Message message) {...}
@@ -225,10 +223,11 @@ public String route(Foo payload) {...}
public List&lt;String&gt; route(Foo payload) {...}</programlisting>
</para>
<para>
In addition to payload-based routing, a common requirement is to route based on metadata available within the
message header as either a property or attribute. Rather than requiring use of the
<interfacename>Message</interfacename> type as the method parameter, the <interfacename>@Router</interfacename>
annotation may also use the @Header parameter annotation that is documented in <xref linkend="annotations"/>.
In addition to payload-based routing, a Message may be routed based on metadata available within the
message header as either a property or attribute. In this case, a method annotated with <interfacename>@Router</interfacename>
may include a parameter annotated with <interfacename>@Header</interfacename> which is mapped to a header value as illustrated
below and documented in <xref linkend="annotations"/>.
<programlisting language="java">@Router
public List&lt;String&gt; route(@Header("orderStatus") OrderStatus status)</programlisting>
</para>
@@ -244,40 +243,38 @@ public List&lt;String&gt; route(@Header("orderStatus") OrderStatus status)</prog
<section id="dynamic-routers">
<title>Dynamic Routers</title>
<para>
So as you can see, Spring Integration provides quite a few different router configurations for most common
So as you can see, Spring Integration provides quite a few different router configurations for common
<emphasis>content-based routing</emphasis> use cases as well as the option of implementing custom routers as POJOs.
For example; <emphasis>Payload Type Router</emphasis> provides a simple way to configure a router which computes <code>channels</code>
based on the <code>payload type</code> of the incoming Message while <emphasis>Header Value Router</emphasis> provides the
same convenience in configuring a router which computes <code>channels</code> based on evaluating the value
of a particular Message Header. There is also an <emphasis>expression-based</emphasis> (SpEL) routers where the <code>channel</code>
is determined based on evaluating an expression which gives these type of routers some dynamic characteristics.
For example <classname>PayloadTypeRouter</classname> provides a simple way to configure a router which computes <code>channels</code>
based on the <code>payload type</code> of the incoming Message while <classname>HeaderValueRouter</classname> provides the
same convenience in configuring a router which computes <code>channels</code> by evaluating the value
of a particular Message Header. There are also <emphasis>expression-based</emphasis> (SpEL) routers where the <code>channel</code>
is determined based on evaluating an expression. Thus, these type of routers exhibit some dynamic characteristics.
</para>
<para>
However these routers share one common attribute - <emphasis>static configuration</emphasis>. Even in the case of
However these routers all require <emphasis>static configuration</emphasis>. Even in the case of
expression-based routers, the expression itself is defined as part of the router configuration which means that
<quote>the same expression operating on the same value will always result in the computation of the same channel</quote>.
This is good in most cases since such routes are well defined and therefore predictable. But there are times when we
need to change router configurations dynamically so message flows could be routed to a different channel.
<emphasis>the same expression operating on the same value will always result in the computation of the same channel</emphasis>.
This is acceptable in most cases since such routes are well defined and therefore predictable. But there are times when we
need to change router configurations dynamically so message flows may be routed to a different channel.
</para>
<para> <emphasis>For example:</emphasis> </para>
<para> <emphasis>Example:</emphasis> </para>
<para>
You might want to bring down some part of your system for maintenance. So, temporarily you want to re-reroute
You might want to bring down some part of your system for maintenance and temporarily re-reroute
messages to a different message flow. Or you may want to introduce more granularity to your message flow by adding another
route to handle a more concrete type of java.lang.Number (in cases of Payload Type Router).
route to handle a more concrete type of java.lang.Number (in the case of <classname>PayloadTypeRouter</classname>).
</para>
<para>
Unfortunately with static router configuration to accomplish this you'd have to bring down your entire application,
Unfortunately with static router configuration to accomplish this you would have to bring down your entire application,
change the configuration of the router (change routes) and bring it back up. This is obviously not the solution.
</para>
<para>
<ulink url="http://www.eaipatterns.com/DynamicRouter.html">
Dynamic Router
</ulink>
pattern describes the mechanisms by which one can change/configure routers dynamically without
bringing down your system or individual routers. 
<para>
The <ulink url="http://www.eaipatterns.com/DynamicRouter.html">Dynamic Router</ulink>
pattern describes the mechanisms by which one can change/configure routers dynamically without
bringing down the system or individual routers. 
</para>
<para>
Before we get into the specifics of how it is accomplished in Spring Integration lets quickly summarize the
Before we get into the specifics of how this is accomplished in Spring Integration let's quickly summarize the
typical flow of the router, which consists of 3 simple steps:
<itemizedlist>
<listitem>
@@ -296,10 +293,10 @@ public List&lt;String&gt; route(@Header("orderStatus") OrderStatus status)</prog
</para>
<para>
There is not much that could be done with regard to router dynamics if Step 1 results in the actual instance of the
<classname>MessageChannel</classname> simply because <classname>MessageChannel</classname> is the <emphasis>final product</emphasis> of any
router's job. However, if Step 1 results in <code>channel identifier</code> that is not and instance of <classname>MessageChannel</classname>,
then there are quite a few possibilities to influence the process of calculating what will be the final instance of the <classname>Message Channel</classname>.
There is not much that can be done with regard to dynamic routing if Step 1 results in the actual instance of the
<classname>MessageChannel</classname> simply because the <classname>MessageChannel</classname> is the <emphasis>final product</emphasis> of any
router's job. However, if Step 1 results in a <code>channel identifier</code> that is not an instance of <classname>MessageChannel</classname>,
then there are quite a few possibilities to influence the process of deriving the <classname>Message Channel</classname>.
Lets look at couple of the examples in the context of the 3 steps mentioned above: 
</para>
<para>
@@ -325,12 +322,12 @@ public List&lt;String&gt; route(@Header("orderStatus") OrderStatus status)</prog
</listitem>
<listitem>
<para><emphasis>Step 3</emphasis> - Resolve <code>channel name</code> to the actual instance of the
<classname>MessageChannel</classname> where using <classname>ChannelResolver</classname> router will obtain a
<classname>MessageChannel</classname> where using <classname>ChannelResolver</classname>, the router will obtain a
reference to a bean (which is hopefully a <classname>MessageChannel</classname>) identified by the result of the
previous step.</para>
</listitem>
</itemizedlist>
In other words each step feeds the next step until thr process completes.
In other words each step feeds the next step until the process completes.
</para>
<para>
<emphasis>Header Value Router</emphasis>
@@ -355,7 +352,7 @@ public List&lt;String&gt; route(@Header("orderStatus") OrderStatus status)</prog
</listitem>
<listitem>
<para><emphasis>Step 3</emphasis> - Resolve <code>channel name</code> to the actual instance of the
<classname>MessageChannel</classname> where using <classname>ChannelResolver</classname> router will obtain a
<classname>MessageChannel</classname> where using <classname>ChannelResolver</classname>, the router will obtain a
reference to a bean (which is hopefully a <classname>MessageChannel</classname>) identified by the result of the
previous step.</para>
</listitem>
@@ -363,10 +360,10 @@ public List&lt;String&gt; route(@Header("orderStatus") OrderStatus status)</prog
</para>
<para>
The above two configurations of two different router types look almost identical.
However if we look at the different configuration of the <classname>HeaderValueRouter</classname> we clearly see that
However if we look at the alternate configuration of the <classname>HeaderValueRouter</classname> we clearly see that
there is no <code>mapping</code> sub element:
<programlisting language="xml"><![CDATA[<header-value-router input-channel="inputChannel" header-name="testHeader">]]></programlisting>
But configuration is still perfectly valid. So the natural question is what about the maping in the Step 2?
But the configuration is still perfectly valid. So the natural question is what about the maping in the Step 2?
</para>
<para>
What this means is that Step 2 is now an optional step. If mapping is not defined then the <code>channel identifier</code>
@@ -382,20 +379,20 @@ public List&lt;String&gt; route(@Header("orderStatus") OrderStatus status)</prog
In the above configuration lets assume that the <code>testHeader</code> value is 'kermit' which is now a <code>channel identifier</code>
(Step 1). Since there is no mapping in this router, resolving this <code>channel identifier</code> to a <code>channel name</code>
(Step 2) is impossible and this <code>channel identifier</code> is now treated as <code>channel name</code>. However what if
there was mapping but for a different value, the end result would still be the same and that is:
there was a mapping but for a different value, the end result would still be the same and that is:
<emphasis>if new value can not be determined through the process of resolving 'channel identifier' to a 'channel name',
such 'channel identifier' becomes 'channel name'</emphasis>
</para>
<para>
So all that is left is for Step 3 to resolve <code>channel name</code> ('kermit') to an actual instance of the
<classname>MessageChannel</classname> identified by this name. That will be done via default
<interface>ChannelResolver</interface> implementation which is <classname>BeanFactoryChannelResolver</classname> which
<classname>MessageChannel</classname> identified by this name. That will be done via a default
<interface>ChannelResolver</interface> implementation which is a <classname>BeanFactoryChannelResolver</classname> which
basically does a bean lookup by the name provided. So now all messages which contain the header/value pair as <code>testHeader=kermit</code>
are going to be routed to a 'kermit' <classname>MessageChannel</classname>.
</para>
<para>
But what if you want to route these messages to 'simpson' channel? Obviously changing static configuration would work,
but would also require bringing your system down. However if you had access to <code>channel identifier</code> map, then you
But what if you want to route these messages to 'simpson' channel? Obviously changing a static configuration will work,
but will also require bringing your system down. However if you had access to the <code>channel identifier</code> map, then you
could just introduce a new mapping where header/value pair is now <code>kermit=simpson</code>, thus allowing Step 2 to treat
'kermit' as <code>channel identifier</code> while resolving it to 'simpson' as <code>channel name</code> .
</para>
@@ -405,11 +402,11 @@ public List&lt;String&gt; route(@Header("orderStatus") OrderStatus status)</prog
will now have a chance to go through Step 2 to be aditionally resolved to the actual <code>channel name</code>.
</para>
<para>
In Spring Integration 2.0 routers hierarchy underwent major refactoring and now any router that is a subclass of the
<classname>AbstractMessageRouter</classname> (all framework defined routers) is a Dynamic Router simply because
In Spring Integration 2.0 the routers hierarchy underwent major refactoring and now any router that is a subclass of the
<classname>AbstractMessageRouter</classname> (which includes all framework defined routers) is a Dynamic Router simply because the
<code>channelIdentiferMap</code> is defined at the <classname>AbstractMessageRouter</classname> with convenient accessors
and modifiers exposed as public methods allowing you to change/add/remove router mapping at runtime via JMX (see section section 29) or
ControlBus (see section section 29.7) functionality. 
and modifiers exposed as public methods allowing you to change/add/remove router mapping at runtime via JMX (see <xref linkend="jmx"/>) or
the ControlBus (see <xref linkend="control-bus"/>) functionality. 
</para>
<para>
@@ -417,28 +414,28 @@ public List&lt;String&gt; route(@Header("orderStatus") OrderStatus status)</prog
</para>
<para>
One of the way to manage the router mappings is through the <ulink url="http://www.eaipatterns.com/ControlBus.html">Control Bus</ulink>
which exposes a Control Channel where you can send
control messages to manage and monitor Spring Integration components which includes routers.
For more information about the Control Bus see section 29.7. Typically you would send a control message asking to invoke a
pattern which exposes a Control Channel where you can send
control messages to manage and monitor Spring Integration components, including routers.
For more information about the Control Bus see <xref linkend="control-bus"/>. Typically you would send a control message asking to invoke a
particular JMX operation on a particular managed component (e.g., router). The two managed operations (methods) that are
specific to changing router resolution process are:
specific to changing router resolution process are:
<itemizedlist>
<listitem>
<para><emphasis>public void setChannelMapping(String channelIdentifier, String channelName)</emphasis> -
<para><code>public void setChannelMapping(String channelIdentifier, String channelName)</code> -
will allow you to add new or modify existing mapping of <code>channel identifier</code> to <code>channel name</code></para>
</listitem>
<listitem>
<para><emphasis>public void removeChannelMapping(String channelIdentifier)</emphasis> -
<para><code>public void removeChannelMapping(String channelIdentifier)</code> -
will allow you to remove a particular channel mapping, thus disconnecting the relationship between
<code>channel identifier</code> and <code>channel name</code> </para>
</listitem>
</itemizedlist>
There are obviously other managed operations, so please refer to an <classname>AbstractMessageRouter</classname> for more detail
For additional managed operations please refer to an <classname>AbstractMessageRouter</classname> for more detail
</para>
<para>
You can also use your favorite JMX client (e.g., JConsole) and use those operations (methods) to change
router configuration. For more information on Spring Integration management and monitoring please visit
section 29 of this manual.
<xref linkend="jmx"/>.
</para>
</section>

View File

@@ -15,17 +15,20 @@
<section>
<title>Programming model</title>
<para>The API for performing splitting consists from one base class,
AbstractMessageSplitter, which is a MessageHandler implementation,
<para>The API for performing splitting consists of one base class,
<classname>AbstractMessageSplitter</classname>, which is a
<interfacename>MessageHandler</interfacename> implementation,
encapsulating features which are common to splitters, such as filling in
the appropriate message headers CORRELATION_ID, SEQUENCE_SIZE, and
SEQUENCE_NUMBER on the messages that are produced. This allows to track
SEQUENCE_NUMBER on the messages that are produced. This enables tracking
down the messages and the results of their processing (in a typical
scenario, these headers would be copied over to the messages that are
produced by the various transforming endpoints), and use them, for
example, in a Composed Message Processor scenario.</para>
example, in a
<ulink url="http://www.eaipatterns.com/DistributionAggregate.html">
Composed Message Processor</ulink> scenario.</para>
<para>An excerpt from AbstractMessageSplitter can be seen below:</para>
<para>An excerpt from <classname>AbstractMessageSplitter</classname> can be seen below:</para>
<programlisting lang="java">public abstract class AbstractMessageSplitter
extends AbstractReplyProducingMessageConsumer {
@@ -34,15 +37,16 @@
}</programlisting>
<para>For implementing a specific Splitter in an application, a developer
can extend AbstractMessageSplitter and implement the splitMessage method,
thus defining the actual logic for splitting the messages. The return
value can be one of the following:</para>
<para>To implement a specific Splitter in an application,
extend <classname>AbstractMessageSplitter</classname> and implement the <code>splitMessage</code> method,
which contains logic for splitting the messages. The return
value may be one of the following:</para>
<itemizedlist>
<listitem>
<para>a Collection (or subclass thereof) or an array of Message
objects - in this case the messages will be sent as such (after the
<para>a <interfacename>Collection</interfacename> (or subclass thereof) or an array of
<interfacename>Message</interfacename> objects -
in this case the messages will be sent as such (after the
CORRELATION_ID, SEQUENCE_SIZE and SEQUENCE_NUMBER are populated).
Using this approach gives more control to the developer, for example
for populating custom message headers as part of the splitting
@@ -50,17 +54,17 @@
</listitem>
<listitem>
<para>a Collection (or subclass thereof) or an array of non-Message
objects - works like the prior case, except that each collection
<para>a <interfacename>Collection</interfacename> (or subclass thereof) or an array of
non-Message objects - works like the prior case, except that each collection
element will be used as a Message payload. Using this approach allows
developers to focus on the domain objects without having to consider
the Messaging system and produces code that is easier to test.</para>
</listitem>
<listitem>
<para>a Message or non-Message object (but not a Collection or an
Array) - it works like the previous cases, except that there is a
single message to be sent out.</para>
<para>a <interfacename>Message</interfacename> or non-Message object
(but not a Collection or an Array) - it works like the previous cases,
except a single message will be sent out.</para>
</listitem>
</itemizedlist>
@@ -68,9 +72,9 @@
algorithm, provided that it defines a method that accepts a single
argument and has a return value. In this case, the return value of the
method will be interpreted as described above. The input argument might
either be a Message or a simple POJO. In the latter case, the splitter
will receive the payload of the incoming message. Since this decouples
the code from the Spring Integration API and will typically be easier
either be a <interfacename>Message</interfacename> or a simple POJO.
In the latter case, the splitter will receive the payload of the incoming message.
Since this decouples the code from the Spring Integration API and will typically be easier
to test, it is the recommended approach.</para>
</section>
@@ -80,7 +84,7 @@
<section>
<title>Configuring a Splitter using XML</title>
<para>A splitter can be configured through XML as follows:<programlisting>&lt;channel id="inputChannel"/&gt;
<para>A splitter can be configured through XML as follows:<programlisting language="xml">&lt;channel id="inputChannel"/&gt;
&lt;splitter id="splitter" <co id="split1" />
ref="splitterBean" <co id="split2" />
@@ -99,10 +103,12 @@
<callout arearefs="split2">
<para>A reference to a bean defined in the application context. The
bean must implement the splitting logic as described in the section
above. <emphasis>Optional</emphasis>.
If reference to a bean is not provided, then it is assumed that the <emphasis>payload</emphasis> of the Message that arrived on the <code>input-channel</code> is
an implementation of <emphasis>java.util.Collection</emphasis> and the default splitting logic will be applied on such Collection,
incorporating each individual element into a Message and depositing it on the <code>output-channel</code>.
above .<emphasis>Optional</emphasis>.
If reference to a bean is not provided, then it is assumed that the <emphasis>payload</emphasis>
of the Message that arrived on the <code>input-channel</code> is
an implementation of <interfacename>java.util.Collection</interfacename>
and the default splitting logic will be applied to the Collection,
incorporating each individual element into a Message and sending it to the <code>output-channel</code>.
</para>
</callout>
@@ -118,15 +124,15 @@
</callout>
<callout arearefs="split5">
<para>The channel where the splitter will send the results of
<para>The channel to which the splitter will send the results of
splitting the incoming message. <emphasis>Optional (because incoming
messages can specify a reply channel themselves)</emphasis>.</para>
</callout>
</calloutlist></para>
<para>
Using a "ref" attribute is generally recommended if the custom splitter handler implementation can be reused in other
Using a <code>ref</code> attribute is generally recommended if the custom splitter implementation may be referenced in other
<code>&lt;splitter&gt;</code> definitions. However if the custom splitter handler implementation should be scoped to a
single definition of the <code>&lt;splitter&gt;</code>, you can configure an inner bean definition:
single definition of the <code>&lt;splitter&gt;</code>, configure an inner bean definition:
<programlisting language="xml"><![CDATA[<splitter id="testSplitter" input-channel="inChannel" method="split"
output-channel="outChannel">
<beans:bean class="org.foo.TestSplitter"/>
@@ -134,7 +140,7 @@
</para>
<note>
<para>
Using both a "ref" attribute and an inner handler definition in the same <code>&lt;splitter&gt;</code>
Using both a <code>ref</code> attribute and an inner handler definition in the same <code>&lt;splitter&gt;</code>
configuration is not allowed, as it creates an ambiguous condition and will result in an Exception being thrown.
</para>
</note>
@@ -146,10 +152,10 @@
<para>The <interfacename>@Splitter</interfacename> annotation is
applicable to methods that expect either the
<interfacename>Message</interfacename> type or the message payload type,
and the return values of the method should be a collection of any type. If
the returned values are not actual <interfacename>Message</interfacename>
objects, then each of them will be sent as the payload of a message. Those
messages will be sent to the output channel as designated for the endpoint
and the return values of the method should be a <interfacename>Collection</interfacename> of any type.
If the returned values are not actual <interfacename>Message</interfacename>
objects, then each item will be wrapped in a Message as its payload. Each
message will be sent to the designated output channel for the endpoint
on which the <interfacename>@Splitter</interfacename> is defined.
<programlisting language="java">@Splitter
List&lt;LineItem&gt; extractItems(Order order) {
@@ -157,8 +163,4 @@ List&lt;LineItem&gt; extractItems(Order order) {
}</programlisting></para>
</section>
</section>
</section>

View File

@@ -81,8 +81,8 @@
</para>
<para>
By default, the <classname>MarshallingTransformer</classname> will pass the payload Object
to the <interfacename>Marshaller</interfacename>, but if its boolean "extractPayload" property
is set to "false", the entire <interfacename>Message</interfacename> instance will be passed
to the <interfacename>Marshaller</interfacename>, but if its boolean <code>extractPayload</code> property
is set to <code>false</code>, the entire <interfacename>Message</interfacename> instance will be passed
to the <interfacename>Marshaller</interfacename> instead. That may be useful for certain custom
implementations of the <interfacename>Marshaller</interfacename> interface, but typically the
payload is the appropriate source Object for marshalling when delegating to any of the various
@@ -147,10 +147,10 @@
<para>
The namespace support for the marshalling transformer requires an input channel, output channel and a
reference to a marshaller. The optional result-type attribute can be used to control the type of result created,
reference to a marshaller. The optional <code>result-type</code> attribute can be used to control the type of result created,
valid values are StringResult or DomResult (the default). Where the provided result types are not sufficient a
reference to a custom implementation of <interfacename>ResultFactory</interfacename> can be provided as an alternative
to setting the result-type attribute using the result-factory attribute. An optional result-transformer can also be
to setting the <code>result-type</code> attribute using the <code>result-factory</code> attribute. An optional <code>result-transformer</code> can also be
specified in order to convert the created <interfacename>Result</interfacename> after marshalling.
<programlisting language="xml"><![CDATA[<si-xml:marshalling-transformer
input-channel="marshallingTransformerStringResultFactory"
@@ -172,7 +172,7 @@
Namespace support for the <classname>XsltPayloadTransformer</classname> allows either a resource to be passed in in order to create the
<interfacename>Templates</interfacename> instance or alternatively a precreated <interfacename>Templates</interfacename>
instance can be passed in as a reference. In common with the marshalling transformer the type of the result output can
be controlled by specifying either the result-factory or result-type attribute. A result-transfomer attribute can also
be controlled by specifying either the result-factory or <code>result-type</code> attribute. A <code>result-transfomer</code> attribute can also
be used to reference an implementation of <interfacename>ResultTransfomer</interfacename> where conversion of the result
is required before sending.
<programlisting language="xml"><![CDATA[<si-xml:xslt-transformer id="xsltTransformerWithResource"
@@ -198,11 +198,11 @@
<int-xml:xslt-param name="helloParameter" value="hello"/>
<int-xml:xslt-param name="firstName" expression="headers.fname"/>
</int-xml:xslt-transformer>]]></programlisting>
If message header names match 1:1 to parameter names, you can simply use <emphasis>xslt-param-headers attribute</emphasis>. There you can also use wildcards for
If message header names match 1:1 to parameter names, you can simply use <code>xslt-param-headers</code> attribute. There you can also use wildcards for
simple pattern matching which supports the following simple pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy".
</para>
<para>
You can also configure individual xslt parameters via <emphasis>xslt-param</emphasis> sub element. There you can use <code>expression</code> or <code>value</code> attribute.
You can also configure individual xslt parameters via &lt;xslt-param/&gt; sub element. There you can use <code>expression</code> or <code>value</code> attribute.
The <code>expression</code> attribute should be any valid SpEL expression with Message being the root object of the expression evaluation context.
The <code>value</code> attribute just like any <code>value</code> in Spring beans allows you to specify simple scalar vallue. YOu can also use property placeholders (e.g., ${some.value})
So as you can see, with the <code>expression</code> and <code>value</code> attribute xslt parameters could now be mapped to any accessible part of the Message as well as any literal value.
@@ -332,7 +332,7 @@
<title>Transforming xml messages using XPath</title>
<para>
When it comes to message transformation XPath is a great way to transform Messages that have XML
payloads by defining XPath transformers via <emphasis>xpath-transformer</emphasis> element.
payloads by defining XPath transformers via &lt;xpath-transformer/&gt; element.
</para>
<para>
<emphasis>Simple XPath transformation</emphasis>
@@ -347,7 +347,7 @@
MessageBuilder.withPayload("<person name='John Doe' age='42' married='true'/>").build();]]></programlisting>
After sending this message to the 'inputChannel' the XPath transformer configured above will transform
this XML Message to a simple Message with payload of 'John Doe' all based on
the simple XPath Expression specified in the <emphasis>xpath-expression</emphasis> attribute.
the simple XPath Expression specified in the <code>xpath-expression</code> attribute.
</para>
<para>
XPath also has capability to perform simple conversion of extracted elements
@@ -358,8 +358,8 @@
The following constants are defined by the <classname>XPathConstants</classname>: <emphasis>BOOLEAN, DOM_OBJECT_MODEL, NODE, NODESET, NUMBER, STRING</emphasis>
</para>
<para>
You can configure the desired type by simply using <emphasis>evaluation-type</emphasis>
attribute of the <emphasis>xpath-transformer</emphasis> element.
You can configure the desired type by simply using <code>evaluation-type</code>
attribute of the &lt;xpath-transformer/&gt; element.
<programlisting language="xml"><![CDATA[<xpath-transformer input-channel="numberInput" xpath-expression="/person/@age"
evaluation-type="NUMBER_RESULT" output-channel="output"/>
@@ -374,7 +374,7 @@
If you need to provide custom mapping for the node extracted by the XPath expression simply provide a reference to the
implementation of the <classname>org.springframework.xml.xpath.NodeMapper</classname> - an interface used by
<classname>XPathOperations</classname> implementations for mapping Node objects on a per-node basis. To provide a
reference to a <classname>NodeMapper</classname> simply use <emphasis>node-mapper</emphasis> attribute:
reference to a <classname>NodeMapper</classname> simply use <code>node-mapper</code> attribute:
<programlisting language="xml"><![CDATA[<xpath-transformer input-channel="nodeMapperInput" xpath-expression="/person/@age"
node-mapper="testNodeMapper" output-channel="output"/>
]]></programlisting>
@@ -420,7 +420,7 @@
</para>
<para>
You can also combine Spring Expression Language (SpEL) expressions with XPath expression and configure
them using <emphasis>expression</emphasis> attribute:
them using <code>expression</code> attribute:
<programlisting language="xml"><![CDATA[xpath-expression id="testExpression" expression="/person/@age * 2"/>]]></programlisting>
In the above case the overall result of the expression will be the result of the XPathe expression multiplied by 2.
</para>
@@ -432,7 +432,7 @@
<para>All XPath based components have namespace support allowing them to be configured as
Message Endpoints with the exception of the XPath selectors which are not designed to act as
endpoints. Each component allows the XPath to either be referenced at the top level or configured via a nested
xpath-expression element. So the following configurations of an xpath-selector are all valid and represent the general
&lt;xpath-expression/&gt; element. So the following configurations of an xpath-selector are all valid and represent the general
form of XPath namespace support. All forms of XPath expression result in the creation of an
<interfacename>XPathExpression</interfacename> using the Spring <classname>XPathExpressionFactory</classname>
<programlisting language="xml"><![CDATA[<si-xml:xpath-selector id="xpathRefSelector"
@@ -487,7 +487,7 @@
</para>
<para>
XPath router namespace support allows for the creation of a Message Endpoint with an input channel but no output channel
since the output channel is determined dynamically. The multi-channel attribute causes the creation of a multi channel router capable of
since the output channel is determined dynamically. The <code>multi-channel</code> attribute causes the creation of a multi channel router capable of
routing a single message to many channels when true and a single channel router when false.
<programlisting language="xml"><![CDATA[<!-- route the message according to exactly one order type channel -->
<si-xml:xpath-router id="orderTypeRouter" input-channel="orderChannel" multi-channel="false">