Removed the @Poller annotation (since configuration metadata should be externalized). Updated ChannelAdapterAnnotationPostProcessor. Only outbound Channel Adapters can be configured with annotations now that @Poller is no longer available. We may add a "poller" attribute to the @ChannelAdapter for providing a reference. That would enable annotation-based inbound adapters. However, the XML support (the <inbound-channel-adapter/> element) is pretty trivial, so this should not be necessrary.Otherwise, the @ChannelAdapter may actually be removed altogether since a @ServiceActivator annotation can be used for any outbound Method (even when no return-value is expected).

This commit is contained in:
Mark Fisher
2008-11-25 20:02:13 +00:00
parent 0e5b4bcb50
commit c1741edf83
2 changed files with 14 additions and 96 deletions

View File

@@ -1,39 +0,0 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation that can be specified at method-level alongside a Message Endpoint
* annotation (e.g. @Splitter, @ChannelAdapter, etc.) in order to provide the
* polling metadata and scheduling information for that endpoint.
*
* @author Mark Fisher
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Poller {
}

View File

@@ -18,24 +18,16 @@ package org.springframework.integration.config.annotation;
import java.lang.reflect.Method;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.integration.annotation.ChannelAdapter;
import org.springframework.integration.annotation.Poller;
import org.springframework.integration.channel.BeanFactoryChannelResolver;
import org.springframework.integration.channel.ChannelResolutionException;
import org.springframework.integration.channel.ChannelResolver;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.SubscribableChannel;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.handler.MethodInvokingMessageHandler;
import org.springframework.integration.message.MethodInvokingMessageSource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -60,41 +52,21 @@ public class ChannelAdapterAnnotationPostProcessor implements MethodAnnotationPo
public Object postProcess(Object bean, String beanName, Method method, ChannelAdapter annotation) {
Assert.notNull(this.beanFactory, "BeanFactory must not be null");
AbstractEndpoint endpoint = null;
MessageChannel channel = this.resolveOrCreateChannel(annotation.value());
Poller pollerAnnotation = AnnotationUtils.findAnnotation(method, Poller.class);
if (method.getParameterTypes().length == 0 && hasReturnValue(method)) {
MethodInvokingMessageSource source = new MethodInvokingMessageSource();
source.setObject(bean);
source.setMethod(method);
endpoint = this.createInboundChannelAdapter(source, channel, pollerAnnotation);
}
else if (method.getParameterTypes().length > 0 && !hasReturnValue(method)) {
MethodInvokingMessageHandler handler = new MethodInvokingMessageHandler(bean, method);
endpoint = this.createOutboundChannelAdapter(channel, handler, pollerAnnotation);
}
else {
throw new IllegalArgumentException("The @ChannelAdapter can only be applied to methods"
+ " that accept no arguments but have a return value (inbound) or methods that"
+ " have no return value but do accept arguments (outbound).");
}
if (endpoint != null) {
String annotationName = ClassUtils.getShortNameAsProperty(annotation.annotationType());
String endpointName = beanName + "." + method.getName() + "." + annotationName;
this.beanFactory.registerSingleton(endpointName, endpoint);
// TODO: move this to IntegrationContextUtils?... common with MAPP
if (endpoint instanceof BeanFactoryAware) {
((BeanFactoryAware) endpoint).setBeanFactory(beanFactory);
}
if (endpoint instanceof InitializingBean) {
try {
((InitializingBean) endpoint).afterPropertiesSet();
}
catch (Exception e) {
throw new BeanInitializationException("failed to initialize annotated channel adapter", e);
}
}
}
Assert.isInstanceOf(SubscribableChannel.class, channel,
"The channel for an Annotation-based Channel Adapter must be a SubscribableChannel.");
Assert.isTrue(method.getParameterTypes().length > 0,
"A method annotated with @ChannelAdapter must accept at least one argument.");
Assert.isTrue(!hasReturnValue(method),
"A method annotated with @ChannelAdapter must not have a return value."
+ " Consider using a @ServiceActivator if a reply Message is expected.");
MethodInvokingMessageHandler handler = new MethodInvokingMessageHandler(bean, method);
EventDrivenConsumer endpoint = new EventDrivenConsumer((SubscribableChannel) channel, handler);
String annotationName = ClassUtils.getShortNameAsProperty(annotation.annotationType());
String endpointName = beanName + "." + method.getName() + "." + annotationName;
this.beanFactory.registerSingleton(endpointName, endpoint);
endpoint.setBeanFactory(beanFactory);
endpoint.afterPropertiesSet();
return bean;
}
@@ -110,21 +82,6 @@ public class ChannelAdapterAnnotationPostProcessor implements MethodAnnotationPo
}
}
private SourcePollingChannelAdapter createInboundChannelAdapter(MethodInvokingMessageSource source, MessageChannel channel, Poller pollerAnnotation) {
Assert.notNull(pollerAnnotation, "The @Poller annotation is required (at method-level) "
+ "when using the @ChannelAdapter annotation with a no-arg method.");
SourcePollingChannelAdapter adapter = new SourcePollingChannelAdapter();
adapter.setSource(source);
adapter.setOutputChannel(channel);
return adapter;
}
private AbstractEndpoint createOutboundChannelAdapter(MessageChannel channel, MethodInvokingMessageHandler handler, Poller pollerAnnotation) {
Assert.isInstanceOf(SubscribableChannel.class, channel,
"The input channel for an Annotation-based endpoint must be a SubscribableChannel.");
return new EventDrivenConsumer((SubscribableChannel) channel, handler);
}
private boolean hasReturnValue(Method method) {
return !method.getReturnType().equals(void.class);
}