GH-2765: Add discardChannel for splitter (#2883)

* GH-2765: Add discardChannel for splitter

Fixes https://github.com/spring-projects/spring-integration/issues/2765

When encountering empty collections, splitter should be able to send
the result to a discard channel.
Currently, when encountering an empty collection,
the splitter ends the flow.
Some use-cases may rely on a custom split function which may returns
empty collections.
These use-cases should be able to define a discard channel
so they can proceed with a possible compensation flow.

* Add `discardChannel` option to the `AbstractMessageSplitter`
* Delegate `discardChannel` population from everywhere it is possible:
DSL, XML, `AbstractMessageSplitter` extension like `FileSplitter` etc.
* Fix `FileSplitterTests` for broken charset
* Document new feature; fix some typos and out-dated code sample

* * Fix `SplitterFactoryBean` for NPE on the `discardChannelName`
propagation

* * Check `this.discardChannel` first
* `Assert.state()` in `doInit()` for mutual exclusiveness
This commit is contained in:
Artem Bilan
2019-04-08 16:42:57 -04:00
committed by Gary Russell
parent 7fa1161f5b
commit 818be4cbe8
18 changed files with 263 additions and 61 deletions

View File

@@ -455,15 +455,13 @@ The following example shows how to use the `split()` method by providing a lambd
@Bean
public IntegrationFlow splitFlow() {
return IntegrationFlows.from("splitInput")
.split(s ->
s.applySequence(false).get().getT2().setDelimiters(","))
.channel(MessageChannels.executor(this.taskExecutor()))
.split(s -> s.applySequence(false).delimiters(","))
.channel(MessageChannels.executor(taskExecutor()))
.get();
}
----
The preceding example creates a splitter that splits a message containing a comma-delimited `String`.
Note: The `getT2()` method comes from a `Tuple` `Collection`, which is the result of `EndpointSpec.get()`, and represents a pair of `ConsumerEndpointFactoryBean` and `DefaultMessageSplitter` for the preceding example.
Also see <<java-dsl-class-cast>>.
@@ -1157,7 +1155,7 @@ Otherwise, creating such a configuration by using `IntegrationFlow` does not mak
By default a `GatewayProxyFactoryBean` gets a conventional bean name, such as `[FLOW_BEAN_NAME.gateway]`.
You can change that ID by using the `@MessagingGateway.name()` attribute or the overloaded `from(Class<?> serviceInterface, String beanName)` factory method.
With Java 8, you can even create an integration fateway with the `java.util.function` interfaces, as the following example shows:
With Java 8, you can even create an integration gateway with the `java.util.function` interfaces, as the following example shows:
====
[source,java]

View File

@@ -64,6 +64,10 @@ In this case, the target `Iterator` is built on their iteration functionality.
In addition, if the splitter's output channel is an instance of a `ReactiveStreamsSubscribableChannel`, the `AbstractMessageSplitter` produces a `Flux` result instead of an `Iterator`, and the output channel is subscribed to this `Flux` for back-pressure-based splitting on downstream flow demand.
Starting with version 5.2, the splitter supports a `discardChannel` option for sending those request messages for which a split function has returned an empty container (collection, array, stream, `Flux` etc.).
In this case there is just no item to iterate for sending to the `outputChannel`.
The `null` splitting result remains as an end of flow indicator.
==== Configuring a Splitter with XML
A splitter can be configured through XML as follows:
@@ -73,11 +77,12 @@ A splitter can be configured through XML as follows:
----
<int:channel id="inputChannel"/>
<int:splitter id="splitter" <1>
ref="splitterBean" <2>
method="split" <3>
input-channel="inputChannel" <4>
output-channel="outputChannel" /> <5>
<int:splitter id="splitter" <1>
ref="splitterBean" <2>
method="split" <3>
input-channel="inputChannel" <4>
output-channel="outputChannel" <5>
discard-channel="discardChannel" /> <6>
<int:channel id="outputChannel"/>
@@ -94,6 +99,8 @@ Optional.
Required.
<5> The channel to which the splitter sends the results of splitting the incoming message.
Optional (because incoming messages can specify a reply channel themselves).
<6> The channel to which the request message is sent in case of empty splitting result.
Optional (the will stop as in case of `null` result).
====
We recommend using a `ref` attribute if the custom splitter implementation can be referenced in other `<splitter>` definitions.

View File

@@ -19,6 +19,9 @@ See <<rate-limiter-advice>> for more information.
The `JsonToObjectTransformer` now supports generics for the target object to deserialize into.
See <<json-transformers>> for more information.
RThe `splitter` now supports a `discardChannel` configuration option.
See <<splitter>> for more information.
[[x5.2-amqp]]
==== AMQP Changes