INT-2243: Delayer: Add 'expression' Support

Previously, the `<delayer>` provided a `delay-header-name` attribute.
In complex cases there was need to precede it with `<header-enricher>`.

* Add support for an 'expression' attribute and sub-element
* Deprecate `delay-header-name`
* Make `DelayHandler.DelayedMessageWrapper` *public* to allow access for Messages in the Store
* Add tests
* Add 'What's new' section
* Polishing Delayer's doc regarding new abilities

JIRA: https://jira.springsource.org/browse/INT-2243, https://jira.springsource.org/browse/INT-3049

INT-2243: ban delay-header-name with expression

INT-2243 Polishing

INT-2243: fall-back to default on Eval Exception

INT-2243: DelayedMessageWrapper refactoring

* Make `DelayedMessageWrapper` Spring Data Mongo mapping compatible.
In terms of Spring Data - add Persistence Constructor

INT-2243 add 'ignore-expression-failures' support

* Add `ignore-expression-failures` to the `<delayer>`
* Add tests for `ignore-expression-failures`
* Add a note to the RM
* Describe SpEL side-effects for `DelayHandler`

Doc Polishing
This commit is contained in:
Artem Bilan
2013-06-15 17:51:58 +03:00
committed by Gary Russell
parent 67fd4a5a60
commit afe56ca6d5
12 changed files with 329 additions and 82 deletions

View File

@@ -21,33 +21,56 @@
<para>
The <code>&lt;delayer&gt;</code> element is used to delay the Message flow between two Message Channels.
As with the other endpoints, you can provide the 'input-channel' and 'output-channel' attributes,
but the delayer also has 'default-delay' and 'delay-header-name' attributes that are used to
determine the number of milliseconds
that each Message should be delayed. The following delays all messages by 3 seconds:
but the delayer also has 'default-delay' and 'expression' attributes (and 'expression' sub-element) that are used to
determine the number of milliseconds that each Message should be delayed. The following delays all messages by 3 seconds:
<programlisting language="xml"><![CDATA[<int:delayer id="delayer" input-channel="input"
default-delay="3000" output-channel="output"/>]]></programlisting>
If you need per-Message determination of the delay, then you can also provide the name of a header
using the 'delay-header-name' attribute:
If you need per-Message determination of the delay, then you can also provide the SpEL expression
using the 'expression' attribute:
<programlisting language="xml"><![CDATA[<int:delayer id="delayer" input-channel="input" output-channel="output"
default-delay="3000" delay-header-name="delay"/>]]></programlisting>
In the example above the 3 second delay would only apply in the case that the header value is
not present for a given inbound Message. If you only want to apply a delay to Messages that have
an explicit header value, then you can set the 'default-delay' to 0 or don't use it at all (by default it is 0).
For any Message that has a delay of 0 (or less), the Message will be sent directly. In fact, if there is not a positive delay
value for a Message, it will be sent to the output channel on the calling Thread.
default-delay="3000" expression="headers['delay']"/>]]></programlisting>
In the example above, the 3 second delay would only apply when the expression evaluates to
<emphasis>null</emphasis> for a given inbound Message. If you only want to apply a delay to Messages that have
a valid result of the expression evaluation, then you can use a 'default-delay' of 0 (the default).
For any Message that has a delay of 0 (or less), the Message will be sent immediately, on the calling Thread.
<tip>
The delay handler supports header values that represent an interval in milliseconds (any
The delay handler supports expression evaluation results that represent an interval in milliseconds (any
Object whose <methodname>toString()</methodname> method produces a value that can be parsed into a
Long) as well as <classname>java.util.Date</classname> instances representing an absolute time.
In the first case, the milliseconds will be counted from the current time (e.g. a value of 5000
would delay the Message for at least 5 seconds from the time it is received by the Delayer).
With a Date instance, the Message will not be released until that Date
occurs. In either case, a value that equates to a non-positive delay, or a Date in the past, will
With a Date instance, the Message will not be released until the time represented by that Date object.
In either case, a value that equates to a non-positive delay, or a Date in the past, will
not result in any delay. Instead, it will be sent directly to the output channel on the original
sender's Thread. If the header is not a Date, and can not be parsed as a Long, the default
sender's Thread. If the expression evaluation result is not a Date, and can not be parsed as a Long, the default
delay (if any) will be applied.
</tip>
<important>
The expression evaluation may throw an evaluation Exception for various reasons, including an invalid
expression, or other conditions. By default, such exceptions are ignored (logged at DEBUG level) and
the delayer falls back to the default delay (if any). You can modify this behavior by setting the
<code>ignore-expression-failures</code> attribute.
By default this attribute is set to <code>true</code> and the Delayer behavior is as described above.
However, if you wish to not ignore expression evaluation exceptions, and throw them to the delayer's caller,
set the <code>ignore-expression-failures</code> attribute to <code>false</code>.
</important>
</para>
<tip>
Notice in the example above that the delay expression is specified as <code>headers['delay']</code>.
This is the SpEL <classname>Indexer</classname> syntax to access a <interfacename>Map</interfacename> element
(<classname>MessageHeaders</classname> implements <interfacename>Map</interfacename>),
it invokes: <code>headers.get("delay")</code>. For simple map element names (that do not contain '.')
you can also use the SpEL <emphasis>dot accessor</emphasis> syntax, where the above header expression
can be specified as <code>headers.delay</code>. But, different results are achieved if the header is missing.
In the first case, the expression will evaluate to <code>null</code>; the second will result in
something like:
<programlisting language="java"><![CDATA[ org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 8):
Field or property 'delay' cannot be found on object of type 'org.springframework.integration.MessageHeaders']]></programlisting>
So, if there is a possibility of the header being omitted, and you want to fall back to the default
delay, it is generally more efficient (and recommended) to use the
<emphasis>Indexer</emphasis> syntax instead of <emphasis>dot property accessor</emphasis> syntax, because detecting
the null is faster than catching an exception.
</tip>
<para>
The delayer delegates to an instance of Spring's <interfacename>TaskScheduler</interfacename> abstraction.
The default scheduler used by the delayer is the <classname>ThreadPoolTaskScheduler</classname> instance
@@ -55,7 +78,7 @@
If you want to delegate to a different scheduler, you can provide a reference through the delayer element's
'scheduler' attribute:
<programlisting language="xml"><![CDATA[<int:delayer id="delayer" input-channel="input" output-channel="output"
delay-header-name="delay"
expression="headers.delay"
scheduler="exampleTaskScheduler"/>
<task:scheduler id="exampleTaskScheduler" pool-size="3"/>]]></programlisting>
@@ -106,7 +129,7 @@
<interfacename>org.aopalliance.aop.Advice</interfacename> implementation within the <code>&lt;advice-chain&gt;</code>.
A sample configuration of the <code>&lt;delayer&gt;</code> may look like this:
<programlisting language="xml"><![CDATA[<int:delayer id="delayer" input-channel="input" output-channel="output"
delay-header-name="delay"
expression="headers.delay"
message-store="jdbcMessageStore">
<int:advice-chain>
<beans:ref bean="customAdviceBean"/>

View File

@@ -312,5 +312,19 @@
set <code>requires-reply</code> to false.
</important>
</section>
<section id="3.0-dalay-expression">
<title>Delayer: delay expression</title>
<para>
Previously, the <code>&lt;delayer&gt;</code> provided a <code>delay-header-name</code> attribute
to determine the <emphasis>delay</emphasis> value at runtime. In complex cases it was necessary
to precede the <code>&lt;delayer&gt;</code> with a <code>&lt;header-enricher&gt;</code>.
Spring Integration 3.0 introduced the <code>expression</code> attribute and <code>expression</code>
sub-element for dynamic delay determination. The <code>delay-header-name</code> attribute is now deprecated
because the header evaluation can be specified in the <code>expression</code>. In addition,
the <code>ignore-expression-failures</code> was introduced to control the behavior when an
expression evaluation fails.
For more information see <xref linkend="delayer"/>.
</para>
</section>
</section>
</chapter>