Factored out RequestMapper strategy (INT-609).
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.http;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.integration.core.Message;
|
||||
import org.springframework.integration.message.MessageBuilder;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.ServletRequestDataBinder;
|
||||
import org.springframework.web.bind.support.WebBindingInitializer;
|
||||
import org.springframework.web.servlet.handler.DispatcherServletWebRequest;
|
||||
|
||||
/**
|
||||
* RequestMapper implementation that binds the request parameter map to a
|
||||
* target instance. The target instance may be a non-singleton bean as
|
||||
* specified by the {@link #setTargetBeanName(String) 'targetBeanName'}
|
||||
* property. Otherwise, this transformer's target type must provide a
|
||||
* default no-arg constructor.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @since 1.0.2
|
||||
*/
|
||||
public class DataBindingRequestMapper implements RequestMapper, BeanFactoryAware, InitializingBean {
|
||||
|
||||
private final Class<?> targetType;
|
||||
|
||||
private volatile String targetBeanName;
|
||||
|
||||
private volatile WebBindingInitializer webBindingInitializer;
|
||||
|
||||
private volatile BeanFactory beanFactory;
|
||||
|
||||
private volatile boolean validated;
|
||||
|
||||
|
||||
public DataBindingRequestMapper(Class<?> targetType) {
|
||||
Assert.notNull(targetType, "targetType must not be null");
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify the name of a bean definition to use when creating the target
|
||||
* instance. The bean must <em>not</em> be a singleton, and it must be
|
||||
* compatible with the {@link #targetType}.
|
||||
* <p>If no 'targetBeanName' value is provided, the target type must
|
||||
* provide a default, no-arg constructor.
|
||||
*/
|
||||
public void setTargetBeanName(String targetBeanName) {
|
||||
this.targetBeanName = targetBeanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify an optional {@link WebBindingInitializer} to be invoked prior
|
||||
* to the request binding process.
|
||||
*/
|
||||
public void setWebBindingInitializer(WebBindingInitializer webBindingInitializer) {
|
||||
this.webBindingInitializer = webBindingInitializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the {@link BeanFactory} necessary to look up a
|
||||
* {@link #setTargetBeanName(String) 'targetBeanName'} if specified.
|
||||
* This method is typically invoked automatically by the container.
|
||||
*/
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
public final void afterPropertiesSet() {
|
||||
this.validateTargetBeanIfNecessary();
|
||||
}
|
||||
|
||||
private void validateTargetBeanIfNecessary() {
|
||||
if (this.targetBeanName != null && !this.validated) {
|
||||
Assert.notNull(this.beanFactory, "beanFactory is required for binding to a bean");
|
||||
if (this.beanFactory.isSingleton(this.targetBeanName)) {
|
||||
throw new IllegalArgumentException("binding target bean must not be a singleton");
|
||||
}
|
||||
this.validated = true;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Message<?> mapRequest(HttpServletRequest request) throws Exception {
|
||||
ServletRequestDataBinder binder = new ServletRequestDataBinder(getTarget());
|
||||
this.initBinder(binder, request);
|
||||
binder.bind(request);
|
||||
// this will immediately throw any bind Exceptions
|
||||
Map map = binder.close();
|
||||
Object payload = map.get(ServletRequestDataBinder.DEFAULT_OBJECT_NAME);
|
||||
return MessageBuilder.withPayload(payload).build();
|
||||
}
|
||||
|
||||
private void initBinder(ServletRequestDataBinder binder, HttpServletRequest request) {
|
||||
if (this.webBindingInitializer != null) {
|
||||
this.webBindingInitializer.initBinder(binder, new DispatcherServletWebRequest(request));
|
||||
}
|
||||
}
|
||||
|
||||
private Object getTarget() throws InstantiationException, IllegalAccessException {
|
||||
if (this.targetBeanName != null) {
|
||||
this.validateTargetBeanIfNecessary();
|
||||
return this.beanFactory.getBean(this.targetBeanName, this.targetType);
|
||||
}
|
||||
return this.targetType.newInstance();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.http;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.integration.core.Message;
|
||||
import org.springframework.integration.message.MessageBuilder;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link RequestMapper} for inbound HttpServletRequests.
|
||||
* The request will be mapped according to the following rules:
|
||||
* <ul>
|
||||
* <li>For a GET request, the parameter Map will be copied as the payload.
|
||||
* The map's keys will be Strings, and the values will be String arrays
|
||||
* as described for {@link ServletRequest#getParameterMap()}.</li>
|
||||
* <li>For other request types, the request body will be used as the payload
|
||||
* and the type will depend on the Content-Type header value. If it
|
||||
* begins with "text", a String will be created. If the Content-Type
|
||||
* is "application/x-java-serialized-object", the request body will be
|
||||
* expected to contain a Serializable Object, and that will be used as
|
||||
* the message payload. Otherwise, the payload will be a byte array.
|
||||
* The parameter Map values will then be added as Message headers.</li>
|
||||
* </ul>
|
||||
* In both cases, the original request headers will be passed in the
|
||||
* MessageHeaders. Likewise, the following headers will be added:
|
||||
* <ul>
|
||||
* <li>{@link HttpHeaders#REQUEST_URL}</li>
|
||||
* <li>{@link HttpHeaders#REQUEST_METHOD}</li>
|
||||
* <li>{@link HttpHeaders#USER_PRINCIPAL} (if available)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @since 1.0.2
|
||||
*/
|
||||
public class DefaultRequestMapper implements RequestMapper {
|
||||
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
|
||||
public Message<?> mapRequest(HttpServletRequest request) throws ServletException, IOException, ResponseStatusCodeException {
|
||||
Message<?> message = null;
|
||||
String contentType = request.getContentType();
|
||||
if (request.getMethod().equals("GET")) {
|
||||
message = this.mapGetRequest(request);
|
||||
}
|
||||
else {
|
||||
Object payload = null;
|
||||
if (contentType != null && contentType.startsWith("text")) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("received " + request.getMethod()
|
||||
+ " request, creating payload with text content");
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
BufferedReader reader = request.getReader();
|
||||
String line = reader.readLine();
|
||||
while (line != null) {
|
||||
sb.append(line);
|
||||
line = reader.readLine();
|
||||
}
|
||||
payload = sb.toString();
|
||||
}
|
||||
else if (contentType != null && contentType.equals("application/x-java-serialized-object")) {
|
||||
try {
|
||||
payload = new ObjectInputStream(request.getInputStream()).readObject();
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
throw new ServletException("failed to deserialize Object in request", e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
InputStream stream = request.getInputStream();
|
||||
int length = request.getContentLength();
|
||||
if (length == -1) {
|
||||
throw new ResponseStatusCodeException(HttpServletResponse.SC_LENGTH_REQUIRED);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("received " + request.getMethod() + " request, "
|
||||
+ "creating byte array payload with content lenth: " + length);
|
||||
}
|
||||
byte[] bytes = new byte[length];
|
||||
stream.read(bytes, 0, length);
|
||||
payload = bytes;
|
||||
}
|
||||
MessageBuilder<?> builder = MessageBuilder.withPayload(payload);
|
||||
this.populateHeaders(request, builder, true);
|
||||
message = builder.build();
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Message<?> mapGetRequest(HttpServletRequest request) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("received GET request, using parameter map as payload");
|
||||
}
|
||||
Map<String, String[]> parameterMap = new HashMap<String, String[]>(request.getParameterMap());
|
||||
MessageBuilder<?> builder = MessageBuilder.withPayload(Collections.unmodifiableMap(parameterMap));
|
||||
this.populateHeaders(request, builder, false);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void populateHeaders(HttpServletRequest request, MessageBuilder<?> builder, boolean includeParameters) {
|
||||
Enumeration<?> headerNames = request.getHeaderNames();
|
||||
if (headerNames != null) {
|
||||
while (headerNames.hasMoreElements()) {
|
||||
String headerName = (String) headerNames.nextElement();
|
||||
Enumeration<?> headerEnum = request.getHeaders(headerName);
|
||||
if (headerEnum != null) {
|
||||
List<Object> headers = new ArrayList<Object>();
|
||||
while (headerEnum.hasMoreElements()) {
|
||||
headers.add(headerEnum.nextElement());
|
||||
}
|
||||
if (headers.size() == 1) {
|
||||
builder.setHeader(headerName, headers.get(0));
|
||||
}
|
||||
else if (headers.size() > 1) {
|
||||
builder.setHeader(headerName, headers);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (includeParameters) {
|
||||
builder.copyHeaders(request.getParameterMap());
|
||||
}
|
||||
builder.setHeader(HttpHeaders.REQUEST_URL, request.getRequestURL().toString());
|
||||
builder.setHeader(HttpHeaders.REQUEST_METHOD, request.getMethod());
|
||||
builder.setHeader(HttpHeaders.USER_PRINCIPAL, request.getUserPrincipal());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,28 +16,21 @@
|
||||
|
||||
package org.springframework.integration.http;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.integration.core.Message;
|
||||
import org.springframework.integration.gateway.SimpleMessagingGateway;
|
||||
import org.springframework.integration.message.MessageBuilder;
|
||||
import org.springframework.integration.message.MessageTimeoutException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.HttpRequestHandler;
|
||||
@@ -49,29 +42,11 @@ import org.springframework.web.servlet.View;
|
||||
* By default GET and POST requests are accepted, but the 'supportedMethods'
|
||||
* property may be set to include others or limit the options (e.g. POST only).
|
||||
* By default the request will be converted to a Message payload according to
|
||||
* the following rules:
|
||||
* <ul>
|
||||
* <li>For a GET request, the parameter Map will be used as the payload.
|
||||
* The map's keys will be Strings, and the values will be String arrays
|
||||
* as described for {@link ServletRequest#getParameterMap()}</li>.
|
||||
* <li>For other request types, the request body will be used as the payload
|
||||
* and the type will depend on the Content-Type header value. If it
|
||||
* begins with "text", a String will be created. Otherwise, the payload
|
||||
* will be a byte array. The parameter Map values are then added as
|
||||
* Message headers.</li>
|
||||
* </ul>
|
||||
* In both cases, when extracting a request payload, the original request
|
||||
* headers will be passed in the MessageHeaders. Likewise, the following
|
||||
* headers will be added:
|
||||
* <ul>
|
||||
* <li>{@link HttpHeaders#REQUEST_URL}</li>
|
||||
* <li>{@link HttpHeaders#REQUEST_METHOD}</li>
|
||||
* <li>{@link HttpHeaders#USER_PRINCIPAL} (if available)</li>
|
||||
* </ul>
|
||||
* To have the full request object passed in the Message payload instead,
|
||||
* set the {@link #extractRequestPayload} value to <code>false</code>.
|
||||
* This can be useful if you intend to use a MessageTransformer downstream
|
||||
* to convert the request in some custom way.
|
||||
* the rules of the {@link DefaultRequestMapper}.
|
||||
* <p/>
|
||||
* To customize the mapping of the request to the Message payload, provide
|
||||
* a reference to a {@link RequestMapper} implementation to the
|
||||
* {@link #setRequestMapper(RequestMapper)} method.
|
||||
* <p/>
|
||||
* The value for {@link #expectReply} is <code>false</code> by default.
|
||||
* This means that as soon as the Message is created and passed to the
|
||||
@@ -112,7 +87,7 @@ public class HttpInboundEndpoint extends SimpleMessagingGateway implements HttpR
|
||||
|
||||
private volatile boolean expectReply;
|
||||
|
||||
private volatile boolean extractRequestPayload = true;
|
||||
private volatile RequestMapper requestMapper = new DefaultRequestMapper();
|
||||
|
||||
private volatile boolean extractReplyPayload = true;
|
||||
|
||||
@@ -145,16 +120,13 @@ public class HttpInboundEndpoint extends SimpleMessagingGateway implements HttpR
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether the inbound request's content should be passed as
|
||||
* the payload of the Message. If this is set to 'false', the entire
|
||||
* request will be sent as the payload. Otherwise, for a GET request
|
||||
* the parameter map will be the payload. For other supported request
|
||||
* methods, the body will be extracted, and the type of the payload
|
||||
* depends on the Content-Type of the request.
|
||||
* The default value is 'true'.
|
||||
* Specify a {@link RequestMapper} implementation to map from the
|
||||
* inbound HTTP request to a Message. The default implementation
|
||||
* is {@link DefaultRequestMapper}.
|
||||
*/
|
||||
public void setExtractRequestPayload(boolean extractRequestPayload) {
|
||||
this.extractRequestPayload = extractRequestPayload;
|
||||
public void setRequestMapper(RequestMapper requestMapper) {
|
||||
Assert.notNull(requestMapper, "requestMapper must not be null");
|
||||
this.requestMapper = requestMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,111 +178,22 @@ public class HttpInboundEndpoint extends SimpleMessagingGateway implements HttpR
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Message<?> requestMessage = this.createRequestMessage(request);
|
||||
Message<?> requestMessage = this.requestMapper.mapRequest(request);
|
||||
Object reply = this.handleRequestMessage(requestMessage);
|
||||
this.generateResponse(requestMessage, reply, request, response);
|
||||
}
|
||||
catch (RequiredContentLengthUnavailableException e) {
|
||||
response.setStatus(HttpServletResponse.SC_LENGTH_REQUIRED);
|
||||
catch (ResponseStatusCodeException e) {
|
||||
response.setStatus(e.getStatusCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a request Message for the provided HTTP request.
|
||||
* @see #setExtractRequestPayload(boolean)
|
||||
*/
|
||||
private Message<?> createRequestMessage(HttpServletRequest httpRequest) throws ServletException, IOException {
|
||||
if (this.extractRequestPayload) {
|
||||
return this.createMessageFromHttpRequestContent(httpRequest);
|
||||
catch (ServletException e) {
|
||||
throw e;
|
||||
}
|
||||
else {
|
||||
return MessageBuilder.withPayload(httpRequest).build();
|
||||
catch (IOException e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private Message<?> createMessageFromHttpRequestContent(HttpServletRequest request) throws ServletException, IOException {
|
||||
Message<?> message = null;
|
||||
String contentType = request.getContentType();
|
||||
if (request.getMethod().equals("GET")) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("received GET request, using parameter map as payload");
|
||||
}
|
||||
MessageBuilder<?> builder = MessageBuilder.withPayload(request.getParameterMap());
|
||||
this.populateHeaders(request, builder, false);
|
||||
message = builder.build();
|
||||
catch (Exception e) {
|
||||
throw new ServletException(e);
|
||||
}
|
||||
else {
|
||||
Object payload = null;
|
||||
if (contentType != null && contentType.startsWith("text")) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("received " + request.getMethod()
|
||||
+ " request, creating payload with text content");
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
BufferedReader reader = request.getReader();
|
||||
String line = reader.readLine();
|
||||
while (line != null) {
|
||||
sb.append(line);
|
||||
line = reader.readLine();
|
||||
}
|
||||
payload = sb.toString();
|
||||
}
|
||||
else if (contentType != null && contentType.equals("application/x-java-serialized-object")) {
|
||||
try {
|
||||
payload = new ObjectInputStream(request.getInputStream()).readObject();
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
throw new ServletException("failed to deserialize Object in request", e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
InputStream stream = request.getInputStream();
|
||||
int length = request.getContentLength();
|
||||
if (length == -1) {
|
||||
throw new RequiredContentLengthUnavailableException();
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("received " + request.getMethod() + " request, "
|
||||
+ "creating byte array payload with content lenth: " + length);
|
||||
}
|
||||
byte[] bytes = new byte[length];
|
||||
stream.read(bytes, 0, length);
|
||||
payload = bytes;
|
||||
}
|
||||
MessageBuilder<?> builder = MessageBuilder.withPayload(payload);
|
||||
this.populateHeaders(request, builder, true);
|
||||
message = builder.build();
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void populateHeaders(HttpServletRequest request, MessageBuilder<?> builder, boolean includeParameters) {
|
||||
Enumeration<?> headerNames = request.getHeaderNames();
|
||||
if (headerNames != null) {
|
||||
while (headerNames.hasMoreElements()) {
|
||||
String headerName = (String) headerNames.nextElement();
|
||||
Enumeration<?> headerEnum = request.getHeaders(headerName);
|
||||
if (headerEnum != null) {
|
||||
List<Object> headers = new ArrayList<Object>();
|
||||
while (headerEnum.hasMoreElements()) {
|
||||
headers.add(headerEnum.nextElement());
|
||||
}
|
||||
if (headers.size() == 1) {
|
||||
builder.setHeader(headerName, headers.get(0));
|
||||
}
|
||||
else if (headers.size() > 1) {
|
||||
builder.setHeader(headerName, headers);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (includeParameters) {
|
||||
builder.copyHeaders(request.getParameterMap());
|
||||
}
|
||||
builder.setHeader(HttpHeaders.REQUEST_URL, request.getRequestURL().toString());
|
||||
builder.setHeader(HttpHeaders.REQUEST_METHOD, request.getMethod());
|
||||
builder.setHeader(HttpHeaders.USER_PRINCIPAL, request.getUserPrincipal());
|
||||
}
|
||||
|
||||
private Object handleRequestMessage(Message<?> requestMessage) {
|
||||
@@ -379,9 +262,4 @@ public class HttpInboundEndpoint extends SimpleMessagingGateway implements HttpR
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class RequiredContentLengthUnavailableException extends RuntimeException {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.http;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.integration.core.Message;
|
||||
|
||||
/**
|
||||
* Strategy interface for mapping from an inbound {@link HttpServletRequest}
|
||||
* to a Message.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public interface RequestMapper {
|
||||
|
||||
Message<?> mapRequest(HttpServletRequest request) throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.http;
|
||||
|
||||
/**
|
||||
* Exception that provides a response status code. This can be used by
|
||||
* {@link RequestMapper} implementations to indicate an error.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ResponseStatusCodeException extends Exception {
|
||||
|
||||
private final int statusCode;
|
||||
|
||||
|
||||
public ResponseStatusCodeException(int statusCode) {
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
|
||||
|
||||
public int getStatusCode() {
|
||||
return this.statusCode;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -76,19 +76,17 @@ public class HttpInboundEndpointParser extends AbstractSingleBeanDefinitionParse
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "request-timeout");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "extract-request-payload");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "extract-reply-payload");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-key");
|
||||
}
|
||||
else {
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(
|
||||
builder, element, "send-timeout", "requestTimeout");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(
|
||||
builder, element, "extract-payload", "extractRequestPayload");
|
||||
}
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "supported-methods");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "view");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "request-key");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "request-mapper");
|
||||
}
|
||||
|
||||
private String getInputChannelAttributeName() {
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="extract-payload" type="xsd:string" default="true"/>
|
||||
<xsd:attribute name="send-timeout" type="xsd:string"/>
|
||||
<xsd:attribute name="supported-methods" type="xsd:string"/>
|
||||
<xsd:attribute name="view" type="xsd:string">
|
||||
@@ -48,6 +47,15 @@
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="request-mapper" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.http.RequestMapper"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="request-key" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
@@ -61,7 +69,6 @@
|
||||
</xsd:annotation>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="gatewayType">
|
||||
<xsd:attribute name="extract-request-payload" type="xsd:string" default="true"/>
|
||||
<xsd:attribute name="extract-reply-payload" type="xsd:string" default="true"/>
|
||||
<xsd:attribute name="supported-methods" type="xsd:string"/>
|
||||
<xsd:attribute name="view" type="xsd:string">
|
||||
@@ -73,6 +80,15 @@
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="request-mapper" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.http.RequestMapper"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="request-key" type="xsd:string"/>
|
||||
<xsd:attribute name="reply-key" type="xsd:string"/>
|
||||
</xsd:extension>
|
||||
|
||||
@@ -40,6 +40,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.easymock.IAnswer;
|
||||
@@ -50,6 +51,7 @@ import org.junit.Test;
|
||||
import org.springframework.integration.core.Message;
|
||||
import org.springframework.integration.core.MessageChannel;
|
||||
import org.springframework.integration.core.MessageHeaders;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.web.servlet.View;
|
||||
@@ -153,14 +155,18 @@ public class HttpInboundEndpointTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleRequest_withExtractRequestPayloadIsFalse_requestObjectIsInPayload()
|
||||
public void handleRequest_withCustomRequestMapper_requestObjectIsInPayload()
|
||||
throws ServletException, IOException {
|
||||
endpoint.setExtractRequestPayload(false);
|
||||
endpoint.setRequestMapper(new RequestMapper() {
|
||||
public Message<?> mapRequest(HttpServletRequest request) throws Exception {
|
||||
return new StringMessage(request.getRequestURI());
|
||||
}
|
||||
});
|
||||
expect(requestChannel.send(isA(Message.class))).andAnswer(
|
||||
new IAnswer<Boolean>() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public Boolean answer() throws Throwable {
|
||||
assertThat(((Message) getCurrentArguments()[0]).getPayload(), is((Object) request));
|
||||
assertThat(((Message) getCurrentArguments()[0]).getPayload(), is((Object) "/anyurl"));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user