/* * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.integration.config.annotation; import static org.junit.Assert.assertEquals; import java.util.ArrayList; import java.util.List; import org.junit.Test; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.annotation.Order; import org.springframework.integration.MessageRejectedException; import org.springframework.integration.annotation.MessageEndpoint; import org.springframework.integration.annotation.ServiceActivator; import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.dispatcher.RoundRobinLoadBalancingStrategy; import org.springframework.integration.test.util.TestUtils; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.support.GenericMessage; /** * @author Mark Fisher * @author Artem Bilan */ public class SubscriberOrderTests { @Test public void directChannelAndFailoverDispatcherWithSingleCallPerMethod() { GenericApplicationContext context = TestUtils.createTestApplicationContext(); context.registerBeanDefinition("postProcessor", new RootBeanDefinition(MessagingAnnotationPostProcessor.class)); RootBeanDefinition channelDefinition = new RootBeanDefinition(DirectChannel.class); context.registerBeanDefinition("input", channelDefinition); RootBeanDefinition testBeanDefinition = new RootBeanDefinition(TestBean.class); testBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue(1); context.registerBeanDefinition("testBean", testBeanDefinition); context.refresh(); TestBean testBean = (TestBean) context.getBean("testBean"); MessageChannel channel = (MessageChannel) context.getBean("input"); channel.send(new GenericMessage<String>("test-1")); channel.send(new GenericMessage<String>("test-2")); channel.send(new GenericMessage<String>("test-3")); channel.send(new GenericMessage<String>("test-4")); channel.send(new GenericMessage<String>("test-5")); List<Integer> calls = testBean.calls; assertEquals(5, calls.size()); assertEquals(1, calls.get(0).intValue()); assertEquals(2, calls.get(1).intValue()); assertEquals(3, calls.get(2).intValue()); assertEquals(4, calls.get(3).intValue()); assertEquals(5, calls.get(4).intValue()); context.close(); } @Test public void directChannelAndFailoverDispatcherWithMultipleCallsPerMethod() { GenericApplicationContext context = TestUtils.createTestApplicationContext(); context.registerBeanDefinition("postProcessor", new RootBeanDefinition(MessagingAnnotationPostProcessor.class)); BeanDefinitionBuilder channelBuilder = BeanDefinitionBuilder.rootBeanDefinition(DirectChannel.class); channelBuilder.addConstructorArgValue(null); RootBeanDefinition channelDefinition = (RootBeanDefinition) channelBuilder.getBeanDefinition(); context.registerBeanDefinition("input", channelDefinition); RootBeanDefinition testBeanDefinition = new RootBeanDefinition(TestBean.class); testBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue(2); context.registerBeanDefinition("testBean", testBeanDefinition); context.refresh(); TestBean testBean = (TestBean) context.getBean("testBean"); MessageChannel channel = (MessageChannel) context.getBean("input"); channel.send(new GenericMessage<String>("test-1")); channel.send(new GenericMessage<String>("test-2")); channel.send(new GenericMessage<String>("test-3")); channel.send(new GenericMessage<String>("test-4")); channel.send(new GenericMessage<String>("test-5")); channel.send(new GenericMessage<String>("test-6")); channel.send(new GenericMessage<String>("test-7")); channel.send(new GenericMessage<String>("test-8")); channel.send(new GenericMessage<String>("test-9")); channel.send(new GenericMessage<String>("test-10")); assertEquals(10, testBean.calls.size()); assertEquals(1, testBean.calls.get(0).intValue()); assertEquals(1, testBean.calls.get(1).intValue()); assertEquals(2, testBean.calls.get(2).intValue()); assertEquals(2, testBean.calls.get(3).intValue()); assertEquals(3, testBean.calls.get(4).intValue()); assertEquals(3, testBean.calls.get(5).intValue()); assertEquals(4, testBean.calls.get(6).intValue()); assertEquals(4, testBean.calls.get(7).intValue()); assertEquals(5, testBean.calls.get(8).intValue()); assertEquals(5, testBean.calls.get(9).intValue()); testBean.reset(); channel.send(new GenericMessage<String>("test-11")); assertEquals(1, testBean.calls.size()); assertEquals(1, testBean.calls.get(0).intValue()); context.close(); } @Test public void directChannelAndRoundRobinDispatcher() { GenericApplicationContext context = TestUtils.createTestApplicationContext(); context.registerBeanDefinition("postProcessor", new RootBeanDefinition(MessagingAnnotationPostProcessor.class)); RootBeanDefinition channelDefinition = new RootBeanDefinition(DirectChannel.class); channelDefinition.getConstructorArgumentValues().addGenericArgumentValue(new RoundRobinLoadBalancingStrategy()); context.registerBeanDefinition("input", channelDefinition); RootBeanDefinition testBeanDefinition = new RootBeanDefinition(TestBean.class); testBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue(1000); context.registerBeanDefinition("testBean", testBeanDefinition); context.refresh(); TestBean testBean = (TestBean) context.getBean("testBean"); MessageChannel channel = (MessageChannel) context.getBean("input"); channel.send(new GenericMessage<String>("test-1")); channel.send(new GenericMessage<String>("test-2")); channel.send(new GenericMessage<String>("test-3")); channel.send(new GenericMessage<String>("test-4")); channel.send(new GenericMessage<String>("test-5")); List<Integer> calls = testBean.calls; assertEquals(5, calls.size()); assertEquals(1, calls.get(0).intValue()); assertEquals(2, calls.get(1).intValue()); assertEquals(3, calls.get(2).intValue()); assertEquals(4, calls.get(3).intValue()); assertEquals(5, calls.get(4).intValue()); context.close(); } static abstract class AbstractTestBean { @Order(4) abstract void fourth(Message<?> message); @Order(2) abstract void second(Message<?> message); } @MessageEndpoint static class TestBean extends AbstractTestBean { private final int maxCallsPerMethod; private volatile List<Integer> calls = new ArrayList<Integer>(); TestBean(int maxCallsPerMethod) { this.maxCallsPerMethod = maxCallsPerMethod; } void reset() { this.calls = new ArrayList<Integer>(); } @Order(3) @ServiceActivator(inputChannel = "input") public void third(Message<?> message) { this.handle(3, message); } @Override @ServiceActivator(inputChannel = "input") public void second(Message<?> message) { this.handle(2, message); } @Order(1) @ServiceActivator(inputChannel = "input") public void first(Message<?> message) { this.handle(1, message); } @Order(5) @ServiceActivator(inputChannel = "input") public void fifth(Message<?> message) { this.handle(5, message); } @Override @ServiceActivator(inputChannel = "input") public void fourth(Message<?> message) { this.handle(4, message); } private void handle(int methodNumber, Message<?> message) { int count = 0; for (int callNumber : this.calls) { if (callNumber == methodNumber) { count++; if (count >= this.maxCallsPerMethod) { throw new MessageRejectedException(message, null); } } } this.calls.add(methodNumber); } } }