INT-330: Added MessageGroup and refactored CorrelatingMessageHandler and MessageGroupProcessors. This is an intermediary commit. Still there are some options for simplification around the MessageGroupListener interface, as onMessageProcessed could likely be moved into the message group.
This commit is contained in:
@@ -1,24 +1,22 @@
|
||||
package org.springframework.integration.aggregator;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.Before;
|
||||
import static org.mockito.Mockito.*;
|
||||
import org.junit.Test;
|
||||
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;
|
||||
|
||||
public class BufferingMessageHandlerIntegrationTest {
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class CorrelatingMessageHandlerIntegrationTest {
|
||||
|
||||
private CompletionStrategy completionStrategy;
|
||||
private CorrelationStrategy correlationStrategy;
|
||||
private MessageStore store = new SimpleMessageStore(100);
|
||||
private MessageChannel outputChannel = mock(MessageChannel.class);
|
||||
private MessageGroupProcessor processor = new PassThroughMessageGroupProcessor();
|
||||
// private CorrelatingMessageHandler customizedHandler = new CorrelatingMessageHandler(
|
||||
// store, correlationStrategy, completionStrategy, processor,
|
||||
// outputChannel);
|
||||
private CorrelatingMessageHandler defaultHandler = new CorrelatingMessageHandler(
|
||||
store, processor);
|
||||
|
||||
@@ -53,7 +51,7 @@ public class BufferingMessageHandlerIntegrationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void completesWithoutReleasingIncompleteCorrellations() throws Exception {
|
||||
public void completesWithoutReleasingIncompleteCorrelations() throws Exception {
|
||||
Message<?> message1 = correlatedMessage(1, 2, 1);
|
||||
Message<?> message2 = correlatedMessage(2, 2, 1);
|
||||
Message<?> message1a = correlatedMessage(1, 2, 2);
|
||||
@@ -16,27 +16,25 @@
|
||||
|
||||
package org.springframework.integration.aggregator;
|
||||
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Matchers.isA;
|
||||
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.List;
|
||||
|
||||
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.core.MessageChannel;
|
||||
import org.springframework.integration.core.MessageHeaders;
|
||||
import org.springframework.integration.message.MessageBuilder;
|
||||
import org.springframework.integration.store.MessageStore;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Matchers.isA;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* @author Iwein Fuld
|
||||
*/
|
||||
@@ -79,12 +77,12 @@ public class CorrelatingMessageHandlerTests {
|
||||
when(correlationStrategy.getCorrelationKey(isA(Message.class)))
|
||||
.thenReturn(correlationKey);
|
||||
|
||||
when(completionStrategy.isComplete(storedMessages)).thenReturn(false);
|
||||
when(completionStrategy.isComplete(Arrays.asList(message1))).thenReturn(false);
|
||||
|
||||
handler.handleMessage(message1);
|
||||
storedMessages.add(message1);
|
||||
|
||||
when(completionStrategy.isComplete(storedMessages)).thenReturn(true);
|
||||
when(completionStrategy.isComplete(Arrays.asList(message1, message2))).thenReturn(true);
|
||||
handler.handleMessage(message2);
|
||||
storedMessages.add(message2);
|
||||
|
||||
@@ -93,15 +91,16 @@ public class CorrelatingMessageHandlerTests {
|
||||
verify(store, times(2)).list(correlationKey);
|
||||
verify(correlationStrategy).getCorrelationKey(message1);
|
||||
verify(correlationStrategy).getCorrelationKey(message2);
|
||||
verify(completionStrategy, times(2)).isComplete(storedMessages);
|
||||
verify(processor).processAndSend(eq(correlationKey),
|
||||
eq(storedMessages), eq(outputChannel),
|
||||
isA(BufferedMessagesCallback.class));
|
||||
verify(completionStrategy).isComplete(Arrays.asList(message1));
|
||||
verify(completionStrategy).isComplete(Arrays.asList(message1, message2));
|
||||
verify(processor).processAndSend(isA(MessageGroup.class),
|
||||
eq(outputChannel)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private Message<?> testMessage(int id, int sequenceNumber) {
|
||||
return MessageBuilder.withPayload("test")
|
||||
return MessageBuilder.withPayload("test"+id)
|
||||
.setHeader(MessageHeaders.ID, id)
|
||||
.setSequenceNumber(sequenceNumber).build();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.springframework.integration.aggregator;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.integration.store.MessageStore;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class MessageGroupTests {
|
||||
|
||||
@Mock
|
||||
private MessageStore store;
|
||||
|
||||
private Object key = new Object();
|
||||
|
||||
@Mock
|
||||
private MessageGroupListener listener;
|
||||
|
||||
@Mock
|
||||
private CompletionStrategy completionStrategy;
|
||||
|
||||
@Test
|
||||
public void shouldBuildMessageGroup() {
|
||||
MessageGroup group = MessageGroup.builder().
|
||||
withStore(store).withCorrelationKey(key).
|
||||
completedBy(completionStrategy).observedBy(listener).
|
||||
build();
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ import org.springframework.integration.core.MessageChannel;
|
||||
import org.springframework.integration.message.MessageBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
@@ -27,13 +26,15 @@ import static org.mockito.Mockito.when;
|
||||
public class MethodInvokingMessageGroupProcessorTests {
|
||||
|
||||
@Mock
|
||||
private BufferedMessagesCallback processedCallback;
|
||||
private MessageGroupListener processedCallback;
|
||||
|
||||
@Mock
|
||||
private MessageChannel outputChannel;
|
||||
|
||||
private Collection<Message<?>> messagesUpForProcessing = new ArrayList<Message<?>>(
|
||||
private List<Message<?>> messagesUpForProcessing = new ArrayList<Message<?>>(
|
||||
3);
|
||||
@Mock
|
||||
private MessageGroup messageGroupMock;
|
||||
|
||||
@Before
|
||||
public void initializeMessagesUpForProcessing() {
|
||||
@@ -66,8 +67,9 @@ public class MethodInvokingMessageGroupProcessorTests {
|
||||
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor
|
||||
.forClass(Message.class);
|
||||
when(outputChannel.send(isA(Message.class))).thenReturn(true);
|
||||
processor.processAndSend(3, messagesUpForProcessing, outputChannel,
|
||||
processedCallback);
|
||||
when(messageGroupMock.getMessages()).thenReturn(messagesUpForProcessing);
|
||||
processor.processAndSend(messageGroupMock, outputChannel
|
||||
);
|
||||
// verify
|
||||
verify(outputChannel).send(messageCaptor.capture());
|
||||
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
|
||||
@@ -91,8 +93,9 @@ public class MethodInvokingMessageGroupProcessorTests {
|
||||
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor
|
||||
.forClass(Message.class);
|
||||
when(outputChannel.send(isA(Message.class))).thenReturn(true);
|
||||
processor.processAndSend(3, messagesUpForProcessing, outputChannel,
|
||||
processedCallback);
|
||||
when(messageGroupMock.getMessages()).thenReturn(messagesUpForProcessing);
|
||||
processor.processAndSend(messageGroupMock, outputChannel
|
||||
);
|
||||
// verify
|
||||
verify(outputChannel).send(messageCaptor.capture());
|
||||
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
|
||||
@@ -108,10 +111,11 @@ public class MethodInvokingMessageGroupProcessorTests {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void voidMethodShouldBeIgnored(List<Integer> flags){
|
||||
public void voidMethodShouldBeIgnored(List<Integer> flags) {
|
||||
fail("this method should not be invoked");
|
||||
}
|
||||
public String methodAcceptingNoCollectionShouldBeIgnored(@Header String irrelevant){
|
||||
|
||||
public String methodAcceptingNoCollectionShouldBeIgnored(@Header String irrelevant) {
|
||||
fail("this method should not be invoked");
|
||||
return null;
|
||||
}
|
||||
@@ -124,15 +128,17 @@ public class MethodInvokingMessageGroupProcessorTests {
|
||||
);
|
||||
|
||||
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor
|
||||
.forClass(Message.class) ;
|
||||
.forClass(Message.class);
|
||||
|
||||
when(outputChannel.send(isA(Message.class))).thenReturn(true);
|
||||
processor.processAndSend(3, messagesUpForProcessing, outputChannel,
|
||||
processedCallback);
|
||||
when(messageGroupMock.getMessages()).thenReturn(messagesUpForProcessing);
|
||||
processor.processAndSend(messageGroupMock, outputChannel
|
||||
);
|
||||
// verify
|
||||
verify(outputChannel).send(messageCaptor.capture());
|
||||
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
|
||||
}
|
||||
|
||||
private class AnnotatedParametersAggregator {
|
||||
public Integer and(List<Integer> flags) {
|
||||
int result = 0;
|
||||
@@ -142,7 +148,7 @@ public class MethodInvokingMessageGroupProcessorTests {
|
||||
return result;
|
||||
}
|
||||
|
||||
public String listHeaderShouldBeIgnored(@Header List<Integer> flags){
|
||||
public String listHeaderShouldBeIgnored(@Header List<Integer> flags) {
|
||||
fail("this method should not be invoked");
|
||||
return "";
|
||||
}
|
||||
@@ -155,11 +161,12 @@ public class MethodInvokingMessageGroupProcessorTests {
|
||||
);
|
||||
|
||||
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor
|
||||
.forClass(Message.class) ;
|
||||
.forClass(Message.class);
|
||||
|
||||
when(outputChannel.send(isA(Message.class))).thenReturn(true);
|
||||
processor.processAndSend(3, messagesUpForProcessing, outputChannel,
|
||||
processedCallback);
|
||||
when(messageGroupMock.getMessages()).thenReturn(messagesUpForProcessing);
|
||||
processor.processAndSend(messageGroupMock, outputChannel
|
||||
);
|
||||
// verify
|
||||
verify(outputChannel).send(messageCaptor.capture());
|
||||
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
|
||||
|
||||
@@ -16,26 +16,24 @@
|
||||
|
||||
package org.springframework.integration.aggregator;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.Ignore;
|
||||
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.core.MessageHeaders;
|
||||
import org.springframework.integration.message.MessageBuilder;
|
||||
import org.springframework.integration.message.MessageHandlingException;
|
||||
import org.springframework.integration.aggregator.CorrelatingMessageHandler;
|
||||
import org.springframework.integration.aggregator.MessageGroupProcessor;
|
||||
import org.springframework.integration.aggregator.BufferedMessagesCallback;
|
||||
import org.springframework.integration.store.SimpleMessageStore;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Marius Bogoevici
|
||||
@@ -252,24 +250,25 @@ public class NewAggregatorEndpointTests {
|
||||
}
|
||||
|
||||
private class MultiplyingProcessor implements MessageGroupProcessor {
|
||||
public void processAndSend(Object correlationKey, Collection<Message<?>> messagesUpForProcessing,
|
||||
MessageChannel outputChannel, BufferedMessagesCallback processedCallback
|
||||
public void processAndSend(MessageGroup group,
|
||||
MessageChannel outputChannel
|
||||
) {
|
||||
Integer product = 1;
|
||||
List<Message<?>> messagesUpForProcessing = group.getMessages();
|
||||
for (Message<?> message : messagesUpForProcessing) {
|
||||
product *= (Integer) message.getPayload();
|
||||
}
|
||||
outputChannel.send(MessageBuilder.withPayload(product).build());
|
||||
|
||||
processedCallback.onProcessingOf(
|
||||
group.onProcessingOf(
|
||||
messagesUpForProcessing.toArray(new Message[messagesUpForProcessing.size()])
|
||||
);
|
||||
processedCallback.onCompletionOf(correlationKey);
|
||||
group.onCompletion();
|
||||
}
|
||||
}
|
||||
|
||||
private class NullReturningMessageProcessor implements MessageGroupProcessor {
|
||||
public void processAndSend(Object correlationKey, Collection<Message<?>> messagesUpForProcessing, MessageChannel outputChannel, BufferedMessagesCallback processedCallback) {
|
||||
public void processAndSend(MessageGroup group, MessageChannel outputChannel) {
|
||||
//noop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,9 @@
|
||||
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 org.junit.Test;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
@@ -31,16 +29,16 @@ 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.aggregator.CorrelatingMessageHandler;
|
||||
import org.springframework.integration.aggregator.MessageGroupProcessor;
|
||||
import org.springframework.integration.aggregator.BufferedMessagesCallback;
|
||||
import org.springframework.integration.store.SimpleMessageStore;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Marius Bogoevici
|
||||
@@ -319,25 +317,26 @@ public class NewConcurrentAggregatorEndpointTests {
|
||||
if (this.aggregator != null) this.aggregator.stop();
|
||||
}
|
||||
|
||||
private class MultiplyingProcessor implements MessageGroupProcessor {
|
||||
public void processAndSend(Object correlationKey, Collection<Message<?>> messagesUpForProcessing,
|
||||
MessageChannel outputChannel, BufferedMessagesCallback processedCallback
|
||||
private class MultiplyingProcessor implements MessageGroupProcessor {
|
||||
public void processAndSend(MessageGroup group,
|
||||
MessageChannel outputChannel
|
||||
) {
|
||||
Integer product = 1;
|
||||
List<Message<?>> messagesUpForProcessing = group.getMessages();
|
||||
for (Message<?> message : messagesUpForProcessing) {
|
||||
product *= (Integer) message.getPayload();
|
||||
}
|
||||
outputChannel.send(MessageBuilder.withPayload(product).build());
|
||||
|
||||
processedCallback.onProcessingOf(
|
||||
group.onProcessingOf(
|
||||
messagesUpForProcessing.toArray(new Message[messagesUpForProcessing.size()])
|
||||
);
|
||||
processedCallback.onCompletionOf(correlationKey);
|
||||
group.onCompletion();
|
||||
}
|
||||
}
|
||||
|
||||
private class NullReturningMessageProcessor implements MessageGroupProcessor {
|
||||
public void processAndSend(Object correlationKey, Collection<Message<?>> messagesUpForProcessing, MessageChannel outputChannel, BufferedMessagesCallback processedCallback) {
|
||||
public void processAndSend(MessageGroup group, MessageChannel outputChannel) {
|
||||
//noop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ public class AggregatorWithCorrelationStrategyTests {
|
||||
this.expectedSize = expectedSize;
|
||||
}
|
||||
|
||||
public boolean isComplete(List<Message<?>> messages) {
|
||||
public boolean isComplete(List<? extends Message<?>> messages) {
|
||||
return messages.size() == expectedSize;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.springframework.integration.core.Message;
|
||||
*/
|
||||
public class TestCompletionStrategy implements CompletionStrategy {
|
||||
|
||||
public boolean isComplete(List<Message<?>> messages) {
|
||||
public boolean isComplete(List<? extends Message<?>> messages) {
|
||||
throw new UnsupportedOperationException("This is not intended to be implemented, but to verify injection into an <aggregator>");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user