From 703e883a02d4b1dcfdf3b625dec9841fa1e4f34a Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Thu, 19 Mar 2009 18:55:11 +0000 Subject: [PATCH] Refactored outbound HTTP support to include HttpRequest and HttpRequestExecutor (formerly HttpExchanger). Also refactored existing RequestMapper to InboundRequestMapper, and added OutboundRequestMapper. --- .../http/AbstractHttpRequestExecutor.java | 94 ++++++++ ...a => DataBindingInboundRequestMapper.java} | 32 ++- ....java => DefaultInboundRequestMapper.java} | 11 +- .../http/DefaultOutboundRequestMapper.java | 139 ++++++++++++ .../integration/http/HttpExchanger.java | 21 -- .../integration/http/HttpInboundEndpoint.java | 16 +- .../http/HttpOutboundEndpoint.java | 93 ++------ .../integration/http/HttpRequest.java | 56 +++++ .../integration/http/HttpRequestExecutor.java | 33 +++ ...tMapper.java => InboundRequestMapper.java} | 7 +- .../http/OutboundRequestMapper.java | 29 +++ .../http/ResponseStatusCodeException.java | 3 +- .../integration/http/SimpleHttpExchanger.java | 200 ------------------ .../http/SimpleHttpRequestExecutor.java | 148 +++++++++++++ .../http/HttpInboundEndpointTests.java | 4 +- ...DataBindingInboundRequestMapperTests.java} | 16 +- 16 files changed, 565 insertions(+), 337 deletions(-) create mode 100644 org.springframework.integration.http/src/main/java/org/springframework/integration/http/AbstractHttpRequestExecutor.java rename org.springframework.integration.http/src/main/java/org/springframework/integration/http/{DataBindingRequestMapper.java => DataBindingInboundRequestMapper.java} (78%) rename org.springframework.integration.http/src/main/java/org/springframework/integration/http/{DefaultRequestMapper.java => DefaultInboundRequestMapper.java} (93%) create mode 100644 org.springframework.integration.http/src/main/java/org/springframework/integration/http/DefaultOutboundRequestMapper.java delete mode 100644 org.springframework.integration.http/src/main/java/org/springframework/integration/http/HttpExchanger.java create mode 100644 org.springframework.integration.http/src/main/java/org/springframework/integration/http/HttpRequest.java create mode 100644 org.springframework.integration.http/src/main/java/org/springframework/integration/http/HttpRequestExecutor.java rename org.springframework.integration.http/src/main/java/org/springframework/integration/http/{RequestMapper.java => InboundRequestMapper.java} (82%) create mode 100644 org.springframework.integration.http/src/main/java/org/springframework/integration/http/OutboundRequestMapper.java delete mode 100644 org.springframework.integration.http/src/main/java/org/springframework/integration/http/SimpleHttpExchanger.java create mode 100644 org.springframework.integration.http/src/main/java/org/springframework/integration/http/SimpleHttpRequestExecutor.java rename org.springframework.integration.http/src/test/java/org/springframework/integration/http/mapper/{DataBindingRequestMapperTests.java => DataBindingInboundRequestMapperTests.java} (84%) 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: *