INT-1347: add convertExceptions to request handler and error-key/code to controller
This commit is contained in:
@@ -16,39 +16,49 @@
|
||||
|
||||
package org.springframework.integration.http;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.MapBindingResult;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.mvc.Controller;
|
||||
|
||||
/**
|
||||
* Inbound HTTP endpoint that implements Spring's {@link Controller}
|
||||
* interface to be used with a DispatcherServlet front controller.
|
||||
* Inbound HTTP endpoint that implements Spring's {@link Controller} interface to be used with a DispatcherServlet front
|
||||
* controller.
|
||||
* <p/>
|
||||
* The {@link #setViewName(String) viewName} will be passed into the
|
||||
* ModelAndView return value.
|
||||
* The {@link #setViewName(String) viewName} will be passed into the ModelAndView return value.
|
||||
* <p/>
|
||||
* This endpoint will have request/reply behavior by default. That
|
||||
* can be overridden by passing <code>false</code> to the constructor.
|
||||
* In the request/reply case, the model map will be passed to the view, and it
|
||||
* will contain either the 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").
|
||||
* This endpoint will have request/reply behavior by default. That can be overridden by passing <code>false</code> to
|
||||
* the constructor. In the request/reply case, the model map will be passed to the view, and it will contain either the
|
||||
* 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
|
||||
* @since 2.0
|
||||
*/
|
||||
public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSupport implements Controller {
|
||||
|
||||
private static final String DEFAULT_ERROR_CODE = "spring.integration.http.handler.error";
|
||||
|
||||
private static final String DEFAULT_REPLY_KEY = "reply";
|
||||
|
||||
private static final String DEFAULT_ERRORS_KEY = "errors";
|
||||
|
||||
private volatile String viewName;
|
||||
|
||||
private volatile String replyKey = DEFAULT_REPLY_KEY;
|
||||
|
||||
private volatile String errorsKey = DEFAULT_ERRORS_KEY;
|
||||
|
||||
private volatile String errorCode = DEFAULT_ERROR_CODE;
|
||||
|
||||
public HttpRequestHandlingController() {
|
||||
this(true);
|
||||
@@ -58,7 +68,6 @@ public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSu
|
||||
super(expectReply);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify the view name.
|
||||
*/
|
||||
@@ -67,30 +76,60 @@ public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSu
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the key to be used when adding the reply Message or payload
|
||||
* to the model map (will be payload only unless the value of
|
||||
* {@link HttpRequestHandlingController#setExtractReplyPayload(boolean)} is <code>false</code>).
|
||||
* The default key is "reply".
|
||||
* Specify the key to be used when adding the reply Message or payload to the model map (will be payload only unless
|
||||
* the value of {@link HttpRequestHandlingController#setExtractReplyPayload(boolean)} is <code>false</code>). The
|
||||
* default key is "reply".
|
||||
*/
|
||||
public void setReplyKey(String replyKey) {
|
||||
this.replyKey = (replyKey != null) ? replyKey : DEFAULT_REPLY_KEY;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* The key used to expose {@link Errors} in the model, in the case that message handling fails. Defaults to
|
||||
* "errors".
|
||||
* @param errorsKey the key value to set
|
||||
*/
|
||||
public final ModelAndView handleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception {
|
||||
public void setErrorsKey(String errorsKey) {
|
||||
this.errorsKey = errorsKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* The error code to use to signal an error in the message handling. In the case of an error this code will be
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
Object reply = super.doHandleRequest(servletRequest, servletResponse);
|
||||
if (reply != null) {
|
||||
modelAndView.addObject(this.replyKey, reply);
|
||||
try {
|
||||
Object reply = super.doHandleRequest(servletRequest, servletResponse);
|
||||
if (reply != null) {
|
||||
modelAndView.addObject(this.replyKey, reply);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
MapBindingResult errors = new MapBindingResult(new HashMap<String, Object>(), "dummy");
|
||||
PrintWriter stackTrace = new PrintWriter(new StringWriter());
|
||||
e.printStackTrace(stackTrace);
|
||||
errors.reject(errorCode, new Object[] { e, e.getMessage(), stackTrace.toString() },
|
||||
"A Spring Integration handler raised an exception while handling an HTTP request. The exception is of type "
|
||||
+ e.getClass() + " and it has a message: (" + e.getMessage() + ")");
|
||||
modelAndView.addObject(errorsKey, errors);
|
||||
}
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -55,44 +55,38 @@ import org.springframework.web.servlet.DispatcherServlet;
|
||||
/**
|
||||
* Base class for HTTP request handling endpoints.
|
||||
* <p/>
|
||||
* 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).
|
||||
* A GET request will generate a payload containing its 'parameterMap' while
|
||||
* a POST request will be converted to a Message payload according to
|
||||
* the registered {@link HttpMessageConverter}s. Several are registered
|
||||
* by default, but the list can be explicitly set via {@link #setMessageConverters(List)}.
|
||||
* 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). A GET request will generate a payload containing its 'parameterMap' while a POST
|
||||
* request will be converted to a Message payload according to the registered {@link HttpMessageConverter}s. Several are
|
||||
* registered by default, but the list can be explicitly set via {@link #setMessageConverters(List)}.
|
||||
* <p/>
|
||||
* To customize the mapping of request headers to the MessageHeaders, provide
|
||||
* a reference to a {@link HeaderMapper HeaderMapper<HttpHeaders>} implementation
|
||||
* to the {@link #setHeaderMapper(HeaderMapper)} method.
|
||||
* To customize the mapping of request headers to the MessageHeaders, provide a reference to a {@link HeaderMapper
|
||||
* HeaderMapper<HttpHeaders>} implementation to the {@link #setHeaderMapper(HeaderMapper)} method.
|
||||
* <p/>
|
||||
* The behavior is "request/reply" by default. Pass <code>false</code>
|
||||
* to the constructor to force send-only as opposed to sendAndReceive.
|
||||
* Send-only means that as soon as the Message is created and passed to the
|
||||
* {@link #setRequestChannel(org.springframework.integration.core.MessageChannel) request channel},
|
||||
* a response will be generated. Subclasses determine how that response is
|
||||
* generated (e.g. simple status response or rendering a View).
|
||||
* The behavior is "request/reply" by default. Pass <code>false</code> to the constructor to force send-only as opposed
|
||||
* to sendAndReceive. Send-only means that as soon as the Message is created and passed to the
|
||||
* {@link #setRequestChannel(org.springframework.integration.MessageChannel) request channel}, a response will be
|
||||
* generated. Subclasses determine how that response is generated (e.g. simple status response or rendering a View).
|
||||
* <p/>
|
||||
* 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>.
|
||||
* 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
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class HttpRequestHandlingEndpointSupport extends AbstractMessagingGateway {
|
||||
|
||||
private static final boolean jaxb2Present =
|
||||
ClassUtils.isPresent("javax.xml.bind.Binder", HttpRequestHandlingEndpointSupport.class.getClassLoader());
|
||||
private static final boolean jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder",
|
||||
HttpRequestHandlingEndpointSupport.class.getClassLoader());
|
||||
|
||||
private static final boolean jacksonPresent =
|
||||
ClassUtils.isPresent("org.codehaus.jackson.map.ObjectMapper", 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());
|
||||
private static final boolean jacksonPresent = ClassUtils.isPresent("org.codehaus.jackson.map.ObjectMapper",
|
||||
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());
|
||||
|
||||
private volatile List<HttpMethod> supportedMethods = Arrays.asList(HttpMethod.GET, HttpMethod.POST);
|
||||
|
||||
@@ -108,7 +102,6 @@ abstract class HttpRequestHandlingEndpointSupport extends AbstractMessagingGatew
|
||||
|
||||
private volatile MultipartResolver multipartResolver;
|
||||
|
||||
|
||||
public HttpRequestHandlingEndpointSupport() {
|
||||
this(true);
|
||||
}
|
||||
@@ -130,11 +123,17 @@ abstract class HttpRequestHandlingEndpointSupport extends AbstractMessagingGatew
|
||||
}
|
||||
if (romePresent) {
|
||||
// TODO add deps for:
|
||||
//this.messageConverters.add(new AtomFeedHttpMessageConverter());
|
||||
//this.messageConverters.add(new RssChannelHttpMessageConverter());
|
||||
// this.messageConverters.add(new AtomFeedHttpMessageConverter());
|
||||
// this.messageConverters.add(new RssChannelHttpMessageConverter());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return whether to expect reply
|
||||
*/
|
||||
protected boolean isExpectReply() {
|
||||
return expectReply;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message body converters to use. These converters are used to convert from and to HTTP requests and
|
||||
@@ -158,8 +157,7 @@ abstract class HttpRequestHandlingEndpointSupport extends AbstractMessagingGatew
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the supported request method names for this gateway.
|
||||
* By default, only GET and POST are supported.
|
||||
* Specify the supported request method names for this gateway. By default, only GET and POST are supported.
|
||||
*/
|
||||
public void setSupportedMethodNames(String... supportedMethods) {
|
||||
Assert.notEmpty(supportedMethods, "at least one supported method is required");
|
||||
@@ -171,8 +169,7 @@ abstract class HttpRequestHandlingEndpointSupport extends AbstractMessagingGatew
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the supported request methods for this gateway.
|
||||
* By default, only GET and POST are supported.
|
||||
* Specify the supported request methods for this gateway. By default, only GET and POST are supported.
|
||||
*/
|
||||
public void setSupportedMethods(HttpMethod... supportedMethods) {
|
||||
Assert.notEmpty(supportedMethods, "at least one supported method is required");
|
||||
@@ -180,29 +177,26 @@ abstract class HttpRequestHandlingEndpointSupport extends AbstractMessagingGatew
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the type of payload to be generated when the inbound HTTP request content
|
||||
* is read by the {@link HttpMessageConverter}s. By default this value is null which
|
||||
* means at runtime any "text" Content-Type will result in String while all others
|
||||
* default to <code>byte[].class</code>.
|
||||
* Specify the type of payload to be generated when the inbound HTTP request content is read by the
|
||||
* {@link HttpMessageConverter}s. By default this value is null which means at runtime any "text" Content-Type will
|
||||
* result in String while all others default to <code>byte[].class</code>.
|
||||
*/
|
||||
public void setRequestPayloadType(Class<?> requestPayloadType) {
|
||||
this.requestPayloadType = requestPayloadType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether only the reply Message's payload should be passed
|
||||
* in the response. If this is set to 'false', the entire Message will
|
||||
* be used to generate the response. The default is 'true'.
|
||||
* Specify whether only the reply Message's payload should be passed in the response. If this is set to 'false', the
|
||||
* entire Message will be used to generate the response. The default is 'true'.
|
||||
*/
|
||||
public void setExtractReplyPayload(boolean extractReplyPayload) {
|
||||
this.extractReplyPayload = extractReplyPayload;
|
||||
this.extractReplyPayload = extractReplyPayload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the {@link MultipartResolver} to use when checking requests.
|
||||
* If no resolver is provided, the "multipartResolver" bean in the context
|
||||
* will be used as a fallback. If that is not available either, this endpoint
|
||||
* will not support multipart requests.
|
||||
* Specify the {@link MultipartResolver} to use when checking requests. If no resolver is provided, the
|
||||
* "multipartResolver" bean in the context will be used as a fallback. If that is not available either, this
|
||||
* endpoint will not support multipart requests.
|
||||
*/
|
||||
public void setMultipartResolver(MultipartResolver multipartResolver) {
|
||||
this.multipartResolver = multipartResolver;
|
||||
@@ -210,12 +204,12 @@ abstract class HttpRequestHandlingEndpointSupport extends AbstractMessagingGatew
|
||||
|
||||
@Override
|
||||
public String getComponentType() {
|
||||
return (this.expectReply) ? "http:inbound-gateway" : "http:inbound-channel-adapter";
|
||||
return (this.expectReply) ? "http:inbound-gateway" : "http:inbound-channel-adapter";
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the {@link MultipartResolver} bean based on the default name defined by
|
||||
* the {@link DispatcherServlet#MULTIPART_RESOLVER_BEAN_NAME} constant if available.
|
||||
* Locates the {@link MultipartResolver} bean based on the default name defined by the
|
||||
* {@link DispatcherServlet#MULTIPART_RESOLVER_BEAN_NAME} constant if available.
|
||||
*/
|
||||
@Override
|
||||
protected void onInit() throws Exception {
|
||||
@@ -223,8 +217,8 @@ abstract class HttpRequestHandlingEndpointSupport extends AbstractMessagingGatew
|
||||
BeanFactory beanFactory = this.getBeanFactory();
|
||||
if (this.multipartResolver == null && beanFactory != null) {
|
||||
try {
|
||||
MultipartResolver multipartResolver =
|
||||
this.getBeanFactory().getBean(DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
|
||||
MultipartResolver multipartResolver = this.getBeanFactory().getBean(
|
||||
DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using MultipartResolver [" + multipartResolver + "]");
|
||||
}
|
||||
@@ -232,19 +226,20 @@ abstract class HttpRequestHandlingEndpointSupport extends AbstractMessagingGatew
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException e) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Unable to locate MultipartResolver with name '" + DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME +
|
||||
"': no multipart request handling will be supported.");
|
||||
logger.debug("Unable to locate MultipartResolver with name '"
|
||||
+ DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME
|
||||
+ "': no multipart request handling will be supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
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())) {
|
||||
@@ -259,12 +254,12 @@ abstract class HttpRequestHandlingEndpointSupport extends AbstractMessagingGatew
|
||||
payload = this.convertParameterMap(servletRequest.getParameterMap());
|
||||
}
|
||||
Map<String, ?> headers = this.headerMapper.toHeaders(request.getHeaders());
|
||||
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, servletRequest.getUserPrincipal())
|
||||
.build();
|
||||
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,
|
||||
servletRequest.getUserPrincipal()).build();
|
||||
Object reply = null;
|
||||
if (this.expectReply) {
|
||||
reply = this.sendAndReceiveMessage(message);
|
||||
@@ -287,9 +282,9 @@ abstract class HttpRequestHandlingEndpointSupport extends AbstractMessagingGatew
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, simply returns the existing request.
|
||||
* 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,
|
||||
* simply returns the existing request.
|
||||
* @param request current HTTP request
|
||||
* @return the processed request (multipart wrapper if necessary)
|
||||
* @see MultipartResolver#resolveMultipart
|
||||
@@ -305,8 +300,7 @@ abstract class HttpRequestHandlingEndpointSupport extends AbstractMessagingGatew
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the request has a readable body (not a GET, HEAD, or OPTIONS request)
|
||||
* and a Content-Type header.
|
||||
* Checks if the request has a readable body (not a GET, HEAD, or OPTIONS request) and a Content-Type header.
|
||||
*/
|
||||
private boolean isReadable(ServletServerHttpRequest request) {
|
||||
HttpMethod method = request.getMethod();
|
||||
@@ -354,8 +348,9 @@ abstract class HttpRequestHandlingEndpointSupport extends AbstractMessagingGatew
|
||||
return converter.read((Class) expectedType, request);
|
||||
}
|
||||
}
|
||||
throw new MessagingException("Could not convert request: no suitable HttpMessageConverter found for expected type [" +
|
||||
expectedType.getName() + "] and content type [" + contentType + "]");
|
||||
throw new MessagingException(
|
||||
"Could not convert request: no suitable HttpMessageConverter found for expected type ["
|
||||
+ expectedType.getName() + "] and content type [" + contentType + "]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,31 +32,31 @@ import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.HttpRequestHandler;
|
||||
|
||||
/**
|
||||
* Inbound Messaging Gateway that handles HTTP Requests. May be configured as a bean in the
|
||||
* Application Context and delegated to from a simple HttpRequestHandlerServlet in
|
||||
* <code>web.xml</code> where the servlet and bean both have the same name. If the
|
||||
* {@link #expectReply} property is set to true, a response can generated from a
|
||||
* reply Message. Otherwise, the gateway will play the role of a unidirectional
|
||||
* Channel Adapter with a simple status-based response (e.g. 200 OK).
|
||||
* Inbound Messaging Gateway that handles HTTP Requests. May be configured as a bean in the Application Context and
|
||||
* delegated to from a simple HttpRequestHandlerServlet in <code>web.xml</code> where the servlet and bean both have the
|
||||
* same name. If the {@link #expectReply} property is set to true, a response can generated from a reply Message.
|
||||
* Otherwise, the gateway will play the role of a unidirectional Channel Adapter with a simple status-based response
|
||||
* (e.g. 200 OK).
|
||||
* <p/>
|
||||
* The default supported request methods are GET and POST, but the list of values can
|
||||
* be configured with the {@link #supportedMethods} property. The payload generated from
|
||||
* a GET request (or HEAD or OPTIONS if supported) will be a {@link MultiValueMap}
|
||||
* containing the parameter values. For a request containing a body (e.g. a POST),
|
||||
* the type of the payload is determined by the {@link #setRequestPayloadType(Class) request payload type}.
|
||||
* The default supported request methods are GET and POST, but the list of values can be configured with the
|
||||
* {@link #supportedMethods} property. The payload generated from a GET request (or HEAD or OPTIONS if supported) will
|
||||
* be a {@link MultiValueMap} containing the parameter values. For a request containing a body (e.g. a POST), the type
|
||||
* of the payload is determined by the {@link #setRequestPayloadType(Class) request payload type}.
|
||||
* <p/>
|
||||
* If the HTTP request is a multipart and a "multipartResolver" bean has been defined
|
||||
* in the context, then it will be converted by the {@link MultipartAwareFormHttpMessageConverter}
|
||||
* as long as the default message converters have not been overwritten (although
|
||||
* providing a customized instance of the Multipart-aware converter is also an option).
|
||||
* If the HTTP request is a multipart and a "multipartResolver" bean has been defined in the context, then it will be
|
||||
* converted by the {@link MultipartAwareFormHttpMessageConverter} as long as the default message converters have not
|
||||
* been overwritten (although providing a customized instance of the Multipart-aware converter is also an option).
|
||||
* <p/>
|
||||
* By default a number of {@link HttpMessageConverter}s are already configured. The list
|
||||
* can be overridden by calling the {@link #setMessageConverters(List)} method.
|
||||
* 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
|
||||
* @since 2.0
|
||||
*/
|
||||
public class HttpRequestHandlingMessagingGateway extends HttpRequestHandlingEndpointSupport implements HttpRequestHandler {
|
||||
public class HttpRequestHandlingMessagingGateway extends HttpRequestHandlingEndpointSupport implements
|
||||
HttpRequestHandler {
|
||||
|
||||
private volatile boolean convertExceptions;
|
||||
|
||||
public HttpRequestHandlingMessagingGateway() {
|
||||
this(true);
|
||||
@@ -66,14 +66,31 @@ public class HttpRequestHandlingMessagingGateway extends HttpRequestHandlingEndp
|
||||
super(expectReply);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
this.convertExceptions = convertExceptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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. That response will be written by the {@link HttpMessageConverter}s.
|
||||
* 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. That
|
||||
* response will be written by the {@link HttpMessageConverter}s.
|
||||
*/
|
||||
public final void handleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException {
|
||||
Object responseContent = super.doHandleRequest(servletRequest, servletResponse);
|
||||
public final void handleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
|
||||
throws ServletException, IOException {
|
||||
Object responseContent = null;
|
||||
try {
|
||||
responseContent = super.doHandleRequest(servletRequest, servletResponse);
|
||||
}
|
||||
catch (Exception e) {
|
||||
responseContent = handleExceptionInternal(e);
|
||||
}
|
||||
if (responseContent != null) {
|
||||
ServletServerHttpRequest request = new ServletServerHttpRequest(servletRequest);
|
||||
ServletServerHttpResponse response = new ServletServerHttpResponse(servletResponse);
|
||||
@@ -81,8 +98,23 @@ public class HttpRequestHandlingMessagingGateway extends HttpRequestHandlingEndp
|
||||
}
|
||||
}
|
||||
|
||||
private Object handleExceptionInternal(Exception e) throws IOException {
|
||||
if (convertExceptions && isExpectReply()) {
|
||||
return e;
|
||||
}
|
||||
else {
|
||||
if (e instanceof IOException) {
|
||||
throw (IOException) e;
|
||||
}
|
||||
else {
|
||||
throw (RuntimeException) e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void writeResponse(Object content, ServletServerHttpResponse response, List<MediaType> acceptTypes) throws IOException {
|
||||
private void writeResponse(Object content, ServletServerHttpResponse response, List<MediaType> acceptTypes)
|
||||
throws IOException {
|
||||
for (HttpMessageConverter converter : this.getMessageConverters()) {
|
||||
for (MediaType acceptType : acceptTypes) {
|
||||
if (converter.canWrite(content.getClass(), acceptType)) {
|
||||
@@ -91,8 +123,8 @@ public class HttpRequestHandlingMessagingGateway extends HttpRequestHandlingEndp
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new MessagingException("Could not convert reply: no suitable HttpMessageConverter found for type [" +
|
||||
content.getClass().getName() + "] and accept types [" + acceptTypes + "]");
|
||||
throw new MessagingException("Could not convert reply: no suitable HttpMessageConverter found for type ["
|
||||
+ content.getClass().getName() + "] and accept types [" + acceptTypes + "]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ public class HttpInboundEndpointParser extends AbstractSingleBeanDefinitionParse
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "extract-reply-payload");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-key");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "convert-exceptions");
|
||||
}
|
||||
else {
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(
|
||||
@@ -88,6 +89,8 @@ 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");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "errors-key");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "error-code");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "message-converters");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "header-mapper");
|
||||
}
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsd:schema xmlns="http://www.springframework.org/schema/integration/http"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
targetNamespace="http://www.springframework.org/schema/integration/http"
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
<xsd:schema xmlns="http://www.springframework.org/schema/integration/http" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
targetNamespace="http://www.springframework.org/schema/integration/http" elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
|
||||
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
|
||||
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
|
||||
<xsd:import namespace="http://www.springframework.org/schema/beans" />
|
||||
<xsd:import namespace="http://www.springframework.org/schema/tool" />
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
@@ -20,16 +17,16 @@
|
||||
<xsd:complexType>
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Defines an inbound HTTP-based Channel Adapter.
|
||||
Defines an inbound HTTP-based Channel Adapter.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:attribute name="id" type="xsd:ID"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="id" type="xsd:ID" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="channel" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
|
||||
<tool:expected-type type="org.springframework.integration.core.MessageChannel" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
@@ -41,8 +38,8 @@
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="send-timeout" type="xsd:string"/>
|
||||
<xsd:attribute name="supported-methods" type="xsd:string"/>
|
||||
<xsd:attribute name="send-timeout" type="xsd:string" />
|
||||
<xsd:attribute name="supported-methods" type="xsd:string" />
|
||||
<xsd:attribute name="view-name" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
@@ -50,6 +47,28 @@
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="errors-key" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
In the case that a view-name is specified this attribute can be used to
|
||||
override the default key of the Errors (if the request cannot be handled).
|
||||
Defaults to "errors" (similar to normal MVC
|
||||
usage).
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="error-code" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
In the case that a view-name is specified this attribute can be used to
|
||||
override the default error code under which the handling exception is exposed.
|
||||
Defaults to
|
||||
"spring.integration.http.handler.error" and is supplied with 3
|
||||
parameters: the exception itself, its message and
|
||||
its stack trace as a String.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="message-converters" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
@@ -61,7 +80,7 @@
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.mapping.HeaderMapper"/>
|
||||
<tool:expected-type type="org.springframework.integration.mapping.HeaderMapper" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
@@ -73,14 +92,14 @@
|
||||
<xsd:complexType>
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Defines an inbound HTTP-based Messaging Gateway.
|
||||
Defines an inbound HTTP-based Messaging Gateway.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="gatewayType">
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="extract-reply-payload" type="xsd:string" default="true"/>
|
||||
<xsd:attribute name="supported-methods" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="extract-reply-payload" type="xsd:string" default="true" />
|
||||
<xsd:attribute name="supported-methods" type="xsd:string" />
|
||||
<xsd:attribute name="view-name" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
@@ -88,6 +107,35 @@
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="errors-key" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
In the case that a view-name is specified this attribute can be used to
|
||||
override the default key of the Errors (if the request cannot be handled).
|
||||
Defaults to "errors" (similar to normal MVC usage).
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="error-code" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
In the case that a view-name is specified this attribute can be used to
|
||||
override the default error code under which the handling exception is exposed.
|
||||
Defaults to "spring.integration.http.handler.error" and is supplied with 3
|
||||
parameters: the exception itself, its message and its stack trace as a String.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="convert-exceptions" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
In the case that a view-name is not specified this attribute can be used to
|
||||
override the default behaviour when there is a message handling exception (which
|
||||
is to rethrow). If this flag is true then the normal conversion process will be
|
||||
applied to the exception and written out to the response body.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="request-payload-type" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
@@ -106,13 +154,13 @@
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.mapping.HeaderMapper"/>
|
||||
<tool:expected-type type="org.springframework.integration.mapping.HeaderMapper" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="reply-key" type="xsd:string"/>
|
||||
<xsd:attribute name="reply-timeout" type="xsd:string"/>
|
||||
<xsd:attribute name="reply-key" type="xsd:string" />
|
||||
<xsd:attribute name="reply-timeout" type="xsd:string" />
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
@@ -122,13 +170,13 @@
|
||||
<xsd:complexType>
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Defines an outbound HTTP-based Channel Adapter.
|
||||
Defines an outbound HTTP-based Channel Adapter.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="uri-variable" type="uriVariableType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xsd:element name="uri-variable" type="uriVariableType" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="id" type="xsd:ID"/>
|
||||
<xsd:attribute name="id" type="xsd:ID" />
|
||||
<xsd:attribute name="url" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
@@ -140,7 +188,7 @@
|
||||
<xsd:attribute name="http-method">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The HTTP method to use when executing requests with this adapter.
|
||||
The HTTP method to use when executing requests with this adapter.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
@@ -151,21 +199,21 @@
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
|
||||
<tool:expected-type type="org.springframework.integration.core.MessageChannel" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="charset" type="xsd:string"/>
|
||||
<xsd:attribute name="extract-payload" type="xsd:string"/>
|
||||
<xsd:attribute name="charset" type="xsd:string" />
|
||||
<xsd:attribute name="extract-payload" type="xsd:string" />
|
||||
<xsd:attribute name="expected-response-type" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The expected type to which the response body should be converted.
|
||||
The expected type to which the response body should be converted.
|
||||
</xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="direct">
|
||||
<tool:expected-type type="java.lang.Class"/>
|
||||
<tool:expected-type type="java.lang.Class" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
@@ -173,8 +221,8 @@
|
||||
<xsd:attribute name="message-converters" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Provide a reference to a list of HttpMessageConverter instances. If specified, these converters will replace
|
||||
all of the default converters that would normally be present on the underlying RestTemplate.
|
||||
Provide a reference to a list of HttpMessageConverter instances. If specified, these converters will replace
|
||||
all of the default converters that would normally be present on the underlying RestTemplate.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
@@ -182,7 +230,7 @@
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.mapping.HeaderMapper"/>
|
||||
<tool:expected-type type="org.springframework.integration.mapping.HeaderMapper" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
@@ -199,7 +247,7 @@
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.http.client.ClientHttpRequestFactory"/>
|
||||
<tool:expected-type type="org.springframework.http.client.ClientHttpRequestFactory" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
@@ -214,7 +262,7 @@
|
||||
<xsd:attribute name="auto-startup" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specifies whether this adapter should start automatically.
|
||||
Specifies whether this adapter should start automatically.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
@@ -225,25 +273,25 @@
|
||||
<xsd:complexType>
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Defines an outbound HTTP-based Messaging Gateway.
|
||||
Defines an outbound HTTP-based Messaging Gateway.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="gatewayType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="uri-variable" type="uriVariableType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xsd:element name="uri-variable" type="uriVariableType" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="url" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
URL to be used as a fallback for any request Message does not contain the request URL Message header.
|
||||
URL to be used as a fallback for any request Message does not contain the request URL Message header.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="http-method">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The HTTP method to use when executing requests with this adapter.
|
||||
The HTTP method to use when executing requests with this adapter.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
@@ -253,8 +301,8 @@
|
||||
<xsd:attribute name="message-converters" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Provide a reference to a list of HttpMessageConverter instances. If specified, these converters will replace
|
||||
all of the default converters that would normally be present on the underlying RestTemplate.
|
||||
Provide a reference to a list of HttpMessageConverter instances. If specified, these converters will replace
|
||||
all of the default converters that would normally be present on the underlying RestTemplate.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
@@ -262,7 +310,7 @@
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.mapping.HeaderMapper"/>
|
||||
<tool:expected-type type="org.springframework.integration.mapping.HeaderMapper" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
@@ -283,25 +331,25 @@
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="extract-request-payload" type="xsd:string"/>
|
||||
<xsd:attribute name="extract-request-payload" type="xsd:string" />
|
||||
<xsd:attribute name="expected-response-type" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The expected type to which the response body should be converted.
|
||||
The expected type to which the response body should be converted.
|
||||
</xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="direct">
|
||||
<tool:expected-type type="java.lang.Class"/>
|
||||
<tool:expected-type type="java.lang.Class" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="charset" type="xsd:string"/>
|
||||
<xsd:attribute name="charset" type="xsd:string" />
|
||||
<xsd:attribute name="request-factory" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.http.client.ClientHttpRequestFactory"/>
|
||||
<tool:expected-type type="org.springframework.http.client.ClientHttpRequestFactory" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
@@ -313,7 +361,7 @@
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="auto-startup" type="xsd:string"/>
|
||||
<xsd:attribute name="auto-startup" type="xsd:string" />
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
@@ -359,15 +407,15 @@
|
||||
<xsd:complexType name="gatewayType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Defines common configuration for gateway adapters.
|
||||
Defines common configuration for gateway adapters.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:attribute name="id" type="xsd:ID"/>
|
||||
<xsd:attribute name="id" type="xsd:ID" />
|
||||
<xsd:attribute name="request-channel" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
|
||||
<tool:expected-type type="org.springframework.integration.core.MessageChannel" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
@@ -376,12 +424,12 @@
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
|
||||
<tool:expected-type type="org.springframework.integration.core.MessageChannel" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="request-timeout" type="xsd:string"/>
|
||||
<xsd:attribute name="request-timeout" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
|
||||
</xsd:schema>
|
||||
@@ -22,12 +22,13 @@ import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
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.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
@@ -136,4 +137,29 @@ public class HttpRequestHandlingControllerTests {
|
||||
assertEquals("ABC", ((Message<?>) reply).getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendWithError() throws Exception {
|
||||
QueueChannel requestChannel = new QueueChannel() {
|
||||
@Override
|
||||
protected boolean doSend(Message<?> message, long timeout) {
|
||||
throw new RuntimeException("Planned");
|
||||
}
|
||||
};
|
||||
HttpRequestHandlingController controller = new HttpRequestHandlingController(false);
|
||||
controller.setRequestChannel(requestChannel);
|
||||
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(1, modelAndView.getModel().size());
|
||||
Errors errors = (Errors) modelAndView.getModel().get("errors");
|
||||
assertEquals(1, errors.getErrorCount());
|
||||
ObjectError error = errors.getAllErrors().get(0);
|
||||
assertEquals(3, error.getArguments().length);
|
||||
assertTrue("Wrong message: "+error, ((String)error.getArguments()[1]).startsWith("failed to send Message"));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -19,8 +19,18 @@ package org.springframework.integration.http;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.junit.Test;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.AbstractHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
@@ -92,4 +102,50 @@ public class HttpRequestHandlingMessagingGatewayTests {
|
||||
assertEquals("HELLO", response.getContentAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExceptionConversion() throws Exception {
|
||||
QueueChannel requestChannel = new QueueChannel() {
|
||||
@Override
|
||||
protected boolean doSend(Message<?> message, long timeout) {
|
||||
throw new RuntimeException("Planned");
|
||||
}
|
||||
};
|
||||
HttpRequestHandlingMessagingGateway gateway = new HttpRequestHandlingMessagingGateway(true);
|
||||
gateway.setRequestChannel(requestChannel);
|
||||
gateway.setConvertExceptions(true);
|
||||
gateway.setMessageConverters(Arrays.<HttpMessageConverter<?>>asList(new DumbHttpMessageConverter()));
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "application/x-java-serialized-object");
|
||||
request.setMethod("GET");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
gateway.handleRequest(request, response);
|
||||
String content = response.getContentAsString();
|
||||
assertEquals("Planned", content);
|
||||
}
|
||||
|
||||
private static class DumbHttpMessageConverter extends AbstractHttpMessageConverter<Exception> {
|
||||
|
||||
public DumbHttpMessageConverter() {
|
||||
setSupportedMediaTypes(Arrays.asList(MediaType.ALL));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Exception readInternal(Class<? extends Exception> clazz, HttpInputMessage inputMessage) throws IOException,
|
||||
HttpMessageNotReadableException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supports(Class<?> clazz) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeInternal(Exception t, HttpOutputMessage outputMessage) throws IOException,
|
||||
HttpMessageNotWritableException {
|
||||
new PrintWriter(outputMessage.getBody()).append(t.getCause().getMessage()).flush();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,4 +20,6 @@
|
||||
|
||||
<inbound-channel-adapter id="putOrDeleteAdapter" channel="requests" supported-methods="PUT, delete"/>
|
||||
|
||||
<inbound-channel-adapter id="inboundController" channel="requests" view-name="foo" error-code="oops"/>
|
||||
|
||||
</beans:beans>
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.core.PollableChannel;
|
||||
import org.springframework.integration.http.HttpRequestHandlingController;
|
||||
import org.springframework.integration.http.HttpRequestHandlingMessagingGateway;
|
||||
import org.springframework.integration.http.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
@@ -62,6 +63,9 @@ public class HttpInboundChannelAdapterParserTests {
|
||||
@Autowired
|
||||
private HttpRequestHandlingMessagingGateway putOrDeleteAdapter;
|
||||
|
||||
@Autowired
|
||||
private HttpRequestHandlingController inboundController;
|
||||
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -137,6 +141,13 @@ public class HttpInboundChannelAdapterParserTests {
|
||||
assertTrue(supportedMethods.contains(HttpMethod.DELETE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testController() throws Exception {
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(inboundController);
|
||||
String errorCode = (String) accessor.getPropertyValue("errorCode");
|
||||
assertEquals("oops", errorCode);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class TestObject implements Serializable {
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
<si:queue/>
|
||||
</si:channel>
|
||||
|
||||
<inbound-gateway id="inboundGateway" request-channel="requests" reply-channel="responses"/>
|
||||
<inbound-gateway id="inboundGateway" request-channel="requests" reply-channel="responses" convert-exceptions="true"/>
|
||||
|
||||
<inbound-gateway id="inboundController" request-channel="requests" reply-channel="responses" view-name="foo" error-code="oops"/>
|
||||
|
||||
</beans:beans>
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.integration.http.config;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.any;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.springframework.integration.test.util.TestUtils.getPropertyValue;
|
||||
@@ -28,10 +29,12 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.core.PollableChannel;
|
||||
import org.springframework.integration.core.SubscribableChannel;
|
||||
import org.springframework.integration.http.HttpRequestHandlingController;
|
||||
import org.springframework.integration.http.HttpRequestHandlingMessagingGateway;
|
||||
import org.springframework.integration.http.MockHttpServletRequest;
|
||||
import org.springframework.integration.http.MockHttpServletResponse;
|
||||
@@ -49,6 +52,9 @@ public class HttpInboundGatewayParserTests {
|
||||
@Autowired
|
||||
private HttpRequestHandlingMessagingGateway gateway;
|
||||
|
||||
@Autowired
|
||||
private HttpRequestHandlingController inboundController;
|
||||
|
||||
@Autowired
|
||||
private SubscribableChannel requests;
|
||||
|
||||
@@ -60,6 +66,7 @@ public class HttpInboundGatewayParserTests {
|
||||
public void checkConfig() {
|
||||
assertNotNull(gateway);
|
||||
assertThat((Boolean) getPropertyValue(gateway, "expectReply"), is(true));
|
||||
assertThat((Boolean) getPropertyValue(gateway, "convertExceptions"), is(true));
|
||||
assertThat((PollableChannel) getPropertyValue(gateway, "replyChannel"), is(responses));
|
||||
}
|
||||
|
||||
@@ -76,4 +83,11 @@ public class HttpInboundGatewayParserTests {
|
||||
assertThat(response.getContentType(), is("application/x-java-serialized-object"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testController() throws Exception {
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(inboundController);
|
||||
String errorCode = (String) accessor.getPropertyValue("errorCode");
|
||||
assertEquals("oops", errorCode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user