Removed AbstractMethodInvokingAdapter and AbstractMessageHandlerAdapter (has been replaced by the new AbstractMessageHandler). The MethodInvokingPayloadTransformer now uses a NameResolvingMethodInvoker.
This commit is contained in:
@@ -1,141 +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 java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.integration.channel.ChannelRegistry;
|
||||
import org.springframework.integration.channel.ChannelRegistryAware;
|
||||
import org.springframework.integration.message.DefaultMessageCreator;
|
||||
import org.springframework.integration.message.DefaultMessageMapper;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageBuilder;
|
||||
import org.springframework.integration.message.MessageCreator;
|
||||
import org.springframework.integration.message.MessageHandlingException;
|
||||
import org.springframework.integration.message.MessageHeaders;
|
||||
import org.springframework.integration.message.MessageMapper;
|
||||
import org.springframework.integration.util.AbstractMethodInvokingAdapter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* 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 extends AbstractMethodInvokingAdapter
|
||||
implements MessageHandler, ChannelRegistryAware {
|
||||
|
||||
public static final String OUTPUT_CHANNEL_NAME_KEY = "outputChannelName";
|
||||
|
||||
|
||||
private volatile boolean methodExpectsMessage;
|
||||
|
||||
private volatile MessageMapper messageMapper = new DefaultMessageMapper();
|
||||
|
||||
private volatile MessageCreator messageCreator = new DefaultMessageCreator();
|
||||
|
||||
private volatile ChannelRegistry channelRegistry;
|
||||
|
||||
|
||||
public void setMethodExpectsMessage(boolean methodExpectsMessage) {
|
||||
this.methodExpectsMessage = methodExpectsMessage;
|
||||
}
|
||||
|
||||
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 setChannelRegistry(ChannelRegistry channelRegistry) {
|
||||
this.channelRegistry = channelRegistry;
|
||||
}
|
||||
|
||||
protected ChannelRegistry getChannelRegistry() {
|
||||
return this.channelRegistry;
|
||||
}
|
||||
|
||||
public Message<?> handle(Message<?> message) {
|
||||
if (!this.isInitialized()) {
|
||||
this.afterPropertiesSet();
|
||||
}
|
||||
if (message == null) {
|
||||
throw new IllegalArgumentException("message must not be null");
|
||||
}
|
||||
Object args[] = null;
|
||||
Object mappingResult = (this.methodExpectsMessage) ? message : this.messageMapper.mapMessage(message);
|
||||
if (mappingResult != null && mappingResult.getClass().isArray()
|
||||
&& (Object.class.isAssignableFrom(mappingResult.getClass().getComponentType()))) {
|
||||
args = (Object[]) mappingResult;
|
||||
}
|
||||
else {
|
||||
args = new Object[] { mappingResult };
|
||||
}
|
||||
try {
|
||||
Object result = null;
|
||||
try {
|
||||
result = this.invokeMethod(args);
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
result = this.invokeMethod(message);
|
||||
this.methodExpectsMessage = true;
|
||||
}
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
return this.handleReturnValue(result, message);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
throw new MessageHandlingException(message, "Handler method '"
|
||||
+ this.getMethodName() + "' threw an Exception.", e.getTargetException());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
throw new MessageHandlingException(message, "Failed to invoke handler method '"
|
||||
+ this.getMethodName() + "' with arguments: " + ObjectUtils.nullSafeToString(args), e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Message<?> createReplyMessage(Object returnValue, Message<?> originalMessage) {
|
||||
Message<?> reply = this.messageCreator.createMessage(returnValue);
|
||||
if (reply == null) {
|
||||
return null;
|
||||
}
|
||||
return MessageBuilder.fromMessage(reply).copyHeadersIfAbsent(originalMessage.getHeaders())
|
||||
.setHeaderIfAbsent(MessageHeaders.CORRELATION_ID, originalMessage.getHeaders().getId()).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses must implement this method to handle the return value.
|
||||
*/
|
||||
protected abstract Message<?> handleReturnValue(Object returnValue, Message<?> originalMessage);
|
||||
|
||||
}
|
||||
@@ -16,15 +16,53 @@
|
||||
|
||||
package org.springframework.integration.transformer;
|
||||
|
||||
import org.springframework.integration.util.AbstractMethodInvokingAdapter;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.util.MethodInvoker;
|
||||
import org.springframework.integration.util.NameResolvingMethodInvoker;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class MethodInvokingPayloadTransformer extends AbstractMethodInvokingAdapter implements PayloadTransformer<Object, Object> {
|
||||
public class MethodInvokingPayloadTransformer implements PayloadTransformer<Object, Object>, InitializingBean {
|
||||
|
||||
private volatile Object object;
|
||||
|
||||
private volatile String methodName;
|
||||
|
||||
private volatile MethodInvoker invoker;
|
||||
|
||||
private volatile boolean initialized;
|
||||
|
||||
private final Object initializationMonitor = new Object();
|
||||
|
||||
|
||||
public void setObject(Object object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public void setMethodName(String methodName) {
|
||||
this.methodName = methodName;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
synchronized (this.initializationMonitor) {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
if (this.object == null || this.methodName == null) {
|
||||
throw new ConfigurationException("the 'object' and 'methodName' are required");
|
||||
}
|
||||
this.invoker = new NameResolvingMethodInvoker(this.object, this.methodName);
|
||||
this.initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Object transform(Object payload) throws Exception {
|
||||
return this.invokeMethod(payload);
|
||||
if (!this.initialized) {
|
||||
this.afterPropertiesSet();
|
||||
}
|
||||
return this.invoker.invokeMethod(payload);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,133 +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.util;
|
||||
|
||||
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.ConfigurationException;
|
||||
|
||||
/**
|
||||
* A base class for adapters that invoke a 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.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public abstract class AbstractMethodInvokingAdapter implements MethodInvoker, InitializingBean, Ordered {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private volatile Object object;
|
||||
|
||||
private volatile Method method;
|
||||
|
||||
private volatile String methodName;
|
||||
|
||||
private volatile int order;
|
||||
|
||||
private volatile MethodInvoker invoker;
|
||||
|
||||
private volatile boolean initialized;
|
||||
|
||||
private final Object initializationMonitor = new Object();
|
||||
|
||||
|
||||
public void setObject(Object object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
protected Object getObject() {
|
||||
return this.object;
|
||||
}
|
||||
|
||||
public void setMethod(Method method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
protected Method getMethod() {
|
||||
return this.method;
|
||||
}
|
||||
|
||||
public void setMethodName(String methodName) {
|
||||
this.methodName = methodName;
|
||||
}
|
||||
|
||||
protected String getMethodName() {
|
||||
return this.methodName;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
protected boolean isInitialized() {
|
||||
return this.initialized;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
synchronized (this.initializationMonitor) {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
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.methodName = this.method.getName();
|
||||
this.invoker = new DefaultMethodInvoker(this.object, this.method);
|
||||
}
|
||||
else {
|
||||
this.invoker = new NameResolvingMethodInvoker(this.object, this.methodName);
|
||||
}
|
||||
this.initialized = true;
|
||||
}
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override this method for custom initialization requirements.
|
||||
*/
|
||||
protected void initialize() {
|
||||
}
|
||||
|
||||
public Object invokeMethod(Object ... args) throws Exception {
|
||||
if (!this.initialized) {
|
||||
this.afterPropertiesSet();
|
||||
}
|
||||
return this.invoker.invokeMethod(args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -72,39 +72,26 @@ public class CorrelationIdTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCorrelationNotPassedIfAlreadySetByHandler() throws Exception {
|
||||
public void testCorrelationNotPassedFromRequestHeaderIfAlreadySetByHandler() throws Exception {
|
||||
Object correlationId = "123-ABC";
|
||||
Message<String> message = MessageBuilder.fromPayload("test")
|
||||
.setCorrelationId(correlationId).build();
|
||||
AbstractMessageHandlerAdapter adapter = new AbstractMessageHandlerAdapter() {
|
||||
@Override
|
||||
protected Message<?> handleReturnValue(Object returnValue, Message<?> originalMessage) {
|
||||
Message<?> resultMessage = this.createReplyMessage(returnValue, originalMessage);
|
||||
return MessageBuilder.fromMessage(resultMessage)
|
||||
.setCorrelationId("456-XYZ").build();
|
||||
}
|
||||
};
|
||||
adapter.setObject(new TestBean());
|
||||
adapter.setMethodName("upperCase");
|
||||
adapter.afterPropertiesSet();
|
||||
Message<?> reply = adapter.handle(message);
|
||||
DefaultMessageHandler handler = new DefaultMessageHandler();
|
||||
handler.setObject(new TestBean());
|
||||
handler.setMethodName("createMessage");
|
||||
handler.afterPropertiesSet();
|
||||
Message<?> reply = handler.handle(message);
|
||||
assertEquals("456-XYZ", reply.getHeaders().getCorrelationId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCorrelationNotCopiedIfAlreadySetByHandler() throws Exception {
|
||||
public void testCorrelationNotCopiedFromRequestMessgeIdIfAlreadySetByHandler() throws Exception {
|
||||
Message<?> message = new StringMessage("test");
|
||||
AbstractMessageHandlerAdapter adapter = new AbstractMessageHandlerAdapter() {
|
||||
@Override
|
||||
protected Message<?> handleReturnValue(Object returnValue, Message<?> originalMessage) {
|
||||
Message<?> resultMessage = this.createReplyMessage(returnValue, originalMessage);
|
||||
return MessageBuilder.fromMessage(resultMessage).setCorrelationId("456-XYZ").build();
|
||||
}
|
||||
};
|
||||
adapter.setObject(new TestBean());
|
||||
adapter.setMethodName("upperCase");
|
||||
adapter.afterPropertiesSet();
|
||||
Message<?> reply = adapter.handle(message);
|
||||
DefaultMessageHandler handler = new DefaultMessageHandler();
|
||||
handler.setObject(new TestBean());
|
||||
handler.setMethodName("createMessage");
|
||||
handler.afterPropertiesSet();
|
||||
Message<?> reply = handler.handle(message);
|
||||
assertEquals("456-XYZ", reply.getHeaders().getCorrelationId());
|
||||
}
|
||||
|
||||
@@ -134,6 +121,10 @@ public class CorrelationIdTests {
|
||||
public String[] split(String input) {
|
||||
return input.split(",");
|
||||
}
|
||||
|
||||
public Message<?> createMessage(String input) {
|
||||
return MessageBuilder.fromPayload(input).setCorrelationId("456-XYZ").build();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user