/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.util.toolbox;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.w3c.dom.Node;
import org.apache.camel.ContextTestSupport;
import org.apache.camel.Exchange;
import org.apache.camel.LoggingLevel;
import org.apache.camel.builder.NotifyBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.processor.aggregate.AggregationStrategy;
import org.apache.camel.util.toolbox.FlexibleAggregationStrategy.CompletionAwareMixin;
import org.apache.camel.util.toolbox.FlexibleAggregationStrategy.TimeoutAwareMixin;
import org.junit.Test;
/**
* Unit tests for the {@link FlexibleAggregationStrategy}.
* @since 2.12
*/
public class FlexibleAggregationStrategiesTest extends ContextTestSupport {
private final CountDownLatch completionLatch = new CountDownLatch(1);
private final CountDownLatch timeoutLatch = new CountDownLatch(1);
@Test @SuppressWarnings("unchecked")
public void testFlexibleAggregationStrategyNoCondition() throws Exception {
getMockEndpoint("mock:result1").expectedMessageCount(1);
getMockEndpoint("mock:result1").message(0).body().isInstanceOf(ArrayList.class);
template.sendBodyAndHeader("direct:start1", "AGGREGATE1", "id", "123");
template.sendBodyAndHeader("direct:start1", "AGGREGATE2", "id", "123");
template.sendBodyAndHeader("direct:start1", "AGGREGATE3", "id", "123");
template.sendBodyAndHeader("direct:start1", "AGGREGATE4", "id", "123");
template.sendBodyAndHeader("direct:start1", "AGGREGATE5", "id", "123");
assertMockEndpointsSatisfied();
List<String> resultList = getMockEndpoint("mock:result1").getReceivedExchanges()
.get(0).getIn().getBody(List.class);
for (int i = 0; i < 5; i++) {
assertEquals("AGGREGATE" + (i + 1), resultList.get(i));
}
}
@Test @SuppressWarnings("unchecked")
public void testFlexibleAggregationStrategyCondition() throws Exception {
getMockEndpoint("mock:result1").expectedMessageCount(1);
getMockEndpoint("mock:result1").message(0).body().isInstanceOf(ArrayList.class);
template.sendBodyAndHeader("direct:start1", "AGGREGATE1", "id", "123");
template.sendBodyAndHeader("direct:start1", "DISCARD", "id", "123");
template.sendBodyAndHeader("direct:start1", "AGGREGATE2", "id", "123");
template.sendBodyAndHeader("direct:start1", "DISCARD", "id", "123");
template.sendBodyAndHeader("direct:start1", "AGGREGATE3", "id", "123");
assertMockEndpointsSatisfied();
List<String> resultList = getMockEndpoint("mock:result1").getReceivedExchanges()
.get(0).getIn().getBody(List.class);
for (int i = 0; i < 3; i++) {
assertEquals("AGGREGATE" + (i + 1), resultList.get(i));
}
}
@Test @SuppressWarnings("unchecked")
public void testFlexibleAggregationStrategyStoreInPropertyHashSet() throws Exception {
getMockEndpoint("mock:result2").expectedMessageCount(1);
getMockEndpoint("mock:result2").message(0).exchangeProperty("AggregationResult").isInstanceOf(HashSet.class);
template.sendBodyAndHeader("direct:start2", "ignored body", "input", "AGGREGATE1");
template.sendBodyAndHeader("direct:start2", "ignored body", "input", "DISCARD");
template.sendBodyAndHeader("direct:start2", "ignored body", "input", "AGGREGATE2");
template.sendBodyAndHeader("direct:start2", "ignored body", "input", "DISCARD");
template.sendBodyAndHeader("direct:start2", "ignored body", "input", "AGGREGATE3");
assertMockEndpointsSatisfied();
HashSet<String> resultSet = getMockEndpoint("mock:result2").getReceivedExchanges().get(0)
.getProperty("AggregationResult", HashSet.class);
assertEquals(3, resultSet.size());
assertTrue(resultSet.contains("AGGREGATE1") && resultSet.contains("AGGREGATE2") && resultSet.contains("AGGREGATE3"));
}
@Test
public void testFlexibleAggregationStrategyStoreInHeaderSingleValue() throws Exception {
getMockEndpoint("mock:result3").expectedMessageCount(1);
getMockEndpoint("mock:result3").message(0).header("AggregationResult").isInstanceOf(String.class);
getMockEndpoint("mock:result3").message(0).header("AggregationResult").isEqualTo("AGGREGATE3");
template.sendBody("direct:start3", "AGGREGATE1");
template.sendBody("direct:start3", "AGGREGATE2");
template.sendBody("direct:start3", "AGGREGATE3");
assertMockEndpointsSatisfied();
}
@Test @SuppressWarnings("rawtypes")
public void testFlexibleAggregationStrategyGenericArrayListWithoutNulls() throws Exception {
getMockEndpoint("mock:result4").expectedMessageCount(1);
getMockEndpoint("mock:result4").message(0).body().isInstanceOf(ArrayList.class);
template.sendBody("direct:start4", "AGGREGATE1");
template.sendBody("direct:start4", 123d);
template.sendBody("direct:start4", null);
assertMockEndpointsSatisfied();
ArrayList list = getMockEndpoint("mock:result4").getReceivedExchanges().get(0).getIn().getBody(ArrayList.class);
assertEquals(2, list.size());
assertTrue(list.contains("AGGREGATE1"));
assertTrue(list.contains(123d));
}
@Test
public void testFlexibleAggregationStrategyFailWithInvalidCast() throws Exception {
getMockEndpoint("mock:result5").expectedMessageCount(0);
try {
template.sendBody("direct:start5", "AGGREGATE1");
} catch (Exception exception) {
assertMockEndpointsSatisfied();
return;
}
fail("Type Conversion exception expected, as we are not ignoring invalid casts");
}
@Test @SuppressWarnings("rawtypes")
public void testFlexibleAggregationStrategyFailOnInvalidCast() throws Exception {
getMockEndpoint("mock:result6").expectedMessageCount(1);
getMockEndpoint("mock:result6").message(0).body().isInstanceOf(ArrayList.class);
template.sendBody("direct:start6", "AGGREGATE1");
template.sendBody("direct:start6", "AGGREGATE2");
template.sendBody("direct:start6", "AGGREGATE3");
ArrayList list = getMockEndpoint("mock:result6").getReceivedExchanges().get(0).getIn().getBody(ArrayList.class);
assertEquals(3, list.size());
for (Object object : list) {
assertNull(object);
}
assertMockEndpointsSatisfied();
}
@Test
public void testFlexibleAggregationStrategyTimeoutCompletionMixins() throws Exception {
getMockEndpoint("mock:result.timeoutAndCompletionAware").expectedMessageCount(2);
getMockEndpoint("mock:result.timeoutAndCompletionAware").message(0).body().isEqualTo("AGGREGATE1");
getMockEndpoint("mock:result.timeoutAndCompletionAware").message(0).exchangeProperty("Timeout").isEqualTo(true);
getMockEndpoint("mock:result.timeoutAndCompletionAware").message(1).body().isEqualTo("AGGREGATE3");
template.sendBody("direct:start.timeoutAndCompletionAware", "AGGREGATE1");
assertTrue(timeoutLatch.await(2500, TimeUnit.MILLISECONDS));
template.sendBody("direct:start.timeoutAndCompletionAware", "AGGREGATE2");
template.sendBody("direct:start.timeoutAndCompletionAware", "AGGREGATE3");
assertTrue(completionLatch.await(2500, TimeUnit.MILLISECONDS));
getMockEndpoint("mock:result.timeoutAndCompletionAware").getReceivedExchanges();
assertMockEndpointsSatisfied();
}
@Test @SuppressWarnings("unchecked")
public void testFlexibleAggregationStrategyPickXPath() throws Exception {
getMockEndpoint("mock:result.xpath1").expectedMessageCount(1);
getMockEndpoint("mock:result.xpath1").message(0).body().isInstanceOf(ArrayList.class);
template.sendBody("direct:start.xpath1", "<envelope><result>ok</result></envelope>");
template.sendBody("direct:start.xpath1", "<envelope><result>error</result></envelope>");
template.sendBody("direct:start.xpath1", "<envelope>no result</envelope>");
assertMockEndpointsSatisfied();
ArrayList<Node> list = getMockEndpoint("mock:result.xpath1").getReceivedExchanges().get(0).getIn().getBody(ArrayList.class);
assertEquals(2, list.size());
assertEquals("ok", list.get(0).getTextContent());
assertEquals("error", list.get(1).getTextContent());
}
@Test
public void testLinkedList() throws Exception {
NotifyBuilder notify = new NotifyBuilder(context).whenDone(1).and().whenExactlyFailed(0).create();
template.sendBody("direct:linkedlist", Arrays.asList("FIRST", "SECOND"));
assertTrue(notify.matches(10, TimeUnit.SECONDS));
}
@Test
public void testHashSet() throws Exception {
HashSet<String> r = new HashSet<>();
r.add("FIRST");
r.add("SECOND");
NotifyBuilder notify = new NotifyBuilder(context).whenDone(1).and().whenExactlyFailed(0).create();
Set result = template.requestBody("direct:hashset", Arrays.asList("FIRST", "SECOND"), Set.class);
assertTrue(notify.matches(10, TimeUnit.SECONDS));
assertEquals(r, result);
}
@Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
from("direct:start1")
.aggregate(AggregationStrategies.flexible(String.class)
.accumulateInCollection(ArrayList.class)
.pick(simple("${body}"))
.condition(simple("${body} contains 'AGGREGATE'")))
.header("id").completionSize(5)
.to("mock:result1");
from("direct:start2")
.aggregate(AggregationStrategies.flexible(String.class)
.accumulateInCollection(HashSet.class)
.pick(simple("${header.input}"))
.condition(simple("${header.input} contains 'AGGREGATE'"))
.storeInProperty("AggregationResult"))
.constant(true).completionSize(5)
.to("mock:result2");
from("direct:start3")
.aggregate(AggregationStrategies.flexible(String.class)
.storeInHeader("AggregationResult"))
.constant(true).completionSize(3)
.to("mock:result3");
from("direct:start4")
.aggregate(AggregationStrategies.flexible().accumulateInCollection(ArrayList.class))
.constant(true).completionSize(3)
.to("mock:result4");
from("direct:start5")
.aggregate(AggregationStrategies.flexible(Integer.class).accumulateInCollection(ArrayList.class))
.constant(true).completionSize(3)
.to("mock:result5");
from("direct:start6")
.aggregate(AggregationStrategies.flexible(Integer.class).ignoreInvalidCasts().storeNulls()
.accumulateInCollection(ArrayList.class))
.constant(true).completionSize(3)
.to("mock:result6");
AggregationStrategy timeoutCompletionStrategy =
AggregationStrategies.flexible(String.class)
.condition(simple("${body} contains 'AGGREGATE'"))
.timeoutAware(new TimeoutAwareMixin() {
@Override
public void timeout(Exchange exchange, int index, int total, long timeout) {
exchange.setProperty("Timeout", true);
timeoutLatch.countDown();
}
})
.completionAware(new CompletionAwareMixin() {
@Override
public void onCompletion(Exchange exchange) {
completionLatch.countDown();
}
});
from("direct:start.timeoutAndCompletionAware")
.aggregate(timeoutCompletionStrategy).constant(true)
.completionTimeout(500).completionSize(2)
.to("mock:result.timeoutAndCompletionAware");
from("direct:start.xpath1")
.aggregate(AggregationStrategies.flexible(Node.class)
.pick(xpath("//result[1]").nodeResult())
.accumulateInCollection(ArrayList.class))
.constant(true).completionSize(3)
.to("mock:result.xpath1");
from("direct:linkedlist")
.log(LoggingLevel.INFO, "Before the first split the body is ${body} and has class ${body.getClass()}")
.split(body(), AggregationStrategies.flexible().pick(body()).accumulateInCollection(LinkedList.class))
.log(LoggingLevel.INFO, "During the first split the body is ${body} and has class ${body.getClass()}")
.end()
.log(LoggingLevel.INFO, "Before the second split the body is ${body} and has class ${body.getClass()}")
.split(body(), AggregationStrategies.flexible().pick(body()).accumulateInCollection(LinkedList.class))
.log(LoggingLevel.INFO, "During the second split the body is ${body} and has class ${body.getClass()}")
.end()
.log(LoggingLevel.INFO, "After the second split the body is ${body} and has class ${body.getClass()}");
from("direct:hashset")
.log(LoggingLevel.INFO, "Before the first split the body is ${body} and has class ${body.getClass()}")
.split(body(), AggregationStrategies.flexible().pick(body()).accumulateInCollection(HashSet.class))
.log(LoggingLevel.INFO, "During the first split the body is ${body} and has class ${body.getClass()}")
.end()
.log(LoggingLevel.INFO, "Before the second split the body is ${body} and has class ${body.getClass()}")
.split(body(), AggregationStrategies.flexible().pick(body()).accumulateInCollection(HashSet.class))
.log(LoggingLevel.INFO, "During the second split the body is ${body} and has class ${body.getClass()}")
.end()
.log(LoggingLevel.INFO, "After the second split the body is ${body} and has class ${body.getClass()}");
}
};
}
}