Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,10 @@ be used for creating commonly used aggregation strategies without having to crea
In the route below we group all the exchanges together using
`GroupedExchangeAggregationStrategy`:

._Java-only: using GroupedExchangeAggregationStrategy_
[tabs]
====
Java::
+
[source,java]
----
from("direct:start")
Expand All @@ -126,6 +129,44 @@ from("direct:start")
.completionTimeout(500L).to("mock:result");
----

XML::
+
[source,xml]
----
<route>
<from uri="direct:start"/>
<aggregate aggregationStrategy="groupedExchangeStrategy" completionTimeout="500">
<correlationExpression>
<constant>true</constant>
</correlationExpression>
<to uri="mock:result"/>
</aggregate>
</route>
----

YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:start
steps:
- aggregate:
aggregationStrategy: groupedExchangeStrategy
completionTimeout: 500
correlationExpression:
constant:
expression: "true"
steps:
- to:
uri: mock:result
- beans:
- name: groupedExchangeStrategy
type: org.apache.camel.processor.aggregate.GroupedExchangeAggregationStrategy
----
====

As a result we have one outgoing `Exchange` being
routed to the `"mock:result"` endpoint. The exchange is a holder
containing all the incoming Exchanges.
Expand Down Expand Up @@ -238,6 +279,61 @@ be used at the same time.

Completion is mandatory and must be configured on the aggregation.

For example, to collect the order lines of each order into a List, and send the order on when it has 10 lines, or when
no new line has arrived for 5 seconds:

[tabs]
====
Java::
+
[source,java]
----
from("direct:lines")
.aggregate(header("orderId"), new GroupedBodyAggregationStrategy())
.completionSize(10)
.completionTimeout(5000)
.to("direct:order");
----

XML::
+
[source,xml]
----
<route>
<from uri="direct:lines"/>
<aggregate aggregationStrategy="groupedBodies" completionSize="10" completionTimeout="5000">
<correlationExpression>
<header>orderId</header>
</correlationExpression>
<to uri="direct:order"/>
</aggregate>
</route>
----

YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:lines
steps:
- aggregate:
correlationExpression:
header:
expression: orderId
aggregationStrategy: groupedBodies
completionSize: 10
completionTimeout: 5000
steps:
- to:
uri: direct:order
- beans:
- name: groupedBodies
type: org.apache.camel.processor.aggregate.GroupedBodyAggregationStrategy
----
====

=== Pre-completion mode

There can be use-cases where you want the incoming
Expand Down Expand Up @@ -397,7 +493,7 @@ from("direct:start")
.aggregate(header("id"), new MyAggregationStrategy())
.completionSize(10).id("myAggregator")
.aggregateController(controller)
.to("mock:aggregated");
.to("mock:result");
----

XML::
Expand All @@ -409,7 +505,7 @@ XML::
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:start"/>
<aggregate aggregationStrategy="myAppender" completionSize="10"
<aggregate id="myAggregator" aggregationStrategy="myAppender" completionSize="10"
aggregateController="myController">
<correlationExpression>
<header>id</header>
Expand All @@ -429,6 +525,7 @@ YAML::
uri: direct:start
steps:
- aggregate:
id: myAggregator
aggregateController: myController
aggregationStrategy: myAppender
completionSize: 10
Expand Down Expand Up @@ -598,9 +695,14 @@ YAML::
----
====

In Java DSL, you can also provide the bean class type directly:
You can also provide the bean class type directly.
In Java DSL you pass the class to `AggregationStrategies.bean`, and in XML or YAML DSL
you specify the bean class in `aggregationStrategy` using the `#class:` syntax as shown:

._Java-only: using AggregationStrategies.bean with class type_
[tabs]
====
Java::
+
[source,java]
----
public void configure() throws Exception {
Expand All @@ -611,10 +713,49 @@ public void configure() throws Exception {
}
----

XML::
+
[source,xml]
----
<route>
<from uri="direct:start"/>
<aggregate aggregationStrategy="#class:com.foo.MyBodyAppender" aggregationStrategyMethodName="append" completionSize="3">
<correlationExpression>
<constant>true</constant>
</correlationExpression>
<to uri="mock:result"/>
</aggregate>
</route>
----

YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:start
steps:
- aggregate:
aggregationStrategy: "#class:com.foo.MyBodyAppender"
aggregationStrategyMethodName: append
completionSize: 3
correlationExpression:
constant:
expression: "true"
steps:
- to:
uri: mock:result
----
====

And if the bean has only one method, we do not need to specify the name
of the method:

._Java-only: using AggregationStrategies.bean without method name_
[tabs]
====
Java::
+
[source,java]
----
public void configure() throws Exception {
Expand All @@ -625,33 +766,13 @@ public void configure() throws Exception {
}
----

And the `append` method could be static:

._Java-only: bean class with static method_
[source,java]
----
public class MyBodyAppender {

public static String append(String existing, String next) {
return next + existing;
}

}
----

When using XML or YAML DSL, you can also specify the bean class directly in `aggregationStrategy`
using the `#class:` syntax as shown:

[tabs]
====

XML::
+
[source,xml]
----
<route>
<from uri="direct:start"/>
<aggregate aggregationStrategy="#class:com.foo.MyBodyAppender" aggregationStrategyMethodName="append" completionSize="3">
<aggregate aggregationStrategy="#class:com.foo.MyBodyAppender" completionSize="3">
<correlationExpression>
<constant>true</constant>
</correlationExpression>
Expand All @@ -670,7 +791,6 @@ YAML::
steps:
- aggregate:
aggregationStrategy: "#class:com.foo.MyBodyAppender"
aggregationStrategyMethodName: append
completionSize: 3
correlationExpression:
constant:
Expand All @@ -681,17 +801,35 @@ YAML::
----
====

And the `append` method could be static:

._Java-only: bean class with static method_
[source,java]
----
public class MyBodyAppender {

public static String append(String existing, String next) {
return next + existing;
}

}
----

=== Aggregating when no data

When using bean as `AggregationStrategy`, then the method is
*only* invoked when there is data to be aggregated, meaning that the message body
is not `null`. In cases where you want to have the method invoked, even when there are no data (message body is `null`),
then set the `strategyMethodAllowNull` to `true`.
then set the `aggregationStrategyMethodAllowNull` to `true`.

When using beans, this can be configured a bit easier using the `beanAllowNull` method
from `AggregationStrategies` as shown:
When using beans in Java DSL, this can be configured a bit easier using the `beanAllowNull` method
from `AggregationStrategies`. In XML and YAML DSL you set the `aggregationStrategyMethodAllowNull`
option to `true`, as shown:

._Java-only: using AggregationStrategies.beanAllowNull_
[tabs]
====
Java::
+
[source,java]
----
public void configure() throws Exception {
Expand All @@ -701,6 +839,43 @@ public void configure() throws Exception {
}
----

XML::
+
[source,xml]
----
<route>
<from uri="direct:start"/>
<pollEnrich timeout="1000"
aggregationStrategy="myAppender"
aggregationStrategyMethodName="append"
aggregationStrategyMethodAllowNull="true">
<constant>seda:foo</constant>
</pollEnrich>
<to uri="mock:result"/>
</route>
----

YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:start
steps:
- pollEnrich:
expression:
constant:
expression: seda:foo
timeout: 1000
aggregationStrategy: myAppender
aggregationStrategyMethodName: append
aggregationStrategyMethodAllowNull: true
- to:
uri: mock:result
----
====

Then the `append` method in the bean would need to deal with the
situation that `newExchange` can be `null`:

Expand Down Expand Up @@ -730,11 +905,21 @@ If we didn't do this, then on timeout the append method would normally not be
invoked, meaning the xref:content-enricher.adoc[Content Enricher] did
not merge/change the message.

In XML and YAML DSL you would configure the `strategyMethodAllowNull` option and
set it to `true` as shown below:
The same works with the aggregate EIP, as shown below:

[tabs]
====
Java::
+
[source,java]
----
public void configure() throws Exception {
from("direct:start")
.aggregate(constant(true), AggregationStrategies.beanAllowNull(appender, "append"))
.completionSize(3)
.to("mock:result");
}
----

XML::
+
Expand Down Expand Up @@ -780,7 +965,7 @@ YAML::

=== Aggregating with different body types

When, for example, using `strategyMethodAllowNull` as `true`, then the
When, for example, using `aggregationStrategyMethodAllowNull` as `true`, then the
parameter type of the message bodies does not have to be the same.
For example suppose we want to aggregate from a `com.foo.User` type to a
`List<String>` that contains the name of the user. We could code a bean as follows:
Expand Down
Loading
Loading