Merge remote-tracking branch 'upstream/master' into 4.0.0-WIP

Conflicts:
	spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java
	spring-integration-core/src/test/java/org/springframework/integration/router/config/RouterWithMappingTests.java
	spring-integration-groovy/src/main/java/org/springframework/integration/groovy/GroovyScriptExecutingMessageProcessor.java
	spring-integration-http/src/test/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGatewayWithPathMappingTests.java
	spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/store/channel/AbstractTxTimeoutMessageStoreTests.java
	spring-integration-jmx/src/main/java/org/springframework/integration/jmx/OperationInvokingMessageHandler.java

Resolved.
This commit is contained in:
Gary Russell
2013-10-30 23:13:27 -04:00
93 changed files with 1657 additions and 787 deletions

View File

@@ -77,10 +77,10 @@ abstract class AbstractStandardMessageHandlerFactoryBean extends AbstractSimpleM
if (this.targetObject != null) {
Assert.state(this.expression == null,
"The 'targetObject' and 'expression' properties are mutually exclusive.");
boolean targetIsDirectReplyProducingHandler = this.extractTypeIfPossible(targetObject,
AbstractReplyProducingMessageHandler.class) != null
&& this.canBeUsedDirect(
(AbstractReplyProducingMessageHandler) targetObject) // give subclasses a say
AbstractReplyProducingMessageHandler actualHandler = this.extractTypeIfPossible(targetObject,
AbstractReplyProducingMessageHandler.class);
boolean targetIsDirectReplyProducingHandler = actualHandler != null
&& this.canBeUsedDirect(actualHandler) // give subclasses a say
&& this.methodIsHandleMessageOrEmpty(this.targetMethodName);
if (this.targetObject instanceof MessageProcessor<?>) {
handler = this.createMessageProcessingHandler((MessageProcessor<?>) this.targetObject);
@@ -89,9 +89,9 @@ abstract class AbstractStandardMessageHandlerFactoryBean extends AbstractSimpleM
if (logger.isDebugEnabled()) {
logger.debug("Wiring handler (" + beanName + ") directly into endpoint");
}
this.checkReuse(actualHandler);
this.postProcessReplyProducer(actualHandler);
handler = (MessageHandler) targetObject;
this.checkReuse((AbstractReplyProducingMessageHandler) handler);
this.postProcessReplyProducer((AbstractReplyProducingMessageHandler) handler);
}
else {
handler = this.createMethodInvokingHandler(this.targetObject, this.targetMethodName);
@@ -120,7 +120,7 @@ abstract class AbstractStandardMessageHandlerFactoryBean extends AbstractSimpleM
}
private void checkReuse(AbstractReplyProducingMessageHandler replyHandler) {
Assert.isTrue(!referencedReplyProducers.contains(targetObject),
Assert.isTrue(!referencedReplyProducers.contains(replyHandler),
"An AbstractReplyProducingMessageHandler may only be referenced once (" +
replyHandler.getComponentName() + ") - use scope=\"prototype\"");
referencedReplyProducers.add(replyHandler);

View File

@@ -28,6 +28,7 @@ import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.springframework.integration.gateway.GatewayProxyFactoryBean;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -43,7 +44,7 @@ import org.springframework.util.xml.DomUtils;
public class GatewayParser extends AbstractSimpleBeanDefinitionParser {
private static String[] referenceAttributes = new String[] {
"default-request-channel", "default-reply-channel", "error-channel", "message-mapper", "async-executor"
"default-request-channel", "default-reply-channel", "error-channel", "message-mapper", "async-executor", "mapper"
};
private static String[] innerAttributes = new String[] {
@@ -93,9 +94,16 @@ public class GatewayParser extends AbstractSimpleBeanDefinitionParser {
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, attributeName);
}
boolean hasMapper = StringUtils.hasText(element.getAttribute("mapper"));
boolean hasDefaultPayloadExpression = StringUtils.hasText(element.getAttribute("default-payload-expression"));
Assert.state(hasMapper ? !hasDefaultPayloadExpression : true, "'default-payload-expression' is not allowed when a 'mapper' is provided");
List<Element> invocationHeaders = DomUtils.getChildElementsByTagName(element, "default-header");
if (!CollectionUtils.isEmpty(invocationHeaders)
|| StringUtils.hasText(element.getAttribute("default-payload-expression"))) {
boolean hasDefaultHeaders = !CollectionUtils.isEmpty(invocationHeaders);
Assert.state(hasMapper ? !hasDefaultHeaders : true, "default-header elements are not allowed when a 'mapper' is provided");
if (hasDefaultHeaders || hasDefaultPayloadExpression) {
BeanDefinitionBuilder methodMetadataBuilder = BeanDefinitionBuilder.genericBeanDefinition(
"org.springframework.integration.gateway.GatewayMethodMetadata");
this.setMethodInvocationHeaders(methodMetadataBuilder, invocationHeaders);
@@ -118,8 +126,11 @@ public class GatewayParser extends AbstractSimpleBeanDefinitionParser {
methodMetadataBuilder.addPropertyValue("requestTimeout", methodElement.getAttribute("request-timeout"));
methodMetadataBuilder.addPropertyValue("replyTimeout", methodElement.getAttribute("reply-timeout"));
IntegrationNamespaceUtils.setValueIfAttributeDefined(methodMetadataBuilder, methodElement, "payload-expression");
Assert.state(hasMapper ? !StringUtils.hasText(element.getAttribute("payload-expression")) : true,
"'payload-expression' is not allowed when a 'mapper' is provided");
invocationHeaders = DomUtils.getChildElementsByTagName(methodElement, "header");
if (!CollectionUtils.isEmpty(invocationHeaders)) {
Assert.state(!hasMapper, "header elements are not allowed when a 'mapper' is provided");
this.setMethodInvocationHeaders(methodMetadataBuilder, invocationHeaders);
}
methodMetadataMap.put(methodName, methodMetadataBuilder.getBeanDefinition());

View File

@@ -20,12 +20,14 @@ import java.util.List;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
@@ -33,14 +35,13 @@ import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.Conventions;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.config.ExpressionFactoryBean;
import org.springframework.integration.config.SpelFunctionFactoryBean;
import org.springframework.integration.endpoint.AbstractPollingEndpoint;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
@@ -462,6 +463,7 @@ public abstract class IntegrationNamespaceUtils {
}
return expressionDef;
}
public static void registerSpelFunctionBean(BeanDefinitionRegistry registry, String functionId, String className,
String methodSignature) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SpelFunctionFactoryBean.class)
@@ -469,6 +471,7 @@ public abstract class IntegrationNamespaceUtils {
.addConstructorArgValue(methodSignature);
registry.registerBeanDefinition(functionId, builder.getBeanDefinition());
}
public static BeanDefinition createExpressionDefIfAttributeDefined(String expressionElementName, Element element) {
Assert.hasText(expressionElementName, "'expressionElementName' must no be empty");

View File

@@ -98,8 +98,7 @@ public class MessageFilter extends AbstractReplyProducingPostProcessingMessageHa
}
@Override
public final void onInit() {
super.onInit();
protected void doInit() {
if (this.selector instanceof AbstractMessageProcessingSelector) {
((AbstractMessageProcessingSelector) this.selector).setConversionService(this.getConversionService());
}

View File

@@ -42,6 +42,7 @@ import org.springframework.integration.annotation.Headers;
import org.springframework.integration.annotation.Payload;
import org.springframework.integration.expression.ExpressionUtils;
import org.springframework.integration.mapping.InboundMessageMapper;
import org.springframework.integration.mapping.MessageMappingException;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
@@ -85,6 +86,8 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
private final List<MethodParameter> parameterList;
private final MethodArgsMessageMapper argsMapper;
private volatile Expression payloadExpression;
private final Map<String, Expression> parameterPayloadExpressions = new HashMap<String, Expression>();
@@ -93,23 +96,28 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
private volatile BeanFactory beanFactory;
public GatewayMethodInboundMessageMapper(Method method) {
this(method, null);
}
public GatewayMethodInboundMessageMapper(Method method, Map<String, Expression> headerExpressions) {
this(method, headerExpressions, null);
this(method, headerExpressions, null, null);
}
public GatewayMethodInboundMessageMapper(Method method, Map<String, Expression> headerExpressions,
Map<String, Expression> globalHeaderExpressions) {
Map<String, Expression> globalHeaderExpressions, MethodArgsMessageMapper mapper) {
Assert.notNull(method, "method must not be null");
this.method = method;
this.headerExpressions = headerExpressions;
this.globalHeaderExpressions = globalHeaderExpressions;
this.parameterList = getMethodParameterList(method);
this.payloadExpression = parsePayloadExpression(method);
if (mapper == null) {
this.argsMapper = new DefaultMethodArgsMessageMapper();
}
else {
this.argsMapper = mapper;
}
}
@@ -135,85 +143,17 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
}
private Message<?> mapArgumentsToMessage(Object[] arguments) {
Object messageOrPayload = null;
boolean foundPayloadAnnotation = false;
Map<String, Object> headers = new HashMap<String, Object>();
EvaluationContext methodInvocationEvaluationContext = createMethodInvocationEvaluationContext(arguments);
if (this.payloadExpression != null) {
messageOrPayload = this.payloadExpression.getValue(methodInvocationEvaluationContext);
try {
return this.argsMapper.toMessage(new MethodArgsHolder(this.method, arguments));
}
for (int i = 0; i < this.parameterList.size(); i++) {
Object argumentValue = arguments[i];
MethodParameter methodParameter = this.parameterList.get(i);
Annotation annotation = this.findMappingAnnotation(methodParameter.getParameterAnnotations());
if (annotation != null) {
if (annotation.annotationType().equals(Payload.class)) {
if (messageOrPayload != null) {
this.throwExceptionForMultipleMessageOrPayloadParameters(methodParameter);
}
String expression = ((Payload) annotation).value();
if (!StringUtils.hasText(expression)) {
messageOrPayload = argumentValue;
}
else {
messageOrPayload = this.evaluatePayloadExpression(expression, argumentValue);
}
foundPayloadAnnotation = true;
}
else if (annotation.annotationType().equals(Header.class)) {
Header headerAnnotation = (Header) annotation;
String headerName = this.determineHeaderName(headerAnnotation, methodParameter);
if (headerAnnotation.required() && argumentValue == null) {
throw new IllegalArgumentException("Received null argument value for required header: '" + headerName + "'");
}
headers.put(headerName, argumentValue);
}
else if (annotation.annotationType().equals(Headers.class)) {
if (argumentValue != null) {
if (!(argumentValue instanceof Map)) {
throw new IllegalArgumentException("@Headers annotation is only valid for Map-typed parameters");
}
for (Object key : ((Map<?, ?>) argumentValue).keySet()) {
Assert.isInstanceOf(String.class, key, "Invalid header name [" + key +
"], name type must be String.");
Object value = ((Map<?, ?>) argumentValue).get(key);
headers.put((String) key, value);
}
}
}
catch (Exception e) {
if (e instanceof MessagingException) {
throw (MessagingException) e;
}
else if (messageOrPayload == null) {
messageOrPayload = argumentValue;
}
else if (Map.class.isAssignableFrom(methodParameter.getParameterType())) {
if (messageOrPayload instanceof Map && !foundPayloadAnnotation) {
if (payloadExpression == null){
throw new MessagingException("Ambiguous method parameters; found more than one " +
"Map-typed parameter and neither one contains a @Payload annotation");
}
}
this.copyHeaders((Map<?, ?>) argumentValue, headers);
}
else if (this.payloadExpression == null) {
this.throwExceptionForMultipleMessageOrPayloadParameters(methodParameter);
else {
throw new MessageMappingException("Failed to map arguments", e);
}
}
Assert.isTrue(messageOrPayload != null, "unable to determine a Message or payload parameter on method [" + method + "]");
MessageBuilder<?> builder = (messageOrPayload instanceof Message)
? MessageBuilder.fromMessage((Message<?>) messageOrPayload)
: MessageBuilder.withPayload(messageOrPayload);
builder.copyHeadersIfAbsent(headers);
// Explicit headers in XML override any @Header annotations...
if (!CollectionUtils.isEmpty(this.headerExpressions)) {
Map<String, Object> evaluatedHeaders = evaluateHeaders(methodInvocationEvaluationContext, this.headerExpressions);
builder.copyHeaders(evaluatedHeaders);
}
// ...whereas global (default) headers do not...
if (!CollectionUtils.isEmpty(this.globalHeaderExpressions)) {
Map<String, Object> evaluatedHeaders = evaluateHeaders(methodInvocationEvaluationContext, this.globalHeaderExpressions);
builder.copyHeadersIfAbsent(evaluatedHeaders);
}
return builder.build();
}
private Map<String, Object> evaluateHeaders(EvaluationContext methodInvocationEvaluationContext, Map<String, Expression> headerExpressions) {
@@ -318,4 +258,94 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
return expression;
}
public class DefaultMethodArgsMessageMapper implements MethodArgsMessageMapper {
@Override
public Message<?> toMessage(MethodArgsHolder holder) throws Exception {
Object messageOrPayload = null;
boolean foundPayloadAnnotation = false;
Object[] arguments = holder.getArgs();
EvaluationContext methodInvocationEvaluationContext = createMethodInvocationEvaluationContext(arguments);
Map<String, Object> headers = new HashMap<String, Object>();
if (GatewayMethodInboundMessageMapper.this.payloadExpression != null) {
messageOrPayload = GatewayMethodInboundMessageMapper.this.payloadExpression.getValue(methodInvocationEvaluationContext);
}
for (int i = 0; i < GatewayMethodInboundMessageMapper.this.parameterList.size(); i++) {
Object argumentValue = arguments[i];
MethodParameter methodParameter = GatewayMethodInboundMessageMapper.this.parameterList.get(i);
Annotation annotation = GatewayMethodInboundMessageMapper.this.findMappingAnnotation(methodParameter.getParameterAnnotations());
if (annotation != null) {
if (annotation.annotationType().equals(Payload.class)) {
if (messageOrPayload != null) {
GatewayMethodInboundMessageMapper.this.throwExceptionForMultipleMessageOrPayloadParameters(methodParameter);
}
String expression = ((Payload) annotation).value();
if (!StringUtils.hasText(expression)) {
messageOrPayload = argumentValue;
}
else {
messageOrPayload = GatewayMethodInboundMessageMapper.this.evaluatePayloadExpression(expression, argumentValue);
}
foundPayloadAnnotation = true;
}
else if (annotation.annotationType().equals(Header.class)) {
Header headerAnnotation = (Header) annotation;
String headerName = GatewayMethodInboundMessageMapper.this.determineHeaderName(headerAnnotation, methodParameter);
if (headerAnnotation.required() && argumentValue == null) {
throw new IllegalArgumentException("Received null argument value for required header: '" + headerName + "'");
}
headers.put(headerName, argumentValue);
}
else if (annotation.annotationType().equals(Headers.class)) {
if (argumentValue != null) {
if (!(argumentValue instanceof Map)) {
throw new IllegalArgumentException("@Headers annotation is only valid for Map-typed parameters");
}
for (Object key : ((Map<?, ?>) argumentValue).keySet()) {
Assert.isInstanceOf(String.class, key, "Invalid header name [" + key +
"], name type must be String.");
Object value = ((Map<?, ?>) argumentValue).get(key);
headers.put((String) key, value);
}
}
}
}
else if (messageOrPayload == null) {
messageOrPayload = argumentValue;
}
else if (Map.class.isAssignableFrom(methodParameter.getParameterType())) {
if (messageOrPayload instanceof Map && !foundPayloadAnnotation) {
if (payloadExpression == null){
throw new MessagingException("Ambiguous method parameters; found more than one " +
"Map-typed parameter and neither one contains a @Payload annotation");
}
}
GatewayMethodInboundMessageMapper.this.copyHeaders((Map<?, ?>) argumentValue, headers);
}
else if (GatewayMethodInboundMessageMapper.this.payloadExpression == null) {
GatewayMethodInboundMessageMapper.this.throwExceptionForMultipleMessageOrPayloadParameters(methodParameter);
}
}
Assert.isTrue(messageOrPayload != null, "unable to determine a Message or payload parameter on method [" + method + "]");
MessageBuilder<?> builder = (messageOrPayload instanceof Message)
? MessageBuilder.fromMessage((Message<?>) messageOrPayload)
: MessageBuilder.withPayload(messageOrPayload);
builder.copyHeadersIfAbsent(headers);
// Explicit headers in XML override any @Header annotations...
if (!CollectionUtils.isEmpty(GatewayMethodInboundMessageMapper.this.headerExpressions)) {
Map<String, Object> evaluatedHeaders = evaluateHeaders(methodInvocationEvaluationContext,
GatewayMethodInboundMessageMapper.this.headerExpressions);
builder.copyHeaders(evaluatedHeaders);
}
// ...whereas global (default) headers do not...
if (!CollectionUtils.isEmpty(GatewayMethodInboundMessageMapper.this.globalHeaderExpressions)) {
Map<String, Object> evaluatedHeaders = evaluateHeaders(methodInvocationEvaluationContext,
GatewayMethodInboundMessageMapper.this.globalHeaderExpressions);
builder.copyHeadersIfAbsent(evaluatedHeaders);
}
return builder.build();
}
}
}

View File

@@ -105,6 +105,8 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Trackab
private volatile GatewayMethodMetadata globalMethodMetadata;
private volatile MethodArgsMessageMapper argsMapper;
/**
* Create a Factory whose service interface type can be configured by setter injection.
* If none is set, it will fall back to the default service interface type,
@@ -214,6 +216,15 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Trackab
this.beanClassLoader = beanClassLoader;
}
/**
* Provide a custom {@link MethodArgsMessageMapper} to map from a {@link MethodArgsHolder}
* to a {@link Message}.
* @param mapper the mapper.
*/
public final void setMapper(MethodArgsMessageMapper mapper) {
this.argsMapper = mapper;
}
@Override
protected void onInit() {
synchronized (this.initializationMonitor) {
@@ -395,7 +406,8 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Trackab
}
}
GatewayMethodInboundMessageMapper messageMapper = new GatewayMethodInboundMessageMapper(method, headerExpressions,
this.globalMethodMetadata != null ? this.globalMethodMetadata.getHeaderExpressions() : null);
this.globalMethodMetadata != null ? this.globalMethodMetadata.getHeaderExpressions() : null,
this.argsMapper);
if (StringUtils.hasText(payloadExpression)) {
messageMapper.setPayloadExpression(payloadExpression);
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2013 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.gateway;
import java.lang.reflect.Method;
/**
* Simple wrapper class containing a {@link Method} and an object
* array containing the arguments for an invocation of that method.
* For example used by a {@link MethodArgsMessageMapper} with this generic
* type to provide custom argument mapping when creating a message
* in a {@code GatewayProxyFactoryBean}.
*
* @author Gary Russell
* @since 3.0
*
*/
public final class MethodArgsHolder {
private final Method method;
private final Object[] args;
public MethodArgsHolder(Method method, Object[] args) {
this.method = method;
this.args = args;
}
public final Method getMethod() {
return method;
}
public final Object[] getArgs() {
return args;
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2013 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.gateway;
import org.springframework.integration.mapping.InboundMessageMapper;
/**
* Implementations of this interface are {@link InboundMessageMapper}s
* that map a {@link MethodArgsHolder} to a {@link org.springframework.integration.Message}.
*
* @author Gary Russell
* @since 3.0
*
*/
public interface MethodArgsMessageMapper extends InboundMessageMapper<MethodArgsHolder> {
}

View File

@@ -19,6 +19,7 @@ package org.springframework.integration.handler;
import java.util.List;
import org.aopalliance.aop.Advice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.integration.core.MessageProducer;
@@ -114,7 +115,7 @@ public abstract class AbstractReplyProducingMessageHandler extends AbstractMessa
@Override
protected void onInit() {
protected final void onInit() {
if (this.getBeanFactory() != null) {
this.messagingTemplate.setBeanFactory(getBeanFactory());
}
@@ -125,6 +126,10 @@ public abstract class AbstractReplyProducingMessageHandler extends AbstractMessa
}
this.advisedRequestHandler = (RequestHandler) proxyFactory.getProxy(this.beanClassLoader);
}
this.doInit();
}
protected void doInit() {
}
/**

View File

@@ -196,8 +196,7 @@ public class DelayHandler extends AbstractReplyProducingMessageHandler implement
}
@Override
protected void onInit() {
super.onInit();
protected void doInit() {
if (this.messageStore == null) {
this.messageStore = new SimpleMessageStore();
}

View File

@@ -55,8 +55,7 @@ public class ServiceActivatingHandler extends AbstractReplyProducingMessageHandl
}
@Override
public final void onInit() {
super.onInit();
protected void doInit() {
if (processor instanceof AbstractMessageProcessor) {
((AbstractMessageProcessor<?>) this.processor).setConversionService(this.getConversionService());
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2013 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.
@@ -28,7 +28,7 @@ import org.springframework.util.Assert;
/**
* Base class for Message Splitter implementations that delegate to a
* {@link MessageProcessor} instance.
*
*
* @author Mark Fisher
* @since 2.0
*/
@@ -43,8 +43,7 @@ abstract class AbstractMessageProcessingSplitter extends AbstractMessageSplitter
}
@Override
public void onInit() {
super.onInit();
protected void doInit() {
ConversionService conversionService = this.getConversionService();
if (conversionService != null && this.messageProcessor instanceof AbstractMessageProcessor) {
((AbstractMessageProcessor<?>) this.messageProcessor).setConversionService(conversionService);

View File

@@ -194,8 +194,7 @@ public class ContentEnricher extends AbstractReplyProducingMessageHandler implem
* the requestChannel is set.
*/
@Override
public void onInit() {
super.onInit();
protected void doInit() {
if (this.replyChannel != null) {
Assert.notNull(this.requestChannel, "If the replyChannel is set, then the requestChannel must not be null");
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2013 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.
@@ -54,8 +54,7 @@ public class MessageTransformingHandler extends AbstractReplyProducingMessageHan
}
@Override
protected void onInit() {
super.onInit();
protected void doInit() {
if (this.getBeanFactory() != null && this.transformer instanceof BeanFactoryAware) {
((BeanFactoryAware) this.transformer).setBeanFactory(this.getBeanFactory());
}

View File

@@ -717,6 +717,22 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="mapper" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
An MethodArgsMessageMapper to map the method arguments to a Message. When this
is provided, no payload-expressions or headers are allowed; the custom mapper is
responsible for creating the message.
]]>
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.gateway.MethodArgsMessageMapper" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>

View File

@@ -23,16 +23,20 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.expression.Expression;
import org.springframework.integration.Message;
import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.handler.DelayHandler;
import org.springframework.integration.test.util.TestUtils;
@@ -48,6 +52,7 @@ import org.springframework.transaction.interceptor.TransactionInterceptor;
* @author Mark Fisher
* @author Artem Bilan
* @author Gunnar Hillert
* @author Gary Russell
* @since 1.0.3
*/
@RunWith(SpringJUnit4ClassRunner.class)
@@ -100,7 +105,7 @@ public class DelayerParserTests {
}
@Test //INT-2649
public void transactionalSubElement() {
public void transactionalSubElement() throws Exception {
Object endpoint = context.getBean("delayerWithTransactional");
DelayHandler delayHandler = TestUtils.getPropertyValue(endpoint, "handler", DelayHandler.class);
List<?> adviceChain = TestUtils.getPropertyValue(delayHandler, "delayedAdviceChain", List.class);
@@ -109,7 +114,8 @@ public class DelayerParserTests {
assertTrue(advice instanceof TransactionInterceptor);
TransactionAttributeSource transactionAttributeSource = ((TransactionInterceptor) advice).getTransactionAttributeSource();
assertTrue(transactionAttributeSource instanceof MatchAlwaysTransactionAttributeSource);
TransactionDefinition definition = transactionAttributeSource.getTransactionAttribute(null, null);
Method method = MessageHandler.class.getMethod("handleMessage", Message.class);
TransactionDefinition definition = transactionAttributeSource.getTransactionAttribute(method, null);
assertEquals(TransactionDefinition.PROPAGATION_REQUIRED, definition.getPropagationBehavior());
assertEquals(TransactionDefinition.ISOLATION_DEFAULT, definition.getIsolationLevel());
assertEquals(TransactionDefinition.TIMEOUT_DEFAULT, definition.getTimeout());

View File

@@ -39,12 +39,12 @@ import org.springframework.util.StopWatch;
/**
* @author Oleg Zhurakousky
* @author Gunnar Hillert
* @author Gary Russell
*/
public class MessageIdGenerationTests {
@Test
public void testCustomIdGenerationWithParentRegistrar() throws Exception{
public void testCustomIdGenerationWithParentRegistrar() throws Exception {
ClassPathXmlApplicationContext parent = new ClassPathXmlApplicationContext("MessageIdGenerationTests-context-withGenerator.xml", this.getClass());
ClassPathXmlApplicationContext child = new ClassPathXmlApplicationContext(new String[]{"MessageIdGenerationTests-context.xml"}, this.getClass(), parent);
@@ -58,7 +58,7 @@ public class MessageIdGenerationTests {
}
@Test
public void testCustomIdGenerationWithParentChileIndependentCreation() throws Exception{
public void testCustomIdGenerationWithParentChildIndependentCreation() throws Exception {
ClassPathXmlApplicationContext parent = new ClassPathXmlApplicationContext("MessageIdGenerationTests-context-withGenerator.xml", this.getClass());
GenericXmlApplicationContext child = new GenericXmlApplicationContext();
child.load("classpath:/org/springframework/integration/core/MessageIdGenerationTests-context.xml");
@@ -89,7 +89,7 @@ public class MessageIdGenerationTests {
}
@Test
public void testCustomIdGenerationWithChildRegistrar() throws Exception{
public void testCustomIdGenerationWithChildRegistrar() throws Exception {
ClassPathXmlApplicationContext parent = new ClassPathXmlApplicationContext("MessageIdGenerationTests-context.xml", this.getClass());
ClassPathXmlApplicationContext child = new ClassPathXmlApplicationContext(new String[]{"MessageIdGenerationTests-context-withGenerator.xml"}, this.getClass(), parent);
@@ -98,13 +98,13 @@ public class MessageIdGenerationTests {
MessageChannel inputChannel = child.getBean("input", MessageChannel.class);
inputChannel.send(new GenericMessage<Integer>(0));
verify(idGenerator, atLeastOnce()).generateId();
parent.close();
child.close();
parent.close();
this.assertDestroy();
}
@Test
public void testCustomIdGenerationWithChildRegistrarClosed() throws Exception{
public void testCustomIdGenerationWithChildRegistrarClosed() throws Exception {
ClassPathXmlApplicationContext parent = new ClassPathXmlApplicationContext("MessageIdGenerationTests-context.xml", this.getClass());
ClassPathXmlApplicationContext child = new ClassPathXmlApplicationContext(new String[]{"MessageIdGenerationTests-context-withGenerator.xml"}, this.getClass(), parent);
@@ -120,7 +120,7 @@ public class MessageIdGenerationTests {
// similar to the last test, but should not fail because child AC is closed before second child AC is started
@Test
public void testCustomIdGenerationWithParentChildIndependentCreationChildrenRegistrarsOneAtTheTime() throws Exception{
public void testCustomIdGenerationWithParentChildIndependentCreationChildrenRegistrarsOneAtTheTime() throws Exception {
ClassPathXmlApplicationContext parent = new ClassPathXmlApplicationContext("MessageIdGenerationTests-context.xml", this.getClass());
GenericXmlApplicationContext childA = new GenericXmlApplicationContext();
@@ -142,7 +142,7 @@ public class MessageIdGenerationTests {
@Test
@Ignore
public void performanceTest(){
public void performanceTest() {
int times = 1000000;
StopWatch watch = new StopWatch();
watch.start();

View File

@@ -20,4 +20,10 @@
<int:channel id="requestChannelBar"/>
<int:channel id="requestChannelBaz"/>
<int:gateway id="customMappedGateway"
service-interface="org.springframework.integration.gateway.GatewayInterfaceTests.Baz"
default-request-channel="requestChannelBaz" mapper="mapper"/>
<bean id="mapper" class="org.springframework.integration.gateway.GatewayInterfaceTests$BazMapper"/>
</beans>

View File

@@ -40,6 +40,7 @@ import org.springframework.integration.channel.DirectChannel;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.support.MessageBuilder;
/**
* @author Oleg Zhurakousky
@@ -238,6 +239,26 @@ public class GatewayInterfaceTests {
new GatewayProxyFactoryBean(NotAnInterface.class);
}
@Test
public void testWithCustomMapper() {
ApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this.getClass());
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
final AtomicBoolean called = new AtomicBoolean();
MessageHandler handler = new MessageHandler() {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
assertThat((String) message.getPayload(), equalTo("fizbuz"));
called.set(true);
}
};
channel.subscribe(handler);
Baz baz = ac.getBean(Baz.class);
baz.baz("hello");
assertTrue(called.get());
}
public interface Foo {
@Gateway(requestChannel="requestChannelFoo")
@@ -256,4 +277,18 @@ public class GatewayInterfaceTests {
public static class NotAnInterface {
public void fail(String payload){}
}
public interface Baz {
public void baz(String payload);
}
public static class BazMapper implements MethodArgsMessageMapper {
@Override
public Message<?> toMessage(MethodArgsHolder object) throws Exception {
return MessageBuilder.withPayload("fizbuz").build();
}
}
}

View File

@@ -34,6 +34,7 @@ import org.springframework.messaging.Message;
import org.springframework.integration.annotation.Header;
import org.springframework.integration.annotation.Headers;
import org.springframework.integration.annotation.Payload;
import org.springframework.integration.mapping.MessageMappingException;
import org.springframework.integration.support.MessageBuilder;
/**
@@ -78,7 +79,7 @@ public class GatewayMethodInboundMessageMapperToMessageTests {
assertEquals("bar", message.getHeaders().get("foo"));
}
@Test(expected = IllegalArgumentException.class)
@Test(expected = MessageMappingException.class)
public void toMessageWithPayloadAndRequiredHeaderButNullValue() throws Exception {
Method method = TestService.class.getMethod(
"sendPayloadAndHeader", String.class, String.class);
@@ -134,7 +135,7 @@ public class GatewayMethodInboundMessageMapperToMessageTests {
assertEquals("test", message.getPayload());
}
@Test(expected = IllegalArgumentException.class)
@Test(expected = MessageMappingException.class)
public void toMessageWithPayloadAndHeadersMapWithNonStringKey() throws Exception {
Method method = TestService.class.getMethod(
"sendPayloadAndHeadersMap", String.class, Map.class);
@@ -166,7 +167,7 @@ public class GatewayMethodInboundMessageMapperToMessageTests {
assertEquals("bar", message.getHeaders().get("foo"));
}
@Test(expected = IllegalArgumentException.class)
@Test(expected = MessageMappingException.class)
public void toMessageWithMessageParameterAndRequiredHeaderButNullValue() throws Exception {
Method method = TestService.class.getMethod("sendMessageAndHeader", Message.class, String.class);
GatewayMethodInboundMessageMapper mapper = new GatewayMethodInboundMessageMapper(method);
@@ -197,7 +198,7 @@ public class GatewayMethodInboundMessageMapperToMessageTests {
assertNull(message.getHeaders().get("foo"));
}
@Test(expected = IllegalArgumentException.class)
@Test(expected = MessageMappingException.class)
public void noArgs() throws Exception {
Method method = TestService.class.getMethod("noArgs", new Class<?>[] {});
GatewayMethodInboundMessageMapper mapper = new GatewayMethodInboundMessageMapper(method);
@@ -205,7 +206,7 @@ public class GatewayMethodInboundMessageMapperToMessageTests {
mapper.toMessage(new Object[] {});
}
@Test(expected = IllegalArgumentException.class)
@Test(expected = MessageMappingException.class)
public void onlyHeaders() throws Exception {
Method method = TestService.class.getMethod("onlyHeaders", String.class, String.class);
GatewayMethodInboundMessageMapper mapper = new GatewayMethodInboundMessageMapper(method);

View File

@@ -94,7 +94,7 @@ public class ServiceActivatorDefaultFrameworkMethodTests {
}
@Test
public void testNotOptimizedReplyingMessageHandler() {
public void testOptimizedReplyingMessageHandler() {
QueueChannel replyChannel = new QueueChannel();
Message<?> message = MessageBuilder.withPayload("test").setReplyChannel(replyChannel).build();
this.optimizedRefReplyingHandlerTestInputChannel.send(message);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2013 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.
@@ -24,18 +24,17 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.integration.config.ConsumerEndpointFactoryBean;
import org.springframework.messaging.PollableChannel;
import org.springframework.integration.router.AbstractMappingMessageRouter;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.PollableChannel;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Mark Fisher
* @author Gary Russell
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@@ -43,10 +42,10 @@ public class RouterWithMappingTests {
@Autowired
private MessageChannel expressionRouter;
@Autowired
@Qualifier("spelRouter")
private ConsumerEndpointFactoryBean spelRouter;
@Qualifier("spelRouter.handler")
private AbstractMappingMessageRouter spelRouterHandler;
@Autowired
private MessageChannel pojoRouter;
@@ -87,8 +86,7 @@ public class RouterWithMappingTests {
assertNull(fooChannelForExpression.receive(0));
assertNull(barChannelForExpression.receive(0));
// validate dynamics
AbstractMappingMessageRouter router = (AbstractMappingMessageRouter) TestUtils.getPropertyValue(spelRouter, "handler");
router.setChannelMapping("baz", "fooChannelForExpression");
spelRouterHandler.setChannelMapping("baz", "fooChannelForExpression");
expressionRouter.send(message3);
assertNull(defaultChannelForExpression.receive(10));
assertNotNull(fooChannelForExpression.receive(10));