@Test public void completesAfterThreshold() throws Exception { defaultHandler.setReleaseStrategy(new MessageCountReleaseStrategy()); MessageChannel discardChannel = mock(MessageChannel.class); when(discardChannel.send(any(Message.class))).thenReturn(true); defaultHandler.setDiscardChannel(discardChannel); Message<?> message1 = correlatedMessage(1, 2, 1); Message<?> message2 = correlatedMessage(1, 2, 2); defaultHandler.handleMessage(message1); verify(outputChannel).send(message1); defaultHandler.handleMessage(message2); verify(outputChannel, never()).send(message2); verify(discardChannel).send(message2); }
@Test public void completesIfNoSequence() throws Exception { defaultHandler.setReleaseStrategy(new MessageCountReleaseStrategy(2)); Message<?> message1 = MessageBuilder.withPayload(1).setCorrelationId("foo").build(); Message<?> message2 = MessageBuilder.withPayload(2).setCorrelationId("foo").build(); Message<?> message3 = MessageBuilder.withPayload(3).setCorrelationId("foo").build(); defaultHandler.handleMessage(message1); verify(outputChannel, never()).send(message3); defaultHandler.handleMessage(message2); verify(outputChannel).send(message2); defaultHandler.handleMessage(message3); verify(outputChannel, never()).send(message3); }
@Bean @ServiceActivator(inputChannel = "aggregatorChannel") public MessageHandler aggregator() { AggregatingMessageHandler handler = new AggregatingMessageHandler(new SimpleMessageGroupProcessor()); handler.setCorrelationStrategy(new ExpressionEvaluatingCorrelationStrategy("1")); handler.setReleaseStrategy(new ExpressionEvaluatingReleaseStrategy("size() == 10")); handler.setOutputChannelName("splitterChannel"); return handler; }
@Before public void configureAggregator() { this.taskExecutor = new SimpleAsyncTaskExecutor(); this.aggregator = new AggregatingMessageHandler(new MultiplyingProcessor(), this.store); this.aggregator.setReleaseStrategy(new SimpleSequenceSizeReleaseStrategy()); }
@Test /* INT-3216 */ public void testDontReapIfAlreadyComplete() throws Exception { MessageGroupProcessor mgp = new DefaultAggregatingMessageGroupProcessor(); AggregatingMessageHandler handler = new AggregatingMessageHandler(mgp); handler.setReleaseStrategy(group -> true); QueueChannel outputChannel = new QueueChannel(); handler.setOutputChannel(outputChannel); MessageGroupStore mgs = TestUtils.getPropertyValue(handler, "messageStore", MessageGroupStore.class); mgs.addMessagesToGroup("foo", new GenericMessage<>("foo")); mgs.completeGroup("foo"); mgs = spy(mgs); new DirectFieldAccessor(handler).setPropertyValue("messageStore", mgs); Method forceComplete = AbstractCorrelatingMessageHandler.class.getDeclaredMethod("forceComplete", MessageGroup.class); forceComplete.setAccessible(true); MessageGroup group = (MessageGroup) TestUtils.getPropertyValue(mgs, "groupIdToMessageGroup", Map.class) .get("foo"); assertTrue(group.isComplete()); forceComplete.invoke(handler, group); verify(mgs, never()).getMessageGroup("foo"); assertNull(outputChannel.receive(0)); }
@Test // INT-2833 public void testReaperReapsAnEmptyGroup() { final MessageGroupStore groupStore = new SimpleMessageStore(); AggregatingMessageHandler handler = new AggregatingMessageHandler(group -> group, groupStore); final List<Message<?>> outputMessages = new ArrayList<>(); handler.setOutputChannel((message, timeout) -> { /* * Executes when group 'bar' completes normally */ outputMessages.add(message); return true; }); handler.setReleaseStrategy(group -> group.size() == 1); Message<String> message = MessageBuilder.withPayload("foo") .setCorrelationId("bar") .build(); handler.handleMessage(message); assertEquals(1, outputMessages.size()); assertEquals(1, TestUtils.getPropertyValue(handler, "messageStore.groupIdToMessageGroup", Map.class).size()); groupStore.expireMessageGroups(0); assertEquals(0, TestUtils.getPropertyValue(handler, "messageStore.groupIdToMessageGroup", Map.class).size()); }
@Test public void batchingWithoutLeftovers() { QueueChannel outputChannel = new QueueChannel(); QueueChannel discardChannel = new QueueChannel(); defaultHandler.setOutputChannel(outputChannel); defaultHandler.setDiscardChannel(discardChannel); defaultHandler.setReleaseStrategy(new SampleSizeReleaseStrategy()); defaultHandler.setExpireGroupsUponCompletion(true); for (int i = 0; i < 10; i++) { defaultHandler.handleMessage(MessageBuilder.withPayload(i).setCorrelationId("A").build()); } assertEquals(5, ((List<?>) outputChannel.receive(0).getPayload()).size()); assertEquals(5, ((List<?>) outputChannel.receive(0).getPayload()).size()); assertNull(discardChannel.receive(0)); }
return true; }); handler.setReleaseStrategy(group -> group.size() == 1);
@Test public void batchingWithLeftovers() { QueueChannel outputChannel = new QueueChannel(); QueueChannel discardChannel = new QueueChannel(); defaultHandler.setOutputChannel(outputChannel); defaultHandler.setDiscardChannel(discardChannel); defaultHandler.setReleaseStrategy(new SampleSizeReleaseStrategy()); defaultHandler.setExpireGroupsUponCompletion(true); for (int i = 0; i < 12; i++) { defaultHandler.handleMessage(MessageBuilder.withPayload(i).setCorrelationId("A").build()); } assertEquals(5, ((List<?>) outputChannel.receive(0).getPayload()).size()); assertEquals(5, ((List<?>) outputChannel.receive(0).getPayload()).size()); assertNull(discardChannel.receive(0)); assertEquals(2, store.getMessageGroup("A").getMessages().size()); }
@Test public void testReapWithChangeInSameMillisecond() throws Exception { MessageGroupProcessor mgp = new DefaultAggregatingMessageGroupProcessor(); AggregatingMessageHandler handler = new AggregatingMessageHandler(mgp); handler.setReleaseStrategy(group -> true); QueueChannel outputChannel = new QueueChannel(); handler.setOutputChannel(outputChannel); MessageGroupStore mgs = TestUtils.getPropertyValue(handler, "messageStore", MessageGroupStore.class); Method forceComplete = AbstractCorrelatingMessageHandler.class.getDeclaredMethod("forceComplete", MessageGroup.class); forceComplete.setAccessible(true); GenericMessage<String> secondMessage = new GenericMessage<>("bar"); mgs.addMessagesToGroup("foo", new GenericMessage<>("foo"), secondMessage); MessageGroup group = mgs.getMessageGroup("foo"); // remove a message mgs.removeMessagesFromGroup("foo", secondMessage); // force lastModified to be the same MessageGroup groupNow = mgs.getMessageGroup("foo"); new DirectFieldAccessor(group).setPropertyValue("lastModified", groupNow.getLastModified()); forceComplete.invoke(handler, group); Message<?> message = outputChannel.receive(0); assertNotNull(message); Collection<?> payload = (Collection<?>) message.getPayload(); assertEquals(1, payload.size()); }
@Test public void shouldRejectDuplicatedSequenceNumbers() { 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); this.aggregator.setReleaseStrategy(new SequenceSizeReleaseStrategy()); this.aggregator.handleMessage(message1); this.aggregator.handleMessage(message3); // duplicated sequence number, either message3 or message4 should be rejected this.aggregator.handleMessage(message4); this.aggregator.handleMessage(message2); Message<?> reply = replyChannel.receive(10000); assertNotNull("A message should be aggregated", reply); assertThat((reply.getPayload()), is(105)); }
@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.aggregator.setReleaseStrategy(new SequenceSizeReleaseStrategy()); 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)); assertTrue(latch.await(10, TimeUnit.SECONDS)); Message<?> reply = replyChannel.receive(10000); assertNotNull("A message should be aggregated", reply); assertThat(reply.getPayload(), is(105)); }
@Test public void testDontReapIfAlreadyCompleteAfterRefetch() throws Exception { MessageGroupProcessor mgp = new DefaultAggregatingMessageGroupProcessor(); AggregatingMessageHandler handler = new AggregatingMessageHandler(mgp); handler.setReleaseStrategy(group -> true); QueueChannel outputChannel = new QueueChannel(); handler.setOutputChannel(outputChannel); MessageGroupStore mgs = TestUtils.getPropertyValue(handler, "messageStore", MessageGroupStore.class); mgs.addMessagesToGroup("foo", new GenericMessage<>("foo")); MessageGroup group = new SimpleMessageGroup(mgs.getMessageGroup("foo")); mgs.completeGroup("foo"); mgs = spy(mgs); new DirectFieldAccessor(handler).setPropertyValue("messageStore", mgs); Method forceComplete = AbstractCorrelatingMessageHandler.class.getDeclaredMethod("forceComplete", MessageGroup.class); forceComplete.setAccessible(true); MessageGroup groupInStore = (MessageGroup) TestUtils.getPropertyValue(mgs, "groupIdToMessageGroup", Map.class) .get("foo"); assertTrue(groupInStore.isComplete()); assertFalse(group.isComplete()); new DirectFieldAccessor(group).setPropertyValue("lastModified", groupInStore.getLastModified()); forceComplete.invoke(handler, group); verify(mgs).getMessageGroup("foo"); assertNull(outputChannel.receive(0)); }
AggregatingMessageHandler handler = new AggregatingMessageHandler(new DefaultAggregatingMessageGroupProcessor()); handler.setCorrelationStrategy(message -> "foo"); handler.setReleaseStrategy(new MessageCountReleaseStrategy(60000)); handler.setExpireGroupsUponCompletion(true); handler.setSendPartialResultOnExpiry(true);
@Test public void testDontReapIfNewGroupFoundDuringRefetch() throws Exception { MessageGroupProcessor mgp = new DefaultAggregatingMessageGroupProcessor(); AggregatingMessageHandler handler = new AggregatingMessageHandler(mgp); handler.setReleaseStrategy(group -> true); QueueChannel outputChannel = new QueueChannel(); handler.setOutputChannel(outputChannel); MessageGroupStore mgs = TestUtils.getPropertyValue(handler, "messageStore", MessageGroupStore.class); mgs.addMessagesToGroup("foo", new GenericMessage<>("foo")); MessageGroup group = new SimpleMessageGroup(mgs.getMessageGroup("foo")); mgs = spy(mgs); new DirectFieldAccessor(handler).setPropertyValue("messageStore", mgs); Method forceComplete = AbstractCorrelatingMessageHandler.class.getDeclaredMethod("forceComplete", MessageGroup.class); forceComplete.setAccessible(true); MessageGroup groupInStore = (MessageGroup) TestUtils.getPropertyValue(mgs, "groupIdToMessageGroup", Map.class) .get("foo"); assertFalse(groupInStore.isComplete()); assertFalse(group.isComplete()); DirectFieldAccessor directFieldAccessor = new DirectFieldAccessor(group); directFieldAccessor.setPropertyValue("lastModified", groupInStore.getLastModified()); directFieldAccessor.setPropertyValue("timestamp", groupInStore.getTimestamp() - 1); forceComplete.invoke(handler, group); verify(mgs).getMessageGroup("foo"); assertNull(outputChannel.receive(0)); }
@Test public void jdkProxy() { 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); AggregatingMessageHandler handler = new AggregatingMessageHandler(aggregator); handler.setReleaseStrategy(new MessageCountReleaseStrategy()); handler.setOutputChannel(output); handler.setBeanFactory(mock(BeanFactory.class)); handler.afterPropertiesSet(); 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); AggregatingMessageHandler handler = new AggregatingMessageHandler(aggregator); handler.setReleaseStrategy(new MessageCountReleaseStrategy()); handler.setOutputChannel(output); handler.setBeanFactory(mock(BeanFactory.class)); handler.afterPropertiesSet(); 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 firstBest() { QueueChannel outputChannel = new QueueChannel(); QueueChannel discardChannel = new QueueChannel(); defaultHandler.setOutputChannel(outputChannel); defaultHandler.setDiscardChannel(discardChannel); defaultHandler.setReleaseStrategy(new FirstBestReleaseStrategy()); for (int i = 0; i < 5; i++) { defaultHandler.handleMessage(MessageBuilder.withPayload(i).setCorrelationId("A").build()); } assertEquals(1, ((List<?>) outputChannel.receive(0).getPayload()).size()); assertNotNull(discardChannel.receive(0)); assertNotNull(discardChannel.receive(0)); assertNotNull(discardChannel.receive(0)); assertNotNull(discardChannel.receive(0)); }
@Test public void waitForAllCustomReleaseStrategyWithLateArrivals() { QueueChannel outputChannel = new QueueChannel(); QueueChannel discardChannel = new QueueChannel(); defaultHandler.setOutputChannel(outputChannel); defaultHandler.setDiscardChannel(discardChannel); defaultHandler.setReleaseStrategy(new SampleSizeReleaseStrategy()); for (int i = 0; i < 5; i++) { defaultHandler.handleMessage(MessageBuilder.withPayload(i).setCorrelationId("A").build()); } assertEquals(5, ((List<?>) outputChannel.receive(0).getPayload()).size()); assertNull(discardChannel.receive(0)); assertEquals(0, store.getMessageGroup("A").getMessages().size()); // send another message with the same correlation id and see it in the discard channel defaultHandler.handleMessage(MessageBuilder.withPayload("foo").setCorrelationId("A").build()); assertNotNull(discardChannel.receive(0)); // expireMessageGroups from aggregator MessageStore and the messages should start accumulating again store.expireMessageGroups(0); defaultHandler.handleMessage(MessageBuilder.withPayload("foo").setCorrelationId("A").build()); assertNull(discardChannel.receive(0)); assertEquals(1, store.getMessageGroup("A").getMessages().size()); }
@Test @Ignore("Until 5.2 with new 'owner' feature on groups") public void testDontReapMessageOfOtherHandler() { MessageGroupStore groupStore = new SimpleMessageStore(); AggregatingMessageHandler handler1 = new AggregatingMessageHandler(group -> group, groupStore); AggregatingMessageHandler handler2 = new AggregatingMessageHandler(group -> group, groupStore); QueueChannel handler1DiscardChannel = new QueueChannel(); handler1.setDiscardChannel(handler1DiscardChannel); QueueChannel handler2DiscardChannel = new QueueChannel(); handler2.setDiscardChannel(handler2DiscardChannel); handler1.setReleaseStrategy(group -> false); handler2.setReleaseStrategy(group -> false); handler1.handleMessage(MessageBuilder.withPayload("foo").setCorrelationId("foo").build()); handler1.handleMessage(MessageBuilder.withPayload("foo").setCorrelationId("foo").build()); handler2.handleMessage(MessageBuilder.withPayload("foo").setCorrelationId("bar").build()); groupStore.expireMessageGroups(0); assertEquals(2, handler1DiscardChannel.getQueueSize()); assertEquals(1, handler2DiscardChannel.getQueueSize()); }