proof read reference guide
This commit is contained in:
@@ -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<T></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<T></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><aggregator></code> definitions. However if a custom
|
||||
aggregator handler implementation should be scoped to a concrete
|
||||
definition of the <code><aggregator></code>, you can use an inner
|
||||
aggregator implementation should be scoped to a single
|
||||
definition of the <code><aggregator></code>, use an inner
|
||||
bean definition (starting with version 1.0.3) for custom aggregator
|
||||
handlers within the <code><aggregator></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><aggregator></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
|
||||
|
||||
@@ -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 <chain> 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 <chain> 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 <header-enricher> 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 <gateway> element.
|
||||
To accomplish this you can utilize Messaging Gateway by including a light configured <gateway> 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 <gateway> 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 <gateway> 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>
|
||||
|
||||
|
||||
@@ -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 <channel/> element:
|
||||
<programlisting language="xml"><channel id="exampleChannel"/></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 <publish-subscribe-channel/> element:
|
||||
<programlisting language="xml"><publish-subscribe-channel id="exampleChannel"/></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 <channel/> 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 <queue/> 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 <queue/> sub-element.
|
||||
You may specify the channel's capacity:
|
||||
<programlisting language="xml"><channel id="queueChannel">
|
||||
<queue capacity="25"/>
|
||||
@@ -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 <publish-subscribe-channel/> 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"><publish-subscribe-channel id="pubsubChannel" task-executor="someExecutor"/></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"><publish-subscribe-channel id="pubsubChannel" apply-sequence="true"/></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 <dispatcher> 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 <dispatcher/> 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 <priority-queue/> 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
|
||||
<interceptors> sub-element can be added within <channel> (or the more specific element
|
||||
types). Provide the "ref" attribute to reference any Spring-managed object that implements the
|
||||
<interceptors/> sub-element can be added within <channel/> (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>
|
||||
<channel-interceptor> 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
|
||||
<channel-interceptor/> 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 <interceptors/> 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>
|
||||
|
||||
|
||||
@@ -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 <filter> 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 <filter> 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><filter></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><filter></code> definitions. However if the custom filter implementation is scoped to a
|
||||
single <code><filter></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><filter></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><filter></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 <expression> element, but in this case it's shown for completeness.
|
||||
<code>source</code> attribute on the <expression> 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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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><router/></code> configuration and its corresponding implementation defined using <code><bean/></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><router></code> definitions. However if the custom router implementation should be scoped to a
|
||||
concrete definition of the <code><router></code>, you can provide an inner bean definition:
|
||||
single definition of the <code><router></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><router></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><router></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><router></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><router></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<String> 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<String> route(@Header("orderStatus") OrderStatus status)</programlisting>
|
||||
</para>
|
||||
@@ -244,40 +243,38 @@ public List<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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>
|
||||
|
||||
|
||||
@@ -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><channel id="inputChannel"/>
|
||||
<para>A splitter can be configured through XML as follows:<programlisting language="xml"><channel id="inputChannel"/>
|
||||
|
||||
<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><splitter></code> definitions. However if the custom splitter handler implementation should be scoped to a
|
||||
single definition of the <code><splitter></code>, you can configure an inner bean definition:
|
||||
single definition of the <code><splitter></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><splitter></code>
|
||||
Using both a <code>ref</code> attribute and an inner handler definition in the same <code><splitter></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<LineItem> extractItems(Order order) {
|
||||
@@ -157,8 +163,4 @@ List<LineItem> extractItems(Order order) {
|
||||
}</programlisting></para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
@@ -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 <xslt-param/> 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 <xpath-transformer/> 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 <xpath-transformer/> 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
|
||||
<xpath-expression/> 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">
|
||||
|
||||
Reference in New Issue
Block a user