001/*
002 * Copyright 2002-2019 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.http.client.support;
018
019import java.io.IOException;
020import java.net.URI;
021import java.util.ArrayList;
022import java.util.List;
023
024import org.apache.commons.logging.Log;
025
026import org.springframework.core.annotation.AnnotationAwareOrderComparator;
027import org.springframework.http.HttpLogging;
028import org.springframework.http.HttpMethod;
029import org.springframework.http.client.ClientHttpRequest;
030import org.springframework.http.client.ClientHttpRequestFactory;
031import org.springframework.http.client.ClientHttpRequestInitializer;
032import org.springframework.http.client.SimpleClientHttpRequestFactory;
033import org.springframework.util.Assert;
034
035/**
036 * Base class for {@link org.springframework.web.client.RestTemplate}
037 * and other HTTP accessing gateway helpers, defining common properties
038 * such as the {@link ClientHttpRequestFactory} to operate on.
039 *
040 * <p>Not intended to be used directly.
041 *
042 * <p>See {@link org.springframework.web.client.RestTemplate} for an entry point.
043 *
044 * @author Arjen Poutsma
045 * @author Juergen Hoeller
046 * @author Phillip Webb
047 * @since 3.0
048 * @see ClientHttpRequestFactory
049 * @see org.springframework.web.client.RestTemplate
050 */
051public abstract class HttpAccessor {
052
053        /** Logger available to subclasses. */
054        protected final Log logger = HttpLogging.forLogName(getClass());
055
056        private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
057
058        private final List<ClientHttpRequestInitializer> clientHttpRequestInitializers = new ArrayList<>();
059
060
061        /**
062         * Set the request factory that this accessor uses for obtaining client request handles.
063         * <p>The default is a {@link SimpleClientHttpRequestFactory} based on the JDK's own
064         * HTTP libraries ({@link java.net.HttpURLConnection}).
065         * <p><b>Note that the standard JDK HTTP library does not support the HTTP PATCH method.
066         * Configure the Apache HttpComponents or OkHttp request factory to enable PATCH.</b>
067         * @see #createRequest(URI, HttpMethod)
068         * @see SimpleClientHttpRequestFactory
069         * @see org.springframework.http.client.HttpComponentsAsyncClientHttpRequestFactory
070         * @see org.springframework.http.client.OkHttp3ClientHttpRequestFactory
071         */
072        public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
073                Assert.notNull(requestFactory, "ClientHttpRequestFactory must not be null");
074                this.requestFactory = requestFactory;
075        }
076
077        /**
078         * Return the request factory that this accessor uses for obtaining client request handles.
079         */
080        public ClientHttpRequestFactory getRequestFactory() {
081                return this.requestFactory;
082        }
083
084
085        /**
086         * Set the request initializers that this accessor should use.
087         * <p>The initializers will get immediately sorted according to their
088         * {@linkplain AnnotationAwareOrderComparator#sort(List) order}.
089         * @since 5.2
090         */
091        public void setClientHttpRequestInitializers(
092                        List<ClientHttpRequestInitializer> clientHttpRequestInitializers) {
093
094                if (this.clientHttpRequestInitializers != clientHttpRequestInitializers) {
095                        this.clientHttpRequestInitializers.clear();
096                        this.clientHttpRequestInitializers.addAll(clientHttpRequestInitializers);
097                        AnnotationAwareOrderComparator.sort(this.clientHttpRequestInitializers);
098                }
099        }
100
101        /**
102         * Get the request initializers that this accessor uses.
103         * <p>The returned {@link List} is active and may be modified. Note,
104         * however, that the initializers will not be resorted according to their
105         * {@linkplain AnnotationAwareOrderComparator#sort(List) order} before the
106         * {@link ClientHttpRequest} is initialized.
107         * @since 5.2
108         * @see #setClientHttpRequestInitializers(List)
109         */
110        public List<ClientHttpRequestInitializer> getClientHttpRequestInitializers() {
111                return this.clientHttpRequestInitializers;
112        }
113
114        /**
115         * Create a new {@link ClientHttpRequest} via this template's {@link ClientHttpRequestFactory}.
116         * @param url the URL to connect to
117         * @param method the HTTP method to execute (GET, POST, etc)
118         * @return the created request
119         * @throws IOException in case of I/O errors
120         * @see #getRequestFactory()
121         * @see ClientHttpRequestFactory#createRequest(URI, HttpMethod)
122         */
123        protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
124                ClientHttpRequest request = getRequestFactory().createRequest(url, method);
125                initialize(request);
126                if (logger.isDebugEnabled()) {
127                        logger.debug("HTTP " + method.name() + " " + url);
128                }
129                return request;
130        }
131
132        private void initialize(ClientHttpRequest request) {
133                this.clientHttpRequestInitializers.forEach(initializer -> initializer.initialize(request));
134        }
135
136}