INT-3571-4.2: Propagate Lifecycle to the Target

JIRA: https://jira.spring.io/browse/INT-3571

* Deprecate `LifecycleMessageSource` and change `SourcePollingChannelAdapter` to get deal with `Lifecycle` directly
* Add `Lifecycle` propagation for the `MessagingMethodInvokerHelper` and its users: `MethodInvokingMessageProcessor`,
`ServiceActivatingHandler`, `MethodInvokingMessageHandler`, `MessageTransformingHandler` etc.
* Fix the bug with `MessagingAnnotationPostProcessor` and `Proxy` for the target object, when we should process annotation on the root method,
but create `MethodInvokingMessageHandler` for the method on the `Proxy`. Apply this logic only when `Proxy` is `JdkDynamic`, because of `CGLIB`
does `proxy-target-class`. In case of `JdkDynamicProxy` throw `IllegalArgumentException` if the method isn't extracted to the service interface.

Add `Lifecycle` tests for all endpoint types
This commit is contained in:
Artem Bilan
2014-12-08 15:42:52 +02:00
committed by Gary Russell
parent de2c6d3ea0
commit 6aaee67809
27 changed files with 587 additions and 117 deletions

View File

@@ -148,7 +148,18 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
List<Annotation> annotations = entry.getValue();
MethodAnnotationPostProcessor postProcessor = postProcessors.get(annotationType);
if (postProcessor != null && postProcessor.shouldCreateEndpoint(method, annotations)) {
Object result = postProcessor.postProcess(bean, beanName, method, annotations);
Method targetMethod = method;
if (AopUtils.isJdkDynamicProxy(bean)) {
try {
targetMethod = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
}
catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Service methods must be extracted to the service "
+ "interface for JdkDynamicProxy. The affected bean is: '" + beanName + "' "
+ "and its method: '" + method + "'", e);
}
}
Object result = postProcessor.postProcess(bean, beanName, targetMethod, annotations);
if (result != null && result instanceof AbstractEndpoint) {
AbstractEndpoint endpoint = (AbstractEndpoint) result;
String autoStartup = MessagingAnnotationUtils.resolveAttribute(annotations, "autoStartup",

View File

@@ -24,6 +24,8 @@ import org.springframework.context.Lifecycle;
*
* @author Artem Bilan
* @since 4.0.6
* @deprecated since 4.2 in favor of direct {@link Lifecycle} usage.
*/
@Deprecated
public interface LifecycleMessageSource<T> extends MessageSource<T>, Lifecycle {
}

View File

@@ -19,6 +19,7 @@ package org.springframework.integration.endpoint;
import java.lang.reflect.Method;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.Lifecycle;
import org.springframework.integration.core.MessageSource;
import org.springframework.messaging.MessagingException;
import org.springframework.util.Assert;
@@ -30,8 +31,10 @@ import org.springframework.util.ReflectionUtils;
*
* @author Mark Fisher
* @author Gary Russell
* @author Artem Bilan
*/
public class MethodInvokingMessageSource extends AbstractMessageSource<Object> implements InitializingBean {
public class MethodInvokingMessageSource extends AbstractMessageSource<Object>
implements InitializingBean, Lifecycle {
private volatile Object object;
@@ -85,6 +88,25 @@ public class MethodInvokingMessageSource extends AbstractMessageSource<Object> i
}
}
@Override
public void start() {
if (this.object instanceof Lifecycle) {
((Lifecycle) this.object).start();
}
}
@Override
public void stop() {
if (this.object instanceof Lifecycle) {
((Lifecycle) this.object).stop();
}
}
@Override
public boolean isRunning() {
return !(this.object instanceof Lifecycle) || ((Lifecycle) this.object).isRunning();
}
@Override
protected Object doReceive() {
try {

View File

@@ -17,7 +17,6 @@
package org.springframework.integration.endpoint;
import org.springframework.context.Lifecycle;
import org.springframework.integration.core.LifecycleMessageSource;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.core.MessagingTemplate;
import org.springframework.integration.history.MessageHistory;
@@ -95,7 +94,7 @@ public class SourcePollingChannelAdapter extends AbstractPollingEndpoint
@Override
protected void doStart() {
if (this.source instanceof LifecycleMessageSource) {
if (this.source instanceof Lifecycle) {
((Lifecycle) this.source).start();
}
super.doStart();
@@ -104,7 +103,7 @@ public class SourcePollingChannelAdapter extends AbstractPollingEndpoint
@Override
protected void doStop() {
if (this.source instanceof LifecycleMessageSource) {
if (this.source instanceof Lifecycle) {
((Lifecycle) this.source).stop();
}
super.doStop();

View File

@@ -19,6 +19,7 @@ package org.springframework.integration.filter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.Lifecycle;
import org.springframework.core.convert.ConversionService;
import org.springframework.messaging.Message;
import org.springframework.integration.core.MessageSelector;
@@ -31,8 +32,10 @@ import org.springframework.util.Assert;
* a {@link MessageProcessor}.
*
* @author Mark Fisher
* @author Artem Bilan
*/
public abstract class AbstractMessageProcessingSelector implements MessageSelector, BeanFactoryAware {
public abstract class AbstractMessageProcessingSelector
implements MessageSelector, BeanFactoryAware, Lifecycle {
private final MessageProcessor<Boolean> messageProcessor;
@@ -62,4 +65,23 @@ public abstract class AbstractMessageProcessingSelector implements MessageSelect
return (Boolean) result;
}
@Override
public void start() {
if (this.messageProcessor instanceof Lifecycle) {
((Lifecycle) this.messageProcessor).start();
}
}
@Override
public void stop() {
if (this.messageProcessor instanceof Lifecycle) {
((Lifecycle) this.messageProcessor).stop();
}
}
@Override
public boolean isRunning() {
return !(this.messageProcessor instanceof Lifecycle) || ((Lifecycle) this.messageProcessor).isRunning();
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.integration.filter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.Lifecycle;
import org.springframework.integration.MessageRejectedException;
import org.springframework.integration.core.MessageSelector;
import org.springframework.integration.handler.AbstractReplyProducingPostProcessingMessageHandler;
@@ -41,7 +42,7 @@ import org.springframework.util.Assert;
* @author Artem Bilan
* @author David Liu
*/
public class MessageFilter extends AbstractReplyProducingPostProcessingMessageHandler {
public class MessageFilter extends AbstractReplyProducingPostProcessingMessageHandler implements Lifecycle {
private final MessageSelector selector;
@@ -122,6 +123,25 @@ public class MessageFilter extends AbstractReplyProducingPostProcessingMessageHa
}
}
@Override
public void start() {
if (this.selector instanceof Lifecycle) {
((Lifecycle) this.selector).start();
}
}
@Override
public void stop() {
if (this.selector instanceof Lifecycle) {
((Lifecycle) this.selector).stop();
}
}
@Override
public boolean isRunning() {
return !(this.selector instanceof Lifecycle) || ((Lifecycle) this.selector).isRunning();
}
@Override
protected Object doHandleRequestMessage(Message<?> message) {
if (this.selector.accept(message)) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2014 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.
@@ -18,6 +18,7 @@ package org.springframework.integration.handler;
import java.lang.reflect.Method;
import org.springframework.context.Lifecycle;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.MessageHandler;
@@ -25,14 +26,15 @@ import org.springframework.util.Assert;
/**
* A {@link MessageHandler} that invokes the specified method on the provided object.
*
*
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Artem Bilan
*/
public class MethodInvokingMessageHandler extends AbstractMessageHandler {
public class MethodInvokingMessageHandler extends AbstractMessageHandler implements Lifecycle {
private volatile MethodInvokingMessageProcessor<Object> processor;
private volatile String componentType;
public MethodInvokingMessageHandler(Object object, Method method) {
@@ -44,7 +46,7 @@ public class MethodInvokingMessageHandler extends AbstractMessageHandler {
public MethodInvokingMessageHandler(Object object, String methodName) {
processor = new MethodInvokingMessageProcessor<Object>(object, methodName);
}
public void setComponentType(String componentType) {
this.componentType = componentType;
}
@@ -54,12 +56,27 @@ public class MethodInvokingMessageHandler extends AbstractMessageHandler {
return this.componentType;
}
@Override
public void start() {
this.processor.start();
}
@Override
public void stop() {
this.processor.stop();
}
@Override
public boolean isRunning() {
return this.processor.isRunning();
}
@Override
protected void handleMessageInternal(Message<?> message) throws Exception {
Object result = processor.processMessage(message);
if (result != null) {
throw new MessagingException(message, "the MethodInvokingMessageHandler method must "
+ "have a void return, but '" + this + "' received a value: [" + result + "]");
+ "have a void return, but '" + this + "' received a value: [" + result + "]");
}
}

View File

@@ -20,16 +20,19 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.Lifecycle;
import org.springframework.core.convert.ConversionService;
import org.springframework.integration.util.MessagingMethodInvokerHelper;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandlingException;
/**
* A MessageProcessor implementation that invokes a method on a target Object. The Method instance or method name may be
* provided as a constructor argument. If a method name is provided, and more than one declared method has that name,
* the method-selection will be dynamic, based on the underlying SpEL method resolution. Alternatively, an annotation
* type may be provided so that the candidates for SpEL's method resolution are determined by the presence of that
* A MessageProcessor implementation that invokes a method on a target Object.
* The Method instance or method name may be provided as a constructor argument.
* If a method name is provided, and more than one declared method has that name,
* the method-selection will be dynamic, based on the underlying SpEL method resolution.
* Alternatively, an annotation type may be provided so that the candidates for
* SpEL's method resolution are determined by the presence of that
* annotation rather than the method name.
*
* @author Dave Syer
@@ -37,7 +40,7 @@ import org.springframework.messaging.MessageHandlingException;
*
* @since 2.0
*/
public class MethodInvokingMessageProcessor<T> extends AbstractMessageProcessor<T> {
public class MethodInvokingMessageProcessor<T> extends AbstractMessageProcessor<T> implements Lifecycle {
private final MessagingMethodInvokerHelper<T> delegate;
@@ -69,6 +72,21 @@ public class MethodInvokingMessageProcessor<T> extends AbstractMessageProcessor<
delegate.setBeanFactory(beanFactory);
}
@Override
public void start() {
this.delegate.start();
}
@Override
public void stop() {
this.delegate.stop();
}
@Override
public boolean isRunning() {
return this.delegate.isRunning();
}
@Override
public T processMessage(Message<?> message) {
try {

View File

@@ -19,6 +19,7 @@ package org.springframework.integration.handler;
import java.lang.reflect.Method;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.Lifecycle;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandlingException;
@@ -28,7 +29,7 @@ import org.springframework.messaging.MessageHandlingException;
* @author Artem Bilan
* @author Gary Russell
*/
public class ServiceActivatingHandler extends AbstractReplyProducingMessageHandler {
public class ServiceActivatingHandler extends AbstractReplyProducingMessageHandler implements Lifecycle {
private final MessageProcessor<?> processor;
@@ -65,6 +66,25 @@ public class ServiceActivatingHandler extends AbstractReplyProducingMessageHandl
}
}
@Override
public void start() {
if (this.processor instanceof Lifecycle) {
((Lifecycle) this.processor).start();
}
}
@Override
public void stop() {
if (this.processor instanceof Lifecycle) {
((Lifecycle) this.processor).stop();
}
}
@Override
public boolean isRunning() {
return !(this.processor instanceof Lifecycle) || ((Lifecycle) this.processor).isRunning();
}
@Override
protected Object handleRequestMessage(Message<?> message) {
try {

View File

@@ -20,6 +20,7 @@ import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.Lifecycle;
import org.springframework.messaging.Message;
import org.springframework.integration.handler.AbstractMessageProcessor;
import org.springframework.integration.handler.MessageProcessor;
@@ -32,7 +33,8 @@ import org.springframework.util.Assert;
* @author Mark Fisher
* @since 2.0
*/
class AbstractMessageProcessingRouter extends AbstractMappingMessageRouter {
class AbstractMessageProcessingRouter extends AbstractMappingMessageRouter
implements Lifecycle {
private final MessageProcessor<?> messageProcessor;
@@ -54,6 +56,25 @@ class AbstractMessageProcessingRouter extends AbstractMappingMessageRouter {
}
}
@Override
public void start() {
if (this.messageProcessor instanceof Lifecycle) {
((Lifecycle) this.messageProcessor).start();
}
}
@Override
public void stop() {
if (this.messageProcessor instanceof Lifecycle) {
((Lifecycle) this.messageProcessor).stop();
}
}
@Override
public boolean isRunning() {
return !(this.messageProcessor instanceof Lifecycle) || ((Lifecycle) this.messageProcessor).isRunning();
}
@Override
protected List<Object> getChannelKeys(Message<?> message) {
Object result = this.messageProcessor.processMessage(message);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -19,6 +19,7 @@ package org.springframework.integration.splitter;
import java.util.Collection;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.Lifecycle;
import org.springframework.core.convert.ConversionService;
import org.springframework.messaging.Message;
import org.springframework.integration.handler.AbstractMessageProcessor;
@@ -30,9 +31,11 @@ import org.springframework.util.Assert;
* {@link MessageProcessor} instance.
*
* @author Mark Fisher
* @author Artem Bilan
* @since 2.0
*/
abstract class AbstractMessageProcessingSplitter extends AbstractMessageSplitter {
abstract class AbstractMessageProcessingSplitter extends AbstractMessageSplitter
implements Lifecycle {
private final MessageProcessor<Collection<?>> messageProcessor;
@@ -58,4 +61,23 @@ abstract class AbstractMessageProcessingSplitter extends AbstractMessageSplitter
return this.messageProcessor.processMessage(message);
}
@Override
public void start() {
if (this.messageProcessor instanceof Lifecycle) {
((Lifecycle) this.messageProcessor).start();
}
}
@Override
public void stop() {
if (this.messageProcessor instanceof Lifecycle) {
((Lifecycle) this.messageProcessor).stop();
}
}
@Override
public boolean isRunning() {
return !(this.messageProcessor instanceof Lifecycle) || ((Lifecycle) this.messageProcessor).isRunning();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2014 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.
@@ -18,6 +18,7 @@ package org.springframework.integration.transformer;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.Lifecycle;
import org.springframework.core.convert.ConversionService;
import org.springframework.integration.handler.AbstractMessageProcessor;
import org.springframework.integration.handler.MessageProcessor;
@@ -31,8 +32,10 @@ import org.springframework.util.Assert;
* Base class for Message Transformers that delegate to a {@link MessageProcessor}.
*
* @author Mark Fisher
* @author Artem Bilan
*/
public abstract class AbstractMessageProcessingTransformer implements Transformer, BeanFactoryAware {
public abstract class AbstractMessageProcessingTransformer
implements Transformer, BeanFactoryAware, Lifecycle {
private final MessageProcessor<?> messageProcessor;
@@ -59,6 +62,25 @@ public abstract class AbstractMessageProcessingTransformer implements Transforme
this.messageBuilderFactory = IntegrationUtils.getMessageBuilderFactory(beanFactory);
}
@Override
public void start() {
if (this.messageProcessor instanceof Lifecycle) {
((Lifecycle) this.messageProcessor).start();
}
}
@Override
public void stop() {
if (this.messageProcessor instanceof Lifecycle) {
((Lifecycle) this.messageProcessor).stop();
}
}
@Override
public boolean isRunning() {
return !(this.messageProcessor instanceof Lifecycle) || ((Lifecycle) this.messageProcessor).isRunning();
}
@Override
public final Message<?> transform(Message<?> message) {
Object result = this.messageProcessor.processMessage(message);

View File

@@ -17,6 +17,7 @@
package org.springframework.integration.transformer;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.Lifecycle;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.support.context.NamedComponent;
import org.springframework.messaging.Message;
@@ -30,8 +31,9 @@ import org.springframework.util.Assert;
*
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Artem Bilan
*/
public class MessageTransformingHandler extends AbstractReplyProducingMessageHandler {
public class MessageTransformingHandler extends AbstractReplyProducingMessageHandler implements Lifecycle {
private final Transformer transformer;
@@ -62,6 +64,25 @@ public class MessageTransformingHandler extends AbstractReplyProducingMessageHan
}
}
@Override
public void start() {
if (this.transformer instanceof Lifecycle) {
((Lifecycle) this.transformer).start();
}
}
@Override
public void stop() {
if (this.transformer instanceof Lifecycle) {
((Lifecycle) this.transformer).stop();
}
}
@Override
public boolean isRunning() {
return !(this.transformer instanceof Lifecycle) || ((Lifecycle) this.transformer).isRunning();
}
@Override
protected Object handleRequestMessage(Message<?> message) {
try {

View File

@@ -40,6 +40,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.Lifecycle;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
@@ -60,17 +61,20 @@ import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.MethodCallback;
import org.springframework.util.ReflectionUtils.MethodFilter;
import org.springframework.util.StringUtils;
/**
* A helper class for processors that invoke a method on a target Object using a combination of message payload(s) and
* headers as arguments. The Method instance or method name may be provided as a constructor argument. If a method name
* is provided, and more than one declared method has that name, the method-selection will be dynamic, based on the
* underlying SpEL method resolution. Alternatively, an annotation type may be provided so that the candidates for
* SpEL's method resolution are determined by the presence of that annotation rather than the method name.
* A helper class for processors that invoke a method on a target Object using
* a combination of message payload(s) and headers as arguments.
* The Method instance or method name may be provided as a constructor argument.
* If a method name is provided, and more than one declared method has that name,
* the method-selection will be dynamic, based on the underlying SpEL method resolution.
* Alternatively, an annotation type may be provided so that the candidates for SpEL's
* method resolution are determined by the presence of that annotation rather than the method name.
*
* @author Mark Fisher
* @author Oleg Zhurakousky
@@ -82,7 +86,7 @@ import org.springframework.util.StringUtils;
*
* @since 2.0
*/
public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator {
public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator implements Lifecycle {
private static final String CANDIDATE_METHODS = "CANDIDATE_METHODS";
@@ -91,6 +95,7 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
private final Log logger = LogFactory.getLog(this.getClass());
private final Object targetObject;
private volatile String displayString;
private volatile boolean requiresReply;
@@ -152,6 +157,25 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
return this.displayString;
}
@Override
public void start() {
if (this.targetObject instanceof Lifecycle) {
((Lifecycle) this.targetObject).start();
}
}
@Override
public void stop() {
if (this.targetObject instanceof Lifecycle) {
((Lifecycle) this.targetObject).stop();
}
}
@Override
public boolean isRunning() {
return !(this.targetObject instanceof Lifecycle) || ((Lifecycle) this.targetObject).isRunning();
}
/*
* Private constructors for internal use
*/
@@ -329,6 +353,10 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
if (methodName != null && !methodName.equals(method.getName())) {
return;
}
if (methodName == null
&& ObjectUtils.containsElement(new String[] {"start", "stop", "isRunning"}, method.getName())) {
return;
}
if (annotationType != null && AnnotationUtils.findAnnotation(method, annotationType) != null) {
matchesAnnotation = true;
}
@@ -532,7 +560,6 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
return (method.getName().equals("clone") && method.getParameterTypes().length == 0);
}
/**
* Helper class for generating and exposing metadata for a candidate handler method. The metadata includes the SpEL
* expression and the expected payload type.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2014 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.
@@ -17,23 +17,28 @@
package org.springframework.integration.config.annotation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.springframework.messaging.Message;
import org.springframework.context.Lifecycle;
import org.springframework.integration.annotation.MessageEndpoint;
import org.springframework.integration.annotation.Splitter;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.integration.test.util.TestUtils.TestApplicationContext;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.GenericMessage;
/**
* @author Mark Fisher
* @author Artem Bilan
*/
public class SplitterAnnotationPostProcessorTests {
@@ -73,17 +78,44 @@ public class SplitterAnnotationPostProcessorTests {
assertNotNull(message4);
assertEquals("test", message4.getPayload());
assertNull(outputChannel.receive(0));
AbstractEndpoint endpoint = context.getBean(AbstractEndpoint.class);
assertTrue(splitter.isRunning());
endpoint.stop();
assertFalse(splitter.isRunning());
endpoint.start();
assertTrue(splitter.isRunning());
context.stop();
}
@MessageEndpoint
public static class TestSplitter {
public static class TestSplitter implements Lifecycle {
@Splitter(inputChannel="input", outputChannel="output")
private boolean running;
@Splitter(inputChannel = "input", outputChannel = "output")
public String[] split(String s) {
return s.split("\\.");
}
@Override
public void start() {
this.running = true;
}
@Override
public void stop() {
this.running = false;
}
@Override
public boolean isRunning() {
return this.running;
}
}
}

View File

@@ -6,7 +6,7 @@
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd">
<message-history tracked-components="publishedChannel,input,*AnnotationTestService*"/>
<message-history tracked-components="publishedChannel,input,annotationTestService*"/>
<annotation-config default-publisher-channel="publishedChannel"/>

View File

@@ -144,29 +144,33 @@ public class EnableIntegrationTests {
private PollableChannel input;
@Autowired
@Qualifier("enableIntegrationTests.AnnotationTestService.handle.serviceActivator")
@Qualifier("annotationTestService.handle.serviceActivator")
private PollingConsumer serviceActivatorEndpoint;
@Autowired
@Qualifier("enableIntegrationTests.AnnotationTestService.handle1.serviceActivator")
@Qualifier("annotationTestService.handle1.serviceActivator")
private PollingConsumer serviceActivatorEndpoint1;
@Autowired
@Qualifier("enableIntegrationTests.AnnotationTestService.handle2.serviceActivator")
@Qualifier("annotationTestService.handle2.serviceActivator")
private PollingConsumer serviceActivatorEndpoint2;
@Autowired
@Qualifier("enableIntegrationTests.AnnotationTestService.handle3.serviceActivator")
@Qualifier("annotationTestService.handle3.serviceActivator")
private PollingConsumer serviceActivatorEndpoint3;
@Autowired
@Qualifier("enableIntegrationTests.AnnotationTestService.handle4.serviceActivator")
@Qualifier("annotationTestService.handle4.serviceActivator")
private PollingConsumer serviceActivatorEndpoint4;
@Autowired
@Qualifier("enableIntegrationTests.AnnotationTestService.transform.transformer")
@Qualifier("annotationTestService.transform.transformer")
private PollingConsumer transformer;
@Autowired
@Qualifier("annotationTestService")
private Lifecycle annotationTestService;
@Autowired
private Trigger myTrigger;
@@ -261,6 +265,12 @@ public class EnableIntegrationTests {
assertEquals(100L, TestUtils.getPropertyValue(trigger, "period"));
assertFalse(TestUtils.getPropertyValue(trigger, "fixedRate", Boolean.class));
assertTrue(this.annotationTestService.isRunning());
this.serviceActivatorEndpoint.stop();
assertFalse(this.annotationTestService.isRunning());
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"));
@@ -288,11 +298,11 @@ public class EnableIntegrationTests {
this.input.send(MessageBuilder.withPayload("Foo").build());
Message<?> interceptedMessage = this.wireTapChannel.receive(1000);
Message<?> interceptedMessage = this.wireTapChannel.receive(10000);
assertNotNull(interceptedMessage);
assertEquals("Foo", interceptedMessage.getPayload());
Message<?> receive = this.output.receive(1000);
Message<?> receive = this.output.receive(10000);
assertNotNull(receive);
assertEquals("FOO", receive.getPayload());
@@ -301,7 +311,7 @@ public class EnableIntegrationTests {
String messageHistoryString = messageHistory.toString();
assertThat(messageHistoryString, Matchers.containsString("input"));
assertThat(messageHistoryString,
Matchers.containsString("AnnotationTestService.handle.serviceActivator.handler"));
Matchers.containsString("annotationTestService.handle.serviceActivator.handler"));
assertThat(messageHistoryString, Matchers.not(Matchers.containsString("output")));
receive = this.publishedChannel.receive(1000);
@@ -319,15 +329,13 @@ public class EnableIntegrationTests {
assertThat(this.testChannelInterceptor.getInvoked(), Matchers.greaterThan(0));
assertThat(this.fbInterceptorCounter.get(), Matchers.greaterThan(0));
assertTrue(this.context
.containsBean("enableIntegrationTests.AnnotationTestService.count.inboundChannelAdapter.source"));
Object messageSource = this.context
.getBean("enableIntegrationTests.AnnotationTestService.count.inboundChannelAdapter.source");
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("enableIntegrationTests.AnnotationTestService.count.inboundChannelAdapter",
SmartLifecycle countSA = this.context.getBean("annotationTestService.count.inboundChannelAdapter",
SmartLifecycle.class);
assertFalse(countSA.isAutoStartup());
assertEquals(23, countSA.getPhase());
@@ -416,7 +424,7 @@ public class EnableIntegrationTests {
assertThat(this.testConverter.getInvoked(), Matchers.greaterThan(0));
assertTrue(this.bytesChannel.send(new GenericMessage<byte[]>("foo".getBytes())));
assertTrue(this.bytesChannel.send(new GenericMessage<Message<?>>(MutableMessageBuilder.withPayload("").build())));
assertTrue(this.bytesChannel.send(new GenericMessage<>(MutableMessageBuilder.withPayload("").build())));
}
@@ -425,8 +433,7 @@ public class EnableIntegrationTests {
assertEquals(2, this.context.getBeanNamesForType(GatewayProxyFactoryBean.class).length);
PollingConsumer consumer = this.context.getBean(
"enableIntegrationTests.AnnotationTestService.annCount.serviceActivator",
PollingConsumer consumer = this.context.getBean("annotationTestService.annCount.serviceActivator",
PollingConsumer.class);
assertFalse(TestUtils.getPropertyValue(consumer, "autoStartup", Boolean.class));
assertEquals(23, TestUtils.getPropertyValue(consumer, "phase"));
@@ -436,8 +443,7 @@ public class EnableIntegrationTests {
"handler.adviceChain", List.class).get(0));
assertEquals(1000L, TestUtils.getPropertyValue(consumer, "trigger.period"));
consumer = this.context.getBean(
"enableIntegrationTests.AnnotationTestService.annCount1.serviceActivator",
consumer = this.context.getBean("annotationTestService.annCount1.serviceActivator",
PollingConsumer.class);
consumer.stop();
assertTrue(TestUtils.getPropertyValue(consumer, "autoStartup", Boolean.class));
@@ -448,8 +454,7 @@ public class EnableIntegrationTests {
"handler.adviceChain", List.class).get(0));
assertEquals(2000L, TestUtils.getPropertyValue(consumer, "trigger.period"));
consumer = this.context.getBean(
"enableIntegrationTests.AnnotationTestService.annCount2.serviceActivator",
consumer = this.context.getBean("annotationTestService.annCount2.serviceActivator",
PollingConsumer.class);
assertFalse(TestUtils.getPropertyValue(consumer, "autoStartup", Boolean.class));
assertEquals(23, TestUtils.getPropertyValue(consumer, "phase"));
@@ -460,9 +465,7 @@ public class EnableIntegrationTests {
assertEquals(1000L, TestUtils.getPropertyValue(consumer, "trigger.period"));
// Tests when the channel is in a "middle" annotation
consumer = this.context.getBean(
"enableIntegrationTests.AnnotationTestService.annCount5.serviceActivator",
PollingConsumer.class);
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"));
@@ -471,9 +474,7 @@ public class EnableIntegrationTests {
"handler.adviceChain", List.class).get(0));
assertEquals(1000L, TestUtils.getPropertyValue(consumer, "trigger.period"));
consumer = this.context.getBean(
"enableIntegrationTests.AnnotationTestService.annAgg1.aggregator",
PollingConsumer.class);
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"));
@@ -483,9 +484,7 @@ public class EnableIntegrationTests {
assertEquals(1000L, TestUtils.getPropertyValue(consumer, "handler.messagingTemplate.sendTimeout"));
assertFalse(TestUtils.getPropertyValue(consumer, "handler.sendPartialResultOnExpiry", Boolean.class));
consumer = this.context.getBean(
"enableIntegrationTests.AnnotationTestService.annAgg2.aggregator",
PollingConsumer.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"));
@@ -610,7 +609,7 @@ public class EnableIntegrationTests {
@IntegrationComponentScan
@EnableIntegration
@PropertySource("classpath:org/springframework/integration/configuration/EnableIntegrationTests.properties")
@EnableMessageHistory({"input", "publishedChannel", "*AnnotationTestService*"})
@EnableMessageHistory({"input", "publishedChannel", "annotationTestService*"})
public static class ContextConfiguration {
@Bean
@@ -866,11 +865,13 @@ public class EnableIntegrationTests {
@ServiceActivator(inputChannel = "sendAsyncChannel")
public MessageHandler sendAsyncHandler() {
return new MessageHandler() {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
asyncAnnotationProcessLatch().countDown();
asyncAnnotationProcessThread().set(Thread.currentThread());
}
};
}
@@ -992,12 +993,54 @@ public class EnableIntegrationTests {
}
public interface AnnotationTestService {
@MessageEndpoint
public static class 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);
}
@MessageEndpoint("annotationTestService")
public static class AnnotationTestServiceImpl implements Lifecycle, AnnotationTestService {
private final AtomicInteger counter = new AtomicInteger();
private boolean running;
@Override
@ServiceActivator(inputChannel = "input", outputChannel = "output",
poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", fixedDelay = "${poller.interval}"))
@Publisher
@@ -1006,6 +1049,7 @@ public class EnableIntegrationTests {
return payload.toUpperCase();
}
@Override
@ServiceActivator(inputChannel = "input1", outputChannel = "output",
poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", fixedRate = "${poller.interval}"))
@Publisher
@@ -1014,6 +1058,7 @@ public class EnableIntegrationTests {
return payload.toUpperCase();
}
@Override
@ServiceActivator(inputChannel = "input2", outputChannel = "output",
poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", cron = "0 5 7 * * *"))
@Publisher
@@ -1022,6 +1067,7 @@ public class EnableIntegrationTests {
return payload.toUpperCase();
}
@Override
@ServiceActivator(inputChannel = "input3", outputChannel = "output", poller = @Poller("myPoller"))
@Publisher
@Payload("#args[0].toLowerCase()")
@@ -1029,6 +1075,7 @@ public class EnableIntegrationTests {
return payload.toUpperCase();
}
@Override
@ServiceActivator(inputChannel = "input4", outputChannel = "output",
poller = @Poller(trigger = "myTrigger"))
@Publisher
@@ -1047,6 +1094,7 @@ public class EnableIntegrationTests {
return payload.toUpperCase();
}*/
@Override
@Transformer(inputChannel = "gatewayChannel")
public String transform(Message<String> message) {
assertTrue(message.getHeaders().containsKey("foo"));
@@ -1056,6 +1104,7 @@ public class EnableIntegrationTests {
return this.handle(message.getPayload());
}
@Override
@Transformer(inputChannel = "gatewayChannel2")
public String transform2(Message<String> message) {
assertTrue(message.getHeaders().containsKey("foo"));
@@ -1065,16 +1114,19 @@ public class EnableIntegrationTests {
return this.handle(message.getPayload()) + "2";
}
@Override
@MyInboundChannelAdapter1
public Integer count() {
return this.counter.incrementAndGet();
}
@Override
@InboundChannelAdapter(value = "fooChannel", poller = @Poller(trigger = "onlyOnceTrigger", maxMessagesPerPoll = "1"))
public String foo() {
return "foo";
}
@Override
@InboundChannelAdapter(value = "messageChannel", poller = @Poller(fixedDelay = "${poller.interval}",
maxMessagesPerPoll = "1"))
public Message<?> message() {
@@ -1098,37 +1150,44 @@ public class EnableIntegrationTests {
// 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;
@@ -1138,10 +1197,27 @@ public class EnableIntegrationTests {
/*@BridgeFrom("")
public void invalidBridgeAnnotationMethod(Object payload) {}*/
@Override
@ServiceActivator(inputChannel = "promiseChannel")
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

View File

@@ -1,3 +1,3 @@
message.history.tracked.components=input, publishedChannel, *AnnotationTestService*
message.history.tracked.components=input, publishedChannel, annotationTestService*
poller.maxMessagesPerPoll=10
poller.interval=100

View File

@@ -34,11 +34,11 @@ import org.mockito.Mockito;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.Lifecycle;
import org.springframework.integration.channel.NullChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean;
import org.springframework.integration.config.TestErrorHandler;
import org.springframework.integration.core.LifecycleMessageSource;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.scheduling.PollerMetadata;
import org.springframework.messaging.Message;
@@ -178,7 +178,8 @@ public class PollingLifecycleTests {
final AtomicBoolean stopInvoked = new AtomicBoolean();
adapterFactory.setSource(new LifecycleMessageSource<Object>() {
MethodInvokingMessageSource source = new MethodInvokingMessageSource();
source.setObject(new Lifecycle() {
@Override
public void start() {
@@ -195,12 +196,10 @@ public class PollingLifecycleTests {
return false;
}
@Override
public Message<Object> receive() {
return null;
}
});
source.setMethodName("isRunning");
adapterFactory.setSource(source);
SourcePollingChannelAdapter adapter = adapterFactory.getObject();
adapter.setTaskScheduler(this.taskScheduler);

View File

@@ -13,7 +13,7 @@
<queue capacity="50"/>
</channel>
<filter input-channel="input"
<filter id="pojoFilter" input-channel="input"
ref="testBean"
method="acceptStringWithMoreThanThreeChars"
output-channel="output"/>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2014 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.
@@ -17,41 +17,59 @@
package org.springframework.integration.filter;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Mark Fisher
* @author Artem Bilan
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class FilterContextTests {
@Autowired
private MessageChannel input;
@Autowired
private PollableChannel output;
@Autowired
private AbstractEndpoint pojoFilter;
@Autowired
private TestBean testBean;
@Test
public void methodInvokingFilterRejects() {
ApplicationContext context = new ClassPathXmlApplicationContext(
"filterContextTests.xml", this.getClass());
MessageChannel input = (MessageChannel) context.getBean("input");
PollableChannel output = (PollableChannel) context.getBean("output");
input.send(new GenericMessage<String>("foo"));
Message<?> reply = output.receive(0);
this.input.send(new GenericMessage<String>("foo"));
Message<?> reply = this.output.receive(0);
assertNull(reply);
assertTrue(this.testBean.isRunning());
this.pojoFilter.stop();
assertFalse(this.testBean.isRunning());
this.pojoFilter.start();
assertTrue(this.testBean.isRunning());
}
@Test
public void methodInvokingFilterAccepts() {
ApplicationContext context = new ClassPathXmlApplicationContext(
"filterContextTests.xml", this.getClass());
MessageChannel input = (MessageChannel) context.getBean("input");
PollableChannel output = (PollableChannel) context.getBean("output");
input.send(new GenericMessage<String>("foobar"));
Message<?> reply = output.receive(0);
this.input.send(new GenericMessage<String>("foobar"));
Message<?> reply = this.output.receive(0);
assertEquals("foobar", reply.getPayload());
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2014 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.
@@ -16,13 +16,33 @@
package org.springframework.integration.filter;
import org.springframework.context.Lifecycle;
/**
* @author Mark Fisher
* @author Artem Bilan
*/
public class TestBean {
public class TestBean implements Lifecycle {
private boolean running;
public boolean acceptStringWithMoreThanThreeChars(String s) {
return s.length() > 3;
}
@Override
public void start() {
this.running = true;
}
@Override
public void stop() {
this.running = false;
}
@Override
public boolean isRunning() {
return this.running;
}
}

View File

@@ -38,7 +38,7 @@
<queue capacity="1" />
</channel>
<router input-channel="pojoRouter" ref="testBean"
<router id="pojoRouterEndpoint" input-channel="pojoRouter" ref="testBean"
default-output-channel="defaultChannelForPojo"
resolution-required="false">
<mapping value="foo" channel="fooChannelForPojo"/>

View File

@@ -16,14 +16,18 @@
package org.springframework.integration.router.config;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.Lifecycle;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.router.AbstractMappingMessageRouter;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
@@ -68,6 +72,12 @@ public class RouterWithMappingTests {
@Autowired
private PollableChannel defaultChannelForPojo;
@Autowired
private AbstractEndpoint pojoRouterEndpoint;
@Autowired
private TestRouter testBean;
@Test
public void expressionRouter() {
Message<?> message1 = MessageBuilder.withPayload(new TestBean("foo")).build();
@@ -110,6 +120,12 @@ public class RouterWithMappingTests {
assertNotNull(defaultChannelForPojo.receive(0));
assertNull(fooChannelForPojo.receive(0));
assertNull(barChannelForPojo.receive(0));
assertTrue(this.testBean.isRunning());
this.pojoRouterEndpoint.stop();
assertFalse(this.testBean.isRunning());
this.pojoRouterEndpoint.start();
assertTrue(this.testBean.isRunning());
}
private static class TestBean {
@@ -126,12 +142,29 @@ public class RouterWithMappingTests {
}
@SuppressWarnings("unused")
private static class TestRouter {
private static class TestRouter implements Lifecycle {
private boolean running;
public String route(TestBean bean) {
return bean.getName();
}
@Override
public void start() {
this.running = true;
}
@Override
public void stop() {
this.running = false;
}
@Override
public boolean isRunning() {
return this.running;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2014 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.
@@ -16,13 +16,33 @@
package org.springframework.integration.transformer;
import org.springframework.context.Lifecycle;
/**
* @author Mark Fisher
* @author Artem Bilan
*/
public class TestBean {
public class TestBean implements Lifecycle {
private boolean running;
public String upperCase(String input) {
return input.toUpperCase();
}
@Override
public void start() {
this.running = true;
}
@Override
public void stop() {
this.running = false;
}
@Override
public boolean isRunning() {
return this.running;
}
}

View File

@@ -13,7 +13,7 @@
<queue capacity="50"/>
</channel>
<transformer input-channel="input" ref="testBean" method="upperCase" output-channel="output">
<transformer id="pojoTransformer" input-channel="input" ref="testBean" method="upperCase" output-channel="output">
<request-handler-advice-chain>
<beans:bean class="org.springframework.integration.transformer.TransformerContextTests$FooAdvice" />
</request-handler-advice-chain>
@@ -26,7 +26,7 @@
</transformer>
<transformer input-channel="directRef" output-channel="output" ref="trans" method="handleMessage"/>
<beans:bean id="trans" class="org.springframework.integration.transformer.TransformerContextTests$Bar"/>
</beans:beans>

View File

@@ -17,11 +17,17 @@
package org.springframework.integration.transformer;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.filter.*;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
import org.springframework.integration.support.MessageBuilder;
@@ -29,42 +35,64 @@ import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Also in JMX - changes here should be reflected there.
*
* @author Mark Fisher
* @author Gary Russell
* @author Artem Bilan
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class TransformerContextTests {
private static volatile int adviceCalled;
@Autowired
private MessageChannel input;
@Autowired
private MessageChannel direct;
@Autowired
private MessageChannel directRef;
@Autowired
private PollableChannel output;
@Autowired
private AbstractEndpoint pojoTransformer;
@Autowired
private TestBean testBean;
@Test
public void methodInvokingTransformer() {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(
"transformerContextTests.xml", this.getClass());
MessageChannel input = context.getBean("input", MessageChannel.class);
PollableChannel output = context.getBean("output", PollableChannel.class);
input.send(new GenericMessage<String>("foo"));
Message<?> reply = output.receive(0);
this.input.send(new GenericMessage<String>("foo"));
Message<?> reply = this.output.receive(0);
assertEquals("FOO", reply.getPayload());
assertEquals(1, adviceCalled);
input = context.getBean("direct", MessageChannel.class);
input.send(new GenericMessage<String>("foo"));
reply = output.receive(0);
this.direct.send(new GenericMessage<String>("foo"));
reply = this.output.receive(0);
assertEquals("FOO", reply.getPayload());
StackTraceElement[] st = (StackTraceElement[]) reply.getHeaders().get("callStack");
assertEquals("doSend", st[6].getMethodName()); // no MethodInvokerHelper
input = context.getBean("directRef", MessageChannel.class);
input.send(new GenericMessage<String>("foo"));
reply = output.receive(0);
this.directRef.send(new GenericMessage<String>("foo"));
reply = this.output.receive(0);
assertEquals("FOO", reply.getPayload());
st = (StackTraceElement[]) reply.getHeaders().get("callStack");
assertEquals("doSend", st[6].getMethodName()); // no MethodInvokerHelper
context.close();
assertTrue(this.testBean.isRunning());
this.pojoTransformer.stop();
assertFalse(this.testBean.isRunning());
this.pojoTransformer.start();
assertTrue(this.testBean.isRunning());
}
public static class FooAdvice extends AbstractRequestHandlerAdvice {