Permalink
Browse files

Merge pull request #460 from garyrussell/INT-2448

* INT-2448:
  INT-2448 Add view-expression to Http Inbound
  • Loading branch information...
2 parents 72f5a26 + 733e0ea commit 020a8bf1e0aa813fad2474f54c04aa4727a54102 Oleg Zhurakousky committed May 25, 2012
@@ -27,9 +27,12 @@
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 @@
* 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 HttpInboundEndpointParser(boolean expectReply) {
@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 @@ protected void doParse(Element element, ParserContext parserContext, BeanDefinit
}
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 @@ protected void doParse(Element element, ParserContext parserContext, BeanDefinit
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 @@ protected void doParse(Element element, ParserContext parserContext, BeanDefinit
}
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 @@ protected void doParse(Element element, ParserContext parserContext, BeanDefinit
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());
@@ -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.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 @@
* 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 @@
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 HttpRequestHandlingController(boolean expectReply) {
* 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,28 +109,58 @@ public void setErrorsKey(String errorsKey) {
* 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.
*/
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");
Oops, something went wrong.

0 comments on commit 020a8bf

Please sign in to comment.