INT-1105, INT-1063: Big merge. Removing old aggregation and correlation stuff, and reaping the reaper.

This commit is contained in:
David Syer
2010-05-02 04:31:05 +00:00
parent ec76ea497a
commit d04c7008b6
58 changed files with 1658 additions and 3797 deletions

View File

@@ -1,352 +0,0 @@
/*
* Copyright 2002-2010 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.aggregator;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.core.MessageHeaders;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.message.MessageHandlingException;
import org.springframework.integration.message.StringMessage;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
/**
* @author Mark Fisher
* @author Marius Bogoevici
*/
public class AggregatorEndpointTests {
private TaskExecutor taskExecutor;
private ThreadPoolTaskScheduler taskScheduler;
private AbstractMessageAggregator aggregator;
@Before
public void configureAggregator() {
this.taskExecutor = new SimpleAsyncTaskExecutor();
this.taskScheduler = new ThreadPoolTaskScheduler();
this.taskScheduler.afterPropertiesSet();
this.aggregator = new TestAggregator();
this.aggregator.setTaskScheduler(this.taskScheduler);
this.aggregator.start();
}
@Test
public void testCompleteGroupWithinTimeout() throws InterruptedException {
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 3, 1, replyChannel, null);
Message<?> message2 = createMessage("456", "ABC", 3, 2, replyChannel, null);
Message<?> message3 = createMessage("789", "ABC", 3, 3, replyChannel, null);
CountDownLatch latch = new CountDownLatch(3);
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message1, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message2, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message3, latch));
latch.await(1000, TimeUnit.MILLISECONDS);
Message<?> reply = replyChannel.receive(500);
assertNotNull(reply);
assertEquals("123456789", reply.getPayload());
}
@Test
public void testCompleteGroupWithinTimeoutWithSameId() throws InterruptedException {
QueueChannel replyChannel = new QueueChannel();
UUID id = UUID.randomUUID();
Message<?> message1 = createMessage("123", "ABC", 3, 1, replyChannel, id);
Message<?> message2 = createMessage("456", "ABC", 3, 2, replyChannel, id);
Message<?> message3 = createMessage("789", "ABC", 3, 3, replyChannel, id);
CountDownLatch latch = new CountDownLatch(3);
//for testing the duplication scenario, the messages must be processed synchronously
new AggregatorTestTask(this.aggregator, message1, latch).run();
new AggregatorTestTask(this.aggregator, message2, latch).run();
new AggregatorTestTask(this.aggregator, message3, latch).run();
Message<?> reply = replyChannel.receive(500);
assertNotNull(reply);
assertEquals("123456789", reply.getPayload());
}
@Test
public void testShouldNotSendPartialResultOnTimeoutByDefault() throws InterruptedException {
QueueChannel discardChannel = new QueueChannel();
this.aggregator.setTimeout(50);
this.aggregator.setReaperInterval(10);
this.aggregator.setDiscardChannel(discardChannel);
QueueChannel replyChannel = new QueueChannel();
Message<?> message = createMessage("123", "ABC", 2, 1, replyChannel, null);
CountDownLatch latch = new CountDownLatch(1);
AggregatorTestTask task = new AggregatorTestTask(this.aggregator, message, latch);
this.taskExecutor.execute(task);
latch.await(2000, TimeUnit.MILLISECONDS);
assertEquals("task should have completed within timeout", 0, latch.getCount());
Message<?> reply = replyChannel.receive(0);
assertNull(reply);
Message<?> discardedMessage = discardChannel.receive(2000);
assertNotNull(discardedMessage);
assertEquals(message, discardedMessage);
}
@Test
public void testShouldSendPartialResultOnTimeoutTrue() throws InterruptedException {
this.aggregator.setTimeout(500);
this.aggregator.setReaperInterval(10);
this.aggregator.setSendPartialResultOnTimeout(true);
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 3, 1, replyChannel, null);
Message<?> message2 = createMessage("456", "ABC", 3, 2, replyChannel, null);
CountDownLatch latch = new CountDownLatch(2);
AggregatorTestTask task1 = new AggregatorTestTask(this.aggregator, message1, latch);
AggregatorTestTask task2 = new AggregatorTestTask(this.aggregator, message2, latch);
this.taskExecutor.execute(task1);
this.taskExecutor.execute(task2);
latch.await(3000, TimeUnit.MILLISECONDS);
assertEquals("handlers should have been invoked within time limit", 0, latch.getCount());
Message<?> reply = replyChannel.receive(3000);
assertNotNull("a reply message should have been received", reply);
assertEquals("123456", reply.getPayload());
assertNull(task1.getException());
assertNull(task2.getException());
}
@Test
public void testMultipleGroupsSimultaneously() throws InterruptedException {
QueueChannel replyChannel1 = new QueueChannel();
QueueChannel replyChannel2 = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 3, 1, replyChannel1, null);
Message<?> message2 = createMessage("456", "ABC", 3, 2, replyChannel1, null);
Message<?> message3 = createMessage("789", "ABC", 3, 3, replyChannel1, null);
Message<?> message4 = createMessage("abc", "XYZ", 3, 1, replyChannel2, null);
Message<?> message5 = createMessage("def", "XYZ", 3, 2, replyChannel2, null);
Message<?> message6 = createMessage("ghi", "XYZ", 3, 3, replyChannel2, null);
CountDownLatch latch = new CountDownLatch(6);
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message1, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message6, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message2, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message5, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message3, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message4, latch));
latch.await(1000, TimeUnit.MILLISECONDS);
Message<?> reply1 = replyChannel1.receive(500);
assertNotNull(reply1);
assertEquals("123456789", reply1.getPayload());
Message<?> reply2 = replyChannel2.receive(500);
assertNotNull(reply2);
assertEquals("abcdefghi", reply2.getPayload());
}
@Test
public void testDiscardChannelForTrackedCorrelationId() {
QueueChannel replyChannel = new QueueChannel();
QueueChannel discardChannel = new QueueChannel();
this.aggregator.setDiscardChannel(discardChannel);
this.aggregator.handleMessage(createMessage("test-1a", 1, 1, 1, replyChannel, null));
assertEquals("test-1a", replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage("test-1b", 1, 1, 1, replyChannel, null));
assertEquals("test-1b", discardChannel.receive(100).getPayload());
}
@Test
public void testTrackedCorrelationIdsCapacityAtLimit() {
QueueChannel replyChannel = new QueueChannel();
QueueChannel discardChannel = new QueueChannel();
this.aggregator.setTrackedCorrelationIdCapacity(3);
this.aggregator.setDiscardChannel(discardChannel);
this.aggregator.handleMessage(createMessage("test-1a", 1, 1, 1, replyChannel, null));
assertEquals("test-1a", replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage("test-2", 2, 1, 1, replyChannel, null));
assertEquals("test-2", replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage("test-3", 3, 1, 1, replyChannel, null));
assertEquals("test-3", replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage("test-1b", 1, 1, 1, replyChannel, null));
assertEquals("test-1b", discardChannel.receive(100).getPayload());
}
@Test
public void testTrackedCorrelationIdsCapacityPassesLimit() {
QueueChannel replyChannel = new QueueChannel();
QueueChannel discardChannel = new QueueChannel();
this.aggregator.setTrackedCorrelationIdCapacity(3);
this.aggregator.setDiscardChannel(discardChannel);
this.aggregator.handleMessage(createMessage("test-1a", 1, 1, 1, replyChannel, null));
assertEquals("test-1a", replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage("test-2", 2, 1, 1, replyChannel, null));
assertEquals("test-2", replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage("test-3", 3, 1, 1, replyChannel, null));
assertEquals("test-3", replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage("test-4", 4, 1, 1, replyChannel, null));
assertEquals("test-4", replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage("test-1b", 1, 1, 1, replyChannel, null));
assertEquals("test-1b", replyChannel.receive(100).getPayload());
assertNull(discardChannel.receive(0));
}
@Test(expected = MessageHandlingException.class)
public void testExceptionThrownIfNoCorrelationId() throws InterruptedException {
Message<?> message = createMessage("123", null, 2, 1, new QueueChannel(), null);
this.aggregator.handleMessage(message);
}
@Test
public void testAdditionalMessageAfterCompletion() throws InterruptedException {
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 3, 1, replyChannel, null);
Message<?> message2 = createMessage("456", "ABC", 3, 2, replyChannel, null);
Message<?> message3 = createMessage("789", "ABC", 3, 3, replyChannel, null);
Message<?> message4 = createMessage("abc", "ABC", 3, 3, replyChannel, null);
CountDownLatch latch = new CountDownLatch(4);
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message1, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message2, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message3, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message4, latch));
latch.await(1000, TimeUnit.MILLISECONDS);
Message<?> reply = replyChannel.receive(500);
assertNotNull(reply);
assertEquals("123456789".length(), ((String)reply.getPayload()).length());
}
@Test
public void testNullReturningAggregator() throws InterruptedException {
this.aggregator = new NullReturningAggregator();
this.aggregator.setTaskScheduler(this.taskScheduler);
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 3, 1, replyChannel, null);
Message<?> message2 = createMessage("456", "ABC", 3, 2, replyChannel, null);
Message<?> message3 = createMessage("789", "ABC", 3, 3, replyChannel, null);
CountDownLatch latch = new CountDownLatch(3);
AggregatorTestTask task1 = new AggregatorTestTask(aggregator, message1, latch);
this.taskExecutor.execute(task1);
AggregatorTestTask task2 = new AggregatorTestTask(aggregator, message2, latch);
this.taskExecutor.execute(task2);
AggregatorTestTask task3 = new AggregatorTestTask(aggregator, message3, latch);
this.taskExecutor.execute(task3);
latch.await(1000, TimeUnit.MILLISECONDS);
assertNull(task1.getException());
assertNull(task2.getException());
assertNull(task3.getException());
Message<?> reply = replyChannel.receive(500);
assertNull(reply);
assertTrue(((NullReturningAggregator) this.aggregator).isAggregationComplete());
}
private static Message<?> createMessage(String payload, Object correlationId,
int sequenceSize, int sequenceNumber, MessageChannel replyChannel, UUID predefinedId) {
MessageBuilder<String> builder = MessageBuilder.withPayload(payload)
.setCorrelationId(correlationId)
.setSequenceSize(sequenceSize)
.setSequenceNumber(sequenceNumber)
.setReplyChannel(replyChannel);
if (predefinedId != null) {
builder.setHeader(MessageHeaders.ID, predefinedId);
}
return builder.build();
}
private static class TestAggregator extends AbstractMessageAggregator {
public Message<?> aggregateMessages(List<Message<?>> messages) {
List<Message<?>> sortableList = new ArrayList<Message<?>>(messages);
Collections.sort(sortableList, new MessageSequenceComparator());
StringBuffer buffer = new StringBuffer();
for (Message<?> message : sortableList) {
buffer.append(message.getPayload().toString());
}
return new StringMessage(buffer.toString());
}
}
private static class NullReturningAggregator extends AbstractMessageAggregator {
private boolean aggregationComplete;
public boolean isAggregationComplete() {
return aggregationComplete;
}
public Message<?> aggregateMessages(List<Message<?>> messages) {
this.aggregationComplete = true;
return null;
}
}
private static class AggregatorTestTask implements Runnable {
private AbstractMessageAggregator aggregator;
private Message<?> message;
private Exception exception;
private CountDownLatch latch;
AggregatorTestTask(AbstractMessageAggregator aggregator, Message<?> message, CountDownLatch latch) {
this.aggregator = aggregator;
this.message = message;
this.latch = latch;
}
public Exception getException() {
return this.exception;
}
public void run() {
try {
this.aggregator.handleMessage(message);
}
catch (Exception e) {
this.exception = e;
}
finally {
this.latch.countDown();
}
}
}
@After
public void stopTaskScheduler() {
this.taskScheduler.destroy();
this.aggregator.stop();
}
}

View File

@@ -1,207 +0,0 @@
/*
* Copyright 2002-2008 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.aggregator;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.integration.annotation.Aggregator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.core.Message;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.message.MessageBuilder;
import java.lang.reflect.Method;
import java.util.List;
import static org.junit.Assert.assertEquals;
/**
* @author Mark Fisher
*/
/*
* TODO This class needs to be removed with INT-1017. We need to ensure that the tests herein are superseded by
* MethodInvokingMessageGroupProcessorTests before deleting it entirely.
*/
public class AggregatorMethodResolutionTests {
@Test
public void singleAnnotation() throws Exception {
SingleAnnotationTestBean bean = new SingleAnnotationTestBean();
MethodInvokingAggregator aggregator = new MethodInvokingAggregator(bean);
Method method = this.getMethod(aggregator);
Method expected = SingleAnnotationTestBean.class.getMethod("method1", new Class[]{List.class});
assertEquals(expected, method);
}
@Test(expected = IllegalArgumentException.class)
public void multipleAnnotations() {
MultipleAnnotationTestBean bean = new MultipleAnnotationTestBean();
new MethodInvokingAggregator(bean);
}
@Test
public void noAnnotations() throws Exception {
NoAnnotationTestBean bean = new NoAnnotationTestBean();
MethodInvokingAggregator aggregator = new MethodInvokingAggregator(bean);
Method method = this.getMethod(aggregator);
Method expected = NoAnnotationTestBean.class.getMethod("method1", new Class[]{List.class});
assertEquals(expected, method);
}
@Test(expected = IllegalArgumentException.class)
public void multiplePublicMethods() {
MultiplePublicMethodTestBean bean = new MultiplePublicMethodTestBean();
new MethodInvokingAggregator(bean);
}
@Test(expected = IllegalArgumentException.class)
public void noPublicMethods() {
NoPublicMethodTestBean bean = new NoPublicMethodTestBean();
new MethodInvokingAggregator(bean);
}
@Test
public void jdkProxy() {
DirectChannel input = new DirectChannel();
QueueChannel output = new QueueChannel();
GreetingService testBean = new GreetingBean();
ProxyFactory proxyFactory = new ProxyFactory(testBean);
proxyFactory.setProxyTargetClass(false);
testBean = (GreetingService) proxyFactory.getProxy();
MethodInvokingAggregator aggregator = new MethodInvokingAggregator(testBean);
aggregator.setAutoStartup(false);
aggregator.setOutputChannel(output);
EventDrivenConsumer endpoint = new EventDrivenConsumer(input, aggregator);
endpoint.start();
Message<?> message = MessageBuilder.withPayload("proxy")
.setCorrelationId("abc")
.build();
input.send(message);
assertEquals("hello proxy", output.receive(0).getPayload());
}
@Test
public void cglibProxy() {
DirectChannel input = new DirectChannel();
QueueChannel output = new QueueChannel();
GreetingService testBean = new GreetingBean();
ProxyFactory proxyFactory = new ProxyFactory(testBean);
proxyFactory.setProxyTargetClass(true);
testBean = (GreetingService) proxyFactory.getProxy();
MethodInvokingAggregator aggregator = new MethodInvokingAggregator(testBean);
aggregator.setAutoStartup(false);
aggregator.setOutputChannel(output);
EventDrivenConsumer endpoint = new EventDrivenConsumer(input, aggregator);
endpoint.start();
Message<?> message = MessageBuilder.withPayload("proxy")
.setCorrelationId("abc")
.build();
input.send(message);
assertEquals("hello proxy", output.receive(0).getPayload());
}
private Method getMethod(MethodInvokingAggregator aggregator) {
Object invoker = new DirectFieldAccessor(aggregator).getPropertyValue("methodInvoker");
return (Method) new DirectFieldAccessor(invoker).getPropertyValue("method");
}
private static class SingleAnnotationTestBean {
@Aggregator
public String method1(List<String> input) {
return input.get(0);
}
public String method2(List<String> input) {
return input.get(0);
}
}
private static class MultipleAnnotationTestBean {
@Aggregator
public String method1(List<String> input) {
return input.get(0);
}
@Aggregator
public String method2(List<String> input) {
return input.get(0);
}
}
private static class NoAnnotationTestBean {
public String method1(List<String> input) {
return input.get(0);
}
String method2(List<String> input) {
return input.get(0);
}
}
private static class MultiplePublicMethodTestBean {
public String upperCase(String s) {
return s.toUpperCase();
}
public String lowerCase(String s) {
return s.toLowerCase();
}
}
private static class NoPublicMethodTestBean {
String lowerCase(String s) {
return s.toLowerCase();
}
}
public interface GreetingService {
String sayHello(List<String> names);
}
public static class GreetingBean implements GreetingService {
private String greeting = "hello";
public void setGreeting(String greeting) {
this.greeting = greeting;
}
@Aggregator
public String sayHello(List<String> names) {
return greeting + " " + names.get(0);
}
}
}

View File

@@ -22,7 +22,6 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import java.util.Collection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -43,7 +42,7 @@ import org.springframework.integration.store.SimpleMessageStore;
* @author Marius Bogoevici
* @author Iwein Fuld
*/
public class NewAggregatorEndpointTests {
public class AggregatorTests {
private CorrelatingMessageHandler aggregator;
@@ -115,34 +114,20 @@ public class NewAggregatorEndpointTests {
aggregator.handleMessage(message6);
aggregator.handleMessage(message4);
aggregator.handleMessage(message2);
@SuppressWarnings("unchecked")
Message<Integer> reply1 = (Message<Integer>) replyChannel1.receive(500);
assertNotNull(reply1);
assertThat(reply1.getPayload(), is(105));
@SuppressWarnings("unchecked")
Message<Integer> reply2 = (Message<Integer>) replyChannel2.receive(500);
assertNotNull(reply2);
assertThat(reply2.getPayload(), is(2431));
}
@Test
public void testDiscardChannelForTrackedCorrelationId() {
QueueChannel replyChannel = new QueueChannel();
QueueChannel discardChannel = new QueueChannel();
this.aggregator.setDiscardChannel(discardChannel);
this.aggregator.handleMessage(createMessage(1, "tracked", 1, 1, replyChannel, null));
Message<?> received1 = replyChannel.receive(0);
assertEquals(1, received1.getPayload());
assertNotNull("Expected aggregated message, but got null", received1);
this.aggregator.handleMessage(createMessage(2, "tracked", 1, 1, replyChannel, null));
Message<?> received2 = discardChannel.receive(0);
assertNotNull("Expected discarded message, but got null", received2);
assertEquals(2, received2.getPayload());
}
@Test
@Ignore
//dropped backwards compatibility for setting capacity limit (it's always Integer.MAX_VALUE)
public void testTrackedCorrelationIdsCapacityAtLimit() {
this.aggregator.start();
QueueChannel replyChannel = new QueueChannel();
QueueChannel discardChannel = new QueueChannel();
//this.aggregator.setTrackedCorrelationIdCapacity(3);
@@ -162,7 +147,6 @@ public class NewAggregatorEndpointTests {
@Ignore
//dropped backwards compatibility for setting capacity limit (it's always Integer.MAX_VALUE)
public void testTrackedCorrelationIdsCapacityPassesLimit() {
this.aggregator.start();
QueueChannel replyChannel = new QueueChannel();
QueueChannel discardChannel = new QueueChannel();
//this.aggregator.setTrackedCorrelationIdCapacity(3);
@@ -258,7 +242,7 @@ public class NewAggregatorEndpointTests {
MessageChannelTemplate channelTemplate, MessageChannel outputChannel
) {
Integer product = 1;
for (Message<?> message : group.getMessages()) {
for (Message<?> message : group.getUnmarked()) {
product *= (Integer) message.getPayload();
}
channelTemplate.send(MessageBuilder.withPayload(product).build(), outputChannel);

View File

@@ -0,0 +1,363 @@
/*
* Copyright 2002-2009 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.aggregator;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.integration.channel.MessageChannelTemplate;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.core.MessageHeaders;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.message.MessageHandler;
import org.springframework.integration.message.MessageHandlingException;
import org.springframework.integration.store.SimpleMessageStore;
/**
* @author Mark Fisher
* @author Marius Bogoevici
* @author Iwein Fuld
*/
public class ConcurrentAggregatorTests {
private TaskExecutor taskExecutor;
private CorrelatingMessageHandler aggregator;
@Before
public void configureAggregator() {
this.taskExecutor = new SimpleAsyncTaskExecutor();
this.aggregator = new CorrelatingMessageHandler(new SimpleMessageStore(
50), new MultiplyingProcessor());
}
@Test
public void testCompleteGroupWithinTimeout() throws InterruptedException {
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage(3, "ABC", 3, 1, replyChannel, null);
Message<?> message2 = createMessage(5, "ABC", 3, 2, replyChannel, null);
Message<?> message3 = createMessage(7, "ABC", 3, 3, replyChannel, null);
CountDownLatch latch = new CountDownLatch(3);
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator,
message1, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator,
message2, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator,
message3, latch));
latch.await(10000, TimeUnit.MILLISECONDS);
assertThat(latch.getCount(), is(0l));
Message<?> reply = replyChannel.receive(2000);
assertNotNull(reply);
assertEquals(reply.getPayload(), 105);
}
@Test
@Ignore
// dropped backwards compatibility for duplicate ID's
public void testCompleteGroupWithinTimeoutWithSameId()
throws InterruptedException {
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage(3, "ABC", 3, 1, replyChannel,
"ID#1");
Message<?> message2 = createMessage(5, "ABC", 3, 2, replyChannel,
"ID#1");
Message<?> message3 = createMessage(7, "ABC", 3, 3, replyChannel,
"ID#1");
CountDownLatch latch = new CountDownLatch(3);
// for testing the duplication scenario, the messages must be processed
// synchronously
new AggregatorTestTask(this.aggregator, message1, latch).run();
new AggregatorTestTask(this.aggregator, message2, latch).run();
new AggregatorTestTask(this.aggregator, message3, latch).run();
Message<?> reply = replyChannel.receive(500);
assertNotNull(reply);
assertEquals("123456789", reply.getPayload());
}
@Test
public void testShouldNotSendPartialResultOnTimeoutByDefault()
throws InterruptedException {
QueueChannel discardChannel = new QueueChannel();
this.aggregator.setDiscardChannel(discardChannel);
QueueChannel replyChannel = new QueueChannel();
Message<?> message = createMessage(3, "ABC", 2, 1, replyChannel, null);
CountDownLatch latch = new CountDownLatch(1);
AggregatorTestTask task = new AggregatorTestTask(this.aggregator,
message, latch);
this.taskExecutor.execute(task);
latch.await(200, TimeUnit.MILLISECONDS);
assertEquals("Task should have completed within timeout", 0, latch
.getCount());
Message<?> reply = replyChannel.receive(100);
assertNull("No message should have been sent normally", reply);
aggregator.forceComplete("ABC");
Message<?> discardedMessage = discardChannel.receive(100);
assertNotNull("A message should have been discarded", discardedMessage);
assertEquals(message, discardedMessage);
}
@Test
public void testShouldSendPartialResultOnTimeoutTrue()
throws InterruptedException {
this.aggregator.setSendPartialResultOnTimeout(true);
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage(3, "ABC", 3, 1, replyChannel, null);
Message<?> message2 = createMessage(5, "ABC", 3, 2, replyChannel, null);
CountDownLatch latch = new CountDownLatch(2);
AggregatorTestTask task1 = new AggregatorTestTask(this.aggregator,
message1, latch);
AggregatorTestTask task2 = new AggregatorTestTask(this.aggregator,
message2, latch);
this.taskExecutor.execute(task1);
this.taskExecutor.execute(task2);
latch.await(300, TimeUnit.MILLISECONDS);
assertEquals("handlers should have been invoked within time limit", 0,
latch.getCount());
this.aggregator.forceComplete("ABC");
Message<?> reply = replyChannel.receive(100);
assertNotNull("A reply message should have been received", reply);
assertEquals(15, reply.getPayload());
assertNull(task1.getException());
assertNull(task2.getException());
}
@Test
public void testMultipleGroupsSimultaneously() throws InterruptedException {
QueueChannel replyChannel1 = new QueueChannel();
QueueChannel replyChannel2 = new QueueChannel();
Message<?> message1 = createMessage(3, "ABC", 3, 1, replyChannel1, null);
Message<?> message2 = createMessage(5, "ABC", 3, 2, replyChannel1, null);
Message<?> message3 = createMessage(7, "ABC", 3, 3, replyChannel1, null);
Message<?> message4 = createMessage(11, "XYZ", 3, 1, replyChannel2,
null);
Message<?> message5 = createMessage(13, "XYZ", 3, 2, replyChannel2,
null);
Message<?> message6 = createMessage(17, "XYZ", 3, 3, replyChannel2,
null);
CountDownLatch latch = new CountDownLatch(6);
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator,
message1, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator,
message6, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator,
message2, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator,
message5, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator,
message3, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator,
message4, latch));
latch.await(1000, TimeUnit.MILLISECONDS);
@SuppressWarnings("unchecked")
Message<Integer> reply1 = (Message<Integer>) replyChannel1.receive(500);
assertNotNull(reply1);
assertThat(reply1.getPayload(), is(105));
@SuppressWarnings("unchecked")
Message<Integer> reply2 = (Message<Integer>) replyChannel2.receive(500);
assertNotNull(reply2);
assertThat(reply2.getPayload(), is(2431));
}
@Test
@Ignore
// dropped backwards compatibility for setting capacity limit (it's always
// Integer.MAX_VALUE)
public void testTrackedCorrelationIdsCapacityAtLimit() {
QueueChannel replyChannel = new QueueChannel();
QueueChannel discardChannel = new QueueChannel();
// this.aggregator.setTrackedCorrelationIdCapacity(3);
this.aggregator.setDiscardChannel(discardChannel);
this.aggregator.handleMessage(createMessage(1, 1, 1, 1, replyChannel,
null));
assertEquals(1, replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage(3, 2, 1, 1, replyChannel,
null));
assertEquals(3, replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage(4, 3, 1, 1, replyChannel,
null));
assertEquals(4, replyChannel.receive(100).getPayload());
// next message with same correlation ID is discarded
this.aggregator.handleMessage(createMessage(2, 1, 1, 1, replyChannel,
null));
assertEquals(2, discardChannel.receive(100).getPayload());
}
@Test
@Ignore
// dropped backwards compatibility for setting capacity limit (it's always
// Integer.MAX_VALUE)
public void testTrackedCorrelationIdsCapacityPassesLimit() {
QueueChannel replyChannel = new QueueChannel();
QueueChannel discardChannel = new QueueChannel();
// this.aggregator.setTrackedCorrelationIdCapacity(3);
this.aggregator.setDiscardChannel(discardChannel);
this.aggregator.handleMessage(createMessage(1, 1, 1, 1, replyChannel,
null));
assertEquals(1, replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage(2, 2, 1, 1, replyChannel,
null));
assertEquals(2, replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage(3, 3, 1, 1, replyChannel,
null));
assertEquals(3, replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage(4, 4, 1, 1, replyChannel,
null));
assertEquals(4, replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage(5, 1, 1, 1, replyChannel,
null));
assertEquals(5, replyChannel.receive(100).getPayload());
assertNull(discardChannel.receive(0));
}
@Test(expected = MessageHandlingException.class)
public void testExceptionThrownIfNoCorrelationId()
throws InterruptedException {
Message<?> message = createMessage(3, null, 2, 1, new QueueChannel(),
null);
this.aggregator.handleMessage(message);
}
@Test
public void testAdditionalMessageAfterCompletion()
throws InterruptedException {
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage(3, "ABC", 3, 1, replyChannel, null);
Message<?> message2 = createMessage(5, "ABC", 3, 2, replyChannel, null);
Message<?> message3 = createMessage(7, "ABC", 3, 3, replyChannel, null);
Message<?> message4 = createMessage(7, "ABC", 3, 3, replyChannel, null);
CountDownLatch latch = new CountDownLatch(4);
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator,
message1, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator,
message2, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator,
message3, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator,
message4, latch));
latch.await(1000, TimeUnit.MILLISECONDS);
Message<?> reply = replyChannel.receive(100);
assertNotNull("A message should be aggregated", reply);
assertThat(((Integer) reply.getPayload()), is(105));
}
@Test
public void testNullReturningAggregator() throws InterruptedException {
this.aggregator = new CorrelatingMessageHandler(new SimpleMessageStore(
50), new NullReturningMessageProcessor());
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage(3, "ABC", 3, 1, replyChannel, null);
Message<?> message2 = createMessage(5, "ABC", 3, 2, replyChannel, null);
Message<?> message3 = createMessage(7, "ABC", 3, 3, replyChannel, null);
CountDownLatch latch = new CountDownLatch(3);
AggregatorTestTask task1 = new AggregatorTestTask(aggregator, message1,
latch);
this.taskExecutor.execute(task1);
AggregatorTestTask task2 = new AggregatorTestTask(aggregator, message2,
latch);
this.taskExecutor.execute(task2);
AggregatorTestTask task3 = new AggregatorTestTask(aggregator, message3,
latch);
this.taskExecutor.execute(task3);
latch.await(1000, TimeUnit.MILLISECONDS);
assertNull(task1.getException());
assertNull(task2.getException());
assertNull(task3.getException());
Message<?> reply = replyChannel.receive(500);
assertNull(reply);
}
private static Message<?> createMessage(Object payload,
Object correlationId, int sequenceSize, int sequenceNumber,
MessageChannel replyChannel, String predefinedId) {
MessageBuilder<Object> builder = MessageBuilder.withPayload(payload)
.setCorrelationId(correlationId).setSequenceSize(sequenceSize)
.setSequenceNumber(sequenceNumber)
.setReplyChannel(replyChannel);
if (predefinedId != null) {
builder.setHeader(MessageHeaders.ID, predefinedId);
}
return builder.build();
}
private static class AggregatorTestTask implements Runnable {
private MessageHandler aggregator;
private Message<?> message;
private Exception exception;
private CountDownLatch latch;
AggregatorTestTask(MessageHandler aggregator, Message<?> message,
CountDownLatch latch) {
this.aggregator = aggregator;
this.message = message;
this.latch = latch;
}
public Exception getException() {
return this.exception;
}
public void run() {
try {
this.aggregator.handleMessage(message);
} catch (Exception e) {
e.printStackTrace();
this.exception = e;
} finally {
this.latch.countDown();
}
}
}
private class MultiplyingProcessor implements MessageGroupProcessor {
public void processAndSend(MessageGroup group,
MessageChannelTemplate channelTemplate,
MessageChannel outputChannel) {
Integer product = 1;
for (Message<?> message : group.getUnmarked()) {
product *= (Integer) message.getPayload();
}
channelTemplate.send(MessageBuilder.withPayload(product).build(),
outputChannel);
}
}
private class NullReturningMessageProcessor implements
MessageGroupProcessor {
public void processAndSend(MessageGroup group,
MessageChannelTemplate channelTemplate,
MessageChannel outputChannel) {
// noop
}
}
}

View File

@@ -36,7 +36,6 @@ public class CorrelatingMessageHandlerIntegrationTest {
private CorrelatingMessageHandler defaultHandler = new CorrelatingMessageHandler(store, processor);
@Before
public void setupHandler() {
defaultHandler.setOutputChannel(outputChannel);
@@ -52,14 +51,17 @@ public class CorrelatingMessageHandlerIntegrationTest {
}
@Test
public void completesAfterSequenceComplete() throws Exception {
public void completesAfterThreshold() throws Exception {
defaultHandler.setReleaseStrategy(new MessageCountReleaseStrategy());
MessageChannel discardChannel = mock(MessageChannel.class);
defaultHandler.setDiscardChannel(discardChannel);
Message<?> message1 = correlatedMessage(1, 2, 1);
Message<?> message2 = correlatedMessage(1, 2, 2);
defaultHandler.handleMessage(message1);
verify(outputChannel, never()).send(message1);
defaultHandler.handleMessage(message2);
verify(outputChannel).send(message1);
verify(outputChannel).send(message2);
defaultHandler.handleMessage(message2);
verify(outputChannel, never()).send(message2);
verify(discardChannel).send(message2);
}
@Test
@@ -82,6 +84,17 @@ public class CorrelatingMessageHandlerIntegrationTest {
verify(outputChannel).send(message2a);
}
@Test
public void completesAfterSequenceComplete() throws Exception {
Message<?> message1 = correlatedMessage(1, 2, 1);
Message<?> message2 = correlatedMessage(1, 2, 2);
defaultHandler.handleMessage(message1);
verify(outputChannel, never()).send(message1);
defaultHandler.handleMessage(message2);
verify(outputChannel).send(message1);
verify(outputChannel).send(message2);
}
private Message<?> correlatedMessage(Object correlationId, Integer sequenceSize, Integer sequenceNumber) {
return MessageBuilder.withPayload("test")

View File

@@ -16,17 +16,17 @@
package org.springframework.integration.aggregator;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
@@ -34,137 +34,107 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.internal.stubbing.answers.DoesNothing;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.integration.channel.MessageChannelTemplate;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.store.MessageStore;
import org.springframework.integration.store.SimpleMessageStore;
import org.springframework.test.util.ReflectionTestUtils;
/**
* @author Iwein Fuld
* @author Dave Syer
*/
@RunWith(MockitoJUnitRunner.class)
public class CorrelatingMessageHandlerTests {
private CorrelatingMessageHandler handler;
private CorrelatingMessageHandler handler;
@Mock
private MessageStore store;
@Mock
private CorrelationStrategy correlationStrategy;
@Mock
private CorrelationStrategy correlationStrategy;
private ReleaseStrategy ReleaseStrategy = new SequenceSizeReleaseStrategy();
@Mock
private CompletionStrategy completionStrategy;
@Mock
private MessageGroupProcessor processor;
@Mock
private MessageGroupProcessor processor;
@Mock
private MessageChannel outputChannel;
@Mock
private MessageChannel outputChannel;
@Before
public void initializeSubject() {
handler = new CorrelatingMessageHandler(new SimpleMessageStore(), correlationStrategy, ReleaseStrategy,
processor);
handler.setOutputChannel(outputChannel);
doAnswer(new DoesNothing()).when(processor).processAndSend(isA(MessageGroup.class),
isA(MessageChannelTemplate.class), eq(outputChannel));
}
@Before
public void initializeSubject() {
handler = new CorrelatingMessageHandler(
store, correlationStrategy, completionStrategy, processor);
handler.setOutputChannel(outputChannel);
doAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock invocation) throws Throwable {
MessageGroup messageGroup = (MessageGroup) invocation.getArguments()[0];
// TODO: remove this?
return null;
}
}).when(processor).processAndSend(isA(MessageGroup.class),
isA(MessageChannelTemplate.class), eq(outputChannel));
}
@Test
public void bufferCompletesNormally() throws Exception {
String correlationKey = "key";
Message<?> message1 = testMessage(correlationKey, 1, 2);
Message<?> message2 = testMessage(correlationKey, 2, 2);
List<Message<?>> storedMessages = new ArrayList<Message<?>>();
@Test
public void bufferCompletesNormally() throws Exception {
String correlationKey = "key";
Message<?> message1 = testMessage(correlationKey, 1);
Message<?> message2 = testMessage(correlationKey, 2);
List<Message<?>> storedMessages = new ArrayList<Message<?>>();
when(correlationStrategy.getCorrelationKey(isA(Message.class))).thenReturn(correlationKey);
when(store.list(correlationKey)).thenReturn(storedMessages);
handler.handleMessage(message1);
storedMessages.add(message1);
verifyLocks(handler, 1);
when(correlationStrategy.getCorrelationKey(isA(Message.class)))
.thenReturn(correlationKey);
handler.handleMessage(message2);
storedMessages.add(message2);
verifyLocks(handler, 0); // lock is removed when group is complete
when(completionStrategy.isComplete(Arrays.<Message<?>>asList(message1))).thenReturn(false);
verify(correlationStrategy).getCorrelationKey(message1);
verify(correlationStrategy).getCorrelationKey(message2);
verify(processor).processAndSend(isA(MessageGroup.class), isA(MessageChannelTemplate.class), eq(outputChannel));
}
handler.handleMessage(message1);
storedMessages.add(message1);
private void verifyLocks(CorrelatingMessageHandler handler, int lockCount) {
assertEquals(lockCount, ((Map<?, ?>) ReflectionTestUtils.getField(handler, "locks")).size());
}
when(completionStrategy.isComplete(Arrays.<Message<?>>asList(message1, message2))).thenReturn(true);
handler.handleMessage(message2);
storedMessages.add(message2);
/*
* The next test verifies that when pruning happens after the completing message arrived, but before the group was
* processed locking prevents forced completion and the group completes normally.
*/
verify(store).put(correlationKey, message1);
verify(store).put(correlationKey, message2);
verify(store, times(2)).list(correlationKey);
verify(correlationStrategy).getCorrelationKey(message1);
verify(correlationStrategy).getCorrelationKey(message2);
verify(completionStrategy).isComplete(Arrays.<Message<?>>asList(message1));
verify(completionStrategy).isComplete(Arrays.<Message<?>>asList(message1, message2));
verify(processor).processAndSend(isA(MessageGroup.class),
isA(MessageChannelTemplate.class), eq(outputChannel)
);
}
@Test
public void shouldNotPruneWhileCompleting() throws Exception {
String correlationKey = "key";
final Message<?> message1 = testMessage(correlationKey, 1, 2);
final Message<?> message2 = testMessage(correlationKey, 2, 2);
final List<Message<?>> storedMessages = new ArrayList<Message<?>>();
/*
The next test verifies that when pruning happens after the completing message arrived, but before the group was
processed locking prevents forced completion and the group completes normally.
*/
final CountDownLatch bothMessagesHandled = new CountDownLatch(2);
@Test
public void shouldNotPruneWhileCompleting() throws Exception {
String correlationKey = "key";
final Message<?> message1 = testMessage(correlationKey, 1);
final Message<?> message2 = testMessage(correlationKey, 2);
final List<Message<?>> storedMessages = new ArrayList<Message<?>>();
when(correlationStrategy.getCorrelationKey(isA(Message.class))).thenReturn(correlationKey);
final CountDownLatch bothMessagesHandled = new CountDownLatch(2);
handler.handleMessage(message1);
bothMessagesHandled.countDown();
storedMessages.add(message1);
Executors.newSingleThreadExecutor().submit(new Runnable() {
public void run() {
handler.handleMessage(message2);
storedMessages.add(message2);
bothMessagesHandled.countDown();
}
});
when(store.list(correlationKey)).thenReturn(storedMessages);
Thread.sleep(20);
assertFalse(handler.forceComplete("key"));
when(correlationStrategy.getCorrelationKey(isA(Message.class)))
.thenReturn(correlationKey);
bothMessagesHandled.await();
when(completionStrategy.isComplete(Arrays.<Message<?>>asList(message1, message2)))
.thenAnswer(new Answer<Boolean>() {
public Boolean answer(InvocationOnMock invocation) throws Throwable {
Thread.sleep(50);
return true;
}
}).thenReturn(true);
}
handler.handleMessage(message1);
bothMessagesHandled.countDown();
storedMessages.add(message1);
Executors.newSingleThreadExecutor().submit(new Runnable() {
public void run() {
handler.handleMessage(message2);
storedMessages.add(message2);
bothMessagesHandled.countDown();
}
});
Thread.sleep(20);
assertFalse(handler.forceComplete("key"));
bothMessagesHandled.await();
verify(store).put(correlationKey, message1);
verify(store).put(correlationKey, message2);
verify(store).deleteAll(correlationKey);
}
private Message<?> testMessage(String correlationKey, int sequenceNumber) {
return MessageBuilder.withPayload("test" + sequenceNumber)
.setCorrelationId(correlationKey)
.setSequenceNumber(sequenceNumber).build();
}
private Message<?> testMessage(String correlationKey, int sequenceNumber, int sequenceSize) {
return MessageBuilder.withPayload("test" + sequenceNumber).setCorrelationId(correlationKey).setSequenceNumber(
sequenceNumber).setSequenceSize(sequenceSize).build();
}
}

View File

@@ -1,51 +0,0 @@
/*
* Copyright 2002-2009 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.aggregator;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.springframework.integration.core.Message;
import org.springframework.integration.message.MessageBuilder;
/**
* @author Alex Peters
* @author Iwein Fuld
*/
public class DefaultMessageAggregatorTests {
DefaultMessageAggregator aggregator = new DefaultMessageAggregator();
@SuppressWarnings("unchecked")
@Test
public void aggregateMessages_withMultiplePayloads_allAsListInResultMsg() {
List<Object> anyPayloads = Arrays.asList("foo", "bar", 123L, new Object());
List<Message<?>> messageGroup = new ArrayList<Message<?>>(anyPayloads.size());
for (Object payload : anyPayloads) {
messageGroup.add(MessageBuilder.withPayload(payload).build());
}
Message<?> result = aggregator.aggregateMessages(messageGroup);
assertThat((List<Object>) result.getPayload(), is(anyPayloads));
}
}

View File

@@ -1,59 +0,0 @@
/*
* Copyright 2002-2008 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.aggregator;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.LinkedHashSet;
import org.junit.Test;
import org.springframework.integration.message.StringMessage;
/**
* @author Mark Fisher
*/
@SuppressWarnings("unchecked")
public class MessageBarrierTests {
@Test
public void testMessageRetrieval() {
MessageBarrier barrier = new MessageBarrier(new LinkedHashSet(), null);
barrier.getMessages().add(new StringMessage("test1"));
assertEquals(1, barrier.getMessages().size());
barrier.getMessages().add(new StringMessage("test2"));
assertEquals(2, barrier.getMessages().size());
}
@Test
public void testTimestamp() {
long before = System.currentTimeMillis();
MessageBarrier barrier = new MessageBarrier(new LinkedHashSet(), null);
long timestamp = barrier.getTimestamp();
assertTrue(before <= timestamp);
long after = System.currentTimeMillis();
assertTrue(after >= timestamp);
}
@Test
public void testEmptyMessageList() {
MessageBarrier barrier = new MessageBarrier(new LinkedHashSet(), null);
assertEquals(0, barrier.getMessages().size());
}
}

View File

@@ -7,9 +7,6 @@ import java.util.Collections;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.integration.core.Message;
import org.springframework.integration.message.MessageBuilder;
@@ -33,17 +30,17 @@ public class MessageGroupTests {
public void shouldFindSupersedingMessages() {
final Message<?> message1 = MessageBuilder.withPayload("test").setSequenceNumber(1).build();
final Message<?> message2 = MessageBuilder.fromMessage(message1).setSequenceNumber(1).build();
assertThat(group.hasNoMessageSuperseding(message1), is(true));
assertThat(group.add(message1), is(true));
group.add(message2);
assertThat(group.hasNoMessageSuperseding(message1), is(false));
assertThat(group.add(message1), is(false));
}
@Test
public void shouldIgnoreMessagesWithZeroSequenceNumber() {
final Message<?> message1 = MessageBuilder.withPayload("test").build();
final Message<?> message2 = MessageBuilder.fromMessage(message1).build();
assertThat(group.hasNoMessageSuperseding(message1), is(true));
assertThat(group.add(message1), is(true));
group.add(message2);
assertThat(group.hasNoMessageSuperseding(message1), is(true));
assertThat(group.add(message1), is(true));
}
}

View File

@@ -1,202 +0,0 @@
/*
* Copyright 2002-2008 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.aggregator;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.junit.Test;
import org.springframework.integration.core.Message;
import org.springframework.integration.message.GenericMessage;
import static org.easymock.EasyMock.*;
/**
* @author Marius Bogoevici
* @author Mark Fisher
* @author Iwein Fuld
*/
@SuppressWarnings("unchecked")
public class MethodInvokingAggregatorTests {
private TestAggregator mockAggregator = createMock(TestAggregator.class);
private List<Message<?>> messages = new ArrayList<Message<?>>();
@Test
public void adapterWithNonParameterizedMessageListBasedMethod() {
expect(mockAggregator.doAggregationOnNonParameterizedListOfMessages(isA(List.class))).andStubReturn(
new GenericMessage<String>(""));
MethodInvokingAggregator aggregator = new MethodInvokingAggregator(mockAggregator,
"doAggregationOnNonParameterizedListOfMessages");
replay(mockAggregator);
aggregator.aggregateMessages(messages);
verify(mockAggregator);
}
@Test
public void adapterWithWildcardParameterizedMessageBasedMethod() {
expect(mockAggregator.doAggregationOnListOfMessagesParametrizedWithWildcard(isA(List.class))).andStubReturn(
new GenericMessage<String>(""));
MethodInvokingAggregator aggregator = new MethodInvokingAggregator(mockAggregator,
"doAggregationOnListOfMessagesParametrizedWithWildcard");
replay(mockAggregator);
aggregator.aggregateMessages(messages);
verify(mockAggregator);
}
@Test
public void adapterWithTypeParameterizedMessageBasedMethod() {
expect(mockAggregator.doAggregationOnListOfMessagesParametrizedWithString(isA(List.class))).andStubReturn(
new GenericMessage<String>(""));
MethodInvokingAggregator aggregator = new MethodInvokingAggregator(mockAggregator,
"doAggregationOnListOfMessagesParametrizedWithString");
replay(mockAggregator);
aggregator.aggregateMessages(messages);
verify(mockAggregator);
}
@Test
public void adapterWithPojoBasedMethod() {
expect(mockAggregator.doAggregationOnListOfStrings(isA(List.class))).andStubReturn(
new GenericMessage<String>(""));
MethodInvokingAggregator aggregator = new MethodInvokingAggregator(mockAggregator,
"doAggregationOnListOfStrings");
replay(mockAggregator);
aggregator.aggregateMessages(messages);
verify(mockAggregator);
}
@Test
public void adapterWithPojoBasedMethodReturningObject() {
expect(mockAggregator.doAggregationOnListOfStringsReturningLong(isA(List.class))).andStubReturn(6l);
MethodInvokingAggregator aggregator = new MethodInvokingAggregator(mockAggregator,
"doAggregationOnListOfStringsReturningLong");
replay(mockAggregator);
aggregator.aggregateMessages(messages);
verify(mockAggregator);
}
@Test
public void adapterWithVoidReturnType() {
MethodInvokingAggregator aggregator = new MethodInvokingAggregator(mockAggregator, "doAggregationWithNoReturn");
replay(mockAggregator);
aggregator.aggregateMessages(messages);
verify(mockAggregator);
}
@Test
public void adapterWithNullReturn() {
MethodInvokingAggregator aggregator = new MethodInvokingAggregator(mockAggregator,
"doAggregationOnListOfStrings");
replay(mockAggregator);
aggregator.aggregateMessages(messages);
verify(mockAggregator);
}
@Test(expected = IllegalArgumentException.class)
public void adapterWithWrongMethodName() {
new MethodInvokingAggregator(mockAggregator, "methodThatDoesNotExist");
}
@Test(expected = IllegalArgumentException.class)
public void invalidParameterTypeUsingMethodName() {
new MethodInvokingAggregator(mockAggregator, "invalidParameterType");
}
@Test(expected = IllegalArgumentException.class)
public void tooManyParametersUsingMethodName() {
new MethodInvokingAggregator(mockAggregator, "tooManyParameters");
}
@Test(expected = IllegalArgumentException.class)
public void notEnoughParametersUsingMethodName() {
new MethodInvokingAggregator(mockAggregator, "notEnoughParameters");
}
@Test(expected = IllegalArgumentException.class)
public void listSubclassParameterUsingMethodName() {
new MethodInvokingAggregator(mockAggregator, "ListSubclassParameter");
}
@Test(expected = IllegalArgumentException.class)
public void invalidParameterTypeUsingMethodObject() throws SecurityException, NoSuchMethodException {
new MethodInvokingAggregator(mockAggregator, mockAggregator.getClass().getMethod("invalidParameterType",
String.class));
}
@Test(expected = IllegalArgumentException.class)
public void tooManyParametersUsingMethodObject() throws SecurityException, NoSuchMethodException {
new MethodInvokingAggregator(mockAggregator, mockAggregator.getClass().getMethod("tooManyParameters",
List.class, List.class));
}
@Test(expected = IllegalArgumentException.class)
public void notEnoughParametersUsingMethodObject() throws SecurityException, NoSuchMethodException {
new MethodInvokingAggregator(mockAggregator, mockAggregator.getClass().getMethod("notEnoughParameters",
new Class[] {}));
}
@Test(expected = IllegalArgumentException.class)
public void listSubclassParameterUsingMethodObject() throws SecurityException, NoSuchMethodException {
new MethodInvokingAggregator(mockAggregator, mockAggregator.getClass().getMethod("listSubclassParameter",
new Class[] { LinkedList.class }));
}
@Test(expected = IllegalArgumentException.class)
public void nullObject() {
new MethodInvokingAggregator(null, "doesNotMatter");
}
@Test(expected = IllegalArgumentException.class)
public void nullMethodName() {
String methodName = null;
new MethodInvokingAggregator(mockAggregator, methodName);
}
@Test(expected = IllegalArgumentException.class)
public void nullMethodObject() {
Method method = null;
new MethodInvokingAggregator(mockAggregator, method);
}
private interface TestAggregator {
public Message<?> doAggregationOnNonParameterizedListOfMessages(List<Message> messages);
public Message<?> doAggregationOnListOfMessagesParametrizedWithWildcard(List<Message<?>> messages);
public Message<?> doAggregationOnListOfMessagesParametrizedWithString(List<Message<String>> messages);
public Message<?> doAggregationOnListOfStrings(List<String> messages);
public Long doAggregationOnListOfStringsReturningLong(List<String> messages);
public void doAggregationWithNoReturn(List<String> message);
public Message<?> invalidParameterType(String invalid);
public Message<?> tooManyParameters(List<?> c1, List<?> c2);
public Message<?> notEnoughParameters();
public Message<?> listSubclassParameter(LinkedList<?> l1);
}
}

View File

@@ -1,22 +1,7 @@
package org.springframework.integration.aggregator;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.integration.annotation.Aggregator;
import org.springframework.integration.annotation.Header;
import org.springframework.integration.channel.MessageChannelTemplate;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.message.MessageBuilder;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.eq;
@@ -24,154 +9,324 @@ import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.integration.annotation.Aggregator;
import org.springframework.integration.annotation.Header;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.MessageChannelTemplate;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.message.MessageBuilder;
@RunWith(MockitoJUnitRunner.class)
public class MethodInvokingMessageGroupProcessorTests {
@Mock
private MessageGroupListener processedCallback;
@Mock
private MessageChannel outputChannel;
@Mock
private MessageChannel outputChannel;
private List<Message<?>> messagesUpForProcessing = new ArrayList<Message<?>>(3);
private List<Message<?>> messagesUpForProcessing = new ArrayList<Message<?>>(
3);
@Mock
private MessageGroup messageGroupMock;
@Mock
private MessageGroup messageGroupMock;
@Mock
private MessageChannelTemplate channelTemplate;
@Mock
private MessageChannelTemplate channelTemplate;
@Before
public void initializeMessagesUpForProcessing() {
messagesUpForProcessing.add(MessageBuilder.withPayload(1).build());
messagesUpForProcessing.add(MessageBuilder.withPayload(2).build());
messagesUpForProcessing.add(MessageBuilder.withPayload(4).build());
}
@Before
public void initializeMessagesUpForProcessing() {
messagesUpForProcessing.add(MessageBuilder.withPayload(1).build());
messagesUpForProcessing.add(MessageBuilder.withPayload(2).build());
messagesUpForProcessing.add(MessageBuilder.withPayload(4).build());
}
private class AnnotatedAggregatorMethod {
@SuppressWarnings("unused")
private class AnnotatedAggregatorMethod {
@Aggregator
@SuppressWarnings("unused")
public Integer and(List<Integer> flags) {
int result = 0;
for (Integer flag : flags) {
result = result | flag;
}
return result;
}
@Aggregator
public Integer and(List<Integer> flags) {
int result = 0;
for (Integer flag : flags) {
result = result | flag;
}
return result;
}
public String know(List<Integer> flags) {
return "I'm not the one ";
}
}
public String know(List<Integer> flags) {
return "I'm not the one ";
}
}
@Test
public void shouldFindAnnotatedAggregatorMethod() throws Exception {
MessageGroupProcessor processor = new MethodInvokingMessageGroupProcessor(
new AnnotatedAggregatorMethod());
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor
.forClass(Message.class);
when(outputChannel.send(isA(Message.class))).thenReturn(true);
when(messageGroupMock.getMessages()).thenReturn(messagesUpForProcessing);
processor.processAndSend(messageGroupMock, channelTemplate, outputChannel);
// verify
verify(channelTemplate).send(messageCaptor.capture(), eq(outputChannel));
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
}
@Test
public void shouldFindAnnotatedAggregatorMethod() throws Exception {
MessageGroupProcessor processor = new MethodInvokingMessageGroupProcessor(new AnnotatedAggregatorMethod());
@SuppressWarnings("unchecked")
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
when(outputChannel.send(isA(Message.class))).thenReturn(true);
when(messageGroupMock.getUnmarked()).thenReturn(messagesUpForProcessing);
processor.processAndSend(messageGroupMock, channelTemplate, outputChannel);
// verify
verify(channelTemplate).send(messageCaptor.capture(), eq(outputChannel));
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
}
@SuppressWarnings("unused")
private class SimpleAggregator {
public Integer and(List<Integer> flags) {
int result = 0;
for (Integer flag : flags) {
result = result | flag;
}
return result;
}
}
private class SimpleAggregator {
public Integer and(List<Integer> flags) {
int result = 0;
for (Integer flag : flags) {
result = result | flag;
}
return result;
}
}
@Test
public void shouldFindSimpleAggregatorMethod() throws Exception {
MessageGroupProcessor processor = new MethodInvokingMessageGroupProcessor(new SimpleAggregator());
@SuppressWarnings("unchecked")
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
when(outputChannel.send(isA(Message.class))).thenReturn(true);
when(messageGroupMock.getUnmarked()).thenReturn(messagesUpForProcessing);
processor.processAndSend(messageGroupMock, channelTemplate, outputChannel);
// verify
verify(channelTemplate).send(messageCaptor.capture(), eq(outputChannel));
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
}
@Test
public void shouldFindSimpleAggregatorMethod() throws Exception {
MessageGroupProcessor processor = new MethodInvokingMessageGroupProcessor(
new SimpleAggregator());
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor
.forClass(Message.class);
when(outputChannel.send(isA(Message.class))).thenReturn(true);
when(messageGroupMock.getMessages()).thenReturn(messagesUpForProcessing);
processor.processAndSend(messageGroupMock, channelTemplate, outputChannel);
// verify
verify(channelTemplate).send(messageCaptor.capture(), eq(outputChannel));
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
}
@SuppressWarnings("unused")
private class UnnanotatedAggregator {
public Integer and(List<Integer> flags) {
int result = 0;
for (Integer flag : flags) {
result = result | flag;
}
return result;
}
public void voidMethodShouldBeIgnored(List<Integer> flags) {
fail("this method should not be invoked");
}
private class UnnanotatedAggregator {
public Integer and(List<Integer> flags) {
int result = 0;
for (Integer flag : flags) {
result = result | flag;
}
return result;
}
public String methodAcceptingNoCollectionShouldBeIgnored(@Header String irrelevant) {
fail("this method should not be invoked");
return null;
}
}
public void voidMethodShouldBeIgnored(List<Integer> flags) {
fail("this method should not be invoked");
}
@Test
public void shouldFindFittingMethodAmongMultipleUnannotated() {
MessageGroupProcessor processor = new MethodInvokingMessageGroupProcessor(new UnnanotatedAggregator());
public String methodAcceptingNoCollectionShouldBeIgnored(@Header String irrelevant) {
fail("this method should not be invoked");
return null;
}
}
@SuppressWarnings("unchecked")
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
@Test
public void shouldFindFittingMethodAmongMultipleUnanotated() {
MessageGroupProcessor processor = new MethodInvokingMessageGroupProcessor(
new UnnanotatedAggregator()
);
when(outputChannel.send(isA(Message.class))).thenReturn(true);
when(messageGroupMock.getUnmarked()).thenReturn(messagesUpForProcessing);
processor.processAndSend(messageGroupMock, channelTemplate, outputChannel);
// verify
verify(channelTemplate).send(messageCaptor.capture(), eq(outputChannel));
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
}
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor
.forClass(Message.class);
@SuppressWarnings("unused")
private class AnnotatedParametersAggregator {
public Integer and(List<Integer> flags) {
int result = 0;
for (Integer flag : flags) {
result = result | flag;
}
return result;
}
when(outputChannel.send(isA(Message.class))).thenReturn(true);
when(messageGroupMock.getMessages()).thenReturn(messagesUpForProcessing);
processor.processAndSend(messageGroupMock, channelTemplate, outputChannel
);
// verify
verify(channelTemplate).send(messageCaptor.capture(), eq(outputChannel));
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
}
public String listHeaderShouldBeIgnored(@Header List<Integer> flags) {
fail("this method should not be invoked");
return "";
}
}
private class AnnotatedParametersAggregator {
public Integer and(List<Integer> flags) {
int result = 0;
for (Integer flag : flags) {
result = result | flag;
}
return result;
}
@Test
public void shouldFindFittingMethodAmongMultipleWithAnnotatedParameters() {
MessageGroupProcessor processor = new MethodInvokingMessageGroupProcessor(new AnnotatedParametersAggregator());
public String listHeaderShouldBeIgnored(@Header List<Integer> flags) {
fail("this method should not be invoked");
return "";
}
}
@SuppressWarnings("unchecked")
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
@Test
public void shouldFindFittingMethodAmongMultipleWithAnnotatedParameters() {
MessageGroupProcessor processor = new MethodInvokingMessageGroupProcessor(
new AnnotatedParametersAggregator()
);
when(outputChannel.send(isA(Message.class))).thenReturn(true);
when(messageGroupMock.getUnmarked()).thenReturn(messagesUpForProcessing);
processor.processAndSend(messageGroupMock, channelTemplate, outputChannel);
// verify
verify(channelTemplate).send(messageCaptor.capture(), eq(outputChannel));
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
}
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor
.forClass(Message.class);
@Test
public void singleAnnotation() throws Exception {
SingleAnnotationTestBean bean = new SingleAnnotationTestBean();
MethodInvokingMessageGroupProcessor aggregator = new MethodInvokingMessageGroupProcessor(bean);
Method method = this.getMethod(aggregator);
Method expected = SingleAnnotationTestBean.class.getMethod("method1", new Class[] { List.class });
assertEquals(expected, method);
}
@Test(expected = IllegalArgumentException.class)
public void multipleAnnotations() {
MultipleAnnotationTestBean bean = new MultipleAnnotationTestBean();
new MethodInvokingMessageGroupProcessor(bean);
}
@Test
public void noAnnotations() throws Exception {
NoAnnotationTestBean bean = new NoAnnotationTestBean();
MethodInvokingMessageGroupProcessor aggregator = new MethodInvokingMessageGroupProcessor(bean);
Method method = this.getMethod(aggregator);
Method expected = NoAnnotationTestBean.class.getMethod("method1", new Class[] { List.class });
assertEquals(expected, method);
}
@Test(expected = IllegalArgumentException.class)
public void multiplePublicMethods() {
MultiplePublicMethodTestBean bean = new MultiplePublicMethodTestBean();
new MethodInvokingMessageGroupProcessor(bean);
}
@Test(expected = IllegalArgumentException.class)
public void noPublicMethods() {
NoPublicMethodTestBean bean = new NoPublicMethodTestBean();
new MethodInvokingMessageGroupProcessor(bean);
}
@Test
public void jdkProxy() {
DirectChannel input = new DirectChannel();
QueueChannel output = new QueueChannel();
GreetingService testBean = new GreetingBean();
ProxyFactory proxyFactory = new ProxyFactory(testBean);
proxyFactory.setProxyTargetClass(false);
testBean = (GreetingService) proxyFactory.getProxy();
MethodInvokingMessageGroupProcessor aggregator = new MethodInvokingMessageGroupProcessor(testBean);
CorrelatingMessageHandler handler = new CorrelatingMessageHandler(aggregator);
handler.setOutputChannel(output);
EventDrivenConsumer endpoint = new EventDrivenConsumer(input, handler);
endpoint.start();
Message<?> message = MessageBuilder.withPayload("proxy").setCorrelationId("abc").build();
input.send(message);
assertEquals("hello proxy", output.receive(0).getPayload());
}
@Test
public void cglibProxy() {
DirectChannel input = new DirectChannel();
QueueChannel output = new QueueChannel();
GreetingService testBean = new GreetingBean();
ProxyFactory proxyFactory = new ProxyFactory(testBean);
proxyFactory.setProxyTargetClass(true);
testBean = (GreetingService) proxyFactory.getProxy();
MethodInvokingMessageGroupProcessor aggregator = new MethodInvokingMessageGroupProcessor(testBean);
CorrelatingMessageHandler handler = new CorrelatingMessageHandler(aggregator);
handler.setOutputChannel(output);
EventDrivenConsumer endpoint = new EventDrivenConsumer(input, handler);
endpoint.start();
Message<?> message = MessageBuilder.withPayload("proxy").setCorrelationId("abc").build();
input.send(message);
assertEquals("hello proxy", output.receive(0).getPayload());
}
private Method getMethod(MethodInvokingMessageGroupProcessor aggregator) {
Object invoker = new DirectFieldAccessor(aggregator).getPropertyValue("adapter");
return (Method) new DirectFieldAccessor(invoker).getPropertyValue("method");
}
@SuppressWarnings("unused")
private static class SingleAnnotationTestBean {
@Aggregator
public String method1(List<String> input) {
return input.get(0);
}
public String method2(List<String> input) {
return input.get(0);
}
}
@SuppressWarnings("unused")
private static class MultipleAnnotationTestBean {
@Aggregator
public String method1(List<String> input) {
return input.get(0);
}
@Aggregator
public String method2(List<String> input) {
return input.get(0);
}
}
@SuppressWarnings("unused")
private static class NoAnnotationTestBean {
public String method1(List<String> input) {
return input.get(0);
}
String method2(List<String> input) {
return input.get(0);
}
}
@SuppressWarnings("unused")
private static class MultiplePublicMethodTestBean {
public String upperCase(String s) {
return s.toUpperCase();
}
public String lowerCase(String s) {
return s.toLowerCase();
}
}
@SuppressWarnings("unused")
private static class NoPublicMethodTestBean {
String lowerCase(String s) {
return s.toLowerCase();
}
}
public interface GreetingService {
String sayHello(List<String> names);
}
public static class GreetingBean implements GreetingService {
private String greeting = "hello";
public void setGreeting(String greeting) {
this.greeting = greeting;
}
@Aggregator
public String sayHello(List<String> names) {
return greeting + " " + names.get(0);
}
}
when(outputChannel.send(isA(Message.class))).thenReturn(true);
when(messageGroupMock.getMessages()).thenReturn(messagesUpForProcessing);
processor.processAndSend(messageGroupMock, channelTemplate, outputChannel
);
// verify
verify(channelTemplate).send(messageCaptor.capture(), eq(outputChannel));
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
}
}

View File

@@ -1,341 +0,0 @@
/*
* Copyright 2002-2009 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.aggregator;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.integration.channel.MessageChannelTemplate;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.core.MessageHeaders;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.message.MessageHandler;
import org.springframework.integration.message.MessageHandlingException;
import org.springframework.integration.store.SimpleMessageStore;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
/**
* @author Mark Fisher
* @author Marius Bogoevici
* @author Iwein Fuld
*/
public class NewConcurrentAggregatorEndpointTests {
private TaskExecutor taskExecutor;
private ThreadPoolTaskScheduler taskScheduler;
private CorrelatingMessageHandler aggregator;
@Before
public void configureAggregator() {
this.taskExecutor = new SimpleAsyncTaskExecutor();
this.taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.afterPropertiesSet();
this.taskScheduler.afterPropertiesSet();
this.aggregator = new CorrelatingMessageHandler(new SimpleMessageStore(50), new MultiplyingProcessor());
this.aggregator.setTaskScheduler(this.taskScheduler);
}
@Test
public void testCompleteGroupWithinTimeout() throws InterruptedException {
this.aggregator.start();
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage(3, "ABC", 3, 1, replyChannel, null);
Message<?> message2 = createMessage(5, "ABC", 3, 2, replyChannel, null);
Message<?> message3 = createMessage(7, "ABC", 3, 3, replyChannel, null);
CountDownLatch latch = new CountDownLatch(3);
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message1, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message2, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message3, latch));
latch.await(10000, TimeUnit.MILLISECONDS);
assertThat(latch.getCount(), is(0l));
Message<?> reply = replyChannel.receive(2000);
assertNotNull(reply);
assertEquals(reply.getPayload(), 105);
}
@Test
@Ignore
//dropped backwards compatibility for duplicate ID's
public void testCompleteGroupWithinTimeoutWithSameId() throws InterruptedException {
this.aggregator.start();
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage(3, "ABC", 3, 1, replyChannel, "ID#1");
Message<?> message2 = createMessage(5, "ABC", 3, 2, replyChannel, "ID#1");
Message<?> message3 = createMessage(7, "ABC", 3, 3, replyChannel, "ID#1");
CountDownLatch latch = new CountDownLatch(3);
//for testing the duplication scenario, the messages must be processed synchronously
new AggregatorTestTask(this.aggregator, message1, latch).run();
new AggregatorTestTask(this.aggregator, message2, latch).run();
new AggregatorTestTask(this.aggregator, message3, latch).run();
Message<?> reply = replyChannel.receive(500);
assertNotNull(reply);
assertEquals("123456789", reply.getPayload());
}
@Test
public void testShouldNotSendPartialResultOnTimeoutByDefault() throws InterruptedException {
this.aggregator.start();
QueueChannel discardChannel = new QueueChannel();
this.aggregator.setTimeout(50);
this.aggregator.setReaperInterval(10);
this.aggregator.setDiscardChannel(discardChannel);
QueueChannel replyChannel = new QueueChannel();
Message<?> message = createMessage(3, "ABC", 2, 1, replyChannel, null);
CountDownLatch latch = new CountDownLatch(1);
AggregatorTestTask task = new AggregatorTestTask(this.aggregator, message, latch);
this.taskExecutor.execute(task);
latch.await(2000, TimeUnit.MILLISECONDS);
assertEquals("Task should have completed within timeout", 0, latch.getCount());
Message<?> reply = replyChannel.receive(100);
assertNull("No message should have been sent normally", reply);
Message<?> discardedMessage = discardChannel.receive(1000);
assertNotNull("A message should have been discarded", discardedMessage);
assertEquals(message, discardedMessage);
}
@Test
public void testShouldSendPartialResultOnTimeoutTrue() throws InterruptedException {
this.aggregator.setTimeout(500);
this.aggregator.setReaperInterval(10);
this.aggregator.setSendPartialResultOnTimeout(true);
this.aggregator.start();
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage(3, "ABC", 3, 1, replyChannel, null);
Message<?> message2 = createMessage(5, "ABC", 3, 2, replyChannel, null);
CountDownLatch latch = new CountDownLatch(2);
AggregatorTestTask task1 = new AggregatorTestTask(this.aggregator, message1, latch);
AggregatorTestTask task2 = new AggregatorTestTask(this.aggregator, message2, latch);
this.taskExecutor.execute(task1);
this.taskExecutor.execute(task2);
latch.await(3000, TimeUnit.MILLISECONDS);
assertEquals("handlers should have been invoked within time limit", 0, latch.getCount());
Message<?> reply = replyChannel.receive(3000);
assertNotNull("A reply message should have been received", reply);
assertEquals(15, reply.getPayload());
assertNull(task1.getException());
assertNull(task2.getException());
}
@Test
public void testMultipleGroupsSimultaneously() throws InterruptedException {
this.aggregator.start();
QueueChannel replyChannel1 = new QueueChannel();
QueueChannel replyChannel2 = new QueueChannel();
Message<?> message1 = createMessage(3, "ABC", 3, 1, replyChannel1, null);
Message<?> message2 = createMessage(5, "ABC", 3, 2, replyChannel1, null);
Message<?> message3 = createMessage(7, "ABC", 3, 3, replyChannel1, null);
Message<?> message4 = createMessage(11, "XYZ", 3, 1, replyChannel2, null);
Message<?> message5 = createMessage(13, "XYZ", 3, 2, replyChannel2, null);
Message<?> message6 = createMessage(17, "XYZ", 3, 3, replyChannel2, null);
CountDownLatch latch = new CountDownLatch(6);
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message1, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message6, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message2, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message5, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message3, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message4, latch));
latch.await(1000, TimeUnit.MILLISECONDS);
Message<Integer> reply1 = (Message<Integer>) replyChannel1.receive(500);
assertNotNull(reply1);
assertThat(reply1.getPayload(), is(105));
Message<Integer> reply2 = (Message<Integer>) replyChannel2.receive(500);
assertNotNull(reply2);
assertThat(reply2.getPayload(), is(2431));
}
@Test
@Ignore
//dropped backwards compatibility for setting capacity limit (it's always Integer.MAX_VALUE)
public void testTrackedCorrelationIdsCapacityAtLimit() {
this.aggregator.start();
QueueChannel replyChannel = new QueueChannel();
QueueChannel discardChannel = new QueueChannel();
//this.aggregator.setTrackedCorrelationIdCapacity(3);
this.aggregator.setDiscardChannel(discardChannel);
this.aggregator.handleMessage(createMessage(1, 1, 1, 1, replyChannel, null));
assertEquals(1, replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage(3, 2, 1, 1, replyChannel, null));
assertEquals(3, replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage(4, 3, 1, 1, replyChannel, null));
assertEquals(4, replyChannel.receive(100).getPayload());
//next message with same correlation ID is discarded
this.aggregator.handleMessage(createMessage(2, 1, 1, 1, replyChannel, null));
assertEquals(2, discardChannel.receive(100).getPayload());
}
@Test
@Ignore
//dropped backwards compatibility for setting capacity limit (it's always Integer.MAX_VALUE)
public void testTrackedCorrelationIdsCapacityPassesLimit() {
this.aggregator.start();
QueueChannel replyChannel = new QueueChannel();
QueueChannel discardChannel = new QueueChannel();
//this.aggregator.setTrackedCorrelationIdCapacity(3);
this.aggregator.setDiscardChannel(discardChannel);
this.aggregator.handleMessage(createMessage(1, 1, 1, 1, replyChannel, null));
assertEquals(1, replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage(2, 2, 1, 1, replyChannel, null));
assertEquals(2, replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage(3, 3, 1, 1, replyChannel, null));
assertEquals(3, replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage(4, 4, 1, 1, replyChannel, null));
assertEquals(4, replyChannel.receive(100).getPayload());
this.aggregator.handleMessage(createMessage(5, 1, 1, 1, replyChannel, null));
assertEquals(5, replyChannel.receive(100).getPayload());
assertNull(discardChannel.receive(0));
}
@Test(expected = MessageHandlingException.class)
public void testExceptionThrownIfNoCorrelationId() throws InterruptedException {
this.aggregator.start();
Message<?> message = createMessage(3, null, 2, 1, new QueueChannel(), null);
this.aggregator.handleMessage(message);
}
@Test
public void testAdditionalMessageAfterCompletion() throws InterruptedException {
this.aggregator.start();
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage(3, "ABC", 3, 1, replyChannel, null);
Message<?> message2 = createMessage(5, "ABC", 3, 2, replyChannel, null);
Message<?> message3 = createMessage(7, "ABC", 3, 3, replyChannel, null);
Message<?> message4 = createMessage(7, "ABC", 3, 3, replyChannel, null);
CountDownLatch latch = new CountDownLatch(4);
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message1, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message2, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message3, latch));
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator, message4, latch));
latch.await(1000, TimeUnit.MILLISECONDS);
Message<?> reply = replyChannel.receive(100);
assertNotNull("A message should be aggregated", reply);
assertThat(((Integer) reply.getPayload()), is(105));
}
@Test
public void testNullReturningAggregator() throws InterruptedException {
this.aggregator.start();
this.aggregator = new CorrelatingMessageHandler(new SimpleMessageStore(50), new NullReturningMessageProcessor());
this.aggregator.setTaskScheduler(this.taskScheduler);
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage(3, "ABC", 3, 1, replyChannel, null);
Message<?> message2 = createMessage(5, "ABC", 3, 2, replyChannel, null);
Message<?> message3 = createMessage(7, "ABC", 3, 3, replyChannel, null);
CountDownLatch latch = new CountDownLatch(3);
AggregatorTestTask task1 = new AggregatorTestTask(aggregator, message1, latch);
this.taskExecutor.execute(task1);
AggregatorTestTask task2 = new AggregatorTestTask(aggregator, message2, latch);
this.taskExecutor.execute(task2);
AggregatorTestTask task3 = new AggregatorTestTask(aggregator, message3, latch);
this.taskExecutor.execute(task3);
latch.await(1000, TimeUnit.MILLISECONDS);
assertNull(task1.getException());
assertNull(task2.getException());
assertNull(task3.getException());
Message<?> reply = replyChannel.receive(500);
assertNull(reply);
}
private static Message<?> createMessage(Object payload, Object correlationId,
int sequenceSize, int sequenceNumber, MessageChannel replyChannel, String predefinedId) {
MessageBuilder<Object> builder = MessageBuilder.withPayload(payload)
.setCorrelationId(correlationId)
.setSequenceSize(sequenceSize)
.setSequenceNumber(sequenceNumber)
.setReplyChannel(replyChannel);
if (predefinedId != null) {
builder.setHeader(MessageHeaders.ID, predefinedId);
}
return builder.build();
}
private static class AggregatorTestTask implements Runnable {
private MessageHandler aggregator;
private Message<?> message;
private Exception exception;
private CountDownLatch latch;
AggregatorTestTask(MessageHandler aggregator, Message<?> message, CountDownLatch latch) {
this.aggregator = aggregator;
this.message = message;
this.latch = latch;
}
public Exception getException() {
return this.exception;
}
public void run() {
try {
this.aggregator.handleMessage(message);
}
catch (Exception e) {
e.printStackTrace();
this.exception = e;
}
finally {
this.latch.countDown();
}
}
}
@After
public void stopTaskScheduler() {
if (this.taskScheduler != null) this.taskScheduler.destroy();
if (this.aggregator != null) this.aggregator.stop();
}
private class MultiplyingProcessor implements MessageGroupProcessor {
public void processAndSend(MessageGroup group,
MessageChannelTemplate channelTemplate, MessageChannel outputChannel
) {
Integer product = 1;
for (Message<?> message : group.getMessages()) {
product *= (Integer) message.getPayload();
}
channelTemplate.send(MessageBuilder.withPayload(product).build(), outputChannel);
}
}
private class NullReturningMessageProcessor implements MessageGroupProcessor {
public void processAndSend(MessageGroup group, MessageChannelTemplate channelTemplate, MessageChannel outputChannel) {
//noop
}
}
}

View File

@@ -1,279 +0,0 @@
/*
* Copyright 2002-2009 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.aggregator;
import org.junit.After;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.junit.Before;
import org.junit.Test;
import org.junit.Ignore;
import static org.junit.matchers.JUnitMatchers.*;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.store.MessageStore;
import org.springframework.integration.store.SimpleMessageStore;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import static java.util.Arrays.*;
/**
* @author Marius Bogoevici
* @author Alex Peters
* @author Iwein Fuld
*/
public class NewResequencerTests {
private CorrelatingMessageHandler resequencer;
private ThreadPoolTaskScheduler taskScheduler;
private DefaultResequencerStrategies resequencerStrategies;
@Before
public void configureResequencer() {
this.resequencerStrategies = new DefaultResequencerStrategies();
MessageStore store = new SimpleMessageStore(30);
this.resequencer = new CorrelatingMessageHandler(store, resequencerStrategies, resequencerStrategies, resequencerStrategies);
this.taskScheduler = TestUtils.createTaskScheduler(10);
this.resequencer.setTaskScheduler(taskScheduler);
this.taskScheduler.afterPropertiesSet();
this.resequencer.start();
}
@Test
public void testBasicResequencing() throws InterruptedException {
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 3, 3, replyChannel);
Message<?> message2 = createMessage("456", "ABC", 3, 1, replyChannel);
Message<?> message3 = createMessage("789", "ABC", 3, 2, replyChannel);
this.resequencer.handleMessage(message1);
this.resequencer.handleMessage(message3);
this.resequencer.handleMessage(message2);
Message<?> reply1 = replyChannel.receive(0);
Message<?> reply2 = replyChannel.receive(0);
Message<?> reply3 = replyChannel.receive(0);
assertNotNull(reply1);
assertEquals(new Integer(1), reply1.getHeaders().getSequenceNumber());
assertNotNull(reply2);
assertEquals(new Integer(2), reply2.getHeaders().getSequenceNumber());
assertNotNull(reply3);
assertEquals(new Integer(3), reply3.getHeaders().getSequenceNumber());
}
@Test
public void testResequencingWithDuplicateMessages() {
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 3, 3, replyChannel);
Message<?> message2 = createMessage("456", "ABC", 3, 1, replyChannel);
Message<?> message3 = createMessage("789", "ABC", 3, 2, replyChannel);
this.resequencer.handleMessage(message1);
this.resequencer.handleMessage(message3);
this.resequencer.handleMessage(message3);
this.resequencer.handleMessage(message2);
Message<?> reply1 = replyChannel.receive(0);
Message<?> reply2 = replyChannel.receive(0);
Message<?> reply3 = replyChannel.receive(0);
assertNotNull(reply1);
assertEquals(new Integer(1), reply1.getHeaders().getSequenceNumber());
assertNotNull(reply2);
assertEquals(new Integer(2), reply2.getHeaders().getSequenceNumber());
assertNotNull(reply3);
assertEquals(new Integer(3), reply3.getHeaders().getSequenceNumber());
}
@Test
@Ignore // TODO: fix this
public void testResequencingWithIncompleteSequenceRelease() throws InterruptedException {
this.resequencerStrategies.setReleasePartialSequences(true);
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 4, 2, replyChannel);
Message<?> message2 = createMessage("456", "ABC", 4, 1, replyChannel);
Message<?> message3 = createMessage("789", "ABC", 4, 4, replyChannel);
Message<?> message4 = createMessage("XYZ", "ABC", 4, 3, replyChannel);
this.resequencer.handleMessage(message1);
this.resequencer.handleMessage(message2);
this.resequencer.handleMessage(message3);
Message<?> reply1 = replyChannel.receive(0);
Message<?> reply2 = replyChannel.receive(0);
Message<?> reply3 = replyChannel.receive(0);
// only messages 1 and 2 should have been received by now
assertNotNull(reply1);
assertEquals(new Integer(1), reply1.getHeaders().getSequenceNumber());
assertNotNull(reply2);
assertEquals(new Integer(2), reply2.getHeaders().getSequenceNumber());
System.err.println(reply3);
assertNull(reply3);
// when sending the last message, the whole sequence must have been sent
this.resequencer.handleMessage(message4);
reply3 = replyChannel.receive(0);
Message<?> reply4 = replyChannel.receive(0);
assertNotNull(reply3);
assertEquals(new Integer(3), reply3.getHeaders().getSequenceNumber());
assertNotNull(reply4);
assertEquals(new Integer(4), reply4.getHeaders().getSequenceNumber());
}
@Test
public void testResequencingWithDiscard() throws InterruptedException {
QueueChannel replyChannel = new QueueChannel();
QueueChannel discardChannel = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 3, 2, replyChannel);
Message<?> message2 = createMessage("456", "ABC", 3, 1, replyChannel);
Message<?> message3 = createMessage("789", "ABC", 3, 3, replyChannel);
this.resequencer.setSendPartialResultOnTimeout(false);
this.resequencerStrategies.setReleasePartialSequences(false);
this.resequencer.setDiscardChannel(discardChannel);
this.resequencer.setTimeout(90000);
this.resequencer.handleMessage(message1);
this.resequencer.handleMessage(message2);
this.resequencer.forceComplete("ABC");
Message<?> reply1 = discardChannel.receive(0);
Message<?> reply2 = discardChannel.receive(0);
Message<?> reply3 = discardChannel.receive(0);
// messages 1 and 2 should have been received by now in no particular order
assertNotNull(reply1);
assertNotNull(reply2);
Integer sequenceNo1 = reply1.getHeaders().getSequenceNumber();
Integer sequenceNo2 = reply2.getHeaders().getSequenceNumber();
assertThat(asList(sequenceNo1, sequenceNo2), hasItems(1, 2));
assertNull(reply3);
// when sending the last message, it waits in the buffer for retries of the other two
this.resequencer.handleMessage(message3);
reply3 = discardChannel.receive(0);
assertNull(reply3);
this.resequencer.handleMessage(message1);
this.resequencer.handleMessage(message2);
reply1 = replyChannel.receive(0);
reply2 = replyChannel.receive(0);
reply3 = replyChannel.receive(0);
assertNotNull(reply1);
assertThat(reply1.getHeaders().getSequenceNumber(), is(new Integer(1)));
assertNotNull(reply2);
assertThat(reply2.getHeaders().getSequenceNumber(), is(new Integer(2)));
assertNotNull(reply3);
assertThat(reply3.getHeaders().getSequenceNumber(), is(new Integer(3)));
}
@Test
@Ignore
//different sequence sizes are not supported
public void testResequencingWithDifferentSequenceSizes() throws InterruptedException {
QueueChannel replyChannel = new QueueChannel();
QueueChannel discardChannel = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 4, 2, replyChannel);
Message<?> message2 = createMessage("456", "ABC", 5, 1, replyChannel);
this.resequencer.setSendPartialResultOnTimeout(false);
//this.resequencer.setReleasePartialSequences(false);
this.resequencer.setDiscardChannel(discardChannel);
this.resequencer.setTimeout(90000);
this.resequencer.handleMessage(message1);
this.resequencer.handleMessage(message2);
//this.resequencer.discardBarrier(this.resequencer.barriers.get("ABC"));
Message<?> reply1 = discardChannel.receive(0);
Message<?> reply2 = discardChannel.receive(0);
// only messages 1 - with sequence number 2 - should have been received by now
// the other has been discarded
assertNotNull(reply1);
assertEquals(new Integer(2), reply1.getHeaders().getSequenceNumber());
assertNull(reply2);
}
@Test
public void testResequencingWithWrongSequenceSizeAndNumber() throws InterruptedException {
QueueChannel replyChannel = new QueueChannel();
QueueChannel discardChannel = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 2, 4, replyChannel);
this.resequencer.setSendPartialResultOnTimeout(false);
//this.resequencer.setReleasePartialSequences(false);
this.resequencer.setDiscardChannel(discardChannel);
this.resequencer.setTimeout(90000);
this.resequencer.handleMessage(message1);
//this.resequencer.discardBarrier(this.resequencer.barriers.get("ABC"));
Message<?> reply1 = discardChannel.receive(0);
// No message has been received - the message has been rejected.
assertNull(reply1);
}
@Test
public void testResequencingWithCompleteSequenceRelease() throws InterruptedException {
//this.resequencer.setReleasePartialSequences(false);
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 4, 2, replyChannel);
Message<?> message2 = createMessage("456", "ABC", 4, 1, replyChannel);
Message<?> message3 = createMessage("789", "ABC", 4, 4, replyChannel);
Message<?> message4 = createMessage("XYZ", "ABC", 4, 3, replyChannel);
this.resequencer.handleMessage(message1);
this.resequencer.handleMessage(message2);
this.resequencer.handleMessage(message3);
Message<?> reply1 = replyChannel.receive(0);
Message<?> reply2 = replyChannel.receive(0);
Message<?> reply3 = replyChannel.receive(0);
// no messages should have been received yet
assertNull(reply1);
assertNull(reply2);
assertNull(reply3);
// after sending the last message, the whole sequence should have been sent
this.resequencer.handleMessage(message4);
reply1 = replyChannel.receive(0);
reply2 = replyChannel.receive(0);
reply3 = replyChannel.receive(0);
Message<?> reply4 = replyChannel.receive(0);
assertNotNull(reply1);
assertEquals(new Integer(1), reply1.getHeaders().getSequenceNumber());
assertNotNull(reply2);
assertEquals(new Integer(2), reply2.getHeaders().getSequenceNumber());
assertNotNull(reply3);
assertEquals(new Integer(3), reply3.getHeaders().getSequenceNumber());
assertNotNull(reply4);
assertEquals(new Integer(4), reply4.getHeaders().getSequenceNumber());
}
@Test
public void testRemovalOfBarrierWhenLastMessageOfSequenceArrives() {
QueueChannel replyChannel = new QueueChannel();
String correlationId = "ABC";
Message<?> message1 = createMessage("123", correlationId, 1, 1,
replyChannel);
resequencer.handleMessage(message1);
//assertThat(resequencer.barriers.containsKey(correlationId), is(false));
}
private static Message<?> createMessage(String payload, Object correlationId,
int sequenceSize, int sequenceNumber, MessageChannel replyChannel) {
return MessageBuilder.withPayload(payload)
.setCorrelationId(correlationId)
.setSequenceSize(sequenceSize)
.setSequenceNumber(sequenceNumber)
.setReplyChannel(replyChannel)
.build();
}
@After
public void stopTaskScheduler() {
this.resequencer.stop();
this.taskScheduler.destroy();
}
}

View File

@@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.aggregator;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@@ -24,178 +23,157 @@ import java.util.List;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.integration.core.Message;
import org.springframework.integration.message.GenericMessage;
/**
* @author Marius Bogoevici
*/
public class CompletionStrategyAdapterTests {
private SimpleCompletionStrategy simpleCompletionStrategy;
public class ReleaseStrategyAdapterTests {
private SimpleReleaseStrategy simpleReleaseStrategy;
@Before
public void setUp() {
simpleCompletionStrategy = new SimpleCompletionStrategy();
simpleReleaseStrategy = new SimpleReleaseStrategy();
}
@Test
public void testTrueConvertedProperly() {
CompletionStrategyAdapter adapter = new CompletionStrategyAdapter(new AlwaysTrueCompletionStrategy(),
ReleaseStrategyAdapter adapter = new ReleaseStrategyAdapter(new AlwaysTrueReleaseStrategy(),
"checkCompleteness");
Assert.assertTrue(adapter.isComplete(new ArrayList<Message<?>>()));
Assert.assertTrue(adapter.canRelease(createListOfMessages(0)));
}
@Test
public void testFalseConvertedProperly() {
CompletionStrategyAdapter adapter = new CompletionStrategyAdapter(new AlwaysFalseCompletionStrategy(),
ReleaseStrategyAdapter adapter = new ReleaseStrategyAdapter(new AlwaysFalseReleaseStrategy(),
"checkCompleteness");
Assert.assertTrue(!adapter.isComplete(new ArrayList<Message<?>>()));
Assert.assertTrue(!adapter.canRelease(createListOfMessages(0)));
}
@Test
public void testAdapterWithNonParameterizedMessageListBasedMethod() {
CompletionStrategy adapter = new CompletionStrategyAdapter(simpleCompletionStrategy,
ReleaseStrategy adapter = new ReleaseStrategyAdapter(simpleReleaseStrategy,
"checkCompletenessOnNonParameterizedListOfMessages");
List<Message<?>> messages = createListOfMessages();
Assert.assertTrue(adapter.isComplete(messages));
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
@Test
public void testAdapterWithWildcardParametrizedMessageBasedMethod() {
CompletionStrategy adapter = new CompletionStrategyAdapter(simpleCompletionStrategy,
ReleaseStrategy adapter = new ReleaseStrategyAdapter(simpleReleaseStrategy,
"checkCompletenessOnListOfMessagesParametrizedWithWildcard");
List<Message<?>> messages = createListOfMessages();
Assert.assertTrue(adapter.isComplete(messages));
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
@Test
public void testAdapterWithTypeParametrizedMessageBasedMethod() {
CompletionStrategy adapter = new CompletionStrategyAdapter(simpleCompletionStrategy,
ReleaseStrategy adapter = new ReleaseStrategyAdapter(simpleReleaseStrategy,
"checkCompletenessOnListOfMessagesParametrizedWithString");
List<Message<?>> messages = createListOfMessages();
Assert.assertTrue(adapter.isComplete(messages));
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
@Test
public void testAdapterWithPojoBasedMethod() {
CompletionStrategy adapter = new CompletionStrategyAdapter(simpleCompletionStrategy,
"checkCompletenessOnListOfStrings");
List<Message<?>> messages = createListOfMessages();
Assert.assertTrue(adapter.isComplete(messages));
ReleaseStrategy adapter = new ReleaseStrategyAdapter(simpleReleaseStrategy, "checkCompletenessOnListOfStrings");
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
@Test
public void testAdapterWithPojoBasedMethodReturningObject() {
CompletionStrategy adapter = new CompletionStrategyAdapter(simpleCompletionStrategy,
"checkCompletenessOnListOfStrings");
List<Message<?>> messages = createListOfMessages();
Assert.assertTrue(adapter.isComplete(messages));
ReleaseStrategy adapter = new ReleaseStrategyAdapter(simpleReleaseStrategy, "checkCompletenessOnListOfStrings");
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
@Test(expected = IllegalArgumentException.class)
public void testAdapterWithWrongMethodName() {
new CompletionStrategyAdapter(simpleCompletionStrategy, "methodThatDoesNotExist");
new ReleaseStrategyAdapter(simpleReleaseStrategy, "methodThatDoesNotExist");
}
@Test(expected = IllegalArgumentException.class)
public void testInvalidParameterTypeUsingMethodName() {
new CompletionStrategyAdapter(simpleCompletionStrategy, "invalidParameterType");
new ReleaseStrategyAdapter(simpleReleaseStrategy, "invalidParameterType");
}
@Test(expected = IllegalArgumentException.class)
public void testTooManyParametersUsingMethodName() {
new CompletionStrategyAdapter(simpleCompletionStrategy, "tooManyParameters");
new ReleaseStrategyAdapter(simpleReleaseStrategy, "tooManyParameters");
}
@Test(expected = IllegalArgumentException.class)
public void testNotEnoughParametersUsingMethodName() {
new CompletionStrategyAdapter(simpleCompletionStrategy, "notEnoughParameters");
new ReleaseStrategyAdapter(simpleReleaseStrategy, "notEnoughParameters");
}
@Test(expected = IllegalArgumentException.class)
public void testListSubclassParameterUsingMethodName() {
new CompletionStrategyAdapter(simpleCompletionStrategy, "ListSubclassParameter");
new ReleaseStrategyAdapter(simpleReleaseStrategy, "ListSubclassParameter");
}
@Test(expected = IllegalArgumentException.class)
public void testWrongReturnType() throws SecurityException, NoSuchMethodError {
new CompletionStrategyAdapter(simpleCompletionStrategy, "wrongReturnType");
}
@Test(expected = IllegalArgumentException.class)
public void testInvalidParameterTypeUsingMethodObject() throws SecurityException, NoSuchMethodException {
new MethodInvokingAggregator(simpleCompletionStrategy, simpleCompletionStrategy.getClass().getMethod(
"invalidParameterType", String.class));
new ReleaseStrategyAdapter(simpleReleaseStrategy, "wrongReturnType");
}
@Test(expected = IllegalArgumentException.class)
public void testTooManyParametersUsingMethodObject() throws SecurityException, NoSuchMethodException {
new CompletionStrategyAdapter(simpleCompletionStrategy, simpleCompletionStrategy.getClass().getMethod(
new ReleaseStrategyAdapter(simpleReleaseStrategy, simpleReleaseStrategy.getClass().getMethod(
"tooManyParameters", List.class, List.class));
}
@Test(expected = IllegalArgumentException.class)
public void testNotEnoughParametersUsingMethodObject() throws SecurityException, NoSuchMethodException {
new CompletionStrategyAdapter(simpleCompletionStrategy, simpleCompletionStrategy.getClass().getMethod(
new ReleaseStrategyAdapter(simpleReleaseStrategy, simpleReleaseStrategy.getClass().getMethod(
"notEnoughParameters", new Class[] {}));
}
@Test(expected = IllegalArgumentException.class)
public void testListSubclassParameterUsingMethodObject() throws SecurityException, NoSuchMethodException {
new CompletionStrategyAdapter(simpleCompletionStrategy, simpleCompletionStrategy.getClass().getMethod(
new ReleaseStrategyAdapter(simpleReleaseStrategy, simpleReleaseStrategy.getClass().getMethod(
"ListSubclassParameter", new Class[] { LinkedList.class }));
}
@Test(expected = IllegalArgumentException.class)
public void testWrongReturnTypeUsingMethodObject() throws SecurityException, NoSuchMethodException {
new CompletionStrategyAdapter(simpleCompletionStrategy, simpleCompletionStrategy.getClass().getMethod(
"wrongReturnType", new Class[] { List.class }));
new ReleaseStrategyAdapter(simpleReleaseStrategy, simpleReleaseStrategy.getClass().getMethod("wrongReturnType",
new Class[] { List.class }));
}
@Test(expected = IllegalArgumentException.class)
public void testNullObject() {
new MethodInvokingAggregator(null, "doesNotMatter");
}
@Test(expected = IllegalArgumentException.class)
public void testNullMethodName() {
String methodName = null;
new MethodInvokingAggregator(simpleCompletionStrategy, methodName);
}
@Test(expected = IllegalArgumentException.class)
public void testNullMethodObject() {
Method method = null;
new MethodInvokingAggregator(simpleCompletionStrategy, method);
}
private static List<Message<?>> createListOfMessages() {
private static MessageGroup createListOfMessages(int size) {
List<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;
if (size > 0) {
messages.add(new GenericMessage<String>("123"));
}
if (size > 1) {
messages.add(new GenericMessage<String>("456"));
}
if (size > 2) {
messages.add(new GenericMessage<String>("789"));
}
return new MessageGroup(messages, "ABC");
}
private static class AlwaysTrueCompletionStrategy {
@SuppressWarnings("unused")
private static class AlwaysTrueReleaseStrategy {
public boolean checkCompleteness(List<Message<?>> messages) {
return true;
}
}
private static class AlwaysFalseCompletionStrategy {
@SuppressWarnings("unused")
private static class AlwaysFalseReleaseStrategy {
public boolean checkCompleteness(List<Message<?>> messages) {
return false;
}
}
private static class SimpleCompletionStrategy {
@SuppressWarnings("unused")
private static class SimpleReleaseStrategy {
public boolean checkCompletenessOnNonParameterizedListOfMessages(List<Message<?>> messages) {
Assert.assertTrue(messages.size() > 0);
@@ -207,13 +185,13 @@ public class CompletionStrategyAdapterTests {
return messages.size() > messages.iterator().next().getHeaders().getSequenceSize();
}
public boolean checkCompletenessOnListOfMessagesParametrizedWithString(
List<Message<String>> messages) {
public boolean checkCompletenessOnListOfMessagesParametrizedWithString(List<Message<String>> messages) {
Assert.assertTrue(messages.size() > 0);
return messages.size() > messages.iterator().next().getHeaders().getSequenceSize();
}
// Example for the case when completeness is checked on the structure of the data
// Example for the case when completeness is checked on the structure of
// the data
public boolean checkCompletenessOnListOfStrings(List<String> messages) {
StringBuffer buffer = new StringBuffer();
for (String content : messages) {

View File

@@ -16,22 +16,23 @@
package org.springframework.integration.aggregator;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.integration.store.MessageStore;
import org.springframework.integration.store.SimpleMessageStore;
/**
* @author Marius Bogoevici
@@ -39,23 +40,20 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
*/
public class ResequencerTests {
private Resequencer resequencer;
private ThreadPoolTaskScheduler taskScheduler;
private CorrelatingMessageHandler resequencer;
private Resequencer processor = new Resequencer();
private MessageStore store = new SimpleMessageStore();
@Before
public void configureResequencer() {
this.resequencer = new Resequencer();
this.taskScheduler = TestUtils.createTaskScheduler(10);
this.resequencer.setTaskScheduler(taskScheduler);
this.taskScheduler.afterPropertiesSet();
this.resequencer.start();
this.resequencer = new CorrelatingMessageHandler(store, processor, processor, processor);
}
@Test
public void testBasicResequencing() throws InterruptedException {
this.resequencer.setReleasePartialSequences(false);
this.processor.setReleasePartialSequences(false);
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 3, 3, replyChannel);
Message<?> message2 = createMessage("456", "ABC", 3, 1, replyChannel);
@@ -76,7 +74,7 @@ public class ResequencerTests {
@Test
public void testResequencingWithDuplicateMessages() {
this.resequencer.setReleasePartialSequences(false);
this.processor.setReleasePartialSequences(false);
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 3, 3, replyChannel);
Message<?> message2 = createMessage("456", "ABC", 3, 1, replyChannel);
@@ -96,11 +94,9 @@ public class ResequencerTests {
assertEquals(new Integer(3), reply3.getHeaders().getSequenceNumber());
}
@Test
public void testResequencingWithIncompleteSequenceRelease() throws InterruptedException {
this.resequencer.setReleasePartialSequences(true);
this.processor.setReleasePartialSequences(true);
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 4, 2, replyChannel);
Message<?> message2 = createMessage("456", "ABC", 4, 1, replyChannel);
@@ -127,7 +123,7 @@ public class ResequencerTests {
assertNotNull(reply4);
assertEquals(new Integer(4), reply4.getHeaders().getSequenceNumber());
}
@Test
public void testResequencingWithDiscard() throws InterruptedException {
QueueChannel discardChannel = new QueueChannel();
@@ -135,59 +131,60 @@ public class ResequencerTests {
Message<?> message2 = createMessage("456", "ABC", 4, 1, null);
Message<?> message3 = createMessage("789", "ABC", 4, 4, null);
this.resequencer.setSendPartialResultOnTimeout(false);
this.resequencer.setReleasePartialSequences(false);
this.processor.setReleasePartialSequences(false);
this.resequencer.setDiscardChannel(discardChannel);
this.resequencer.setTimeout(90000);
this.resequencer.handleMessage(message1);
this.resequencer.handleMessage(message2);
this.resequencer.discardBarrier(this.resequencer.barriers.get("ABC"));
// this.resequencer.discardBarrier(this.resequencer.barriers.get("ABC"));
this.resequencer.forceComplete("ABC");
Message<?> reply1 = discardChannel.receive(0);
Message<?> reply2 = discardChannel.receive(0);
Message<?> reply3 = discardChannel.receive(0);
// only messages 1 and 2 should have been received by now
assertNotNull(reply1);
assertEquals(new Integer(1), reply1.getHeaders().getSequenceNumber());
assertNotNull(reply2);
assertEquals(new Integer(2), reply2.getHeaders().getSequenceNumber());
assertNull(reply3);
ArrayList<Integer> sequence = new ArrayList<Integer>(Arrays.asList(reply1.getHeaders().getSequenceNumber(), reply2.getHeaders()
.getSequenceNumber()));
Collections.sort(sequence);
assertEquals("[1, 2]", sequence.toString());
// when sending the last message, the whole sequence must have been sent
this.resequencer.handleMessage(message3);
reply3 = discardChannel.receive(0);
assertNull(reply3);
}
@Test
public void testResequencingWithDifferentSequenceSizes() throws InterruptedException {
QueueChannel discardChannel = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 4, 2, null);
Message<?> message2 = createMessage("456", "ABC", 5, 1, null);
this.resequencer.setSendPartialResultOnTimeout(false);
this.resequencer.setReleasePartialSequences(false);
this.processor.setReleasePartialSequences(false);
this.resequencer.setDiscardChannel(discardChannel);
this.resequencer.setTimeout(90000);
this.resequencer.handleMessage(message1);
this.resequencer.handleMessage(message2);
this.resequencer.discardBarrier(this.resequencer.barriers.get("ABC"));
Message<?> reply1 = discardChannel.receive(0);
Message<?> reply2 = discardChannel.receive(0);
// only messages 1 - with sequence number 2 - should have been received by now
// the other has been discarded
assertNotNull(reply1);
assertEquals(new Integer(2), reply1.getHeaders().getSequenceNumber());
assertNull(reply2);
// this.resequencer.discardBarrier(this.resequencer.barriers.get("ABC"));
Message<?> discard1 = discardChannel.receive(0);
Message<?> discard2 = discardChannel.receive(0);
// message2 has been discarded because it came in with the wrong sequence size
assertNotNull(discard1);
assertEquals(new Integer(1), discard1.getHeaders().getSequenceNumber());
assertNull(discard2);
}
@Test
public void testResequencingWithWrongSequenceSizeAndNumber() throws InterruptedException {
QueueChannel discardChannel = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 2, 4, null);
this.resequencer.setSendPartialResultOnTimeout(false);
this.resequencer.setReleasePartialSequences(false);
this.processor.setReleasePartialSequences(false);
this.resequencer.setDiscardChannel(discardChannel);
this.resequencer.setTimeout(90000);
this.resequencer.handleMessage(message1);
this.resequencer.discardBarrier(this.resequencer.barriers.get("ABC"));
// this.resequencer.discardBarrier(this.resequencer.barriers.get("ABC"));
Message<?> reply1 = discardChannel.receive(0);
// No message has been received - the message has been rejected.
assertNull(reply1);
@@ -195,7 +192,7 @@ public class ResequencerTests {
@Test
public void testResequencingWithCompleteSequenceRelease() throws InterruptedException {
this.resequencer.setReleasePartialSequences(false);
this.processor.setReleasePartialSequences(false);
QueueChannel replyChannel = new QueueChannel();
Message<?> message1 = createMessage("123", "ABC", 4, 2, replyChannel);
Message<?> message2 = createMessage("456", "ABC", 4, 1, replyChannel);
@@ -226,32 +223,20 @@ public class ResequencerTests {
assertNotNull(reply4);
assertEquals(new Integer(4), reply4.getHeaders().getSequenceNumber());
}
@Test
public void testRemovalOfBarrierWhenLastMessageOfSequenceArrives() {
QueueChannel replyChannel = new QueueChannel();
String correlationId = "ABC";
Message<?> message1 = createMessage("123", correlationId, 1, 1,
replyChannel);
Message<?> message1 = createMessage("123", correlationId, 1, 1, replyChannel);
resequencer.handleMessage(message1);
assertThat(resequencer.barriers.containsKey(correlationId), is(false));
assertTrue(store.list(correlationId).isEmpty());
}
private static Message<?> createMessage(String payload, Object correlationId,
int sequenceSize, int sequenceNumber, MessageChannel replyChannel) {
return MessageBuilder.withPayload(payload)
.setCorrelationId(correlationId)
.setSequenceSize(sequenceSize)
.setSequenceNumber(sequenceNumber)
.setReplyChannel(replyChannel)
.build();
}
@After
public void stopTaskScheduler() {
this.resequencer.stop();
this.taskScheduler.destroy();
private static Message<?> createMessage(String payload, Object correlationId, int sequenceSize, int sequenceNumber,
MessageChannel replyChannel) {
return MessageBuilder.withPayload(payload).setCorrelationId(correlationId).setSequenceSize(sequenceSize)
.setSequenceNumber(sequenceNumber).setReplyChannel(replyChannel).build();
}
}

View File

@@ -19,28 +19,23 @@ package org.springframework.integration.aggregator;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.springframework.integration.aggregator.SequenceSizeCompletionStrategy;
import org.springframework.integration.core.Message;
import org.springframework.integration.message.MessageBuilder;
/**
* @author Mark Fisher
*/
public class SequenceSizeCompletionStrategyTests {
public class SequenceSizeReleaseStrategyTests {
@Test
public void testIncompleteList() {
Message<String> message = MessageBuilder.withPayload("test1")
.setSequenceSize(2).build();
List<Message<?>> messages = new ArrayList<Message<?>>();
MessageGroup messages = new MessageGroup("FOO");
messages.add(message);
SequenceSizeCompletionStrategy completionStrategy = new SequenceSizeCompletionStrategy();
assertFalse(completionStrategy.isComplete(messages));
SequenceSizeReleaseStrategy ReleaseStrategy = new SequenceSizeReleaseStrategy();
assertFalse(ReleaseStrategy.canRelease(messages));
}
@Test
@@ -49,23 +44,17 @@ public class SequenceSizeCompletionStrategyTests {
.setSequenceSize(2).build();
Message<String> message2 = MessageBuilder.withPayload("test2")
.setSequenceSize(2).build();
List<Message<?>> messages = new ArrayList<Message<?>>();
MessageGroup messages = new MessageGroup("FOO");
messages.add(message1);
messages.add(message2);
SequenceSizeCompletionStrategy completionStrategy = new SequenceSizeCompletionStrategy();
assertTrue(completionStrategy.isComplete(messages));
SequenceSizeReleaseStrategy ReleaseStrategy = new SequenceSizeReleaseStrategy();
assertTrue(ReleaseStrategy.canRelease(messages));
}
@Test
public void testEmptyList() {
SequenceSizeCompletionStrategy completionStrategy = new SequenceSizeCompletionStrategy();
assertFalse(completionStrategy.isComplete(new ArrayList<Message<?>>()));
}
@Test
public void testNullList() {
SequenceSizeCompletionStrategy completionStrategy = new SequenceSizeCompletionStrategy();
assertFalse(completionStrategy.isComplete(null));
SequenceSizeReleaseStrategy ReleaseStrategy = new SequenceSizeReleaseStrategy();
assertTrue(ReleaseStrategy.canRelease(new MessageGroup("FOO")));
}
}

View File

@@ -77,7 +77,7 @@ public class AggregatorParserTests {
public void testPropertyAssignment() throws Exception {
EventDrivenConsumer endpoint =
(EventDrivenConsumer) context.getBean("completelyDefinedAggregator");
CompletionStrategy completionStrategy = (CompletionStrategy) context.getBean("completionStrategy");
ReleaseStrategy ReleaseStrategy = (ReleaseStrategy) context.getBean("releaseStrategy");
CorrelationStrategy correlationStrategy = (CorrelationStrategy) context.getBean("correlationStrategy");
MessageChannel outputChannel = (MessageChannel) context.getBean("outputChannel");
MessageChannel discardChannel = (MessageChannel) context.getBean("discardChannel");
@@ -88,8 +88,8 @@ public class AggregatorParserTests {
assertEquals("The MethodInvokingAggregator is not injected with the appropriate aggregation method",
expectedMethod, ((MessageListMethodAdapter) new DirectFieldAccessor(accessor.getPropertyValue("outputProcessor")).getPropertyValue("adapter")).getMethod());
assertEquals(
"The AggregatorEndpoint is not injected with the appropriate CompletionStrategy instance",
completionStrategy, accessor.getPropertyValue("completionStrategy"));
"The AggregatorEndpoint is not injected with the appropriate ReleaseStrategy instance",
ReleaseStrategy, accessor.getPropertyValue("ReleaseStrategy"));
assertEquals("The AggregatorEndpoint is not injected with the appropriate CorrelationStrategy instance",
correlationStrategy, accessor.getPropertyValue("correlationStrategy"));
Assert.assertEquals("The AggregatorEndpoint is not injected with the appropriate output channel",
@@ -101,10 +101,6 @@ public class AggregatorParserTests {
Assert.assertEquals(
"The AggregatorEndpoint is not configured with the appropriate 'send partial results on timeout' flag",
true, accessor.getPropertyValue("sendPartialResultOnTimeout"));
Assert.assertEquals("The AggregatorEndpoint is not configured with the appropriate reaper interval",
135l, accessor.getPropertyValue("reaperInterval"));
Assert.assertEquals("The AggregatorEndpoint is not configured with the appropriate timeout",
42l, accessor.getPropertyValue("timeout"));
}
@Test
@@ -119,7 +115,7 @@ public class AggregatorParserTests {
input.send(message);
}
PollableChannel outputChannel = (PollableChannel) context.getBean("outputChannel");
Message<?> response = outputChannel.receive();
Message<?> response = outputChannel.receive(10);
Assert.assertEquals(6l, response.getPayload());
}
@@ -129,38 +125,38 @@ public class AggregatorParserTests {
}
@Test(expected=BeanCreationException.class)
public void testDuplicateCompletionStrategyDefinition() {
public void testDuplicateReleaseStrategyDefinition() {
context = new ClassPathXmlApplicationContext(
"completionStrategyMethodWithMissingReference.xml", this.getClass());
"ReleaseStrategyMethodWithMissingReference.xml", this.getClass());
}
@Test
public void testAggregatorWithPojoCompletionStrategy() {
MessageChannel input = (MessageChannel) context.getBean("aggregatorWithPojoCompletionStrategyInput");
public void testAggregatorWithPojoReleaseStrategy() {
MessageChannel input = (MessageChannel) context.getBean("aggregatorWithPojoReleaseStrategyInput");
EventDrivenConsumer endpoint =
(EventDrivenConsumer) context.getBean("aggregatorWithPojoCompletionStrategy");
CompletionStrategy completionStrategy = (CompletionStrategy) new DirectFieldAccessor(
new DirectFieldAccessor(endpoint).getPropertyValue("handler")).getPropertyValue("completionStrategy");
Assert.assertTrue(completionStrategy instanceof CompletionStrategyAdapter);
DirectFieldAccessor completionStrategyAccessor = new DirectFieldAccessor(completionStrategy);
MethodInvoker invoker = (MethodInvoker) completionStrategyAccessor.getPropertyValue("invoker");
Assert.assertTrue(new DirectFieldAccessor(invoker).getPropertyValue("object") instanceof MaxValueCompletionStrategy);
Assert.assertTrue(((Method) completionStrategyAccessor.getPropertyValue("method")).getName().equals("checkCompleteness"));
input.send(createMessage(1l, "correllationId", 0, 0, null));
input.send(createMessage(2l, "correllationId", 0, 1, null));
input.send(createMessage(3l, "correllationId", 0, 2, null));
(EventDrivenConsumer) context.getBean("aggregatorWithPojoReleaseStrategy");
ReleaseStrategy ReleaseStrategy = (ReleaseStrategy) new DirectFieldAccessor(
new DirectFieldAccessor(endpoint).getPropertyValue("handler")).getPropertyValue("ReleaseStrategy");
Assert.assertTrue(ReleaseStrategy instanceof ReleaseStrategyAdapter);
DirectFieldAccessor ReleaseStrategyAccessor = new DirectFieldAccessor(ReleaseStrategy);
MethodInvoker invoker = (MethodInvoker) ReleaseStrategyAccessor.getPropertyValue("invoker");
Assert.assertTrue(new DirectFieldAccessor(invoker).getPropertyValue("object") instanceof MaxValueReleaseStrategy);
Assert.assertTrue(((Method) ReleaseStrategyAccessor.getPropertyValue("method")).getName().equals("checkCompleteness"));
input.send(createMessage(1l, "correllationId", 4, 0, null));
input.send(createMessage(2l, "correllationId", 4, 1, null));
input.send(createMessage(3l, "correllationId", 4, 2, null));
PollableChannel outputChannel = (PollableChannel) context.getBean("outputChannel");
Message<?> reply = outputChannel.receive(0);
Assert.assertNull(reply);
input.send(createMessage(5l, "correllationId", 0, 3, null));
input.send(createMessage(5l, "correllationId", 4, 3, null));
reply = outputChannel.receive(0);
Assert.assertNotNull(reply);
assertEquals(11l, reply.getPayload());
}
@Test(expected = BeanCreationException.class)
public void testAggregatorWithInvalidCompletionStrategyMethod() {
context = new ClassPathXmlApplicationContext("invalidCompletionStrategyMethod.xml", this.getClass());
public void testAggregatorWithInvalidReleaseStrategyMethod() {
context = new ClassPathXmlApplicationContext("invalidReleaseStrategyMethod.xml", this.getClass());
}

View File

@@ -12,7 +12,7 @@
<beans:bean id="pojoCorrelationStrategy"
class="org.springframework.integration.config.AggregatorWithCorrelationStrategyTests$PojoCorrelationStrategy"/>
<beans:bean id="completionStrategy" class="org.springframework.integration.config.AggregatorWithCorrelationStrategyTests$MessageCountCompletionStrategy">
<beans:bean id="releaseStrategy" class="org.springframework.integration.config.AggregatorWithCorrelationStrategyTests$MessageCountReleaseStrategy">
<beans:constructor-arg value="3"/>
</beans:bean>
@@ -31,13 +31,13 @@
</channel>
<aggregator ref="aggregator"
completion-strategy="completionStrategy"
release-strategy="releaseStrategy"
correlation-strategy="correlationStrategy"
input-channel="inputChannel"
output-channel="outputChannel"/>
<aggregator ref="aggregator"
completion-strategy="completionStrategy"
release-strategy="releaseStrategy"
correlation-strategy="pojoCorrelationStrategy" correlation-strategy-method="correlate"
input-channel="pojoInputChannel"
output-channel="pojoOutputChannel"/>

View File

@@ -21,7 +21,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.integration.aggregator.CompletionStrategy;
import org.springframework.integration.aggregator.MessageGroup;
import org.springframework.integration.aggregator.ReleaseStrategy;
import org.springframework.integration.aggregator.CorrelationStrategy;
import org.springframework.integration.annotation.Aggregator;
import org.springframework.integration.channel.PollableChannel;
@@ -31,7 +32,6 @@ import org.springframework.integration.message.MessageBuilder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Collection;
import java.util.List;
import static org.junit.Assert.assertThat;
@@ -45,108 +45,125 @@ import static org.junit.matchers.JUnitMatchers.containsString;
@RunWith(SpringJUnit4ClassRunner.class)
public class AggregatorWithCorrelationStrategyTests {
@Autowired
@Qualifier("inputChannel")
MessageChannel inputChannel;
@Autowired
@Qualifier("inputChannel")
MessageChannel inputChannel;
@Autowired
@Qualifier("outputChannel")
PollableChannel outputChannel;
@Autowired
@Qualifier("outputChannel")
PollableChannel outputChannel;
@Autowired
@Qualifier("pojoInputChannel")
MessageChannel pojoInputChannel;
@Autowired
@Qualifier("pojoInputChannel")
MessageChannel pojoInputChannel;
@Autowired
@Qualifier("pojoOutputChannel")
PollableChannel pojoOutputChannel;
@Autowired
@Qualifier("pojoOutputChannel")
PollableChannel pojoOutputChannel;
@Test
public void testCorrelationAndCompletion() {
inputChannel.send(MessageBuilder.withPayload("A1").setSequenceNumber(0).setSequenceSize(3)
.build());
inputChannel.send(MessageBuilder.withPayload("B2").setSequenceNumber(0).setSequenceSize(3)
.build());
inputChannel.send(MessageBuilder.withPayload("C3").setSequenceNumber(0).setSequenceSize(3)
.build());
inputChannel.send(MessageBuilder.withPayload("A4").setSequenceNumber(1).setSequenceSize(3)
.build());
inputChannel.send(MessageBuilder.withPayload("B5").setSequenceNumber(1).setSequenceSize(3)
.build());
inputChannel.send(MessageBuilder.withPayload("C6").setSequenceNumber(1).setSequenceSize(3)
.build());
inputChannel.send(MessageBuilder.withPayload("A7").setSequenceNumber(2).setSequenceSize(3)
.build());
inputChannel.send(MessageBuilder.withPayload("B8").setSequenceNumber(2).setSequenceSize(3)
.build());
inputChannel.send(MessageBuilder.withPayload("C9").setSequenceNumber(2).setSequenceSize(3)
.build());
receiveAndCompare(outputChannel, "A1", "A4", "A7");
receiveAndCompare(outputChannel, "B2", "B5", "B8");
receiveAndCompare(outputChannel, "C3", "C6", "C9");
}
@Test
public void testCorrelationAndCompletion() {
inputChannel.send(MessageBuilder.withPayload("A1").setSequenceNumber(0).build());
inputChannel.send(MessageBuilder.withPayload("B2").setSequenceNumber(0).build());
inputChannel.send(MessageBuilder.withPayload("C3").setSequenceNumber(0).build());
inputChannel.send(MessageBuilder.withPayload("A4").setSequenceNumber(1).build());
inputChannel.send(MessageBuilder.withPayload("B5").setSequenceNumber(1).build());
inputChannel.send(MessageBuilder.withPayload("C6").setSequenceNumber(1).build());
inputChannel.send(MessageBuilder.withPayload("A7").setSequenceNumber(2).build());
inputChannel.send(MessageBuilder.withPayload("B8").setSequenceNumber(2).build());
inputChannel.send(MessageBuilder.withPayload("C9").setSequenceNumber(2).build());
receiveAndCompare(outputChannel, "A1","A4","A7");
receiveAndCompare(outputChannel, "B2","B5","B8");
receiveAndCompare(outputChannel, "C3","C6","C9");
}
@Test
public void testCorrelationAndCompletionWithPojo() {
// the test verifies how a pojo strategy is applied
// Strings are correlated by their first letter, integers are correlated
// by the last digit
pojoInputChannel.send(MessageBuilder.withPayload("X1")
.setSequenceNumber(0).setSequenceSize(3).build());
pojoInputChannel.send(MessageBuilder.withPayload(93).setSequenceNumber(
0).setSequenceSize(3).build());
pojoInputChannel.send(MessageBuilder.withPayload("X4")
.setSequenceNumber(1).setSequenceSize(3).build());
pojoInputChannel.send(MessageBuilder.withPayload(113)
.setSequenceNumber(1).setSequenceSize(3).build());
pojoInputChannel.send(MessageBuilder.withPayload("X7")
.setSequenceNumber(2).setSequenceSize(3).build());
pojoInputChannel.send(MessageBuilder.withPayload(213)
.setSequenceNumber(2).setSequenceSize(3).build());
receiveAndCompare(pojoOutputChannel, "X1", "X4", "X7");
receiveAndCompare(pojoOutputChannel, "93", "113", "213");
}
@Test
public void testCorrelationAndCompletionWithPojo() {
// the test verifies how a pojo strategy is applied
// Strings are correlated by their first letter, integers are correlated by the last digit
pojoInputChannel.send(MessageBuilder.withPayload("X1").setSequenceNumber(0).build());
pojoInputChannel.send(MessageBuilder.withPayload(93).setSequenceNumber(0).build());
pojoInputChannel.send(MessageBuilder.withPayload("X4").setSequenceNumber(1).build());
pojoInputChannel.send(MessageBuilder.withPayload(113).setSequenceNumber(1).build());
pojoInputChannel.send(MessageBuilder.withPayload("X7").setSequenceNumber(2).build());
pojoInputChannel.send(MessageBuilder.withPayload(213).setSequenceNumber(2).build());
receiveAndCompare(pojoOutputChannel, "X1","X4","X7");
receiveAndCompare(pojoOutputChannel, "93","113","213");
}
private void receiveAndCompare(PollableChannel outputChannel,
String... expectedValues) {
Message<?> message = outputChannel.receive(500);
Assert.assertNotNull(message);
for (String expectedValue : expectedValues) {
assertThat((String) message.getPayload(),
containsString(expectedValue));
}
}
private void receiveAndCompare(PollableChannel outputChannel, String... expectedValues) {
Message<?> message = outputChannel.receive(500);
Assert.assertNotNull(message);
for (String expectedValue : expectedValues) {
assertThat((String)message.getPayload(), containsString(expectedValue));
}
}
public static class MessageCountReleaseStrategy implements
ReleaseStrategy {
private final int expectedSize;
public static class MessageCountCompletionStrategy implements CompletionStrategy {
public MessageCountReleaseStrategy(int expectedSize) {
this.expectedSize = expectedSize;
}
private final int expectedSize;
public boolean canRelease(MessageGroup messages) {
return messages.size() == expectedSize;
}
}
public MessageCountCompletionStrategy(int expectedSize) {
this.expectedSize = expectedSize;
}
public static class FirstLetterCorrelationStrategy implements
CorrelationStrategy {
public boolean isComplete(Collection<? extends Message<?>> messages) {
return messages.size() == expectedSize;
}
public Object getCorrelationKey(Message<?> message) {
return message.getPayload().toString().subSequence(0, 1);
}
}
}
public static class FirstLetterCorrelationStrategy implements CorrelationStrategy {
public static class PojoCorrelationStrategy {
public Object getCorrelationKey(Message<?> message) {
return message.getPayload().toString().subSequence(0,1);
}
public String correlate(String message) {
return message.substring(0, 1);
}
}
public String correlate(Integer message) {
return Integer.toString(message % 10);
}
public static class PojoCorrelationStrategy {
}
public String correlate(String message) {
return message.substring(0,1);
}
public static class SimpleAggregator {
public String correlate(Integer message) {
return Integer.toString(message % 10);
}
@Aggregator
public String concatenate(List<Object> payloads) {
StringBuffer buffer = new StringBuffer();
for (Object payload : payloads) {
buffer.append(payload.toString());
}
return buffer.toString();
}
}
public static class SimpleAggregator {
@Aggregator
public String concatenate(List<Object> payloads) {
StringBuffer buffer = new StringBuffer();
for (Object payload: payloads) {
buffer.append(payload.toString());
}
return buffer.toString();
}
}
}
}

View File

@@ -17,12 +17,12 @@ package org.springframework.integration.config;
import java.util.List;
public class MaxValueCompletionStrategy {
public class MaxValueReleaseStrategy {
private long maxValue;
public MaxValueCompletionStrategy(long maxValue){
public MaxValueReleaseStrategy(long maxValue){
this.maxValue = maxValue;
}

View File

@@ -7,7 +7,7 @@
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd">
<aggregator id="aggregator" ref="adderBean" method="add" completion-strategy="testCompletionStrategy"
<aggregator id="aggregator" ref="adderBean" method="add" release-strategy="testReleaseStrategy"
input-channel="input-channel" output-channel="replyChannel">
</aggregator>
@@ -16,6 +16,6 @@
<beans:bean id="adderBean" class="org.springframework.integration.config.Adder"/>
<beans:bean id="completionStrategyBean" class="org.springframework.integration.config.TestCompletionStrategy"/>
<beans:bean id="ReleaseStrategyBean" class="org.springframework.integration.config.TestReleaseStrategy"/>
</beans:beans>

View File

@@ -19,6 +19,7 @@ package org.springframework.integration.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.springframework.integration.test.util.TestUtils.getPropertyValue;
import java.util.ArrayList;
@@ -26,12 +27,12 @@ import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.aggregator.CorrelatingMessageHandler;
import org.springframework.integration.aggregator.CorrelationStrategy;
import org.springframework.integration.aggregator.CorrelationStrategyAdapter;
import org.springframework.integration.aggregator.Resequencer;
import org.springframework.integration.channel.NullChannel;
import org.springframework.integration.channel.PollableChannel;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageChannel;
@@ -79,21 +80,15 @@ public class ResequencerParserTests {
@Test
public void testDefaultResequencerProperties() {
EventDrivenConsumer endpoint = (EventDrivenConsumer) context.getBean("defaultResequencer");
Resequencer resequencer = TestUtils.getPropertyValue(endpoint, "handler", Resequencer.class);
CorrelatingMessageHandler resequencer = TestUtils.getPropertyValue(endpoint, "handler", CorrelatingMessageHandler.class);
assertNull(getPropertyValue(resequencer, "outputChannel"));
assertNull(getPropertyValue(resequencer, "discardChannel"));
assertTrue(getPropertyValue(resequencer, "discardChannel") instanceof NullChannel);
assertEquals("The ResequencerEndpoint is not set with the appropriate timeout value",
1000l, getPropertyValue(resequencer, "channelTemplate.sendTimeout"));
assertEquals("The ResequencerEndpoint is not configured with the appropriate 'send partial results on timeout' flag",
false, getPropertyValue(resequencer, "sendPartialResultOnTimeout"));
assertEquals("The ResequencerEndpoint is not configured with the appropriate reaper interval",
1000l, getPropertyValue(resequencer, "reaperInterval"));
assertEquals("The ResequencerEndpoint is not configured with the appropriate tracked correlationId capacity",
1000, getPropertyValue(resequencer, "trackedCorrelationIdCapacity"));
assertEquals("The ResequencerEndpoint is not configured with the appropriate timeout",
60000l, getPropertyValue(resequencer, "timeout"));
assertEquals("The ResequencerEndpoint is not configured with the appropriate 'release partial sequences' flag",
true, getPropertyValue(resequencer, "releasePartialSequences"));
false, getPropertyValue(getPropertyValue(resequencer, "outputProcessor"), "releasePartialSequences"));
}
@Test
@@ -101,7 +96,7 @@ public class ResequencerParserTests {
EventDrivenConsumer endpoint = (EventDrivenConsumer) context.getBean("completelyDefinedResequencer");
MessageChannel outputChannel = (MessageChannel) context.getBean("outputChannel");
MessageChannel discardChannel = (MessageChannel) context.getBean("discardChannel");
Resequencer resequencer = TestUtils.getPropertyValue(endpoint, "handler", Resequencer.class);
CorrelatingMessageHandler resequencer = TestUtils.getPropertyValue(endpoint, "handler", CorrelatingMessageHandler.class);
assertEquals("The ResequencerEndpoint is not injected with the appropriate output channel",
outputChannel, getPropertyValue(resequencer, "outputChannel"));
assertEquals("The ResequencerEndpoint is not injected with the appropriate discard channel",
@@ -110,20 +105,14 @@ public class ResequencerParserTests {
86420000l, getPropertyValue(resequencer, "channelTemplate.sendTimeout"));
assertEquals("The ResequencerEndpoint is not configured with the appropriate 'send partial results on timeout' flag",
true, getPropertyValue(resequencer, "sendPartialResultOnTimeout"));
assertEquals("The ResequencerEndpoint is not configured with the appropriate reaper interval",
135l, getPropertyValue(resequencer, "reaperInterval"));
assertEquals("The ResequencerEndpoint is not configured with the appropriate tracked correlationId capacity",
99, getPropertyValue(resequencer, "trackedCorrelationIdCapacity"));
assertEquals("The ResequencerEndpoint is not configured with the appropriate timeout",
42l, getPropertyValue(resequencer, "timeout"));
assertEquals("The ResequencerEndpoint is not configured with the appropriate 'release partial sequences' flag",
false, getPropertyValue(resequencer, "releasePartialSequences"));
false, getPropertyValue(getPropertyValue(resequencer, "outputProcessor"), "releasePartialSequences"));
}
@Test
public void testCorrelationStrategyRefOnly() throws Exception {
EventDrivenConsumer endpoint = (EventDrivenConsumer) context.getBean("resequencerWithCorrelationStrategyRefOnly");
Resequencer resequencer = TestUtils.getPropertyValue(endpoint, "handler", Resequencer.class);
CorrelatingMessageHandler resequencer = TestUtils.getPropertyValue(endpoint, "handler", CorrelatingMessageHandler.class);
assertEquals("The ResequencerEndpoint is not configured with the appropriate CorrelationStrategy",
context.getBean("testCorrelationStrategy"), getPropertyValue(resequencer, "correlationStrategy"));
}
@@ -131,7 +120,7 @@ public class ResequencerParserTests {
@Test
public void testCorrelationStrategyRefAndMethod() throws Exception {
EventDrivenConsumer endpoint = (EventDrivenConsumer) context.getBean("resequencerWithCorrelationStrategyRefAndMethod");
Resequencer resequencer = TestUtils.getPropertyValue(endpoint, "handler", Resequencer.class);
CorrelatingMessageHandler resequencer = TestUtils.getPropertyValue(endpoint, "handler", CorrelatingMessageHandler.class);
Object correlationStrategy = getPropertyValue(resequencer, "correlationStrategy");
assertEquals("The ResequencerEndpoint is not configured with a CorrelationStrategy adapter",
CorrelationStrategyAdapter.class, correlationStrategy.getClass());

View File

@@ -16,17 +16,16 @@
package org.springframework.integration.config;
import java.util.Collection;
import org.springframework.integration.aggregator.CompletionStrategy;
import org.springframework.integration.core.Message;
import org.springframework.integration.aggregator.MessageGroup;
import org.springframework.integration.aggregator.ReleaseStrategy;
/**
* @author Marius Bogoevici
*/
public class TestCompletionStrategy implements CompletionStrategy {
public class TestReleaseStrategy implements ReleaseStrategy {
public boolean isComplete(Collection<? extends Message<?>> messages) {
public boolean canRelease(MessageGroup messages) {
throw new UnsupportedOperationException("This is not intended to be implemented, but to verify injection into an <aggregator>");
}

View File

@@ -24,7 +24,7 @@
output-channel="outputChannel"
discard-channel="discardChannel"
ref="aggregatorBean"
completion-strategy="completionStrategy"
release-strategy="releaseStrategy"
correlation-strategy="correlationStrategy"
send-timeout="86420000"
send-partial-result-on-timeout="true"
@@ -39,14 +39,14 @@
input-channel="aggregatorWithReferenceAndMethodInput"
output-channel="outputChannel"/>
<channel id="aggregatorWithPojoCompletionStrategyInput"/>
<aggregator id="aggregatorWithPojoCompletionStrategy"
input-channel="aggregatorWithPojoCompletionStrategyInput"
<channel id="aggregatorWithPojoReleaseStrategyInput"/>
<aggregator id="aggregatorWithPojoReleaseStrategy"
input-channel="aggregatorWithPojoReleaseStrategyInput"
output-channel="outputChannel"
ref="adderBean"
method="add"
completion-strategy="pojoCompletionStrategy"
completion-strategy-method="checkCompleteness"/>
release-strategy="pojoReleaseStrategy"
release-strategy-method="checkCompleteness"/>
<beans:bean id="aggregatorBean"
class="org.springframework.integration.config.TestAggregatorBean" />
@@ -54,13 +54,13 @@
<beans:bean id="adderBean"
class="org.springframework.integration.config.Adder" />
<beans:bean id="completionStrategy"
class="org.springframework.integration.config.TestCompletionStrategy" />
<beans:bean id="releaseStrategy"
class="org.springframework.integration.config.TestReleaseStrategy" />
<beans:bean id="correlationStrategy" class="org.springframework.integration.config.TestCorrelationStrategy"/>
<beans:bean id="pojoCompletionStrategy"
class="org.springframework.integration.config.MaxValueCompletionStrategy">
<beans:bean id="pojoReleaseStrategy"
class="org.springframework.integration.config.MaxValueReleaseStrategy">
<beans:constructor-arg value="10" />
</beans:bean>

View File

@@ -20,7 +20,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.springframework.integration.test.util.TestUtils.getPropertyValue;
import java.lang.reflect.Method;
@@ -28,17 +27,18 @@ import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.aggregator.AbstractMessageAggregator;
import org.springframework.integration.aggregator.CompletionStrategyAdapter;
import org.springframework.integration.aggregator.ReleaseStrategyAdapter;
import org.springframework.integration.aggregator.CorrelatingMessageHandler;
import org.springframework.integration.aggregator.CorrelationStrategyAdapter;
import org.springframework.integration.aggregator.SequenceSizeCompletionStrategy;
import org.springframework.integration.aggregator.SequenceSizeReleaseStrategy;
import org.springframework.integration.channel.BeanFactoryChannelResolver;
import org.springframework.integration.channel.ChannelResolver;
import org.springframework.integration.channel.NullChannel;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.message.MessageHandler;
import org.springframework.integration.test.util.TestUtils;
/**
@@ -52,18 +52,13 @@ public class AggregatorAnnotationTests {
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "classpath:/org/springframework/integration/config/annotation/testAnnotatedAggregator.xml" });
final String endpointName = "endpointWithDefaultAnnotation";
AbstractMessageAggregator aggregator = this.getAggregator(context, endpointName);
assertTrue(getPropertyValue(aggregator, "completionStrategy") instanceof SequenceSizeCompletionStrategy);
MessageHandler aggregator = this.getAggregator(context, endpointName);
assertTrue(getPropertyValue(aggregator, "ReleaseStrategy") instanceof SequenceSizeReleaseStrategy);
assertNull(getPropertyValue(aggregator, "outputChannel"));
assertNull(getPropertyValue(aggregator, "discardChannel"));
assertEquals(AbstractMessageAggregator.DEFAULT_SEND_TIMEOUT,
assertTrue(getPropertyValue(aggregator, "discardChannel") instanceof NullChannel);
assertEquals(CorrelatingMessageHandler.DEFAULT_SEND_TIMEOUT,
getPropertyValue(aggregator, "channelTemplate.sendTimeout"));
assertEquals(AbstractMessageAggregator.DEFAULT_TIMEOUT, getPropertyValue(aggregator, "timeout"));
assertEquals(false, getPropertyValue(aggregator, "sendPartialResultOnTimeout"));
assertEquals(AbstractMessageAggregator.DEFAULT_REAPER_INTERVAL,
getPropertyValue(aggregator, "reaperInterval"));
assertEquals(AbstractMessageAggregator.DEFAULT_TRACKED_CORRRELATION_ID_CAPACITY,
getPropertyValue(aggregator, "trackedCorrelationIdCapacity"));
}
@Test
@@ -71,32 +66,29 @@ public class AggregatorAnnotationTests {
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "classpath:/org/springframework/integration/config/annotation/testAnnotatedAggregator.xml" });
final String endpointName = "endpointWithCustomizedAnnotation";
AbstractMessageAggregator aggregator = this.getAggregator(context, endpointName);
assertTrue(getPropertyValue(aggregator, "completionStrategy")
instanceof SequenceSizeCompletionStrategy);
MessageHandler aggregator = this.getAggregator(context, endpointName);
assertTrue(getPropertyValue(aggregator, "ReleaseStrategy")
instanceof SequenceSizeReleaseStrategy);
ChannelResolver channelResolver = new BeanFactoryChannelResolver(context);
assertEquals(channelResolver.resolveChannelName("outputChannel"),
getPropertyValue(aggregator, "outputChannel"));
assertEquals(channelResolver.resolveChannelName("discardChannel"),
getPropertyValue(aggregator, "discardChannel"));
assertEquals(98765432l, getPropertyValue(aggregator, "channelTemplate.sendTimeout"));
assertEquals(4567890l, getPropertyValue(aggregator, "timeout"));
assertEquals(true, getPropertyValue(aggregator, "sendPartialResultOnTimeout"));
assertEquals(1234l, getPropertyValue(aggregator, "reaperInterval"));
assertEquals(42, getPropertyValue(aggregator, "trackedCorrelationIdCapacity"));
}
@Test
public void testAnnotationWithCustomCompletionStrategy() throws Exception {
public void testAnnotationWithCustomReleaseStrategy() throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "classpath:/org/springframework/integration/config/annotation/testAnnotatedAggregator.xml" });
final String endpointName = "endpointWithDefaultAnnotationAndCustomCompletionStrategy";
AbstractMessageAggregator aggregator = this.getAggregator(context, endpointName);
Object completionStrategy = getPropertyValue(aggregator, "completionStrategy");
Assert.assertTrue(completionStrategy instanceof CompletionStrategyAdapter);
CompletionStrategyAdapter completionStrategyAdapter = (CompletionStrategyAdapter) completionStrategy;
final String endpointName = "endpointWithDefaultAnnotationAndCustomReleaseStrategy";
MessageHandler aggregator = this.getAggregator(context, endpointName);
Object ReleaseStrategy = getPropertyValue(aggregator, "ReleaseStrategy");
Assert.assertTrue(ReleaseStrategy instanceof ReleaseStrategyAdapter);
ReleaseStrategyAdapter ReleaseStrategyAdapter = (ReleaseStrategyAdapter) ReleaseStrategy;
DirectFieldAccessor invokerAccessor = new DirectFieldAccessor(
new DirectFieldAccessor(completionStrategyAdapter).getPropertyValue("invoker"));
new DirectFieldAccessor(ReleaseStrategyAdapter).getPropertyValue("invoker"));
Object targetObject = invokerAccessor.getPropertyValue("object");
assertSame(context.getBean(endpointName), targetObject);
Method completionCheckerMethod = (Method) invokerAccessor.getPropertyValue("method");
@@ -108,12 +100,12 @@ public class AggregatorAnnotationTests {
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "classpath:/org/springframework/integration/config/annotation/testAnnotatedAggregator.xml" });
final String endpointName = "endpointWithCorrelationStrategy";
AbstractMessageAggregator aggregator = this.getAggregator(context, endpointName);
MessageHandler aggregator = this.getAggregator(context, endpointName);
Object correlationStrategy = getPropertyValue(aggregator, "correlationStrategy");
Assert.assertTrue(correlationStrategy instanceof CorrelationStrategyAdapter);
CorrelationStrategyAdapter completionStrategyAdapter = (CorrelationStrategyAdapter) correlationStrategy;
CorrelationStrategyAdapter ReleaseStrategyAdapter = (CorrelationStrategyAdapter) correlationStrategy;
DirectFieldAccessor processorAccessor = new DirectFieldAccessor(
new DirectFieldAccessor(completionStrategyAdapter).getPropertyValue("processor"));
new DirectFieldAccessor(ReleaseStrategyAdapter).getPropertyValue("processor"));
Object targetObject = processorAccessor.getPropertyValue("targetObject");
assertSame(context.getBean(endpointName), targetObject);
Map<?, ?> handlerMethods = (Map<?, ?>) processorAccessor.getPropertyValue("handlerMethods");
@@ -125,10 +117,10 @@ public class AggregatorAnnotationTests {
private AbstractMessageAggregator getAggregator(ApplicationContext context, final String endpointName) {
private MessageHandler getAggregator(ApplicationContext context, final String endpointName) {
EventDrivenConsumer endpoint = (EventDrivenConsumer) context.getBean(
endpointName + ".aggregatingMethod.aggregator");
return TestUtils.getPropertyValue(endpoint, "handler", AbstractMessageAggregator.class);
return TestUtils.getPropertyValue(endpoint, "handler", MessageHandler.class);
}
}

View File

@@ -20,7 +20,7 @@ import java.util.List;
import org.springframework.integration.annotation.MessageEndpoint;
import org.springframework.integration.annotation.Aggregator;
import org.springframework.integration.annotation.CompletionStrategy;
import org.springframework.integration.annotation.ReleaseStrategy;
import org.springframework.integration.annotation.CorrelationStrategy;
/**
@@ -38,7 +38,7 @@ public class TestAnnotatedEndpointWithCorrelationStrategy {
return buffer.toString();
}
@CompletionStrategy
@ReleaseStrategy
public boolean isComplete(List<String> payloads) {
return payloads.size() == 3;
}

View File

@@ -24,7 +24,7 @@ import java.util.concurrent.ConcurrentMap;
import org.springframework.integration.aggregator.MessageSequenceComparator;
import org.springframework.integration.annotation.Aggregator;
import org.springframework.integration.annotation.CompletionStrategy;
import org.springframework.integration.annotation.ReleaseStrategy;
import org.springframework.integration.annotation.MessageEndpoint;
import org.springframework.integration.core.Message;
import org.springframework.integration.message.StringMessage;
@@ -32,8 +32,8 @@ import org.springframework.integration.message.StringMessage;
/**
* @author Marius Bogoevici
*/
@MessageEndpoint("endpointWithDefaultAnnotationAndCustomCompletionStrategy")
public class TestAnnotatedEndpointWithCompletionStrategy {
@MessageEndpoint("endpointWithDefaultAnnotationAndCustomReleaseStrategy")
public class TestAnnotatedEndpointWithReleaseStrategy {
private final ConcurrentMap<Object, Message<?>> aggregatedMessages = new ConcurrentHashMap<Object, Message<?>>();
@@ -54,7 +54,7 @@ public class TestAnnotatedEndpointWithCompletionStrategy {
return returnedMessage;
}
@CompletionStrategy
@ReleaseStrategy
public boolean completionChecker(List<Message<?>> messages) {
return true;
}

View File

@@ -8,7 +8,7 @@
<beans:bean id="correlationStrategy" class="org.springframework.integration.config.CorrelationStrategyInvalidConfigurationTests$VoidReturningCorrelationStrategy"/>
<beans:bean id="completionStrategy" class="org.springframework.integration.config.AggregatorWithCorrelationStrategyTests$MessageCountCompletionStrategy">
<beans:bean id="releaseStrategy" class="org.springframework.integration.config.AggregatorWithCorrelationStrategyTests$MessageCountReleaseStrategy">
<beans:constructor-arg value="3"/>
</beans:bean>
@@ -21,8 +21,8 @@
</channel>
<aggregator ref="aggregator"
completion-strategy="completionStrategy"
correlation-strategy="correlationStrategy" completion-strategy-method="invalidCorrelationMethod"
release-strategy="releaseStrategy" release-strategy-method="invalidCorrelationMethod"
correlation-strategy="correlationStrategy"
input-channel="inputChannel"
output-channel="outputChannel"/>

View File

@@ -7,12 +7,12 @@
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd">
<aggregator id="aggregatorWithPojoCompletionStrategy"
completion-strategy="completionStrategy"
<aggregator id="aggregatorWithPojoReleaseStrategy"
ref="adderBean" method="add"
input-channel="inputChannel"
output-channel="replyChannel"
completion-strategy-method="invalidMethodName"/>
release-strategy="releaseStrategy"
release-strategy-method="invalidMethodName"/>
<channel id="inputChannel"/>
<channel id="replyChannel"/>
@@ -20,11 +20,11 @@
<beans:bean id="adderBean"
class="org.springframework.integration.config.Adder" />
<beans:bean id="completionStrategy"
class="org.springframework.integration.config.TestCompletionStrategy" />
<beans:bean id="releaseStrategy"
class="org.springframework.integration.config.TestReleaseStrategy" />
<beans:bean id="pojoCompletionStrategy"
class="org.springframework.integration.config.MaxValueCompletionStrategy">
<beans:bean id="pojoReleaseStrategy"
class="org.springframework.integration.config.MaxValueReleaseStrategy">
<beans:constructor-arg value="10" />
</beans:bean>

View File

@@ -20,8 +20,6 @@ import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.Arrays;
import org.junit.Test;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessagingException;
@@ -68,13 +66,4 @@ public class SimpleMessageStoreTests {
assertEquals(1, store.list("bar").size());
}
@Test
public void shouldListByCorrelationAfterAddAll() throws Exception {
SimpleMessageStore store = new SimpleMessageStore();
Message<String> testMessage1 = MessageBuilder.withPayload("foo").build();
Message<String> testMessage2 = MessageBuilder.withPayload("bar").build();
store.put("bar", Arrays.<Message<?>>asList(testMessage1, testMessage2));
assertEquals(2, store.list("bar").size());
}
}