Fix typos in the Reference Manual

Update note on channel interceptors in docs

Update `channel.adoc` including `afterReceiveCompletion(..)` in the
list of methods that are not invoked when an interceptor is applied
to `PollableChannel`

Improve `aggregator.adoc` formatting in docs

Fix and improve `channel.adoc` formatting in docs

Convert tabs to spaces of `codec.adoc` in docs

Convert tabs to spaces and fix formatting of `content-enrichment.adoc` in docs

Convert tabs to spaces and fix formatting of `logging-adapter.adoc` in docs

Convert tabs to spaces on `metrics.adoc` in docs

Improve `resequencer.adoc` formatting in docs

Improve `splitter.adoc` formatting in docs

* Fix more typos in the Reference Manual
This commit is contained in:
Guilherme Trein
2016-03-27 15:17:50 -04:00
committed by Artem Bilan
parent 4ac3a79df7
commit dee5c91bd8
8 changed files with 96 additions and 103 deletions

View File

@@ -161,17 +161,11 @@ public interface ReleaseStrategy {
In general, any POJO can implement the completion decision logic if it provides a method that accepts a single `java.util.List` as an argument (parameterized lists are supported as well), and returns a boolean value.
This method will be invoked after the arrival of each new message, to decide whether the group is complete or not, as follows:
if the argument is a `java.util.List<T>`, and the parameter type T is assignable to `Message`, then the whole list of messages accumulated in the group will be sent to the method
if the argument is a non-parametrized `java.util.List` or the parameter type is not assignable to `Message`, then the method will receive the payloads of the accumulated messages
the method must return true if the message group is ready for aggregation, and false otherwise.
* if the argument is a `java.util.List<T>`, and the parameter type T is assignable to `Message`, then the whole list of messages accumulated in the group will be sent to the method
* if the argument is a non-parametrized `java.util.List` or the parameter type is not assignable to `Message`, then the method will receive the payloads of the accumulated messages
* the method must return true if the message group is ready for aggregation, and false otherwise.
For example:
@@ -222,7 +216,7 @@ To avoid such situations, you should consider configuring a `MessageGroupStoreRe
For information about configuring a reaper, see <<reaper>>.
Spring Integration provides an out-of-the box implementation for `ReleaseStrategy`, the `SequenceSizeReleaseStrategy`.
This implementation consults the SEQUENCE_NUMBER and SEQUENCE_SIZE headers of each arriving message to decide when a message group is complete and ready to be aggregated.
This implementation consults the `SEQUENCE_NUMBER` and `SEQUENCE_SIZE` headers of each arriving message to decide when a message group is complete and ready to be aggregated.
As shown above, it is also the default strategy.
===== CorrelationStrategy
@@ -239,14 +233,14 @@ public interface CorrelationStrategy {
----
The method returns an Object which represents the correlation key used for associating the message with a message group.
The key must satisfy the criteria used for a key in a Map with respect to the implementation of equals() and hashCode().
The key must satisfy the criteria used for a key in a Map with respect to the implementation of `equals()` and `hashCode()`.
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 `ServiceActivator` (including support for @Header annotations).
The method must return a value, and the value must not be `null`.
Spring Integration provides an out-of-the box implementation for `CorrelationStrategy`, the `HeaderAttributeCorrelationStrategy`.
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 the value of the CORRELATION_ID header attribute.
By default, the correlation strategy is a `HeaderAttributeCorrelationStrategy` returning the value of the `CORRELATION_ID` header attribute.
If you have a custom header name you would like to use for correlation, then simply configure that on an instance of `HeaderAttributeCorrelationStrategy` and provide that as a reference for the Aggregator's correlation-strategy.
===== LockRegistry
@@ -517,7 +511,7 @@ If the group is not released by the release strategy during timeout, then the ex
Timed-out groups are either discarded, or a partial release occurs (based on `send-partial-result-on-expiry`).
=====
Using a `ref` attribute is generally recommended if a custom aggregator handler implementation may be referenced in other`<aggregator>` definitions.
Using a `ref` attribute is generally recommended if a custom aggregator handler implementation may be referenced in other `<aggregator>` definitions.
However if a custom aggregator implementation is only being used by a single definition of the `<aggregator>`, you can use an inner bean definition (starting with version 1.0.3) to configure the aggregation POJO within the `<aggregator>` element:
[source,xml]
----
@@ -542,7 +536,6 @@ public class PojoAggregator {
}
return total;
}
}
----
@@ -685,7 +678,6 @@ public class Waiter {
public String correlateBy(OrderItem item) {
...
}
}
----

View File

@@ -68,7 +68,7 @@ Each is briefly described in the sections below.
The `PublishSubscribeChannel` implementation broadcasts any Message sent to it to all of its subscribed handlers.
This is most often used for sending _Event Messages_ whose primary role is notification as opposed to _Document Messages_ which are generally intended to be processed by a single handler.
Note that the `PublishSubscribeChannel` is intended for sending only.
Since it broadcasts to its subscribers directly when its` send(Message)` method is invoked, consumers cannot poll for Messages (it does not implement `PollableChannel` and therefore has no `receive()` method).
Since it broadcasts to its subscribers directly when its `send(Message)` method is invoked, consumers cannot poll for Messages (it does not implement `PollableChannel` and therefore has no `receive()` method).
Instead, any subscriber must be a `MessageHandler` itself, and the subscriber's `handleMessage(Message)` method will be invoked in turn.
Prior to version 3.0, invoking the send method on a `PublishSubscribeChannel` that had no subscribers returned `false`.
@@ -144,7 +144,7 @@ Below you will see how each of these can be configured.
The `DirectChannel` internally delegates to a Message Dispatcher to invoke its subscribed Message Handlers, and that dispatcher can have a load-balancing strategy exposed via _load-balancer_ or _load-balancer-ref_ attributes (mutually exclusive).
The load balancing strategy is used by the Message Dispatcher to help determine how Messages are distributed amongst Message Handlers in the case that there are multiple Message Handlers subscribed to the same channel.
As a convinience the _load-balancer_ attribute exposes enumeration of values pointing to pre-existing implementations of `LoadBalancingStrategy`.
As a convenience the _load-balancer_ attribute exposes enumeration of values pointing to pre-existing implementations of `LoadBalancingStrategy`.
The "round-robin" (load-balances across the handlers in rotation) and "none" (for the cases where one wants to explicitely disable load balancing) are the only available values.
Other strategy implementations may be added in future versions.
However, since version 3.0 you can provide your own implementation of the `LoadBalancingStrategy` and inject it using _load-balancer-ref_ attribute which should point to a bean that implements `LoadBalancingStrategy`.
@@ -254,7 +254,7 @@ NOTE: Keep in mind that `receive()` calls are only relevant for `PollableChannel
In fact the `SubscribableChannel` interface does not even define a `receive()` method.
The reason for this is that when a Message is sent to a `SubscribableChannel` it will be sent directly to one or more subscribers depending on the type of channel (e.g.
a PublishSubscribeChannel sends to all of its subscribers).
Therefore, the `preReceive(..)` and `postReceive(..)` interceptor methods are only invoked when the interceptor is applied to a `PollableChannel`.
Therefore, the `preReceive(..)`, `postReceive(..)` and `afterReceiveCompletion(..)` interceptor methods are only invoked when the interceptor is applied to a `PollableChannel`.
Spring Integration also provides an implementation of the http://eaipatterns.com/WireTap.html[Wire Tap] pattern.
It is a simple interceptor that sends the Message to another channel without otherwise altering the existing flow.
@@ -336,15 +336,15 @@ To create a Message Channel instance, you can use the <channel/> element:
----
The default channel type is _Point to Point_.
To create a _Publish Subscribe_ channel, use the <publish-subscribe-channel/> element:
To create a _Publish Subscribe_ channel, use the `<publish-subscribe-channel/>` element:
[source,xml]
----
<int:publish-subscribe-channel id="exampleChannel"/>
----
When using the <channel/> element without any sub-elements, it will create a `DirectChannel` instance (a `SubscribableChannel`).
When using the `<channel/>` element without any sub-elements, it will create a `DirectChannel` instance (a `SubscribableChannel`).
However, you can alternatively provide a variety of <queue/> sub-elements to create any of the pollable channel types (as described in<<channel-implementations>>).
However, you can alternatively provide a variety of `<queue/>` sub-elements to create any of the pollable channel types (as described in <<channel-implementations>>).
Examples of each are shown below.
[[channel-configuration-directchannel]]
@@ -358,7 +358,7 @@ As mentioned above, `DirectChannel` is the default type.
----
A default channel will have a _round-robin_ load-balancer and will also have failover enabled (See the discussion in <<channel-implementations-directchannel>> for more detail).
To disable one or both of these, add a <dispatcher/> sub-element and configure the attributes:
To disable one or both of these, add a `<dispatcher/>` sub-element and configure the attributes:
[source,xml]
----
<int:channel id="failFastChannel">
@@ -396,7 +396,7 @@ Multiple types can be provided as a comma-delimited list:
----
So the 'numberChannel' above will only accept Messages with a data-type of `java.lang.Number`.
But what happens if the payload of the Message is not of the required type? It depends on whether you have defined a bean named "integrationConversionService" that is an instance of Spring's http://static.springsource.org/spring/docs/current/spring-framework-reference/html/validation.html#core-convert-ConversionService-API[Conversion Service].
But what happens if the payload of the Message is not of the required type? It depends on whether you have defined a bean named `integrationConversionService` that is an instance of Spring's http://static.springsource.org/spring/docs/current/spring-framework-reference/html/validation.html#core-convert-ConversionService-API[Conversion Service].
If not, then an Exception would be thrown immediately, but if you do have an "integrationConversionService" bean defined, it will be used in an attempt to convert the Message's payload to the acceptable type.
You can even register custom converters.
@@ -425,9 +425,9 @@ All we need to do is implement a Converter.
[source,java]
----
public static class StringToIntegerConverter implements Converter<String, Integer> {
public Integer convert(String source) {
return Integer.parseInt(source);
}
public Integer convert(String source) {
return Integer.parseInt(source);
}
}
----
@@ -518,7 +518,7 @@ public BasicMessageGroupStore mongoDbChannelMessageStore(MongoDbFactory mongoDbF
@Bean
public PollableChannel priorityQueue(BasicMessageGroupStore mongoDbChannelMessageStore) {
return new QueueChannel(new MessageGroupQueue(mongoDbChannelMessageStore, "priorityQueue"));
return new QueueChannel(new MessageGroupQueue(mongoDbChannelMessageStore, "priorityQueue"));
}
----
@@ -724,7 +724,7 @@ The default value for `order` will be 0 and for `pattern`, the default is '*' (t
===== Wire Tap
As mentioned above, Spring Integration provides a simple _Wire Tap_ interceptor out of the box.
You can configure a _Wire Tap_ on any channel within an <interceptors/> element.
You can configure a _Wire Tap_ 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:
[source,xml]
----

View File

@@ -58,17 +58,18 @@ serializer that is aware of the object's structure and can directly serialize se
[source,java]
----
public class AddressSerializer extends Serializer<Address> {
@Override
public void write(Kryo kryo, Output output, Address address) {
output.writeString(address.getStreet());
output.writeString(address.getCity());
output.writeString(address.getCountry());
}
@Override
public Address read(Kryo kryo, Input input, Class<Address> type) {
return new Address(input.readString(),input.readString(),input.readString());
}
@Override
public void write(Kryo kryo, Output output, Address address) {
output.writeString(address.getStreet());
output.writeString(address.getCity());
output.writeString(address.getCountry());
}
@Override
public Address read(Kryo kryo, Input input, Class<Address> type) {
return new Address(input.readString(), input.readString(), input.readString());
}
}
----
@@ -103,21 +104,21 @@ registering a custom serializer explicitly:
[source,java]
----
public class Address implements KryoSerializable {
...
...
@Override
public void write(Kryo kryo, Output output) {
output.writeString(this.street);
output.writeString(this.city);
output.writeString(this.country);
}
@Override
public void write(Kryo kryo, Output output) {
output.writeString(this.street);
output.writeString(this.city);
output.writeString(this.country);
}
@Override
public void read(Kryo kryo, Input input) {
this.street = input.readString();
this.city = input.readString();
this.country = input.readString();
}
@Override
public void read(Kryo kryo, Input input) {
this.street = input.readString();
this.city = input.readString();
this.country = input.readString();
}
}
----

View File

@@ -36,8 +36,8 @@ It is exposed via the `<header-enricher>` element.
[source,xml]
----
<int:header-enricher input-channel="in" output-channel="out">
<int:header name="foo" value="123"/>
<int:header name="bar" ref="someBean"/>
<int:header name="foo" value="123"/>
<int:header name="bar" ref="someBean"/>
</int:header-enricher>
----
@@ -46,12 +46,12 @@ The _Header Enricher_ also provides helpful sub-elements to set well-known heade
[source,xml]
----
<int:header-enricher input-channel="in" output-channel="out">
<int:error-channel ref="applicationErrorChannel"/>
<int:reply-channel ref="quoteReplyChannel"/>
<int:correlation-id value="123"/>
<int:priority value="HIGHEST"/>
<routing-slip value="channel1; routingSlipRoutingStrategy; request.headers[myRoutingSlipChannel]"/>
<int:header name="bar" ref="someBean"/>
<int:error-channel ref="applicationErrorChannel"/>
<int:reply-channel ref="quoteReplyChannel"/>
<int:correlation-id value="123"/>
<int:priority value="HIGHEST"/>
<routing-slip value="channel1; routingSlipRoutingStrategy; request.headers[myRoutingSlipChannel]"/>
<int:header name="bar" ref="someBean"/>
</int:header-enricher>
----
@@ -79,10 +79,10 @@ Let's look at the following configuration:
[source,java]
----
public class MyBean {
public String computeValue(String payload){
return payload.toUpperCase() + "_US";
}
}
----
@@ -91,9 +91,9 @@ You can also configure your POJO as inner bean:
[source,xml]
----
<int:header-enricher input-channel="inputChannel" output-channel="outputChannel">
<int:header name="some_header">
<bean class="org.MyEnricher"/>
</int:header>
<int:header name="some_header">
<bean class="org.MyEnricher"/>
</int:header>
</int:header-enricher>
----
@@ -102,9 +102,9 @@ as well as point to a Groovy script:
[source,xml]
----
<int:header-enricher input-channel="inputChannel" output-channel="outputChannel">
<int:header name="some_header">
<int-groovy:script location="org/SampleGroovyHeaderEnricher.groovy"/>
</int:header>
<int:header name="some_header">
<int-groovy:script location="org/SampleGroovyHeaderEnricher.groovy"/>
</int:header>
</int:header-enricher>
----
@@ -119,7 +119,7 @@ That is where SpEL shows its true power.
[source,xml]
----
<int:header-enricher input-channel="in" output-channel="out">
<int:header name="foo" expression="payload.toUpperCase() + '_US'"/>
<int:header name="foo" expression="payload.toUpperCase() + '_US'"/>
</int:header-enricher>
----
@@ -146,13 +146,13 @@ public HeaderEnricher enrichHeaders() {
@Bean
@Transformer(inputChannel="enrichHeadersChannel", outputChannel="emailChannel")
public HeaderEnricher enrichHeaders() {
Map<String, HeaderValueMessageProcessor<?>> headersToAdd = new HashMap<>();
headersToAdd.put("emailUrl", new StaticHeaderValueMessageProcessor<String>(this.imapUrl));
Expression expression = new SpelExpressionParser().parseExpression("payload.from[0].toString()");
headersToAdd.put("from",
new ExpressionEvaluatingHeaderValueMessageProcessor<>(expression, String.class));
HeaderEnricher enricher = new HeaderEnricher(headersToAdd);
return enricher;
Map<String, HeaderValueMessageProcessor<?>> headersToAdd = new HashMap<>();
headersToAdd.put("emailUrl", new StaticHeaderValueMessageProcessor<String>(this.imapUrl));
Expression expression = new SpelExpressionParser().parseExpression("payload.from[0].toString()");
headersToAdd.put("from",
new ExpressionEvaluatingHeaderValueMessageProcessor<>(expression, String.class));
HeaderEnricher enricher = new HeaderEnricher(headersToAdd);
return enricher;
}
----
@@ -205,11 +205,11 @@ This sub-element is a convenience only, and is the equivalent of specifying:
[source,xml]
----
<int:reply-channel
expression="@integrationHeaderChannelRegistry.channelToChannelName(headers.replyChannel)"
overwrite="true" />
expression="@integrationHeaderChannelRegistry.channelToChannelName(headers.replyChannel)"
overwrite="true" />
<int:error-channel
expression="@integrationHeaderChannelRegistry.channelToChannelName(headers.errorChannel)"
overwrite="true" />
expression="@integrationHeaderChannelRegistry.channelToChannelName(headers.errorChannel)"
overwrite="true" />
----
Starting with _version 4.1_, you can now override the registry's configured reaper delay, so the the channel mapping is retained for at least the specified time, regardless of the reaper delay:
@@ -217,12 +217,12 @@ Starting with _version 4.1_, you can now override the registry's configured reap
[source,xml]
----
<int:header-enricher input-channel="inputTtl" output-channel="next">
<int:header-channels-to-string time-to-live-expression="120000" />
<int:header-channels-to-string time-to-live-expression="120000" />
</int:header-enricher>
<int:header-enricher input-channel="inputCustomTtl" output-channel="next">
<int:header-channels-to-string
time-to-live-expression="headers['channelTTL'] ?: 120000" />
<int:header-channels-to-string
time-to-live-expression="headers['channelTTL'] ?: 120000" />
</int:header-enricher>
----
@@ -381,14 +381,14 @@ Through the implicitly set `reply-channel` a `User` object is returned and using
----
NOTE: The code samples shown here, are part of the _Spring
Integration Samples_ project.
Integration Samples_ project.
Please feel free to check it out at:null
_How do I pass only a subset of data to the request channel?_
Using a `request-payload-expression` attribute a single property of the payload can be passed on to the request channel instead of the full message.
In the example below on the username property is passed on to the request channel.
Keep in mind, that alwhough only the username is passed on, the resulting message send to the request channel will contain the full set of `MessageHeaders`.
Keep in mind, that although only the username is passed on, the resulting message send to the request channel will contain the full set of `MessageHeaders`.
[source,xml]
----
@@ -414,7 +414,7 @@ The reply contains a full `User` object, which is ultimately added to the `Map`
input-channel="findUserWithMapEnricherChannel"
request-channel="findUserByUsernameServiceChannel"
request-payload-expression="payload.username">
<int:property name="user" expression="payload"/>
<int:property name="user" expression="payload"/>
</int:enricher>
----

View File

@@ -1,7 +1,7 @@
[[logging-channel-adapter]]
=== Logging Channel Adapter
The `<logging-channel-adapter/>` is often used in conjunction with a Wire Tap, as discussed in<<channel-wiretap>>.
The `<logging-channel-adapter/>` is often used in conjunction with a Wire Tap, as discussed in <<channel-wiretap>>.
However, it can also be used as the ultimate consumer of any flow.
For example, consider a flow that ends with a `<service-activator/>` that returns a result, but you wish to discard that result.
To do that, you could send the result to `NullChannel`.
@@ -12,11 +12,11 @@ With a `NullChannel`, you would only see the discarded message when logging at `
----
<int:logging-channel-adapter
channel="" <1>
level="INFO" <2>
expression="" <3>
log-full-message="false" <4>
logger-name="" /> <5>
channel="" <1>
level="INFO" <2>
expression="" <3>
log-full-message="false" <4>
logger-name="" /> <5>
----

View File

@@ -40,12 +40,12 @@ A number of options are available:
@Configuration
@EnableIntegration
@EnableIntegrationManagement(
defaultLoggingEnabled = "false", <1>
defaultCountsEnabled = "false", <2>
defaultStatsEnabled = "false", <3>
countsEnabled = { "foo", "${count.patterns}" }, <4>
statsEnabled = { "qux", "!*" }, <5>
MetricsFactory = "myMetricsFactory") <6>
defaultLoggingEnabled = "false", <1>
defaultCountsEnabled = "false", <2>
defaultStatsEnabled = "false", <3>
countsEnabled = { "foo", "${count.patterns}" }, <4>
statsEnabled = { "qux", "!*" }, <5>
MetricsFactory = "myMetricsFactory") <6>
public static class ContextConfiguration {
...
}

View File

@@ -8,10 +8,10 @@ Related to the Aggregator, albeit different from a functional standpoint, is the
[[resequencer-functionality]]
==== Functionality
The Resequencer works in a similar way to the Aggregator, in the sense that it uses the CORRELATION_ID to store messages in groups, the difference being that the Resequencer does not process the messages in any way.
It simply releases them in the order of their SEQUENCE_NUMBER header values.
The Resequencer works in a similar way to the Aggregator, in the sense that it uses the `CORRELATION_ID` to store messages in groups, the difference being that the Resequencer does not process the messages in any way.
It simply releases them in the order of their `SEQUENCE_NUMBER` header values.
With respect to that, the user might opt to release all messages at once (after the whole sequence, according to the SEQUENCE_SIZE, has been released), or as soon as a valid sequence is available.
With respect to that, the user might opt to release all messages at once (after the whole sequence, according to the `SEQUENCE_SIZE`, has been released), or as soon as a valid sequence is available.
==== Configuring a Resequencer

View File

@@ -9,8 +9,8 @@ Very often, they are upstream producers in a pipeline that includes an Aggregato
==== Programming model
The API for performing splitting consists of one base class, `AbstractMessageSplitter`, which is a `MessageHandler` 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 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 ahttp://www.eaipatterns.com/DistributionAggregate.html[Composed Message Processor] scenario.
The API for performing splitting consists of one base class, `AbstractMessageSplitter`, which is a `MessageHandler` 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 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 http://www.eaipatterns.com/DistributionAggregate.html[Composed Message Processor] scenario.
An excerpt from `AbstractMessageSplitter` can be seen below:
@@ -27,7 +27,7 @@ public abstract class AbstractMessageSplitter
To implement a specific Splitter in an application, extend `AbstractMessageSplitter` and implement the `splitMessage` method, which contains logic for splitting the messages.
The return value may be one of the following:
* A `Collection` or an array of Messages, or an `Iterable` (or `Iterator`) that iterates over Messages - in this case the messages will be sent as such (after the CORRELATION_ID, SEQUENCE_SIZE and SEQUENCE_NUMBER are populated).
* A `Collection` or an array of Messages, or an `Iterable` (or `Iterator`) that iterates over Messages - 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 process.
* A `Collection` or an array of non-Message objects, or an `Iterable` (or `Iterator`) that iterates over non-Message objects - works like the prior case, except that each collection element will be used as a Message payload.
@@ -107,7 +107,7 @@ However if the custom splitter handler implementation should be scoped to a sing
<int:splitter id="testSplitter" input-channel="inChannel" method="split"
output-channel="outChannel">
<beans:bean class="org.foo.TestSplitter"/>
</int:spliter>
</int:splitter>
----
NOTE: Using both a `ref` attribute and an inner handler definition in the same `<int:splitter>` configuration is not allowed, as it creates an ambiguous condition and will result in an Exception being thrown.