diff --git a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/AbstractHttpRequestExecutor.java b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/AbstractHttpRequestExecutor.java new file mode 100644 index 0000000000..bfeafbd758 --- /dev/null +++ b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/AbstractHttpRequestExecutor.java @@ -0,0 +1,94 @@ +/* + * 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.IOException; +import java.io.InputStream; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Base class for {@link HttpRequestExecutor} implementations. + * + * @author Mark Fisher + * @author Juergen Hoeller + * @since 1.0.2 + */ +public abstract class AbstractHttpRequestExecutor implements HttpRequestExecutor { + + protected static final String HTTP_HEADER_ACCEPT_LANGUAGE = "Accept-Language"; + + protected static final String HTTP_HEADER_ACCEPT_ENCODING = "Accept-Encoding"; + + protected static final String HTTP_HEADER_CONTENT_ENCODING = "Content-Encoding"; + + protected static final String HTTP_HEADER_CONTENT_TYPE = "Content-Type"; + + protected static final String HTTP_HEADER_CONTENT_LENGTH = "Content-Length"; + + protected static final String ENCODING_GZIP = "gzip"; + + + protected final Log logger = LogFactory.getLog(getClass()); + + private boolean acceptGzipEncoding = true; + + + /** + * Set whether to accept GZIP encoding, that is, whether to + * send the HTTP "Accept-Encoding" header with "gzip" as value. + *
Default is "true". Turn this flag off if you do not want + * GZIP response compression even if enabled on the HTTP server. + */ + public void setAcceptGzipEncoding(boolean acceptGzipEncoding) { + this.acceptGzipEncoding = acceptGzipEncoding; + } + + /** + * Return whether to accept GZIP encoding, that is, whether to + * send the HTTP "Accept-Encoding" header with "gzip" as its value. + */ + public boolean isAcceptGzipEncoding() { + return this.acceptGzipEncoding; + } + + /** + * Execute a request to send its content to its target URL. + * @param request the request to execute + * @return the InputStream result + * @throws IOException if thrown by I/O operations + * @throws Exception in case of general errors + */ + public final InputStream executeRequest(HttpRequest request) throws Exception { + if (logger.isDebugEnabled()) { + StringBuilder sb = new StringBuilder("Sending HTTP request to [" + request.getTargetUrl() + "]"); + Integer contentLength = request.getContentLength(); + if (contentLength != null) { + sb.append(", with size " + contentLength); + } + logger.debug(sb.toString()); + } + return doExecuteRequest(request); + } + + /** + * Subclasses must implement this method to execute the request. + */ + protected abstract InputStream doExecuteRequest(HttpRequest request) throws Exception; + +} diff --git a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/DataBindingRequestMapper.java b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/DataBindingInboundRequestMapper.java similarity index 78% rename from org.springframework.integration.http/src/main/java/org/springframework/integration/http/DataBindingRequestMapper.java rename to org.springframework.integration.http/src/main/java/org/springframework/integration/http/DataBindingInboundRequestMapper.java index a34535f598..585a1d2601 100644 --- a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/DataBindingRequestMapper.java +++ b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/DataBindingInboundRequestMapper.java @@ -32,18 +32,18 @@ import org.springframework.web.bind.support.WebBindingInitializer; import org.springframework.web.servlet.handler.DispatcherServletWebRequest; /** - * RequestMapper implementation that binds the request parameter map to a - * target instance. The target instance may be a non-singleton bean as + * InboundRequestMapper implementation that binds the request parameter map to + * a target instance. The target instance may be a non-singleton bean as * specified by the {@link #setTargetBeanName(String) 'targetBeanName'} - * property. Otherwise, this transformer's target type must provide a - * default no-arg constructor. + * property. Otherwise, this mapper's target type must provide a default, + * no-arg constructor. * * @author Mark Fisher * @since 1.0.2 */ -public class DataBindingRequestMapper implements RequestMapper, BeanFactoryAware, InitializingBean { +public class DataBindingInboundRequestMapper implements InboundRequestMapper, BeanFactoryAware, InitializingBean { - private final Class> targetType; + private volatile Class> targetType = Object.class; private volatile String targetBeanName; @@ -54,12 +54,20 @@ public class DataBindingRequestMapper implements RequestMapper, BeanFactoryAware private volatile boolean validated; - public DataBindingRequestMapper(Class> targetType) { + public DataBindingInboundRequestMapper() { + this.targetType = Object.class; + } + + public DataBindingInboundRequestMapper(Class> targetType) { Assert.notNull(targetType, "targetType must not be null"); this.targetType = targetType; } + public void setTargetType(Class> targetType) { + this.targetType = targetType; + } + /** * Specify the name of a bean definition to use when creating the target * instance. The bean must not be a singleton, and it must be @@ -89,6 +97,10 @@ public class DataBindingRequestMapper implements RequestMapper, BeanFactoryAware } public final void afterPropertiesSet() { + if (this.targetBeanName == null && Object.class.equals(this.targetType)) { + throw new IllegalArgumentException( + "When no 'targetBeanName' is provided, the 'targetType' must be more specific than Object."); + } this.validateTargetBeanIfNecessary(); } @@ -98,12 +110,16 @@ public class DataBindingRequestMapper implements RequestMapper, BeanFactoryAware if (this.beanFactory.isSingleton(this.targetBeanName)) { throw new IllegalArgumentException("binding target bean must not be a singleton"); } + Class> beanType = this.beanFactory.getType(this.targetBeanName); + if (beanType != null) { + Assert.isAssignable(this.targetType, beanType); + } this.validated = true; } } @SuppressWarnings("unchecked") - public Message> mapRequest(HttpServletRequest request) throws Exception { + public Message> toMessage(HttpServletRequest request) throws Exception { ServletRequestDataBinder binder = new ServletRequestDataBinder(getTarget()); this.initBinder(binder, request); binder.bind(request); diff --git a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/DefaultRequestMapper.java b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/DefaultInboundRequestMapper.java similarity index 93% rename from org.springframework.integration.http/src/main/java/org/springframework/integration/http/DefaultRequestMapper.java rename to org.springframework.integration.http/src/main/java/org/springframework/integration/http/DefaultInboundRequestMapper.java index 84af1a9697..cd09351e29 100644 --- a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/DefaultRequestMapper.java +++ b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/DefaultInboundRequestMapper.java @@ -17,7 +17,6 @@ package org.springframework.integration.http; import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.util.ArrayList; @@ -39,7 +38,7 @@ import org.springframework.integration.core.Message; import org.springframework.integration.message.MessageBuilder; /** - * Default implementation of {@link RequestMapper} for inbound HttpServletRequests. + * Default implementation of {@link InboundRequestMapper} for inbound HttpServletRequests. * The request will be mapped according to the following rules: *
false by default.
* This means that as soon as the Message is created and passed to the
@@ -87,7 +87,7 @@ public class HttpInboundEndpoint extends SimpleMessagingGateway implements HttpR
private volatile boolean expectReply;
- private volatile RequestMapper requestMapper = new DefaultRequestMapper();
+ private volatile InboundRequestMapper requestMapper = new DefaultInboundRequestMapper();
private volatile boolean extractReplyPayload = true;
@@ -120,11 +120,11 @@ public class HttpInboundEndpoint extends SimpleMessagingGateway implements HttpR
}
/**
- * Specify a {@link RequestMapper} implementation to map from the
+ * Specify a {@link InboundRequestMapper} implementation to map from the
* inbound HTTP request to a Message. The default implementation
- * is {@link DefaultRequestMapper}.
+ * is {@link DefaultInboundRequestMapper}.
*/
- public void setRequestMapper(RequestMapper requestMapper) {
+ public void setRequestMapper(InboundRequestMapper requestMapper) {
Assert.notNull(requestMapper, "requestMapper must not be null");
this.requestMapper = requestMapper;
}
@@ -178,7 +178,7 @@ public class HttpInboundEndpoint extends SimpleMessagingGateway implements HttpR
return;
}
try {
- Message> requestMessage = this.requestMapper.mapRequest(request);
+ Message> requestMessage = this.requestMapper.toMessage(request);
Object reply = this.handleRequestMessage(requestMessage);
this.generateResponse(requestMessage, reply, request, response);
}
diff --git a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/HttpOutboundEndpoint.java b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/HttpOutboundEndpoint.java
index c6b2932997..cb8d53b00a 100644
--- a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/HttpOutboundEndpoint.java
+++ b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/HttpOutboundEndpoint.java
@@ -17,112 +17,47 @@
package org.springframework.integration.http;
import java.io.ByteArrayOutputStream;
-import java.io.IOException;
import java.io.InputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.nio.charset.Charset;
+import java.net.URL;
import org.springframework.integration.core.Message;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.handler.ReplyMessageHolder;
import org.springframework.integration.message.MessageHandlingException;
-import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
/**
+ * An outbound endpoint for executing an HTTP request and mapping the response
+ * to a reply Message.
+ *
* @author Mark Fisher
- * @author Juergen Hoeller
- * @author Iwein Fuld
* @since 1.0.2
*/
public class HttpOutboundEndpoint extends AbstractReplyProducingMessageHandler {
- private volatile String charset = "UTF-8";
+ private final OutboundRequestMapper requestMapper;
- private volatile boolean acceptGzipEncoding = true;
+ private volatile HttpRequestExecutor requestExecutor;
- private volatile HttpExchanger exchanger;
- public HttpOutboundEndpoint(String url) {
- this.exchanger = new SimpleHttpExchanger(url);
+ public HttpOutboundEndpoint(URL url) {
+ this.requestMapper = new DefaultOutboundRequestMapper(url);
+ this.requestExecutor = new SimpleHttpRequestExecutor();
}
- /**
- * Specify the charset name to use for converting String-typed payloads to
- * bytes. The default is 'UTF-8'.
- */
- public void setCharset(String charset) {
- Assert.isTrue(Charset.isSupported(charset), "unsupported charset '"
- + charset + "'");
- this.charset = charset;
- }
-
- /**
- * Specify the content type to use for sending HTTP requests.
- * - * Default is "application/x-java-serialized-object". - */ - public void setContentType(String contentType) { - Assert.notNull(contentType, "'contentType' must not be null"); - this.exchanger.setContentType(contentType); - } - - /** - * Set whether to accept GZIP encoding, that is, whether to send the HTTP - * "Accept-Encoding" header with "gzip" as value. - *
- * Default is "true". Turn this flag off if you do not want GZIP response
- * compression even if enabled on the HTTP server.
- */
- public void setAcceptGzipEncoding(boolean acceptGzipEncoding) {
- this.acceptGzipEncoding = acceptGzipEncoding;
- }
-
- /**
- * Return whether to accept GZIP encoding, that is, whether to send the HTTP
- * "Accept-Encoding" header with "gzip" as value.
- */
- public boolean isAcceptGzipEncoding() {
- return this.acceptGzipEncoding;
- }
@Override
- protected void handleRequestMessage(Message> requestMessage,
- ReplyMessageHolder replyMessageHolder) {
- Object payload = requestMessage.getPayload();
- byte[] bytes = null;
+ protected void handleRequestMessage(Message> requestMessage, ReplyMessageHolder replyMessageHolder) {
try {
- if (payload instanceof byte[]) {
- bytes = (byte[]) payload;
- }
- else if (payload instanceof String) {
- bytes = ((String) payload).getBytes(this.charset);
- }
- else if (payload instanceof Serializable) {
- ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
- ObjectOutputStream objectStream = new ObjectOutputStream(
- byteStream);
- objectStream.writeObject(payload);
- objectStream.flush();
- objectStream.close();
- bytes = byteStream.toByteArray();
- }
- else {
- throw new IllegalArgumentException(
- "payload must be a byte array, String, or Serializable object");
- }
- ByteArrayOutputStream requestByteStream = new ByteArrayOutputStream();
- requestByteStream.write(bytes);
-
+ HttpRequest request = this.requestMapper.fromMessage(requestMessage);
+ InputStream responseBody = this.requestExecutor.executeRequest(request);
ByteArrayOutputStream responseByteStream = new ByteArrayOutputStream();
- InputStream responseBody = exchanger.exchange(requestByteStream);
FileCopyUtils.copy(responseBody, responseByteStream);
replyMessageHolder.set(responseByteStream.toByteArray());
}
- catch (IOException e) {
+ catch (Exception e) {
throw new MessageHandlingException(requestMessage,
- "failed to send HTTP request", e);
+ "failed to execute HTTP request", e);
}
}
diff --git a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/HttpRequest.java b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/HttpRequest.java
new file mode 100644
index 0000000000..70cfe68c74
--- /dev/null
+++ b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/HttpRequest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.net.URL;
+
+/**
+ * Representation of an HTTP request to be executed by an implementation of
+ * the {@link HttpRequestExecutor} strategy.
+ *
+ * @author Mark Fisher
+ * @since 1.0.2
+ */
+public interface HttpRequest {
+
+ /**
+ * Return the target URL for this request.
+ */
+ URL getTargetUrl();
+
+ /**
+ * Return the request method ("GET", "POST", etc).
+ */
+ String getRequestMethod();
+
+ /**
+ * Return the content type for requests.
+ */
+ String getContentType();
+
+ /**
+ * Return the content length if known, else
- * Default is "application/x-java-serialized-object".
- */
- public void setContentType(String contentType) {
- Assert.notNull(contentType, "'contentType' must not be null");
- this.contentType = contentType;
- }
-
- /**
- * Return the content type used for sending HTTP requests.
- */
- public String getContentType() {
- return contentType;
- }
-
- /**
- * Set whether to accept GZIP encoding, that is, whether to send the HTTP
- * "Accept-Encoding" header with "gzip" as value.
- *
- * Default is "true". Turn this flag off if you do not want GZIP response
- * compression even if enabled on the HTTP server.
- */
- public void setAcceptGzipEncoding(boolean acceptGzipEncoding) {
- this.acceptGzipEncoding = acceptGzipEncoding;
- }
-
- /**
- * Return whether to accept GZIP encoding, that is, whether to send the HTTP
- * "Accept-Encoding" header with "gzip" as value.
- */
- public boolean isAcceptGzipEncoding() {
- return this.acceptGzipEncoding;
- }
-
- public InputStream exchange(ByteArrayOutputStream requestBody) throws IOException {
- HttpURLConnection connection = this.openConnection();
- this.prepareConnection(connection, requestBody.size());
- this.writeRequestBody(connection, requestBody);
- this.validateResponse(connection);
- return this.readResponseBody(connection);
- }
-
- /**
- * Open an HttpURLConnection for this gateway's URL.
- * @return the HttpURLConnection for the given request
- * @throws IOException if thrown by I/O methods
- * @see java.net.URL#openConnection()
- */
- private HttpURLConnection openConnection() throws IOException {
- URLConnection con = this.url.openConnection();
- if (!(con instanceof HttpURLConnection)) {
- throw new IOException("Service URL [" + this.url
- + "] is not an HTTP URL");
- }
- return (HttpURLConnection) con;
- }
-
- /**
- * Prepare the given HTTP connection.
- *
- * This implementation specifies POST as method,
- * "application/x-java-serialized-object" as "Content-Type" header, and the
- * given content length as "Content-Length" header.
- * @param con the HTTP connection to prepare
- * @param contentLength the length of the content to send
- * @throws IOException if thrown by HttpURLConnection methods
- * @see java.net.HttpURLConnection#setRequestMethod
- * @see java.net.HttpURLConnection#setRequestProperty
- */
- private void prepareConnection(HttpURLConnection con, int contentLength)
- throws IOException {
- con.setDoOutput(true);
- con.setRequestMethod(HTTP_METHOD_POST);
- con.setRequestProperty(HTTP_HEADER_CONTENT_TYPE, getContentType());
- con.setRequestProperty(HTTP_HEADER_CONTENT_LENGTH, Integer
- .toString(contentLength));
- LocaleContext locale = LocaleContextHolder.getLocaleContext();
- if (locale != null) {
- con.setRequestProperty(HTTP_HEADER_ACCEPT_LANGUAGE, StringUtils
- .toLanguageTag(locale.getLocale()));
- }
- if (isAcceptGzipEncoding()) {
- con.setRequestProperty(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
- }
- }
-
- private void writeRequestBody(HttpURLConnection con,
- ByteArrayOutputStream baos) throws IOException {
- baos.writeTo(con.getOutputStream());
- }
-
- private void validateResponse(HttpURLConnection con) throws IOException {
- if (con.getResponseCode() >= 300) {
- throw new IOException(
- "Did not receive successful HTTP response: status code = "
- + con.getResponseCode() + ", status message = ["
- + con.getResponseMessage() + "]");
- }
- }
-
- /**
- * Extract the response body from the given executed remote invocation
- * request.
- *
- * This implementation simply reads the serialized invocation from the
- * HttpURLConnection's InputStream. If the response is recognized as GZIP
- * response, the InputStream will get wrapped in a GZIPInputStream.
- * @param config the HTTP invoker configuration that specifies the target
- * service
- * @param con the HttpURLConnection to read the response body from
- * @return an InputStream for the response body
- * @throws IOException if thrown by I/O methods
- * @see #isGzipResponse
- * @see java.util.zip.GZIPInputStream
- * @see java.net.HttpURLConnection#getInputStream()
- * @see java.net.HttpURLConnection#getHeaderField(int)
- * @see java.net.HttpURLConnection#getHeaderFieldKey(int)
- */
- private InputStream readResponseBody(HttpURLConnection con)
- throws IOException {
- if (isGzipResponse(con)) {
- // GZIP response found - need to unzip.
- return new GZIPInputStream(con.getInputStream());
- }
- else {
- // Plain response found.
- return con.getInputStream();
- }
- }
-
- /**
- * Determine whether the given response is a GZIP response.
- *
- * This implementation checks whether the HTTP "Content-Encoding" header
- * contains "gzip" (in any casing).
- * @param con the HttpURLConnection to check
- */
- private boolean isGzipResponse(HttpURLConnection con) {
- String encodingHeader = con
- .getHeaderField(HTTP_HEADER_CONTENT_ENCODING);
- return (encodingHeader != null && encodingHeader.toLowerCase().indexOf(
- ENCODING_GZIP) != -1);
- }
-
-}
diff --git a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/SimpleHttpRequestExecutor.java b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/SimpleHttpRequestExecutor.java
new file mode 100644
index 0000000000..0d5d6ce91d
--- /dev/null
+++ b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/SimpleHttpRequestExecutor.java
@@ -0,0 +1,148 @@
+/*
+ * 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.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.zip.GZIPInputStream;
+
+import org.springframework.context.i18n.LocaleContext;
+import org.springframework.context.i18n.LocaleContextHolder;
+import org.springframework.util.StringUtils;
+
+/**
+ * Implementation of {@link HttpRequestExecutor} that uses {@link HttpURLConnection}
+ * directly. This version has limited functionality but no additional dependencies.
+ * For more features, see {@link CommonsHttpRequestExecutor}. (TODO)
+ *
+ * @author Juergen Hoeller
+ * @author Iwein Fuld
+ * @author Mark Fisher
+ * @since 1.0.2
+ */
+public class SimpleHttpRequestExecutor extends AbstractHttpRequestExecutor {
+
+ @Override
+ protected InputStream doExecuteRequest(HttpRequest request) throws Exception {
+ HttpURLConnection connection = this.openConnection(request.getTargetUrl());
+ this.prepareConnection(connection, request);
+ this.writeRequestBody(connection, request.getBody());
+ this.validateResponse(connection);
+ return this.readResponseBody(connection);
+ }
+
+ /**
+ * Open an HttpURLConnection for the given request URL.
+ * @return the HttpURLConnection for the given request
+ * @throws IOException if thrown by I/O methods
+ * @see java.net.URL#openConnection()
+ */
+ private HttpURLConnection openConnection(URL url) throws IOException {
+ URLConnection con = url.openConnection();
+ if (!(con instanceof HttpURLConnection)) {
+ throw new IOException("target URL [" + url + "] is not an HTTP URL");
+ }
+ return (HttpURLConnection) con;
+ }
+
+ /**
+ * Prepare the given HTTP connection.
+ *
+ * The request method (e.g. "POST), "Content-Type" header, and content
+ * length will be determined from the provided {@link HttpRequest}.
+ * @param request HttpRequest for which the connection should be prepared
+ * @throws IOException if thrown by HttpURLConnection methods
+ * @see java.net.HttpURLConnection#setRequestMethod
+ * @see java.net.HttpURLConnection#setRequestProperty
+ */
+ private void prepareConnection(HttpURLConnection con, HttpRequest request) throws IOException {
+ con.setDoOutput(true);
+ con.setRequestMethod(request.getRequestMethod());
+ String contentType = request.getContentType();
+ if (contentType != null) {
+ con.setRequestProperty(HTTP_HEADER_CONTENT_TYPE, contentType);
+ }
+ Integer contentLength = request.getContentLength();
+ if (contentLength != null) {
+ con.setRequestProperty(HTTP_HEADER_CONTENT_LENGTH, contentLength.toString());
+ }
+ LocaleContext locale = LocaleContextHolder.getLocaleContext();
+ if (locale != null) {
+ con.setRequestProperty(HTTP_HEADER_ACCEPT_LANGUAGE,
+ StringUtils.toLanguageTag(locale.getLocale()));
+ }
+ if (isAcceptGzipEncoding()) {
+ con.setRequestProperty(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
+ }
+ }
+
+ private void writeRequestBody(HttpURLConnection con, ByteArrayOutputStream baos) throws IOException {
+ baos.writeTo(con.getOutputStream());
+ }
+
+ private void validateResponse(HttpURLConnection con) throws IOException {
+ if (con.getResponseCode() >= 300) {
+ throw new IOException(
+ "Did not receive successful HTTP response: status code = "
+ + con.getResponseCode() + ", status message = ["
+ + con.getResponseMessage() + "]");
+ }
+ }
+
+ /**
+ * Extract the response body from the connection after the request has
+ * been successfully executed.
+ *
+ * This implementation simply reads the HttpURLConnection's InputStream.
+ * If the response is recognized as GZIP response, the InputStream will be
+ * wrapped in a GZIPInputStream.
+ * @param con the HttpURLConnection to read the response body from
+ * @return an InputStream for the response body
+ * @throws IOException if thrown by I/O methods
+ * @see #isGzipResponse
+ * @see java.util.zip.GZIPInputStream
+ * @see java.net.HttpURLConnection#getInputStream()
+ */
+ private InputStream readResponseBody(HttpURLConnection con) throws IOException {
+ if (isGzipResponse(con)) {
+ // GZIP response found - need to unzip.
+ return new GZIPInputStream(con.getInputStream());
+ }
+ else {
+ // Plain response found.
+ return con.getInputStream();
+ }
+ }
+
+ /**
+ * Determine whether the given response is a GZIP response.
+ *
+ * This implementation checks whether the HTTP "Content-Encoding" header
+ * contains "gzip" (in any casing).
+ * @param con the HttpURLConnection to check
+ */
+ private boolean isGzipResponse(HttpURLConnection con) {
+ String encodingHeader = con.getHeaderField(HTTP_HEADER_CONTENT_ENCODING);
+ return (encodingHeader != null
+ && encodingHeader.toLowerCase().indexOf(ENCODING_GZIP) != -1);
+ }
+
+}
diff --git a/org.springframework.integration.http/src/test/java/org/springframework/integration/http/HttpInboundEndpointTests.java b/org.springframework.integration.http/src/test/java/org/springframework/integration/http/HttpInboundEndpointTests.java
index ebecca7a4e..fca65658ac 100644
--- a/org.springframework.integration.http/src/test/java/org/springframework/integration/http/HttpInboundEndpointTests.java
+++ b/org.springframework.integration.http/src/test/java/org/springframework/integration/http/HttpInboundEndpointTests.java
@@ -157,8 +157,8 @@ public class HttpInboundEndpointTests {
@Test
public void handleRequest_withCustomRequestMapper_requestObjectIsInPayload()
throws ServletException, IOException {
- endpoint.setRequestMapper(new RequestMapper() {
- public Message> mapRequest(HttpServletRequest request) throws Exception {
+ endpoint.setRequestMapper(new InboundRequestMapper() {
+ public Message> toMessage(HttpServletRequest request) throws Exception {
return new StringMessage(request.getRequestURI());
}
});
diff --git a/org.springframework.integration.http/src/test/java/org/springframework/integration/http/mapper/DataBindingRequestMapperTests.java b/org.springframework.integration.http/src/test/java/org/springframework/integration/http/mapper/DataBindingInboundRequestMapperTests.java
similarity index 84%
rename from org.springframework.integration.http/src/test/java/org/springframework/integration/http/mapper/DataBindingRequestMapperTests.java
rename to org.springframework.integration.http/src/test/java/org/springframework/integration/http/mapper/DataBindingInboundRequestMapperTests.java
index 82251b5543..f1b661505e 100644
--- a/org.springframework.integration.http/src/test/java/org/springframework/integration/http/mapper/DataBindingRequestMapperTests.java
+++ b/org.springframework.integration.http/src/test/java/org/springframework/integration/http/mapper/DataBindingInboundRequestMapperTests.java
@@ -24,22 +24,22 @@ import org.junit.Test;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.integration.core.Message;
-import org.springframework.integration.http.DataBindingRequestMapper;
+import org.springframework.integration.http.DataBindingInboundRequestMapper;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
/**
* @author Mark Fisher
*/
-public class DataBindingRequestMapperTests {
+public class DataBindingInboundRequestMapperTests {
@Test
public void bindToType() throws Exception {
- DataBindingRequestMapper mapper = new DataBindingRequestMapper(TestBean.class);
+ DataBindingInboundRequestMapper mapper = new DataBindingInboundRequestMapper(TestBean.class);
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("name", "testBean");
request.setParameter("age", "42");
- Message> result = mapper.mapRequest(request);
+ Message> result = mapper.toMessage(request);
assertNotNull(result);
assertEquals(TestBean.class, result.getPayload().getClass());
TestBean payload = (TestBean) result.getPayload();
@@ -49,14 +49,14 @@ public class DataBindingRequestMapperTests {
@Test
public void bindToTypeWithBindingInitializer() throws Exception {
- DataBindingRequestMapper mapper = new DataBindingRequestMapper(TestBean.class);
+ DataBindingInboundRequestMapper mapper = new DataBindingInboundRequestMapper(TestBean.class);
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
initializer.setDirectFieldAccess(true);
mapper.setWebBindingInitializer(initializer);
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("name", "testBean");
request.setParameter("age", "42");
- Message> result = mapper.mapRequest(request);
+ Message> result = mapper.toMessage(request);
assertNotNull(result);
assertEquals(TestBean.class, result.getPayload().getClass());
TestBean payload = (TestBean) result.getPayload();
@@ -70,12 +70,12 @@ public class DataBindingRequestMapperTests {
MutablePropertyValues properties = new MutablePropertyValues();
properties.addPropertyValue("name", "prototype");
context.registerPrototype("prototypeTarget", TestBean.class, properties);
- DataBindingRequestMapper mapper = new DataBindingRequestMapper(TestBean.class);
+ DataBindingInboundRequestMapper mapper = new DataBindingInboundRequestMapper(TestBean.class);
mapper.setTargetBeanName("prototypeTarget");
mapper.setBeanFactory(context);
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("age", "42");
- Message> result = mapper.mapRequest(request);
+ Message> result = mapper.toMessage(request);
assertNotNull(result);
assertEquals(TestBean.class, result.getPayload().getClass());
TestBean payload = (TestBean) result.getPayload();
null.
+ */
+ Integer getContentLength();
+
+ /**
+ * Return the request body as a {@link ByteArrayOutputStream}.
+ */
+ ByteArrayOutputStream getBody();
+
+}
diff --git a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/HttpRequestExecutor.java b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/HttpRequestExecutor.java
new file mode 100644
index 0000000000..707b37879b
--- /dev/null
+++ b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/HttpRequestExecutor.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2002-2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.integration.http;
+
+import java.io.InputStream;
+
+/**
+ * Strategy that will allow a http request response exchange with a remote
+ * server.
+ *
+ * @author Iwein Fuld
+ * @author Mark Fisher
+ * @since 1.0.2
+ */
+public interface HttpRequestExecutor {
+
+ InputStream executeRequest(HttpRequest request) throws Exception;
+
+}
diff --git a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/RequestMapper.java b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/InboundRequestMapper.java
similarity index 82%
rename from org.springframework.integration.http/src/main/java/org/springframework/integration/http/RequestMapper.java
rename to org.springframework.integration.http/src/main/java/org/springframework/integration/http/InboundRequestMapper.java
index c2d38a9e89..670a877148 100644
--- a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/RequestMapper.java
+++ b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/InboundRequestMapper.java
@@ -18,16 +18,15 @@ package org.springframework.integration.http;
import javax.servlet.http.HttpServletRequest;
-import org.springframework.integration.core.Message;
+import org.springframework.integration.message.InboundMessageMapper;
/**
* Strategy interface for mapping from an inbound {@link HttpServletRequest}
* to a Message.
*
* @author Mark Fisher
+ * @since 1.0.2
*/
-public interface RequestMapper {
-
- Message> mapRequest(HttpServletRequest request) throws Exception;
+public interface InboundRequestMapper extends InboundMessageMapper