Added support for @HeaderAttribute and @HeaderProperty parameter annotations (INT-192).
This commit is contained in:
@@ -1,93 +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.adapter;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.integration.handler.HandlerMethodInvoker;
|
||||
import org.springframework.integration.handler.MessageHandler;
|
||||
import org.springframework.integration.message.DefaultMessageCreator;
|
||||
import org.springframework.integration.message.DefaultMessageMapper;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageCreator;
|
||||
import org.springframework.integration.message.MessageMapper;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} that invokes the specified method on the provided object.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class MethodInvokingHandler implements MessageHandler, InitializingBean {
|
||||
|
||||
private volatile Object object;
|
||||
|
||||
private volatile String methodName;
|
||||
|
||||
private volatile MessageMapper messageMapper = new DefaultMessageMapper();
|
||||
|
||||
private volatile MessageCreator messageCreator = new DefaultMessageCreator();
|
||||
|
||||
protected volatile HandlerMethodInvoker<?> invoker;
|
||||
|
||||
private volatile boolean initialized;
|
||||
|
||||
private final Object initMonitor = new Object();
|
||||
|
||||
|
||||
public void setObject(Object object) {
|
||||
Assert.notNull(object, "'object' must not be null");
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public void setMethodName(String methodName) {
|
||||
Assert.notNull(methodName, "'methodName' must not be null");
|
||||
this.methodName = methodName;
|
||||
}
|
||||
|
||||
public void setMessageMapper(MessageMapper messageMapper) {
|
||||
Assert.notNull(messageMapper, "'messageMapper' must not be null");
|
||||
this.messageMapper = messageMapper;
|
||||
}
|
||||
|
||||
public void setMessageCreator(MessageCreator messageCreator) {
|
||||
Assert.notNull(messageCreator, "'messageCreator' must not be null");
|
||||
this.messageCreator = messageCreator;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
synchronized (this.initMonitor) {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
this.invoker = new HandlerMethodInvoker(this.object, this.methodName);
|
||||
this.initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Message<?> handle(Message<?> message) {
|
||||
if (!this.initialized) {
|
||||
this.afterPropertiesSet();
|
||||
}
|
||||
Object args = this.messageMapper.mapMessage(message);
|
||||
Object result = this.invoker.invokeMethod(args);
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
return this.messageCreator.createMessage(result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,15 +16,17 @@
|
||||
|
||||
package org.springframework.integration.adapter;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.handler.HandlerMethodInvoker;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessagingException;
|
||||
import org.springframework.integration.message.Source;
|
||||
import org.springframework.integration.util.MethodValidator;
|
||||
import org.springframework.integration.util.NameResolvingMethodInvoker;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -33,16 +35,16 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class MethodInvokingSource<T> implements Source<Object>, InitializingBean {
|
||||
public class MethodInvokingSource implements Source<Object>, InitializingBean {
|
||||
|
||||
private T object;
|
||||
private Object object;
|
||||
|
||||
private String method;
|
||||
|
||||
private HandlerMethodInvoker<T> invoker;
|
||||
private NameResolvingMethodInvoker invoker;
|
||||
|
||||
|
||||
public void setObject(T object) {
|
||||
public void setObject(Object object) {
|
||||
Assert.notNull(object, "'object' must not be null");
|
||||
this.object = object;
|
||||
}
|
||||
@@ -53,7 +55,7 @@ public class MethodInvokingSource<T> implements Source<Object>, InitializingBean
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
this.invoker = new HandlerMethodInvoker<T>(this.object, this.method);
|
||||
this.invoker = new NameResolvingMethodInvoker(this.object, this.method);
|
||||
this.invoker.setMethodValidator(new MessageReceivingMethodValidator());
|
||||
}
|
||||
|
||||
@@ -61,7 +63,15 @@ public class MethodInvokingSource<T> implements Source<Object>, InitializingBean
|
||||
if (this.invoker == null) {
|
||||
this.afterPropertiesSet();
|
||||
}
|
||||
return new GenericMessage<Object>(this.invoker.invokeMethod(new Object[] {}));
|
||||
try {
|
||||
return new GenericMessage<Object>(this.invoker.invokeMethod(new Object[] {}));
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new MessagingException(
|
||||
"Source method '" + this.method + "' threw an Exception.", e.getTargetException());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
throw new MessagingException("Failed to invoke source method '" + this.method + "'.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,35 +16,30 @@
|
||||
|
||||
package org.springframework.integration.adapter;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.handler.AbstractMessageHandlerAdapter;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessagingException;
|
||||
import org.springframework.integration.message.Target;
|
||||
import org.springframework.integration.util.MethodValidator;
|
||||
|
||||
/**
|
||||
* A messaging target that invokes the specified method on the provided object.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class MethodInvokingTarget extends MethodInvokingHandler implements Target {
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
super.afterPropertiesSet();
|
||||
this.invoker.setMethodValidator(new MethodValidator() {
|
||||
public void validate(Method method) throws Exception {
|
||||
if (!method.getReturnType().equals(void.class)) {
|
||||
throw new ConfigurationException("target method must have a void return");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
public class MethodInvokingTarget extends AbstractMessageHandlerAdapter implements Target {
|
||||
|
||||
public boolean send(Message<?> message) {
|
||||
this.handle(message);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Message<?> handleReturnValue(Object returnValue, Message<?> originalMessage) {
|
||||
if (returnValue != null) {
|
||||
throw new MessagingException(originalMessage, "The target method returned a non-null Object. " +
|
||||
"MethodInvokingTarget should only be used for methods that return no value (preferably void).");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ public class MessageEndpointAnnotationPostProcessor implements BeanPostProcessor
|
||||
int period = polledAnnotation.period();
|
||||
long initialDelay = polledAnnotation.initialDelay();
|
||||
boolean fixedRate = polledAnnotation.fixedRate();
|
||||
MethodInvokingSource<Object> source = new MethodInvokingSource<Object>();
|
||||
MethodInvokingSource source = new MethodInvokingSource();
|
||||
source.setObject(bean);
|
||||
source.setMethod(method.getName());
|
||||
SynchronousChannel channel = new SynchronousChannel();
|
||||
|
||||
@@ -16,48 +16,66 @@
|
||||
|
||||
package org.springframework.integration.handler;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.message.DefaultMessageCreator;
|
||||
import org.springframework.integration.message.DefaultMessageMapper;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageHeader;
|
||||
import org.springframework.integration.message.MessageCreator;
|
||||
import org.springframework.integration.message.MessageMapper;
|
||||
import org.springframework.integration.message.MessagingException;
|
||||
import org.springframework.integration.util.DefaultMethodInvoker;
|
||||
import org.springframework.integration.util.MethodInvoker;
|
||||
import org.springframework.integration.util.NameResolvingMethodInvoker;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Base implementation of the {@link MessageHandler} interface that creates an
|
||||
* invoker for the specified method and target object. It also accepts an
|
||||
* implementation of the {@link MessageMapper} strategy which it exposes to
|
||||
* subclasses for converting the {@link Message} to an object. Likewise, if the
|
||||
* method has a non-null return value, a reply message will be generated by the
|
||||
* mapper.
|
||||
* An implementation of the {@link MessageHandler} interface that invokes the specified method and target object. Either
|
||||
* a {@link Method} reference or a 'methodName' may be provided, but both are not necessary. In fact, while preference
|
||||
* is given to a {@link Method} reference if available, an Exception will be thrown if a non-matching 'methodName' has
|
||||
* also been provided. Therefore, to avoid such ambiguity, it is recommended to provide just one or the other.
|
||||
* <p>
|
||||
* This handler also accepts an implementation of the {@link MessageMapper} strategy interface which it uses for
|
||||
* converting from the {@link Message} being handled to an Object prior to invoking the method. Likewise, if the method
|
||||
* has a non-null return value, a reply message will be generated by the configured implementation of the
|
||||
* {@link MessageCreator} strategy interface. In both cases, the default implementations will simply consider the
|
||||
* message's payload.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public abstract class AbstractMessageHandlerAdapter<T> implements MessageHandler, Ordered, InitializingBean {
|
||||
public abstract class AbstractMessageHandlerAdapter implements MessageHandler, InitializingBean {
|
||||
|
||||
public static final String OUTPUT_CHANNEL_NAME_KEY = "outputChannelName";
|
||||
|
||||
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private volatile T object;
|
||||
private volatile Object object;
|
||||
|
||||
private volatile Method method;
|
||||
|
||||
private volatile String methodName;
|
||||
|
||||
private volatile HandlerMethodInvoker<T> invoker;
|
||||
private volatile boolean methodExpectsMessage;
|
||||
|
||||
private volatile int order = Integer.MAX_VALUE;
|
||||
private volatile MessageMapper messageMapper = new DefaultMessageMapper();
|
||||
|
||||
private volatile MessageCreator messageCreator = new DefaultMessageCreator();
|
||||
|
||||
protected volatile MethodInvoker invoker;
|
||||
|
||||
private volatile boolean initialized;
|
||||
|
||||
private final Object lifecycleMonitor = new Object();
|
||||
private final Object initializationMonitor = new Object();
|
||||
|
||||
|
||||
public void setObject(T object) {
|
||||
Assert.notNull(object, "'object' must not be null");
|
||||
public void setObject(Object object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
@@ -65,64 +83,112 @@ public abstract class AbstractMessageHandlerAdapter<T> implements MessageHandler
|
||||
return this.object;
|
||||
}
|
||||
|
||||
public void setMethod(Method method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
protected Method getMethod() {
|
||||
return this.method;
|
||||
}
|
||||
|
||||
public void setMethodName(String methodName) {
|
||||
Assert.notNull(methodName, "'methodName' must not be null");
|
||||
this.methodName = methodName;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
public void setMethodExpectsMessage(boolean methodExpectsMessage) {
|
||||
this.methodExpectsMessage = methodExpectsMessage;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
public void setMessageMapper(MessageMapper messageMapper) {
|
||||
Assert.notNull(messageMapper, "'messageMapper' must not be null");
|
||||
this.messageMapper = messageMapper;
|
||||
}
|
||||
|
||||
public final void afterPropertiesSet() {
|
||||
synchronized (this.lifecycleMonitor) {
|
||||
public void setMessageCreator(MessageCreator messageCreator) {
|
||||
Assert.notNull(messageCreator, "'messageCreator' must not be null");
|
||||
this.messageCreator = messageCreator;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
synchronized (this.initializationMonitor) {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
this.invoker = new HandlerMethodInvoker<T>(this.object, this.methodName);
|
||||
if (this.object == null) {
|
||||
throw new ConfigurationException("The target 'object' must not be null.");
|
||||
}
|
||||
if (this.method == null && this.methodName == null) {
|
||||
throw new ConfigurationException("Either a 'method' or 'methodName' is required.");
|
||||
}
|
||||
if (this.method != null) {
|
||||
if (this.methodName != null && !this.methodName.equals(this.method.getName())) {
|
||||
throw new ConfigurationException("An ambiguity exists between the 'method' and 'methodName' properties. " +
|
||||
"Note that only one of them is required, but if both are provided they must match.");
|
||||
}
|
||||
this.invoker = new DefaultMethodInvoker(this.object, this.method);
|
||||
}
|
||||
else {
|
||||
this.invoker = new NameResolvingMethodInvoker(this.object, this.methodName);
|
||||
}
|
||||
this.initialized = true;
|
||||
}
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
public final Message<?> handle(Message<?> message) {
|
||||
if (!this.initialized) {
|
||||
this.afterPropertiesSet();
|
||||
}
|
||||
Object result = this.doHandle(message, invoker);
|
||||
if (result != null) {
|
||||
Message<?> reply = (result instanceof Message) ? (Message<?>) result :
|
||||
this.createReplyMessage(result, message.getHeader());
|
||||
Object correlationId = reply.getHeader().getCorrelationId();
|
||||
if (correlationId == null) {
|
||||
Object orginalCorrelationId = message.getHeader().getCorrelationId();
|
||||
reply.getHeader().setCorrelationId((orginalCorrelationId != null) ?
|
||||
orginalCorrelationId : message.getId());
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override this method to provide additional initialization.
|
||||
* Subclasses may override this method for custom initialization requirements.
|
||||
*/
|
||||
protected void initialize() {
|
||||
}
|
||||
|
||||
protected Message<?> createReplyMessage(Object payload, MessageHeader originalMessageHeader) {
|
||||
return new GenericMessage<Object>(payload, originalMessageHeader);
|
||||
public Message<?> handle(Message<?> message) {
|
||||
if (message == null) {
|
||||
throw new IllegalArgumentException("message must not be null");
|
||||
}
|
||||
if (!this.initialized) {
|
||||
this.afterPropertiesSet();
|
||||
}
|
||||
Object args[] = null;
|
||||
Object mappingResult = (this.methodExpectsMessage) ? message : this.messageMapper.mapMessage(message);
|
||||
if (mappingResult.getClass().isArray()) {
|
||||
args = (Object[]) mappingResult;
|
||||
}
|
||||
else {
|
||||
args = new Object[] { mappingResult };
|
||||
}
|
||||
try {
|
||||
Object result = this.invoker.invokeMethod(args);
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
return this.handleReturnValue(result, message);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new MessagingException(
|
||||
"Handler method '" + this.method + "' threw an Exception.", e.getTargetException());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
throw new MessagingException("Failed to invoke handler method '" + this.method +
|
||||
"' with arguments: " + ObjectUtils.nullSafeToString(args), e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Message<?> createReplyMessage(Object returnValue, Message<?> originalMessage) {
|
||||
Message<?> reply = this.messageCreator.createMessage(returnValue);
|
||||
if (reply != null) {
|
||||
reply.copyHeader(originalMessage.getHeader(), false);
|
||||
Object correlationId = reply.getHeader().getCorrelationId();
|
||||
if (correlationId == null) {
|
||||
Object orginalCorrelationId = originalMessage.getHeader().getCorrelationId();
|
||||
reply.getHeader().setCorrelationId((orginalCorrelationId != null) ?
|
||||
orginalCorrelationId : originalMessage.getId());
|
||||
}
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses must implement this method. The invoker has been created for
|
||||
* the provided target object and method. May return an object of type
|
||||
* {@link Message}, else rely on the message mapper to convert.
|
||||
* Subclasses must implement this method to handle the return value.
|
||||
*/
|
||||
protected abstract Object doHandle(Message<?> message, HandlerMethodInvoker<T> invoker);
|
||||
protected abstract Message<?> handleReturnValue(Object returnValue, Message<?> originalMessage);
|
||||
|
||||
}
|
||||
|
||||
@@ -16,39 +16,20 @@
|
||||
|
||||
package org.springframework.integration.handler;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageCreator;
|
||||
|
||||
/**
|
||||
* An implementation of {@link MessageHandler} that invokes the specified method
|
||||
* on the provided target object. If {@link #shouldUseMapperOnInvocation} is set
|
||||
* to <code>true</code> (the default), it will use the provided
|
||||
* {@link org.springframework.integration.message.MessageMapper} strategy to
|
||||
* convert the inbound {@link Message} to an object that will be passed as the
|
||||
* method parameter. If the method has a non-null return value, a reply message
|
||||
* will be generated by the mapper.
|
||||
* An implementation of {@link MessageHandler} that invokes the specified method and target object.
|
||||
* It will use the provided implementation of the {@link MessageCreator} strategy interface to convert
|
||||
* the method invocation's return value to a reply Message.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class DefaultMessageHandlerAdapter<T> extends AbstractMessageHandlerAdapter<T> implements Ordered {
|
||||
public class DefaultMessageHandlerAdapter extends AbstractMessageHandlerAdapter {
|
||||
|
||||
private boolean expectsMessage = false;
|
||||
|
||||
/**
|
||||
* Specify whether the handler should pass the message when invoking the
|
||||
* target method. The default is <code>false</code> indicating that the
|
||||
* message's <em>payload</em> should be passed as the argument. To force
|
||||
* passing the {@link Message} directly, set this to <code>true</code>.
|
||||
*/
|
||||
public void setExpectsMessage(boolean expectsMessage) {
|
||||
this.expectsMessage = expectsMessage;
|
||||
}
|
||||
|
||||
public Object doHandle(Message message, HandlerMethodInvoker invoker) {
|
||||
if (this.expectsMessage) {
|
||||
return invoker.invokeMethod(message);
|
||||
}
|
||||
return invoker.invokeMethod(message.getPayload());
|
||||
protected Message<?> handleReturnValue(Object returnValue, Message<?> originalMessage) {
|
||||
return this.createReplyMessage(returnValue, originalMessage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,76 +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.handler;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import org.springframework.beans.support.ArgumentConvertingMethodInvoker;
|
||||
import org.springframework.integration.message.MessagingException;
|
||||
import org.springframework.integration.util.MethodValidator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MethodInvoker;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* A simple wrapper for {@link MethodInvoker}.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class HandlerMethodInvoker<T> {
|
||||
|
||||
private T object;
|
||||
|
||||
private String method;
|
||||
|
||||
private MethodValidator methodValidator;
|
||||
|
||||
|
||||
public HandlerMethodInvoker(T object, String method) {
|
||||
Assert.notNull(object, "'object' must not be null");
|
||||
Assert.notNull(method, "'method' must not be null");
|
||||
this.object = object;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public void setMethodValidator(MethodValidator methodValidator) {
|
||||
this.methodValidator = methodValidator;
|
||||
}
|
||||
|
||||
public Object invokeMethod(Object ... args) {
|
||||
try {
|
||||
MethodInvoker methodInvoker = new ArgumentConvertingMethodInvoker();
|
||||
methodInvoker.setTargetObject(this.object);
|
||||
methodInvoker.setTargetMethod(this.method);
|
||||
methodInvoker.setArguments(args);
|
||||
methodInvoker.prepare();
|
||||
methodInvoker.getPreparedMethod().setAccessible(true);
|
||||
if (this.methodValidator != null) {
|
||||
this.methodValidator.validate(methodInvoker.getPreparedMethod());
|
||||
}
|
||||
return methodInvoker.invoke();
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
throw new MessagingException(
|
||||
"Method '" + this.method + "' threw an Exception.", e.getTargetException());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
throw new MessagingException("Failed to invoke method '" + this.method +
|
||||
"' with arguments: " + ObjectUtils.nullSafeToString(args), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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.handler.annotation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageHandlingException;
|
||||
import org.springframework.integration.message.MessageHeader;
|
||||
import org.springframework.integration.message.MessageMapper;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class AnnotationMethodMessageMapper implements MessageMapper {
|
||||
|
||||
private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
private final Method method;
|
||||
|
||||
private MethodParameterMetadata[] parameterMetadata;
|
||||
|
||||
private volatile boolean initialized;
|
||||
|
||||
private final Object initializationMonitor = new Object();
|
||||
|
||||
|
||||
public AnnotationMethodMessageMapper(Method method) {
|
||||
Assert.notNull(method, "method must not be null");
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
|
||||
public void initialize() {
|
||||
synchronized (this.initializationMonitor) {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
Class<?>[] paramTypes = this.method.getParameterTypes();
|
||||
this.parameterMetadata = new MethodParameterMetadata[paramTypes.length];
|
||||
for (int i = 0; i < parameterMetadata.length; i++) {
|
||||
MethodParameter methodParam = new MethodParameter(this.method, i);
|
||||
methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);
|
||||
GenericTypeResolver.resolveParameterType(methodParam, this.method.getDeclaringClass());
|
||||
Object[] paramAnns = methodParam.getParameterAnnotations();
|
||||
String attributeName = null;
|
||||
String propertyName = null;
|
||||
for (int j = 0; j < paramAnns.length; j++) {
|
||||
Object paramAnn = paramAnns[j];
|
||||
if (HeaderAttribute.class.isInstance(paramAnn)) {
|
||||
HeaderAttribute headerAttribute = (HeaderAttribute) paramAnn;
|
||||
attributeName = this.resolveParameterNameIfNecessary(headerAttribute.value(), methodParam);
|
||||
parameterMetadata[i] = new MethodParameterMetadata(HeaderAttribute.class, attributeName, headerAttribute.required());
|
||||
}
|
||||
else if (HeaderProperty.class.isInstance(paramAnn)) {
|
||||
HeaderProperty headerProperty = (HeaderProperty) paramAnn;
|
||||
propertyName = this.resolveParameterNameIfNecessary(headerProperty.value(), methodParam);
|
||||
parameterMetadata[i] = new MethodParameterMetadata(HeaderProperty.class, propertyName, headerProperty.required());
|
||||
}
|
||||
}
|
||||
if (attributeName != null && propertyName != null) {
|
||||
throw new ConfigurationException("The @HeaderAttribute and @HeaderProperty annotations " +
|
||||
"are mutually exclusive. They should not both be provided on the same parameter.");
|
||||
}
|
||||
if (attributeName == null && propertyName == null) {
|
||||
parameterMetadata[i] = new MethodParameterMetadata(methodParam.getParameterType(), null, false);
|
||||
}
|
||||
}
|
||||
this.initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Object[] mapMessage(Message message) {
|
||||
if (message == null) {
|
||||
return null;
|
||||
}
|
||||
if (!this.initialized) {
|
||||
this.initialize();
|
||||
}
|
||||
Object[] args = new Object[this.parameterMetadata.length];
|
||||
for (int i = 0; i < this.parameterMetadata.length; i++) {
|
||||
MethodParameterMetadata metadata = this.parameterMetadata[i];
|
||||
Class<?> type = metadata.type;
|
||||
if (type.equals(HeaderAttribute.class)) {
|
||||
Object value = message.getHeader().getAttribute(metadata.key);
|
||||
if (value == null && metadata.required) {
|
||||
throw new MessageHandlingException(message,
|
||||
"required attribute '" + metadata.key + "' not available");
|
||||
}
|
||||
args[i] = value;
|
||||
}
|
||||
else if (type.equals(HeaderProperty.class)) {
|
||||
Object value = message.getHeader().getProperty(metadata.key);
|
||||
if (value == null && metadata.required) {
|
||||
throw new MessageHandlingException(message,
|
||||
"required property '" + metadata.key + "' not available");
|
||||
}
|
||||
args[i] = value;
|
||||
}
|
||||
else if (Message.class.isAssignableFrom(type)) {
|
||||
args[i] = message;
|
||||
}
|
||||
else if (Map.class.isAssignableFrom(type)) {
|
||||
args[i] = this.getHeaderAttributes(message);
|
||||
}
|
||||
else if (Properties.class.isAssignableFrom(type)) {
|
||||
args[i] = this.getHeaderProperties(message);
|
||||
}
|
||||
else {
|
||||
args[i] = message.getPayload();
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
private Map<String, Object> getHeaderAttributes(Message<?> message) {
|
||||
Map<String, Object> attributes = new HashMap<String, Object>();
|
||||
MessageHeader header = message.getHeader();
|
||||
Set<String> attributeNames = header.getAttributeNames();
|
||||
for (String name : attributeNames) {
|
||||
attributes.put(name, header.getAttribute(name));
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private Properties getHeaderProperties(Message<?> message) {
|
||||
Properties properties = new Properties();
|
||||
MessageHeader header = message.getHeader();
|
||||
Set<String> propertyNames = header.getPropertyNames();
|
||||
for (String name : propertyNames) {
|
||||
properties.setProperty(name, header.getProperty(name));
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
private String resolveParameterNameIfNecessary(String paramName, MethodParameter methodParam) {
|
||||
if (!StringUtils.hasText(paramName)) {
|
||||
paramName = methodParam.getParameterName();
|
||||
if (paramName == null) {
|
||||
throw new IllegalStateException("No parameter name specified and not available in class file.");
|
||||
}
|
||||
}
|
||||
return paramName;
|
||||
}
|
||||
|
||||
|
||||
private static class MethodParameterMetadata {
|
||||
|
||||
private final Class<?> type;
|
||||
|
||||
private final String key;
|
||||
|
||||
private final boolean required;
|
||||
|
||||
|
||||
MethodParameterMetadata(Class<?> type, String key, boolean required) {
|
||||
this.type = type;
|
||||
this.key = key;
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.handler.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation indicating that a method parameter's value should be
|
||||
* retrieved from an attribute in the message header. The value of
|
||||
* the annotation provides the attribute key, and the optional
|
||||
* 'required' property specifies whether the attribute value must
|
||||
* be available within the header.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
@Target(ElementType.PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface HeaderAttribute {
|
||||
|
||||
String value() default "";
|
||||
|
||||
boolean required() default true;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.handler.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation indicating that a method parameter's value should be
|
||||
* retrieved from a property in the message header. The value of
|
||||
* the annotation provides the property key, and the optional
|
||||
* 'required' property specifies whether the property value must
|
||||
* be available within the header.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
@Target(ElementType.PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface HeaderProperty {
|
||||
|
||||
String value() default "";
|
||||
|
||||
boolean required() default true;
|
||||
|
||||
}
|
||||
@@ -20,8 +20,6 @@ import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.handler.AbstractMessageHandlerAdapter;
|
||||
import org.springframework.integration.handler.MessageHandler;
|
||||
@@ -36,14 +34,10 @@ public abstract class AbstractMessageHandlerCreator implements MessageHandlerCre
|
||||
|
||||
public final MessageHandler createHandler(Object object, Method method, Map<String, ?> attributes) {
|
||||
MessageHandler handler = this.doCreateHandler(object, method, attributes);
|
||||
if (handler instanceof AbstractMessageHandlerAdapter<?>) {
|
||||
if (handler instanceof AbstractMessageHandlerAdapter) {
|
||||
AbstractMessageHandlerAdapter adapter = ((AbstractMessageHandlerAdapter) handler);
|
||||
adapter.setObject(object);
|
||||
adapter.setMethodName(method.getName());
|
||||
Order orderAnnotation = (Order) AnnotationUtils.getAnnotation(method, Order.class);
|
||||
if (orderAnnotation != null) {
|
||||
adapter.setOrder(orderAnnotation.value());
|
||||
}
|
||||
}
|
||||
if (handler instanceof InitializingBean) {
|
||||
try {
|
||||
|
||||
@@ -40,8 +40,8 @@ public class DefaultMessageHandlerCreator extends AbstractMessageHandlerCreator
|
||||
if (types.length != 1) {
|
||||
throw new ConfigurationException("exactly one method parameter is required");
|
||||
}
|
||||
DefaultMessageHandlerAdapter<Object> adapter = new DefaultMessageHandlerAdapter<Object>();
|
||||
adapter.setExpectsMessage(Message.class.isAssignableFrom(types[0]));
|
||||
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
|
||||
adapter.setMethodExpectsMessage(Message.class.isAssignableFrom(types[0]));
|
||||
return adapter;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ public class GenericMessage<T> implements Message<T> {
|
||||
*/
|
||||
public GenericMessage(T payload, MessageHeader headerToCopy) {
|
||||
this(payload);
|
||||
this.copyHeader(headerToCopy);
|
||||
this.copyHeader(headerToCopy, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,18 +100,39 @@ public class GenericMessage<T> implements Message<T> {
|
||||
return "[ID=" + this.id + "][Header=" + this.header + "][Payload='" + this.payload + "']";
|
||||
}
|
||||
|
||||
private void copyHeader(final MessageHeader headerToCopy) {
|
||||
public void copyHeader(final MessageHeader headerToCopy, boolean overrideExistingValues) {
|
||||
Set<String> propertyNames = headerToCopy.getPropertyNames();
|
||||
for (String key : propertyNames) {
|
||||
this.header.setProperty(key, headerToCopy.getProperty(key));
|
||||
if (overrideExistingValues) {
|
||||
this.header.setProperty(key, headerToCopy.getProperty(key));
|
||||
}
|
||||
else if (this.header.getProperty(key) == null) {
|
||||
this.header.setProperty(key, headerToCopy.getProperty(key));
|
||||
}
|
||||
}
|
||||
Set<String> attributeNames = headerToCopy.getAttributeNames();
|
||||
for (String key : attributeNames) {
|
||||
this.header.setAttribute(key, headerToCopy.getAttribute(key));
|
||||
if (overrideExistingValues) {
|
||||
this.header.setAttribute(key, headerToCopy.getAttribute(key));
|
||||
}
|
||||
else {
|
||||
this.header.setAttributeIfAbsent(key, headerToCopy.getAttribute(key));
|
||||
}
|
||||
}
|
||||
if (overrideExistingValues) {
|
||||
this.header.setSequenceNumber(headerToCopy.getSequenceNumber());
|
||||
this.header.setSequenceSize(headerToCopy.getSequenceSize());
|
||||
this.header.setReturnAddress(headerToCopy.getReturnAddress());
|
||||
}
|
||||
else {
|
||||
if (headerToCopy.getSequenceSize() > 1 && this.header.getSequenceSize() == 1) {
|
||||
this.header.setSequenceSize(headerToCopy.getSequenceSize());
|
||||
this.header.setSequenceNumber(headerToCopy.getSequenceNumber());
|
||||
}
|
||||
if (headerToCopy.getReturnAddress() != null && this.header.getReturnAddress() == null) {
|
||||
this.header.setReturnAddress(headerToCopy.getReturnAddress());
|
||||
}
|
||||
}
|
||||
this.header.setSequenceNumber(headerToCopy.getSequenceNumber());
|
||||
this.header.setSequenceSize(headerToCopy.getSequenceSize());
|
||||
this.header.setReturnAddress(headerToCopy.getReturnAddress());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,4 +33,6 @@ public interface Message<T> extends Serializable {
|
||||
|
||||
boolean isExpired();
|
||||
|
||||
void copyHeader(MessageHeader header, boolean overwriteExistingValues);
|
||||
|
||||
}
|
||||
|
||||
@@ -17,18 +17,10 @@
|
||||
package org.springframework.integration.router;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.handler.HandlerMethodInvoker;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Aggregator adapter for methods annotated with {@link org.springframework.integration.annotation.Aggregator @Aggregator}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.integration.router;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
@@ -23,8 +24,9 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.handler.HandlerMethodInvoker;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessagingException;
|
||||
import org.springframework.integration.util.DefaultMethodInvoker;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
@@ -36,7 +38,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
public abstract class MessageListMethodAdapter {
|
||||
|
||||
private final HandlerMethodInvoker<Object> invoker;
|
||||
private final DefaultMethodInvoker invoker;
|
||||
|
||||
protected volatile Method method;
|
||||
|
||||
@@ -49,31 +51,39 @@ public abstract class MessageListMethodAdapter {
|
||||
throw new ConfigurationException("Method '" + methodName +
|
||||
"(List<?> args)' not found on '" + object.getClass().getName() + "'.");
|
||||
}
|
||||
this.invoker = new HandlerMethodInvoker<Object>(object, this.method.getName());
|
||||
this.invoker = new DefaultMethodInvoker(object, this.method);
|
||||
}
|
||||
|
||||
public MessageListMethodAdapter(Object object, Method method) {
|
||||
Assert.notNull(object, "'object' must not be null");
|
||||
Assert.notNull(method, "'method' must not be null");
|
||||
if (method.getParameterTypes().length != 1 || !method.getParameterTypes()[0].equals(List.class)) {
|
||||
throw new ConfigurationException(
|
||||
"Method must accept exactly one parameter, and it must be a List.");
|
||||
throw new ConfigurationException("Method must accept exactly one parameter, and it must be a List.");
|
||||
}
|
||||
this.method = method;
|
||||
this.invoker = new HandlerMethodInvoker<Object>(object, this.method.getName());
|
||||
this.invoker = new DefaultMethodInvoker(object, this.method);
|
||||
}
|
||||
|
||||
|
||||
private static boolean isActualTypeParameterizedMessage(Method method) {
|
||||
return getCollectionActualType(method) instanceof ParameterizedType
|
||||
return (getCollectionActualType(method) instanceof ParameterizedType)
|
||||
&& Message.class.isAssignableFrom((Class<?>) ((ParameterizedType) getCollectionActualType(method)).getRawType());
|
||||
}
|
||||
|
||||
protected final Object executeMethod(List<Message<?>> messages) {
|
||||
if (isMethodParameterParameterized(this.method) && isHavingActualTypeArguments(this.method)
|
||||
&& (isActualTypeRawMessage(this.method) || isActualTypeParameterizedMessage(this.method))) {
|
||||
return this.invoker.invokeMethod(messages);
|
||||
try {
|
||||
if (isMethodParameterParameterized(this.method) && isHavingActualTypeArguments(this.method)
|
||||
&& (isActualTypeRawMessage(this.method) || isActualTypeParameterizedMessage(this.method))) {
|
||||
return this.invoker.invokeMethod(messages);
|
||||
}
|
||||
return this.invoker.invokeMethod(extractPayloadsFromMessages(messages));
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new MessagingException(
|
||||
"Method '" + this.method + "' threw an Exception.", e.getTargetException());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
throw new MessagingException("Failed to invoke method '" + this.method + "'.");
|
||||
}
|
||||
return this.invoker.invokeMethod(extractPayloadsFromMessages(messages));
|
||||
}
|
||||
|
||||
private List<?> extractPayloadsFromMessages(List<Message<?>> messages) {
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.integration.router;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.annotation.Router;
|
||||
@@ -26,11 +25,8 @@ import org.springframework.integration.channel.ChannelRegistry;
|
||||
import org.springframework.integration.channel.ChannelRegistryAware;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.handler.AbstractMessageHandlerAdapter;
|
||||
import org.springframework.integration.handler.HandlerMethodInvoker;
|
||||
import org.springframework.integration.handler.annotation.AnnotationMethodMessageMapper;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageHandlingException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* MessageHandler adapter for methods annotated with {@link Router @Router}.
|
||||
@@ -39,28 +35,21 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class RouterMessageHandlerAdapter extends AbstractMessageHandlerAdapter implements ChannelRegistryAware {
|
||||
|
||||
private static final String PROPERTY_KEY = "property";
|
||||
|
||||
private static final String ATTRIBUTE_KEY = "attribute";
|
||||
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final Map<String, ?> attributes;
|
||||
|
||||
private volatile ChannelRegistry channelRegistry;
|
||||
|
||||
|
||||
public RouterMessageHandlerAdapter(Object object, Method method, Map<String, ?> attributes) {
|
||||
Assert.notNull(object, "'object' must not be null");
|
||||
Assert.notNull(method, "'method' must not be null");
|
||||
Assert.notNull(attributes, "'attributes' must not be null");
|
||||
public RouterMessageHandlerAdapter(Object object, Method method) {
|
||||
this.setObject(object);
|
||||
this.setMethodName(method.getName());
|
||||
this.method = method;
|
||||
this.attributes = attributes;
|
||||
this.setMethod(method);
|
||||
if (method.getParameterTypes().length < 1) {
|
||||
throw new ConfigurationException("The router method must accept at least one argument.");
|
||||
}
|
||||
if (method.getParameterTypes()[0].equals(Message.class)) {
|
||||
this.setMethodExpectsMessage(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setChannelRegistry(ChannelRegistry channelRegistry) {
|
||||
this.channelRegistry = channelRegistry;
|
||||
}
|
||||
@@ -71,55 +60,20 @@ public class RouterMessageHandlerAdapter extends AbstractMessageHandlerAdapter i
|
||||
if (target != null && this.channelRegistry != null && (target instanceof ChannelRegistryAware)) {
|
||||
((ChannelRegistryAware) target).setChannelRegistry(this.channelRegistry);
|
||||
}
|
||||
this.setMessageMapper(new AnnotationMethodMessageMapper(this.getMethod()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doHandle(Message message, HandlerMethodInvoker invoker) {
|
||||
if (method.getParameterTypes().length != 1) {
|
||||
throw new ConfigurationException(
|
||||
"method must accept exactly one parameter");
|
||||
}
|
||||
String propertyName = (String) attributes.get(PROPERTY_KEY);
|
||||
String attributeName = (String) attributes.get(ATTRIBUTE_KEY);
|
||||
Object retval = null;
|
||||
if (StringUtils.hasText(propertyName)) {
|
||||
if (StringUtils.hasText(attributeName)) {
|
||||
throw new ConfigurationException(
|
||||
"cannot accept both 'property' and 'attribute'");
|
||||
}
|
||||
String property = message.getHeader().getProperty(propertyName);
|
||||
if (!StringUtils.hasText(property)) {
|
||||
throw new MessageHandlingException(message,
|
||||
"no '" + propertyName + "' property available for router method");
|
||||
}
|
||||
retval = this.invokeMethod(invoker, property);
|
||||
}
|
||||
else if (StringUtils.hasText(attributeName)) {
|
||||
Object attribute = message.getHeader().getAttribute(attributeName);
|
||||
if (attribute == null) {
|
||||
throw new MessageHandlingException(message,
|
||||
"no '" + attributeName + "' attribute available for router method");
|
||||
}
|
||||
retval = this.invokeMethod(invoker, attribute);
|
||||
}
|
||||
else {
|
||||
Class<?> type = method.getParameterTypes()[0];
|
||||
if (type.equals(Message.class)) {
|
||||
retval = this.invokeMethod(invoker, message);
|
||||
}
|
||||
else {
|
||||
retval = this.invokeMethod(invoker, message.getPayload());
|
||||
}
|
||||
}
|
||||
if (retval != null) {
|
||||
if (retval instanceof Collection) {
|
||||
Collection<?> channels = (Collection<?>) retval;
|
||||
protected Message<?> handleReturnValue(Object returnValue, Message<?> originalMessage) {
|
||||
if (returnValue != null) {
|
||||
if (returnValue instanceof Collection) {
|
||||
Collection<?> channels = (Collection<?>) returnValue;
|
||||
for (Object channel : channels) {
|
||||
if (channel instanceof MessageChannel) {
|
||||
this.sendMessage(message, (MessageChannel) channel);
|
||||
this.sendMessage(originalMessage, (MessageChannel) channel);
|
||||
}
|
||||
else if (channel instanceof String) {
|
||||
this.sendMessage(message, (String) channel);
|
||||
this.sendMessage(originalMessage, (String) channel);
|
||||
}
|
||||
else {
|
||||
throw new ConfigurationException(
|
||||
@@ -127,21 +81,21 @@ public class RouterMessageHandlerAdapter extends AbstractMessageHandlerAdapter i
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (retval instanceof MessageChannel[]) {
|
||||
for (MessageChannel channel : (MessageChannel[]) retval) {
|
||||
this.sendMessage(message, channel);
|
||||
else if (returnValue instanceof MessageChannel[]) {
|
||||
for (MessageChannel channel : (MessageChannel[]) returnValue) {
|
||||
this.sendMessage(originalMessage, channel);
|
||||
}
|
||||
}
|
||||
else if (retval instanceof String[]) {
|
||||
for (String channelName : (String[]) retval) {
|
||||
this.sendMessage(message, channelName);
|
||||
else if (returnValue instanceof String[]) {
|
||||
for (String channelName : (String[]) returnValue) {
|
||||
this.sendMessage(originalMessage, channelName);
|
||||
}
|
||||
}
|
||||
else if (retval instanceof MessageChannel) {
|
||||
this.sendMessage(message, (MessageChannel) retval);
|
||||
else if (returnValue instanceof MessageChannel) {
|
||||
this.sendMessage(originalMessage, (MessageChannel) returnValue);
|
||||
}
|
||||
else if (retval instanceof String) {
|
||||
this.sendMessage(message, (String) retval);
|
||||
else if (returnValue instanceof String) {
|
||||
this.sendMessage(originalMessage, (String) returnValue);
|
||||
}
|
||||
else {
|
||||
throw new ConfigurationException(
|
||||
@@ -151,14 +105,6 @@ public class RouterMessageHandlerAdapter extends AbstractMessageHandlerAdapter i
|
||||
return null;
|
||||
}
|
||||
|
||||
private Object invokeMethod(HandlerMethodInvoker<?> 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.channelRegistry.lookupChannel(channelName);
|
||||
if (channel == null) {
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.integration.router;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.annotation.Splitter;
|
||||
@@ -26,9 +25,7 @@ import org.springframework.integration.channel.ChannelRegistry;
|
||||
import org.springframework.integration.channel.ChannelRegistryAware;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.handler.AbstractMessageHandlerAdapter;
|
||||
import org.springframework.integration.handler.HandlerMethodInvoker;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageHeader;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -37,9 +34,7 @@ import org.springframework.util.Assert;
|
||||
* @author Mark Fisher
|
||||
* @author Marius Bogoevici
|
||||
*/
|
||||
public class SplitterMessageHandlerAdapter<T> extends AbstractMessageHandlerAdapter<T> implements ChannelRegistryAware {
|
||||
|
||||
private final Method method;
|
||||
public class SplitterMessageHandlerAdapter extends AbstractMessageHandlerAdapter implements ChannelRegistryAware {
|
||||
|
||||
private final String outputChannelName;
|
||||
|
||||
@@ -48,17 +43,20 @@ public class SplitterMessageHandlerAdapter<T> extends AbstractMessageHandlerAdap
|
||||
private volatile long sendTimeout = -1;
|
||||
|
||||
|
||||
public SplitterMessageHandlerAdapter(T object, Method method, Map<String, ?> attributes) {
|
||||
Assert.notNull(object, "'object' must not be null");
|
||||
Assert.notNull(method, "'method' must not be null");
|
||||
Assert.isTrue(attributes != null && attributes.get(OUTPUT_CHANNEL_NAME_KEY) != null,
|
||||
"The '" + OUTPUT_CHANNEL_NAME_KEY + "' attribute is required.");
|
||||
public SplitterMessageHandlerAdapter(Object object, Method method, String outputChannelName) {
|
||||
Assert.hasText(outputChannelName, "output channel name is required");
|
||||
this.setObject(object);
|
||||
this.setMethodName(method.getName());
|
||||
this.method = method;
|
||||
this.outputChannelName = (String) attributes.get(OUTPUT_CHANNEL_NAME_KEY);
|
||||
this.setMethod(method);
|
||||
this.outputChannelName = outputChannelName;
|
||||
if (method.getParameterTypes().length < 1) {
|
||||
throw new ConfigurationException("The splitter method must accept at least one argument.");
|
||||
}
|
||||
if (method.getParameterTypes()[0].equals(Message.class)) {
|
||||
this.setMethodExpectsMessage(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setChannelRegistry(ChannelRegistry channelRegistry) {
|
||||
this.channelRegistry = channelRegistry;
|
||||
}
|
||||
@@ -68,45 +66,32 @@ public class SplitterMessageHandlerAdapter<T> extends AbstractMessageHandlerAdap
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final Object doHandle(Message<?> message, HandlerMethodInvoker<T> invoker) {
|
||||
final MessageHeader originalMessageHeader = message.getHeader();
|
||||
if (method.getParameterTypes().length != 1) {
|
||||
throw new ConfigurationException(
|
||||
"Splitter method must accept exactly one parameter");
|
||||
}
|
||||
Object retval = null;
|
||||
Class<?> type = method.getParameterTypes()[0];
|
||||
if (type.equals(Message.class)) {
|
||||
retval = invoker.invokeMethod(message);
|
||||
}
|
||||
else {
|
||||
retval = invoker.invokeMethod(message.getPayload());
|
||||
}
|
||||
if (retval == null) {
|
||||
protected final Message<?> handleReturnValue(Object returnValue, Message<?> originalMessage) {
|
||||
if (returnValue == null) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Splitter method '" + this.method.getName() + "' returned null");
|
||||
logger.warn("Splitter method returned null.");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (retval instanceof Collection) {
|
||||
Collection<?> items = (Collection<?>) retval;
|
||||
if (returnValue instanceof Collection) {
|
||||
Collection<?> items = (Collection<?>) returnValue;
|
||||
int sequenceNumber = 0;
|
||||
int sequenceSize = items.size();
|
||||
for (Object item : items) {
|
||||
Message<?> splitMessage = (item instanceof Message<?>) ? (Message<?>) item :
|
||||
this.createReplyMessage(item, originalMessageHeader);
|
||||
this.prepareMessage(splitMessage, message.getId(), ++sequenceNumber, sequenceSize);
|
||||
Message<?> splitMessage = (item instanceof Message<?>) ?
|
||||
(Message<?>) item : this.createReplyMessage(item, originalMessage);
|
||||
this.prepareMessage(splitMessage, originalMessage.getId(), ++sequenceNumber, sequenceSize);
|
||||
this.sendMessage(splitMessage, this.outputChannelName);
|
||||
}
|
||||
}
|
||||
else if (retval.getClass().isArray()) {
|
||||
Object[] array = (Object[]) retval;
|
||||
else if (returnValue.getClass().isArray()) {
|
||||
Object[] array = (Object[]) returnValue;
|
||||
int sequenceNumber = 0;
|
||||
int sequenceSize = array.length;
|
||||
for (Object item : array) {
|
||||
Message<?> splitMessage = (item instanceof Message<?>) ? (Message<?>) item :
|
||||
this.createReplyMessage(item, originalMessageHeader);
|
||||
this.prepareMessage(splitMessage, message.getId(), ++sequenceNumber, sequenceSize);
|
||||
Message<?> splitMessage = (item instanceof Message<?>) ?
|
||||
(Message<?>) item : this.createReplyMessage(item, originalMessage);
|
||||
this.prepareMessage(splitMessage, originalMessage.getId(), ++sequenceNumber, sequenceSize);
|
||||
this.sendMessage(splitMessage, this.outputChannelName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import org.springframework.integration.router.RouterMessageHandlerAdapter;
|
||||
public class RouterMessageHandlerCreator extends AbstractMessageHandlerCreator {
|
||||
|
||||
public MessageHandler doCreateHandler(Object object, Method method, Map<String, ?> attributes) {
|
||||
return new RouterMessageHandlerAdapter(object, method, attributes);
|
||||
return new RouterMessageHandlerAdapter(object, method);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.integration.router.config;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.integration.handler.AbstractMessageHandlerAdapter;
|
||||
import org.springframework.integration.handler.MessageHandler;
|
||||
import org.springframework.integration.handler.config.AbstractMessageHandlerCreator;
|
||||
import org.springframework.integration.router.SplitterMessageHandlerAdapter;
|
||||
@@ -31,6 +32,8 @@ import org.springframework.integration.router.SplitterMessageHandlerAdapter;
|
||||
public class SplitterMessageHandlerCreator extends AbstractMessageHandlerCreator {
|
||||
|
||||
public MessageHandler doCreateHandler(Object object, Method method, Map<String, ?> attributes) {
|
||||
return new SplitterMessageHandlerAdapter(object, method, attributes);
|
||||
String outputChannelName = (String) attributes.get(AbstractMessageHandlerAdapter.OUTPUT_CHANNEL_NAME_KEY);
|
||||
return new SplitterMessageHandlerAdapter(object, method, outputChannelName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.SimpleTypeConverter;
|
||||
import org.springframework.beans.TypeConverter;
|
||||
import org.springframework.beans.TypeMismatchException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Implementation of {@link MethodInvoker} to be used when the actual {@link Method} reference is known.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class DefaultMethodInvoker implements MethodInvoker {
|
||||
|
||||
private final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private final Object object;
|
||||
|
||||
private final Method method;
|
||||
|
||||
private volatile TypeConverter typeConverter;
|
||||
|
||||
|
||||
public DefaultMethodInvoker(Object object, Method method) {
|
||||
Assert.notNull(object, "object must not be null");
|
||||
Assert.notNull(method, "method must not be null");
|
||||
this.object = object;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
|
||||
public void setTypeConverter(TypeConverter typeConverter) {
|
||||
this.typeConverter = typeConverter;
|
||||
}
|
||||
|
||||
protected TypeConverter getTypeConverter() {
|
||||
if (this.typeConverter == null) {
|
||||
this.typeConverter = new SimpleTypeConverter();
|
||||
}
|
||||
return this.typeConverter;
|
||||
}
|
||||
|
||||
public Object invokeMethod(Object ... args) throws Exception {
|
||||
TypeConverter converter = getTypeConverter();
|
||||
int argCount = args.length;
|
||||
Class<?>[] paramTypes = this.method.getParameterTypes();
|
||||
if (paramTypes.length != argCount) {
|
||||
throw new IllegalArgumentException("Wrong number of arguments. Expected types " +
|
||||
ObjectUtils.nullSafeToString(paramTypes) + ", but received values " +
|
||||
ObjectUtils.nullSafeToString(args) + ".");
|
||||
}
|
||||
Object[] convertedArgs = new Object[argCount];
|
||||
boolean match = true;
|
||||
for (int i = 0; i < argCount && match; i++) {
|
||||
try {
|
||||
convertedArgs[i] = converter.convertIfNecessary(args[i], paramTypes[i]);
|
||||
}
|
||||
catch (TypeMismatchException e) {
|
||||
throw new IllegalArgumentException("Failed to convert argument type.", e);
|
||||
}
|
||||
}
|
||||
this.method.setAccessible(true);
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
logger.debug("invoking method '" + this.method.getName() + "' with arguments " + ObjectUtils.nullSafeToString(convertedArgs));
|
||||
}
|
||||
return this.method.invoke(this.object, convertedArgs);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
/**
|
||||
* A strategy interface for invoking a method.
|
||||
* Typically used by adapters.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public interface MethodInvoker {
|
||||
|
||||
Object invokeMethod(Object ... args) throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import org.springframework.beans.support.ArgumentConvertingMethodInvoker;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Implementation of {@link MethodInvoker} to be used when only the method name is known.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class NameResolvingMethodInvoker implements MethodInvoker {
|
||||
|
||||
private final Object object;
|
||||
|
||||
private final String methodName;
|
||||
|
||||
private volatile MethodValidator methodValidator;
|
||||
|
||||
|
||||
public NameResolvingMethodInvoker(Object object, String methodName) {
|
||||
Assert.notNull(object, "'object' must not be null");
|
||||
Assert.notNull(methodName, "'methodName' must not be null");
|
||||
this.object = object;
|
||||
this.methodName = methodName;
|
||||
}
|
||||
|
||||
|
||||
public void setMethodValidator(MethodValidator methodValidator) {
|
||||
this.methodValidator = methodValidator;
|
||||
}
|
||||
|
||||
public Object invokeMethod(Object ... args) throws Exception {
|
||||
ArgumentConvertingMethodInvoker invoker = new ArgumentConvertingMethodInvoker();
|
||||
invoker.setTargetObject(this.object);
|
||||
invoker.setTargetMethod(this.methodName);
|
||||
invoker.setArguments(args);
|
||||
invoker.prepare();
|
||||
invoker.getPreparedMethod().setAccessible(true);
|
||||
if (this.methodValidator != null) {
|
||||
this.methodValidator.validate(invoker.getPreparedMethod());
|
||||
}
|
||||
return invoker.invoke();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,7 +31,7 @@ public class MethodInvokingSourceTests {
|
||||
|
||||
@Test
|
||||
public void testValidMethod() {
|
||||
MethodInvokingSource<TestBean> source = new MethodInvokingSource<TestBean>();
|
||||
MethodInvokingSource source = new MethodInvokingSource();
|
||||
source.setObject(new TestBean());
|
||||
source.setMethod("validMethod");
|
||||
Message<?> result = source.receive();
|
||||
@@ -42,7 +42,7 @@ public class MethodInvokingSourceTests {
|
||||
|
||||
@Test(expected=MessagingException.class)
|
||||
public void testNoMatchingMethodName() {
|
||||
MethodInvokingSource<TestBean> source = new MethodInvokingSource<TestBean>();
|
||||
MethodInvokingSource source = new MethodInvokingSource();
|
||||
source.setObject(new TestBean());
|
||||
source.setMethod("noMatchingMethod");
|
||||
source.receive();
|
||||
@@ -50,7 +50,7 @@ public class MethodInvokingSourceTests {
|
||||
|
||||
@Test(expected=MessagingException.class)
|
||||
public void testInvalidMethodWithArg() {
|
||||
MethodInvokingSource<TestBean> source = new MethodInvokingSource<TestBean>();
|
||||
MethodInvokingSource source = new MethodInvokingSource();
|
||||
source.setObject(new TestBean());
|
||||
source.setMethod("invalidMethodWithArg");
|
||||
source.receive();
|
||||
@@ -58,7 +58,7 @@ public class MethodInvokingSourceTests {
|
||||
|
||||
@Test(expected=MessagingException.class)
|
||||
public void testInvalidMethodWithNoReturnValue() {
|
||||
MethodInvokingSource<TestBean> source = new MethodInvokingSource<TestBean>();
|
||||
MethodInvokingSource source = new MethodInvokingSource();
|
||||
source.setObject(new TestBean());
|
||||
source.setMethod("invalidMethodWithNoReturnValue");
|
||||
source.receive();
|
||||
|
||||
@@ -23,18 +23,19 @@ import java.util.List;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.handler.HandlerMethodInvoker;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.router.AggregatingMessageHandler;
|
||||
import org.springframework.integration.router.CompletionStrategy;
|
||||
import org.springframework.integration.router.CompletionStrategyAdapter;
|
||||
import org.springframework.integration.util.MethodInvoker;
|
||||
|
||||
/**
|
||||
* @author Marius Bogoevici
|
||||
@@ -43,9 +44,10 @@ public class AggregatorParserTests {
|
||||
|
||||
private ApplicationContext context;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
context = new ClassPathXmlApplicationContext("aggregatorParserTests.xml", this.getClass());
|
||||
this.context = new ClassPathXmlApplicationContext("aggregatorParserTests.xml", this.getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -110,27 +112,27 @@ public class AggregatorParserTests {
|
||||
addingAggregator.handle(message);
|
||||
}
|
||||
MessageChannel replyChannel = (MessageChannel) context.getBean("replyChannel");
|
||||
Message response = replyChannel.receive();
|
||||
Message<?> response = replyChannel.receive();
|
||||
Assert.assertEquals(6l, response.getPayload());
|
||||
}
|
||||
|
||||
|
||||
@Test(expected=BeanCreationException.class)
|
||||
public void testMissingMethodOnAggregator() {
|
||||
context = new ClassPathXmlApplicationContext("invalidMethodNameAggregator.xml", this.getClass());
|
||||
}
|
||||
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void testDuplicateCompletionStrategyDefinition() {
|
||||
context = new ClassPathXmlApplicationContext("completionStrategyMethodWithMissingReference.xml", this.getClass());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAggregatorWithPojoCompletionStrategy(){
|
||||
AggregatingMessageHandler aggregatorWithPojoCompletionStrategy = (AggregatingMessageHandler) context.getBean("aggregatorWithPojoCompletionStrategy");
|
||||
CompletionStrategy completionStrategy = (CompletionStrategy)new DirectFieldAccessor(aggregatorWithPojoCompletionStrategy).getPropertyValue("completionStrategy");
|
||||
Assert.assertTrue(completionStrategy instanceof CompletionStrategyAdapter);
|
||||
DirectFieldAccessor completionStrategyAccessor = new DirectFieldAccessor(completionStrategy);
|
||||
HandlerMethodInvoker<?> invoker = (HandlerMethodInvoker<?>)completionStrategyAccessor.getPropertyValue("invoker");
|
||||
MethodInvoker invoker = (MethodInvoker) completionStrategyAccessor.getPropertyValue("invoker");
|
||||
Assert.assertTrue(new DirectFieldAccessor(invoker).getPropertyValue("object") instanceof MaxValueCompletionStrategy);
|
||||
Assert.assertTrue(((Method)completionStrategyAccessor.getPropertyValue("method")).getName().equals("checkCompleteness"));
|
||||
|
||||
@@ -145,12 +147,13 @@ public class AggregatorParserTests {
|
||||
Assert.assertNotNull(reply);
|
||||
Assert.assertEquals(11l, reply.getPayload());
|
||||
}
|
||||
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void testAggregatorWithDuplicateCompletionStrategy() {
|
||||
context = new ClassPathXmlApplicationContext("duplicateCompletionStrategy.xml", this.getClass());
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static <T> Message<T> createMessage(T payload, Object correlationId, int sequenceSize, int sequenceNumber,
|
||||
MessageChannel replyChannel) {
|
||||
GenericMessage<T> message = new GenericMessage<T>(payload);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.integration.config;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
@@ -31,6 +32,9 @@ import org.springframework.integration.handler.MessageHandlerChain;
|
||||
import org.springframework.integration.router.AggregatingMessageHandler;
|
||||
import org.springframework.integration.router.CompletionStrategyAdapter;
|
||||
|
||||
/**
|
||||
* @author Marius Bogoevici
|
||||
*/
|
||||
public class CompletionStrategyAnnotationTests {
|
||||
|
||||
@Test
|
||||
@@ -44,7 +48,8 @@ public class CompletionStrategyAnnotationTests {
|
||||
DirectFieldAccessor invokerAccessor = new DirectFieldAccessor(new DirectFieldAccessor(
|
||||
aggregatingMessageHandlerAccessor.getPropertyValue("completionStrategy")).getPropertyValue("invoker"));
|
||||
Assert.assertSame(context.getBean(endpointName), invokerAccessor.getPropertyValue("object"));
|
||||
Assert.assertEquals("completionChecker", invokerAccessor.getPropertyValue("method"));
|
||||
Method completionCheckerMethod = (Method) invokerAccessor.getPropertyValue("method");
|
||||
Assert.assertEquals("completionChecker", completionCheckerMethod.getName());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -19,16 +19,12 @@ package org.springframework.integration.handler;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.integration.channel.ChannelRegistry;
|
||||
import org.springframework.integration.channel.DefaultChannelRegistry;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
import org.springframework.integration.router.SplitterMessageHandlerAdapter;
|
||||
@@ -44,7 +40,7 @@ public class CorrelationIdTests {
|
||||
Object correlationId = "123-ABC";
|
||||
Message<?> message = new StringMessage("test");
|
||||
message.getHeader().setCorrelationId(correlationId);
|
||||
DefaultMessageHandlerAdapter<TestBean> adapter = new DefaultMessageHandlerAdapter<TestBean>();
|
||||
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
|
||||
adapter.setObject(new TestBean());
|
||||
adapter.setMethodName("upperCase");
|
||||
adapter.afterPropertiesSet();
|
||||
@@ -55,7 +51,7 @@ public class CorrelationIdTests {
|
||||
@Test
|
||||
public void testCorrelationIdCopiedFromMessageIdByDefault() {
|
||||
Message<?> message = new StringMessage("test");
|
||||
DefaultMessageHandlerAdapter<TestBean> adapter = new DefaultMessageHandlerAdapter<TestBean>();
|
||||
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
|
||||
adapter.setObject(new TestBean());
|
||||
adapter.setMethodName("upperCase");
|
||||
adapter.afterPropertiesSet();
|
||||
@@ -67,7 +63,7 @@ public class CorrelationIdTests {
|
||||
public void testCorrelationIdCopiedFromMessageCorrelationIdIfAvailable() {
|
||||
Message<?> message = new StringMessage("messageId","test");
|
||||
message.getHeader().setCorrelationId("correlationId");
|
||||
DefaultMessageHandlerAdapter<TestBean> adapter = new DefaultMessageHandlerAdapter<TestBean>();
|
||||
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
|
||||
adapter.setObject(new TestBean());
|
||||
adapter.setMethodName("upperCase");
|
||||
adapter.afterPropertiesSet();
|
||||
@@ -81,14 +77,13 @@ public class CorrelationIdTests {
|
||||
Object correlationId = "123-ABC";
|
||||
Message<?> message = new StringMessage("test");
|
||||
message.getHeader().setCorrelationId(correlationId);
|
||||
AbstractMessageHandlerAdapter<TestBean> adapter = new AbstractMessageHandlerAdapter<TestBean>() {
|
||||
AbstractMessageHandlerAdapter adapter = new AbstractMessageHandlerAdapter() {
|
||||
@Override
|
||||
protected Object doHandle(Message<?> message, HandlerMethodInvoker<TestBean> invoker) {
|
||||
Object result = invoker.invokeMethod(message.getPayload());
|
||||
Message<?> resultMessage = new GenericMessage<Object>(result);
|
||||
protected Message<?> handleReturnValue(Object returnValue, Message<?> originalMessage) {
|
||||
Message<?> resultMessage = this.createReplyMessage(returnValue, originalMessage);
|
||||
resultMessage.getHeader().setCorrelationId("456-XYZ");
|
||||
return resultMessage;
|
||||
}
|
||||
return resultMessage;
|
||||
}
|
||||
};
|
||||
adapter.setObject(new TestBean());
|
||||
adapter.setMethodName("upperCase");
|
||||
@@ -100,14 +95,13 @@ public class CorrelationIdTests {
|
||||
@Test
|
||||
public void testCorrelationNotCopiedIfAlreadySetByHandler() throws Exception {
|
||||
Message<?> message = new StringMessage("test");
|
||||
AbstractMessageHandlerAdapter<TestBean> adapter = new AbstractMessageHandlerAdapter<TestBean>() {
|
||||
AbstractMessageHandlerAdapter adapter = new AbstractMessageHandlerAdapter() {
|
||||
@Override
|
||||
protected Object doHandle(Message<?> message, HandlerMethodInvoker<TestBean> invoker) {
|
||||
Object result = invoker.invokeMethod(message.getPayload());
|
||||
Message<?> resultMessage = new GenericMessage<Object>(result);
|
||||
protected Message<?> handleReturnValue(Object returnValue, Message<?> originalMessage) {
|
||||
Message<?> resultMessage = this.createReplyMessage(returnValue, originalMessage);
|
||||
resultMessage.getHeader().setCorrelationId("456-XYZ");
|
||||
return resultMessage;
|
||||
}
|
||||
return resultMessage;
|
||||
}
|
||||
};
|
||||
adapter.setObject(new TestBean());
|
||||
adapter.setMethodName("upperCase");
|
||||
@@ -119,17 +113,15 @@ public class CorrelationIdTests {
|
||||
@Test
|
||||
public void testCorrelationIdWithSplitter() throws Exception {
|
||||
Message<?> message = new StringMessage("test1,test2");
|
||||
DefaultMessageHandlerAdapter<TestBean> adapter = new DefaultMessageHandlerAdapter<TestBean>();
|
||||
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
|
||||
adapter.setObject(new TestBean());
|
||||
adapter.setMethodName("upperCase");
|
||||
adapter.afterPropertiesSet();
|
||||
MessageChannel testChannel = new QueueChannel();
|
||||
ChannelRegistry channelRegistry = new DefaultChannelRegistry();
|
||||
channelRegistry.registerChannel("testChannel", testChannel);
|
||||
Map<String, String> attributes = new HashMap<String, String>();
|
||||
attributes.put(AbstractMessageHandlerAdapter.OUTPUT_CHANNEL_NAME_KEY, "testChannel");
|
||||
SplitterMessageHandlerAdapter<TestBean> splitter = new SplitterMessageHandlerAdapter<TestBean>(
|
||||
new TestBean(), TestBean.class.getMethod("split", String.class), attributes);
|
||||
SplitterMessageHandlerAdapter splitter = new SplitterMessageHandlerAdapter(
|
||||
new TestBean(), TestBean.class.getMethod("split", String.class), "testChannel");
|
||||
splitter.setChannelRegistry(channelRegistry);
|
||||
splitter.afterPropertiesSet();
|
||||
splitter.handle(message);
|
||||
|
||||
@@ -30,7 +30,7 @@ public class DefaultMessageHandlerAdapterTests {
|
||||
|
||||
@Test
|
||||
public void testPayloadAsMethodParameterAndObjectAsReturnValue() {
|
||||
DefaultMessageHandlerAdapter<TestHandler> adapter = new DefaultMessageHandlerAdapter<TestHandler>();
|
||||
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
|
||||
adapter.setObject(new TestHandler());
|
||||
adapter.setMethodName("acceptPayloadAndReturnObject");
|
||||
adapter.afterPropertiesSet();
|
||||
@@ -40,7 +40,7 @@ public class DefaultMessageHandlerAdapterTests {
|
||||
|
||||
@Test
|
||||
public void testPayloadAsMethodParameterAndMessageAsReturnValue() {
|
||||
DefaultMessageHandlerAdapter<TestHandler> adapter = new DefaultMessageHandlerAdapter<TestHandler>();
|
||||
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
|
||||
adapter.setObject(new TestHandler());
|
||||
adapter.setMethodName("acceptPayloadAndReturnMessage");
|
||||
adapter.afterPropertiesSet();
|
||||
@@ -50,8 +50,8 @@ public class DefaultMessageHandlerAdapterTests {
|
||||
|
||||
@Test
|
||||
public void testMessageAsMethodParameterAndObjectAsReturnValue() {
|
||||
DefaultMessageHandlerAdapter<TestHandler> adapter = new DefaultMessageHandlerAdapter<TestHandler>();
|
||||
adapter.setExpectsMessage(true);
|
||||
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
|
||||
adapter.setMethodExpectsMessage(true);
|
||||
adapter.setObject(new TestHandler());
|
||||
adapter.setMethodName("acceptMessageAndReturnObject");
|
||||
adapter.afterPropertiesSet();
|
||||
@@ -61,8 +61,8 @@ public class DefaultMessageHandlerAdapterTests {
|
||||
|
||||
@Test
|
||||
public void testMessageAsMethodParameterAndMessageAsReturnValue() {
|
||||
DefaultMessageHandlerAdapter<TestHandler> adapter = new DefaultMessageHandlerAdapter<TestHandler>();
|
||||
adapter.setExpectsMessage(true);
|
||||
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
|
||||
adapter.setMethodExpectsMessage(true);
|
||||
adapter.setObject(new TestHandler());
|
||||
adapter.setMethodName("acceptMessageAndReturnMessage");
|
||||
adapter.afterPropertiesSet();
|
||||
@@ -72,8 +72,8 @@ public class DefaultMessageHandlerAdapterTests {
|
||||
|
||||
@Test
|
||||
public void testMessageSubclassAsMethodParameterAndMessageAsReturnValue() {
|
||||
DefaultMessageHandlerAdapter<TestHandler> adapter = new DefaultMessageHandlerAdapter<TestHandler>();
|
||||
adapter.setExpectsMessage(true);
|
||||
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
|
||||
adapter.setMethodExpectsMessage(true);
|
||||
adapter.setObject(new TestHandler());
|
||||
adapter.setMethodName("acceptMessageSubclassAndReturnMessage");
|
||||
adapter.afterPropertiesSet();
|
||||
@@ -83,8 +83,8 @@ public class DefaultMessageHandlerAdapterTests {
|
||||
|
||||
@Test
|
||||
public void testMessageSubclassAsMethodParameterAndMessageSubclassAsReturnValue() {
|
||||
DefaultMessageHandlerAdapter<TestHandler> adapter = new DefaultMessageHandlerAdapter<TestHandler>();
|
||||
adapter.setExpectsMessage(true);
|
||||
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
|
||||
adapter.setMethodExpectsMessage(true);
|
||||
adapter.setObject(new TestHandler());
|
||||
adapter.setMethodName("acceptMessageSubclassAndReturnMessageSubclass");
|
||||
adapter.afterPropertiesSet();
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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.handler.annotation;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.integration.annotation.Handler;
|
||||
import org.springframework.integration.handler.DefaultMessageHandlerAdapter;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageHandlingException;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class AnnotationMethodMessageMapperTests {
|
||||
|
||||
@Test
|
||||
public void testOptionalAttribute() throws Exception {
|
||||
Method method = TestHandler.class.getMethod("optionalAttribute", Integer.class);
|
||||
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
|
||||
Object[] args = (Object[]) mapper.mapMessage(new StringMessage("foo"));
|
||||
assertEquals(1, args.length);
|
||||
assertNull(args[0]);
|
||||
}
|
||||
|
||||
@Test(expected=MessageHandlingException.class)
|
||||
public void testRequiredAttributeNotProvided() throws Exception {
|
||||
Method method = TestHandler.class.getMethod("requiredAttribute", Integer.class);
|
||||
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
|
||||
mapper.mapMessage(new StringMessage("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiredAttributeProvided() throws Exception {
|
||||
Method method = TestHandler.class.getMethod("requiredAttribute", Integer.class);
|
||||
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
|
||||
Message<?> message = new StringMessage("foo");
|
||||
message.getHeader().setAttribute("num", new Integer(123));
|
||||
Object[] args = (Object[]) mapper.mapMessage(message);
|
||||
assertEquals(1, args.length);
|
||||
assertEquals(new Integer(123), args[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalProperty() throws Exception {
|
||||
Method method = TestHandler.class.getMethod("optionalProperty", String.class);
|
||||
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
|
||||
Object[] args = (Object[]) mapper.mapMessage(new StringMessage("foo"));
|
||||
assertEquals(1, args.length);
|
||||
assertNull(args[0]);
|
||||
}
|
||||
|
||||
@Test(expected=MessageHandlingException.class)
|
||||
public void testRequiredPropertyNotProvided() throws Exception {
|
||||
Method method = TestHandler.class.getMethod("requiredProperty", String.class);
|
||||
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
|
||||
mapper.mapMessage(new StringMessage("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiredPropertyProvided() throws Exception {
|
||||
Method method = TestHandler.class.getMethod("requiredProperty", String.class);
|
||||
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
|
||||
Message<?> message = new StringMessage("foo");
|
||||
message.getHeader().setProperty("prop", "bar");
|
||||
Object[] args = (Object[]) mapper.mapMessage(message);
|
||||
assertEquals(1, args.length);
|
||||
assertEquals("bar", args[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessageOnlyWithAdapter() throws Exception {
|
||||
TestHandler handler = new TestHandler();
|
||||
Method method = handler.getClass().getMethod("messageOnly", Message.class);
|
||||
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
|
||||
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
|
||||
adapter.setObject(handler);
|
||||
adapter.setMethod(method);
|
||||
adapter.setMessageMapper(mapper);
|
||||
Message<?> result = adapter.handle(new StringMessage("foo"));
|
||||
assertEquals("foo", result.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessageAndHeaderWithAdapter() throws Exception {
|
||||
TestHandler handler = new TestHandler();
|
||||
Method method = handler.getClass().getMethod("messageAndAttribute", Message.class, Integer.class);
|
||||
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
|
||||
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
|
||||
adapter.setObject(handler);
|
||||
adapter.setMethod(method);
|
||||
adapter.setMessageMapper(mapper);
|
||||
Message<?> message = new StringMessage("foo");
|
||||
message.getHeader().setAttribute("number", 42);
|
||||
Message<?> result = adapter.handle(message);
|
||||
assertEquals("foo-42", result.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderAndPropertyWithAdapter() throws Exception {
|
||||
TestHandler handler = new TestHandler();
|
||||
Method method = handler.getClass().getMethod("propertyAndAttribute", String.class, Integer.class);
|
||||
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
|
||||
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
|
||||
adapter.setObject(handler);
|
||||
adapter.setMethod(method);
|
||||
adapter.setMessageMapper(mapper);
|
||||
Message<?> message = new StringMessage("foo");
|
||||
message.getHeader().setProperty("prop", "bar");
|
||||
message.getHeader().setAttribute("number", 42);
|
||||
Message<?> result = adapter.handle(message);
|
||||
assertEquals("bar-42", result.getPayload());
|
||||
}
|
||||
|
||||
|
||||
private static class TestHandler {
|
||||
|
||||
@Handler
|
||||
public String messageOnly(Message<?> message) {
|
||||
return (String) message.getPayload();
|
||||
}
|
||||
|
||||
@Handler
|
||||
public String messageAndAttribute(Message<?> message, @HeaderAttribute("number") Integer num) {
|
||||
return (String) message.getPayload() + "-" + num.toString();
|
||||
}
|
||||
|
||||
@Handler
|
||||
public String propertyAndAttribute(@HeaderProperty String prop, @HeaderAttribute("number") Integer num) {
|
||||
return prop + "-" + num.toString();
|
||||
}
|
||||
|
||||
@Handler
|
||||
public Integer optionalAttribute(@HeaderAttribute(required=false) Integer num) {
|
||||
return num;
|
||||
}
|
||||
|
||||
@Handler
|
||||
public Integer requiredAttribute(@HeaderAttribute(value="num", required=true) Integer num) {
|
||||
return num;
|
||||
}
|
||||
|
||||
@Handler
|
||||
public String optionalProperty(@HeaderProperty(required=false) String prop) {
|
||||
return prop;
|
||||
}
|
||||
|
||||
@Handler
|
||||
public String requiredProperty(@HeaderProperty(value="prop", required=true) String prop) {
|
||||
return prop;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,6 +34,8 @@ import org.springframework.integration.channel.ChannelRegistryAware;
|
||||
import org.springframework.integration.channel.DefaultChannelRegistry;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.handler.annotation.HeaderAttribute;
|
||||
import org.springframework.integration.handler.annotation.HeaderProperty;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
@@ -47,8 +49,7 @@ public class RouterMessageHandlerAdapterTests {
|
||||
public void testChannelNameResolutionByPayload() throws Exception {
|
||||
SingleChannelNameRoutingTestBean testBean = new SingleChannelNameRoutingTestBean();
|
||||
Method routingMethod = testBean.getClass().getMethod("routePayload", String.class);
|
||||
Map<String, Object> attribs = new ConcurrentHashMap<String, Object>();
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod, attribs);
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod);
|
||||
Message<String> message = new GenericMessage<String>("123", "bar");
|
||||
QueueChannel barChannel = new QueueChannel();
|
||||
ChannelRegistry channelRegistry = new DefaultChannelRegistry();
|
||||
@@ -64,10 +65,8 @@ public class RouterMessageHandlerAdapterTests {
|
||||
@Test
|
||||
public void testChannelNameResolutionByProperty() throws Exception {
|
||||
SingleChannelNameRoutingTestBean testBean = new SingleChannelNameRoutingTestBean();
|
||||
Method routingMethod = testBean.getClass().getMethod("routePayload", String.class);
|
||||
Map<String, Object> attribs = new ConcurrentHashMap<String, Object>();
|
||||
attribs.put("property", "returnAddress");
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod, attribs);
|
||||
Method routingMethod = testBean.getClass().getMethod("routeByProperty", String.class);
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod);
|
||||
Message<String> message = new GenericMessage<String>("123", "bar");
|
||||
message.getHeader().setProperty("returnAddress", "baz");
|
||||
QueueChannel barChannel = new QueueChannel();
|
||||
@@ -88,10 +87,8 @@ public class RouterMessageHandlerAdapterTests {
|
||||
@Test
|
||||
public void testChannelNameResolutionByAttribute() throws Exception {
|
||||
SingleChannelNameRoutingTestBean testBean = new SingleChannelNameRoutingTestBean();
|
||||
Method routingMethod = testBean.getClass().getMethod("routePayload", String.class);
|
||||
Map<String, Object> attribs = new ConcurrentHashMap<String, Object>();
|
||||
attribs.put("attribute", "returnAddress");
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod, attribs);
|
||||
Method routingMethod = testBean.getClass().getMethod("routeByAttribute", String.class);
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod);
|
||||
Message<String> message = new GenericMessage<String>("123", "bar");
|
||||
message.getHeader().setProperty("returnAddress", "bad");
|
||||
message.getHeader().setAttribute("returnAddress", "baz");
|
||||
@@ -116,12 +113,9 @@ public class RouterMessageHandlerAdapterTests {
|
||||
|
||||
@Test(expected=ConfigurationException.class)
|
||||
public void testFailsWhenPropertyAndAttributeAreBothProvided() throws Exception {
|
||||
SingleChannelNameRoutingTestBean testBean = new SingleChannelNameRoutingTestBean();
|
||||
Method routingMethod = testBean.getClass().getMethod("routePayload", String.class);
|
||||
Map<String, Object> attribs = new ConcurrentHashMap<String, Object>();
|
||||
attribs.put("property", "targetChannel");
|
||||
attribs.put("attribute", "returnAddress");
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod, attribs);
|
||||
InvalidRoutingTestBean testBean = new InvalidRoutingTestBean();
|
||||
Method routingMethod = testBean.getClass().getMethod("tooManyAnnotations", String.class);
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod);
|
||||
adapter.afterPropertiesSet();
|
||||
adapter.handle(new GenericMessage<String>("123", "testing"));
|
||||
}
|
||||
@@ -130,8 +124,7 @@ public class RouterMessageHandlerAdapterTests {
|
||||
public void testChannelNameResolutionByMessage() throws Exception {
|
||||
SingleChannelNameRoutingTestBean testBean = new SingleChannelNameRoutingTestBean();
|
||||
Method routingMethod = testBean.getClass().getMethod("routeMessage", Message.class);
|
||||
Map<String, Object> attribs = new ConcurrentHashMap<String, Object>();
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod, attribs);
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod);
|
||||
Message<String> fooMessage = new StringMessage("foo");
|
||||
Message<String> barMessage = new StringMessage("bar");
|
||||
Message<String> badMessage = new StringMessage("bad");
|
||||
@@ -166,8 +159,7 @@ public class RouterMessageHandlerAdapterTests {
|
||||
channelRegistry.registerChannel("bar-channel", barChannel);
|
||||
SingleChannelInstanceRoutingTestBean testBean = new SingleChannelInstanceRoutingTestBean(channelRegistry);
|
||||
Method routingMethod = testBean.getClass().getMethod("routePayload", String.class);
|
||||
Map<String, Object> attribs = new ConcurrentHashMap<String, Object>();
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod, attribs);
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod);
|
||||
Message<String> fooMessage = new StringMessage("foo");
|
||||
Message<String> barMessage = new StringMessage("bar");
|
||||
Message<String> badMessage = new StringMessage("bad");
|
||||
@@ -197,8 +189,7 @@ public class RouterMessageHandlerAdapterTests {
|
||||
channelRegistry.registerChannel("bar-channel", barChannel);
|
||||
SingleChannelInstanceRoutingTestBean testBean = new SingleChannelInstanceRoutingTestBean(channelRegistry);
|
||||
Method routingMethod = testBean.getClass().getMethod("routeMessage", Message.class);
|
||||
Map<String, Object> attribs = new ConcurrentHashMap<String, Object>();
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod, attribs);
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod);
|
||||
Message<String> fooMessage = new StringMessage("foo");
|
||||
Message<String> barMessage = new StringMessage("bar");
|
||||
Message<String> badMessage = new StringMessage("bad");
|
||||
@@ -228,8 +219,7 @@ public class RouterMessageHandlerAdapterTests {
|
||||
channelRegistry.registerChannel("bar-channel", barChannel);
|
||||
MultiChannelNameRoutingTestBean testBean = new MultiChannelNameRoutingTestBean();
|
||||
Method routingMethod = testBean.getClass().getMethod("routePayload", String.class);
|
||||
Map<String, Object> attribs = new ConcurrentHashMap<String, Object>();
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod, attribs);
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod);
|
||||
Message<String> fooMessage = new StringMessage("foo");
|
||||
Message<String> barMessage = new StringMessage("bar");
|
||||
Message<String> badMessage = new StringMessage("bad");
|
||||
@@ -265,8 +255,7 @@ public class RouterMessageHandlerAdapterTests {
|
||||
channelRegistry.registerChannel("bar-channel", barChannel);
|
||||
MultiChannelNameRoutingTestBean testBean = new MultiChannelNameRoutingTestBean();
|
||||
Method routingMethod = testBean.getClass().getMethod("routeMessage", Message.class);
|
||||
Map<String, Object> attribs = new ConcurrentHashMap<String, Object>();
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod, attribs);
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod);
|
||||
Message<String> fooMessage = new StringMessage("foo");
|
||||
Message<String> barMessage = new StringMessage("bar");
|
||||
Message<String> badMessage = new StringMessage("bad");
|
||||
@@ -302,8 +291,7 @@ public class RouterMessageHandlerAdapterTests {
|
||||
channelRegistry.registerChannel("bar-channel", barChannel);
|
||||
MultiChannelNameRoutingTestBean testBean = new MultiChannelNameRoutingTestBean();
|
||||
Method routingMethod = testBean.getClass().getMethod("routeMessageToArray", Message.class);
|
||||
Map<String, Object> attribs = new ConcurrentHashMap<String, Object>();
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod, attribs);
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod);
|
||||
Message<String> fooMessage = new StringMessage("foo");
|
||||
Message<String> barMessage = new StringMessage("bar");
|
||||
Message<String> badMessage = new StringMessage("bad");
|
||||
@@ -339,8 +327,7 @@ public class RouterMessageHandlerAdapterTests {
|
||||
channelRegistry.registerChannel("bar-channel", barChannel);
|
||||
MultiChannelInstanceRoutingTestBean testBean = new MultiChannelInstanceRoutingTestBean(channelRegistry);
|
||||
Method routingMethod = testBean.getClass().getMethod("routePayload", String.class);
|
||||
Map<String, Object> attribs = new ConcurrentHashMap<String, Object>();
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod, attribs);
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod);
|
||||
Message<String> fooMessage = new StringMessage("foo");
|
||||
Message<String> barMessage = new StringMessage("bar");
|
||||
Message<String> badMessage = new StringMessage("bad");
|
||||
@@ -376,8 +363,7 @@ public class RouterMessageHandlerAdapterTests {
|
||||
channelRegistry.registerChannel("bar-channel", barChannel);
|
||||
MultiChannelInstanceRoutingTestBean testBean = new MultiChannelInstanceRoutingTestBean(channelRegistry);
|
||||
Method routingMethod = testBean.getClass().getMethod("routeMessage", Message.class);
|
||||
Map<String, Object> attribs = new ConcurrentHashMap<String, Object>();
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod, attribs);
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod);
|
||||
Message<String> fooMessage = new StringMessage("foo");
|
||||
Message<String> barMessage = new StringMessage("bar");
|
||||
Message<String> badMessage = new StringMessage("bad");
|
||||
@@ -413,8 +399,7 @@ public class RouterMessageHandlerAdapterTests {
|
||||
channelRegistry.registerChannel("bar-channel", barChannel);
|
||||
MultiChannelInstanceRoutingTestBean testBean = new MultiChannelInstanceRoutingTestBean(channelRegistry);
|
||||
Method routingMethod = testBean.getClass().getMethod("routeMessageToArray", Message.class);
|
||||
Map<String, Object> attribs = new ConcurrentHashMap<String, Object>();
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod, attribs);
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod);
|
||||
Message<String> fooMessage = new StringMessage("foo");
|
||||
Message<String> barMessage = new StringMessage("bar");
|
||||
Message<String> badMessage = new StringMessage("bad");
|
||||
@@ -448,8 +433,7 @@ public class RouterMessageHandlerAdapterTests {
|
||||
channelRegistry.registerChannel("foo-channel", fooChannel);
|
||||
ChannelRegistryAwareTestBean testBean = new ChannelRegistryAwareTestBean();
|
||||
Method routingMethod = testBean.getClass().getMethod("route", String.class);
|
||||
Map<String, Object> attribs = new ConcurrentHashMap<String, Object>();
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod, attribs);
|
||||
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod);
|
||||
adapter.setChannelRegistry(channelRegistry);
|
||||
assertNull(testBean.getChannelRegistry());
|
||||
adapter.afterPropertiesSet();
|
||||
@@ -468,6 +452,14 @@ public class RouterMessageHandlerAdapterTests {
|
||||
return name + "-channel";
|
||||
}
|
||||
|
||||
public String routeByProperty(@HeaderProperty("returnAddress") String name) {
|
||||
return name + "-channel";
|
||||
}
|
||||
|
||||
public String routeByAttribute(@HeaderAttribute("returnAddress") String name) {
|
||||
return name + "-channel";
|
||||
}
|
||||
|
||||
public String routeMessage(Message<?> message) {
|
||||
if (message.getPayload().equals("foo")) {
|
||||
return "foo-channel";
|
||||
@@ -591,4 +583,12 @@ public class RouterMessageHandlerAdapterTests {
|
||||
}
|
||||
}
|
||||
|
||||
public static class InvalidRoutingTestBean {
|
||||
|
||||
public String tooManyAnnotations(@HeaderProperty("foo") @HeaderAttribute("bar") String name) {
|
||||
return name + "-channel";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,17 +23,14 @@ import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.channel.ChannelRegistry;
|
||||
import org.springframework.integration.channel.DefaultChannelRegistry;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.handler.AbstractMessageHandlerAdapter;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessagingException;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
|
||||
/**
|
||||
@@ -47,12 +44,9 @@ public class SplitterMessageHandlerAdapterTests {
|
||||
|
||||
private SplitterTestBean testBean = new SplitterTestBean();
|
||||
|
||||
private Map<String, Object> attribs = new ConcurrentHashMap<String, Object>();
|
||||
|
||||
|
||||
public SplitterMessageHandlerAdapterTests() {
|
||||
this.channelRegistry.registerChannel("testChannel", testChannel);
|
||||
this.attribs.put(AbstractMessageHandlerAdapter.OUTPUT_CHANNEL_NAME_KEY, "testChannel");
|
||||
}
|
||||
|
||||
|
||||
@@ -160,10 +154,10 @@ public class SplitterMessageHandlerAdapterTests {
|
||||
assertEquals("bar", reply2.getPayload());
|
||||
}
|
||||
|
||||
@Test(expected=ConfigurationException.class)
|
||||
@Test(expected=MessagingException.class)
|
||||
public void testInvalidReturnType() throws Exception {
|
||||
Method splittingMethod = this.testBean.getClass().getMethod("invalidParameterCount", String.class, String.class);
|
||||
SplitterMessageHandlerAdapter adapter = new SplitterMessageHandlerAdapter(testBean, splittingMethod, attribs);
|
||||
SplitterMessageHandlerAdapter adapter = new SplitterMessageHandlerAdapter(testBean, splittingMethod, "testChannel");
|
||||
adapter.setChannelRegistry(channelRegistry);
|
||||
adapter.afterPropertiesSet();
|
||||
StringMessage message = new StringMessage("foo.bar");
|
||||
@@ -208,7 +202,7 @@ public class SplitterMessageHandlerAdapterTests {
|
||||
private SplitterMessageHandlerAdapter getAdapter(String methodName) throws Exception {
|
||||
Class<?> paramType = methodName.startsWith("message") ? Message.class : String.class;
|
||||
Method splittingMethod = this.testBean.getClass().getMethod(methodName, paramType);
|
||||
SplitterMessageHandlerAdapter adapter = new SplitterMessageHandlerAdapter(testBean, splittingMethod, attribs);
|
||||
SplitterMessageHandlerAdapter adapter = new SplitterMessageHandlerAdapter(testBean, splittingMethod, "testChannel");
|
||||
adapter.setChannelRegistry(channelRegistry);
|
||||
adapter.afterPropertiesSet();
|
||||
return adapter;
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.TypeMismatchException;
|
||||
import org.springframework.integration.util.DefaultMethodInvoker;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class DefaultMethodInvokerTests {
|
||||
|
||||
@Test
|
||||
public void testStringArgumentWithVoidReturnAndNoConversionNecessary() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
String methodName = "stringArgumentWithVoidReturn";
|
||||
Method method = testBean.getClass().getMethod(methodName, String.class);
|
||||
DefaultMethodInvoker invoker = new DefaultMethodInvoker(testBean, method);
|
||||
invoker.invokeMethod("test");
|
||||
assertEquals("test", testBean.lastStringArgument);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringArgumentWithVoidReturnAndSuccessfulConversion() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
String methodName = "stringArgumentWithVoidReturn";
|
||||
Method method = testBean.getClass().getMethod(methodName, String.class);
|
||||
DefaultMethodInvoker invoker = new DefaultMethodInvoker(testBean, method);
|
||||
invoker.invokeMethod(new Integer(123));
|
||||
assertEquals("123", testBean.lastStringArgument);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntegerArgumentWithVoidReturnAndSuccessfulConversion() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
String methodName = "integerArgumentWithVoidReturn";
|
||||
Method method = testBean.getClass().getMethod(methodName, Integer.class);
|
||||
DefaultMethodInvoker invoker = new DefaultMethodInvoker(testBean, method);
|
||||
invoker.invokeMethod("123");
|
||||
assertEquals(new Integer(123), testBean.lastIntegerArgument);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntegerArgumentWithVoidReturnAndFailedConversion() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
String methodName = "integerArgumentWithVoidReturn";
|
||||
Method method = testBean.getClass().getMethod(methodName, Integer.class);
|
||||
DefaultMethodInvoker invoker = new DefaultMethodInvoker(testBean, method);
|
||||
try {
|
||||
invoker.invokeMethod("ABC");
|
||||
throw new IllegalStateException("method invocation should have failed with TypeMismatchException");
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertEquals(TypeMismatchException.class, e.getCause().getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoArgumentsAndNoConversionRequired() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
String methodName = "stringAndIntegerArgumentMethod";
|
||||
Method method = testBean.getClass().getMethod(methodName, String.class, Integer.class);
|
||||
DefaultMethodInvoker invoker = new DefaultMethodInvoker(testBean, method);
|
||||
Object result = invoker.invokeMethod("ABC", new Integer(456));
|
||||
assertEquals(result, "ABC:456");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoArgumentsAndSuccessfulConversion() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
String methodName = "stringAndIntegerArgumentMethod";
|
||||
Method method = testBean.getClass().getMethod(methodName, String.class, Integer.class);
|
||||
DefaultMethodInvoker invoker = new DefaultMethodInvoker(testBean, method);
|
||||
Object result = invoker.invokeMethod("ABC", "789");
|
||||
assertEquals(result, "ABC:789");
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testTwoArgumentMethodWithOnlyOneArgumentProvided() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
String methodName = "stringAndIntegerArgumentMethod";
|
||||
Method method = testBean.getClass().getMethod(methodName, String.class, Integer.class);
|
||||
DefaultMethodInvoker invoker = new DefaultMethodInvoker(testBean, method);
|
||||
invoker.invokeMethod("ABC");
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testTwoArgumentMethodWithOnlyThreeArgumentsProvided() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
String methodName = "stringAndIntegerArgumentMethod";
|
||||
Method method = testBean.getClass().getMethod(methodName, String.class, Integer.class);
|
||||
DefaultMethodInvoker invoker = new DefaultMethodInvoker(testBean, method);
|
||||
invoker.invokeMethod("ABC", new Integer(123), new Integer(456));
|
||||
}
|
||||
|
||||
|
||||
private static class TestBean {
|
||||
|
||||
String lastStringArgument;
|
||||
|
||||
Integer lastIntegerArgument;
|
||||
|
||||
|
||||
public void stringArgumentWithVoidReturn(String s) {
|
||||
this.lastStringArgument = s;
|
||||
}
|
||||
|
||||
public void integerArgumentWithVoidReturn(Integer i) {
|
||||
this.lastIntegerArgument = i;
|
||||
}
|
||||
|
||||
public String stringAndIntegerArgumentMethod(String s, Integer i) {
|
||||
return s + ":" + i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user