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:
Iwein Fuld
2009-12-29 18:19:35 +00:00
parent 89c06965f0
commit 058e555de9
19 changed files with 277 additions and 146 deletions

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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();
}
}

View File

@@ -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));

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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;
}

View File

@@ -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>");
}