Added @Router annotation and handler adapter

This commit is contained in:
Mark Fisher
2007-12-16 18:45:20 +00:00
parent b45d80a32e
commit 45b6cc85ca
3 changed files with 244 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
/*
* 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.handler.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;
/**
* Indicates that a method is capable of resolving to a channel or channel name
* based on a message, message payload, message attribute, or message property.
*
* @author Mark Fisher
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Router {
/**
* String value representing the name of the property that should be passed
* into the router method. This and 'attribute' should not both be provided.
*/
String property() default "";
/**
* String value representing the name of the attribute that should be passed
* into the router method. This and 'property' should not both be provided.
*/
String attribute() default "";
}

View File

@@ -0,0 +1,41 @@
/*
* 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.handler.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.springframework.integration.MessagingConfigurationException;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.router.RouterMessageHandlerAdapter;
/**
* A handler creator for methods annotation with {@link Router @Router}.
*
* @author Mark Fisher
*/
public class RouterAnnotationHandlerCreator extends AbstractAnnotationHandlerCreator {
public MessageHandler doCreateHandler(Object object, Method method, Annotation annotation) {
if (!annotation.annotationType().equals(Router.class)) {
throw new MessagingConfigurationException(
"RouterAnnotationHandlerCreator only applies to the @Router annotation");
}
return new RouterMessageHandlerAdapter(object, method, (Router) annotation);
}
}

View File

@@ -0,0 +1,153 @@
/*
* 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.router;
import java.lang.reflect.Method;
import java.util.Collection;
import org.springframework.integration.MessagingConfigurationException;
import org.springframework.integration.channel.ChannelMapping;
import org.springframework.integration.channel.ChannelMappingAware;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.endpoint.SimpleMethodInvoker;
import org.springframework.integration.handler.AbstractMessageHandlerAdapter;
import org.springframework.integration.handler.annotation.Router;
import org.springframework.integration.message.Message;
import org.springframework.util.StringUtils;
/**
* MessageHandler adapter for methods annotated with {@link Router @Router}.
*
* @author Mark Fisher
*/
public class RouterMessageHandlerAdapter extends AbstractMessageHandlerAdapter implements ChannelMappingAware {
private Router routerAnnotation;
private Method method;
private ChannelMapping channelMapping;
public RouterMessageHandlerAdapter(Object object, Method method, Router routerAnnotation) {
this.setObject(object);
this.method = method;
this.routerAnnotation = routerAnnotation;
}
public void setChannelMapping(ChannelMapping channelMapping) {
this.channelMapping = channelMapping;
}
@Override
protected Object doHandle(Message message, SimpleMethodInvoker invoker) {
if (method.getParameterTypes().length != 1) {
throw new MessagingConfigurationException(
"method must accept exactly one parameter");
}
String propertyName = routerAnnotation.property();
String attributeName = routerAnnotation.attribute();
Object retval = null;
if (StringUtils.hasText(propertyName)) {
if (StringUtils.hasText(attributeName)) {
throw new MessagingConfigurationException(
"cannot accept both 'property' and 'attribute'");
}
String property = message.getHeader().getProperty(propertyName);
retval = this.invokeMethod(invoker, property);
}
else if (StringUtils.hasText(attributeName)) {
Object attribute = message.getHeader().getAttribute(attributeName);
retval = this.invokeMethod(invoker, attribute);
}
else {
Class<?> type = method.getParameterTypes()[0];
if (type.equals(Message.class)) {
retval = this.invokeMethod(invoker, message);
}
retval = this.invokeMethod(invoker, message.getPayload());
}
if (retval != null) {
if (retval instanceof Collection) {
Collection<?> channels = (Collection<?>) retval;
for (Object channel : channels) {
if (channel instanceof MessageChannel) {
this.sendMessage(message, (MessageChannel) channel);
}
else if (channel instanceof String) {
this.sendMessage(message, (String) channel);
}
else {
throw new MessagingConfigurationException(
"router method must return type 'MessageChannel' or 'String'");
}
}
}
else if (retval instanceof MessageChannel[]) {
for (MessageChannel channel : (MessageChannel[]) retval) {
this.sendMessage(message, channel);
}
}
else if (retval instanceof String[]) {
for (String channelName : (String[]) retval) {
this.sendMessage(message, channelName);
}
}
else if (retval instanceof MessageChannel) {
this.sendMessage(message, (MessageChannel) retval);
}
else if (retval instanceof String) {
this.sendMessage(message, (String) retval);
}
else {
throw new MessagingConfigurationException(
"router method must return type 'MessageChannel' or 'String'");
}
}
return null;
}
private Object invokeMethod(SimpleMethodInvoker<?> invoker, Object parameter) {
if (this.logger.isDebugEnabled()) {
logger.debug("invoking method '" + method.getName() + "' with parameter of type '" +
parameter.getClass().getName() + "'");
}
return invoker.invokeMethod(parameter);
}
private boolean sendMessage(Message<?> message, String channelName) {
MessageChannel channel = this.channelMapping.getChannel(channelName);
if (channel == null) {
if (logger.isWarnEnabled()) {
logger.warn("unable to resolve channel for name '" + channelName + "'");
}
return false;
}
if (logger.isDebugEnabled()) {
logger.debug("sending message to channel '" + channelName + "'");
}
return this.sendMessage(message, channel);
}
private boolean sendMessage(Message<?> message, MessageChannel channel) {
if (logger.isDebugEnabled()) {
logger.debug("sending message to channel '" + channel + "'");
}
return channel.send(message);
}
}