Adds AggregatorAdapter and support for the 'method' attribute in <aggregtor> elements (INT-137). Target methods must conform with a signature pattern as follows: ReturnType methodName (Collection<CollectionType> args).
If CollectionType is Message or any of its descendants (including parametrized types), the aggregator will pass the collection of messages to be aggregated 'as is', leaving to the target method to extract the payloads. If CollectionType is non-Message, the payloads will be extracted and passed to the target collection. If the result of the method call is not a Message, it will be wrapped in a GenericMessage.
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.integration.config;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author Marius Bogoevici
|
||||
*/
|
||||
public class Adder {
|
||||
|
||||
public Long add(Collection<Long> results) {
|
||||
long total = 0;
|
||||
for (long partialResult: results) {
|
||||
total += partialResult;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,9 +24,11 @@ import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
import org.springframework.integration.router.AggregatingMessageHandler;
|
||||
@@ -41,7 +43,6 @@ public class AggregatorParserTests {
|
||||
|
||||
private ApplicationContext context;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
context = new ClassPathXmlApplicationContext("aggregatorParserTests.xml", this.getClass());
|
||||
@@ -100,10 +101,29 @@ public class AggregatorParserTests {
|
||||
99, getPropertyValue(completeAggregatingMessageHandler, "trackedCorrelationIdCapacity", int.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleJavaBeanAggregator() {
|
||||
AggregatingMessageHandler addingAggregator = (AggregatingMessageHandler) context.getBean("aggregatorWithReferenceAndMethod");
|
||||
List<Message<?>> outboundMessages = new ArrayList<Message<?>>();
|
||||
outboundMessages.add(createMessage(1l, "id1", 3, 1, null));
|
||||
outboundMessages.add(createMessage(2l, "id1", 3, 3, null));
|
||||
outboundMessages.add(createMessage(3l, "id1", 3, 2, null));
|
||||
for (Message<?> message : outboundMessages) {
|
||||
addingAggregator.handle(message);
|
||||
}
|
||||
MessageChannel replyChannel = (MessageChannel) context.getBean("replyChannel");
|
||||
Message response = replyChannel.receive();
|
||||
Assert.assertEquals(6l, response.getPayload());
|
||||
}
|
||||
|
||||
@Test(expected=BeanCreationException.class)
|
||||
public void testMissingMethodOnAggregator() {
|
||||
context = new ClassPathXmlApplicationContext("invalidMethodNameAggregator.xml", this.getClass());
|
||||
}
|
||||
|
||||
private static Message<?> createMessage(String payload, Object correlationId, int sequenceSize, int sequenceNumber,
|
||||
private static <T> Message<T> createMessage(T payload, Object correlationId, int sequenceSize, int sequenceNumber,
|
||||
MessageChannel replyChannel) {
|
||||
StringMessage message = new StringMessage(payload);
|
||||
GenericMessage<T> message = new GenericMessage<T>(payload);
|
||||
message.getHeader().setCorrelationId(correlationId);
|
||||
message.getHeader().setSequenceSize(sequenceSize);
|
||||
message.getHeader().setSequenceNumber(sequenceNumber);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.integration.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -34,16 +35,19 @@ public class TestAggregator implements Aggregator {
|
||||
|
||||
private final ConcurrentMap<Object, Message<?>> aggregatedMessages = new ConcurrentHashMap<Object, Message<?>>();
|
||||
|
||||
|
||||
public Message<?> aggregate(List<Message<?>> messages) {
|
||||
public Message<?> aggregate(Collection<Message<?>> messages) {
|
||||
List<Message<?>> sortableList = new ArrayList<Message<?>>(messages);
|
||||
Collections.sort(sortableList, new MessageSequenceComparator());
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
Object correlationId = null;
|
||||
for (Message<?> message : sortableList) {
|
||||
buffer.append(message.getPayload().toString());
|
||||
if (null == correlationId) {
|
||||
correlationId = message.getHeader().getCorrelationId();
|
||||
}
|
||||
}
|
||||
Message<?> returnedMessage = new StringMessage(buffer.toString());
|
||||
aggregatedMessages.put(messages.get(0).getHeader().getCorrelationId(), returnedMessage);
|
||||
aggregatedMessages.put(correlationId, returnedMessage);
|
||||
return returnedMessage;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,16 @@
|
||||
send-partial-result-on-timeout="true"
|
||||
reaper-interval="135"
|
||||
tracked-correlation-id-capacity="99"/>
|
||||
|
||||
<aggregator id="aggregatorWithReferenceAndMethod" ref="adderBean" method="add" default-reply-channel="replyChannel"/>
|
||||
|
||||
<channel id="replyChannel"/>
|
||||
|
||||
<channel id="discardChannel"/>
|
||||
|
||||
<beans:bean id="aggregatorBean" class="org.springframework.integration.config.TestAggregator"/>
|
||||
|
||||
<beans:bean id="adderBean" class="org.springframework.integration.config.Adder"/>
|
||||
|
||||
<beans:bean id="completionStrategy" class="org.springframework.integration.config.TestCompletionStrategy"/>
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration-core-1.0.xsd">
|
||||
|
||||
<aggregator id="aggregatorWithReferenceAndMethod" ref="adderBean" method="substract" default-reply-channel="replyChannel"/>
|
||||
|
||||
<channel id="replyChannel"/>
|
||||
|
||||
<beans:bean id="adderBean" class="org.springframework.integration.config.Adder"/>
|
||||
|
||||
</beans:beans>
|
||||
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
@@ -207,7 +208,7 @@ public class AggregatingMessageHandlerTests {
|
||||
|
||||
private static class TestAggregator implements Aggregator {
|
||||
|
||||
public Message<?> aggregate(List<Message<?>> messages) {
|
||||
public Message<?> aggregate(Collection<Message<?>> messages) {
|
||||
List<Message<?>> sortableList = new ArrayList<Message<?>>(messages);
|
||||
Collections.sort(sortableList, new MessageSequenceComparator());
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.integration.router;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.integration.MessagingConfigurationException;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.message.Message;
|
||||
|
||||
/**
|
||||
* @author Marius Bogoevici
|
||||
*/
|
||||
public class AggregatorAdapterTests {
|
||||
|
||||
private SimpleAggregator simpleAggregator;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
simpleAggregator = new SimpleAggregator();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdapterWithMessageCollectionBasedMethod() {
|
||||
Aggregator aggregator = new AggregatorAdapter(simpleAggregator, "doAggregationOnCollectionOfMessages");
|
||||
Collection<Message<?>> messages = createCollectionOfMessages();
|
||||
Message<?> returnedMessge = aggregator.aggregate(messages);
|
||||
Assert.assertTrue(simpleAggregator.isAggregationPerformed());
|
||||
Assert.assertEquals("123456789", returnedMessge.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdapterWithWildcardParametrizedMessageBasedMethod() {
|
||||
Aggregator aggregator = new AggregatorAdapter(simpleAggregator, "doAggregationOnCollectionOfMessagesParametrizedWithWildcard");
|
||||
Collection<Message<?>> messages = createCollectionOfMessages();
|
||||
Message<?> returnedMessge = aggregator.aggregate(messages);
|
||||
Assert.assertTrue(simpleAggregator.isAggregationPerformed());
|
||||
Assert.assertEquals("123456789", returnedMessge.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdapterWithTypeParametrizedMessageBasedMethod() {
|
||||
Aggregator aggregator = new AggregatorAdapter(simpleAggregator, "doAggregationOnCollectionOfMessagesParametrizedWithString");
|
||||
Collection<Message<?>> messages = createCollectionOfMessages();
|
||||
Message<?> returnedMessge = aggregator.aggregate(messages);
|
||||
Assert.assertTrue(simpleAggregator.isAggregationPerformed());
|
||||
Assert.assertEquals("123456789", returnedMessge.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdapterWithPojoBasedMethod() {
|
||||
Aggregator aggregator = new AggregatorAdapter(simpleAggregator, "doAggregationOnCollectionOfStrings");
|
||||
Collection<Message<?>> messages = createCollectionOfMessages();
|
||||
Message<?> returnedMessge = aggregator.aggregate(messages);
|
||||
Assert.assertTrue(simpleAggregator.isAggregationPerformed());
|
||||
Assert.assertEquals("123456789", returnedMessge.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdapterWithPojoBasedMethodReturningObject() {
|
||||
Aggregator aggregator = new AggregatorAdapter(simpleAggregator, "doAggregationOnCollectionOfStringsReturningLong");
|
||||
Collection<Message<?>> messages = createCollectionOfMessages();
|
||||
Message<?> returnedMessge = aggregator.aggregate(messages);
|
||||
Assert.assertTrue(simpleAggregator.isAggregationPerformed());
|
||||
Assert.assertEquals(123456789l, returnedMessge.getPayload());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testAdapterWithWrongMethodName() {
|
||||
Aggregator aggregator = new AggregatorAdapter(simpleAggregator, "methodThatDoesNotExist");
|
||||
}
|
||||
|
||||
private static Collection<Message<?>> createCollectionOfMessages() {
|
||||
Collection<Message<?>> messages = new ArrayList<Message<?>>();
|
||||
messages.add(new GenericMessage<String>("123"));
|
||||
messages.add(new GenericMessage<String>("456"));
|
||||
messages.add(new GenericMessage<String>("789"));
|
||||
return messages;
|
||||
}
|
||||
|
||||
private class SimpleAggregator {
|
||||
|
||||
private volatile boolean aggregationPerformed;
|
||||
|
||||
|
||||
public SimpleAggregator() {
|
||||
aggregationPerformed = false;
|
||||
}
|
||||
|
||||
public Message<?> doAggregationOnCollectionOfMessages(Collection<Message> messages) {
|
||||
aggregationPerformed = true;
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for (Message<?> message : messages) {
|
||||
buffer.append(message.getPayload());
|
||||
}
|
||||
return new GenericMessage<String>(buffer.toString());
|
||||
}
|
||||
|
||||
public Message<?> doAggregationOnCollectionOfMessagesParametrizedWithWildcard(Collection<Message<?>> messages) {
|
||||
aggregationPerformed = true;
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for (Message<?> message : messages) {
|
||||
buffer.append(message.getPayload());
|
||||
}
|
||||
return new GenericMessage<String>(buffer.toString());
|
||||
}
|
||||
|
||||
public Message<?> doAggregationOnCollectionOfMessagesParametrizedWithString(Collection<Message<String>> messages) {
|
||||
aggregationPerformed = true;
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for (Message<String> message : messages) {
|
||||
buffer.append(message.getPayload());
|
||||
}
|
||||
return new GenericMessage<String>(buffer.toString());
|
||||
}
|
||||
|
||||
public Message<?> doAggregationOnCollectionOfStrings(Collection<String> messages) {
|
||||
aggregationPerformed = true;
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for (String payload : messages) {
|
||||
buffer.append(payload);
|
||||
}
|
||||
return new GenericMessage<String>(buffer.toString());
|
||||
}
|
||||
|
||||
public Long doAggregationOnCollectionOfStringsReturningLong(Collection<String> messages) {
|
||||
aggregationPerformed = true;
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for (String payload : messages) {
|
||||
buffer.append(payload);
|
||||
}
|
||||
return Long.parseLong(buffer.toString());
|
||||
}
|
||||
|
||||
public boolean isAggregationPerformed() {
|
||||
return aggregationPerformed;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user