diff --git a/spring-integration-core/src/main/java/org/springframework/integration/mapping/HeaderMapper.java b/spring-integration-core/src/main/java/org/springframework/integration/mapping/HeaderMapper.java index 70b010d150..ba3fdeba1f 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/mapping/HeaderMapper.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/mapping/HeaderMapper.java @@ -33,6 +33,6 @@ public interface HeaderMapper { void fromHeaders(MessageHeaders headers, T target); - Map toHeaders(T source); + Map toHeaders(T source); } diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/config/HttpInboundEndpointParser.java b/spring-integration-http/src/main/java/org/springframework/integration/http/config/HttpInboundEndpointParser.java index f99f8f5f80..8a648d0816 100644 --- a/spring-integration-http/src/main/java/org/springframework/integration/http/config/HttpInboundEndpointParser.java +++ b/spring-integration-http/src/main/java/org/springframework/integration/http/config/HttpInboundEndpointParser.java @@ -16,14 +16,21 @@ package org.springframework.integration.http.config; +import java.util.List; + import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; +import org.springframework.beans.factory.support.ManagedMap; +import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.integration.config.ExpressionFactoryBean; import org.springframework.integration.config.xml.IntegrationNamespaceUtils; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; - +import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; /** @@ -60,8 +67,9 @@ public class HttpInboundEndpointParser extends AbstractSingleBeanDefinitionParse id = element.getAttribute("name"); } if (!StringUtils.hasText(id)) { - parserContext.getReaderContext().error("The 'id' or 'name' is required.", element); + id = BeanDefinitionReaderUtils.generateBeanName(definition, parserContext.getRegistry()); } + return id; } @@ -76,6 +84,32 @@ public class HttpInboundEndpointParser extends AbstractSingleBeanDefinitionParse } builder.addPropertyReference("requestChannel", inputChannelRef); IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "error-channel"); + + + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "path"); + String payloadExpression = element.getAttribute("payload-expression"); + if (StringUtils.hasText(payloadExpression)){ + RootBeanDefinition expressionDef = new RootBeanDefinition(ExpressionFactoryBean.class); + expressionDef.getConstructorArgumentValues().addGenericArgumentValue(payloadExpression); + builder.addPropertyValue("payloadExpression", expressionDef); + } + + List headerElements = DomUtils.getChildElementsByTagName(element, "header"); + + if (!CollectionUtils.isEmpty(headerElements)) { + ManagedMap headerElementsMap = new ManagedMap(); + for (Element headerElement : headerElements) { + String name = headerElement.getAttribute("name"); + String expression = headerElement.getAttribute("expression"); + if (StringUtils.hasText(expression)){ + RootBeanDefinition expressionDef = new RootBeanDefinition(ExpressionFactoryBean.class); + expressionDef.getConstructorArgumentValues().addGenericArgumentValue(expression); + headerElementsMap.put(name, expressionDef); + } + } + builder.addPropertyValue("headerExpressions", headerElementsMap); + } + if (this.expectReply) { IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "request-timeout"); diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingEndpointSupport.java b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingEndpointSupport.java index 363b016060..90b7f8b7a2 100644 --- a/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingEndpointSupport.java +++ b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingEndpointSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2011 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. @@ -27,6 +27,13 @@ import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.context.expression.BeanFactoryResolver; +import org.springframework.context.expression.MapAccessor; +import org.springframework.core.convert.ConversionService; +import org.springframework.expression.Expression; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.expression.spel.support.StandardTypeConverter; +import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; @@ -50,13 +57,18 @@ import org.springframework.integration.http.multipart.MultipartHttpInputMessage; import org.springframework.integration.http.support.DefaultHttpHeaderMapper; import org.springframework.integration.mapping.HeaderMapper; import org.springframework.integration.support.MessageBuilder; +import org.springframework.util.AntPathMatcher; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.CollectionUtils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; +import org.springframework.util.PathMatcher; +import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.MultipartResolver; import org.springframework.web.servlet.DispatcherServlet; +import org.springframework.web.util.UrlPathHelper; /** * Base class for HTTP request handling endpoints. @@ -79,10 +91,11 @@ import org.springframework.web.servlet.DispatcherServlet; * false. * * @author Mark Fisher + * @author Oleg Zhurakousky * @since 2.0 */ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySupport { - + private static final boolean jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", HttpRequestHandlingEndpointSupport.class.getClassLoader()); @@ -104,9 +117,19 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor private final boolean expectReply; + private volatile String path; + + private final UrlPathHelper urlPathHelper = new UrlPathHelper(); + + private final PathMatcher pathMatcher = new AntPathMatcher(); + private volatile boolean extractReplyPayload = true; private volatile MultipartResolver multipartResolver; + + private volatile Expression payloadExpression; + + private volatile Map headerExpressions; public HttpRequestHandlingEndpointSupport() { this(true); @@ -141,6 +164,39 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor return expectReply; } + /** + * Set the path template for which this endpoint expects requests. + * May include path variable {keys} to match against. + */ + public void setPath(String path) { + this.path = path; + } + + String getPath() { + return path; + } + + /** + * Specifies a SpEL expression to evaluate in order to generate the Message payload. + * The EvaluationContext will be populated with an HttpEntity instance as the root object, + * and it may contain one or both of the #pathVariables and + * #queryParameters variables if present. Those variables' values are Maps. + */ + public void setPayloadExpression(Expression payloadExpression) { + this.payloadExpression = payloadExpression; + } + + /** + * Specifies a Map of SpEL expressions to evaluate in order to generate the Message headers. + * The keys in the map will be used as the header names. When evaluating the expression, + * the EvaluationContext will be populated with an HttpEntity instance as the root object, + * and it may contain one or both of the #pathVariables and + * #queryParameters variables if present. Those variables' values are Maps. + */ + public void setHeaderExpressions(Map headerExpressions) { + this.headerExpressions = headerExpressions; + } + /** * Set the message body converters to use. These converters are used to convert from and to HTTP requests and * responses. @@ -244,28 +300,71 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor * Handles the HTTP request by generating a Message and sending it to the request channel. If this gateway's * 'expectReply' property is true, it will also generate a response from the reply Message once received. */ - protected final Object doHandleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) - throws IOException { + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected final Object doHandleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException { try { ServletServerHttpRequest request = this.prepareRequest(servletRequest); if (!this.supportedMethods.contains(request.getMethod())) { servletResponse.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); return null; } - Object payload = null; + + Object requestBody = null; if (this.isReadable(request)) { - payload = this.generatePayloadFromRequestBody(request); + requestBody = this.extractRequestBody(request); } - else { - payload = this.convertParameterMap(servletRequest.getParameterMap()); + HttpEntity httpEntity = new HttpEntity(requestBody, request.getHeaders()); + + StandardEvaluationContext evaluationContext = this.createEvaluationContext(); + evaluationContext.setRootObject(httpEntity); + + LinkedMultiValueMap requestParams = this.convertParameterMap(servletRequest.getParameterMap()); + evaluationContext.setVariable("requestParams", requestParams); + + if (StringUtils.hasText(this.path)) { + String lookupPath = this.urlPathHelper.getLookupPathForRequest(servletRequest); + Map pathVariables = this.pathMatcher.extractUriTemplateVariables(this.path, lookupPath); + if (!pathVariables.isEmpty()) { + if (logger.isDebugEnabled()) { + logger.debug("Mapped path variables: " + pathVariables); + } + evaluationContext.setVariable("pathVariables", pathVariables); + } } - Map headers = this.headerMapper.toHeaders(request.getHeaders()); - Message message = MessageBuilder.withPayload(payload).copyHeaders(headers).setHeader( - org.springframework.integration.http.HttpHeaders.REQUEST_URL, request.getURI().toString()) + + Map headers = this.headerMapper.toHeaders(request.getHeaders()); + Object payload = null; + if (this.payloadExpression != null) { + // create payload based on SpEL + payload = this.payloadExpression.getValue(evaluationContext); + } + if (!CollectionUtils.isEmpty(this.headerExpressions)) { + for (String headerName : this.headerExpressions.keySet()) { + Expression headerExpression = this.headerExpressions.get(headerName); + Object headerValue = headerExpression.getValue(evaluationContext); + if (headerValue != null) { + headers.put(headerName, headerValue); + } + } + } + + if (payload == null) { + if (requestBody != null) { + payload = requestBody; + } + else { + payload = requestParams; + } + } + + Message message = MessageBuilder.withPayload(payload).copyHeaders(headers) + .setHeader(org.springframework.integration.http.HttpHeaders.REQUEST_URL, + request.getURI().toString()) .setHeader(org.springframework.integration.http.HttpHeaders.REQUEST_METHOD, - request.getMethod().toString()).setHeader( - org.springframework.integration.http.HttpHeaders.USER_PRINCIPAL, + request.getMethod().toString()) + .setHeader(org.springframework.integration.http.HttpHeaders.USER_PRINCIPAL, servletRequest.getUserPrincipal()).build(); + Object reply = null; if (this.expectReply) { reply = this.sendAndReceiveMessage(message); @@ -273,7 +372,7 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor ServletServerHttpResponse response = new ServletServerHttpResponse(servletResponse); this.headerMapper.fromHeaders(((Message) reply).getHeaders(), response.getHeaders()); HttpStatus httpStatus = this.resolveHttpStatusFromHeaders(((Message) reply).getHeaders()); - if (httpStatus != null){ + if (httpStatus != null) { response.setStatusCode(httpStatus); } response.close(); @@ -348,7 +447,7 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor } @SuppressWarnings({"unchecked", "rawtypes"}) - private Object generatePayloadFromRequestBody(ServletServerHttpRequest request) throws IOException { + private Object extractRequestBody(ServletServerHttpRequest request) throws IOException { MediaType contentType = request.getHeaders().getContentType(); Class expectedType = this.requestPayloadType; if (expectedType == null) { @@ -378,5 +477,18 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor } return httpStatus; } - + + private StandardEvaluationContext createEvaluationContext(){ + StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); + evaluationContext.addPropertyAccessor(new MapAccessor()); + BeanFactory beanFactory = this.getBeanFactory(); + if (beanFactory != null) { + evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory)); + } + ConversionService conversionService = this.getConversionService(); + if (conversionService != null) { + evaluationContext.setTypeConverter(new StandardTypeConverter(conversionService)); + } + return evaluationContext; + } } diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/UriPathHandlerMapping.java b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/UriPathHandlerMapping.java new file mode 100644 index 0000000000..971f11abd9 --- /dev/null +++ b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/UriPathHandlerMapping.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2011 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.http.inbound; + +import org.springframework.web.servlet.handler.AbstractDetectingUrlHandlerMapping; + +/** + * A {@link org.springframework.web.servlet.HandlerMapping} implementation that matches + * against the value of the 'path' attribute, if present, on a Spring Integration HTTP + * <inbound-channel-adapter> or <inbound-gateway> element. + * + * @author Oleg Zhurakousky + * @author Mark Fisher + * @since 2.1 + */ +public class UriPathHandlerMapping extends AbstractDetectingUrlHandlerMapping { + + @Override + protected String[] determineUrlsForHandler(String beanName) { + String[] urls = null; + Class beanClass = getApplicationContext().getType(beanName); + if (HttpRequestHandlingEndpointSupport.class.isAssignableFrom(beanClass)) { + HttpRequestHandlingEndpointSupport endpoint = getApplicationContext().getBean(beanName, HttpRequestHandlingEndpointSupport.class); + String path = endpoint.getPath(); + if (path != null) { + urls = new String[]{path}; + } + } + return urls; + } + +} diff --git a/spring-integration-http/src/main/resources/org/springframework/integration/http/config/spring-integration-http-2.1.xsd b/spring-integration-http/src/main/resources/org/springframework/integration/http/config/spring-integration-http-2.1.xsd index 92a827ea1c..a39372fd6d 100644 --- a/spring-integration-http/src/main/resources/org/springframework/integration/http/config/spring-integration-http-2.1.xsd +++ b/spring-integration-http/src/main/resources/org/springframework/integration/http/config/spring-integration-http-2.1.xsd @@ -20,8 +20,18 @@ Defines an inbound HTTP-based Channel Adapter. + + + - + + + + [DEPRECATED since v2.1] Use 'path' attribute if you want to specify the path or + 'id' attribute if you simply want to identify this component + + + @@ -57,6 +67,20 @@ + + + + Allows you to specify SpEL expression to construct a Message payload + + + + + + + Allows you to specify URI path (e.g., /orderId/{order}) + + + @@ -116,6 +140,9 @@ The String "HTTP_REQUEST_HEADERS" will match against any of the standard HTTP Re + + + @@ -135,6 +162,20 @@ The String "HTTP_REQUEST_HEADERS" will match against any of the standard HTTP Re + + + + Allows you to specify SpEL expression to construct a Message payload + + + + + + + Allows you to specify URI path (e.g., /orderId/{order}) + + + @@ -493,6 +534,28 @@ The String "HTTP_REQUEST_HEADERS" will match against any of the standard HTTP Re + + + + + + + + + + + + + + + + diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpInboundChannelAdapterParserTests-context.xml b/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpInboundChannelAdapterParserTests-context.xml index 4dc44dabb2..dff2dee5a0 100644 --- a/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpInboundChannelAdapterParserTests-context.xml +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpInboundChannelAdapterParserTests-context.xml @@ -26,5 +26,28 @@ + + +
+ + + +
+ + + +
+ diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpInboundChannelAdapterParserTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpInboundChannelAdapterParserTests.java index 18a0252235..47b6b4eb47 100644 --- a/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpInboundChannelAdapterParserTests.java +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpInboundChannelAdapterParserTests.java @@ -35,6 +35,8 @@ import org.junit.runner.RunWith; import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.integration.Message; @@ -46,6 +48,7 @@ import org.springframework.integration.http.inbound.HttpRequestHandlingMessaging import org.springframework.integration.http.support.DefaultHttpHeaderMapper; import org.springframework.integration.test.util.TestUtils; import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.ExpectedException; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.util.MultiValueMap; @@ -72,7 +75,18 @@ public class HttpInboundChannelAdapterParserTests { @Autowired private HttpRequestHandlingMessagingGateway withMappedHeaders; - + + @Autowired + private HttpRequestHandlingMessagingGateway inboundAdapterWithExpressions; + + @Autowired + @Qualifier("/fname/{blah}/lname/{boo}") + private HttpRequestHandlingMessagingGateway inboundAdapterWithNameAndExpressions; + + @Autowired + @Qualifier("/fname/{f}/lname/{l}") + private HttpRequestHandlingMessagingGateway inboundAdapterWithNameNoPath; + @Autowired private HttpRequestHandlingController inboundController; @@ -113,6 +127,72 @@ public class HttpInboundChannelAdapterParserTests { assertEquals("foo", map.get("foo")); assertEquals("bar", map.get("bar")); } + + @Test + // INT-1677 + public void withExpressions() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("POST"); + request.setContentType("text/plain"); + request.setParameter("foo", "bar"); + request.setContent("hello".getBytes()); + request.setRequestURI("/fname/bill/lname/clinton"); + + MockHttpServletResponse response = new MockHttpServletResponse(); + inboundAdapterWithExpressions.handleRequest(request, response); + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); + Message message = requests.receive(0); + assertNotNull(message); + Object payload = message.getPayload(); + assertTrue(payload instanceof String); + assertEquals("bill", payload); + assertEquals("clinton", message.getHeaders().get("lname")); + } + + @Test // ensure that 'path' takes priority over name + // INT-1677 + public void withNameAndExpressionsAndPath() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("POST"); + request.setContentType("text/plain"); + request.setParameter("foo", "bar"); + request.setContent("hello".getBytes()); + request.setRequestURI("/fname/bill/lname/clinton"); + + MockHttpServletResponse response = new MockHttpServletResponse(); + inboundAdapterWithNameAndExpressions.handleRequest(request, response); + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); + Message message = requests.receive(0); + assertNotNull(message); + Object payload = message.getPayload(); + assertTrue(payload instanceof String); + assertEquals("bill", payload); + assertEquals("clinton", message.getHeaders().get("lname")); + } + + @Test + // INT-1677 + @ExpectedException(SpelEvaluationException.class) + public void withNameAndExpressionsNoPath() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("POST"); + request.setContentType("text/plain"); + request.setParameter("foo", "bar"); + request.setContent("hello".getBytes()); + request.setRequestURI("/fname/bill/lname/clinton"); + + MockHttpServletResponse response = new MockHttpServletResponse(); + inboundAdapterWithNameNoPath.handleRequest(request, response); + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); + Message message = requests.receive(0); + assertNotNull(message); + Object payload = message.getPayload(); + assertTrue(payload instanceof String); + assertEquals("hello", payload); // default payload + assertNull(message.getHeaders().get("lname")); + } + + @Test public void getRequestNotAllowed() throws Exception { diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGatewayWithPathMappingTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGatewayWithPathMappingTests.java new file mode 100644 index 0000000000..dd9648cf51 --- /dev/null +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGatewayWithPathMappingTests.java @@ -0,0 +1,127 @@ +/* + * Copyright 2002-2011 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.http.inbound; + +import java.util.Map; + +import org.junit.Test; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.integration.Message; +import org.springframework.integration.MessageChannel; +import org.springframework.integration.MessagingException; +import org.springframework.integration.channel.DirectChannel; +import org.springframework.integration.core.MessageHandler; +import org.springframework.integration.http.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +import static org.junit.Assert.assertEquals; + +/** + * @author Oleg Zhurakousky + */ +public class HttpRequestHandlingMessagingGatewayWithPathMappingTests { + + private static ExpressionParser PARSER = new SpelExpressionParser(); + + + @Test + public void withoutExpression() throws Exception { + DirectChannel echoChannel = new DirectChannel(); + echoChannel.subscribe(new MessageHandler() { + + public void handleMessage(Message message) throws MessagingException { + MessageChannel replyChannel = (MessageChannel) message.getHeaders().getReplyChannel(); + replyChannel.send(message); + } + }); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("POST"); + request.setContentType("text/plain"); + request.setParameter("foo", "bar"); + request.setContent("hello".getBytes()); + request.setRequestURI("/fname/bill/lname/clinton"); + + HttpRequestHandlingMessagingGateway gateway = new HttpRequestHandlingMessagingGateway(true); + gateway.setPath("/fname/{f}/lname/{l}"); + gateway.setRequestChannel(echoChannel); + + MockHttpServletResponse response = new MockHttpServletResponse(); + + Object result = gateway.doHandleRequest(request, response); + assertEquals("hello", result); + + } + + @Test + public void withPayloadExpressionPointingToPathVariable() throws Exception { + DirectChannel echoChannel = new DirectChannel(); + echoChannel.subscribe(new MessageHandler() { + public void handleMessage(Message message) throws MessagingException { + MessageChannel replyChannel = (MessageChannel) message.getHeaders().getReplyChannel(); + replyChannel.send(message); + } + }); + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setMethod("POST"); + request.setContentType("text/plain"); + request.setParameter("foo", "bar"); + request.setContent("hello".getBytes()); + request.setRequestURI("/fname/bill/lname/clinton"); + + HttpRequestHandlingMessagingGateway gateway = new HttpRequestHandlingMessagingGateway(true); + gateway.setPath("/fname/{f}/lname/{l}"); + gateway.setRequestChannel(echoChannel); + gateway.setPayloadExpression(PARSER.parseExpression("#pathVariables.f")); + + Object result = gateway.doHandleRequest(request, response); + assertEquals("bill", result); + } + + @SuppressWarnings("unchecked") + @Test + public void withoutPayloadExpressionPointingToUriVariables() throws Exception { + + DirectChannel echoChannel = new DirectChannel(); + echoChannel.subscribe(new MessageHandler() { + + public void handleMessage(Message message) throws MessagingException { + MessageChannel replyChannel = (MessageChannel) message.getHeaders().getReplyChannel(); + replyChannel.send(message); + } + }); + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setMethod("POST"); + request.setContentType("text/plain"); + request.setParameter("foo", "bar"); + request.setContent("hello".getBytes()); + request.setRequestURI("/fname/bill/lname/clinton"); + + HttpRequestHandlingMessagingGateway gateway = new HttpRequestHandlingMessagingGateway(true); + gateway.setPath("/fname/{f}/lname/{l}"); + gateway.setRequestChannel(echoChannel); + gateway.setPayloadExpression(PARSER.parseExpression("#pathVariables")); + + Object result = gateway.doHandleRequest(request, response); + assertEquals("bill", ((Map)result).get("f")); + } + +}