/*
* Copyright 2014-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.configuration;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import org.aopalliance.intercept.MethodInterceptor;
import org.apache.commons.logging.Log;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.Lifecycle;
import org.springframework.context.SmartLifecycle;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.expression.EvaluationContext;
import org.springframework.integration.annotation.Aggregator;
import org.springframework.integration.annotation.BridgeFrom;
import org.springframework.integration.annotation.BridgeTo;
import org.springframework.integration.annotation.Gateway;
import org.springframework.integration.annotation.GatewayHeader;
import org.springframework.integration.annotation.InboundChannelAdapter;
import org.springframework.integration.annotation.IntegrationComponentScan;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.annotation.Poller;
import org.springframework.integration.annotation.Publisher;
import org.springframework.integration.annotation.Role;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.annotation.Transformer;
import org.springframework.integration.annotation.UseSpelInvoker;
import org.springframework.integration.channel.AbstractMessageChannel;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.NullChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.channel.interceptor.WireTap;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.config.EnableMessageHistory;
import org.springframework.integration.config.EnablePublisher;
import org.springframework.integration.config.ExpressionControlBusFactoryBean;
import org.springframework.integration.config.GlobalChannelInterceptor;
import org.springframework.integration.config.IntegrationConverter;
import org.springframework.integration.config.SpelFunctionFactoryBean;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.core.MessagingTemplate;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.endpoint.MethodInvokingMessageSource;
import org.springframework.integration.endpoint.PollingConsumer;
import org.springframework.integration.expression.SpelPropertyAccessorRegistrar;
import org.springframework.integration.gateway.GatewayProxyFactoryBean;
import org.springframework.integration.history.MessageHistory;
import org.springframework.integration.history.MessageHistoryConfigurer;
import org.springframework.integration.json.JsonPropertyAccessor;
import org.springframework.integration.scheduling.PollerMetadata;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.support.MutableMessageBuilder;
import org.springframework.integration.support.SmartLifecycleRoleController;
import org.springframework.integration.test.util.OnlyOnceTrigger;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageDeliveryException;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.messaging.support.ChannelInterceptorAdapter;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.scheduling.support.PeriodicTrigger;
import org.springframework.stereotype.Component;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import org.springframework.util.ClassUtils;
import org.springframework.util.MultiValueMap;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* @author Artem Bilan
* @author Gary Russell
* @since 4.0
*/
@ContextConfiguration(loader = AnnotationConfigContextLoader.class,
classes = { EnableIntegrationTests.ContextConfiguration.class,
EnableIntegrationTests.ContextConfiguration2.class })
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext
public class EnableIntegrationTests {
@Autowired
private ApplicationContext context;
@Autowired
private PollableChannel input;
@Autowired
private SmartLifecycleRoleController roleController;
@Autowired
@Qualifier("annotationTestService.handle.serviceActivator")
private PollingConsumer serviceActivatorEndpoint;
@Autowired
@Qualifier("annotationTestService.handle1.serviceActivator")
private PollingConsumer serviceActivatorEndpoint1;
@Autowired
@Qualifier("annotationTestService.handle2.serviceActivator")
private PollingConsumer serviceActivatorEndpoint2;
@Autowired
@Qualifier("annotationTestService.handle3.serviceActivator")
private PollingConsumer serviceActivatorEndpoint3;
@Autowired
@Qualifier("annotationTestService.handle4.serviceActivator")
private PollingConsumer serviceActivatorEndpoint4;
@Autowired
@Qualifier("annotationTestService.transform.transformer")
private PollingConsumer transformer;
@Autowired
@Qualifier("annotationTestService")
private Lifecycle annotationTestService;
@Autowired
private Trigger myTrigger;
@Autowired
private QueueChannel output;
@Autowired
private QueueChannel wireTapFromOutput;
@Autowired
private PollableChannel publishedChannel;
@Autowired
private PollableChannel wireTapChannel;
@Autowired
private MessageHistoryConfigurer configurer;
@Autowired
private TestGateway testGateway;
@Autowired
private CountDownLatch asyncAnnotationProcessLatch;
@Autowired
private AtomicReference<Thread> asyncAnnotationProcessThread;
@Autowired
private TestGateway2 testGateway2;
@Autowired
private TestChannelInterceptor testChannelInterceptor;
@Autowired
private AtomicInteger fbInterceptorCounter;
@Autowired
private MessageChannel numberChannel;
@Autowired
private TestConverter testConverter;
@Autowired
private MessageChannel bytesChannel;
@Autowired
private PollableChannel counterChannel;
@Autowired
private PollableChannel messageChannel;
@Autowired
private PollableChannel fooChannel;
@Autowired
private MessageChannel bridgeInput;
@Autowired
private PollableChannel bridgeOutput;
@Autowired
private MessageChannel pollableBridgeInput;
@Autowired
private PollableChannel pollableBridgeOutput;
@Autowired
private MessageChannel metaBridgeInput;
@Autowired
private PollableChannel metaBridgeOutput;
@Autowired
private MessageChannel bridgeToInput;
@Autowired
private PollableChannel bridgeToOutput;
@Autowired
private PollableChannel pollableBridgeToInput;
@Autowired
private MessageChannel myBridgeToInput;
@Autowired
private MessageChannel controlBusChannel;
@Autowired
private CountDownLatch inputReceiveLatch;
@Autowired
@Qualifier("enableIntegrationTests.ContextConfiguration2.sendAsyncHandler.serviceActivator")
private AbstractEndpoint sendAsyncHandler;
@Autowired
@Qualifier("enableIntegrationTests.ChildConfiguration.autoCreatedChannelMessageSource.inboundChannelAdapter")
private Lifecycle autoCreatedChannelMessageSourceAdapter;
@Test
public void testAnnotatedServiceActivator() throws Exception {
this.serviceActivatorEndpoint.setReceiveTimeout(10000);
this.serviceActivatorEndpoint.start();
assertTrue(this.inputReceiveLatch.await(10, TimeUnit.SECONDS));
assertEquals(10L, TestUtils.getPropertyValue(this.serviceActivatorEndpoint, "maxMessagesPerPoll"));
Trigger trigger = TestUtils.getPropertyValue(this.serviceActivatorEndpoint, "trigger", Trigger.class);
assertThat(trigger, Matchers.instanceOf(PeriodicTrigger.class));
assertEquals(100L, TestUtils.getPropertyValue(trigger, "period"));
assertFalse(TestUtils.getPropertyValue(trigger, "fixedRate", Boolean.class));
assertTrue(this.annotationTestService.isRunning());
Log logger = spy(TestUtils.getPropertyValue(this.serviceActivatorEndpoint, "logger", Log.class));
when(logger.isDebugEnabled()).thenReturn(true);
final CountDownLatch pollerInterruptedLatch = new CountDownLatch(1);
doAnswer(invocation -> {
pollerInterruptedLatch.countDown();
invocation.callRealMethod();
return null;
}).when(logger).debug("Received no Message during the poll, returning 'false'");
new DirectFieldAccessor(this.serviceActivatorEndpoint).setPropertyValue("logger", logger);
this.serviceActivatorEndpoint.stop();
assertFalse(this.annotationTestService.isRunning());
// wait until the service activator's poller is interrupted.
assertTrue(pollerInterruptedLatch.await(10, TimeUnit.SECONDS));
this.serviceActivatorEndpoint.start();
assertTrue(this.annotationTestService.isRunning());
trigger = TestUtils.getPropertyValue(this.serviceActivatorEndpoint1, "trigger", Trigger.class);
assertThat(trigger, Matchers.instanceOf(PeriodicTrigger.class));
assertEquals(100L, TestUtils.getPropertyValue(trigger, "period"));
assertTrue(TestUtils.getPropertyValue(trigger, "fixedRate", Boolean.class));
trigger = TestUtils.getPropertyValue(this.serviceActivatorEndpoint2, "trigger", Trigger.class);
assertThat(trigger, Matchers.instanceOf(CronTrigger.class));
assertEquals("0 5 7 * * *", TestUtils.getPropertyValue(trigger, "sequenceGenerator.expression"));
trigger = TestUtils.getPropertyValue(this.serviceActivatorEndpoint3, "trigger", Trigger.class);
assertThat(trigger, Matchers.instanceOf(PeriodicTrigger.class));
assertEquals(11L, TestUtils.getPropertyValue(trigger, "period"));
assertFalse(TestUtils.getPropertyValue(trigger, "fixedRate", Boolean.class));
trigger = TestUtils.getPropertyValue(this.serviceActivatorEndpoint4, "trigger", Trigger.class);
assertThat(trigger, Matchers.instanceOf(PeriodicTrigger.class));
assertEquals(1000L, TestUtils.getPropertyValue(trigger, "period"));
assertFalse(TestUtils.getPropertyValue(trigger, "fixedRate", Boolean.class));
assertSame(this.myTrigger, trigger);
trigger = TestUtils.getPropertyValue(this.transformer, "trigger", Trigger.class);
assertThat(trigger, Matchers.instanceOf(PeriodicTrigger.class));
assertEquals(10L, TestUtils.getPropertyValue(trigger, "period"));
assertFalse(TestUtils.getPropertyValue(trigger, "fixedRate", Boolean.class));
this.input.send(MessageBuilder.withPayload("Foo").build());
Message<?> interceptedMessage = this.wireTapChannel.receive(10000);
assertNotNull(interceptedMessage);
assertEquals("Foo", interceptedMessage.getPayload());
Message<?> receive = this.output.receive(10000);
assertNotNull(receive);
assertEquals("FOO", receive.getPayload());
receive = this.wireTapFromOutput.receive(10000);
assertNotNull(receive);
assertEquals("FOO", receive.getPayload());
MessageHistory messageHistory = receive.getHeaders().get(MessageHistory.HEADER_NAME, MessageHistory.class);
assertNotNull(messageHistory);
String messageHistoryString = messageHistory.toString();
assertThat(messageHistoryString, Matchers.containsString("input"));
assertThat(messageHistoryString,
Matchers.containsString("annotationTestService.handle.serviceActivator.handler"));
assertThat(messageHistoryString, Matchers.not(Matchers.containsString("output")));
receive = this.publishedChannel.receive(10000);
assertNotNull(receive);
assertEquals("foo", receive.getPayload());
messageHistory = receive.getHeaders().get(MessageHistory.HEADER_NAME, MessageHistory.class);
assertNotNull(messageHistory);
messageHistoryString = messageHistory.toString();
assertThat(messageHistoryString, Matchers.not(Matchers.containsString("input")));
assertThat(messageHistoryString, Matchers.not(Matchers.containsString("output")));
assertThat(messageHistoryString, Matchers.containsString("publishedChannel"));
assertNull(this.wireTapChannel.receive(0));
assertThat(this.testChannelInterceptor.getInvoked(), Matchers.greaterThan(0));
assertThat(this.fbInterceptorCounter.get(), Matchers.greaterThan(0));
assertTrue(this.context.containsBean("annotationTestService.count.inboundChannelAdapter.source"));
Object messageSource = this.context.getBean("annotationTestService.count.inboundChannelAdapter.source");
assertThat(messageSource, Matchers.instanceOf(MethodInvokingMessageSource.class));
assertNull(this.counterChannel.receive(10));
SmartLifecycle countSA = this.context.getBean("annotationTestService.count.inboundChannelAdapter",
SmartLifecycle.class);
assertFalse(countSA.isAutoStartup());
assertEquals(23, countSA.getPhase());
countSA.start();
for (int i = 0; i < 10; i++) {
Message<?> message = this.counterChannel.receive(1000);
assertNotNull(message);
assertEquals(i + 1, message.getPayload());
}
Message<?> message = this.fooChannel.receive(1000);
assertNotNull(message);
assertEquals("foo", message.getPayload());
message = this.fooChannel.receive(1000);
assertNotNull(message);
assertEquals("foo", message.getPayload());
assertNull(this.fooChannel.receive(10));
message = this.messageChannel.receive(1000);
assertNotNull(message);
assertEquals("bar", message.getPayload());
assertTrue(message.getHeaders().containsKey("foo"));
assertEquals("FOO", message.getHeaders().get("foo"));
MessagingTemplate messagingTemplate = new MessagingTemplate(this.controlBusChannel);
assertFalse(messagingTemplate.convertSendAndReceive("@lifecycle.isRunning()", Boolean.class));
this.controlBusChannel.send(new GenericMessage<String>("@lifecycle.start()"));
assertTrue(messagingTemplate.convertSendAndReceive("@lifecycle.isRunning()", Boolean.class));
this.controlBusChannel.send(new GenericMessage<String>("@lifecycle.stop()"));
assertFalse(messagingTemplate.convertSendAndReceive("@lifecycle.isRunning()", Boolean.class));
}
@Test
@DirtiesContext
public void testChangePatterns() {
try {
this.configurer.setComponentNamePatterns(new String[] { "*" });
fail("ExpectedException");
}
catch (IllegalStateException e) {
assertThat(e.getMessage(), containsString("cannot be changed"));
}
this.configurer.stop();
this.configurer.setComponentNamePatterns(new String[] { "*" });
assertEquals("*", TestUtils.getPropertyValue(this.configurer, "componentNamePatterns", String[].class)[0]);
}
@Test
public void testMessagingGateway() throws InterruptedException {
String payload = "bar";
String result = this.testGateway.echo(payload);
assertEquals(payload.toUpperCase(), result.substring(0, payload.length()));
assertThat(result, containsString("InvocableHandlerMethod"));
assertThat(result, not(containsString("SpelExpression")));
result = this.testGateway2.echo2(payload);
assertNotNull(result);
assertEquals(payload.toUpperCase() + "2", result.substring(0, payload.length() + 1));
assertThat(result, not(containsString("InvocableHandlerMethod")));
assertThat(result, containsString("SpelExpression"));
assertThat(result, containsString("CompoundExpression.getValueInternal"));
assertNotNull(this.testGateway2.echo2("baz"));
result = this.testGateway2.echo2("baz"); // third one should be compiled
assertNotNull(result);
assertEquals("BAZ2", result.substring(0, 4));
assertThat(result, not(containsString("InvocableHandlerMethod")));
assertThat(result, containsString("SpelExpression"));
assertThat(result, is(new RegexMatcher<String>(".+Ex\\d.getValue\\(.+")));
this.testGateway.sendAsync("foo");
assertTrue(this.asyncAnnotationProcessLatch.await(1, TimeUnit.SECONDS));
assertNotSame(Thread.currentThread(), this.asyncAnnotationProcessThread.get());
}
@Test
public void testParentChildAnnotationConfiguration() {
AnnotationConfigApplicationContext child = new AnnotationConfigApplicationContext();
child.register(ChildConfiguration.class);
child.setParent(this.context);
child.refresh();
AbstractMessageChannel foo = child.getBean("foo", AbstractMessageChannel.class);
ChannelInterceptor baz = child.getBean("baz", ChannelInterceptor.class);
assertTrue(foo.getChannelInterceptors().contains(baz));
assertFalse(this.output.getChannelInterceptors().contains(baz));
child.close();
}
@Test
public void testParentChildAnnotationConfigurationFromAnotherPackage() {
AnnotationConfigApplicationContext child = new AnnotationConfigApplicationContext();
child.register(org.springframework.integration.configuration2.ChildConfiguration.class);
child.setParent(this.context);
child.refresh();
AbstractMessageChannel foo = child.getBean("foo", AbstractMessageChannel.class);
ChannelInterceptor baz = child.getBean("baz", ChannelInterceptor.class);
assertTrue(foo.getChannelInterceptors().contains(baz));
assertFalse(this.output.getChannelInterceptors().contains(baz));
child.close();
}
@Test
public void testIntegrationConverter() {
this.numberChannel.send(new GenericMessage<Integer>(10));
this.numberChannel.send(new GenericMessage<Boolean>(true));
assertThat(this.testConverter.getInvoked(), Matchers.greaterThan(0));
assertTrue(this.bytesChannel.send(new GenericMessage<byte[]>("foo".getBytes())));
assertTrue(this.bytesChannel.send(new GenericMessage<>(MutableMessageBuilder.withPayload("").build())));
}
@Test
public void testMetaAnnotations() {
assertEquals(2, this.context.getBeanNamesForType(GatewayProxyFactoryBean.class).length);
PollingConsumer consumer = this.context.getBean("annotationTestService.annCount.serviceActivator",
PollingConsumer.class);
assertFalse(TestUtils.getPropertyValue(consumer, "autoStartup", Boolean.class));
assertEquals(23, TestUtils.getPropertyValue(consumer, "phase"));
assertSame(context.getBean("annInput"), TestUtils.getPropertyValue(consumer, "inputChannel"));
assertEquals("annOutput", TestUtils.getPropertyValue(consumer, "handler.outputChannelName"));
assertSame(context.getBean("annAdvice"), TestUtils.getPropertyValue(consumer,
"handler.adviceChain", List.class).get(0));
assertEquals(1000L, TestUtils.getPropertyValue(consumer, "trigger.period"));
consumer = this.context.getBean("annotationTestService.annCount1.serviceActivator",
PollingConsumer.class);
consumer.stop();
assertTrue(TestUtils.getPropertyValue(consumer, "autoStartup", Boolean.class));
assertEquals(23, TestUtils.getPropertyValue(consumer, "phase"));
assertSame(context.getBean("annInput1"), TestUtils.getPropertyValue(consumer, "inputChannel"));
assertEquals("annOutput", TestUtils.getPropertyValue(consumer, "handler.outputChannelName"));
assertSame(context.getBean("annAdvice1"), TestUtils.getPropertyValue(consumer,
"handler.adviceChain", List.class).get(0));
assertEquals(2000L, TestUtils.getPropertyValue(consumer, "trigger.period"));
consumer = this.context.getBean("annotationTestService.annCount2.serviceActivator",
PollingConsumer.class);
assertFalse(TestUtils.getPropertyValue(consumer, "autoStartup", Boolean.class));
assertEquals(23, TestUtils.getPropertyValue(consumer, "phase"));
assertSame(context.getBean("annInput"), TestUtils.getPropertyValue(consumer, "inputChannel"));
assertEquals("annOutput", TestUtils.getPropertyValue(consumer, "handler.outputChannelName"));
assertSame(context.getBean("annAdvice"), TestUtils.getPropertyValue(consumer,
"handler.adviceChain", List.class).get(0));
assertEquals(1000L, TestUtils.getPropertyValue(consumer, "trigger.period"));
// Tests when the channel is in a "middle" annotation
consumer = this.context.getBean("annotationTestService.annCount5.serviceActivator", PollingConsumer.class);
assertFalse(TestUtils.getPropertyValue(consumer, "autoStartup", Boolean.class));
assertEquals(23, TestUtils.getPropertyValue(consumer, "phase"));
assertSame(context.getBean("annInput3"), TestUtils.getPropertyValue(consumer, "inputChannel"));
assertEquals("annOutput", TestUtils.getPropertyValue(consumer, "handler.outputChannelName"));
assertSame(context.getBean("annAdvice"), TestUtils.getPropertyValue(consumer,
"handler.adviceChain", List.class).get(0));
assertEquals(1000L, TestUtils.getPropertyValue(consumer, "trigger.period"));
consumer = this.context.getBean("annotationTestService.annAgg1.aggregator", PollingConsumer.class);
assertFalse(TestUtils.getPropertyValue(consumer, "autoStartup", Boolean.class));
assertEquals(23, TestUtils.getPropertyValue(consumer, "phase"));
assertSame(context.getBean("annInput"), TestUtils.getPropertyValue(consumer, "inputChannel"));
assertEquals("annOutput", TestUtils.getPropertyValue(consumer, "handler.outputChannelName"));
assertEquals("annOutput", TestUtils.getPropertyValue(consumer, "handler.discardChannelName"));
assertEquals(1000L, TestUtils.getPropertyValue(consumer, "trigger.period"));
assertEquals(-1L, TestUtils.getPropertyValue(consumer, "handler.messagingTemplate.sendTimeout"));
assertFalse(TestUtils.getPropertyValue(consumer, "handler.sendPartialResultOnExpiry", Boolean.class));
consumer = this.context.getBean("annotationTestService.annAgg2.aggregator", PollingConsumer.class);
assertFalse(TestUtils.getPropertyValue(consumer, "autoStartup", Boolean.class));
assertEquals(23, TestUtils.getPropertyValue(consumer, "phase"));
assertSame(context.getBean("annInput"), TestUtils.getPropertyValue(consumer, "inputChannel"));
assertEquals("annOutput", TestUtils.getPropertyValue(consumer, "handler.outputChannelName"));
assertEquals("annOutput", TestUtils.getPropertyValue(consumer, "handler.discardChannelName"));
assertEquals(1000L, TestUtils.getPropertyValue(consumer, "trigger.period"));
assertEquals(75L, TestUtils.getPropertyValue(consumer, "handler.messagingTemplate.sendTimeout"));
assertTrue(TestUtils.getPropertyValue(consumer, "handler.sendPartialResultOnExpiry", Boolean.class));
}
@Test
public void testBridgeAnnotations() {
GenericMessage<?> testMessage = new GenericMessage<Object>("foo");
this.bridgeInput.send(testMessage);
Message<?> receive = this.bridgeOutput.receive(2000);
assertNotNull(receive);
assertSame(receive, testMessage);
assertNull(this.bridgeOutput.receive(10));
this.pollableBridgeInput.send(testMessage);
receive = this.pollableBridgeOutput.receive(2000);
assertNotNull(receive);
assertSame(receive, testMessage);
assertNull(this.pollableBridgeOutput.receive(10));
try {
this.metaBridgeInput.send(testMessage);
fail("MessageDeliveryException expected");
}
catch (Exception e) {
assertThat(e, Matchers.instanceOf(MessageDeliveryException.class));
assertThat(e.getMessage(), Matchers.containsString("Dispatcher has no subscribers"));
}
this.context.getBean("enableIntegrationTests.ContextConfiguration.metaBridgeOutput.bridgeFrom",
Lifecycle.class).start();
this.metaBridgeInput.send(testMessage);
receive = this.metaBridgeOutput.receive(2000);
assertNotNull(receive);
assertSame(receive, testMessage);
assertNull(this.metaBridgeOutput.receive(10));
this.bridgeToInput.send(testMessage);
receive = this.bridgeToOutput.receive(2000);
assertNotNull(receive);
assertSame(receive, testMessage);
assertNull(this.bridgeToOutput.receive(10));
PollableChannel replyChannel = new QueueChannel();
Message<?> bridgeMessage = MessageBuilder.fromMessage(testMessage).setReplyChannel(replyChannel).build();
this.pollableBridgeToInput.send(bridgeMessage);
receive = replyChannel.receive(2000);
assertNotNull(receive);
assertSame(receive, bridgeMessage);
assertNull(replyChannel.receive(10));
try {
this.myBridgeToInput.send(testMessage);
fail("MessageDeliveryException expected");
}
catch (Exception e) {
assertThat(e, Matchers.instanceOf(MessageDeliveryException.class));
assertThat(e.getMessage(), Matchers.containsString("Dispatcher has no subscribers"));
}
this.context.getBean("enableIntegrationTests.ContextConfiguration.myBridgeToInput.bridgeTo",
Lifecycle.class).start();
this.myBridgeToInput.send(bridgeMessage);
receive = replyChannel.receive(2000);
assertNotNull(receive);
assertSame(receive, bridgeMessage);
assertNull(replyChannel.receive(10));
}
@Test
public void testMonoGateway() throws Exception {
final AtomicReference<List<Integer>> ref = new AtomicReference<List<Integer>>();
final CountDownLatch consumeLatch = new CountDownLatch(1);
Flux.just("1", "2", "3", "4", "5")
.map(Integer::parseInt)
.flatMap(this.testGateway::multiply)
.collectList()
.subscribe(integers -> {
ref.set(integers);
consumeLatch.countDown();
});
assertTrue(consumeLatch.await(0, TimeUnit.SECONDS)); // runs on same thread
List<Integer> integers = ref.get();
assertEquals(5, integers.size());
assertThat(integers, Matchers.<Integer>contains(2, 4, 6, 8, 10));
}
@Test
@DirtiesContext
public void testRoles() {
assertThat(this.roleController.getRoles(), containsInAnyOrder("foo", "bar"));
assertFalse(this.roleController.allEndpointsRunning("foo"));
assertFalse(this.roleController.noEndpointsRunning("foo"));
assertTrue(this.roleController.allEndpointsRunning("bar"));
assertFalse(this.roleController.noEndpointsRunning("bar"));
Map<String, Boolean> state = this.roleController.getEndpointsRunningStatus("foo");
assertThat(state.get("annotationTestService.handle.serviceActivator"), equalTo(Boolean.FALSE));
assertThat(state.get("enableIntegrationTests.ContextConfiguration2.sendAsyncHandler.serviceActivator"),
equalTo(Boolean.TRUE));
this.roleController.startLifecyclesInRole("foo");
assertTrue(this.roleController.allEndpointsRunning("foo"));
this.roleController.stopLifecyclesInRole("foo");
assertFalse(this.roleController.allEndpointsRunning("foo"));
assertTrue(this.roleController.noEndpointsRunning("foo"));
@SuppressWarnings("unchecked")
MultiValueMap<String, SmartLifecycle> lifecycles = TestUtils.getPropertyValue(this.roleController,
"lifecycles", MultiValueMap.class);
assertEquals(2, lifecycles.size());
assertEquals(2, lifecycles.get("foo").size());
assertEquals(1, lifecycles.get("bar").size());
assertFalse(this.serviceActivatorEndpoint.isRunning());
assertFalse(this.sendAsyncHandler.isRunning());
assertEquals(2, lifecycles.size());
assertEquals(2, lifecycles.get("foo").size());
}
@Test
public void testSourcePollingChannelAdapterOutputChannelLateBinding() {
QueueChannel testChannel = new QueueChannel();
ConfigurableListableBeanFactory beanFactory =
(ConfigurableListableBeanFactory) this.context.getAutowireCapableBeanFactory();
beanFactory.registerSingleton("lateBindingChannel", testChannel);
beanFactory.initializeBean(testChannel, "lateBindingChannel");
this.autoCreatedChannelMessageSourceAdapter.start();
Message<?> receive = testChannel.receive(10000);
assertNotNull(receive);
assertEquals("bar", receive.getPayload());
this.autoCreatedChannelMessageSourceAdapter.stop();
}
@Test
public void testIntegrationEvaluationContextCustomization() {
EvaluationContext evaluationContext = this.context.getBean(EvaluationContext.class);
List<?> propertyAccessors = TestUtils.getPropertyValue(evaluationContext, "propertyAccessors", List.class);
assertThat(propertyAccessors.get(0), instanceOf(JsonPropertyAccessor.class));
Map<?, ?> variables = TestUtils.getPropertyValue(evaluationContext, "variables", Map.class);
Object testSpelFunction = variables.get("testSpelFunction");
assertEquals(ClassUtils.getStaticMethod(TestSpelFunction.class, "bar", Object.class), testSpelFunction);
}
@Configuration
@ComponentScan
@IntegrationComponentScan
@EnableIntegration
// INT-3853 @PropertySource("classpath:org/springframework/integration/configuration/EnableIntegrationTests.properties")
@EnableMessageHistory({ "input", "publishedChannel", "annotationTestService*" })
public static class ContextConfiguration {
@Bean
public CountDownLatch inputReceiveLatch() {
return new CountDownLatch(1);
}
@Bean
public QueueChannel input() {
return new QueueChannel() {
@Override
protected Message<?> doReceive(long timeout) {
inputReceiveLatch().countDown();
return super.doReceive(timeout);
}
};
}
@Bean
public QueueChannel input1() {
return new QueueChannel();
}
@Bean
public QueueChannel input2() {
return new QueueChannel();
}
@Bean
public QueueChannel input3() {
return new QueueChannel();
}
@Bean
public QueueChannel input4() {
return new QueueChannel();
}
@Bean
public Trigger myTrigger() {
return new PeriodicTrigger(1000L);
}
@Bean
public Trigger onlyOnceTrigger() {
return new OnlyOnceTrigger();
}
@Bean
public WireTap wireTapFromOutputInterceptor() {
return new WireTap("wireTapFromOutput");
}
@Bean
public PollableChannel output() {
QueueChannel queueChannel = new QueueChannel();
queueChannel.addInterceptor(wireTapFromOutputInterceptor());
return queueChannel;
}
@Bean
public PollableChannel wireTapFromOutput() {
return new QueueChannel();
}
@Bean
public PollableChannel wireTapChannel() {
return new QueueChannel();
}
@Bean
@GlobalChannelInterceptor(patterns = "${global.wireTap.pattern}")
public WireTap wireTap() {
return new WireTap(this.wireTapChannel());
}
@Bean
public AtomicInteger fbInterceptorCounter() {
return new AtomicInteger();
}
@Bean
@GlobalChannelInterceptor
public FactoryBean<ChannelInterceptor> ciFactoryBean() {
return new AbstractFactoryBean<ChannelInterceptor>() {
@Override
public Class<?> getObjectType() {
return ChannelInterceptor.class;
}
@Override
protected ChannelInterceptor createInstance() throws Exception {
return new ChannelInterceptorAdapter() {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
fbInterceptorCounter().incrementAndGet();
return super.preSend(message, channel);
}
};
}
};
}
@Bean
@BridgeFrom("bridgeInput")
public QueueChannel bridgeOutput() {
return new QueueChannel();
}
@Bean
public PollableChannel pollableBridgeInput() {
return new QueueChannel();
}
@Bean
@BridgeFrom(value = "pollableBridgeInput", poller = @Poller(fixedDelay = "1000"))
public QueueChannel pollableBridgeOutput() {
return new QueueChannel();
}
@Bean
@MyBridgeFrom
public QueueChannel metaBridgeOutput() {
return new QueueChannel();
}
@Bean
public QueueChannel bridgeToOutput() {
return new QueueChannel();
}
@Bean
@BridgeTo("bridgeToOutput")
public MessageChannel bridgeToInput() {
return new DirectChannel();
}
@Bean
@BridgeTo(poller = @Poller(fixedDelay = "500"))
public QueueChannel pollableBridgeToInput() {
return new QueueChannel();
}
@Bean
@MyBridgeTo
public MessageChannel myBridgeToInput() {
return new DirectChannel();
}
// Error because @Bridge* annotations are only for MessageChannel beans.
/*@Bean
@BridgeTo
public String invalidBridgeAnnotation() {
return "invalidBridgeAnnotation";
}*/
// Error because @Bridge* annotations are mutually exclusive.
/*@Bean
@BridgeTo
@BridgeFrom("foo")
public MessageChannel invalidBridgeAnnotation2() {
return new DirectChannel();
}*/
// beans for metaAnnotation tests
@Bean
public MethodInterceptor annAdvice() {
return mock(MethodInterceptor.class);
}
@Bean
public QueueChannel annInput() {
return new QueueChannel();
}
@Bean
public QueueChannel annOutput() {
return new QueueChannel();
}
@Bean
public MethodInterceptor annAdvice1() {
return mock(MethodInterceptor.class);
}
@Bean
public QueueChannel annInput1() {
return new QueueChannel();
}
@Bean
public QueueChannel annInput3() {
return new QueueChannel();
}
}
@Component
@GlobalChannelInterceptor
public static class TestChannelInterceptor extends ChannelInterceptorAdapter {
private final AtomicInteger invoked = new AtomicInteger();
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
this.invoked.incrementAndGet();
return message;
}
public Integer getInvoked() {
return invoked.get();
}
}
@Component
@IntegrationConverter
public static class TestConverter implements Converter<Boolean, Number> {
private final AtomicInteger invoked = new AtomicInteger();
@Override
public Number convert(Boolean source) {
this.invoked.incrementAndGet();
return source ? 1 : 0;
}
public Integer getInvoked() {
return invoked.get();
}
}
@Configuration
@EnableIntegration
@ImportResource("classpath:org/springframework/integration/configuration/EnableIntegrationTests-context.xml")
@EnableMessageHistory("${message.history.tracked.components}")
@EnablePublisher("publishedChannel")
@EnableAsync
public static class ContextConfiguration2 {
/*
INT-3853
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}*/
@Bean
public MessageChannel sendAsyncChannel() {
return new DirectChannel();
}
@Bean
public CountDownLatch asyncAnnotationProcessLatch() {
return new CountDownLatch(1);
}
@Bean
public AtomicReference<Thread> asyncAnnotationProcessThread() {
return new AtomicReference<Thread>();
}
@Bean
@ServiceActivator(inputChannel = "sendAsyncChannel")
@Role("foo")
public MessageHandler sendAsyncHandler() {
return new MessageHandler() {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
asyncAnnotationProcessLatch().countDown();
asyncAnnotationProcessThread().set(Thread.currentThread());
}
};
}
@Bean
@ServiceActivator(inputChannel = "controlBusChannel")
@Role("bar")
public ExpressionControlBusFactoryBean controlBus() {
return new ExpressionControlBusFactoryBean();
}
@Bean
public Lifecycle lifecycle() {
return new Lifecycle() {
private volatile boolean running;
@Override
public void start() {
this.running = true;
}
@Override
public void stop() {
this.running = false;
}
@Override
public boolean isRunning() {
return this.running;
}
};
}
@Bean
public PollableChannel publishedChannel() {
return new QueueChannel();
}
@Bean
public PollableChannel gatewayChannel() {
return new QueueChannel();
}
@Bean
public PollableChannel gatewayChannel2() {
return new QueueChannel();
}
@Bean
public PollableChannel counterChannel() {
return new QueueChannel();
}
@Bean
public PollableChannel fooChannel() {
return new QueueChannel();
}
@Bean
public PollableChannel messageChannel() {
return new QueueChannel();
}
@Bean
public QueueChannel numberChannel() {
QueueChannel channel = new QueueChannel();
channel.setDatatypes(Number.class);
return channel;
}
@Bean
public QueueChannel bytesChannel() {
QueueChannel channel = new QueueChannel();
channel.setDatatypes(byte[].class);
return channel;
}
@Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata defaultPoller() {
PollerMetadata pollerMetadata = new PollerMetadata();
pollerMetadata.setTrigger(new PeriodicTrigger(10));
return pollerMetadata;
}
@Bean
public PollerMetadata myPoller() {
PollerMetadata pollerMetadata = new PollerMetadata();
pollerMetadata.setTrigger(new PeriodicTrigger(11));
return pollerMetadata;
}
@Bean
@IntegrationConverter
public SerializingConverter serializingConverter() {
return new SerializingConverter();
}
@Bean
public DirectChannel monoChannel() {
return new DirectChannel();
}
@Bean
public AnnotationTestService annotationTestService() {
return new AnnotationTestServiceImpl();
}
@Bean
public SpelFunctionFactoryBean testSpelFunction() {
return new SpelFunctionFactoryBean(TestSpelFunction.class, "bar");
}
@Bean
public SpelPropertyAccessorRegistrar spelPropertyAccessorRegistrar() {
return new SpelPropertyAccessorRegistrar(new JsonPropertyAccessor());
}
}
@Configuration
@EnableIntegration
public static class ChildConfiguration {
@Bean
public MessageChannel foo() {
return new DirectChannel();
}
@Bean
@GlobalChannelInterceptor(patterns = "*")
public WireTap baz() {
return new WireTap(new NullChannel());
}
//Before INT-3961 it fails with the DestinationResolutionException
@InboundChannelAdapter(channel = "lateBindingChannel", autoStartup = "false",
poller = @Poller(fixedDelay = "100"))
@Bean
public MessageSource<String> autoCreatedChannelMessageSource() {
return () -> new GenericMessage<>("bar");
}
}
public interface AnnotationTestService {
String handle(String payload);
String handle1(String payload);
String handle2(String payload);
String handle3(String payload);
String handle4(String payload);
String transform(Message<String> message);
String transform2(Message<String> message);
Integer count();
String foo();
Message<?> message();
Integer annCount();
Integer annCount1();
Integer annCount2();
Integer annCount5();
Integer annCount8();
Integer annAgg1(List<?> messages);
Integer annAgg2(List<?> messages);
Integer multiply(Integer value);
}
public static class AnnotationTestServiceImpl implements Lifecycle, AnnotationTestService {
private final AtomicInteger counter = new AtomicInteger();
private boolean running;
@Override
@ServiceActivator(inputChannel = "input", outputChannel = "output", autoStartup = "false",
poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", fixedDelay = "${poller.interval}"))
@Publisher
@Payload("#args[0].toLowerCase()")
@Role("foo")
public String handle(String payload) {
return payload.toUpperCase();
}
@Override
@ServiceActivator(inputChannel = "input1", outputChannel = "output",
poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", fixedRate = "${poller.interval}"))
@Publisher
@Payload("#args[0].toLowerCase()")
public String handle1(String payload) {
return payload.toUpperCase();
}
@Override
@ServiceActivator(inputChannel = "input2", outputChannel = "output",
poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", cron = "0 5 7 * * *"))
@Publisher
@Payload("#args[0].toLowerCase()")
public String handle2(String payload) {
return payload.toUpperCase();
}
@Override
@ServiceActivator(inputChannel = "input3", outputChannel = "output", poller = @Poller("myPoller"))
@Publisher
@Payload("#args[0].toLowerCase()")
public String handle3(String payload) {
return payload.toUpperCase();
}
@Override
@ServiceActivator(inputChannel = "input4", outputChannel = "output",
poller = @Poller(trigger = "myTrigger"))
@Publisher
@Payload("#args[0].toLowerCase()")
public String handle4(String payload) {
return payload.toUpperCase();
}
/*
* This is an error because input5 is not defined and is therefore a DirectChannel.
*/
/*@ServiceActivator(inputChannel = "input5", outputChannel = "output", poller = @Poller("defaultPollerMetadata"))
@Publisher
@Payload("#args[0].toLowerCase()")
public String handle5(String payload) {
return payload.toUpperCase();
}*/
@Override
@Transformer(inputChannel = "gatewayChannel")
public String transform(Message<String> message) {
assertTrue(message.getHeaders().containsKey("foo"));
assertEquals("FOO", message.getHeaders().get("foo"));
assertTrue(message.getHeaders().containsKey("calledMethod"));
assertEquals("echo", message.getHeaders().get("calledMethod"));
return this.handle(message.getPayload()) + Arrays.asList(new Throwable().getStackTrace()).toString();
}
@Override
@Transformer(inputChannel = "gatewayChannel2")
@UseSpelInvoker(compilerMode = "${xxxxxxxx:IMMEDIATE}")
public String transform2(Message<String> message) {
assertTrue(message.getHeaders().containsKey("foo"));
assertEquals("FOO", message.getHeaders().get("foo"));
assertTrue(message.getHeaders().containsKey("calledMethod"));
assertEquals("echo2", message.getHeaders().get("calledMethod"));
return this.handle(message.getPayload()) + "2" + Arrays.asList(new Throwable().getStackTrace()).toString();
}
@Override
@MyInboundChannelAdapter1
public Integer count() {
return this.counter.incrementAndGet();
}
@Override
@InboundChannelAdapter(value = "fooChannel",
poller = @Poller(trigger = "onlyOnceTrigger", maxMessagesPerPoll = "2"))
public String foo() {
return "foo";
}
@Override
@InboundChannelAdapter(value = "messageChannel", poller = @Poller(fixedDelay = "${poller.interval}",
maxMessagesPerPoll = "1"))
public Message<?> message() {
return MessageBuilder.withPayload("bar").setHeader("foo", "FOO").build();
}
/*
* This is an error because 'InboundChannelAdapter' method must not have any arguments.
*/
/*@InboundChannelAdapter("errorChannel")
public String error1(Object arg) {
return "foo";
}*/
/*
* This is an error because 'InboundChannelAdapter' return type must not be 'void'.
*/
/*@InboundChannelAdapter("errorChannel")
public void error2() {
}*/
// metaAnnotation tests
@Override
@MyServiceActivator
public Integer annCount() {
return 0;
}
@Override
@MyServiceActivator1(inputChannel = "annInput1", autoStartup = "true",
adviceChain = { "annAdvice1" }, poller = @Poller(fixedRate = "2000"))
public Integer annCount1() {
return 0;
}
@Override
@MyServiceActivatorNoLocalAtts
public Integer annCount2() {
return 0;
}
@Override
@MyServiceActivator5
public Integer annCount5() {
return 0;
}
@Override
@MyServiceActivator8
public Integer annCount8() {
return 0;
}
@Override
@MyAggregator
public Integer annAgg1(List<?> messages) {
return 42;
}
@Override
@MyAggregatorDefaultOverrideDefaults
public Integer annAgg2(List<?> messages) {
return 42;
}
// Error because @Bridge* annotations are only for @Bean methods.
/*@BridgeFrom("")
public void invalidBridgeAnnotationMethod(Object payload) {}*/
@Override
@ServiceActivator(inputChannel = "monoChannel")
public Integer multiply(Integer value) {
return value * 2;
}
@Override
public void start() {
this.running = true;
}
@Override
public void stop() {
this.running = false;
}
@Override
public boolean isRunning() {
return this.running;
}
}
@TestMessagingGateway
public interface TestGateway {
@Gateway(headers = @GatewayHeader(name = "calledMethod", expression = "#gatewayMethod.name"))
String echo(String payload);
@Gateway(requestChannel = "sendAsyncChannel")
@Async
void sendAsync(String payload);
@Gateway(requestChannel = "monoChannel")
Mono<Integer> multiply(Integer value);
}
@TestMessagingGateway2
public interface TestGateway2 {
@Gateway(headers = @GatewayHeader(name = "calledMethod", expression = "#gatewayMethod.name"))
String echo2(String payload);
}
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@MessagingGateway(defaultRequestChannel = "gatewayChannel",
defaultRequestTimeout = "${default.request.timeout:12300}", defaultReplyTimeout = "#{13400}",
defaultHeaders = @GatewayHeader(name = "foo", value = "FOO"))
public @interface TestMessagingGateway {
String defaultRequestChannel() default "";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@TestMessagingGateway(defaultRequestChannel = "gatewayChannel2")
public @interface TestMessagingGateway2 {
String defaultRequestChannel() default "";
}
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@ServiceActivator(autoStartup = "false",
phase = "23",
inputChannel = "annInput",
outputChannel = "annOutput",
adviceChain = { "annAdvice" },
poller = @Poller(fixedDelay = "1000"))
public @interface MyServiceActivator {
String inputChannel() default "";
String outputChannel() default "";
String[] adviceChain() default { };
String autoStartup() default "";
String phase() default "";
Poller[] poller() default { };
}
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@MyServiceActivator
public @interface MyServiceActivator1 {
String inputChannel() default "";
String outputChannel() default "";
String[] adviceChain() default { };
String autoStartup() default "";
String phase() default "";
Poller[] poller() default { };
}
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@MyServiceActivator1
public @interface MyServiceActivator2 {
String inputChannel() default "";
}
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@MyServiceActivator2
public @interface MyServiceActivator3 {
String inputChannel() default "";
}
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@MyServiceActivator3(inputChannel = "annInput3")
public @interface MyServiceActivator4 {
String inputChannel() default "";
}
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@MyServiceActivator4
public @interface MyServiceActivator5 {
String inputChannel() default "";
}
// Test prevent infinite recursion
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@MyServiceActivator5
public @interface MyServiceActivator6 {
String inputChannel() default "";
}
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@MyServiceActivator8
public @interface MyServiceActivator7 {
String inputChannel() default "";
}
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@MyServiceActivator7
public @interface MyServiceActivator8 {
String inputChannel() default "";
}
// end test infinite recursion
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@ServiceActivator(autoStartup = "false",
phase = "23",
inputChannel = "annInput",
outputChannel = "annOutput",
adviceChain = { "annAdvice" },
poller = @Poller(fixedDelay = "1000"))
public @interface MyServiceActivatorNoLocalAtts {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Aggregator(autoStartup = "false",
phase = "23",
inputChannel = "annInput",
outputChannel = "annOutput",
discardChannel = "annOutput",
poller = @Poller(fixedDelay = "1000"))
public @interface MyAggregator {
String inputChannel() default "";
String outputChannel() default "";
String discardChannel() default "";
long sendTimeout() default 1000L;
boolean sendPartialResultsOnExpiry() default false;
String autoStartup() default "";
String phase() default "";
Poller[] poller() default { };
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Aggregator(autoStartup = "false",
phase = "23",
inputChannel = "annInput",
outputChannel = "annOutput",
discardChannel = "annOutput",
sendPartialResultsOnExpiry = "false",
sendTimeout = "1000",
poller = @Poller(fixedDelay = "1000"))
public @interface MyAggregatorDefaultOverrideDefaults {
String sendPartialResultsOnExpiry() default "true";
String sendTimeout() default "75";
}
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@InboundChannelAdapter(value = "counterChannel", autoStartup = "false", phase = "23")
public @interface MyInboundChannelAdapter {
String value() default "";
String autoStartup() default "";
String phase() default "";
Poller[] poller() default { };
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@MyInboundChannelAdapter
public @interface MyInboundChannelAdapter1 {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@BridgeFrom(value = "metaBridgeInput", autoStartup = "false")
public @interface MyBridgeFrom {
String value() default "";
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@BridgeTo(autoStartup = "false")
public @interface MyBridgeTo {
}
// Error because the annotation is on a class; it must be on an interface
// @MessagingGateway(defaultRequestChannel = "gatewayChannel", defaultHeaders = @GatewayHeader(name = "foo", value = "FOO"))
// public static class TestGateway2 { }
public static class TestSpelFunction {
public static Object bar(Object o) {
return o;
}
}
public class RegexMatcher<T> extends BaseMatcher<T> {
private final String regex;
public RegexMatcher(String regex) {
this.regex = regex;
}
@Override
public boolean matches(Object o) {
return ((String) o).matches(regex);
}
@Override
public void describeTo(Description description) {
description.appendText("matches regex=");
}
}
}