From b37cd05aff945c4503e2a954e5e4b22e5b9ded49 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Fri, 23 Jul 2010 18:03:01 +0000 Subject: [PATCH] INT-670 added support for 'payload-expression' on element's sub-elements --- .../integration/config/xml/GatewayParser.java | 24 +++--- .../gateway/GatewayMethodDefinition.java | 47 ++++++++--- .../gateway/GatewayProxyFactoryBean.java | 7 +- .../handler/ArgumentArrayMessageMapper.java | 6 +- .../config/xml/spring-integration-2.0.xsd | 21 +++-- ...ewayWithPayloadExpressionTests-context.xml | 21 +++++ .../GatewayWithPayloadExpressionTests.java | 79 +++++++++++++++++++ ...derEnrichedGatewayTests-failed-context.xml | 17 ---- .../gateway/HeaderEnrichedGatewayTests.java | 36 ++++----- 9 files changed, 187 insertions(+), 71 deletions(-) create mode 100644 spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayWithPayloadExpressionTests-context.xml create mode 100644 spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayWithPayloadExpressionTests.java delete mode 100644 spring-integration-core/src/test/java/org/springframework/integration/gateway/HeaderEnrichedGatewayTests-failed-context.xml diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/GatewayParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/GatewayParser.java index aedd49d8b7..0a1f855557 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/GatewayParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/GatewayParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -19,16 +19,15 @@ package org.springframework.integration.config.xml; import java.util.List; import java.util.Map; +import org.w3c.dom.Element; + import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.ManagedMap; import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; -import org.springframework.integration.core.MessageHeaders; -import org.springframework.integration.gateway.GatewayMethodDefinition; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.xml.DomUtils; -import org.w3c.dom.Element; /** * Parser for the <gateway/> element. @@ -88,11 +87,13 @@ public class GatewayParser extends AbstractSimpleBeanDefinitionParser { } for (Element methodElement : elements) { String methodName = methodElement.getAttribute("name"); - BeanDefinitionBuilder gatewayDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(GatewayMethodDefinition.class); + BeanDefinitionBuilder gatewayDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition( + "org.springframework.integration.gateway.GatewayMethodDefinition"); gatewayDefinitionBuilder.addPropertyValue("requestChannelName", methodElement.getAttribute("request-channel")); gatewayDefinitionBuilder.addPropertyValue("replyChannelName", methodElement.getAttribute("reply-channel")); gatewayDefinitionBuilder.addPropertyValue("requestTimeout", methodElement.getAttribute("request-timeout")); gatewayDefinitionBuilder.addPropertyValue("replyTimeout", methodElement.getAttribute("reply-timeout")); + IntegrationNamespaceUtils.setValueIfAttributeDefined(gatewayDefinitionBuilder, methodElement, "payload-expression"); List invocationHeaders = DomUtils.getChildElementsByTagName(methodElement, "header"); if (!CollectionUtils.isEmpty(invocationHeaders)){ this.setMethodInvocationHeaders(gatewayDefinitionBuilder, invocationHeaders); @@ -101,20 +102,13 @@ public class GatewayParser extends AbstractSimpleBeanDefinitionParser { } builder.addPropertyValue("methodToChannelMap", methodToChannelMap); } - /* - * - */ + private void setMethodInvocationHeaders(BeanDefinitionBuilder gatewayDefinitionBuilder, List invocationHeaders){ Map methodInvocationHeaders = new ManagedMap(); for (Element headerElement : invocationHeaders) { - String name = headerElement.getAttribute("name"); - if (name.startsWith(MessageHeaders.PREFIX)){ - throw new IllegalArgumentException("Attempting to set header: " + name + ". Prefix: '" - + MessageHeaders.PREFIX + "' is reservered for SI internal use"); - } else { - methodInvocationHeaders.put(name, headerElement.getAttribute("value")); - } + methodInvocationHeaders.put(headerElement.getAttribute("name"), headerElement.getAttribute("value")); } gatewayDefinitionBuilder.addPropertyValue("staticHeaders", methodInvocationHeaders); } + } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodDefinition.java b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodDefinition.java index c810ee39a8..f2c44b3d27 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodDefinition.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodDefinition.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2010 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. @@ -13,55 +13,80 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.integration.gateway; import java.util.HashMap; import java.util.Map; /** - * Represents the definition of Gateway methods, when using multiple methos per - * Gateway interface
- * + * Represents the definition of Gateway methods, when using multiple methods per Gateway interface. + * <si:method name="echo" request-channel="inputA" reply-timeout="2" request-timeout="200"/> * * @author Oleg Zhurakousky - * @since 2.0.M1 + * @since 2.0 */ public class GatewayMethodDefinition { - private String requestChannelName; - private String replyChannelName; - private String requestTimeout; - private String replyTimeout; - private Map staticHeaders = new HashMap(); + private volatile String payloadExpression; + + private volatile String requestChannelName; + + private volatile String replyChannelName; + + private volatile String requestTimeout; + + private volatile String replyTimeout; + + private volatile Map staticHeaders = new HashMap(); + + + public String getPayloadExpression() { + return payloadExpression; + } + + public void setPayloadExpression(String payloadExpression) { + this.payloadExpression = payloadExpression; + } + public Map getStaticHeaders() { return staticHeaders; } + public void setStaticHeaders(Map staticHeaders) { this.staticHeaders = staticHeaders; } + public String getRequestChannelName() { return requestChannelName; } + public void setRequestChannelName(String requestChannelName) { this.requestChannelName = requestChannelName; } + public String getReplyChannelName() { return replyChannelName; } + public void setReplyChannelName(String replyChannelName) { this.replyChannelName = replyChannelName; } + public String getRequestTimeout() { return requestTimeout; } + public void setRequestTimeout(String requestTimeout) { this.requestTimeout = requestTimeout; } + public String getReplyTimeout() { return replyTimeout; } + public void setReplyTimeout(String replyTimeout) { this.replyTimeout = replyTimeout; } - + } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java index ab149f6b2b..b85566fbbe 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java @@ -266,6 +266,7 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Factory MessageChannel replyChannel = this.defaultReplyChannel; long requestTimeout = this.defaultRequestTimeout; long replyTimeout = this.defaultReplyTimeout; + String payloadExpression = null; Map staticHeaders = null; if (gatewayAnnotation != null) { Assert.state(this.getChannelResolver() != null, "ChannelResolver is required"); @@ -280,6 +281,7 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Factory Assert.state(this.getChannelResolver() != null, "ChannelResolver is required"); GatewayMethodDefinition gatewayDefinition = methodToChannelMap.get(method.getName()); if (gatewayDefinition != null) { + payloadExpression = gatewayDefinition.getPayloadExpression(); staticHeaders = gatewayDefinition.getStaticHeaders(); String requestChannelName = gatewayDefinition.getRequestChannelName(); requestChannel = this.resolveChannel(requestChannel, requestChannelName); @@ -296,7 +298,10 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Factory } } ArgumentArrayMessageMapper messageMapper = new ArgumentArrayMessageMapper(method, staticHeaders); - messageMapper.setBeanFactory(this.getBeanFactory()); + if (StringUtils.hasText(payloadExpression)) { + messageMapper.setPayloadExpression(payloadExpression); + } + messageMapper.setBeanFactory(this.getBeanFactory()); SimpleMessagingGateway gateway = new SimpleMessagingGateway(messageMapper, new SimpleMessageMapper()); gateway.setExceptionMapper(exceptionMapper); if (this.getTaskScheduler() != null) { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/ArgumentArrayMessageMapper.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/ArgumentArrayMessageMapper.java index c49c316ff9..5f8fc08e1b 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/ArgumentArrayMessageMapper.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/ArgumentArrayMessageMapper.java @@ -113,7 +113,7 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper parameterList; - private final Expression payloadExpression; + private volatile Expression payloadExpression; private final Map parameterPayloadExpressions = new HashMap(); @@ -135,6 +135,10 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper - + @@ -473,12 +473,21 @@ + + + + + + + - + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayWithPayloadExpressionTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayWithPayloadExpressionTests-context.xml new file mode 100644 index 0000000000..b743f96f25 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayWithPayloadExpressionTests-context.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayWithPayloadExpressionTests.java b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayWithPayloadExpressionTests.java new file mode 100644 index 0000000000..bd50e8d02d --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayWithPayloadExpressionTests.java @@ -0,0 +1,79 @@ +/* + * Copyright 2002-2010 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 static junit.framework.Assert.assertEquals; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.integration.channel.PollableChannel; +import org.springframework.integration.core.Message; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Mark Fisher + * @since 2.0 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class GatewayWithPayloadExpressionTests { + + @Autowired + private SampleGateway gateway; + + @Autowired + private PollableChannel input; + + + @Test + public void simpleExpression() throws Exception { + gateway.send1("foo"); + Message result = input.receive(0); + assertEquals("foobar", result.getPayload()); + } + + @Test + public void beanResolvingExpression() throws Exception { + gateway.send2("foo"); + Message result = input.receive(0); + assertEquals(324, result.getPayload()); + } + + + public static interface SampleGateway { + + void send1(String value); + + void send2(String value); + } + + + public static class TestBean { + + public int sum(String s) { + int sum = 0; + for (byte b : s.getBytes()) { + sum += b; + } + return sum; + } + } + +} diff --git a/spring-integration-core/src/test/java/org/springframework/integration/gateway/HeaderEnrichedGatewayTests-failed-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/gateway/HeaderEnrichedGatewayTests-failed-context.xml deleted file mode 100644 index 5ff5c76419..0000000000 --- a/spring-integration-core/src/test/java/org/springframework/integration/gateway/HeaderEnrichedGatewayTests-failed-context.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - diff --git a/spring-integration-core/src/test/java/org/springframework/integration/gateway/HeaderEnrichedGatewayTests.java b/spring-integration-core/src/test/java/org/springframework/integration/gateway/HeaderEnrichedGatewayTests.java index a1d55075b7..80d69ddd89 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/gateway/HeaderEnrichedGatewayTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/gateway/HeaderEnrichedGatewayTests.java @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.integration.gateway; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNull; @@ -22,10 +24,8 @@ import org.junit.runner.RunWith; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -import org.springframework.beans.factory.BeanDefinitionStoreException; + import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.integration.annotation.Header; import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.core.Message; @@ -41,15 +41,16 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class HeaderEnrichedGatewayTests { + @Autowired - @Qualifier("gateway") private SampleGateway gateway; + @Autowired - @Qualifier("input") private DirectChannel input; - + private Object testPayload; + @Test public void validateStaticHeaderMappings() throws Exception { MessageHandler handler = Mockito.mock(MessageHandler.class); @@ -70,19 +71,13 @@ public class HeaderEnrichedGatewayTests { gateway.sendStringWithParameterHeaders((String) testPayload, "headerA", "headerB"); Mockito.verify(handler, Mockito.times(1)).handleMessage(Mockito.any(Message.class)); } - @Test(expected=BeanDefinitionStoreException.class) - public void validateFailedGatewayHeaders() throws Exception { - new ClassPathXmlApplicationContext("HeaderEnrichedGatewayTests-failed-context.xml", HeaderEnrichedGatewayTests.class); - } - /* - * - */ - @SuppressWarnings("unchecked") - private void prepareHandlerForTest(MessageHandler handler){ + + + private void prepareHandlerForTest(MessageHandler handler) { Mockito.reset(handler); - Mockito.doAnswer(new Answer() { + Mockito.doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) { - Message message = (Message) invocation.getArguments()[0]; + Message message = (Message) invocation.getArguments()[0]; assertEquals(testPayload, message.getPayload()); assertEquals("foo", message.getHeaders().get("foo")); assertEquals("bar", message.getHeaders().get("bar")); @@ -95,10 +90,10 @@ public class HeaderEnrichedGatewayTests { }}) .when(handler).handleMessage(Mockito.any(Message.class)); } - /* - * - */ + + public static interface SampleGateway { + public void sendString(String value); public void sendInteger(Integer value); @@ -106,4 +101,5 @@ public class HeaderEnrichedGatewayTests { public void sendStringWithParameterHeaders(String value, @Header("headerA") String headerA, @Header("headerB") String headerB); } + }