001/*
002 * Copyright 2002-2018 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;
018
019import java.io.Closeable;
020import java.io.IOException;
021import java.net.URI;
022
023import org.apache.http.client.HttpClient;
024import org.apache.http.client.config.RequestConfig;
025import org.apache.http.client.methods.Configurable;
026import org.apache.http.client.methods.HttpUriRequest;
027import org.apache.http.client.protocol.HttpClientContext;
028import org.apache.http.impl.client.CloseableHttpClient;
029import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
030import org.apache.http.impl.nio.client.HttpAsyncClients;
031import org.apache.http.nio.client.HttpAsyncClient;
032import org.apache.http.protocol.HttpContext;
033
034import org.springframework.beans.factory.InitializingBean;
035import org.springframework.http.HttpMethod;
036import org.springframework.util.Assert;
037
038/**
039 * Asynchronous extension of the {@link HttpComponentsClientHttpRequestFactory}. Uses
040 * <a href="https://hc.apache.org/httpcomponents-asyncclient-dev/">Apache HttpComponents
041 * HttpAsyncClient 4.0</a> to create requests.
042 *
043 * @author Arjen Poutsma
044 * @author Stephane Nicoll
045 * @since 4.0
046 * @see HttpAsyncClient
047 * @deprecated as of Spring 5.0, with no direct replacement
048 */
049@Deprecated
050public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory
051                implements AsyncClientHttpRequestFactory, InitializingBean {
052
053        private HttpAsyncClient asyncClient;
054
055
056        /**
057         * Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
058         * with a default {@link HttpAsyncClient} and {@link HttpClient}.
059         */
060        public HttpComponentsAsyncClientHttpRequestFactory() {
061                super();
062                this.asyncClient = HttpAsyncClients.createSystem();
063        }
064
065        /**
066         * Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
067         * with the given {@link HttpAsyncClient} instance and a default {@link HttpClient}.
068         * @param asyncClient the HttpAsyncClient instance to use for this request factory
069         * @since 4.3.10
070         */
071        public HttpComponentsAsyncClientHttpRequestFactory(HttpAsyncClient asyncClient) {
072                super();
073                this.asyncClient = asyncClient;
074        }
075
076        /**
077         * Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
078         * with the given {@link CloseableHttpAsyncClient} instance and a default {@link HttpClient}.
079         * @param asyncClient the CloseableHttpAsyncClient instance to use for this request factory
080         */
081        public HttpComponentsAsyncClientHttpRequestFactory(CloseableHttpAsyncClient asyncClient) {
082                super();
083                this.asyncClient = asyncClient;
084        }
085
086        /**
087         * Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
088         * with the given {@link HttpClient} and {@link HttpAsyncClient} instances.
089         * @param httpClient the HttpClient instance to use for this request factory
090         * @param asyncClient the HttpAsyncClient instance to use for this request factory
091         * @since 4.3.10
092         */
093        public HttpComponentsAsyncClientHttpRequestFactory(HttpClient httpClient, HttpAsyncClient asyncClient) {
094                super(httpClient);
095                this.asyncClient = asyncClient;
096        }
097
098        /**
099         * Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
100         * with the given {@link CloseableHttpClient} and {@link CloseableHttpAsyncClient} instances.
101         * @param httpClient the CloseableHttpClient instance to use for this request factory
102         * @param asyncClient the CloseableHttpAsyncClient instance to use for this request factory
103         */
104        public HttpComponentsAsyncClientHttpRequestFactory(
105                        CloseableHttpClient httpClient, CloseableHttpAsyncClient asyncClient) {
106
107                super(httpClient);
108                this.asyncClient = asyncClient;
109        }
110
111
112        /**
113         * Set the {@code HttpAsyncClient} used for
114         * {@linkplain #createAsyncRequest(URI, HttpMethod) synchronous execution}.
115         * @since 4.3.10
116         * @see #setHttpClient(HttpClient)
117         */
118        public void setAsyncClient(HttpAsyncClient asyncClient) {
119                Assert.notNull(asyncClient, "HttpAsyncClient must not be null");
120                this.asyncClient = asyncClient;
121        }
122
123        /**
124         * Return the {@code HttpAsyncClient} used for
125         * {@linkplain #createAsyncRequest(URI, HttpMethod) synchronous execution}.
126         * @since 4.3.10
127         * @see #getHttpClient()
128         */
129        public HttpAsyncClient getAsyncClient() {
130                return this.asyncClient;
131        }
132
133        /**
134         * Set the {@code CloseableHttpAsyncClient} used for
135         * {@linkplain #createAsyncRequest(URI, HttpMethod) asynchronous execution}.
136         * @deprecated as of 4.3.10, in favor of {@link #setAsyncClient(HttpAsyncClient)}
137         */
138        @Deprecated
139        public void setHttpAsyncClient(CloseableHttpAsyncClient asyncClient) {
140                this.asyncClient = asyncClient;
141        }
142
143        /**
144         * Return the {@code CloseableHttpAsyncClient} used for
145         * {@linkplain #createAsyncRequest(URI, HttpMethod) asynchronous execution}.
146         * @deprecated as of 4.3.10, in favor of {@link #getAsyncClient()}
147         */
148        @Deprecated
149        public CloseableHttpAsyncClient getHttpAsyncClient() {
150                Assert.state(this.asyncClient instanceof CloseableHttpAsyncClient,
151                                "No CloseableHttpAsyncClient - use getAsyncClient() instead");
152                return (CloseableHttpAsyncClient) this.asyncClient;
153        }
154
155
156        @Override
157        public void afterPropertiesSet() {
158                startAsyncClient();
159        }
160
161        private HttpAsyncClient startAsyncClient() {
162                HttpAsyncClient client = getAsyncClient();
163                if (client instanceof CloseableHttpAsyncClient) {
164                        @SuppressWarnings("resource")
165                        CloseableHttpAsyncClient closeableAsyncClient = (CloseableHttpAsyncClient) client;
166                        if (!closeableAsyncClient.isRunning()) {
167                                closeableAsyncClient.start();
168                        }
169                }
170                return client;
171        }
172
173        @Override
174        public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) throws IOException {
175                HttpAsyncClient client = startAsyncClient();
176
177                HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri);
178                postProcessHttpRequest(httpRequest);
179                HttpContext context = createHttpContext(httpMethod, uri);
180                if (context == null) {
181                        context = HttpClientContext.create();
182                }
183
184                // Request configuration not set in the context
185                if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
186                        // Use request configuration given by the user, when available
187                        RequestConfig config = null;
188                        if (httpRequest instanceof Configurable) {
189                                config = ((Configurable) httpRequest).getConfig();
190                        }
191                        if (config == null) {
192                                config = createRequestConfig(client);
193                        }
194                        if (config != null) {
195                                context.setAttribute(HttpClientContext.REQUEST_CONFIG, config);
196                        }
197                }
198
199                return new HttpComponentsAsyncClientHttpRequest(client, httpRequest, context);
200        }
201
202        @Override
203        public void destroy() throws Exception {
204                try {
205                        super.destroy();
206                }
207                finally {
208                        HttpAsyncClient asyncClient = getAsyncClient();
209                        if (asyncClient instanceof Closeable) {
210                                ((Closeable) asyncClient).close();
211                        }
212                }
213        }
214
215}