INT-916, INT-939 replaced HttpOutboundEndpoint with the RestTemplate-based HttpRequestExecutingMessageHandler

This commit is contained in:
Mark Fisher
2010-06-23 20:19:59 +00:00
parent 91452275ad
commit 341a08f7ff
10 changed files with 495 additions and 571 deletions

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2002-2010 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 org.springframework.http.MediaType;
/**
* Strategy for resolving the content type of a given object. The content type
* will be represented as an instance of the {@link MediaType} enum.
*
* @author Mark Fisher
* @since 2.0
*/
public interface ContentTypeResolver {
/**
* Resolves the content type of a given object.
*
* @param content the object whose content type should be resolved
*/
MediaType resolveContentType(Object content);
/**
* Resolves the content type of a given String instance and charset name.
*
* @param content the String whose content type should be resolved
* @param charset charset name
*/
MediaType resolveContentType(String content, String charset);
}

View File

@@ -16,26 +16,16 @@
package org.springframework.integration.http;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.transform.Source;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.integration.core.Message;
import org.springframework.integration.message.MessageDeliveryException;
import org.springframework.util.Assert;
/**
@@ -46,38 +36,13 @@ import org.springframework.util.Assert;
*/
public class DefaultOutboundRequestMapper implements OutboundRequestMapper {
private volatile URL defaultUrl;
private volatile boolean extractPayload = true;
private volatile ContentTypeResolver contentTypeResolver = new DefaultContentTypeResolver();
private volatile String charset = "UTF-8";
/**
* Create a DefaultOutboundRequestMapper with no default URL.
*/
public DefaultOutboundRequestMapper() {
}
/**
* Create a DefaultOutboundRequestMapper with the given default URL.
*/
public DefaultOutboundRequestMapper(URL defaultUrl) {
this.defaultUrl = defaultUrl;
}
/**
* Specify the default URL to use when the outbound message does not
* contain a value for the {@link HttpHeaders#REQUEST_URL} header.
* This default is optional, but if no value is provided, and a Message
* does not contain the header, then a MessageDeliveryException will be
* thrown at runtime.
*/
public void setDefaultUrl(URL defaultUrl) {
this.defaultUrl = defaultUrl;
}
/**
* Specify whether the outbound message's payload should be extracted
* when preparing the request body. Otherwise the Message instance itself
@@ -96,284 +61,80 @@ public class DefaultOutboundRequestMapper implements OutboundRequestMapper {
this.charset = charset;
}
public HttpRequest fromMessage(Message<?> message) throws Exception {
public HttpEntity<?> fromMessage(Message<?> message) throws Exception {
Assert.notNull(message, "message must not be null");
URL url = this.resolveUrl(message);
if (url == null) {
throw new MessageDeliveryException(message, "failed to determine a target URL for Message");
}
Object requestMethodHeader = message.getHeaders().get(HttpHeaders.REQUEST_METHOD);
String requestMethod = (requestMethodHeader != null) ?
requestMethodHeader.toString().toUpperCase() : "POST";
if (this.extractPayload) {
Object payload = message.getPayload();
Assert.notNull(payload, "payload must not be null");
return this.createRequestFromPayload(payload, url, requestMethod);
}
return this.createRequestFromMessage(message, url, requestMethod);
return (this.extractPayload) ? this.createHttpEntityWithPayloadAsBody(message)
: this.createHttpEntityWithMessageAsBody(message);
}
@SuppressWarnings("unchecked")
private HttpRequest createRequestFromPayload(Object payload, URL url, String requestMethod) throws Exception {
ByteArrayOutputStream requestBody = new ByteArrayOutputStream();
String contentType = null;
if ("POST".equals(requestMethod) || "PUT".equals(requestMethod)) {
contentType = this.writeToRequestBody(payload, requestBody);
private HttpEntity<?> createHttpEntityWithPayloadAsBody(Message<?> requestMessage) {
if (requestMessage.getPayload() instanceof HttpEntity<?>) {
return (HttpEntity<?>) requestMessage.getPayload();
}
else {
Assert.isTrue(payload instanceof Map,
"Message payload must be a Map for a '" + requestMethod + "' request.");
Map<String, String[]> parameterMap = this.createParameterMap((Map<?,?>) payload);
Assert.notNull(parameterMap, "Payload must be a Map with String typed keys and " +
"String or String array typed values for a '" + requestMethod + "' request.");
url = this.addQueryParametersToUrl(url, parameterMap);
}
return new DefaultHttpRequest(url, requestMethod, requestBody, contentType);
}
private HttpRequest createRequestFromMessage(Message<?> message, URL url, String requestMethod) throws Exception {
Assert.isTrue("POST".equals(requestMethod) || "PUT".equals(requestMethod),
"POST or PUT request method is required when the 'extractPayload' value is false.");
ByteArrayOutputStream requestBody = new ByteArrayOutputStream();
String contentType = this.writeToRequestBody(message, requestBody);
return new DefaultHttpRequest(url, requestMethod, requestBody, contentType);
}
/**
* Creates a parameter map with String keys and String array values from
* the provided map if possible. If the provided map contains any keys that
* are not String typed, or any values that are not String or String array
* typed, then this method will return <code>null</code>.
*/
private Map<String, String[]> createParameterMap(Map<?,?> map) {
Map<String, String[]> parameterMap = new HashMap<String, String[]>();
for (Object key : map.keySet()) {
if (!(key instanceof String)) {
return null;
}
String[] stringArrayValue = null;
Object value = map.get(key);
// TODO: provide more fine-grained control over header mapping
HttpHeaders httpHeaders = new HttpHeaders();
for (String headerName : requestMessage.getHeaders().keySet()) {
Object value = requestMessage.getHeaders().get(headerName);
if (value instanceof String) {
stringArrayValue = new String[] { (String) value };
httpHeaders.add(headerName, (String) value);
}
else if (value instanceof String[]) {
stringArrayValue = (String[]) value;
}
Object payload = requestMessage.getPayload();
MediaType contentType = (payload instanceof String) ? this.contentTypeResolver.resolveContentType((String) payload, this.charset)
: this.contentTypeResolver.resolveContentType(payload);
httpHeaders.setContentType(contentType);
return new HttpEntity(requestMessage.getPayload(), httpHeaders);
}
private HttpEntity<Object> createHttpEntityWithMessageAsBody(Message<?> requestMessage) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("application", "x-java-serialized-object"));
return new HttpEntity<Object>(requestMessage, headers);
}
private static class DefaultContentTypeResolver implements ContentTypeResolver {
@SuppressWarnings("unchecked")
public MediaType resolveContentType(Object content) {
MediaType contentType = null;
if (content instanceof byte[]) {
contentType = MediaType.APPLICATION_OCTET_STREAM;
}
else if (content instanceof Source) {
contentType = MediaType.TEXT_XML;
}
else {
return null;
}
parameterMap.put((String) key, stringArrayValue);
}
return parameterMap;
}
@SuppressWarnings("unchecked")
private String writeToRequestBody(Object object, ByteArrayOutputStream byteStream) throws Exception {
String contentType = null;
if (object instanceof byte[]) {
byteStream.write((byte[]) object);
contentType = "application/octet-stream";
}
else if (object instanceof String) {
byteStream.write(((String) object).getBytes(this.charset));
contentType = "text/plain; charset=" + this.charset;
}
else {
if (object instanceof Map && isFormData((Map) object)) {
byte[] data = this.formDataAsBytes((Map) object);
if (data != null) {
byteStream.write(data);
contentType = "application/x-www-form-urlencoded";
if (content instanceof Map && isFormData((Map) content)) {
contentType = MediaType.APPLICATION_FORM_URLENCODED;
}
if (contentType == null && content instanceof Serializable) {
contentType = new MediaType("application", "x-java-serialized-object");
}
}
if (contentType == null && object instanceof Serializable) {
byteStream.write(this.serializeObject((Serializable) object));
contentType = "application/x-java-serialized-object";
if (contentType == null) {
throw new IllegalArgumentException("payload must be a byte array, " +
"String, Map, Source, or Serializable object, received: " + content.getClass());
}
return contentType;
}
if (contentType == null) {
throw new IllegalArgumentException("payload must be a byte array, " +
"String, Map, or Serializable object for a 'POST' or 'PUT' request");
}
return contentType;
}
/**
* If all keys are Strings, we'll consider the Map to be form data.
*/
@SuppressWarnings("unchecked")
private boolean isFormData(Map map) {
for (Object key : map.keySet()) {
if (!(key instanceof String)) {
return false;
}
public MediaType resolveContentType(String content, String charset) {
return new MediaType("text", "plain", Charset.forName(charset));
}
return true;
}
@SuppressWarnings("unchecked")
private byte[] formDataAsBytes(Map form) throws UnsupportedEncodingException {
StringBuilder builder = new StringBuilder();
Iterator<?> nameIterator = form.keySet().iterator();
while (nameIterator.hasNext()) {
Object next = nameIterator.next();
Assert.isTrue(next instanceof String, "Form map keys must be Strings.");
String name = (String) next;
Object value = form.get(name);
if (value == null) {
builder.append(URLEncoder.encode(name, this.charset));
}
else {
List<String> values = null;
if (value instanceof String) {
values = Collections.singletonList((String) value);
}
else if (value instanceof String[]) {
values = Arrays.asList((String[]) value);
}
else {
if (!(value instanceof Iterable)) {
return null;
}
Iterator iterator = ((Iterable) value).iterator();
values = new ArrayList<String>();
while (iterator.hasNext()) {
Object nextValue = iterator.next();
if (!(nextValue instanceof String)) {
return null;
}
values.add((String) nextValue);
}
}
Iterator<String> valueIterator = values.iterator();
builder.append(URLEncoder.encode(name, this.charset));
while (valueIterator.hasNext()) {
builder.append('=' + URLEncoder.encode(valueIterator.next(), this.charset));
if (valueIterator.hasNext()) {
builder.append('&' + URLEncoder.encode(name, this.charset));
}
/**
* If all keys are Strings, we'll consider the Map to be form data.
*/
private boolean isFormData(Map<?, ?> map) {
for (Object key : map.keySet()) {
if (!(key instanceof String)) {
return false;
}
}
if (nameIterator.hasNext()) {
builder.append('&');
}
return true;
}
return builder.toString().getBytes(this.charset);
}
private byte[] serializeObject(Serializable object) throws IOException {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ObjectOutputStream objectStream = new ObjectOutputStream(byteStream);
objectStream.writeObject(object);
objectStream.flush();
objectStream.close();
return byteStream.toByteArray();
}
/**
* Resolve the request URL for the given Message. This implementation
* returns the value associated with the {@link HttpHeaders#REQUEST_URL}
* key if available in the Message's headers. Otherwise, it falls back to
* the default URL as provided to the constructor of this mapper instance.
* @throws MalformedURLException if an error occurs while constructing the URL
*/
private URL resolveUrl(Message<?> message) throws MalformedURLException {
Object urlHeader = message.getHeaders().get(HttpHeaders.REQUEST_URL);
if (urlHeader == null) {
return this.defaultUrl;
}
if (urlHeader instanceof URL) {
return (URL) urlHeader;
}
if (urlHeader instanceof URI) {
return ((URI) urlHeader).toURL();
}
if (urlHeader instanceof String) {
return new URL((String) urlHeader);
}
throw new IllegalArgumentException("Target URL in Message header must be a URL, URI, or String.");
}
/**
* Constructs a query string by appending the parameter map values to the URL.
* @throws Exception if an error occurs encoding or constructing the URL
*/
private URL addQueryParametersToUrl(URL url, Map<String, String[]> parameterMap) throws Exception {
if (parameterMap == null || parameterMap.size() == 0) {
return url;
}
String urlString = url.toExternalForm();
String fragment = "";
int fragmentStartIndex = urlString.indexOf('#');
if (fragmentStartIndex != -1) {
fragment = urlString.substring(fragmentStartIndex);
urlString = urlString.substring(0, fragmentStartIndex);
}
StringBuilder sb = new StringBuilder(urlString);
if (urlString.indexOf('?') == -1) {
sb.append('?');
}
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
String[] values = entry.getValue();
for (String value : values) {
char lastChar = sb.charAt(sb.length() -1);
if (lastChar != '?' && lastChar != '&') {
sb.append('&');
}
sb.append(URLEncoder.encode(entry.getKey(), this.charset) + "=");
sb.append(URLEncoder.encode(value, this.charset));
}
}
sb.append(fragment);
return new URL(sb.toString());
}
/**
* Default implementation of {@link HttpRequest}.
*/
class DefaultHttpRequest implements HttpRequest {
private final URL targetUrl;
private final String requestMethod;
private final String contentType;
private volatile ByteArrayOutputStream requestBody;
DefaultHttpRequest(
URL targetUrl, String requestMethod, ByteArrayOutputStream requestBody, String contentType)
throws IOException {
Assert.notNull(targetUrl, "target url must not be null");
this.targetUrl = targetUrl;
this.requestMethod = (requestMethod != null) ? requestMethod : "POST";
this.requestBody = requestBody;
this.contentType = contentType;
}
public URL getTargetUrl() {
return this.targetUrl;
}
public String getRequestMethod() {
return this.requestMethod;
}
public String getContentType() {
return this.contentType;
}
public Integer getContentLength() {
return (this.requestBody != null) ? this.requestBody.size() : null;
}
public ByteArrayOutputStream getBody() {
return this.requestBody;
}
}
}

View File

@@ -1,149 +0,0 @@
/*
* 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.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectStreamException;
import java.net.URL;
import org.springframework.integration.core.Message;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.message.MessageHandlingException;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
/**
* An outbound endpoint that maps a request Message to an {@link HttpRequest},
* executes that request, and then maps the response to a reply Message.
*
* @author Mark Fisher
* @since 1.0.2
*/
public class HttpOutboundEndpoint extends AbstractReplyProducingMessageHandler {
private volatile OutboundRequestMapper requestMapper;
private volatile HttpRequestExecutor requestExecutor = new SimpleHttpRequestExecutor();
/**
* Create an HttpOutboundEndpoint with no default URL.
*/
public HttpOutboundEndpoint() {
this.requestMapper = new DefaultOutboundRequestMapper();
}
/**
* Create an HttpOutboundEndpoint that will send requests to the provided
* URL by default. If a Message contains a valid value for the
* {@link HttpHeaders#REQUEST_URL} header, that will take precedence.
* If a custom {@link OutboundRequestMapper} instance is registered
* through the {@link #setRequestMapper(OutboundRequestMapper)} method,
* this default URL will not be used.
*/
public HttpOutboundEndpoint(URL defaultUrl) {
this.requestMapper = new DefaultOutboundRequestMapper(defaultUrl);
}
/**
* Specify an {@link OutboundRequestMapper} implementation to map from
* Messages to outbound {@link HttpRequest} objects. The default
* implementation is {@link DefaultOutboundRequestMapper}.
*/
public void setRequestMapper(OutboundRequestMapper requestMapper) {
Assert.notNull(requestMapper, "requestMapper must not be null");
this.requestMapper = requestMapper;
}
/**
* Specify the {@link HttpRequestExecutor} to use for executing the
* {@link HttpRequest} instances at runtime. The default implementation
* is {@link SimpleHttpRequestExecutor}.
*/
public void setRequestExecutor(HttpRequestExecutor requestExecutor) {
Assert.notNull(requestExecutor, "requestExecutor must not be null");
this.requestExecutor = requestExecutor;
}
@Override
protected Object handleRequestMessage(Message<?> requestMessage) {
try {
HttpRequest request = this.requestMapper.fromMessage(requestMessage);
HttpResponse response = this.requestExecutor.executeRequest(request);
Object reply = this.createReplyFromResponse(response);
return reply;
}
catch (Exception e) {
throw new MessageHandlingException(requestMessage, "failed to execute HTTP request", e);
}
}
private Object createReplyFromResponse(HttpResponse response) throws Exception {
InputStream responseBody = response.getBody();
Assert.notNull(responseBody, "received null response body");
String contentType = response.getFirstHeader("Content-Type");
if (contentType != null && contentType.startsWith("application/x-java-serialized-object")) {
// may be either a payload or a serialized Message instance
return this.deserializePayload(responseBody);
}
ByteArrayOutputStream responseByteStream = new ByteArrayOutputStream();
FileCopyUtils.copy(responseBody, responseByteStream);
if (contentType != null && contentType.startsWith("text")) {
String charsetName = this.getCharsetName(response);
if (charsetName == null) {
charsetName = "ISO-8859-1";
}
return responseByteStream.toString(charsetName);
}
return responseByteStream.toByteArray();
}
private String getCharsetName(HttpResponse httpResponse) {
String contentType = httpResponse.getFirstHeader("Content-Type");
if (contentType != null) {
int beginIndex = contentType.indexOf("charset=");
if (beginIndex != -1) {
return contentType.substring(beginIndex + "charset=".length()).trim();
}
}
return null;
}
private Object deserializePayload(InputStream responseBody) throws IOException, ClassNotFoundException {
ObjectInputStream objectStream = null;
try {
objectStream = new ObjectInputStream(responseBody);
return objectStream.readObject();
}
catch (ObjectStreamException e) {
throw new IllegalArgumentException("failed to deserialize response", e);
}
finally {
try {
objectStream.close();
}
catch (Exception e) {
// ignore
}
}
}
}

View File

@@ -0,0 +1,235 @@
/*
* Copyright 2002-2010 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.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessagingException;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.message.MessageHandler;
import org.springframework.integration.message.MessageHandlingException;
import org.springframework.util.Assert;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
/**
* A {@link MessageHandler} implementation that executes HTTP requests by delegating
* to a {@link RestTemplate} instance.
*
* @author Mark Fisher
* @since 2.0
*/
public class HttpRequestExecutingMessageHandler extends AbstractReplyProducingMessageHandler {
private final String defaultUri;
private volatile HttpMethod defaultHttpMethod = HttpMethod.POST;
private volatile OutboundRequestMapper requestMapper = new DefaultOutboundRequestMapper();
private volatile Class<?> expectedResponseType = Object.class;
private final RestTemplate restTemplate = new RestTemplate();
/**
* Create an adapter that has no default URI. Any Message sent to this handler will be
* required to contain a valid value for the {@link HttpHeaders#REQUEST_URL} header.
*/
public HttpRequestExecutingMessageHandler() {
this((String) null);
}
/**
* Create an HttpOutboundEndpoint that will send requests to the provided
* URI by default. If a Message contains a valid value for the
* {@link HttpHeaders#REQUEST_URL} header, that will take precedence.
*/
public HttpRequestExecutingMessageHandler(URI defaultUri) {
this(defaultUri.toString());
}
/**
* Create an HttpOutboundEndpoint that will send requests to the provided
* URI by default. If a Message contains a valid value for the
* {@link HttpHeaders#REQUEST_URL} header, that will take precedence.
*/
public HttpRequestExecutingMessageHandler(String defaultUri) {
this.restTemplate.getMessageConverters().add(0, new SerializingHttpMessageConverter());
this.defaultUri = defaultUri;
}
/**
* Specify the default {@link HttpMethod}. This will provide a fallback in the case
* that a Message does not contain the HTTP method as a header. If this is not
* explicitly specified, then the default method will be POST.
*/
public void setDefaultHttpMethod(HttpMethod defaultHttpMethod) {
this.defaultHttpMethod = defaultHttpMethod;
}
/**
* Specify the expected response type for the REST request.
*/
public void setExpectedResponseType(Class<?> expectedResponseType) {
this.expectedResponseType = (expectedResponseType != null) ? expectedResponseType : byte[].class;
}
/**
* Set the {@link ResponseErrorHandler} for the underlying {@link RestTemplate}.
* @see RestTemplate#setErrorHandler(ResponseErrorHandler)
*/
public void setErrorHandler(ResponseErrorHandler errorHandler) {
this.restTemplate.setErrorHandler(errorHandler);
}
/**
* Set a list of {@link HttpMessageConverter}s to be used by the underlying {@link RestTemplate}.
* Converters configured via this method will override the default converters.
* @see RestTemplate#setMessageConverters(java.util.List)
*/
public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
this.restTemplate.setMessageConverters(messageConverters);
}
/**
* Set the {@link ClientHttpRequestFactory} for the underlying {@link RestTemplate}.
* @see RestTemplate#setRequestFactory(ClientHttpRequestFactory)
*/
public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
this.restTemplate.setRequestFactory(requestFactory);
}
/**
* Specify the {@link OutboundRequestMapper} implementation to use for mapping a
* {@link Message} into an {@link HttpEntity} when executing an HTTP request.
* <p>
* If not provided explicitly, the default implementation is {@link DefaultOutboundRequestMapper}.
*/
public void setRequestMapper(OutboundRequestMapper requestMapper) {
Assert.notNull(requestMapper, "requestMapper must not be null");
this.requestMapper = requestMapper;
}
@Override
protected Object handleRequestMessage(Message<?> requestMessage) {
String uri = null;
try {
uri = this.resolveUri(requestMessage);
HttpMethod httpMethod = this.resolveHttpMethod(requestMessage);
// TODO: allow a boolean flag for treating Map as queryParams vs. uriVariables?
Map<String, ?> uriVariables = this.determineUriVariables(requestMessage);
HttpEntity<?> httpRequest = this.requestMapper.fromMessage(requestMessage);
if (!isWritableRequestMethod(httpMethod) && httpRequest.getBody() != null) {
httpRequest = new HttpEntity<Object>(null, httpRequest.getHeaders());
}
HttpEntity<?> httpResponse = this.restTemplate.exchange(uri, httpMethod, httpRequest, this.expectedResponseType, uriVariables);
Object responseBody = httpResponse.getBody();
MessageBuilder<?> replyBuilder = (responseBody instanceof Message<?>) ?
MessageBuilder.fromMessage((Message<?>) responseBody) : MessageBuilder.withPayload(responseBody);
return replyBuilder.copyHeaders(httpResponse.getHeaders().toSingleValueMap()).build();
}
catch (MessagingException e) {
throw e;
}
catch (Exception e) {
throw new MessageHandlingException(requestMessage, "HTTP request execution failed for URI [" + uri + "]", e);
}
}
private boolean isWritableRequestMethod(HttpMethod httpMethod) {
switch (httpMethod) {
case POST: case PUT: return true;
default: return false;
}
}
/**
* Resolve the request URL for the given Message. This implementation
* returns the value associated with the {@link HttpHeaders#REQUEST_URL}
* key if available in the Message's headers. Otherwise, it falls back to
* the default URI as provided to the constructor of this handler instance.
* @throws MalformedURLException if an error occurs while constructing the URL
*/
private String resolveUri(Message<?> message) throws MalformedURLException {
Object urlHeader = message.getHeaders().get(HttpHeaders.REQUEST_URL);
if (urlHeader == null) {
Assert.notNull(this.defaultUri,
"No request URL header available in request Message, and no default has been provided.");
return this.defaultUri;
}
if (urlHeader instanceof URL) {
return ((URL) urlHeader).toString();
}
if (urlHeader instanceof URI) {
return ((URI) urlHeader).toString();
}
if (urlHeader instanceof String) {
return (String) urlHeader;
}
throw new IllegalArgumentException("Target URL in Message header must be a URL, URI, or String.");
}
private HttpMethod resolveHttpMethod(Message<?> requestMessage) {
HttpMethod httpMethod = null;
Object methodFromMessage = requestMessage.getHeaders().get(HttpHeaders.REQUEST_METHOD);
if (methodFromMessage instanceof HttpMethod) {
httpMethod = (HttpMethod) methodFromMessage;
}
else if (methodFromMessage instanceof String) {
httpMethod = HttpMethod.valueOf((String) methodFromMessage);
}
else if (methodFromMessage != null) {
throw new IllegalArgumentException("expected an HttpMethod enum instance or String for " +
"the REQUEST_METHOD header, but received type: " + methodFromMessage.getClass());
}
if (httpMethod == null) {
httpMethod = this.defaultHttpMethod;
}
return httpMethod;
}
private Map<String, ?> determineUriVariables(Message<?> requestMessage) {
Map<String, Object> uriVariables = new HashMap<String, Object>();
if (requestMessage.getPayload() instanceof Map<?,?>) {
Map<?,?> payloadMap = (Map<?,?>) requestMessage.getPayload();
for (Object key : payloadMap.keySet()) {
if (key instanceof String) {
System.out.println("adding value for key: " + key);
uriVariables.put((String) key, payloadMap.get(key).toString());
}
else if (logger.isDebugEnabled()) {
logger.debug("ignoring Map value for non-String key: " + key);
}
}
}
return uriVariables;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 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.
@@ -16,14 +16,15 @@
package org.springframework.integration.http;
import org.springframework.http.HttpEntity;
import org.springframework.integration.message.OutboundMessageMapper;
/**
* Strategy for mapping to an {@link HttpRequest} from a message.
* Strategy for mapping to an {@link HttpEntity} from a message.
*
* @author Mark Fisher
* @since 1.0.2
*/
public interface OutboundRequestMapper extends OutboundMessageMapper<HttpRequest> {
public interface OutboundRequestMapper extends OutboundMessageMapper<HttpEntity<?>> {
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 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.
@@ -19,7 +19,6 @@ package org.springframework.integration.http.config;
import org.w3c.dom.Element;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractConsumerEndpointParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
@@ -42,44 +41,39 @@ public class HttpOutboundGatewayParser extends AbstractConsumerEndpointParser {
@Override
protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
PACKAGE_PATH + ".HttpRequestExecutingMessageHandler");
String defaultUrl = element.getAttribute("default-url");
if (StringUtils.hasText(defaultUrl)) {
builder.addConstructorArgValue(defaultUrl);
}
String charset = element.getAttribute("charset");
String extractPayload = element.getAttribute("extract-request-payload");
String requestMapperRef = element.getAttribute("request-mapper");
if (StringUtils.hasText(requestMapperRef)) {
if (StringUtils.hasText(defaultUrl)) {
this.requestMapperConflictError("default-url", parserContext, element);
return null;
}
else if (StringUtils.hasText(charset)) {
if (StringUtils.hasText(charset)) {
this.requestMapperConflictError("charset", parserContext, element);
return null;
}
else if (StringUtils.hasText(extractPayload)) {
if (StringUtils.hasText(extractPayload)) {
this.requestMapperConflictError("extract-request-payload", parserContext, element);
return null;
}
builder.addPropertyReference("requestMapper", requestMapperRef);
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
PACKAGE_PATH + ".HttpOutboundEndpoint");
if (!StringUtils.hasText(requestMapperRef)) {
else {
BeanDefinitionBuilder mapperBuilder = BeanDefinitionBuilder.genericBeanDefinition(
PACKAGE_PATH + ".DefaultOutboundRequestMapper");
if (StringUtils.hasText(defaultUrl)) {
mapperBuilder.addConstructorArgValue(defaultUrl);
}
if (StringUtils.hasText(charset)) {
mapperBuilder.addPropertyValue("charset", charset);
}
if (StringUtils.hasText(extractPayload)) {
mapperBuilder.addPropertyValue("extractPayload", extractPayload);
}
requestMapperRef = BeanDefinitionReaderUtils.registerWithGeneratedName(
mapperBuilder.getBeanDefinition(), parserContext.getRegistry());
builder.addPropertyValue("requestMapper", mapperBuilder.getBeanDefinition());
}
builder.addPropertyReference("requestMapper", requestMapperRef);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "request-timeout", "sendTimeout");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "request-executor");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "request-factory");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel", "outputChannel");
return builder;
}

View File

@@ -105,7 +105,13 @@
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="gatewayType">
<xsd:attribute name="default-url" type="xsd:string"/>
<xsd:attribute name="default-url" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
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="extract-request-payload" type="xsd:string"/>
<xsd:attribute name="charset" type="xsd:string"/>
<xsd:attribute name="request-mapper" type="xsd:string">
@@ -117,11 +123,11 @@
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="request-executor" 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.integration.http.HttpRequestExecutor"/>
<tool:expected-type type="org.springframework.http.client.ClientHttpRequestFactory"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
@@ -129,8 +135,7 @@
<xsd:attribute name="order" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Specifies the order for invocation when this gateway is connected as a
subscriber to a SubscribableChannel.
Specifies the order for invocation when this gateway is connected as a subscriber to a SubscribableChannel.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>

View File

@@ -17,11 +17,10 @@
package org.springframework.integration.http;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -30,6 +29,8 @@ import java.util.Map;
import org.junit.Test;
import org.springframework.http.HttpEntity;
import org.springframework.http.MediaType;
import org.springframework.integration.core.Message;
import org.springframework.integration.message.MessageBuilder;
@@ -40,38 +41,61 @@ public class DefaultOutboundRequestMapperTests {
@Test
public void simpleStringValueFormData() throws Exception {
DefaultOutboundRequestMapper mapper = new DefaultOutboundRequestMapper(new URL("http://example.org"));
DefaultOutboundRequestMapper mapper = new DefaultOutboundRequestMapper();
Map<String, String> form = new LinkedHashMap<String, String>();
form.put("a", "1");
form.put("b", "2");
form.put("c", "3");
Message<?> message = MessageBuilder.withPayload(form).build();
HttpRequest request = mapper.fromMessage(message);
String bodyText = request.getBody().toString("UTF-8");
assertEquals("a=1&b=2&c=3", bodyText);
assertEquals("application/x-www-form-urlencoded", request.getContentType());
HttpEntity<?> request = mapper.fromMessage(message);
Object body = request.getBody();
assertTrue(body instanceof Map<?, ?>);
Map<?, ?> map = (Map <?, ?>) body;
assertEquals("1", map.get("a"));
assertEquals("2", map.get("b"));
assertEquals("3", map.get("c"));
assertEquals(MediaType.APPLICATION_FORM_URLENCODED, request.getHeaders().getContentType());
}
@Test
@SuppressWarnings("unchecked")
public void stringArrayValueFormData() throws Exception {
DefaultOutboundRequestMapper mapper = new DefaultOutboundRequestMapper(new URL("http://example.org"));
DefaultOutboundRequestMapper mapper = new DefaultOutboundRequestMapper();
Map form = new LinkedHashMap();
form.put("a", new String[] { "1", "2", "3" });
form.put("b", "4");
form.put("c", new String[] { "5" });
form.put("d", "6");
Message<?> message = MessageBuilder.withPayload(form).build();
HttpRequest request = mapper.fromMessage(message);
String bodyText = request.getBody().toString("UTF-8");
assertEquals("a=1&a=2&a=3&b=4&c=5&d=6", bodyText);
assertEquals("application/x-www-form-urlencoded", request.getContentType());
HttpEntity<?> request = mapper.fromMessage(message);
Object body = request.getBody();
assertTrue(body instanceof Map<?, ?>);
Map<?, ?> map = (Map <?, ?>) body;
Object entryA = map.get("a");
assertEquals(String[].class, entryA.getClass());
String[] resultA = (String[]) entryA;
assertEquals(3, resultA.length);
assertEquals("1", resultA[0]);
assertEquals("2", resultA[1]);
assertEquals("3", resultA[2]);
Object entryB = map.get("b");
assertEquals(String.class, entryB.getClass());
assertEquals("4", entryB);
Object entryC = map.get("c");
assertEquals(String[].class, entryC.getClass());
String[] resultC = (String[]) entryC;
assertEquals(1, resultC.length);
assertEquals("5", resultC[0]);
Object entryD = map.get("d");
assertEquals(String.class, entryD.getClass());
assertEquals("6", entryD);
assertEquals(MediaType.APPLICATION_FORM_URLENCODED, request.getHeaders().getContentType());
}
@Test
@SuppressWarnings("unchecked")
public void stringListValueFormData() throws Exception {
DefaultOutboundRequestMapper mapper = new DefaultOutboundRequestMapper(new URL("http://example.org"));
public void listValueFormData() throws Exception {
DefaultOutboundRequestMapper mapper = new DefaultOutboundRequestMapper();
Map form = new LinkedHashMap();
List<String> listA = new ArrayList<String>();
listA.add("1");
@@ -80,58 +104,62 @@ public class DefaultOutboundRequestMapperTests {
form.put("b", Collections.EMPTY_LIST);
form.put("c", Collections.singletonList("3"));
Message<?> message = MessageBuilder.withPayload(form).build();
HttpRequest request = mapper.fromMessage(message);
String bodyText = request.getBody().toString("UTF-8");
assertEquals("a=1&a=2&b&c=3", bodyText);
assertEquals("application/x-www-form-urlencoded", request.getContentType());
HttpEntity<?> request = mapper.fromMessage(message);
Object body = request.getBody();
assertTrue(body instanceof Map<?, ?>);
Map<?, ?> map = (Map <?, ?>) body;
Object entryA = map.get("a");
assertTrue(entryA instanceof List<?>);
List<?> resultA = (List<?>) entryA;
assertEquals(2, resultA.size());
assertEquals("1", resultA.get(0));
assertEquals("2", resultA.get(1));
Object entryB = map.get("b");
assertTrue(entryB instanceof List<?>);
List<?> resultB = (List<?>) entryB;
assertEquals(0, resultB.size());
Object entryC = map.get("c");
assertTrue(entryC instanceof List<?>);
List<?> resultC = (List<?>) entryC;
assertEquals(1, resultC.size());
assertEquals("3", resultC.get(0));
assertEquals(MediaType.APPLICATION_FORM_URLENCODED, request.getHeaders().getContentType());
}
@Test
@SuppressWarnings("unchecked")
public void nameOnlyWithNullValues() throws Exception {
DefaultOutboundRequestMapper mapper = new DefaultOutboundRequestMapper(new URL("http://example.org"));
DefaultOutboundRequestMapper mapper = new DefaultOutboundRequestMapper();
Map form = new LinkedHashMap();
form.put("a", null);
form.put("b", "foo");
form.put("c", null);
Message<?> message = MessageBuilder.withPayload(form).build();
HttpRequest request = mapper.fromMessage(message);
String bodyText = request.getBody().toString("UTF-8");
assertEquals("a&b=foo&c", bodyText);
assertEquals("application/x-www-form-urlencoded", request.getContentType());
HttpEntity<?> request = mapper.fromMessage(message);
Object body = request.getBody();
assertTrue(body instanceof Map<?, ?>);
Map<?, ?> map = (Map<?, ?>) body;
assertTrue(map.containsKey("a"));
assertNull(map.get("a"));
Object entryB = map.get("b");
assertEquals("foo", entryB);
assertTrue(map.containsKey("c"));
assertNull(map.get("c"));
assertEquals(MediaType.APPLICATION_FORM_URLENCODED, request.getHeaders().getContentType());
}
@Test
public void encodedFormData() throws Exception {
DefaultOutboundRequestMapper mapper = new DefaultOutboundRequestMapper(new URL("http://example.org"));
Map<String, String> form = new LinkedHashMap<String, String>();
form.put("a", "1 + 2 + 3");
form.put("b", "4+5");
form.put("c", "97%");
Message<?> message = MessageBuilder.withPayload(form).build();
HttpRequest request = mapper.fromMessage(message);
String bodyText = request.getBody().toString("UTF-8");
assertEquals("a=1+%2B+2+%2B+3&b=4%2B5&c=97%25", bodyText);
assertEquals("application/x-www-form-urlencoded", request.getContentType());
}
@Test
@SuppressWarnings("unchecked")
public void nonFormDataInMap() throws Exception {
DefaultOutboundRequestMapper mapper = new DefaultOutboundRequestMapper(new URL("http://example.org"));
DefaultOutboundRequestMapper mapper = new DefaultOutboundRequestMapper();
Map<String, TestBean> form = new LinkedHashMap<String, TestBean>();
form.put("A", new TestBean());
form.put("B", new TestBean());
Message<?> message = MessageBuilder.withPayload(form).build();
HttpRequest request = mapper.fromMessage(message);
byte[] body = request.getBody().toByteArray();
ByteArrayInputStream byteStream = new ByteArrayInputStream(body);
Object result = new ObjectInputStream(byteStream).readObject();
assertEquals(LinkedHashMap.class, result.getClass());
Map<String, TestBean> resultMap = (Map<String, TestBean>) result;
assertEquals(2, resultMap.size());
assertEquals(TestBean.class, resultMap.get("A").getClass());
assertEquals(TestBean.class, resultMap.get("B").getClass());
HttpEntity<?> request = mapper.fromMessage(message);
Map<?, ?> map = (Map<?, ?>) request.getBody();
assertEquals(2, map.size());
assertEquals(TestBean.class, map.get("A").getClass());
assertEquals(TestBean.class, map.get("B").getClass());
}

View File

@@ -8,7 +8,7 @@
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/http
http://www.springframework.org/schema/integration/http/spring-integration-http.xsd">
http://www.springframework.org/schema/integration/http/spring-integration-http.xsd">
<si:channel id="requests"/>
@@ -20,8 +20,9 @@
<outbound-gateway id="fullConfigWithMapper"
request-channel="requests"
request-mapper="mapper"
request-executor="executor"
default-url="http://localhost/test1"
request-mapper="testMapper"
request-factory="testRequestFactory"
request-timeout="1234"
reply-channel="replies"
order="77"
@@ -29,19 +30,18 @@
<outbound-gateway id="fullConfigWithoutMapper"
request-channel="requests"
default-url="http://localhost/test"
default-url="http://localhost/test2"
extract-request-payload="false"
charset="UTF-8"
request-executor="executor"
request-factory="testRequestFactory"
request-timeout="1234"
reply-channel="replies"/>
<beans:bean id="mapper" class="org.springframework.integration.http.DefaultOutboundRequestMapper">
<beans:property name="defaultUrl" value="http://localhost/test"/>
<beans:bean id="testMapper" class="org.springframework.integration.http.DefaultOutboundRequestMapper">
<beans:property name="charset" value="UTF-8"/>
<beans:property name="extractPayload" value="false"/>
</beans:bean>
<beans:bean id="executor" class="org.springframework.integration.http.SimpleHttpRequestExecutor"/>
<beans:bean id="testRequestFactory" class="org.springframework.http.client.SimpleClientHttpRequestFactory"/>
</beans:beans>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 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.
@@ -22,8 +22,6 @@ import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.net.URL;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -31,13 +29,13 @@ import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.http.DefaultOutboundRequestMapper;
import org.springframework.integration.http.HttpOutboundEndpoint;
import org.springframework.integration.http.HttpRequestExecutor;
import org.springframework.integration.http.HttpRequestExecutingMessageHandler;
import org.springframework.integration.http.OutboundRequestMapper;
import org.springframework.integration.http.SimpleHttpRequestExecutor;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -63,22 +61,24 @@ public class HttpOutboundGatewayParserTests {
@Test
public void minimalConfig() {
HttpOutboundEndpoint gateway = (HttpOutboundEndpoint) new DirectFieldAccessor(
HttpRequestExecutingMessageHandler handler = (HttpRequestExecutingMessageHandler) new DirectFieldAccessor(
this.minimalConfigEndpoint).getPropertyValue("handler");
MessageChannel requestChannel = (MessageChannel) new DirectFieldAccessor(
this.minimalConfigEndpoint).getPropertyValue("inputChannel");
assertEquals(this.applicationContext.getBean("requests"), requestChannel);
DirectFieldAccessor accessor = new DirectFieldAccessor(gateway);
Object replyChannel = accessor.getPropertyValue("outputChannel");
DirectFieldAccessor handlerAccessor = new DirectFieldAccessor(handler);
Object replyChannel = handlerAccessor.getPropertyValue("outputChannel");
assertNull(replyChannel);
OutboundRequestMapper mapper = (OutboundRequestMapper) accessor.getPropertyValue("requestMapper");
HttpRequestExecutor executor = (HttpRequestExecutor) accessor.getPropertyValue("requestExecutor");
OutboundRequestMapper mapper = (OutboundRequestMapper) handlerAccessor.getPropertyValue("requestMapper");
DirectFieldAccessor templateAccessor = new DirectFieldAccessor(handlerAccessor.getPropertyValue("restTemplate"));
ClientHttpRequestFactory requestFactory = (ClientHttpRequestFactory)
templateAccessor.getPropertyValue("requestFactory");
assertTrue(mapper instanceof DefaultOutboundRequestMapper);
assertTrue(executor instanceof SimpleHttpRequestExecutor);
Object mapperBean = this.applicationContext.getBean("mapper");
assertTrue(requestFactory instanceof SimpleClientHttpRequestFactory);
Object mapperBean = this.applicationContext.getBean("testMapper");
assertNotSame(mapperBean, mapper);
DirectFieldAccessor mapperAccessor = new DirectFieldAccessor(mapper);
assertNull(mapperAccessor.getPropertyValue("defaultUrl"));
assertNull(handlerAccessor.getPropertyValue("defaultUri"));
assertEquals("UTF-8", mapperAccessor.getPropertyValue("charset"));
assertEquals(true, mapperAccessor.getPropertyValue("extractPayload"));
}
@@ -86,59 +86,63 @@ public class HttpOutboundGatewayParserTests {
@Test
public void fullConfigWithMapper() throws Exception {
DirectFieldAccessor endpointAccessor = new DirectFieldAccessor(this.fullConfigWithMapperEndpoint);
HttpOutboundEndpoint gateway = (HttpOutboundEndpoint) endpointAccessor.getPropertyValue("handler");
HttpRequestExecutingMessageHandler handler = (HttpRequestExecutingMessageHandler) endpointAccessor.getPropertyValue("handler");
MessageChannel requestChannel = (MessageChannel) new DirectFieldAccessor(
this.fullConfigWithMapperEndpoint).getPropertyValue("inputChannel");
assertEquals(this.applicationContext.getBean("requests"), requestChannel);
DirectFieldAccessor accessor = new DirectFieldAccessor(gateway);
assertEquals(77, accessor.getPropertyValue("order"));
DirectFieldAccessor handlerAccessor = new DirectFieldAccessor(handler);
assertEquals(77, handlerAccessor.getPropertyValue("order"));
assertEquals(Boolean.FALSE, endpointAccessor.getPropertyValue("autoStartup"));
Object replyChannel = accessor.getPropertyValue("outputChannel");
Object replyChannel = handlerAccessor.getPropertyValue("outputChannel");
assertNotNull(replyChannel);
assertEquals(this.applicationContext.getBean("replies"), replyChannel);
OutboundRequestMapper mapper = (OutboundRequestMapper) accessor.getPropertyValue("requestMapper");
HttpRequestExecutor executor = (HttpRequestExecutor) accessor.getPropertyValue("requestExecutor");
OutboundRequestMapper mapper = (OutboundRequestMapper) handlerAccessor.getPropertyValue("requestMapper");
DirectFieldAccessor templateAccessor = new DirectFieldAccessor(handlerAccessor.getPropertyValue("restTemplate"));
ClientHttpRequestFactory requestFactory = (ClientHttpRequestFactory)
templateAccessor.getPropertyValue("requestFactory");
assertTrue(mapper instanceof DefaultOutboundRequestMapper);
assertTrue(executor instanceof SimpleHttpRequestExecutor);
Object mapperBean = this.applicationContext.getBean("mapper");
assertTrue(requestFactory instanceof SimpleClientHttpRequestFactory);
Object mapperBean = this.applicationContext.getBean("testMapper");
assertEquals(mapperBean, mapper);
DirectFieldAccessor mapperAccessor = new DirectFieldAccessor(mapper);
assertEquals(new URL("http://localhost/test"), mapperAccessor.getPropertyValue("defaultUrl"));
assertEquals("http://localhost/test1", handlerAccessor.getPropertyValue("defaultUri"));
assertEquals("UTF-8", mapperAccessor.getPropertyValue("charset"));
assertEquals(false, mapperAccessor.getPropertyValue("extractPayload"));
Object executorBean = this.applicationContext.getBean("executor");
assertEquals(executorBean, executor);
Object requestFactoryBean = this.applicationContext.getBean("testRequestFactory");
assertEquals(requestFactoryBean, requestFactory);
Object sendTimeout = new DirectFieldAccessor(
accessor.getPropertyValue("channelTemplate")).getPropertyValue("sendTimeout");
handlerAccessor.getPropertyValue("channelTemplate")).getPropertyValue("sendTimeout");
assertEquals(new Long("1234"), sendTimeout);
}
@Test
public void fullConfigWithoutMapper() throws Exception {
HttpOutboundEndpoint gateway = (HttpOutboundEndpoint) new DirectFieldAccessor(
HttpRequestExecutingMessageHandler handler = (HttpRequestExecutingMessageHandler) new DirectFieldAccessor(
this.fullConfigWithoutMapperEndpoint).getPropertyValue("handler");
MessageChannel requestChannel = (MessageChannel) new DirectFieldAccessor(
this.fullConfigWithoutMapperEndpoint).getPropertyValue("inputChannel");
assertEquals(this.applicationContext.getBean("requests"), requestChannel);
DirectFieldAccessor accessor = new DirectFieldAccessor(gateway);
Object replyChannel = accessor.getPropertyValue("outputChannel");
DirectFieldAccessor handlerAccessor = new DirectFieldAccessor(handler);
Object replyChannel = handlerAccessor.getPropertyValue("outputChannel");
assertNotNull(replyChannel);
assertEquals(this.applicationContext.getBean("replies"), replyChannel);
OutboundRequestMapper mapper = (OutboundRequestMapper) accessor.getPropertyValue("requestMapper");
HttpRequestExecutor executor = (HttpRequestExecutor) accessor.getPropertyValue("requestExecutor");
OutboundRequestMapper mapper = (OutboundRequestMapper) handlerAccessor.getPropertyValue("requestMapper");
DirectFieldAccessor templateAccessor = new DirectFieldAccessor(handlerAccessor.getPropertyValue("restTemplate"));
ClientHttpRequestFactory requestFactory = (ClientHttpRequestFactory)
templateAccessor.getPropertyValue("requestFactory");
assertTrue(mapper instanceof DefaultOutboundRequestMapper);
assertTrue(executor instanceof SimpleHttpRequestExecutor);
Object mapperBean = this.applicationContext.getBean("mapper");
assertTrue(requestFactory instanceof SimpleClientHttpRequestFactory);
Object mapperBean = this.applicationContext.getBean("testMapper");
assertNotSame(mapperBean, mapper);
DirectFieldAccessor mapperAccessor = new DirectFieldAccessor(mapper);
assertEquals(new URL("http://localhost/test"), mapperAccessor.getPropertyValue("defaultUrl"));
assertEquals("http://localhost/test2", handlerAccessor.getPropertyValue("defaultUri"));
assertEquals("UTF-8", mapperAccessor.getPropertyValue("charset"));
assertEquals(false, mapperAccessor.getPropertyValue("extractPayload"));
Object executorBean = this.applicationContext.getBean("executor");
assertEquals(executorBean, executor);
Object requestFactoryBean = this.applicationContext.getBean("testRequestFactory");
assertEquals(requestFactoryBean, requestFactory);
Object sendTimeout = new DirectFieldAccessor(
accessor.getPropertyValue("channelTemplate")).getPropertyValue("sendTimeout");
handlerAccessor.getPropertyValue("channelTemplate")).getPropertyValue("sendTimeout");
assertEquals(new Long("1234"), sendTimeout);
}
}
}