polishing

This commit is contained in:
Mark Fisher
2011-09-02 16:01:37 -04:00
parent 581f21f3eb
commit b4c210691c
6 changed files with 105 additions and 114 deletions

View File

@@ -33,6 +33,6 @@ public interface HeaderMapper<T> {
void fromHeaders(MessageHeaders headers, T target);
Map<String, ?> toHeaders(T source);
<V> Map<String, V> toHeaders(T source);
}

View File

@@ -57,15 +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.UriTemplate;
import org.springframework.web.util.UrlPathHelper;
/**
* Base class for HTTP request handling endpoints.
@@ -116,6 +119,10 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor
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;
@@ -156,7 +163,11 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor
protected boolean isExpectReply() {
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;
}
@@ -165,13 +176,27 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor
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 <code>#pathVariables</code> and
* <code>#queryParameters</code> 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 <code>#pathVariables</code> and
* <code>#queryParameters</code> variables if present. Those variables' values are Maps.
*/
public void setHeaderExpressions(Map<String, Expression> headerExpressions) {
this.headerExpressions = headerExpressions;
}
/**
* Set the message body converters to use. These converters are used to convert from and to HTTP requests and
* responses.
@@ -276,87 +301,70 @@ abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewaySuppor
* 'expectReply' property is true, it will also generate a response from the reply Message once received.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
protected final Object doHandleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
throws IOException {
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;
}
Map uriVariableMappings = null;
//
StandardEvaluationContext evaluationContext = this.createEvaluationContext();
Object requestBody = null;
if (this.isReadable(request)) {
requestBody = this.extractRequestBody(request);
evaluationContext.setVariable("requestBody", requestBody);
}
HttpEntity httpEntity = new HttpEntity(requestBody, request.getHeaders());
StandardEvaluationContext evaluationContext = this.createEvaluationContext();
evaluationContext.setRootObject(httpEntity);
LinkedMultiValueMap<String, String> requestParameterMap = this.convertParameterMap(servletRequest.getParameterMap());
evaluationContext.setVariable("requestParameterMap", uriVariableMappings);// bind the whole map
for (String parameterName : requestParameterMap.keySet()) { // bind individual parameters
evaluationContext.setVariable(parameterName, requestParameterMap.get(parameterName));
}
if (StringUtils.hasText(this.path)){
UriTemplate template = new UriTemplate(this.path);
uriVariableMappings = template.match(request.getURI().getPath());
if (!uriVariableMappings.isEmpty()){
if (logger.isDebugEnabled()){
logger.debug("Mapped URI variables: " + uriVariableMappings);
}
// set the whole map
evaluationContext.setVariable("pathVariables", uriVariableMappings);
for (Object key : uriVariableMappings.keySet()) {
// add individual elements
evaluationContext.setVariable((String) key, uriVariableMappings.get(key));
LinkedMultiValueMap<String, String> 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);
}
}
else {
logger.warn("Was not able to match UriVariables to path: " + this.path);
}
}
//
Map<String, ?> headers = this.headerMapper.toHeaders(request.getHeaders());
Object payload = null;
if (this.payloadExpression != null){
// create payload based on SpEL
payload = this.payloadExpression.getValue(evaluationContext, request);
}
if (this.headerExpressions != null){
for (String headerName : this.headerExpressions.keySet()) {
Expression headerExpression = this.headerExpressions.get(headerName);
Object headerValue = headerExpression.getValue(evaluationContext, request);
((Map<String, Object>)headers).put(headerName, headerValue);
evaluationContext.setVariable("pathVariables", pathVariables);
}
}
if (payload == null){
if (this.isReadable(request)) {
//payload = this.extractRequestBody(request);
}
Map<String, Object> 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 = requestParameterMap;
payload = requestParams;
}
}
Message<?> message = MessageBuilder.withPayload(payload).copyHeaders(headers).setHeader(
org.springframework.integration.http.HttpHeaders.REQUEST_URL, request.getURI().toString())
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);
@@ -364,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();

View File

@@ -13,52 +13,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.http.inbound;
import java.util.Collections;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.util.ObjectUtils;
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
* &lt;inbound-channel-adapter&gt; or &lt;inbound-gateway&gt; element.
*
* @author Oleg Zhurakousky
* @author Mark Fisher
* @since 2.1
*/
public class UriPathHandlerMapping extends AbstractDetectingUrlHandlerMapping {
public UriPathHandlerMapping(){
this.setOrder(Integer.MIN_VALUE);
}
protected void detectHandlers() throws BeansException {
if (logger.isDebugEnabled()) {
logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
}
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), HttpRequestHandlingEndpointSupport.class);
for (String beanName : beanNames) {
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
// URL paths found: Let's consider it a handler.
registerHandler(urls, beanName);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
}
}
}
}
@Override
protected String[] determineUrlsForHandler(String beanName) {
ApplicationContext context = this.getApplicationContext();
HttpRequestHandlingEndpointSupport handler = context.getBean(beanName, HttpRequestHandlingEndpointSupport.class);
String path = handler.getPath();
return Collections.singletonList(path).toArray(new String[]{});
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;
}
}

View File

@@ -31,23 +31,23 @@
path="/fname/{f}/lname/{l}"
channel="requests"
mapped-request-headers="foo,bar"
payload-expression="#f">
<header name="lname" expression="#l"/>
payload-expression="#pathVariables.f">
<header name="lname" expression="#pathVariables.l"/>
</inbound-channel-adapter>
<inbound-channel-adapter name="/fname/{blah}/lname/{boo}"
path="/fname/{f}/lname/{l}"
channel="requests"
mapped-request-headers="foo,bar"
payload-expression="#f">
<header name="lname" expression="#l"/>
payload-expression="#pathVariables.f">
<header name="lname" expression="#pathVariables.l"/>
</inbound-channel-adapter>
<inbound-channel-adapter name="/fname/{f}/lname/{l}"
channel="requests"
mapped-request-headers="foo,bar"
payload-expression="#f">
<header name="lname" expression="#l"/>
payload-expression="#pathVariables.f">
<header name="lname" expression="#pathVariables.l"/>
</inbound-channel-adapter>
</beans:beans>

View File

@@ -36,6 +36,7 @@ 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;
@@ -47,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;
@@ -146,6 +148,7 @@ public class HttpInboundChannelAdapterParserTests {
assertEquals("bill", payload);
assertEquals("clinton", message.getHeaders().get("lname"));
}
@Test // ensure that 'path' takes priority over name
// INT-1677
public void withNameAndExpressionsAndPath() throws Exception {
@@ -167,8 +170,9 @@ public class HttpInboundChannelAdapterParserTests {
assertEquals("clinton", message.getHeaders().get("lname"));
}
@Test
@Test
// INT-1677
@ExpectedException(SpelEvaluationException.class)
public void withNameAndExpressionsNoPath() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");

View File

@@ -68,11 +68,9 @@ public class HttpRequestHandlingMessagingGatewayWithPathMappingTests {
}
@Test
public void withoutPayloadExpressionPointingToUriVariable() throws Exception {
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);
@@ -80,21 +78,20 @@ 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("#f"));
gateway.setPayloadExpression(PARSER.parseExpression("#pathVariables.f"));
Object result = gateway.doHandleRequest(request, response);
assertEquals("bill", result);
}
@SuppressWarnings("unchecked")