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
This commit is contained in:
Gary Russell
2012-05-22 15:01:09 -04:00
committed by Oleg Zhurakousky
parent 72f5a26682
commit 733e0ead45
10 changed files with 301 additions and 100 deletions

View File

@@ -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<Element> headerElements = DomUtils.getChildElementsByTagName(element, "header");
if (!CollectionUtils.isEmpty(headerElements)) {
ManagedMap<String, Object> headerElementsMap = new ManagedMap<String, Object>();
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());

View File

@@ -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 <code>spring.integration.http.handler.error</code>. 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<String, Object>(), "dummy");

View File

@@ -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
* <code>false</code>.
*
*
* @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<String, Expression> 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();

View File

@@ -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;
* <p/>
* 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);

View File

@@ -191,6 +191,15 @@ The String "HTTP_REQUEST_HEADERS" will match against any of the standard HTTP Re
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="view-expression" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
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.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="errors-key" type="xsd:string">
<xsd:annotation>
<xsd:documentation>

View File

@@ -28,6 +28,12 @@
<inbound-gateway id="inboundController" request-channel="requests" reply-channel="responses" view-name="foo" error-code="oops"/>
<inbound-gateway id="inboundControllerViewExp"
request-channel="requests"
reply-channel="responses"
view-expression="'bar'"
error-code="oops"/>
<inbound-gateway id="withMappedHeaders" request-channel="requests"
mapped-response-headers="abc, xyz"
mapped-request-headers="foo,bar"/>

View File

@@ -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<String, Object> mapOfHeaders = new HashMap<String, Object>();
mapOfHeaders.put("abc", "abc");
MessageHeaders mh = new MessageHeaders(mapOfHeaders);
@@ -140,12 +157,12 @@ public class HttpInboundGatewayParserTests {
List<String> 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<String, Object> mapOfHeaders = new HashMap<String, Object>();
mapOfHeaders.put("abc", "abc");
Person person = new Person();
@@ -169,7 +186,7 @@ public class HttpInboundGatewayParserTests {
List<String> 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<Person, String>{
public String convert(Person source) {
return source.getName();
}
}
}

View File

@@ -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<String> 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<String> 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();

View File

@@ -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<Exception> {
public TestHttpMessageConverter() {
setSupportedMediaTypes(Arrays.asList(MediaType.ALL));
}

View File

@@ -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<String, Object>)result).get("f"));
assertTrue(result instanceof Message);
assertEquals("bill", ((Map<String, Object>) ((Message<?>)result).getPayload()).get("f"));
}
}