Deleted 17-07-2016-Estilos-de-aprendizaje-e-Innovacion-educagiva.adoc

<!DOCTYPE html>

    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />

    <title>Estilos de aprendizaje e Innovación educagiva - Tecnología, Innovación y más..</title>

    <meta name="HandheldFriendly" content="True">
    <meta name="MobileOptimized" content="320">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

    <meta name="description" content="">

    <meta name="twitter:card" content="summary">
    <meta name="twitter:title" content="Estilos de aprendizaje e Innovación educagiva">
    <meta name="twitter:description" content="">

    <meta property="og:type" content="article">
    <meta property="og:title" content="Estilos de aprendizaje e Innovación educagiva">
    <meta property="og:description" content="">

    <link href="/favicon.ico" rel="shortcut icon" type="image/x-icon">
    <link href="/apple-touch-icon-precomposed.png" rel="apple-touch-icon">

    <link rel="stylesheet" type="text/css" href="//marchelo2212.github.io/themes/uno/assets/css/uno.css?v=1.0.0" />

    <link rel="canonical" href="https://marchelo2212.github.io17-07-2016-Estilos-de-aprendizaje-e-Innovacion-educagiva.adoc" />

    <meta property="og:site_name" content="Tecnología, Innovación y más.." />
    <meta property="og:type" content="article" />
    <meta property="og:title" content="Estilos de aprendizaje e Innovación educagiva" />
    <meta property="og:description" content="Dentro de las diversas acciones que un docente desarrolla en clase siempre debe tomar en cuenta los divesos estilos de aprendizaje de sus estudiantes, de esta manera podemos asegurar que cada actividad podrá generar un mejor aprendizaje en cada uno..." />
    <meta property="og:url" content="https://marchelo2212.github.io17-07-2016-Estilos-de-aprendizaje-e-Innovacion-educagiva.adoc" />
    <meta property="article:published_time" content="Invalid date" />
    <meta property="article:modified_time" content="2016-07-30T18:36:52.013Z" />
    <meta property="article:tag" content="e-learning" />
    <meta property="article:tag" content="innovación" />
    <meta property="article:tag" content="estilos de aprendizaje" />
    <meta property="article:tag" content="TIC" />
    <meta property="article:tag" content="educación" />

    <meta name="twitter:card" content="summary" />
    <meta name="twitter:title" content="Estilos de aprendizaje e Innovación educagiva" />
    <meta name="twitter:description" content="Dentro de las diversas acciones que un docente desarrolla en clase siempre debe tomar en cuenta los divesos estilos de aprendizaje de sus estudiantes, de esta manera podemos asegurar que cada actividad podrá generar un mejor aprendizaje en cada uno..." />
    <meta name="twitter:url" content="https://marchelo2212.github.io17-07-2016-Estilos-de-aprendizaje-e-Innovacion-educagiva.adoc" />

    <meta name="generator" content="Ghost ?" />
    <link rel="alternate" type="application/rss+xml" title="Tecnología, Innovación y más.." href="https://marchelo2212.github.io/rss" />
    <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/default.min.css">

Tecnología, Innovación y más..

Sitio dedicado a recopilar las cosas que he realizado en algunos lados, para poder tenerlas todas un poco ordenadas, aquí encontrarás cosas referente a:
    Software Libre - GNU / Linux
    Innovación Educativa
    Ciencia y Tecnología
    Entre otras....

Blog

                      Facebook

                      Twitter

                      Google-plus

                      LinkedIn

                      Email

        <time datetime="Invalid date" class="post-meta__date date">Invalid date</time> • on e-learning,  innovación,  estilos de aprendizaje, TIC,  educación
         by Marcelo Sotaminga

Estilos de aprendizaje e Innovación educagiva

Dentro de las diversas acciones que un docente desarrolla en clase siempre debe tomar en cuenta los divesos estilos de aprendizaje de sus estudiantes, de esta manera podemos asegurar que cada actividad podrá generar un mejor aprendizaje en cada uno de ellos.

1.[fase1]

<<#presupuesto,Presupuesto>>

[Presupuesto]

Learn how to use attributes within the link macro.

efer to Section B for more information.

[Fase 1]: Diseño de una aula smart classroom

La educación del siglo XXI se ha visto inmersa por los grandes cambios sociales que se han suscitado por la implementación de las TICs en las diversas actividades del ser humano, esto ha obligado al surgimiento de cambios en el cómo, donde, con quién, y con qué se hacen diversas
cosas u actividades.

En el sector de la educación se ha dado la apertura para de creación de nuevos recursos didácticos, en los que un factor común es el uso de la tecnología, por ende han surgido nuevos teorías, modelos o visiones del aprendizaje como son el conectivismo, flipped classroom, gamificación,mlearning, learning analytics entre otras, todas buscando lograr un mejor aprendizaje en el estudiante donde la tecnología, la pedagogía y el conocimiento se mezclen de tal manera que generen aprendizajes significativos y colaborativos para todos los participantes.

Así mismo debido al uso masivo de las TICs han aparecido nuevas competencias digitales, tipos de aprendizaje, formas de aprendizaje, etc, es así que el docente ha necesitado responderdiversas exigencias como el manejo de la tecnología, la pedagogía y el conocimiento del contenido (Modelo TPACK) y con ello han surgido nuevas necesidades dentro de los espacios donde se genera el proceso de enseñanza – aprendizaje.

El presente proyecto de aula promverá un trabajo colaborativo dentro de todos los integrantes un aula de clases, desarrollará la creatividad de los estudiantes y promoverá el liderazgo de cada uno de ellos, se lo ha diseñado de tal manera que se logren emplear metodologías educativas innovadoras y distruptivas en las que se pueda sacar el mayor provecho de las capacidades de los estudiantes, la metodología y el ambiente físico.

En vista que dentro del aula de clases se desarrolarán la mayoría de actividades académicas se ha buscado el lograr un espacio físico que facilite la interacción con las personas de una forma acogedora, pero a la vez, también nos permita generar conocimiento de una forma democrática y asimilar el mismo de igual manera.

Contextualización

La Unidad Educativa "Milenio", esta ubicada al norte de la ciudad Quito, capital de Ecuador, cuenta con un cuerpo docente de 38 docentes para las diferentes áreas del conocimiento, oferta un bachillerato unificado en ciencias y también se encuetra entre las unidades educativas con capacidad de ofertar un Bachillerato Internacional.

Esta propuesta de proyecto esta dirigida a estudiantes de nivel secundario del primer años de bachillerato, entre los 15 y 16 años de edad, para trabajar la asignatura de emprendimiento y gestión; el espacio físico tiene las dimensiones 16m de largo por 8 de ancho, cuenta con energía eléctrica, red inalámbrica interna y conexión a internet con uan velocidad de 10mbps.

Este espacio físico se lo contruyó con las siguientes características:

Puerta estilo francesa.

Ventanales de 3m en cada pared

Vídrios templado transparentes

Multiples tomas correinte tanto en paredes como techo.

Pizarra para marcador líquido

Mueblés stándar de clase (sella y mesas individual) estudiante.

Escritio y silla para el docente.

Libreros, casilleros para los estudiantes

Proyector

Sistema de audio (parlantes)

Un computador para el docente con sistema windows 8.1

De esta manera este espacio posee las carácterísitcas comunes al compararla con otras aulas de clase de la institución; sin embargo gracias a la gestión realizada por parte de las autoridades se ha logrado un fondo de 3200 usd, para la aducación de este espacio y tranformarlo en una smarth class acorde las necesidades de la misma y posibilidades ya existentes.

De esta manera el actual proyecto propone un rediseño interno del aula de clase y una  optimización del espacio, buscando el mejorar el desempeño de cada participate del proceso

Transformando el aula de clase a una Smarth ClassRoom

Al querer tranformar este espacio es necesario buscar una integracion del espacio con la tecnología, acorde  lo mencionado por Gros, 2000 y 2004;
Hutchings y Standley, (2000) donde defienden, a partir de sus ideas y reflexiones, que en una smart classroom debería asociarse

“… una integración invisible de la tecnología en el espacio de aprendizaje.”

Debtro de una smarth Classroom se busca la  intersección de tres elementos que interactúan en el diseño del espacio de aprendizaje:

El diseño arquitectónico y la ergonomía del aula, poseer mobiliario e
instrumentos que faciliten el trabajo dentro del aula, la creatividad y colaboración.

La integración de la tecnología de manera: funcional, invisible, justificada e
intensiva

Una metodología didáctica: innovadora, disruptiva y oblicua; adecuada a este
espacio con la finalidad de hacer más eficiente y satisfactorio el proceso de
aprendizaje.

Para poder considerarse una Smart classroom necesariamente deberá poseer ciertas
características didácticas como son:

Flexibilidad en la estructura física

Adaptabilidad

Confortabilidad

Riqueza y variabilidad

Conectividad

Personalización

Por todo esto se ha planteado el siguiente plano de la clase en la que se pueden evidenciar los cambios que se necesitrarían.

De esta manera los cambios que se realizarán son los siguientes:

Aula cuenta con una PDI (Pizarra Digital Interactiva), de bajo costo, ya que se la realizo con el proyecto de Jonny Lee Chunlee,

Usar sistema operativos GNU/Linux Edubuntu, ya que posee gran cantidad de software educativo didáctivo.

Incorporar mesas para trabajo grupal

Agregar computadores, core I3 con sistema operativo Edubunto

Incorporar tablets

Generar un espacios que promuevan la creatividad y el trabajo colaborativo.

Se ha planeado para realizar trabajado en grupos de 4 estudiantes, en el caso de ser más se podrán dar uso a puf ubicados alrededor, se cuenta con dos áreas bien limitadas, el área "académcia", donde se realizá en su mayoría el proceso de enseñana aprendizaje guiada por el docente/facilitador y el segundo "recreativo"donde se podrá continuar con este proceso de una manera menos formal y más libre.

Se ha generado estos espacios con el fin de que el estudiante logre identificar cada área y que logre trabajar de diferente manera en cada una, es decir, en el área "académica" se busca dirigir la atención a que el estudiante comprenda las directrices planteadas y/o conocimiento s necesarios para realizar las actividades.

Por otro lado en el área recreativa el estudiante podrá relajarse y sentirse libres el la convivencia con sus compañeros,interactuando y trabajando colaborativamente desde diversos puntos de esta área.

también se han ubicado áreas para la ubicación de materiales del estudiante (pertenencias) y otro de materiales del Aula (Librero, armario), así mismo se ha instalado una impresora inalámbrica para poder tener impreso o imprimir cualquier documentación que se necesite.

También se cuenta con una mesa principal que permitirá tener un espacio para trabajar entre todos, así cada estudiante podrá construir su conocimiento y aportar al del resto  y esto facilitará la flexión, análisis y síntesis de toda la información/concimeinto y resolver infinidad de retos.

El docente/facilitador cuenta con su espacio ubicado de tal manera que le sea fácil dirigirse al grupo y verificar el desarrollo de las actividades o planificar las mismas. Una las de las carácterísitcas de todo el inmobiliario es que puede desplazarse con facilidad, ya que posee ruedas en cada pata.

Para visializar en 3D esta aula por favor visite este link:

mapa 3D Smarth ClassRoom

Presupuesto

Es necesario dar todo el uso posible al inmobiliario ya existe al igual que a la tecnología que posee ya el aula de clase por ello se propone:

Table 1. Tabla de presupuesto

<colgroup>
<col>
<col>
<col>
<col>
</colgroup>

Cantidad
Descripción
Valor Individual
Valor Total

Total

3274

16

Sillas giratorias

20

320

4

Mesas para trabajo grupal 6 personas

70

280

5

Laptos Core I3

250

1250

5

Tablets

100

500

2

Sofas

130

260

8

Puf – cojines

15

120

1

Mesa grupal grande

130

130

1

Impresora multifunción (copiadora, escanner e impresota)

150

150

2

Alfombras

120

240

1

Dispensador de agua caliente/fria

24

24

Este valor de 3274 dólares es el cambio del euro (3000) a dolar.

    Please enable JavaScript to view the comments powered by Disqus.
    comments powered by Disqus

                © 2016. All rights reserved.
                Uno theme by Dale-Anthony
                Proudly published with Hubpress


coherence.adoc

coherence.adoc

[[bucket4j-coherence, Bucket4j-Coherence]]
=== Oracle Coherence integration
==== Dependencies
To use ``bucket4j-coherence`` extension you need to add the following dependency:
[source, xml, subs=attributes+]
----
<dependency>
    <groupId>com.github.vladimir-bukhtoyarov</groupId>
    <artifactId>bucket4j-coherence</artifactId>
    <version>{revnumber}</version>
</dependency>
----

==== Example of Bucket instantiation
[source, java]
----
com.tangosol.net.NamedCache<K, byte[]> cache = ...;
private static final CoherenceProxyManager<K> proxyManager = new CoherenceProxyManager(map);

...
BucketConfiguration configuration = BucketConfiguration.builder()
    .addLimit(Bandwidth.simple(1_000, Duration.ofMinutes(1)))
    .build(key, configuration);

Bucket bucket = proxyManager.builder().build(configuration);
----

==== Configuring POF serialization for Bucket4j library classes
If you configure nothing, then by default Java serialization will be used for serialization Bucket4j library classes. Java serialization can be rather slow and should be avoided in general.
``Bucket4j`` provides https://docs.oracle.com/cd/E24290_01/coh.371/e22837/api_pof.htm#COHDG1363[custom POF serializers] for all library classes that could be transferred over the network.
To let Coherence know about POF serializers you should register three serializers in the POF configuration config file:
====
``io.github.bucket4j.grid.coherence.pof.CoherenceEntryProcessorPofSerializer`` for class ``io.github.bucket4j.grid.coherence.CoherenceProcessor``
====

.Example of POF serialization config:
[source, xml]
----
<pof-config xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config coherence-pof-config.xsd">

    <user-type-list>
        <!-- Include default Coherence types -->
        <include>coherence-pof-config.xml</include>

        <!-- Define serializers for Bucket4j classes -->
        <user-type>
            <type-id>1001</type-id>
            <class-name>io.github.bucket4j.grid.coherence.CoherenceProcessor</class-name>
            <serializer>
                <class-name>io.github.bucket4j.grid.coherence.pof.CoherenceEntryProcessorPofSerializer</class-name>
            </serializer>
        </user-type>
    </user-type-list>
</pof-config>
----
Double-check with https://docs.oracle.com/cd/E24290_01/coh.371/e22837/api_pof.htm#COHDG5182[official Oracle Coherence documentation] in case of any questions related to ``Portable Object Format``.

[[bucket4j-coherence, Bucket4j-Coherence]]
=== Oracle Coherence integration
==== Dependencies
To use ``bucket4j-coherence`` extension you need to add following dependency:
[source, xml, subs=attributes+]
----
<dependency>
    <groupId>com.github.vladimir-bukhtoyarov</groupId>
    <artifactId>bucket4j-coherence</artifactId>
    <version>{revnumber}</version>
</dependency>
----

==== Example of Bucket instantiation
[source, java]
----
com.tangosol.net.NamedCache<K, byte[]> cache = ...;
private static final CoherenceProxyManager<K> proxyManager = new CoherenceProxyManager(map);

...
BucketConfiguration configuration = BucketConfiguration.builder()
    .addLimit(Bandwidth.simple(1_000, Duration.ofMinutes(1)))
    .build(key, configuration);

Bucket bucket = proxyManager.builder().build(configuration);
----

==== Configuring POF serialization for Bucket4j library classes
If you configure nothing, then by default Java serialization will be used for serialization Bucket4j library classes. Java serialization can be rather slow and should be avoided in general.
``Bucket4j`` provides https://docs.oracle.com/cd/E24290_01/coh.371/e22837/api_pof.htm#COHDG1363[custom POF serializers] for all library classes that could be transferred over network.
To let Coherence know about POF serializers you should register three serializers in the POF configuration config file:
====
``io.github.bucket4j.grid.coherence.pof.CoherenceEntryProcessorPofSerializer`` for class ``io.github.bucket4j.grid.coherence.CoherenceProcessor``
====

.Example of POF serialization config:
[source, xml]
----
<pof-config xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config coherence-pof-config.xsd">

    <user-type-list>
        <!-- Include default Coherence types -->
        <include>coherence-pof-config.xml</include>

        <!-- Define serializers for Bucket4j classes -->
        <user-type>
            <type-id>1001</type-id>
            <class-name>io.github.bucket4j.grid.coherence.CoherenceProcessor</class-name>
            <serializer>
                <class-name>io.github.bucket4j.grid.coherence.pof.CoherenceEntryProcessorPofSerializer</class-name>
            </serializer>
        </user-type>
    </user-type-list>
</pof-config>
----
Double check with https://docs.oracle.com/cd/E24290_01/coh.371/e22837/api_pof.htm#COHDG5182[official Oracle Coherence documentation] in case of any questions related to ``Portable Object Format``.


Update 2016-05-22-Facebook-hacker-cup-Power-Overwhelming.adoc

= Facebook hacker cup: Power Overwhelming
:hp-tags: competitions, migrated

You are to inflict maximum damage to the zerg army. There are two types of units - Warrior and Shield. Warriors do damage every second, while a shield protects your entire army for one second. Your army is instantly overrun after the shield generators expire. Given \(G\) cost to build a shield, \(W\) cost to build a warrior and total money \(M\), how many shields would you build?

=== Solution

Let \(X\) and \(Y\) be the optimal number of generators and number of warriors to be built, respectively. Let's start with a simple concrete example. Suppose shields and warriors both cost 1 unit and you have total money of 5 units. Also assume 1 unit of damage per warrior. What is the optimum value of \(X\) and \(Y\)? It would be optimum if you can inflict maximum damage. With 5 units of money, you can buy shields/warriors in the following combinations.

.Combinations of \(X, Y\)
|===
|X |Y |Damage

|1
|4
|4

|2
|3
|6

|3
|2
|6

|4
|1
|4
|===

In this case, the optimal choice of \(X, Y\) seem to be \((2, 3)\) and \((3, 4)\) respectively, both of which maximize the product \(XY\). In the general case, the cost to buy \(X\) generators is \(XG\), cost to buy \(Y\) warriors is \(YW\). Since we are limited by \(M\) amount of money, \(X, Y\) must satisfy \(XG + YW \le M\). This can be represented as a line and the inequality encapsulates a region for candidate \((X, Y)\) values.

.Candidate solution region
image::post2/fig1.png[]

We want \(X, Y \mid \arg\max{XY} \). Geometrically, \(XY\) represents the area of the rectangle shaded in blue.

.The area to be maximized
image::post2/fig2.png[]

We need to find integer values of \(X, Y\) that maximize this area.

How do we go about doing that?
We know that the line will intersect X and Y axis at \(M/G, M/W\).
We also know that the optimal rectangle touches the line. If it doesn't, the area can be trivially increased by increasing either/both \(X, Y\) values until it touches the line.

The boring calculus way for figuring this out is as follows:

\(A = XY \\
A = \frac{M - YW}{G}Y \\
\\
\frac{\partial A}{\partial Y} = \frac{Y(M - WY)}{G} \\
\arg\max{A} \implies \frac{Y(M - WY)}{G} = 0 \\
Y = M / 2W \)

This gives corresponding \(X = M/2G\)

A more interesting way to arrive at the same conclusion would be to think as follows:
- The shaded triangle increases its area as long as X and Y increase.
- Start with \((0, 0)\) and increase both \(X, Y\) by 1. This gives us a small rectangle with bottom left \((0, 0)\) and top right \((1, 1)\).
- If the straight line was X + Y = 1, it would be a right angled isosceles triangle. The \(X, Y\) value would always increase in the direction of line \(Y = X\), which would cut the line in middle at \((X/2, Y/2)\)
- Generalizing this, the value of \(X. Y\) will increase as long as we go on the direction of line that joins \((0, 0)\) to midpoint of the line \(XG + YW = M\). The mid point of this line is, unsurprisingly, \(M/2G, M/2W)\)

There are other ways to arrive at this. Perhaps I should write a post that exclusively deals with this problem.

Coming back to our original question, the optimal number of shields must be \(M/2G\). If, \(M/2G\) is not an integer, we go towards the origin on the line that joins \((0, 0)\) and \(M/2G, M/2W)\). However,I was able to get away by taking \(\lfoor M/2G \rfloor\).


Update 2016-05-26-Clever-Clouds-CEO-to-speak-at-Lunatech.adoc

# Clever Cloud’s CEO to speak at Lunatech

:published_at: 2016-05-26
:hp-tags: company

Friday 27 May 2016 Clever Cloud’s CEO, *Quentin Adam*, will be visiting Lunatech where he will give a presentation about using Clever Cloud with Scala.

Clever Cloud is a “Europe-based PaaS company” that helps “developers deploy and run their apps with bulletproof infrastructure, automatic scaling, fair pricing” and aims “to make an easy-to-use service, without any vendor lock-in”.

Due to his experience at Clever Cloud — where he can work a wide range of technologies and tools — he has a lot of knowledge and is able to speak about many different subjects. He regularly speaks at various tech conferences.

We are opening up the presentation to everyone. Feel free to join us at 16:00.

# Clever Cloud’s CEO to speak at Lunatech

:published_at: 2016-01-25
:hp-tags: company

Friday 27 May 2016 Clever Cloud’s CEO, *Quentin Adam*, will be visiting Lunatech where he will give a presentation about using Clever Cloud with Scala.

Clever Cloud is a “Europe-based PaaS company” that helps “developers deploy and run their apps with bulletproof infrastructure, automatic scaling, fair pricing” and aims “to make an easy-to-use service, without any vendor lock-in”.

Due to his experience at Clever Cloud — where he can work a wide range of technologies and tools — he has a lot of knowledge and is able to speak about many different subjects. He regularly speaks at various tech conferences.

We are opening up the presentation to everyone. Feel free to join us at 16:00.


CAMEL-16861: Cleanup docs

CAMEL-16861: Cleanup docs

= Aggregate EIP
:doctitle: Aggregate
:shortname: aggregate
:description: Aggregates many messages into a single message
:since:
:supportlevel: Stable

The
http://www.enterpriseintegrationpatterns.com/Aggregator.html[Aggregator]
from the xref:enterprise-integration-patterns.adoc[EIP patterns] allows
you to combine a number of messages together into a single message.

How do we combine the results of individual, but related messages so that they can be processed as a whole?

image::eip/Aggregator.gif[image]

Use a stateful filter, an Aggregator, to collect and store individual messages until a complete set of related messages has been received. Then, the Aggregator publishes a single message distilled from the individual messages.

The aggregator is one of the most complex EIP and has many features and configurations.

The logic for combing messages together is _correlated_ in buckets based on a _correlation key_.
Messages with the same correlation key is aggregated together, using an `AggregationStrategy`.

== Aggregate options

// eip options: START
include::partial$eip-options.adoc[]
// eip options: END

== Worker pools

The aggregate EIP will always use a worker pool, that is used to process all the outgoing messages from the aggregator.
The worker pool is determined accordingly:

- If a custom `ExecutorService` has been configured, then this is used as worker pool.
- If `parallelProcessing=true` then a _default_ worker pool (is 10 worker threads by default) is created.
However, the thread pool size and other configurations can be configured using _thread pool profiles_.
- Otherwise, a single threaded worker pool is created.

== Aggregating

The `AggregationStrategy` is used for aggregating the old, and the new exchanges together into a single exchange;
that becomes the next old, when the next message is aggregated, and so forth.

Possible implementations include performing some kind of combining or
delta processing, such as adding line items together into an invoice or
just using the newest exchange and removing old exchanges such as for
state tracking or market data prices; where old values are of little
use.

Notice the aggregation strategy is a mandatory option and must be
provided to the aggregator.

IMPORTANT: In the aggregate method, do not create a new exchange instance to return,
instead return either the old or new exchange from the input parameters;
favor returning the old exchange whenever possible.

Here are a few example `AggregationStrategy` implementations that should
help you create your own custom strategy.

[source,java]
----
//simply combines Exchange String body values using '+' as a delimiter
class StringAggregationStrategy implements AggregationStrategy {

    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
        if (oldExchange == null) {
            return newExchange;
        }

        String oldBody = oldExchange.getIn().getBody(String.class);
        String newBody = newExchange.getIn().getBody(String.class);
        oldExchange.getIn().setBody(oldBody + "+" + newBody);
        return oldExchange;
    }
}

//simply combines Exchange body values into an ArrayList<Object>
class ArrayListAggregationStrategy implements AggregationStrategy {

    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
        Object newBody = newExchange.getIn().getBody();
        ArrayList<Object> list = null;
        if (oldExchange == null) {
            list = new ArrayList<Object>();
            list.add(newBody);
            newExchange.getIn().setBody(list);
            return newExchange;
        } else {
            list = oldExchange.getIn().getBody(ArrayList.class);
            list.add(newBody);
            return oldExchange;
        }
    }
}
----

TIP: The `org.apache.camel.builder.AggregationStrategies` is a builder that can
be used for creating commonly used aggregation strategies without having to create a class.

=== Exchange Properties

The completed (outgoing) exchange from the Aggregate EIP contains the following information
as exchange properties, allowing you to know how the exchange was completed, and how
many messages were combined.

[width="100%",cols="3,1m,6",options="header"]
|=======================================================================
| Property | Type | Description
| `CamelAggregatedSize` | `int` | The total number of messages aggregated.
| `CamelAggregatedCompletedBy` | `String` | The condition that triggered the completion. Possible values are size, timeout, interval, predicate, force, strategy, and consumer. The consumer value represents the completion from batch consumer.
| `CamelAggregatedCorrelationKey` | `String` | The correlation identifier as a `String`.
| `CamelAggregatedTimeout` | `long` | The time-out in milliseconds as set by the completion time-out.
|=======================================================================

=== Aggregate by grouping exchanges

In the route below we group all the exchanges together using
`GroupedExchangeAggregationStrategy`:

[source,java]
----
from("direct:start")
    // aggregate all using same expression and group the
    // exchanges so we get one single exchange containing all
    // the others
    .aggregate(new GroupedExchangeAggregationStrategy()).constant(true)
    // wait for 0.5 seconds to aggregate
    .completionTimeout(500L).to("mock:result");
----

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.

The output of the aggregator will then contain the exchanges grouped
together in a list as shown below:

[source,java]
----
List<Exchange> grouped = exchange.getMessage().getBody(List.class);
----

=== Aggregating into a List

If you want to aggregate some value from the messages `<V>` into a `List<V>`
then you can use the
`org.apache.camel.processor.aggregate.AbstractListAggregationStrategy`
abstract class.

The completed Exchange that is sent out of the aggregator will contain the `List<V>` in
the message body.

For example to aggregate a `List<Integer>` you can extend this class as
shown below, and implement the `getValue` method:

[source,java]
----
public class MyListOfNumbersStrategy extends AbstractListAggregationStrategy<Integer> {

    @Override
    public Integer getValue(Exchange exchange) {
        // the message body contains a number, so just return that as-is
        return exchange.getIn().getBody(Integer.class);
    }
}
----

The `org.apache.camel.builder.AggregationStrategies` is a builder that can
be used for creating commonly used aggregation strategies without having to create a class.

The previous example can also be built using the builder as shown:

[source,java]
----
AggregationStrategy agg = AggregationStrategies.flexible(Integer.class)
    .accumulateInCollection(ArrayList.class)
    .pick(body());
----

=== Aggregating on timeout

If your aggregation strategy implements
`TimeoutAwareAggregationStrategy`, then Camel will invoke the `timeout`
method when the timeout occurs. Notice that the values for index and
total parameters will be -1, and the timeout parameter will be provided
only if configured as a fixed value. You must *not* throw any exceptions
from the `timeout` method.

=== Aggregate with persistent repository

The aggregator provides a pluggable repository which you can implement
your own `org.apache.camel.spi.AggregationRepository`.

If you need persistent repository then Camel provides numerous implementations, such as from the
xref:ROOT:caffeine-cache-component.adoc[Caffeine],
xref:ROOT:cql-component.adoc[CassandraQL],
xref:ROOT:ehcache-component.adoc[EHCache],
xref:ROOT:infinispan-component.adoc[Infinispan],
xref:ROOT:jcache-component.adoc[JCache],
xref:others:leveldb.adoc[LevelDB],
xref:others:redis.adoc[Redis],
or xref:ROOT:sql-component.adoc[SQL] components.

== Completion

When aggregation xref:manual::exchange.adoc[Exchange]s at some point you need to
indicate that the aggregated exchanges is complete, so they can be sent
out of the aggregator. Camel allows you to indicate completion in
various ways as follows:

* _completionTimeout_ - Is an inactivity timeout in which is triggered if
no new exchanges have been aggregated for that particular correlation
key within the period.
* _completionInterval_ - Once every X period all the current aggregated
exchanges are completed.
* _completionSize_ - Is a number indicating that after X aggregated
exchanges its complete.
* _completionPredicate_ - Runs a xref:manual::predicate.adoc[Predicate] when a new
exchange is aggregated to determine if we are complete or not.
The configured aggregationStrategy can implement the
Predicate interface and will be used as the completionPredicate if no
completionPredicate is configured. The configured aggregationStrategy can
override the `preComplete` method and will be used as
the completionPredicate in pre-complete check mode. See further below
for more details.
* _completionFromBatchConsumer_ - Special option for
xref:manual::batch-consumer.adoc[Batch Consumer] which allows you to complete
when all the messages from the batch has been aggregated.
* _forceCompletionOnStop_ - Indicates to complete all current
aggregated exchanges when the context is stopped
* _AggregateController_ - which allows to use an external source (`AggregateController` implementation) to complete groups or all groups.
This can be done using Java or JMX API.

All the different completions are per correlation key. You can
combine them in any way you like. It's basically the first which
triggers that wins. So you can use a completion size together with a
completion timeout. Only completionTimeout and completionInterval cannot
be used at the same time.

Completion is mandatory and must be configured on the aggregation.

=== Pre-completion mode

There can be use-cases where you want the incoming
xref:manual::exchange.adoc[Exchange] to determine if the correlation group
should pre-complete, and then the incoming
xref:manual::exchange.adoc[Exchange] is starting a new group from scratch.
The pre-completion mode must be enabled by the `AggregationStrategy` by overriding the `canPreComplete` method
to return a `true` value.

When pre completion is enabled then the `preComplete` method is invoked:

[source,java]
----
/**
 * Determines if the aggregation should complete the current group, and start a new group, or the aggregation
 * should continue using the current group.
 *
 * @param oldExchange the oldest exchange (is <tt>null</tt> on first aggregation as we only have the new exchange)
 * @param newExchange the newest exchange (can be <tt>null</tt> if there was no data possible to acquire)
 * @return <tt>true</tt> to complete current group and start a new group, or <tt>false</tt> to keep using current
 */
boolean preComplete(Exchange oldExchange, Exchange newExchange);
----

If the `preComplete` method returns `true`, then the existing correlation groups is
completed (without aggregating the incoming exchange (`newExchange`).
Then the `newExchange` is used to start the correlation group from scratch,
so the group would contain only that new incoming exchange. This is
known as pre-completion mode.

When the aggregation is in _pre-completion_ mode, then only the following completions are in use:

* _completionTimeout_ or _completionInterval_ can also be used as fallback
completions
* any other completion are not used (such as by size, from batch consumer etc)
* _eagerCheckCompletion_ is implied as `true`, but the option has no effect

=== CompletionAwareAggregationStrategy

If your aggregation strategy implements
`CompletionAwareAggregationStrategy`, then Camel will invoke the
`onComplete` method when the aggregated `Exchange` is completed. This
allows you to do any last minute custom logic such as to clean up some
resources, or additional work on the exchange as it's now completed.
You must *not* throw any exceptions from the `onCompletion` method.

=== Completing current group decided from the AggregationStrategy

The `AggregationStrategy` supports checking for the

the exchange property (`Exchange.AGGREGATION_COMPLETE_CURRENT_GROUP`)
on the returned `Exchange` that contains a boolean to indicate if the current
group should be completed. This allows to overrule any existing
completion predicates / sizes / timeouts etc, and complete the group.

For example the following logic will complete the
group if the message body size is larger than 5. This is done by setting
the exchange property `Exchange.AGGREGATION_COMPLETE_CURRENT_GROUP` to `true`.

[source,java]
----
public final class MyCompletionStrategy implements AggregationStrategy {
    @Override
    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
        if (oldExchange == null) {
            return newExchange;
        }
        String body = oldExchange.getIn().getBody(String.class) + "+"
            + newExchange.getIn().getBody(String.class);
        oldExchange.getIn().setBody(body);
        if (body.length() >= 5) {
            oldExchange.setProperty(Exchange.AGGREGATION_COMPLETE_CURRENT_GROUP, true);
        }
        return oldExchange;
    }
}
----

=== Completing all previous group decided from the AggregationStrategy

The `AggregationStrategy` checks an exchange property, from the returned exchange,
indicating if all previous groups should be completed.

This allows to overrule any existing
completion predicates / sizes / timeouts etc, and complete all the existing
previous group.

The following logic will complete all the
previous groups, and start a new aggregation group.

This is done by setting the property `Exchange.AGGREGATION_COMPLETE_ALL_GROUPS` to `true`
on the returned exchange.

[source,java]
----
public final class MyCompletionStrategy implements AggregationStrategy {
    @Override
    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
        if (oldExchange == null) {
            // we start a new correlation group, so complete all previous groups
            newExchange.setProperty(Exchange.AGGREGATION_COMPLETE_ALL_GROUPS, true);
            return newExchange;
        }

        String body1 = oldExchange.getIn().getBody(String.class);
        String body2 = newExchange.getIn().getBody(String.class);

        oldExchange.getIn().setBody(body1 + body2);
        return oldExchange;
    }
}
----

=== Manually force the completion of all aggregated Exchanges immediately

You can manually trigger completion of all current aggregated exchanges
by sending an exchange containing the exchange property
`Exchange.AGGREGATION_COMPLETE_ALL_GROUPS` set to `true`. The message is
considered a signal message only, the message headers/contents will not
be processed otherwise.

You can alternatively set the exchange property
`Exchange.AGGREGATION_COMPLETE_ALL_GROUPS_INCLUSIVE` to `true` to trigger
completion of all groups after processing the current message.

=== Using a controller to force the aggregator to complete

The `org.apache.camel.processor.aggregate.AggregateController` allows
you to control the aggregate at runtime using Java or JMX API. This can
be used to force completing groups of exchanges, or query its current
runtime statistics.

The aggregator provides a default implementation if no custom have been
configured, which can be accessed using `getAggregateController()` method.
Though it may be easier to configure a controller in the route using
`aggregateController` as shown below:

[source,java]
----
private AggregateController controller = new DefaultAggregateController();

from("direct:start")
   .aggregate(header("id"), new MyAggregationStrategy())
      .completionSize(10).id("myAggregator")
      .aggregateController(controller)
      .to("mock:aggregated");
----

Then there is API on `AggregateController` to force completion. For
example to complete a group with key foo:

[source,java]
----
int groups = controller.forceCompletionOfGroup("foo");
----

The returned value is the number of groups completed.
A value of 1 is returned if the foo group existed, otherwise 0 is returned.

There is also a method to complete all groups:

[source,java]
----
int groups = controller.forceCompletionOfAllGroups();
----

The controller can also be used in XML DSL using the `aggregateControllerRef` to
refer to a bean with the controller implementation, which is looked up in the registry.

When using Spring XML you can create the bean with `<bean>` as shown:

[source,xml]
----
<bean id="myController" class="org.apache.camel.processor.aggregate.DefaultAggregateController"/>

<camelContext xmlns="http://camel.apache.org/schema/spring">
    <route>
        <from uri="direct:start"/>
        <aggregate strategyRef="myAppender" completionSize="10"
                   aggregateControllerRef="myController">
            <correlationExpression>
                <header>id</header>
            </correlationExpression>
            <to uri="mock:result"/>
        </aggregate>
    </route>
</camelContext>
----

There is also JMX API on the aggregator which is available under the processors node in the Camel JMX tree.

== Aggregating with Beans

To use the `AggregationStrategy` you had to implement the
`org.apache.camel.AggregationStrategy` interface,
which means your logic would be tied to the Camel API.
You can use a bean for the logic and let Camel adapt to your
bean. To use a bean a convention must be followed:

* there must be a public method to use
* the method must not be void
* the method can be static or non-static
* the method must have 2 or more parameters
* the parameters are paired, so the first half is applied to the
`oldExchange`, and the reminder half is for the `newExchange`.
 Therefore, there must be an equal number of parameters, eg 2, 4, 6 etc.

The paired methods is expected to be ordered as follows:

* the first parameter is the message body
* optional, the 2nd parameter is a `Map` of the headers
* optional, the 3rd parameter is a `Map` of the exchange properties

This convention is best explained with some examples.

In the method below, we have only 2 parameters, so the 1st parameter is
the body of the `oldExchange`, and the 2nd is paired to the body of the
`newExchange`:

[source,java]
----
public String append(String existing, String next) {
    return existing + next;
}
----

In the method below, we have only 4 parameters, so the 1st parameter is
the body of the `oldExchange`, and the 2nd is the `Map` of the
`oldExchange` headers, and the 3rd is paired to the body of the `newExchange`,
and the 4th parameter is the `Map` of the `newExchange` headers:

[source,java]
----
public String append(String existing, Map existingHeaders, String next, Map nextHeaders) {
    return existing + next;
}
----

And finally if we have 6 parameters, that includes the exchange properties:

[source,java]
----
public String append(String existing, Map existingHeaders, Map existingProperties,
                     String next, Map nextHeaders, Map nextProperties) {
    return existing + next;
}
----

To use this with the aggregate EIP we can use a bean with the aggregate logic as follows:

[source,java]
----
public class MyBodyAppender {

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

}
----

And then in the Camel route we create an instance of our bean, and then
refer to the bean in the route using `bean` method from
`org.apache.camel.builder.AggregationStrategies` as shown:

[source,java]
----
private MyBodyAppender appender = new MyBodyAppender();

public void configure() throws Exception {
    from("direct:start")
        .aggregate(constant(true), AggregationStrategies.bean(appender, "append"))
            .completionSize(3)
            .to("mock:result");
}
----

We can also provide the bean class type directly:

[source,java]
----
public void configure() throws Exception {
    from("direct:start")
        .aggregate(constant(true), AggregationStrategies.bean(MyBodyAppender.class, "append"))
            .completionSize(3)
            .to("mock:result");
}
----

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

[source,java]
----
public void configure() throws Exception {
    from("direct:start")
        .aggregate(constant(true), AggregationStrategies.bean(MyBodyAppender.class))
            .completionSize(3)
            .to("mock:result");
}
----

And the `append` method could be static:

[source,java]
----
public class MyBodyAppender {

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

}
----

If you are using XML DSL then we need to declare a `<bean>` with the bean:

[source,xml]
----
<bean id="myAppender" class="com.foo.MyBodyAppender"/>
----

And in the Camel route we use `strategyRef` to refer to the bean by its
id, and the `strategyMethodName` can be used to define the method name
to call:

[source,xml]
----
<camelContext xmlns="http://camel.apache.org/schema/spring">
    <route>
        <from uri="direct:start"/>
        <aggregate strategyRef="myAppender" strategyMethodName="append" completionSize="3">
            <correlationExpression>
                <constant>true</constant>
            </correlationExpression>
            <to uri="mock:result"/>
        </aggregate>
    </route>
</camelContext>
----

When using XML DSL you can also specify the bean class directly in `strategyRef`
using the `#class:` syntax as shown:

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

You can use this in XML DSL when you are not using the classic Spring XML files;
where you use XML only for Camel routes.

=== 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`.

When using beans this can be configured a bit easier using the `beanAllowNull` method
from `AggregationStrategies` as shown:

[source,java]
----
public void configure() throws Exception {
    from("direct:start")
        .pollEnrich("seda:foo", 1000, AggregationStrategies.beanAllowNull(appender, "append"))
            .to("mock:result");
}
----

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

[source,java]
----
public class MyBodyAppender {

    public String append(String existing, String next) {
        if (next == null) {
            return "NewWasNull" + existing;
        } else {
            return existing + next;
        }
    }

}
----

In the example above we use the xref:content-enricher.adoc[Content Enricher]
EIP using `pollEnrich`. The `newExchange` will be `null` in the
situation we could not get any data from the "seda:foo" endpoint, and
a timeout was hit after 1 second.

So if we need to do special merge logic we would need to set `setAllowNullNewExchange=true`.
If we don'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 DSL you would configure the `strategyMethodAllowNull` option and
set it to `true` as shown below:

[source,xml]
----
<camelContext xmlns="http://camel.apache.org/schema/spring">
    <route>
        <from uri="direct:start"/>
        <aggregate strategyRef="myAppender"
                   strategyMethodName="append"
                   strategyMethodAllowNull="true"
                   completionSize="3">
            <correlationExpression>
                <constant>true</constant>
            </correlationExpression>
            <to uri="mock:result"/>
        </aggregate>
    </route>
</camelContext>
----

=== Aggregating with different body types

When for example using `strategyMethodAllowNull` as `true`, then the
parameter types 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:

[source,java]
----
public final class MyUserAppender {

    public List addUsers(List names, User user) {
        if (names == null) {
            names = new ArrayList();
        }
        names.add(user.getName());
        return names;
    }
}
----

Notice that the return type is a `List` which we want to contain the name of the users.
The 1st parameter is the `List` of names, and the 2nd parameter is the incoming `com.foo.User` type.

= Aggregate EIP
:doctitle: Aggregate
:shortname: aggregate
:description: Aggregates many messages into a single message
:since:
:supportlevel: Stable

The
http://www.enterpriseintegrationpatterns.com/Aggregator.html[Aggregator]
from the xref:enterprise-integration-patterns.adoc[EIP patterns] allows
you to combine a number of messages together into a single message.

image::eip/Aggregator.gif[image]

The aggregator is one of the most complex EIP and has many features and configurations.

The logic for combing messages together is _correlated_ in buckets based on a _correlation key_.
Messages with the same correlation key is aggregated together, using an `AggregationStrategy`.

== Aggregator options

// eip options: START
include::partial$eip-options.adoc[]
// eip options: END

== Worker pools

The aggregate EIP will always use a worker pool, that is used to process all the outgoing messages from the aggregator.
The worker pool is determined accordingly:

- If a custom `ExecutorService` has been configured, then this is used as worker pool.
- If `parallelProcessing=true` then a _default_ worker pool (is 10 worker threads by default) is created.
However, the thread pool size and other configurations can be configured using _thread pool profiles_.
- Otherwise, a single threaded worker pool is created.

== Aggregating

The `AggregationStrategy` is used for aggregating the old, and the new exchanges together into a single exchange;
that becomes the next old, when the next message is aggregated, and so forth.

Possible implementations include performing some kind of combining or
delta processing, such as adding line items together into an invoice or
just using the newest exchange and removing old exchanges such as for
state tracking or market data prices; where old values are of little
use.

Notice the aggregation strategy is a mandatory option and must be
provided to the aggregator.

IMPORTANT: In the aggregate method, do not create a new exchange instance to return,
instead return either the old or new exchange from the input parameters;
favor returning the old exchange whenever possible.

Here are a few example `AggregationStrategy` implementations that should
help you create your own custom strategy.

[source,java]
----
//simply combines Exchange String body values using '+' as a delimiter
class StringAggregationStrategy implements AggregationStrategy {

    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
        if (oldExchange == null) {
            return newExchange;
        }

        String oldBody = oldExchange.getIn().getBody(String.class);
        String newBody = newExchange.getIn().getBody(String.class);
        oldExchange.getIn().setBody(oldBody + "+" + newBody);
        return oldExchange;
    }
}

//simply combines Exchange body values into an ArrayList<Object>
class ArrayListAggregationStrategy implements AggregationStrategy {

    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
        Object newBody = newExchange.getIn().getBody();
        ArrayList<Object> list = null;
        if (oldExchange == null) {
            list = new ArrayList<Object>();
            list.add(newBody);
            newExchange.getIn().setBody(list);
            return newExchange;
        } else {
            list = oldExchange.getIn().getBody(ArrayList.class);
            list.add(newBody);
            return oldExchange;
        }
    }
}
----

TIP: The `org.apache.camel.builder.AggregationStrategies` is a builder that can
be used for creating commonly used aggregation strategies without having to create a class.

=== Aggregate by grouping exchanges

In the route below we group all the exchanges together using
`GroupedExchangeAggregationStrategy`:

[source,java]
----
from("direct:start")
    // aggregate all using same expression and group the
    // exchanges so we get one single exchange containing all
    // the others
    .aggregate(new GroupedExchangeAggregationStrategy()).constant(true)
    // wait for 0.5 seconds to aggregate
    .completionTimeout(500L).to("mock:result");
----

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.

The output of the aggregator will then contain the exchanges grouped
together in a list as shown below:

[source,java]
----
List<Exchange> grouped = exchange.getMessage().getBody(List.class);
----

=== Aggregating into a List

If you want to aggregate some value from the messages `<V>` into a `List<V>`
then you can use the
`org.apache.camel.processor.aggregate.AbstractListAggregationStrategy`
abstract class.

The completed Exchange that is sent out of the aggregator will contain the `List<V>` in
the message body.

For example to aggregate a `List<Integer>` you can extend this class as
shown below, and implement the `getValue` method:

[source,java]
----
public class MyListOfNumbersStrategy extends AbstractListAggregationStrategy<Integer> {

    @Override
    public Integer getValue(Exchange exchange) {
        // the message body contains a number, so just return that as-is
        return exchange.getIn().getBody(Integer.class);
    }
}
----

The `org.apache.camel.builder.AggregationStrategies` is a builder that can
be used for creating commonly used aggregation strategies without having to create a class.

The previous example can also be built using the builder as shown:

[source,java]
----
AggregationStrategy agg = AggregationStrategies.flexible(Integer.class)
    .accumulateInCollection(ArrayList.class)
    .pick(body());
----

=== Aggregating on timeout

If your aggregation strategy implements
`TimeoutAwareAggregationStrategy`, then Camel will invoke the `timeout`
method when the timeout occurs. Notice that the values for index and
total parameters will be -1, and the timeout parameter will be provided
only if configured as a fixed value. You must *not* throw any exceptions
from the `timeout` method.

=== Aggregate with persistent repository

The aggregator provides a pluggable repository which you can implement
your own `org.apache.camel.spi.AggregationRepository`.

If you need persistent repository then Camel provides numerous implementations, such as from the
xref:ROOT:caffeine-cache-component.adoc[Caffeine],
xref:ROOT:cql-component.adoc[CassandraQL],
xref:ROOT:ehcache-component.adoc[EHCache],
xref:ROOT:infinispan-component.adoc[Infinispan],
xref:ROOT:jcache-component.adoc[JCache],
xref:others:leveldb.adoc[LevelDB],
xref:others:redis.adoc[Redis],
or xref:ROOT:sql-component.adoc[SQL] components.

== Completion

When aggregation xref:manual::exchange.adoc[Exchange]s at some point you need to
indicate that the aggregated exchanges is complete, so they can be sent
out of the aggregator. Camel allows you to indicate completion in
various ways as follows:

* _completionTimeout_ - Is an inactivity timeout in which is triggered if
no new exchanges have been aggregated for that particular correlation
key within the period.
* _completionInterval_ - Once every X period all the current aggregated
exchanges are completed.
* _completionSize_ - Is a number indicating that after X aggregated
exchanges its complete.
* _completionPredicate_ - Runs a xref:manual::predicate.adoc[Predicate] when a new
exchange is aggregated to determine if we are complete or not.
The configured aggregationStrategy can implement the
Predicate interface and will be used as the completionPredicate if no
completionPredicate is configured. The configured aggregationStrategy can
override the `preComplete` method and will be used as
the completionPredicate in pre-complete check mode. See further below
for more details.
* _completionFromBatchConsumer_ - Special option for
xref:manual::batch-consumer.adoc[Batch Consumer] which allows you to complete
when all the messages from the batch has been aggregated.
* _forceCompletionOnStop_ - Indicates to complete all current
aggregated exchanges when the context is stopped
* _AggregateController_ - which allows to use an external source (`AggregateController` implementation) to complete groups or all groups.
This can be done using Java or JMX API.

All the different completions are per correlation key. You can
combine them in any way you like. It's basically the first which
triggers that wins. So you can use a completion size together with a
completion timeout. Only completionTimeout and completionInterval cannot
be used at the same time.

Completion is mandatory and must be configured on the aggregation.

=== Pre-completion mode

There can be use-cases where you want the incoming
xref:manual::exchange.adoc[Exchange] to determine if the correlation group
should pre-complete, and then the incoming
xref:manual::exchange.adoc[Exchange] is starting a new group from scratch.
The pre-completion mode must be enabled by the `AggregationStrategy` by overriding the `canPreComplete` method
to return a `true` value.

When pre completion is enabled then the `preComplete` method is invoked:

[source,java]
----
/**
 * Determines if the aggregation should complete the current group, and start a new group, or the aggregation
 * should continue using the current group.
 *
 * @param oldExchange the oldest exchange (is <tt>null</tt> on first aggregation as we only have the new exchange)
 * @param newExchange the newest exchange (can be <tt>null</tt> if there was no data possible to acquire)
 * @return <tt>true</tt> to complete current group and start a new group, or <tt>false</tt> to keep using current
 */
boolean preComplete(Exchange oldExchange, Exchange newExchange);
----

If the `preComplete` method returns `true`, then the existing correlation groups is
completed (without aggregating the incoming exchange (`newExchange`).
Then the `newExchange` is used to start the correlation group from scratch,
so the group would contain only that new incoming exchange. This is
known as pre-completion mode.

When the aggregation is in _pre-completion_ mode, then only the following completions are in use:

* _completionTimeout_ or _completionInterval_ can also be used as fallback
completions
* any other completion are not used (such as by size, from batch consumer etc)
* _eagerCheckCompletion_ is implied as `true`, but the option has no effect

=== CompletionAwareAggregationStrategy

If your aggregation strategy implements
`CompletionAwareAggregationStrategy`, then Camel will invoke the
`onComplete` method when the aggregated `Exchange` is completed. This
allows you to do any last minute custom logic such as to clean up some
resources, or additional work on the exchange as it's now completed.
You must *not* throw any exceptions from the `onCompletion` method.

=== Completing current group decided from the AggregationStrategy

The `AggregationStrategy` supports checking for the

the exchange property (`Exchange.AGGREGATION_COMPLETE_CURRENT_GROUP`)
on the returned `Exchange` that contains a boolean to indicate if the current
group should be completed. This allows to overrule any existing
completion predicates / sizes / timeouts etc, and complete the group.

For example the following logic will complete the
group if the message body size is larger than 5. This is done by setting
the exchange property `Exchange.AGGREGATION_COMPLETE_CURRENT_GROUP` to `true`.

[source,java]
----
public final class MyCompletionStrategy implements AggregationStrategy {
    @Override
    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
        if (oldExchange == null) {
            return newExchange;
        }
        String body = oldExchange.getIn().getBody(String.class) + "+"
            + newExchange.getIn().getBody(String.class);
        oldExchange.getIn().setBody(body);
        if (body.length() >= 5) {
            oldExchange.setProperty(Exchange.AGGREGATION_COMPLETE_CURRENT_GROUP, true);
        }
        return oldExchange;
    }
}
----

=== Completing all previous group decided from the AggregationStrategy

The `AggregationStrategy` checks an exchange property, from the returned exchange,
indicating if all previous groups should be completed.

This allows to overrule any existing
completion predicates / sizes / timeouts etc, and complete all the existing
previous group.

The following logic will complete all the
previous groups, and start a new aggregation group.

This is done by setting the property `Exchange.AGGREGATION_COMPLETE_ALL_GROUPS` to `true`
on the returned exchange.

[source,java]
----
public final class MyCompletionStrategy implements AggregationStrategy {
    @Override
    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
        if (oldExchange == null) {
            // we start a new correlation group, so complete all previous groups
            newExchange.setProperty(Exchange.AGGREGATION_COMPLETE_ALL_GROUPS, true);
            return newExchange;
        }

        String body1 = oldExchange.getIn().getBody(String.class);
        String body2 = newExchange.getIn().getBody(String.class);

        oldExchange.getIn().setBody(body1 + body2);
        return oldExchange;
    }
}
----

=== Manually force the completion of all aggregated Exchanges immediately

You can manually trigger completion of all current aggregated exchanges
by sending an exchange containing the exchange property
`Exchange.AGGREGATION_COMPLETE_ALL_GROUPS` set to `true`. The message is
considered a signal message only, the message headers/contents will not
be processed otherwise.

You can alternatively set the exchange property
`Exchange.AGGREGATION_COMPLETE_ALL_GROUPS_INCLUSIVE` to `true` to trigger
completion of all groups after processing the current message.

=== Using a controller to force the aggregator to complete

The `org.apache.camel.processor.aggregate.AggregateController` allows
you to control the aggregate at runtime using Java or JMX API. This can
be used to force completing groups of exchanges, or query its current
runtime statistics.

The aggregator provides a default implementation if no custom have been
configured, which can be accessed using `getAggregateController()` method.
Though it may be easier to configure a controller in the route using
`aggregateController` as shown below:

[source,java]
----
private AggregateController controller = new DefaultAggregateController();

from("direct:start")
   .aggregate(header("id"), new MyAggregationStrategy())
      .completionSize(10).id("myAggregator")
      .aggregateController(controller)
      .to("mock:aggregated");
----

Then there is API on `AggregateController` to force completion. For
example to complete a group with key foo:

[source,java]
----
int groups = controller.forceCompletionOfGroup("foo");
----

The returned value is the number of groups completed.
A value of 1 is returned if the foo group existed, otherwise 0 is returned.

There is also a method to complete all groups:

[source,java]
----
int groups = controller.forceCompletionOfAllGroups();
----

The controller can also be used in XML DSL using the `aggregateControllerRef` to
refer to a bean with the controller implementation, which is looked up in the registry.

When using Spring XML you can create the bean with `<bean>` as shown:

[source,xml]
----
<bean id="myController" class="org.apache.camel.processor.aggregate.DefaultAggregateController"/>

<camelContext xmlns="http://camel.apache.org/schema/spring">
    <route>
        <from uri="direct:start"/>
        <aggregate strategyRef="myAppender" completionSize="10"
                   aggregateControllerRef="myController">
            <correlationExpression>
                <header>id</header>
            </correlationExpression>
            <to uri="mock:result"/>
        </aggregate>
    </route>
</camelContext>
----

There is also JMX API on the aggregator which is available under the processors node in the Camel JMX tree.

== Aggregating with Beans

To use the `AggregationStrategy` you had to implement the
`org.apache.camel.AggregationStrategy` interface,
which means your logic would be tied to the Camel API.
You can use a bean for the logic and let Camel adapt to your
bean. To use a bean a convention must be followed:

* there must be a public method to use
* the method must not be void
* the method can be static or non-static
* the method must have 2 or more parameters
* the parameters are paired, so the first half is applied to the
`oldExchange`, and the reminder half is for the `newExchange`.
 Therefore, there must be an equal number of parameters, eg 2, 4, 6 etc.

The paired methods is expected to be ordered as follows:

* the first parameter is the message body
* optional, the 2nd parameter is a `Map` of the headers
* optional, the 3rd parameter is a `Map` of the exchange properties

This convention is best explained with some examples.

In the method below, we have only 2 parameters, so the 1st parameter is
the body of the `oldExchange`, and the 2nd is paired to the body of the
`newExchange`:

[source,java]
----
public String append(String existing, String next) {
    return existing + next;
}
----

In the method below, we have only 4 parameters, so the 1st parameter is
the body of the `oldExchange`, and the 2nd is the `Map` of the
`oldExchange` headers, and the 3rd is paired to the body of the `newExchange`,
and the 4th parameter is the `Map` of the `newExchange` headers:

[source,java]
----
public String append(String existing, Map existingHeaders, String next, Map nextHeaders) {
    return existing + next;
}
----

And finally if we have 6 parameters, that includes the exchange properties:

[source,java]
----
public String append(String existing, Map existingHeaders, Map existingProperties,
                     String next, Map nextHeaders, Map nextProperties) {
    return existing + next;
}
----

To use this with the aggregate EIP we can use a bean with the aggregate logic as follows:

[source,java]
----
public class MyBodyAppender {

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

}
----

And then in the Camel route we create an instance of our bean, and then
refer to the bean in the route using `bean` method from
`org.apache.camel.builder.AggregationStrategies` as shown:

[source,java]
----
private MyBodyAppender appender = new MyBodyAppender();

public void configure() throws Exception {
    from("direct:start")
        .aggregate(constant(true), AggregationStrategies.bean(appender, "append"))
            .completionSize(3)
            .to("mock:result");
}
----

We can also provide the bean class type directly:

[source,java]
----
public void configure() throws Exception {
    from("direct:start")
        .aggregate(constant(true), AggregationStrategies.bean(MyBodyAppender.class, "append"))
            .completionSize(3)
            .to("mock:result");
}
----

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

[source,java]
----
public void configure() throws Exception {
    from("direct:start")
        .aggregate(constant(true), AggregationStrategies.bean(MyBodyAppender.class))
            .completionSize(3)
            .to("mock:result");
}
----

And the `append` method could be static:

[source,java]
----
public class MyBodyAppender {

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

}
----

If you are using XML DSL then we need to declare a `<bean>` with the bean:

[source,xml]
----
<bean id="myAppender" class="com.foo.MyBodyAppender"/>
----

And in the Camel route we use `strategyRef` to refer to the bean by its
id, and the `strategyMethodName` can be used to define the method name
to call:

[source,xml]
----
<camelContext xmlns="http://camel.apache.org/schema/spring">
    <route>
        <from uri="direct:start"/>
        <aggregate strategyRef="myAppender" strategyMethodName="append" completionSize="3">
            <correlationExpression>
                <constant>true</constant>
            </correlationExpression>
            <to uri="mock:result"/>
        </aggregate>
    </route>
</camelContext>
----

When using XML DSL you can also specify the bean class directly in `strategyRef`
using the `#class:` syntax as shown:

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

You can use this in XML DSL when you are not using the classic Spring XML files;
where you use XML only for Camel routes.

=== 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`.

When using beans this can be configured a bit easier using the `beanAllowNull` method
from `AggregationStrategies` as shown:

[source,java]
----
public void configure() throws Exception {
    from("direct:start")
        .pollEnrich("seda:foo", 1000, AggregationStrategies.beanAllowNull(appender, "append"))
            .to("mock:result");
}
----

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

[source,java]
----
public class MyBodyAppender {

    public String append(String existing, String next) {
        if (next == null) {
            return "NewWasNull" + existing;
        } else {
            return existing + next;
        }
    }

}
----

In the example above we use the xref:content-enricher.adoc[Content Enricher]
EIP using `pollEnrich`. The `newExchange` will be `null` in the
situation we could not get any data from the "seda:foo" endpoint, and
a timeout was hit after 1 second.

So if we need to do special merge logic we would need to set `setAllowNullNewExchange=true`.
If we don'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 DSL you would configure the `strategyMethodAllowNull` option and
set it to `true` as shown below:

[source,xml]
----
<camelContext xmlns="http://camel.apache.org/schema/spring">
    <route>
        <from uri="direct:start"/>
        <aggregate strategyRef="myAppender"
                   strategyMethodName="append"
                   strategyMethodAllowNull="true"
                   completionSize="3">
            <correlationExpression>
                <constant>true</constant>
            </correlationExpression>
            <to uri="mock:result"/>
        </aggregate>
    </route>
</camelContext>
----

=== Aggregating with different body types

When for example using `strategyMethodAllowNull` as `true`, then the
parameter types 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:

[source,java]
----
public final class MyUserAppender {

    public List addUsers(List names, User user) {
        if (names == null) {
            names = new ArrayList();
        }
        names.add(user.getName());
        return names;
    }
}
----

Notice that the return type is a `List` which we want to contain the name of the users.
The 1st parameter is the `List` of names, and the 2nd parameter is the incoming `com.foo.User` type.


asynchronous.adoc

asynchronous.adoc

=== Asynchronous API
Since version ``3.0`` Bucket4j provides asynchronous analogs for the majority of API methods.
Async view of proxyManager is available through ``asAsync()`` method:
[source, java]
----
ProxyManager proxyManager = ...;
AsyncProxyManager asyncProxyManager = proxyManager.asAsync();

BucketConfiguration configuration = ...;
AsyncBucketProxy asyncBucket = asyncProxyManager.builder().build(key, configuration);
----
Each method of class ```AsyncBucketProxy``` has full equivalence with the same semantic in asynchronous version in the ```Bucket``` class.

==== Example - limiting the rate of access to the asynchronous servlet
Imagine that you develop an SMS service, which allows sending SMS via an HTTP interface.
You want your architecture to be protected from overloading, clustered, and fully asynchronous.

**Overloading protection requirement:**

> To prevent fraud and service overloading you want to introduce the following limit for any outbound phone number: The bucket size is 20 SMS (which cannot be exceeded at any given time), with a "refill rate" of 10 SMS per minute that continually increases tokens in the bucket.
In other words, if a client sends 10 SMS per minute, it will never be throttled,
and moreover, the client has overdraft equals to 20 SMS which can be used if the average is a little bit higher than 10 SMS/minute on short time period.
**Solution:** let's use bucket4j for this.

**Clustering requirement:**

> You want to avoid the single point of failure, if one server crashed that information about consumed tokens should not be lost,
thus it would be better to use any distributed computation platform for storing the buckets.

**Solution:** let's use JBoss Infinispan for this and ``bucket4j-infinispan`` extension.
Hazelcast and Apache Ignite will be also well-chosen, Infinispan just selected as an example.

**Asynchronous processing requirement:**
Also for maximum scalability, you want from architecture to be fully non-blocking,
non-blocking architecture means that both sms sending and limit checking should be asynchronous.
**Solution:** let's use asynchronous features provided by bucket4j and Servlet-API.

**Mockup of service based on top of Servlet API and bucket4j-infinispan**:
[source, java]
----
public class SmsServlet extends javax.servlet.http.HttpServlet {

    private SmsSender smsSender;
    private AsyncProxyManager<String> buckets;
    private Supplier<BucketConfiguration> configuration;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        ServletContext ctx = config.getServletContext();

        smsSender = (SmsSender) ctx.getAttribute("sms-sender");

        FunctionalMapImpl<String, byte[]> bucketMap = (FunctionalMapImpl<String, byte[]>) ctx.getAttribute("bucket-map");
        this.buckets = new InfinispanProxyManager(bucketMap).asAsync();

        this.configuration = () -> {
            long overdraft = 20;
            Refill refill = Refill.greedy(10, Duration.ofMinutes(1));
            Bandwidth limit = Bandwidth.classic(overdraft, refill);
            return BucketConfiguratiion.builder()
                .addLimit(limit)
                .build();
        };
    }

    @Override
    protected void doPost(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;

        String fromNumber = req.getParameter("from");
        String toNumber = req.getParameter("to");
        String text = req.getParameter("text");

        AsyncBucketProxy bucket = buckets.builder().build(fromNumber, configuration);
        CompletableFuture<ConsumptionProbe> limitCheckingFuture = bucket.asAsync().tryConsumeAndReturnRemaining(1);
        final AsyncContext asyncContext = req.startAsync();
        limitCheckingFuture.thenCompose(probe -> {
            if (!probe.isConsumed()) {
                Result throttledResult = Result.throttled(probe);
                return CompletableFuture.completedFuture(throttledResult);
            } else {
                CompletableFuture<Result> sendingFuture = smsSender.sendAsync(fromNumber, toNumber, text);
                return sendingFuture;
            }
        }).whenComplete((result, exception) -> {
            HttpServletResponse asyncResponse = (HttpServletResponse) asyncContext.getResponse();
            try {
                asyncResponse.setContentType("text/plain");
                if (exception != null || result.isFailed()) {
                    asyncResponse.setStatus(500);
                    asyncResponse.getWriter().println("Internal Error");
                } else if (result.isThrottled()) {
                    asyncResponse.setStatus(429);
                    asyncResponse.setHeader("X-Rate-Limit-Retry-After-Seconds", "" + result.getRetryAfter());
                    asyncResponse.getWriter().append("Too many requests");
                } else {
                    asyncResponse.setStatus(200);
                    asyncResponse.getWriter().append("Success");
                }
            } finally{
                asyncContext.complete();
            }
        });
    }

}
----

=== Asynchronous API
Since version ``3.0`` Bucket4j provides asynchronous analogs for majority of API methods.
Async view of proxyManager is available through ``asAsync()`` method:
[source, java]
----
ProxyManager proxyManager = ...;
AsyncProxyManager asyncProxyManager = proxyManager.asAsync();

BucketConfiguration configuration = ...;
AsyncBucketProxy asyncBucket = asyncProxyManager.builder().build(key, configuration);
----
Each method of class ```AsyncBucketProxy``` has full equivalence with same semantic in synchronous version in the ```Bucket``` class.

==== Example - limiting the rate of access to asynchronous servlet
Imagine that you develop SMS service, which allows send SMS via HTTP interface.
You want from your architecture to be protected from overloading, clustered and fully asynchronous.

**Overloading protection requirement:**

> To prevent fraud and service overloading you want to introduce following limit for any outbound phone number: The bucket size is 20 SMS (which cannot be exceeded at any given time), with a "refill rate" of 10 SMS per minute that continually increases tokens in the bucket.
In other words, if client sends 10 SMS per minute, it will never be throttled,
and moreover client have overdraft equals to 20 SMS which can be used if average is little bit higher that 10 SMS/minute on short time period.
**Solution:** lets use bucket4j for this.

**Clustering requirement:**

> You want to avoid the single point of failure, if one server crashed that information about consumed tokens should not be lost,
thus it would be better to use any distributed computation platform for storing the buckets.

**Solution:** lets use JBoss Infinispan for this and ``bucket4j-infinispan`` extension.
Hazelcast and Apache Ignite will be also well choice, Infinispan just selected as example.

**Asynchronous processing requirement:**
Also for maximum scalability you want from architecture to be fully non-blocking,
non-blocking architecture means that both SMS sending and limit checking should be asynchronous.
**Solution:** lets use asynchronous features provided by bucket4j and Servlet-API.

**Mockup of service based on top of Servlet API and bucket4j-infinispan**:
[source, java]
----
public class SmsServlet extends javax.servlet.http.HttpServlet {

    private SmsSender smsSender;
    private AsyncProxyManager<String> buckets;
    private Supplier<BucketConfiguration> configuration;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        ServletContext ctx = config.getServletContext();

        smsSender = (SmsSender) ctx.getAttribute("sms-sender");

        FunctionalMapImpl<String, byte[]> bucketMap = (FunctionalMapImpl<String, byte[]>) ctx.getAttribute("bucket-map");
        this.buckets = new InfinispanProxyManager(bucketMap).asAsync();

        this.configuration = () -> {
            long overdraft = 20;
            Refill refill = Refill.greedy(10, Duration.ofMinutes(1));
            Bandwidth limit = Bandwidth.classic(overdraft, refill);
            return BucketConfiguratiion.builder()
                .addLimit(limit)
                .build();
        };
    }

    @Override
    protected void doPost(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;

        String fromNumber = req.getParameter("from");
        String toNumber = req.getParameter("to");
        String text = req.getParameter("text");

        AsyncBucketProxy bucket = buckets.builder().build(fromNumber, configuration);
        CompletableFuture<ConsumptionProbe> limitCheckingFuture = bucket.asAsync().tryConsumeAndReturnRemaining(1);
        final AsyncContext asyncContext = req.startAsync();
        limitCheckingFuture.thenCompose(probe -> {
            if (!probe.isConsumed()) {
                Result throttledResult = Result.throttled(probe);
                return CompletableFuture.completedFuture(throttledResult);
            } else {
                CompletableFuture<Result> sendingFuture = smsSender.sendAsync(fromNumber, toNumber, text);
                return sendingFuture;
            }
        }).whenComplete((result, exception) -> {
            HttpServletResponse asyncResponse = (HttpServletResponse) asyncContext.getResponse();
            try {
                asyncResponse.setContentType("text/plain");
                if (exception != null || result.isFailed()) {
                    asyncResponse.setStatus(500);
                    asyncResponse.getWriter().println("Internal Error");
                } else if (result.isThrottled()) {
                    asyncResponse.setStatus(429);
                    asyncResponse.setHeader("X-Rate-Limit-Retry-After-Seconds", "" + result.getRetryAfter());
                    asyncResponse.getWriter().append("Too many requests");
                } else {
                    asyncResponse.setStatus(200);
                    asyncResponse.getWriter().append("Success");
                }
            } finally{
                asyncContext.complete();
            }
        });
    }

}
----