From 733e0ead45c07c88903762d5cd2c4e6b846e474c Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Tue, 22 May 2012 15:01:09 -0400 Subject: [PATCH] INT-2448 Add view-expression to Http Inbound https://jira.springsource.org/browse/INT-2488 Previously the view name could be specified; with this change, either the view name or a view-epression can be provided, with the reply message being the root object of the evaluation context. INT-2448 Polishing Remove deprecation from view-name. Reuse evaluation context. INT-2448 Polishing PR Comments --- .../config/HttpInboundEndpointParser.java | 55 ++++++++---- .../HttpRequestHandlingController.java | 61 +++++++++++--- .../HttpRequestHandlingEndpointSupport.java | 71 +++++++++------- .../HttpRequestHandlingMessagingGateway.java | 11 ++- .../config/spring-integration-http-2.2.xsd | 9 ++ .../HttpInboundGatewayParserTests-context.xml | 6 ++ .../config/HttpInboundGatewayParserTests.java | 47 +++++++---- .../HttpRequestHandlingControllerTests.java | 84 +++++++++++++++++++ ...pRequestHandlingMessagingGatewayTests.java | 9 +- ...gMessagingGatewayWithPathMappingTests.java | 48 ++++++----- 10 files changed, 301 insertions(+), 100 deletions(-) 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 65b315a0e7..556e8efa41 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 @@ -27,9 +27,12 @@ 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.expression.common.LiteralExpression; import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.config.ExpressionFactoryBean; import org.springframework.integration.config.xml.IntegrationNamespaceUtils; +import org.springframework.integration.http.inbound.HttpRequestHandlingController; +import org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; @@ -39,8 +42,8 @@ import org.w3c.dom.Element; * Parser for the 'inbound-channel-adapter' and 'inbound-gateway' elements * of the 'http' namespace. The constructor's boolean value specifies whether * a reply is to be expected. This value should be 'false' for the - * 'inbound-channel-adapter' and 'true' for the 'inbound-gateway'. - * + * 'inbound-channel-adapter' and 'true' for the 'inbound-gateway'. + * * @author Mark Fisher * @author Oleg Zhurakousky * @author Gary Russell @@ -57,9 +60,9 @@ public class HttpInboundEndpointParser extends AbstractSingleBeanDefinitionParse @Override protected String getBeanClassName(Element element) { - return element.hasAttribute("view-name") - ? "org.springframework.integration.http.inbound.HttpRequestHandlingController" - : "org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway"; + return element.hasAttribute("view-name") || element.hasAttribute("view-expression") + ? HttpRequestHandlingController.class.getName() + : HttpRequestHandlingMessagingGateway.class.getName(); } @Override @@ -96,18 +99,18 @@ 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)){ + 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) { @@ -117,11 +120,11 @@ public class HttpInboundEndpointParser extends AbstractSingleBeanDefinitionParse 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"); @@ -136,18 +139,34 @@ public class HttpInboundEndpointParser extends AbstractSingleBeanDefinitionParse } IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "supported-methods", "supportedMethodNames"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "request-payload-type"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "view-name"); + String viewName = element.getAttribute("view-name"); + String viewExpression = element.getAttribute("view-expression"); + boolean hasViewName = StringUtils.hasText(viewName); + boolean hasViewExpression = StringUtils.hasText(viewExpression); + if (hasViewName ? hasViewExpression : false) { + parserContext.getReaderContext().error("Only one of 'view' or 'view-expression' is allowed", element); + } + if (hasViewName) { + RootBeanDefinition expressionDef = new RootBeanDefinition(LiteralExpression.class); + expressionDef.getConstructorArgumentValues().addGenericArgumentValue(viewName); + builder.addPropertyValue("viewExpression", expressionDef); + } + else if (hasViewExpression) { + RootBeanDefinition expressionDef = new RootBeanDefinition(ExpressionFactoryBean.class); + expressionDef.getConstructorArgumentValues().addGenericArgumentValue(viewExpression); + builder.addPropertyValue("viewExpression", expressionDef); + } IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "errors-key"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "error-code"); IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "message-converters"); - - + + //IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "header-mapper"); String headerMapper = element.getAttribute("header-mapper"); String mappedRequestHeaders = element.getAttribute("mapped-request-headers"); String mappedResponseHeaders = element.getAttribute("mapped-response-headers"); - - + + if (StringUtils.hasText(headerMapper)) { if (StringUtils.hasText(mappedRequestHeaders) || StringUtils.hasText(mappedResponseHeaders)) { parserContext.getReaderContext().error("Neither 'mappped-request-headers' or 'mapped-response-headers' " + @@ -159,7 +178,7 @@ public class HttpInboundEndpointParser extends AbstractSingleBeanDefinitionParse BeanDefinitionBuilder headerMapperBuilder = BeanDefinitionBuilder.genericBeanDefinition( "org.springframework.integration.http.support.DefaultHttpHeaderMapper"); headerMapperBuilder.setFactoryMethod("inboundMapper"); - + IntegrationNamespaceUtils.setValueIfAttributeDefined(headerMapperBuilder, element, "mapped-request-headers", "inboundHeaderNames"); IntegrationNamespaceUtils.setValueIfAttributeDefined(headerMapperBuilder, element, "mapped-response-headers", "outboundHeaderNames"); builder.addPropertyValue("headerMapper", headerMapperBuilder.getBeanDefinition()); diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingController.java b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingController.java index 00fba2cbb5..0a43cf3ef4 100644 --- a/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingController.java +++ b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingController.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2012 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,9 +24,16 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.context.MessageSource; +import org.springframework.expression.Expression; +import org.springframework.expression.common.LiteralExpression; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.integration.Message; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; import org.springframework.validation.Errors; import org.springframework.validation.MapBindingResult; import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.View; import org.springframework.web.servlet.mvc.Controller; /** @@ -40,8 +47,9 @@ import org.springframework.web.servlet.mvc.Controller; * reply Message or payload depending on the value of {@link #extractReplyPayload} (true by default, meaning just the * payload). The corresponding key in the map is determined by the {@link #replyKey} property (with a default of * "reply"). - * + * * @author Mark Fisher + * @author Gary Russell * @since 2.0 */ public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSupport implements Controller { @@ -52,7 +60,9 @@ public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSu private static final String DEFAULT_ERRORS_KEY = "errors"; - private volatile String viewName; + private volatile Expression viewExpression; + + private volatile StandardEvaluationContext evaluationContext; private volatile String replyKey = DEFAULT_REPLY_KEY; @@ -72,7 +82,8 @@ public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSu * Specify the view name. */ public void setViewName(String viewName) { - this.viewName = viewName; + Assert.isTrue(StringUtils.hasText(viewName), "View name must contain text"); + this.viewExpression = new LiteralExpression(viewName); } /** @@ -98,13 +109,27 @@ public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSu * provided in an object error to be optionally translated in the standard MVC way using a {@link MessageSource}. * The default value is spring.integration.http.handler.error. Three arguments are provided: the * exception, its message and its stack trace as a String. - * + * * @param errorCode the error code to set */ public void setErrorCode(String errorCode) { this.errorCode = errorCode; } + /** + * Specifies a SpEL expression to evaluate in order to generate the view name. + * The EvaluationContext will be populated with the reply message as the root object, + */ + public void setViewExpression(Expression viewExpression) { + this.viewExpression = viewExpression; + } + + @Override + protected void onInit() throws Exception { + super.onInit(); + this.evaluationContext = this.createEvaluationContext(); + } + /** * 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. @@ -112,14 +137,30 @@ public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSu public final ModelAndView handleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { ModelAndView modelAndView = new ModelAndView(); - if (this.viewName != null) { - modelAndView.setViewName(this.viewName); - } try { - Object reply = super.doHandleRequest(servletRequest, servletResponse); - if (reply != null) { + Message replyMessage = super.doHandleRequest(servletRequest, servletResponse); + if (replyMessage != null) { + Object reply = setupResponseAndConvertReply(servletResponse, replyMessage); modelAndView.addObject(this.replyKey, reply); } + if (this.viewExpression != null) { + Object view; + if (replyMessage != null) { + view = this.viewExpression.getValue(this.evaluationContext, replyMessage); + } + else { + view = this.viewExpression.getValue(this.evaluationContext); + } + if (view instanceof View) { + modelAndView.setView((View) view); + } + else if (view instanceof String) { + modelAndView.setViewName((String) view); + } + else { + throw new IllegalStateException("view expression must resolve to a View or String"); + } + } } catch (Exception e) { MapBindingResult errors = new MapBindingResult(new HashMap(), "dummy"); 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 4f76e53823..e0353e5306 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-2011 the original author or authors. + * Copyright 2002-2012 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. @@ -91,13 +91,14 @@ import org.springframework.web.util.UrlPathHelper; * In a request-reply scenario, the reply Message's payload will be extracted prior to generating a response by default. * To have the entire serialized Message available for the response, switch the {@link #extractReplyPayload} value to * false. - * + * * @author Mark Fisher * @author Oleg Zhurakousky + * @author Gary Russell * @since 2.0 */ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySupport { - + private static final boolean jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", HttpRequestHandlingEndpointSupport.class.getClassLoader()); @@ -105,7 +106,7 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor HttpRequestHandlingEndpointSupport.class.getClassLoader()) && ClassUtils.isPresent("org.codehaus.jackson.JsonGenerator", HttpRequestHandlingEndpointSupport.class .getClassLoader()); - + private static boolean romePresent = ClassUtils.isPresent("com.sun.syndication.feed.WireFeed", HttpRequestHandlingEndpointSupport.class.getClassLoader()); @@ -128,7 +129,7 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor private volatile boolean extractReplyPayload = true; private volatile MultipartResolver multipartResolver; - + private volatile Expression payloadExpression; private volatile Map headerExpressions; @@ -154,10 +155,10 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor } if (romePresent) { this.messageConverters.add(new AtomFeedHttpMessageConverter()); - this.messageConverters.add(new RssChannelHttpMessageConverter()); + this.messageConverters.add(new RssChannelHttpMessageConverter()); } } - + /** * @return whether to expect reply */ @@ -167,12 +168,12 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor /** * Set the path template for which this endpoint expects requests. - * May include path variable {keys} to match against. + * May include path variable {keys} to match against. */ public void setPath(String path) { this.path = path; } - + String getPath() { return path; } @@ -300,9 +301,10 @@ 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. + * @return a the response Message */ @SuppressWarnings({ "rawtypes", "unchecked" }) - protected final Object doHandleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException { + protected final Message doHandleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException { try { ServletServerHttpRequest request = this.prepareRequest(servletRequest); if (!this.supportedMethods.contains(request.getMethod())) { @@ -351,13 +353,13 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor if (payload == null) { if (requestBody != null) { - payload = requestBody; + payload = requestBody; } else { payload = requestParams; } } - + MessageBuilder messageBuilder = null; if (payload instanceof Message){ @@ -366,28 +368,16 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor else { messageBuilder = MessageBuilder.withPayload(payload).copyHeaders(headers); } - + Message message = messageBuilder .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, servletRequest.getUserPrincipal()) .build(); - - Object reply = null; + + Message reply = null; if (this.expectReply) { reply = this.sendAndReceiveMessage(message); - if (reply != null) { - ServletServerHttpResponse response = new ServletServerHttpResponse(servletResponse); - this.headerMapper.fromHeaders(((Message) reply).getHeaders(), response.getHeaders()); - HttpStatus httpStatus = this.resolveHttpStatusFromHeaders(((Message) reply).getHeaders()); - if (httpStatus != null) { - response.setStatusCode(httpStatus); - } - response.close(); - if (this.extractReplyPayload) { - reply = ((Message) reply).getPayload(); - } - } } else { this.send(message); @@ -399,6 +389,29 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor } } + /** + * Converts the reply message to the appropriate HTTP reply object and + * sets up the servlet response. + * @param servletResponse The servlet response. + * @param replyMessage The reply message. + * @return The message payload (if {@link #extractReplyPayload}) otherwise the + * message. + */ + protected final Object setupResponseAndConvertReply(HttpServletResponse servletResponse, Message replyMessage) { + ServletServerHttpResponse response = new ServletServerHttpResponse(servletResponse); + this.headerMapper.fromHeaders(replyMessage.getHeaders(), response.getHeaders()); + HttpStatus httpStatus = this.resolveHttpStatusFromHeaders(((Message) replyMessage).getHeaders()); + if (httpStatus != null) { + response.setStatusCode(httpStatus); + } + response.close(); + Object reply = replyMessage; + if (this.extractReplyPayload) { + reply = replyMessage.getPayload(); + } + return reply; + } + /** * Prepares an instance of {@link ServletServerHttpRequest} from the raw {@link HttpServletRequest}. Also converts * the request into a multipart request to make multiparts available if necessary. If no multipart resolver is set, @@ -485,8 +498,8 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor } return httpStatus; } - - private StandardEvaluationContext createEvaluationContext(){ + + protected StandardEvaluationContext createEvaluationContext(){ StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); evaluationContext.addPropertyAccessor(new MapAccessor()); BeanFactory beanFactory = this.getBeanFactory(); diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGateway.java b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGateway.java index 0aefe320b2..c41c03c457 100644 --- a/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGateway.java +++ b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGateway.java @@ -29,6 +29,7 @@ import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.http.server.ServletServerHttpResponse; +import org.springframework.integration.Message; import org.springframework.integration.MessagingException; import org.springframework.integration.http.converter.MultipartAwareFormHttpMessageConverter; import org.springframework.util.CollectionUtils; @@ -53,7 +54,7 @@ import org.springframework.web.HttpRequestHandler; *

* By default a number of {@link HttpMessageConverter}s are already configured. The list can be overridden by calling * the {@link #setMessageConverters(List)} method. - * + * * @author Mark Fisher * @author Oleg Zhurakousky * @since 2.0 @@ -76,7 +77,7 @@ public class HttpRequestHandlingMessagingGateway extends HttpRequestHandlingEndp * Flag to determine if conversion and writing out of message handling exceptions should be attempted (default * false, in which case they will simply be re-thrown). If the flag is true and no message converter can convert the * exception a new exception will be thrown. - * + * * @param convertExceptions the flag to set */ public void setConvertExceptions(boolean convertExceptions) { @@ -91,8 +92,12 @@ public class HttpRequestHandlingMessagingGateway extends HttpRequestHandlingEndp public final void handleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException { Object responseContent = null; + Message responseMessage; try { - responseContent = super.doHandleRequest(servletRequest, servletResponse); + responseMessage = super.doHandleRequest(servletRequest, servletResponse); + if (responseMessage != null) { + responseContent = setupResponseAndConvertReply(servletResponse, responseMessage); + } } catch (Exception e) { responseContent = handleExceptionInternal(e); diff --git a/spring-integration-http/src/main/resources/org/springframework/integration/http/config/spring-integration-http-2.2.xsd b/spring-integration-http/src/main/resources/org/springframework/integration/http/config/spring-integration-http-2.2.xsd index dbe6e31930..3437fc003a 100644 --- a/spring-integration-http/src/main/resources/org/springframework/integration/http/config/spring-integration-http-2.2.xsd +++ b/spring-integration-http/src/main/resources/org/springframework/integration/http/config/spring-integration-http-2.2.xsd @@ -191,6 +191,15 @@ The String "HTTP_REQUEST_HEADERS" will match against any of the standard HTTP Re + + + + SpEL expression that resolves to a view to be resolved when rendering a response. + The expression can resolve to a view name or View object. + The root object of the evaluation context is the reply message. + + + diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpInboundGatewayParserTests-context.xml b/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpInboundGatewayParserTests-context.xml index 35e867fc64..375af22d4b 100644 --- a/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpInboundGatewayParserTests-context.xml +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpInboundGatewayParserTests-context.xml @@ -28,6 +28,12 @@ + + diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpInboundGatewayParserTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpInboundGatewayParserTests.java index df411e3e32..7dbbdb89ac 100644 --- a/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpInboundGatewayParserTests.java +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpInboundGatewayParserTests.java @@ -37,6 +37,8 @@ import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.core.convert.converter.Converter; +import org.springframework.expression.common.LiteralExpression; +import org.springframework.expression.spel.standard.SpelExpression; import org.springframework.http.HttpHeaders; import org.springframework.integration.Message; import org.springframework.integration.MessageHeaders; @@ -61,15 +63,15 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class HttpInboundGatewayParserTests { - + @Autowired @Qualifier("inboundGateway") private HttpRequestHandlingMessagingGateway gateway; - + @Autowired @Qualifier("withMappedHeaders") private HttpRequestHandlingMessagingGateway withMappedHeaders; - + @Autowired @Qualifier("withMappedHeadersAndConverter") private HttpRequestHandlingMessagingGateway withMappedHeadersAndConverter; @@ -77,6 +79,9 @@ public class HttpInboundGatewayParserTests { @Autowired private HttpRequestHandlingController inboundController; + @Autowired + private HttpRequestHandlingController inboundControllerViewExp; + @Autowired private SubscribableChannel requests; @@ -96,7 +101,7 @@ public class HttpInboundGatewayParserTests { assertEquals(Long.valueOf(1234), TestUtils.getPropertyValue(messagingTemplate, "sendTimeout")); assertEquals(Long.valueOf(4567), TestUtils.getPropertyValue(messagingTemplate, "receiveTimeout")); } - + @Test(timeout=1000) public void checkFlow() throws Exception { requests.subscribe(handlerExpecting(any(Message.class))); @@ -115,13 +120,25 @@ public class HttpInboundGatewayParserTests { DirectFieldAccessor accessor = new DirectFieldAccessor(inboundController); String errorCode = (String) accessor.getPropertyValue("errorCode"); assertEquals("oops", errorCode); + LiteralExpression viewExpression = (LiteralExpression) accessor.getPropertyValue("viewExpression"); + assertEquals("foo", viewExpression.getValue()); } - + + @Test + public void testControllerViewExp() throws Exception { + DirectFieldAccessor accessor = new DirectFieldAccessor(inboundControllerViewExp); + String errorCode = (String) accessor.getPropertyValue("errorCode"); + assertEquals("oops", errorCode); + SpelExpression viewExpression = (SpelExpression) accessor.getPropertyValue("viewExpression"); + assertNotNull(viewExpression); + assertEquals("'bar'", viewExpression.getExpressionString()); + } + @Test public void requestWithHeaders() throws Exception { - DefaultHttpHeaderMapper headerMapper = + DefaultHttpHeaderMapper headerMapper = (DefaultHttpHeaderMapper) TestUtils.getPropertyValue(withMappedHeaders, "headerMapper"); - + HttpHeaders headers = new HttpHeaders(); headers.set("foo", "foo"); headers.set("bar", "bar"); @@ -130,7 +147,7 @@ public class HttpInboundGatewayParserTests { assertTrue(map.size() == 2); assertEquals("foo", map.get("foo")); assertEquals("bar", map.get("bar")); - + Map mapOfHeaders = new HashMap(); mapOfHeaders.put("abc", "abc"); MessageHeaders mh = new MessageHeaders(mapOfHeaders); @@ -140,12 +157,12 @@ public class HttpInboundGatewayParserTests { List abc = headers.get("X-abc"); assertEquals("abc", abc.get(0)); } - + @Test public void requestWithHeadersWithConversionService() throws Exception { - DefaultHttpHeaderMapper headerMapper = + DefaultHttpHeaderMapper headerMapper = (DefaultHttpHeaderMapper) TestUtils.getPropertyValue(withMappedHeadersAndConverter, "headerMapper"); - + HttpHeaders headers = new HttpHeaders(); headers.set("foo", "foo"); headers.set("bar", "bar"); @@ -154,7 +171,7 @@ public class HttpInboundGatewayParserTests { assertTrue(map.size() == 2); assertEquals("foo", map.get("foo")); assertEquals("bar", map.get("bar")); - + Map mapOfHeaders = new HashMap(); mapOfHeaders.put("abc", "abc"); Person person = new Person(); @@ -169,7 +186,7 @@ public class HttpInboundGatewayParserTests { List personHeaders = headers.get("X-person"); assertEquals("Oleg", personHeaders.get(0)); } - + public static class Person{ private String name; @@ -181,13 +198,13 @@ public class HttpInboundGatewayParserTests { this.name = name; } } - + public static class PersonConverter implements Converter{ public String convert(Person source) { return source.getName(); } - + } } diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/inbound/HttpRequestHandlingControllerTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/inbound/HttpRequestHandlingControllerTests.java index 6846a62eef..d303de6c9f 100644 --- a/spring-integration-http/src/test/java/org/springframework/integration/http/inbound/HttpRequestHandlingControllerTests.java +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/inbound/HttpRequestHandlingControllerTests.java @@ -19,21 +19,28 @@ package org.springframework.integration.http.inbound; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; import org.junit.Test; +import org.springframework.expression.Expression; +import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.Message; import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.channel.QueueChannel; import org.springframework.integration.handler.AbstractReplyProducingMessageHandler; +import org.springframework.integration.support.MessageBuilder; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.validation.Errors; import org.springframework.validation.ObjectError; import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.View; /** * @author Mark Fisher + * @author Gary Russell * @since 2.0 */ public class HttpRequestHandlingControllerTests { @@ -57,6 +64,26 @@ public class HttpRequestHandlingControllerTests { assertEquals("hello", requestMessage.getPayload()); } + @Test + public void sendOnlyViewExpression() throws Exception { + QueueChannel requestChannel = new QueueChannel(); + HttpRequestHandlingController controller = new HttpRequestHandlingController(false); + controller.setRequestChannel(requestChannel); + Expression viewExpression = new SpelExpressionParser().parseExpression("'baz'"); + controller.setViewExpression(viewExpression); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("POST"); + request.setContent("hello".getBytes()); + request.setContentType("text/plain"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView modelAndView = controller.handleRequest(request, response); + assertEquals("baz", modelAndView.getViewName()); + assertEquals(0, modelAndView.getModel().size()); + Message requestMessage = requestChannel.receive(0); + assertNotNull(requestMessage); + assertEquals("hello", requestMessage.getPayload()); + } + @Test public void requestReply() throws Exception { DirectChannel requestChannel = new DirectChannel(); @@ -83,6 +110,63 @@ public class HttpRequestHandlingControllerTests { assertEquals("HELLO", reply); } + @Test + public void requestReplyViewExpressionString() throws Exception { + DirectChannel requestChannel = new DirectChannel(); + AbstractReplyProducingMessageHandler handler = new AbstractReplyProducingMessageHandler() { + @Override + protected Message handleRequestMessage(Message requestMessage) { + return MessageBuilder.withPayload("foo") + .setHeader("bar", "baz").build(); + } + }; + requestChannel.subscribe(handler); + HttpRequestHandlingController controller = new HttpRequestHandlingController(true); + controller.setRequestChannel(requestChannel); + Expression viewExpression = new SpelExpressionParser().parseExpression("headers['bar']"); + controller.setViewExpression(viewExpression); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("POST"); + request.setContent("hello".getBytes()); + request.setContentType("text/plain"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView modelAndView = controller.handleRequest(request, response); + assertEquals("baz", modelAndView.getViewName()); + assertEquals(1, modelAndView.getModel().size()); + Object reply = modelAndView.getModel().get("reply"); + assertNotNull(reply); + assertEquals("foo", reply); + } + + @Test + public void requestReplyViewExpressionView() throws Exception { + final View view = mock(View.class); + DirectChannel requestChannel = new DirectChannel(); + AbstractReplyProducingMessageHandler handler = new AbstractReplyProducingMessageHandler() { + @Override + protected Message handleRequestMessage(Message requestMessage) { + return MessageBuilder.withPayload("foo") + .setHeader("bar", view).build(); + } + }; + requestChannel.subscribe(handler); + HttpRequestHandlingController controller = new HttpRequestHandlingController(true); + controller.setRequestChannel(requestChannel); + Expression viewExpression = new SpelExpressionParser().parseExpression("headers['bar']"); + controller.setViewExpression(viewExpression); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("POST"); + request.setContent("hello".getBytes()); + request.setContentType("text/plain"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView modelAndView = controller.handleRequest(request, response); + assertSame(view, modelAndView.getView()); + assertEquals(1, modelAndView.getModel().size()); + Object reply = modelAndView.getModel().get("reply"); + assertNotNull(reply); + assertEquals("foo", reply); + } + @Test public void requestReplyWithCustomReplyKey() throws Exception { DirectChannel requestChannel = new DirectChannel(); diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGatewayTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGatewayTests.java index 9dc7b93824..c6bf40d00b 100644 --- a/spring-integration-http/src/test/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGatewayTests.java +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGatewayTests.java @@ -44,6 +44,7 @@ import org.springframework.util.SerializationUtils; /** * @author Mark Fisher + * @author Gary Russell * @since 2.0 */ public class HttpRequestHandlingMessagingGatewayTests { @@ -89,6 +90,7 @@ public class HttpRequestHandlingMessagingGatewayTests { public void stringExpectedWithReply() throws Exception { DirectChannel requestChannel = new DirectChannel(); requestChannel.subscribe(new AbstractReplyProducingMessageHandler() { + @Override protected Object handleRequestMessage(Message requestMessage) { return requestMessage.getPayload().toString().toUpperCase(); } @@ -110,6 +112,7 @@ public class HttpRequestHandlingMessagingGatewayTests { public void noAcceptHeaderOnRequest() throws Exception { DirectChannel requestChannel = new DirectChannel(); requestChannel.subscribe(new AbstractReplyProducingMessageHandler() { + @Override protected Object handleRequestMessage(Message requestMessage) { return requestMessage.getPayload().toString().toUpperCase(); } @@ -149,7 +152,7 @@ public class HttpRequestHandlingMessagingGatewayTests { @Test public void multiValueParameterMap() throws Exception { - QueueChannel channel = new QueueChannel(); + QueueChannel channel = new QueueChannel(); HttpRequestHandlingMessagingGateway gateway = new HttpRequestHandlingMessagingGateway(false); gateway.setRequestChannel(channel); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test"); @@ -175,7 +178,7 @@ public class HttpRequestHandlingMessagingGatewayTests { @Test public void serializableRequestBody() throws Exception { - QueueChannel channel = new QueueChannel(); + QueueChannel channel = new QueueChannel(); HttpRequestHandlingMessagingGateway gateway = new HttpRequestHandlingMessagingGateway(false); gateway.setRequestPayloadType(TestBean.class); gateway.setRequestChannel(channel); @@ -200,7 +203,7 @@ public class HttpRequestHandlingMessagingGatewayTests { private static class TestHttpMessageConverter extends AbstractHttpMessageConverter { - + public TestHttpMessageConverter() { setSupportedMediaTypes(Arrays.asList(MediaType.ALL)); } 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 index be20673939..07fdc4c9c1 100644 --- 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 @@ -16,10 +16,12 @@ package org.springframework.integration.http.inbound; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + 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; @@ -30,21 +32,20 @@ import org.springframework.integration.core.MessageHandler; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; -import static org.junit.Assert.assertEquals; - /** * @author Oleg Zhurakousky + * @author Gary Russell */ 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); @@ -56,18 +57,19 @@ public class HttpRequestHandlingMessagingGatewayWithPathMappingTests { 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); - + assertTrue(result instanceof Message); + assertEquals("hello", ((Message) result).getPayload()); + } - + @Test public void withPayloadExpressionPointingToPathVariable() throws Exception { DirectChannel echoChannel = new DirectChannel(); @@ -92,16 +94,17 @@ public class HttpRequestHandlingMessagingGatewayWithPathMappingTests { gateway.setPayloadExpression(PARSER.parseExpression("#pathVariables.f")); Object result = gateway.doHandleRequest(request, response); - assertEquals("bill", result); + assertTrue(result instanceof Message); + assertEquals("bill", ((Message)result).getPayload()); } - + @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); @@ -109,20 +112,21 @@ public class HttpRequestHandlingMessagingGatewayWithPathMappingTests { }); 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")); + assertTrue(result instanceof Message); + assertEquals("bill", ((Map) ((Message)result).getPayload()).get("f")); } - + }