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:
committed by
Gary Russell
parent
de2c6d3ea0
commit
6aaee67809
@@ -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",
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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 + "]");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
message.history.tracked.components=input, publishedChannel, *AnnotationTestService*
|
||||
message.history.tracked.components=input, publishedChannel, annotationTestService*
|
||||
poller.maxMessagesPerPoll=10
|
||||
poller.interval=100
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"/>
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user