Added basic support for annotated endpoints.

This commit is contained in:
Mark Fisher
2007-12-11 07:33:06 +00:00
parent 0e9a93ef42
commit ec98fa35c4
13 changed files with 235 additions and 14 deletions

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.integration.annotation;
package org.springframework.integration.aop;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;

View File

@@ -23,7 +23,6 @@ import org.aopalliance.aop.Advice;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.integration.annotation.Publisher;
import org.springframework.integration.channel.ChannelMapping;
import org.springframework.util.Assert;

View File

@@ -25,7 +25,6 @@ import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.integration.annotation.Publisher;
import org.springframework.integration.channel.ChannelMapping;
import org.springframework.util.Assert;

View File

@@ -72,6 +72,10 @@ public class MessageBus implements ChannelMapping, ApplicationContextAware, Life
this.activateSubscriptions(applicationContext);
}
public void setAutoCreateChannels(boolean autoCreateChannels) {
this.autoCreateChannels = autoCreateChannels;
}
@SuppressWarnings("unchecked")
private void registerChannels(ApplicationContext context) {
Map<String, MessageChannel> channelBeans =

View File

@@ -17,6 +17,7 @@
package org.springframework.integration.endpoint;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.Ordered;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageMapper;
@@ -31,7 +32,7 @@ import org.springframework.util.Assert;
*
* @author Mark Fisher
*/
public class MessageHandlerAdapter<T> implements MessageHandler, InitializingBean {
public class MessageHandlerAdapter<T> implements MessageHandler, Ordered, InitializingBean {
private T object;
@@ -41,6 +42,8 @@ public class MessageHandlerAdapter<T> implements MessageHandler, InitializingBea
private SimpleMethodInvoker<T> invoker;
private int order = Integer.MAX_VALUE;
public void setObject(T object) {
Assert.notNull(object, "'object' must not be null");
@@ -52,6 +55,14 @@ public class MessageHandlerAdapter<T> implements MessageHandler, InitializingBea
this.method = method;
}
public void setOrder(int order) {
this.order = order;
}
public int getOrder() {
return this.order;
}
public void afterPropertiesSet() {
this.invoker = new SimpleMethodInvoker<T>(this.object, this.method);
}

View File

@@ -0,0 +1,155 @@
/*
* Copyright 2002-2007 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.endpoint.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.OrderComparator;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.integration.bus.ConsumerPolicy;
import org.springframework.integration.bus.MessageBus;
import org.springframework.integration.endpoint.GenericMessageEndpoint;
import org.springframework.integration.endpoint.InboundMethodInvokingChannelAdapter;
import org.springframework.integration.endpoint.MessageHandlerAdapter;
import org.springframework.integration.endpoint.OutboundMethodInvokingChannelAdapter;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.handler.MessageHandlerChain;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* An endpoint implementation for classes annotated with {@link MessageEndpoint @MessageEndpoint}.
*
* @author Mark Fisher
*/
public class AnnotationAwareMessageEndpoint extends GenericMessageEndpoint implements InitializingBean {
private Object targetObject;
private MessageBus messageBus;
public AnnotationAwareMessageEndpoint(Object targetObject, MessageBus messageBus) {
Assert.notNull(targetObject, "targetObject must not be null");
Assert.notNull(messageBus, "messageBus must not be null");
this.targetObject = targetObject;
this.messageBus = messageBus;
}
public void afterPropertiesSet() {
this.configureInputChannel();
this.configureDefaultOutputChannel();
this.createHandlerChain();
this.messageBus.registerEndpoint(ClassUtils.getShortNameAsProperty(targetObject.getClass()), this);
}
private void configureInputChannel() {
MessageEndpoint endpointAnnotation = this.targetObject.getClass().getAnnotation(MessageEndpoint.class);
String channelName = endpointAnnotation.input();
if (StringUtils.hasText(channelName)) {
this.setInputChannelName(channelName);
ConsumerPolicy consumerPolicy = new ConsumerPolicy();
consumerPolicy.setPeriod(endpointAnnotation.pollPeriod());
this.setConsumerPolicy(consumerPolicy);
}
else {
ReflectionUtils.doWithMethods(targetObject.getClass(), new ReflectionUtils.MethodCallback() {
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Annotation annotation = AnnotationUtils.getAnnotation(method, Polled.class);
if (annotation != null) {
InboundMethodInvokingChannelAdapter<Object> adapter =
new InboundMethodInvokingChannelAdapter<Object>();
adapter.setObject(targetObject);
adapter.setMethod(method.getName());
adapter.afterPropertiesSet();
String channelName = ClassUtils.getShortNameAsProperty(
targetObject.getClass()) + "-inputChannel";
messageBus.registerChannel(channelName, adapter);
setInputChannelName(channelName);
return;
}
}
});
}
}
private void configureDefaultOutputChannel() {
MessageEndpoint endpointAnnotation = this.targetObject.getClass().getAnnotation(MessageEndpoint.class);
String channelName = endpointAnnotation.defaultOutput();
if (StringUtils.hasText(channelName)) {
this.setDefaultOutputChannelName(channelName);
}
else {
ReflectionUtils.doWithMethods(targetObject.getClass(), new ReflectionUtils.MethodCallback() {
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Annotation annotation = AnnotationUtils.getAnnotation(method, DefaultOutput.class);
if (annotation != null) {
OutboundMethodInvokingChannelAdapter<Object> adapter =
new OutboundMethodInvokingChannelAdapter<Object>();
adapter.setObject(targetObject);
adapter.setMethod(method.getName());
adapter.afterPropertiesSet();
String channelName = ClassUtils.getShortNameAsProperty(
targetObject.getClass()) + "-defaultOutputChannel";
messageBus.registerChannel(channelName, adapter);
setDefaultOutputChannelName(channelName);
return;
}
}
});
}
}
@SuppressWarnings("unchecked")
private void createHandlerChain() {
final List<MessageHandlerAdapter<?>> handlers = new ArrayList<MessageHandlerAdapter<?>>();
ReflectionUtils.doWithMethods(targetObject.getClass(), new ReflectionUtils.MethodCallback() {
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Annotation annotation = AnnotationUtils.getAnnotation(method, Handler.class);
if (annotation != null) {
MessageHandlerAdapter<Object> adapter = new MessageHandlerAdapter<Object>();
adapter.setObject(targetObject);
adapter.setMethod(method.getName());
adapter.afterPropertiesSet();
Order orderAnnotation = (Order) AnnotationUtils.getAnnotation(method, Order.class);
if (orderAnnotation != null) {
adapter.setOrder(orderAnnotation.value());
}
handlers.add(adapter);
}
}
});
if (handlers.size() > 0) {
MessageHandlerChain handlerChain = new MessageHandlerChain();
Collections.sort(handlers, new OrderComparator());
for (MessageHandler handler : handlers) {
handlerChain.add(handler);
}
this.setHandler(handlerChain);
}
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.integration.annotation;
package org.springframework.integration.endpoint.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
@@ -36,6 +36,6 @@ import org.springframework.integration.message.Message;
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Target {
public @interface DefaultOutput {
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.integration.annotation;
package org.springframework.integration.endpoint.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.integration.annotation;
package org.springframework.integration.endpoint.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
@@ -37,8 +37,10 @@ import org.springframework.stereotype.Component;
@Component
public @interface MessageEndpoint {
String input();
String input() default "";
String output();
String defaultOutput() default "";
int pollPeriod() default 0;
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.integration.annotation;
package org.springframework.integration.endpoint.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
@@ -35,6 +35,8 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Source {
public @interface Polled {
int period() default 100;
}

View File

@@ -23,7 +23,6 @@ import static org.junit.Assert.assertNull;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.integration.annotation.Publisher;
import org.springframework.integration.channel.ChannelMapping;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.channel.PointToPointChannel;

View File

@@ -16,7 +16,6 @@
package org.springframework.integration.aop;
import org.springframework.integration.annotation.Publisher;
/**
* @author Mark Fisher

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2007 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.endpoint.annotation;
import org.junit.Test;
import org.springframework.integration.bus.MessageBus;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.message.DocumentMessage;
/**
* @author Mark Fisher
*/
public class AnnotationAwareMessageEndpointTests {
@Test
public void testSimpleHandler() throws InterruptedException {
MessageBus messageBus = new MessageBus();
messageBus.setAutoCreateChannels(true);
AnnotationAwareMessageEndpoint endpoint =
new AnnotationAwareMessageEndpoint(new SimpleEndpoint(), messageBus);
endpoint.afterPropertiesSet();
MessageChannel channel = messageBus.getChannel("testChannel");
messageBus.start();
endpoint.afterPropertiesSet();
channel.send(new DocumentMessage(1, "world"), 10);
}
@MessageEndpoint(input="testChannel", pollPeriod=10)
public class SimpleEndpoint {
@Handler
public void sayHello(String name) {
System.out.println("hello " + name);
}
}
}