/*
* Copyright 2002-2016 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 static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.annotation.MessageEndpoint;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.annotation.Transformer;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.support.channel.BeanFactoryChannelResolver;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.integration.test.util.TestUtils.TestApplicationContext;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.core.DestinationResolver;
import org.springframework.messaging.support.GenericMessage;
/**
* @author Mark Fisher
* @author Gary Russell
* @author Artem Bilan
*/
public class MessagingAnnotationPostProcessorTests {
@Test
public void serviceActivatorAnnotation() {
TestApplicationContext context = TestUtils.createTestApplicationContext();
DirectChannel inputChannel = new DirectChannel();
context.registerChannel("inputChannel", inputChannel);
context.refresh();
MessagingAnnotationPostProcessor postProcessor = new MessagingAnnotationPostProcessor();
postProcessor.setBeanFactory(context.getBeanFactory());
postProcessor.afterPropertiesSet();
ServiceActivatorAnnotatedBean bean = new ServiceActivatorAnnotatedBean();
postProcessor.postProcessAfterInitialization(bean, "testBean");
assertTrue(context.containsBean("testBean.test.serviceActivator"));
Object endpoint = context.getBean("testBean.test.serviceActivator");
assertTrue(endpoint instanceof AbstractEndpoint);
}
@Test
public void serviceActivatorInApplicationContext() throws Exception {
AbstractApplicationContext context = new ClassPathXmlApplicationContext(
"serviceActivatorAnnotationPostProcessorTests.xml", this.getClass());
MessageChannel inputChannel = (MessageChannel) context.getBean("inputChannel");
PollableChannel outputChannel = (PollableChannel) context.getBean("outputChannel");
inputChannel.send(new GenericMessage<String>("world"));
Message<?> reply = outputChannel.receive(0);
assertEquals("hello world", reply.getPayload());
context.close();
}
@Test
public void testSimpleHandler() throws InterruptedException {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("simpleAnnotatedEndpointTests.xml", this.getClass());
context.start();
MessageChannel inputChannel = (MessageChannel) context.getBean("inputChannel");
PollableChannel outputChannel = (PollableChannel) context.getBean("outputChannel");
GenericMessage<String> messageToSend = new GenericMessage<String>("world");
inputChannel.send(messageToSend);
Message<?> message = outputChannel.receive(1000);
assertEquals("hello world", message.getPayload());
inputChannel = context.getBean("advisedIn", MessageChannel.class);
outputChannel = context.getBean("advisedOut", PollableChannel.class);
inputChannel.send(messageToSend);
message = outputChannel.receive(1000);
assertEquals("hello world advised", message.getPayload());
context.close();
}
@Test
public void messageAsMethodParameter() throws InterruptedException {
AbstractApplicationContext context = new ClassPathXmlApplicationContext(
"messageParameterAnnotatedEndpointTests.xml", this.getClass());
context.start();
MessageChannel inputChannel = (MessageChannel) context.getBean("inputChannel");
PollableChannel outputChannel = (PollableChannel) context.getBean("outputChannel");
inputChannel.send(new GenericMessage<String>("world"));
Message<?> message = outputChannel.receive(1000);
assertEquals("hello world", message.getPayload());
context.close();
}
@Test
public void typeConvertingHandler() throws InterruptedException {
AbstractApplicationContext context = new ClassPathXmlApplicationContext(
"typeConvertingEndpointTests.xml", this.getClass());
context.start();
MessageChannel inputChannel = (MessageChannel) context.getBean("inputChannel");
PollableChannel outputChannel = (PollableChannel) context.getBean("outputChannel");
inputChannel.send(new GenericMessage<String>("123"));
Message<?> message = outputChannel.receive(1000);
assertEquals(246, message.getPayload());
context.close();
}
@Test
public void outboundOnlyServiceActivator() throws InterruptedException {
TestApplicationContext context = TestUtils.createTestApplicationContext();
context.registerChannel("testChannel", new DirectChannel());
MessagingAnnotationPostProcessor postProcessor = new MessagingAnnotationPostProcessor();
postProcessor.setBeanFactory(context.getBeanFactory());
postProcessor.afterPropertiesSet();
CountDownLatch latch = new CountDownLatch(1);
OutboundOnlyTestBean testBean = new OutboundOnlyTestBean(latch);
postProcessor.postProcessAfterInitialization(testBean, "testBean");
context.refresh();
DestinationResolver<MessageChannel> channelResolver = new BeanFactoryChannelResolver(context);
MessageChannel testChannel = channelResolver.resolveDestination("testChannel");
testChannel.send(new GenericMessage<String>("foo"));
latch.await(1000, TimeUnit.MILLISECONDS);
assertEquals(0, latch.getCount());
assertEquals("foo", testBean.getMessageText());
context.stop();
}
@Test(expected = IllegalArgumentException.class)
public void testPostProcessorWithoutBeanFactory() {
MessagingAnnotationPostProcessor postProcessor =
new MessagingAnnotationPostProcessor();
postProcessor.afterPropertiesSet();
}
@Test
public void testChannelResolution() {
TestApplicationContext context = TestUtils.createTestApplicationContext();
DirectChannel inputChannel = new DirectChannel();
QueueChannel outputChannel = new QueueChannel();
DirectChannel eventBus = new DirectChannel();
context.registerChannel("inputChannel", inputChannel);
context.registerChannel("outputChannel", outputChannel);
context.registerChannel("eventBus", eventBus);
MessagingAnnotationPostProcessor postProcessor = new MessagingAnnotationPostProcessor();
postProcessor.setBeanFactory(context.getBeanFactory());
postProcessor.afterPropertiesSet();
ServiceActivatorAnnotatedBean bean = new ServiceActivatorAnnotatedBean();
postProcessor.postProcessAfterInitialization(bean, "testBean");
context.refresh();
Message<?> message = MessageBuilder.withPayload("test")
.setReplyChannelName("outputChannel").build();
inputChannel.send(message);
Message<?> reply = outputChannel.receive(0);
assertNotNull(reply);
eventBus.send(new GenericMessage<String>("foo"));
assertTrue(bean.getInvoked());
context.stop();
}
@Test
public void testProxiedMessageEndpointAnnotation() {
TestApplicationContext context = TestUtils.createTestApplicationContext();
DirectChannel inputChannel = new DirectChannel();
QueueChannel outputChannel = new QueueChannel();
context.registerChannel("inputChannel", inputChannel);
context.registerChannel("outputChannel", outputChannel);
MessagingAnnotationPostProcessor postProcessor = new MessagingAnnotationPostProcessor();
postProcessor.setBeanFactory(context.getBeanFactory());
postProcessor.afterPropertiesSet();
ProxyFactory proxyFactory = new ProxyFactory(new AnnotatedTestService());
Object proxy = proxyFactory.getProxy();
postProcessor.postProcessAfterInitialization(proxy, "proxy");
context.refresh();
inputChannel.send(new GenericMessage<String>("world"));
Message<?> message = outputChannel.receive(1000);
assertEquals("hello world", message.getPayload());
context.stop();
}
@Test
public void testMessageEndpointAnnotationInherited() {
TestApplicationContext context = TestUtils.createTestApplicationContext();
DirectChannel inputChannel = new DirectChannel();
QueueChannel outputChannel = new QueueChannel();
context.registerChannel("inputChannel", inputChannel);
context.registerChannel("outputChannel", outputChannel);
MessagingAnnotationPostProcessor postProcessor = new MessagingAnnotationPostProcessor();
postProcessor.setBeanFactory(context.getBeanFactory());
postProcessor.afterPropertiesSet();
postProcessor.postProcessAfterInitialization(new SimpleAnnotatedEndpointSubclass(), "subclass");
context.refresh();
inputChannel.send(new GenericMessage<String>("world"));
Message<?> message = outputChannel.receive(1000);
assertEquals("hello world", message.getPayload());
context.stop();
}
@Test
public void testMessageEndpointAnnotationInheritedWithProxy() {
TestApplicationContext context = TestUtils.createTestApplicationContext();
DirectChannel inputChannel = new DirectChannel();
QueueChannel outputChannel = new QueueChannel();
context.registerChannel("inputChannel", inputChannel);
context.registerChannel("outputChannel", outputChannel);
MessagingAnnotationPostProcessor postProcessor = new MessagingAnnotationPostProcessor();
postProcessor.setBeanFactory(context.getBeanFactory());
postProcessor.afterPropertiesSet();
ProxyFactory proxyFactory = new ProxyFactory(new SimpleAnnotatedEndpointSubclass());
Object proxy = proxyFactory.getProxy();
postProcessor.postProcessAfterInitialization(proxy, "proxy");
context.refresh();
inputChannel.send(new GenericMessage<String>("world"));
Message<?> message = outputChannel.receive(1000);
assertEquals("hello world", message.getPayload());
context.stop();
}
@Test
public void testMessageEndpointAnnotationInheritedFromInterface() {
TestApplicationContext context = TestUtils.createTestApplicationContext();
DirectChannel inputChannel = new DirectChannel();
QueueChannel outputChannel = new QueueChannel();
context.registerChannel("inputChannel", inputChannel);
context.registerChannel("outputChannel", outputChannel);
MessagingAnnotationPostProcessor postProcessor = new MessagingAnnotationPostProcessor();
postProcessor.setBeanFactory(context.getBeanFactory());
postProcessor.afterPropertiesSet();
postProcessor.postProcessAfterInitialization(new SimpleAnnotatedEndpointImplementation(), "impl");
context.refresh();
inputChannel.send(new GenericMessage<String>("ABC"));
Message<?> message = outputChannel.receive(1000);
assertEquals("test-ABC", message.getPayload());
context.stop();
}
@Test
public void testMessageEndpointAnnotationInheritedFromInterfaceWithAutoCreatedChannels() {
TestApplicationContext context = TestUtils.createTestApplicationContext();
DirectChannel inputChannel = new DirectChannel();
QueueChannel outputChannel = new QueueChannel();
context.registerChannel("inputChannel", inputChannel);
context.registerChannel("outputChannel", outputChannel);
MessagingAnnotationPostProcessor postProcessor = new MessagingAnnotationPostProcessor();
postProcessor.setBeanFactory(context.getBeanFactory());
postProcessor.afterPropertiesSet();
postProcessor.postProcessAfterInitialization(new SimpleAnnotatedEndpointImplementation(), "impl");
context.refresh();
inputChannel.send(new GenericMessage<String>("ABC"));
Message<?> message = outputChannel.receive(1000);
assertEquals("test-ABC", message.getPayload());
context.stop();
}
@Test
public void testMessageEndpointAnnotationInheritedFromInterfaceWithProxy() {
TestApplicationContext context = TestUtils.createTestApplicationContext();
DirectChannel inputChannel = new DirectChannel();
QueueChannel outputChannel = new QueueChannel();
context.registerChannel("inputChannel", inputChannel);
context.registerChannel("outputChannel", outputChannel);
MessagingAnnotationPostProcessor postProcessor = new MessagingAnnotationPostProcessor();
postProcessor.setBeanFactory(context.getBeanFactory());
postProcessor.afterPropertiesSet();
ProxyFactory proxyFactory = new ProxyFactory(new SimpleAnnotatedEndpointImplementation());
Object proxy = proxyFactory.getProxy();
postProcessor.postProcessAfterInitialization(proxy, "proxy");
context.refresh();
inputChannel.send(new GenericMessage<String>("ABC"));
Message<?> message = outputChannel.receive(1000);
assertEquals("test-ABC", message.getPayload());
context.stop();
}
@Test
public void testTransformer() {
TestApplicationContext context = TestUtils.createTestApplicationContext();
DirectChannel inputChannel = new DirectChannel();
context.registerChannel("inputChannel", inputChannel);
QueueChannel outputChannel = new QueueChannel();
context.registerChannel("outputChannel", outputChannel);
MessagingAnnotationPostProcessor postProcessor = new MessagingAnnotationPostProcessor();
postProcessor.setBeanFactory(context.getBeanFactory());
postProcessor.afterPropertiesSet();
TransformerAnnotationTestBean testBean = new TransformerAnnotationTestBean();
postProcessor.postProcessAfterInitialization(testBean, "testBean");
context.refresh();
inputChannel.send(new GenericMessage<String>("foo"));
Message<?> reply = outputChannel.receive(0);
assertEquals("FOO", reply.getPayload());
context.stop();
}
@MessageEndpoint
public static class OutboundOnlyTestBean {
private String messageText;
private final CountDownLatch latch;
OutboundOnlyTestBean(CountDownLatch latch) {
this.latch = latch;
}
public String getMessageText() {
return this.messageText;
}
@ServiceActivator(inputChannel = "testChannel")
public void countdown(String input) {
this.messageText = input;
latch.countDown();
}
}
public static class SimpleAnnotatedEndpointSubclass extends AnnotatedTestService {
}
@MessageEndpoint
public interface SimpleAnnotatedEndpointInterface {
String test(String input);
}
public static class SimpleAnnotatedEndpointImplementation implements SimpleAnnotatedEndpointInterface {
@Override
@ServiceActivator(inputChannel = "inputChannel", outputChannel = "outputChannel")
public String test(String input) {
return "test-" + input;
}
}
@MessageEndpoint
public static class ServiceActivatorAnnotatedBean {
public final AtomicBoolean invoked = new AtomicBoolean();
@ServiceActivator(inputChannel = "inputChannel")
public String test(String s) {
return s + s;
}
@EventHandler
public void eventBus(Object payload) {
invoked.set(true);
}
public Boolean getInvoked() {
return invoked.get();
}
}
@MessageEndpoint
public static class TransformerAnnotationTestBean {
@Transformer(inputChannel = "inputChannel", outputChannel = "outputChannel")
public String transformBefore(String input) {
return input.toUpperCase();
}
}
public static class ServiceActivatorAdvice extends AbstractRequestHandlerAdvice {
@Override
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) throws Exception {
return callback.execute() + " advised";
}
}
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@ServiceActivator(inputChannel = "eventBus")
public static @interface EventHandler {
}
}