From 6aaee678098c814aaa105f1c92ab94d6aa1cdf50 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 8 Dec 2014 15:42:52 +0200 Subject: [PATCH] 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 --- .../MessagingAnnotationPostProcessor.java | 13 +- .../core/LifecycleMessageSource.java | 2 + .../endpoint/MethodInvokingMessageSource.java | 24 ++- .../endpoint/SourcePollingChannelAdapter.java | 5 +- .../AbstractMessageProcessingSelector.java | 24 ++- .../integration/filter/MessageFilter.java | 22 ++- .../handler/MethodInvokingMessageHandler.java | 29 +++- .../MethodInvokingMessageProcessor.java | 28 +++- .../handler/ServiceActivatingHandler.java | 22 ++- .../AbstractMessageProcessingRouter.java | 23 ++- .../AbstractMessageProcessingSplitter.java | 26 +++- .../AbstractMessageProcessingTransformer.java | 26 +++- .../MessageTransformingHandler.java | 23 ++- .../util/MessagingMethodInvokerHelper.java | 41 ++++- .../SplitterAnnotationPostProcessorTests.java | 42 +++++- .../EnableIntegrationTests-context.xml | 2 +- .../configuration/EnableIntegrationTests.java | 142 ++++++++++++++---- .../EnableIntegrationTests.properties | 2 +- .../endpoint/PollingLifecycleTests.java | 13 +- ...sts.xml => FilterContextTests-context.xml} | 2 +- .../filter/FilterContextTests.java | 48 ++++-- .../integration/filter/TestBean.java | 24 ++- .../config/RouterWithMappingTests-context.xml | 2 +- .../router/config/RouterWithMappingTests.java | 37 ++++- .../integration/transformer/TestBean.java | 24 ++- ...ml => TransformerContextTests-context.xml} | 4 +- .../transformer/TransformerContextTests.java | 54 +++++-- 27 files changed, 587 insertions(+), 117 deletions(-) rename spring-integration-core/src/test/java/org/springframework/integration/filter/{filterContextTests.xml => FilterContextTests-context.xml} (94%) rename spring-integration-core/src/test/java/org/springframework/integration/transformer/{transformerContextTests.xml => TransformerContextTests-context.xml} (91%) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java index 31f11f84f8..4733d44708 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java @@ -148,7 +148,18 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean List 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", diff --git a/spring-integration-core/src/main/java/org/springframework/integration/core/LifecycleMessageSource.java b/spring-integration-core/src/main/java/org/springframework/integration/core/LifecycleMessageSource.java index 57dc6391f5..ab6233b1d0 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/core/LifecycleMessageSource.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/core/LifecycleMessageSource.java @@ -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 extends MessageSource, Lifecycle { } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/endpoint/MethodInvokingMessageSource.java b/spring-integration-core/src/main/java/org/springframework/integration/endpoint/MethodInvokingMessageSource.java index 3dde97e696..6a1b001a5f 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/endpoint/MethodInvokingMessageSource.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/endpoint/MethodInvokingMessageSource.java @@ -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 implements InitializingBean { +public class MethodInvokingMessageSource extends AbstractMessageSource + implements InitializingBean, Lifecycle { private volatile Object object; @@ -85,6 +88,25 @@ public class MethodInvokingMessageSource extends AbstractMessageSource 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 { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/endpoint/SourcePollingChannelAdapter.java b/spring-integration-core/src/main/java/org/springframework/integration/endpoint/SourcePollingChannelAdapter.java index 3bd75f9e66..824612855f 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/endpoint/SourcePollingChannelAdapter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/endpoint/SourcePollingChannelAdapter.java @@ -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(); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/filter/AbstractMessageProcessingSelector.java b/spring-integration-core/src/main/java/org/springframework/integration/filter/AbstractMessageProcessingSelector.java index 71c568a87c..f38acf2d3a 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/filter/AbstractMessageProcessingSelector.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/filter/AbstractMessageProcessingSelector.java @@ -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 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(); + } + } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/filter/MessageFilter.java b/spring-integration-core/src/main/java/org/springframework/integration/filter/MessageFilter.java index c93d986bb8..ccb7a9f4fa 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/filter/MessageFilter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/filter/MessageFilter.java @@ -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)) { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/MethodInvokingMessageHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/MethodInvokingMessageHandler.java index 1e62e41dc7..144bf94cfc 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/MethodInvokingMessageHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/MethodInvokingMessageHandler.java @@ -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 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, 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 + "]"); } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/MethodInvokingMessageProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/MethodInvokingMessageProcessor.java index ea7e3d0c82..610e1223ec 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/MethodInvokingMessageProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/MethodInvokingMessageProcessor.java @@ -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 extends AbstractMessageProcessor { +public class MethodInvokingMessageProcessor extends AbstractMessageProcessor implements Lifecycle { private final MessagingMethodInvokerHelper delegate; @@ -69,6 +72,21 @@ public class MethodInvokingMessageProcessor 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 { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/ServiceActivatingHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/ServiceActivatingHandler.java index 98b94b8646..4688926f55 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/ServiceActivatingHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/ServiceActivatingHandler.java @@ -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 { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMessageProcessingRouter.java b/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMessageProcessingRouter.java index f5ec81462f..fbeb34a6b2 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMessageProcessingRouter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMessageProcessingRouter.java @@ -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 getChannelKeys(Message message) { Object result = this.messageProcessor.processMessage(message); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/splitter/AbstractMessageProcessingSplitter.java b/spring-integration-core/src/main/java/org/springframework/integration/splitter/AbstractMessageProcessingSplitter.java index bce1d9202c..ff2956a3ce 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/splitter/AbstractMessageProcessingSplitter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/splitter/AbstractMessageProcessingSplitter.java @@ -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> 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(); + } + } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/transformer/AbstractMessageProcessingTransformer.java b/spring-integration-core/src/main/java/org/springframework/integration/transformer/AbstractMessageProcessingTransformer.java index 3ea4796d75..ea0579cd81 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/transformer/AbstractMessageProcessingTransformer.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/transformer/AbstractMessageProcessingTransformer.java @@ -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); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/transformer/MessageTransformingHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/transformer/MessageTransformingHandler.java index d338d05725..cc93fe6555 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/transformer/MessageTransformingHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/transformer/MessageTransformingHandler.java @@ -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 { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java b/spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java index 5478285bc5..f453a2b2b7 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java @@ -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 extends AbstractExpressionEvaluator { +public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator implements Lifecycle { private static final String CANDIDATE_METHODS = "CANDIDATE_METHODS"; @@ -91,6 +95,7 @@ public class MessagingMethodInvokerHelper 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 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 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 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. diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/SplitterAnnotationPostProcessorTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/SplitterAnnotationPostProcessorTests.java index 5447a66565..b911404747 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/SplitterAnnotationPostProcessorTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/SplitterAnnotationPostProcessorTests.java @@ -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; + } + } } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests-context.xml index af2d32b8f7..0acd6e489d 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests-context.xml @@ -6,7 +6,7 @@ http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd"> - + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java index 6cfc9f9f2b..3eea09f86c 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java @@ -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("foo".getBytes()))); - assertTrue(this.bytesChannel.send(new GenericMessage>(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 message); + + String transform2(Message 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 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 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 diff --git a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.properties b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.properties index 579f83e22f..8efc0502b5 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.properties +++ b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.properties @@ -1,3 +1,3 @@ -message.history.tracked.components=input, publishedChannel, *AnnotationTestService* +message.history.tracked.components=input, publishedChannel, annotationTestService* poller.maxMessagesPerPoll=10 poller.interval=100 diff --git a/spring-integration-core/src/test/java/org/springframework/integration/endpoint/PollingLifecycleTests.java b/spring-integration-core/src/test/java/org/springframework/integration/endpoint/PollingLifecycleTests.java index 6bd72ce4cd..1c5fa06aef 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/endpoint/PollingLifecycleTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/endpoint/PollingLifecycleTests.java @@ -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() { + MethodInvokingMessageSource source = new MethodInvokingMessageSource(); + source.setObject(new Lifecycle() { @Override public void start() { @@ -195,12 +196,10 @@ public class PollingLifecycleTests { return false; } - @Override - public Message receive() { - return null; - } - }); + source.setMethodName("isRunning"); + + adapterFactory.setSource(source); SourcePollingChannelAdapter adapter = adapterFactory.getObject(); adapter.setTaskScheduler(this.taskScheduler); diff --git a/spring-integration-core/src/test/java/org/springframework/integration/filter/filterContextTests.xml b/spring-integration-core/src/test/java/org/springframework/integration/filter/FilterContextTests-context.xml similarity index 94% rename from spring-integration-core/src/test/java/org/springframework/integration/filter/filterContextTests.xml rename to spring-integration-core/src/test/java/org/springframework/integration/filter/FilterContextTests-context.xml index 7f6f573463..c73d1e7893 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/filter/filterContextTests.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/filter/FilterContextTests-context.xml @@ -13,7 +13,7 @@ - diff --git a/spring-integration-core/src/test/java/org/springframework/integration/filter/FilterContextTests.java b/spring-integration-core/src/test/java/org/springframework/integration/filter/FilterContextTests.java index 3bad236435..a8ac9183b0 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/filter/FilterContextTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/filter/FilterContextTests.java @@ -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("foo")); - Message reply = output.receive(0); + this.input.send(new GenericMessage("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("foobar")); - Message reply = output.receive(0); + this.input.send(new GenericMessage("foobar")); + Message reply = this.output.receive(0); assertEquals("foobar", reply.getPayload()); } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/filter/TestBean.java b/spring-integration-core/src/test/java/org/springframework/integration/filter/TestBean.java index 177b2d7ece..ce3381f9f9 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/filter/TestBean.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/filter/TestBean.java @@ -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; + } + } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/router/config/RouterWithMappingTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/router/config/RouterWithMappingTests-context.xml index 7321a6d514..d5230785cd 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/router/config/RouterWithMappingTests-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/router/config/RouterWithMappingTests-context.xml @@ -38,7 +38,7 @@ - diff --git a/spring-integration-core/src/test/java/org/springframework/integration/router/config/RouterWithMappingTests.java b/spring-integration-core/src/test/java/org/springframework/integration/router/config/RouterWithMappingTests.java index 8047ba6b38..03b5d5ae33 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/router/config/RouterWithMappingTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/router/config/RouterWithMappingTests.java @@ -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; + } + } } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/transformer/TestBean.java b/spring-integration-core/src/test/java/org/springframework/integration/transformer/TestBean.java index b9a2bd4b48..2f5f01afbe 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/transformer/TestBean.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/transformer/TestBean.java @@ -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; + } + } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/transformer/transformerContextTests.xml b/spring-integration-core/src/test/java/org/springframework/integration/transformer/TransformerContextTests-context.xml similarity index 91% rename from spring-integration-core/src/test/java/org/springframework/integration/transformer/transformerContextTests.xml rename to spring-integration-core/src/test/java/org/springframework/integration/transformer/TransformerContextTests-context.xml index 3c1da9a78d..169b77bd85 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/transformer/transformerContextTests.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/transformer/TransformerContextTests-context.xml @@ -13,7 +13,7 @@ - + @@ -26,7 +26,7 @@ - + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/transformer/TransformerContextTests.java b/spring-integration-core/src/test/java/org/springframework/integration/transformer/TransformerContextTests.java index 61d61bf4b0..3aa4ecc05b 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/transformer/TransformerContextTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/transformer/TransformerContextTests.java @@ -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("foo")); - Message reply = output.receive(0); + this.input.send(new GenericMessage("foo")); + Message reply = this.output.receive(0); assertEquals("FOO", reply.getPayload()); assertEquals(1, adviceCalled); - input = context.getBean("direct", MessageChannel.class); - input.send(new GenericMessage("foo")); - reply = output.receive(0); + this.direct.send(new GenericMessage("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("foo")); - reply = output.receive(0); + this.directRef.send(new GenericMessage("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 {