Remove AsyncRestTemplate and related types

This commit is contained in:
Rossen Stoyanchev
2021-10-08 17:59:03 +01:00
parent 932291b867
commit e3b48c23dd
40 changed files with 37 additions and 4813 deletions

View File

@@ -1,85 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.http.client;
import java.io.IOException;
import java.io.OutputStream;
import org.springframework.http.HttpHeaders;
import org.springframework.util.Assert;
import org.springframework.util.concurrent.ListenableFuture;
/**
* Abstract base for {@link AsyncClientHttpRequest} that makes sure that headers and body
* are not written multiple times.
*
* @author Arjen Poutsma
* @since 4.0
* @deprecated as of Spring 5.0, in favor of {@link org.springframework.http.client.reactive.AbstractClientHttpRequest}
*/
@Deprecated
abstract class AbstractAsyncClientHttpRequest implements AsyncClientHttpRequest {
private final HttpHeaders headers = new HttpHeaders();
private boolean executed = false;
@Override
public final HttpHeaders getHeaders() {
return (this.executed ? HttpHeaders.readOnlyHttpHeaders(this.headers) : this.headers);
}
@Override
public final OutputStream getBody() throws IOException {
assertNotExecuted();
return getBodyInternal(this.headers);
}
@Override
public ListenableFuture<ClientHttpResponse> executeAsync() throws IOException {
assertNotExecuted();
ListenableFuture<ClientHttpResponse> result = executeInternal(this.headers);
this.executed = true;
return result;
}
/**
* Asserts that this request has not been {@linkplain #executeAsync() executed} yet.
* @throws IllegalStateException if this request has been executed
*/
protected void assertNotExecuted() {
Assert.state(!this.executed, "ClientHttpRequest already executed");
}
/**
* Abstract template method that returns the body.
* @param headers the HTTP headers
* @return the body output stream
*/
protected abstract OutputStream getBodyInternal(HttpHeaders headers) throws IOException;
/**
* Abstract template method that writes the given headers and content to the HTTP request.
* @param headers the HTTP headers
* @return the response object for the executed request
*/
protected abstract ListenableFuture<ClientHttpResponse> executeInternal(HttpHeaders headers)
throws IOException;
}

View File

@@ -1,65 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.http.client;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.springframework.http.HttpHeaders;
import org.springframework.util.concurrent.ListenableFuture;
/**
* Base implementation of {@link AsyncClientHttpRequest} that buffers output
* in a byte array before sending it over the wire.
*
* @author Arjen Poutsma
* @since 4.0
* @deprecated as of Spring 5.0, with no direct replacement
*/
@Deprecated
abstract class AbstractBufferingAsyncClientHttpRequest extends AbstractAsyncClientHttpRequest {
private ByteArrayOutputStream bufferedOutput = new ByteArrayOutputStream(1024);
@Override
protected OutputStream getBodyInternal(HttpHeaders headers) throws IOException {
return this.bufferedOutput;
}
@Override
protected ListenableFuture<ClientHttpResponse> executeInternal(HttpHeaders headers) throws IOException {
byte[] bytes = this.bufferedOutput.toByteArray();
if (headers.getContentLength() < 0) {
headers.setContentLength(bytes.length);
}
ListenableFuture<ClientHttpResponse> result = executeInternal(headers, bytes);
this.bufferedOutput = new ByteArrayOutputStream(0);
return result;
}
/**
* Abstract template method that writes the given headers and content to the HTTP request.
* @param headers the HTTP headers
* @param bufferedOutput the body content
* @return the response object for the executed request
*/
protected abstract ListenableFuture<ClientHttpResponse> executeInternal(
HttpHeaders headers, byte[] bufferedOutput) throws IOException;
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.http.client;
import java.io.IOException;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.HttpRequest;
import org.springframework.util.concurrent.ListenableFuture;
/**
* Represents a client-side asynchronous HTTP request. Created via an
* implementation of the {@link AsyncClientHttpRequestFactory}.
*
* <p>A {@code AsyncHttpRequest} can be {@linkplain #executeAsync() executed},
* getting a future {@link ClientHttpResponse} which can be read from.
*
* @author Arjen Poutsma
* @since 4.0
* @see AsyncClientHttpRequestFactory#createAsyncRequest
* @deprecated as of Spring 5.0, in favor of {@link org.springframework.web.reactive.function.client.ClientRequest}
*/
@Deprecated
public interface AsyncClientHttpRequest extends HttpRequest, HttpOutputMessage {
/**
* Execute this request asynchronously, resulting in a Future handle.
* {@link ClientHttpResponse} that can be read.
* @return the future response result of the execution
* @throws java.io.IOException in case of I/O errors
*/
ListenableFuture<ClientHttpResponse> executeAsync() throws IOException;
}

View File

@@ -1,50 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.http.client;
import java.io.IOException;
import org.springframework.http.HttpRequest;
import org.springframework.util.concurrent.ListenableFuture;
/**
* Represents the context of a client-side HTTP request execution.
*
* <p>Used to invoke the next interceptor in the interceptor chain, or -
* if the calling interceptor is last - execute the request itself.
*
* @author Jakub Narloch
* @author Rossen Stoyanchev
* @since 4.3
* @see AsyncClientHttpRequestInterceptor
* @deprecated as of Spring 5.0, in favor of
* {@link org.springframework.web.reactive.function.client.ExchangeFilterFunction}
*/
@Deprecated
public interface AsyncClientHttpRequestExecution {
/**
* Resume the request execution by invoking the next interceptor in the chain
* or executing the request to the remote service.
* @param request the HTTP request, containing the HTTP method and headers
* @param body the body of the request
* @return a corresponding future handle
* @throws IOException in case of I/O errors
*/
ListenableFuture<ClientHttpResponse> executeAsync(HttpRequest request, byte[] body) throws IOException;
}

View File

@@ -1,47 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.http.client;
import java.io.IOException;
import java.net.URI;
import org.springframework.http.HttpMethod;
/**
* Factory for {@link AsyncClientHttpRequest} objects.
* Requests are created by the {@link #createAsyncRequest(URI, HttpMethod)} method.
*
* @author Arjen Poutsma
* @since 4.0
* @deprecated as of Spring 5.0, in favor of {@link org.springframework.http.client.reactive.ClientHttpConnector}
*/
@Deprecated
public interface AsyncClientHttpRequestFactory {
/**
* Create a new asynchronous {@link AsyncClientHttpRequest} for the specified URI
* and HTTP method.
* <p>The returned request can be written to, and then executed by calling
* {@link AsyncClientHttpRequest#executeAsync()}.
* @param uri the URI to create a request for
* @param httpMethod the HTTP method to execute
* @return the created request
* @throws IOException in case of I/O errors
*/
AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) throws IOException;
}

View File

@@ -1,73 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.http.client;
import java.io.IOException;
import org.springframework.http.HttpRequest;
import org.springframework.util.concurrent.ListenableFuture;
/**
* Intercepts client-side HTTP requests. Implementations of this interface can be
* {@linkplain org.springframework.web.client.AsyncRestTemplate#setInterceptors registered}
* with the {@link org.springframework.web.client.AsyncRestTemplate} as to modify
* the outgoing {@link HttpRequest} and/or register to modify the incoming
* {@link ClientHttpResponse} with help of a
* {@link org.springframework.util.concurrent.ListenableFutureAdapter}.
*
* <p>The main entry point for interceptors is {@link #intercept}.
*
* @author Jakub Narloch
* @author Rossen Stoyanchev
* @since 4.3
* @see org.springframework.web.client.AsyncRestTemplate
* @see org.springframework.http.client.support.InterceptingAsyncHttpAccessor
* @deprecated as of Spring 5.0, in favor of
* {@link org.springframework.web.reactive.function.client.ExchangeFilterFunction}
*/
@Deprecated
public interface AsyncClientHttpRequestInterceptor {
/**
* Intercept the given request, and return a response future. The given
* {@link AsyncClientHttpRequestExecution} allows the interceptor to pass on
* the request to the next entity in the chain.
* <p>An implementation might follow this pattern:
* <ol>
* <li>Examine the {@linkplain HttpRequest request} and body</li>
* <li>Optionally {@linkplain org.springframework.http.client.support.HttpRequestWrapper
* wrap} the request to filter HTTP attributes.</li>
* <li>Optionally modify the body of the request.</li>
* <li>One of the following:
* <ul>
* <li>execute the request through {@link ClientHttpRequestExecution}</li>
* <li>don't execute the request to block the execution altogether</li>
* </ul>
* <li>Optionally adapt the response to filter HTTP attributes with the help of
* {@link org.springframework.util.concurrent.ListenableFutureAdapter
* ListenableFutureAdapter}.</li>
* </ol>
* @param request the request, containing method, URI, and headers
* @param body the body of the request
* @param execution the request execution
* @return the response future
* @throws IOException in case of I/O errors
*/
ListenableFuture<ClientHttpResponse> intercept(HttpRequest request, byte[] body,
AsyncClientHttpRequestExecution execution) throws IOException;
}

View File

@@ -1,172 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.http.client;
import java.io.IOException;
import java.net.URI;
import java.util.concurrent.Future;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.nio.client.HttpAsyncClient;
import org.apache.http.nio.entity.NByteArrayEntity;
import org.apache.http.protocol.HttpContext;
import org.springframework.http.HttpHeaders;
import org.springframework.util.concurrent.FailureCallback;
import org.springframework.util.concurrent.FutureAdapter;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;
import org.springframework.util.concurrent.ListenableFutureCallbackRegistry;
import org.springframework.util.concurrent.SuccessCallback;
/**
* {@link ClientHttpRequest} implementation based on
* Apache HttpComponents HttpAsyncClient.
*
* <p>Created via the {@link HttpComponentsClientHttpRequestFactory}.
*
* @author Oleg Kalnichevski
* @author Arjen Poutsma
* @since 4.0
* @see HttpComponentsClientHttpRequestFactory#createRequest
* @deprecated as of Spring 5.0, in favor of
* {@link org.springframework.http.client.reactive.HttpComponentsClientHttpConnector}
*/
@Deprecated
final class HttpComponentsAsyncClientHttpRequest extends AbstractBufferingAsyncClientHttpRequest {
private final HttpAsyncClient httpClient;
private final HttpUriRequest httpRequest;
private final HttpContext httpContext;
HttpComponentsAsyncClientHttpRequest(HttpAsyncClient client, HttpUriRequest request, HttpContext context) {
this.httpClient = client;
this.httpRequest = request;
this.httpContext = context;
}
@Override
public String getMethodValue() {
return this.httpRequest.getMethod();
}
@Override
public URI getURI() {
return this.httpRequest.getURI();
}
HttpContext getHttpContext() {
return this.httpContext;
}
@Override
protected ListenableFuture<ClientHttpResponse> executeInternal(HttpHeaders headers, byte[] bufferedOutput)
throws IOException {
HttpComponentsClientHttpRequest.addHeaders(this.httpRequest, headers);
if (this.httpRequest instanceof HttpEntityEnclosingRequest) {
HttpEntityEnclosingRequest entityEnclosingRequest = (HttpEntityEnclosingRequest) this.httpRequest;
HttpEntity requestEntity = new NByteArrayEntity(bufferedOutput);
entityEnclosingRequest.setEntity(requestEntity);
}
HttpResponseFutureCallback callback = new HttpResponseFutureCallback(this.httpRequest);
Future<HttpResponse> futureResponse = this.httpClient.execute(this.httpRequest, this.httpContext, callback);
return new ClientHttpResponseFuture(futureResponse, callback);
}
private static class HttpResponseFutureCallback implements FutureCallback<HttpResponse> {
private final HttpUriRequest request;
private final ListenableFutureCallbackRegistry<ClientHttpResponse> callbacks =
new ListenableFutureCallbackRegistry<>();
public HttpResponseFutureCallback(HttpUriRequest request) {
this.request = request;
}
public void addCallback(ListenableFutureCallback<? super ClientHttpResponse> callback) {
this.callbacks.addCallback(callback);
}
public void addSuccessCallback(SuccessCallback<? super ClientHttpResponse> callback) {
this.callbacks.addSuccessCallback(callback);
}
public void addFailureCallback(FailureCallback callback) {
this.callbacks.addFailureCallback(callback);
}
@Override
public void completed(HttpResponse result) {
this.callbacks.success(new HttpComponentsAsyncClientHttpResponse(result));
}
@Override
public void failed(Exception ex) {
this.callbacks.failure(ex);
}
@Override
public void cancelled() {
this.request.abort();
}
}
private static class ClientHttpResponseFuture extends FutureAdapter<ClientHttpResponse, HttpResponse>
implements ListenableFuture<ClientHttpResponse> {
private final HttpResponseFutureCallback callback;
public ClientHttpResponseFuture(Future<HttpResponse> response, HttpResponseFutureCallback callback) {
super(response);
this.callback = callback;
}
@Override
protected ClientHttpResponse adapt(HttpResponse response) {
return new HttpComponentsAsyncClientHttpResponse(response);
}
@Override
public void addCallback(ListenableFutureCallback<? super ClientHttpResponse> callback) {
this.callback.addCallback(callback);
}
@Override
public void addCallback(SuccessCallback<? super ClientHttpResponse> successCallback,
FailureCallback failureCallback) {
this.callback.addSuccessCallback(successCallback);
this.callback.addFailureCallback(failureCallback);
}
}
}

View File

@@ -1,216 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.http.client;
import java.io.Closeable;
import java.io.IOException;
import java.net.URI;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.Configurable;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.nio.client.HttpAsyncClient;
import org.apache.http.protocol.HttpContext;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.HttpMethod;
import org.springframework.util.Assert;
/**
* Asynchronous extension of the {@link HttpComponentsClientHttpRequestFactory}. Uses
* <a href="https://hc.apache.org/httpcomponents-asyncclient-dev/">Apache HttpComponents
* HttpAsyncClient 4.0</a> to create requests.
*
* @author Arjen Poutsma
* @author Stephane Nicoll
* @since 4.0
* @see HttpAsyncClient
* @deprecated as of Spring 5.0, in favor of
* {@link org.springframework.http.client.reactive.HttpComponentsClientHttpConnector}
*/
@Deprecated
public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory
implements AsyncClientHttpRequestFactory, InitializingBean {
private HttpAsyncClient asyncClient;
/**
* Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
* with a default {@link HttpAsyncClient} and {@link HttpClient}.
*/
public HttpComponentsAsyncClientHttpRequestFactory() {
super();
this.asyncClient = HttpAsyncClients.createSystem();
}
/**
* Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
* with the given {@link HttpAsyncClient} instance and a default {@link HttpClient}.
* @param asyncClient the HttpAsyncClient instance to use for this request factory
* @since 4.3.10
*/
public HttpComponentsAsyncClientHttpRequestFactory(HttpAsyncClient asyncClient) {
super();
this.asyncClient = asyncClient;
}
/**
* Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
* with the given {@link CloseableHttpAsyncClient} instance and a default {@link HttpClient}.
* @param asyncClient the CloseableHttpAsyncClient instance to use for this request factory
*/
public HttpComponentsAsyncClientHttpRequestFactory(CloseableHttpAsyncClient asyncClient) {
super();
this.asyncClient = asyncClient;
}
/**
* Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
* with the given {@link HttpClient} and {@link HttpAsyncClient} instances.
* @param httpClient the HttpClient instance to use for this request factory
* @param asyncClient the HttpAsyncClient instance to use for this request factory
* @since 4.3.10
*/
public HttpComponentsAsyncClientHttpRequestFactory(HttpClient httpClient, HttpAsyncClient asyncClient) {
super(httpClient);
this.asyncClient = asyncClient;
}
/**
* Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
* with the given {@link CloseableHttpClient} and {@link CloseableHttpAsyncClient} instances.
* @param httpClient the CloseableHttpClient instance to use for this request factory
* @param asyncClient the CloseableHttpAsyncClient instance to use for this request factory
*/
public HttpComponentsAsyncClientHttpRequestFactory(
CloseableHttpClient httpClient, CloseableHttpAsyncClient asyncClient) {
super(httpClient);
this.asyncClient = asyncClient;
}
/**
* Set the {@code HttpAsyncClient} used for
* {@linkplain #createAsyncRequest(URI, HttpMethod) synchronous execution}.
* @since 4.3.10
* @see #setHttpClient(HttpClient)
*/
public void setAsyncClient(HttpAsyncClient asyncClient) {
Assert.notNull(asyncClient, "HttpAsyncClient must not be null");
this.asyncClient = asyncClient;
}
/**
* Return the {@code HttpAsyncClient} used for
* {@linkplain #createAsyncRequest(URI, HttpMethod) synchronous execution}.
* @since 4.3.10
* @see #getHttpClient()
*/
public HttpAsyncClient getAsyncClient() {
return this.asyncClient;
}
/**
* Set the {@code CloseableHttpAsyncClient} used for
* {@linkplain #createAsyncRequest(URI, HttpMethod) asynchronous execution}.
* @deprecated as of 4.3.10, in favor of {@link #setAsyncClient(HttpAsyncClient)}
*/
@Deprecated
public void setHttpAsyncClient(CloseableHttpAsyncClient asyncClient) {
this.asyncClient = asyncClient;
}
/**
* Return the {@code CloseableHttpAsyncClient} used for
* {@linkplain #createAsyncRequest(URI, HttpMethod) asynchronous execution}.
* @deprecated as of 4.3.10, in favor of {@link #getAsyncClient()}
*/
@Deprecated
public CloseableHttpAsyncClient getHttpAsyncClient() {
Assert.state(this.asyncClient instanceof CloseableHttpAsyncClient,
"No CloseableHttpAsyncClient - use getAsyncClient() instead");
return (CloseableHttpAsyncClient) this.asyncClient;
}
@Override
public void afterPropertiesSet() {
startAsyncClient();
}
private HttpAsyncClient startAsyncClient() {
HttpAsyncClient client = getAsyncClient();
if (client instanceof CloseableHttpAsyncClient) {
@SuppressWarnings("resource")
CloseableHttpAsyncClient closeableAsyncClient = (CloseableHttpAsyncClient) client;
if (!closeableAsyncClient.isRunning()) {
closeableAsyncClient.start();
}
}
return client;
}
@Override
public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) throws IOException {
HttpAsyncClient client = startAsyncClient();
HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri);
postProcessHttpRequest(httpRequest);
HttpContext context = createHttpContext(httpMethod, uri);
if (context == null) {
context = HttpClientContext.create();
}
// Request configuration not set in the context
if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
// Use request configuration given by the user, when available
RequestConfig config = null;
if (httpRequest instanceof Configurable) {
config = ((Configurable) httpRequest).getConfig();
}
if (config == null) {
config = createRequestConfig(client);
}
if (config != null) {
context.setAttribute(HttpClientContext.REQUEST_CONFIG, config);
}
}
return new HttpComponentsAsyncClientHttpRequest(client, httpRequest, context);
}
@Override
public void destroy() throws Exception {
try {
super.destroy();
}
finally {
HttpAsyncClient asyncClient = getAsyncClient();
if (asyncClient instanceof Closeable) {
((Closeable) asyncClient).close();
}
}
}
}

View File

@@ -1,90 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.http.client;
import java.io.IOException;
import java.io.InputStream;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.util.StreamUtils;
/**
* {@link ClientHttpResponse} implementation based on
* Apache HttpComponents HttpAsyncClient.
*
* <p>Created via the {@link HttpComponentsAsyncClientHttpRequest}.
*
* @author Oleg Kalnichevski
* @author Arjen Poutsma
* @since 4.0
* @see HttpComponentsAsyncClientHttpRequest#executeAsync()
* @deprecated as of Spring 5.0, in favor of
* {@link org.springframework.http.client.reactive.HttpComponentsClientHttpConnector}
*/
@Deprecated
final class HttpComponentsAsyncClientHttpResponse extends AbstractClientHttpResponse {
private final HttpResponse httpResponse;
@Nullable
private HttpHeaders headers;
HttpComponentsAsyncClientHttpResponse(HttpResponse httpResponse) {
this.httpResponse = httpResponse;
}
@Override
public int getRawStatusCode() throws IOException {
return this.httpResponse.getStatusLine().getStatusCode();
}
@Override
public String getStatusText() throws IOException {
return this.httpResponse.getStatusLine().getReasonPhrase();
}
@Override
public HttpHeaders getHeaders() {
if (this.headers == null) {
this.headers = new HttpHeaders();
for (Header header : this.httpResponse.getAllHeaders()) {
this.headers.add(header.getName(), header.getValue());
}
}
return this.headers;
}
@Override
public InputStream getBody() throws IOException {
HttpEntity entity = this.httpResponse.getEntity();
return (entity != null ? entity.getContent() : StreamUtils.emptyInput());
}
@Override
public void close() {
// HTTP responses returned by async HTTP client are not bound to an
// active connection and do not have to deallocate any resources...
}
}

View File

@@ -1,125 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.http.client;
import java.io.IOException;
import java.net.URI;
import java.util.Iterator;
import java.util.List;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest;
import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;
import org.springframework.util.concurrent.ListenableFuture;
/**
* An {@link AsyncClientHttpRequest} wrapper that enriches it proceeds the actual
* request execution with calling the registered interceptors.
*
* @author Jakub Narloch
* @author Rossen Stoyanchev
* @see InterceptingAsyncClientHttpRequestFactory
* @deprecated as of Spring 5.0, with no direct replacement
*/
@Deprecated
class InterceptingAsyncClientHttpRequest extends AbstractBufferingAsyncClientHttpRequest {
private AsyncClientHttpRequestFactory requestFactory;
private List<AsyncClientHttpRequestInterceptor> interceptors;
private URI uri;
private HttpMethod httpMethod;
/**
* Create new instance of {@link InterceptingAsyncClientHttpRequest}.
* @param requestFactory the async request factory
* @param interceptors the list of interceptors
* @param uri the request URI
* @param httpMethod the HTTP method
*/
public InterceptingAsyncClientHttpRequest(AsyncClientHttpRequestFactory requestFactory,
List<AsyncClientHttpRequestInterceptor> interceptors, URI uri, HttpMethod httpMethod) {
this.requestFactory = requestFactory;
this.interceptors = interceptors;
this.uri = uri;
this.httpMethod = httpMethod;
}
@Override
protected ListenableFuture<ClientHttpResponse> executeInternal(HttpHeaders headers, byte[] body)
throws IOException {
return new AsyncRequestExecution().executeAsync(this, body);
}
@Override
public HttpMethod getMethod() {
return this.httpMethod;
}
@Override
public String getMethodValue() {
return this.httpMethod.name();
}
@Override
public URI getURI() {
return this.uri;
}
private class AsyncRequestExecution implements AsyncClientHttpRequestExecution {
private Iterator<AsyncClientHttpRequestInterceptor> iterator;
public AsyncRequestExecution() {
this.iterator = interceptors.iterator();
}
@Override
public ListenableFuture<ClientHttpResponse> executeAsync(HttpRequest request, byte[] body)
throws IOException {
if (this.iterator.hasNext()) {
AsyncClientHttpRequestInterceptor interceptor = this.iterator.next();
return interceptor.intercept(request, body, this);
}
else {
URI uri = request.getURI();
HttpMethod method = request.getMethod();
HttpHeaders headers = request.getHeaders();
Assert.state(method != null, "No standard HTTP method");
AsyncClientHttpRequest delegate = requestFactory.createAsyncRequest(uri, method);
delegate.getHeaders().putAll(headers);
if (body.length > 0) {
StreamUtils.copy(body, delegate.getBody());
}
return delegate.executeAsync();
}
}
}
}

View File

@@ -1,62 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.http.client;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import org.springframework.http.HttpMethod;
import org.springframework.lang.Nullable;
/**
* Wrapper for a {@link AsyncClientHttpRequestFactory} that has support for
* {@link AsyncClientHttpRequestInterceptor AsyncClientHttpRequestInterceptors}.
*
* @author Jakub Narloch
* @since 4.3
* @see InterceptingAsyncClientHttpRequest
* @deprecated as of Spring 5.0, with no direct replacement
*/
@Deprecated
public class InterceptingAsyncClientHttpRequestFactory implements AsyncClientHttpRequestFactory {
private AsyncClientHttpRequestFactory delegate;
private List<AsyncClientHttpRequestInterceptor> interceptors;
/**
* Create new instance of {@link InterceptingAsyncClientHttpRequestFactory}
* with delegated request factory and list of interceptors.
* @param delegate the request factory to delegate to
* @param interceptors the list of interceptors to use
*/
public InterceptingAsyncClientHttpRequestFactory(AsyncClientHttpRequestFactory delegate,
@Nullable List<AsyncClientHttpRequestInterceptor> interceptors) {
this.delegate = delegate;
this.interceptors = (interceptors != null ? interceptors : Collections.emptyList());
}
@Override
public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod method) {
return new InterceptingAsyncClientHttpRequest(this.delegate, this.interceptors, uri, method);
}
}

View File

@@ -1,187 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.http.client;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.util.concurrent.ExecutionException;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBufOutputStream;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpVersion;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.SettableListenableFuture;
/**
* {@link ClientHttpRequest} implementation based on Netty 4.
*
* <p>Created via the {@link Netty4ClientHttpRequestFactory}.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @author Brian Clozel
* @since 4.1.2
* @deprecated as of Spring 5.0, in favor of
* {@link org.springframework.http.client.reactive.ReactorClientHttpConnector}
*/
@Deprecated
class Netty4ClientHttpRequest extends AbstractAsyncClientHttpRequest implements ClientHttpRequest {
private final Bootstrap bootstrap;
private final URI uri;
private final HttpMethod method;
private final ByteBufOutputStream body;
public Netty4ClientHttpRequest(Bootstrap bootstrap, URI uri, HttpMethod method) {
this.bootstrap = bootstrap;
this.uri = uri;
this.method = method;
this.body = new ByteBufOutputStream(Unpooled.buffer(1024));
}
@Override
public HttpMethod getMethod() {
return this.method;
}
@Override
public String getMethodValue() {
return this.method.name();
}
@Override
public URI getURI() {
return this.uri;
}
@Override
public ClientHttpResponse execute() throws IOException {
try {
return executeAsync().get();
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IOException("Interrupted during request execution", ex);
}
catch (ExecutionException ex) {
if (ex.getCause() instanceof IOException) {
throw (IOException) ex.getCause();
}
else {
throw new IOException(ex.getMessage(), ex.getCause());
}
}
}
@Override
protected OutputStream getBodyInternal(HttpHeaders headers) throws IOException {
return this.body;
}
@Override
protected ListenableFuture<ClientHttpResponse> executeInternal(final HttpHeaders headers) throws IOException {
final SettableListenableFuture<ClientHttpResponse> responseFuture = new SettableListenableFuture<>();
ChannelFutureListener connectionListener = future -> {
if (future.isSuccess()) {
Channel channel = future.channel();
channel.pipeline().addLast(new RequestExecuteHandler(responseFuture));
FullHttpRequest nettyRequest = createFullHttpRequest(headers);
channel.writeAndFlush(nettyRequest);
}
else {
responseFuture.setException(future.cause());
}
};
this.bootstrap.connect(this.uri.getHost(), getPort(this.uri)).addListener(connectionListener);
return responseFuture;
}
private FullHttpRequest createFullHttpRequest(HttpHeaders headers) {
io.netty.handler.codec.http.HttpMethod nettyMethod =
io.netty.handler.codec.http.HttpMethod.valueOf(this.method.name());
String authority = this.uri.getRawAuthority();
String path = this.uri.toString().substring(this.uri.toString().indexOf(authority) + authority.length());
FullHttpRequest nettyRequest = new DefaultFullHttpRequest(
HttpVersion.HTTP_1_1, nettyMethod, path, this.body.buffer());
nettyRequest.headers().set(HttpHeaders.HOST, this.uri.getHost() + ":" + getPort(this.uri));
nettyRequest.headers().set(HttpHeaders.CONNECTION, "close");
headers.forEach((headerName, headerValues) -> nettyRequest.headers().add(headerName, headerValues));
if (!nettyRequest.headers().contains(HttpHeaders.CONTENT_LENGTH) && this.body.buffer().readableBytes() > 0) {
nettyRequest.headers().set(HttpHeaders.CONTENT_LENGTH, this.body.buffer().readableBytes());
}
return nettyRequest;
}
private static int getPort(URI uri) {
int port = uri.getPort();
if (port == -1) {
if ("http".equalsIgnoreCase(uri.getScheme())) {
port = 80;
}
else if ("https".equalsIgnoreCase(uri.getScheme())) {
port = 443;
}
}
return port;
}
/**
* A SimpleChannelInboundHandler to update the given SettableListenableFuture.
*/
private static class RequestExecuteHandler extends SimpleChannelInboundHandler<FullHttpResponse> {
private final SettableListenableFuture<ClientHttpResponse> responseFuture;
public RequestExecuteHandler(SettableListenableFuture<ClientHttpResponse> responseFuture) {
this.responseFuture = responseFuture;
}
@Override
protected void channelRead0(ChannelHandlerContext context, FullHttpResponse response) throws Exception {
this.responseFuture.set(new Netty4ClientHttpResponse(context, response));
}
@Override
public void exceptionCaught(ChannelHandlerContext context, Throwable cause) throws Exception {
this.responseFuture.setException(cause);
}
}
}

View File

@@ -1,243 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.http.client;
import java.io.IOException;
import java.net.URI;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLException;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.SocketChannelConfig;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.timeout.ReadTimeoutHandler;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.HttpMethod;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* {@link org.springframework.http.client.ClientHttpRequestFactory} implementation
* that uses <a href="https://netty.io/">Netty 4</a> to create requests.
*
* <p>Allows to use a pre-configured {@link EventLoopGroup} instance: useful for
* sharing across multiple clients.
*
* <p>Note that this implementation consistently closes the HTTP connection on each
* request.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @author Brian Clozel
* @author Mark Paluch
* @since 4.1.2
* @deprecated as of Spring 5.0, in favor of
* {@link org.springframework.http.client.reactive.ReactorClientHttpConnector}
*/
@Deprecated
public class Netty4ClientHttpRequestFactory implements ClientHttpRequestFactory,
AsyncClientHttpRequestFactory, InitializingBean, DisposableBean {
/**
* The default maximum response size.
* @see #setMaxResponseSize(int)
*/
public static final int DEFAULT_MAX_RESPONSE_SIZE = 1024 * 1024 * 10;
private final EventLoopGroup eventLoopGroup;
private final boolean defaultEventLoopGroup;
private int maxResponseSize = DEFAULT_MAX_RESPONSE_SIZE;
@Nullable
private SslContext sslContext;
private int connectTimeout = -1;
private int readTimeout = -1;
@Nullable
private volatile Bootstrap bootstrap;
/**
* Create a new {@code Netty4ClientHttpRequestFactory} with a default
* {@link NioEventLoopGroup}.
*/
public Netty4ClientHttpRequestFactory() {
int ioWorkerCount = Runtime.getRuntime().availableProcessors() * 2;
this.eventLoopGroup = new NioEventLoopGroup(ioWorkerCount);
this.defaultEventLoopGroup = true;
}
/**
* Create a new {@code Netty4ClientHttpRequestFactory} with the given
* {@link EventLoopGroup}.
* <p><b>NOTE:</b> the given group will <strong>not</strong> be
* {@linkplain EventLoopGroup#shutdownGracefully() shutdown} by this factory;
* doing so becomes the responsibility of the caller.
*/
public Netty4ClientHttpRequestFactory(EventLoopGroup eventLoopGroup) {
Assert.notNull(eventLoopGroup, "EventLoopGroup must not be null");
this.eventLoopGroup = eventLoopGroup;
this.defaultEventLoopGroup = false;
}
/**
* Set the default maximum response size.
* <p>By default this is set to {@link #DEFAULT_MAX_RESPONSE_SIZE}.
* @since 4.1.5
* @see HttpObjectAggregator#HttpObjectAggregator(int)
*/
public void setMaxResponseSize(int maxResponseSize) {
this.maxResponseSize = maxResponseSize;
}
/**
* Set the SSL context. When configured it is used to create and insert an
* {@link io.netty.handler.ssl.SslHandler} in the channel pipeline.
* <p>A default client SslContext is configured if none has been provided.
*/
public void setSslContext(SslContext sslContext) {
this.sslContext = sslContext;
}
/**
* Set the underlying connect timeout (in milliseconds).
* A timeout value of 0 specifies an infinite timeout.
* @see ChannelConfig#setConnectTimeoutMillis(int)
*/
public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
}
/**
* Set the underlying URLConnection's read timeout (in milliseconds).
* A timeout value of 0 specifies an infinite timeout.
* @see ReadTimeoutHandler
*/
public void setReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
}
@Override
public void afterPropertiesSet() {
if (this.sslContext == null) {
this.sslContext = getDefaultClientSslContext();
}
}
private SslContext getDefaultClientSslContext() {
try {
return SslContextBuilder.forClient().build();
}
catch (SSLException ex) {
throw new IllegalStateException("Could not create default client SslContext", ex);
}
}
@Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
return createRequestInternal(uri, httpMethod);
}
@Override
public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) throws IOException {
return createRequestInternal(uri, httpMethod);
}
private Netty4ClientHttpRequest createRequestInternal(URI uri, HttpMethod httpMethod) {
return new Netty4ClientHttpRequest(getBootstrap(uri), uri, httpMethod);
}
private Bootstrap getBootstrap(URI uri) {
boolean isSecure = (uri.getPort() == 443 || "https".equalsIgnoreCase(uri.getScheme()));
if (isSecure) {
return buildBootstrap(uri, true);
}
else {
Bootstrap bootstrap = this.bootstrap;
if (bootstrap == null) {
bootstrap = buildBootstrap(uri, false);
this.bootstrap = bootstrap;
}
return bootstrap;
}
}
private Bootstrap buildBootstrap(URI uri, boolean isSecure) {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(this.eventLoopGroup).channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
configureChannel(channel.config());
ChannelPipeline pipeline = channel.pipeline();
if (isSecure) {
Assert.notNull(sslContext, "sslContext should not be null");
pipeline.addLast(sslContext.newHandler(channel.alloc(), uri.getHost(), uri.getPort()));
}
pipeline.addLast(new HttpClientCodec());
pipeline.addLast(new HttpObjectAggregator(maxResponseSize));
if (readTimeout > 0) {
pipeline.addLast(new ReadTimeoutHandler(readTimeout,
TimeUnit.MILLISECONDS));
}
}
});
return bootstrap;
}
/**
* Template method for changing properties on the given {@link SocketChannelConfig}.
* <p>The default implementation sets the connect timeout based on the set property.
* @param config the channel configuration
*/
protected void configureChannel(SocketChannelConfig config) {
if (this.connectTimeout >= 0) {
config.setConnectTimeoutMillis(this.connectTimeout);
}
}
@Override
public void destroy() throws InterruptedException {
if (this.defaultEventLoopGroup) {
// Clean up the EventLoopGroup if we created it in the constructor
this.eventLoopGroup.shutdownGracefully().sync();
}
}
}

View File

@@ -1,96 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.http.client;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import io.netty.buffer.ByteBufInputStream;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpResponse;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* {@link ClientHttpResponse} implementation based on Netty 4.
*
* @author Arjen Poutsma
* @since 4.1.2
* @deprecated as of Spring 5.0, in favor of
* {@link org.springframework.http.client.reactive.ReactorClientHttpConnector}
*/
@Deprecated
class Netty4ClientHttpResponse extends AbstractClientHttpResponse {
private final ChannelHandlerContext context;
private final FullHttpResponse nettyResponse;
private final ByteBufInputStream body;
@Nullable
private volatile HttpHeaders headers;
public Netty4ClientHttpResponse(ChannelHandlerContext context, FullHttpResponse nettyResponse) {
Assert.notNull(context, "ChannelHandlerContext must not be null");
Assert.notNull(nettyResponse, "FullHttpResponse must not be null");
this.context = context;
this.nettyResponse = nettyResponse;
this.body = new ByteBufInputStream(this.nettyResponse.content());
this.nettyResponse.retain();
}
@Override
public int getRawStatusCode() throws IOException {
return this.nettyResponse.getStatus().code();
}
@Override
public String getStatusText() throws IOException {
return this.nettyResponse.getStatus().reasonPhrase();
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = this.headers;
if (headers == null) {
headers = new HttpHeaders();
for (Map.Entry<String, String> entry : this.nettyResponse.headers()) {
headers.add(entry.getKey(), entry.getValue());
}
this.headers = headers;
}
return headers;
}
@Override
public InputStream getBody() throws IOException {
return this.body;
}
@Override
public void close() {
this.nettyResponse.release();
this.context.close();
}
}

View File

@@ -1,109 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.http.client;
import java.io.IOException;
import java.net.URI;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.SettableListenableFuture;
/**
* {@link AsyncClientHttpRequest} implementation based on OkHttp 3.x.
*
* <p>Created via the {@link OkHttp3ClientHttpRequestFactory}.
*
* @author Luciano Leggieri
* @author Arjen Poutsma
* @author Roy Clarkson
* @since 4.3
* @deprecated as of Spring 5.0, with no direct replacement
*/
@Deprecated
class OkHttp3AsyncClientHttpRequest extends AbstractBufferingAsyncClientHttpRequest {
private final OkHttpClient client;
private final URI uri;
private final HttpMethod method;
public OkHttp3AsyncClientHttpRequest(OkHttpClient client, URI uri, HttpMethod method) {
this.client = client;
this.uri = uri;
this.method = method;
}
@Override
public HttpMethod getMethod() {
return this.method;
}
@Override
public String getMethodValue() {
return this.method.name();
}
@Override
public URI getURI() {
return this.uri;
}
@Override
protected ListenableFuture<ClientHttpResponse> executeInternal(HttpHeaders headers, byte[] content)
throws IOException {
Request request = OkHttp3ClientHttpRequestFactory.buildRequest(headers, content, this.uri, this.method);
return new OkHttpListenableFuture(this.client.newCall(request));
}
private static class OkHttpListenableFuture extends SettableListenableFuture<ClientHttpResponse> {
private final Call call;
public OkHttpListenableFuture(Call call) {
this.call = call;
this.call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
set(new OkHttp3ClientHttpResponse(response));
}
@Override
public void onFailure(Call call, IOException ex) {
setException(ex);
}
});
}
@Override
protected void interruptTask() {
this.call.cancel();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 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.
@@ -42,9 +42,7 @@ import org.springframework.util.StringUtils;
* @author Roy Clarkson
* @since 4.3
*/
@SuppressWarnings("deprecation")
public class OkHttp3ClientHttpRequestFactory
implements ClientHttpRequestFactory, AsyncClientHttpRequestFactory, DisposableBean {
public class OkHttp3ClientHttpRequestFactory implements ClientHttpRequestFactory, DisposableBean {
private OkHttpClient client;
@@ -106,11 +104,6 @@ public class OkHttp3ClientHttpRequestFactory
return new OkHttp3ClientHttpRequest(this.client, uri, httpMethod);
}
@Override
public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) {
return new OkHttp3AsyncClientHttpRequest(this.client, uri, httpMethod);
}
@Override
public void destroy() throws IOException {

View File

@@ -1,99 +0,0 @@
/*
* Copyright 2002-2021 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
*
* https://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.http.client;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import org.springframework.core.task.AsyncListenableTaskExecutor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.concurrent.ListenableFuture;
/**
* {@link org.springframework.http.client.ClientHttpRequest} implementation that uses
* standard JDK facilities to execute buffered requests. Created via the
* {@link org.springframework.http.client.SimpleClientHttpRequestFactory}.
*
* @author Arjen Poutsma
* @since 3.0
* @see org.springframework.http.client.SimpleClientHttpRequestFactory#createRequest
* @deprecated as of Spring 5.0, with no direct replacement
*/
@Deprecated
final class SimpleBufferingAsyncClientHttpRequest extends AbstractBufferingAsyncClientHttpRequest {
private final HttpURLConnection connection;
private final boolean outputStreaming;
private final AsyncListenableTaskExecutor taskExecutor;
SimpleBufferingAsyncClientHttpRequest(HttpURLConnection connection,
boolean outputStreaming, AsyncListenableTaskExecutor taskExecutor) {
this.connection = connection;
this.outputStreaming = outputStreaming;
this.taskExecutor = taskExecutor;
}
@Override
public String getMethodValue() {
return this.connection.getRequestMethod();
}
@Override
public URI getURI() {
try {
return this.connection.getURL().toURI();
}
catch (URISyntaxException ex) {
throw new IllegalStateException("Could not get HttpURLConnection URI: " + ex.getMessage(), ex);
}
}
@Override
protected ListenableFuture<ClientHttpResponse> executeInternal(
HttpHeaders headers, byte[] bufferedOutput) throws IOException {
return this.taskExecutor.submitListenable(() -> {
SimpleBufferingClientHttpRequest.addHeaders(this.connection, headers);
// JDK <1.8 doesn't support getOutputStream with HTTP DELETE
if (getMethod() == HttpMethod.DELETE && bufferedOutput.length == 0) {
this.connection.setDoOutput(false);
}
if (this.connection.getDoOutput() && this.outputStreaming) {
this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
}
this.connection.connect();
if (this.connection.getDoOutput()) {
FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());
}
else {
// Immediately trigger the request in a no-output scenario as well
this.connection.getResponseCode();
}
return new SimpleClientHttpResponse(this.connection);
});
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2021 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.
@@ -23,10 +23,8 @@ import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import org.springframework.core.task.AsyncListenableTaskExecutor;
import org.springframework.http.HttpMethod;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* {@link ClientHttpRequestFactory} implementation that uses standard JDK facilities.
@@ -37,8 +35,7 @@ import org.springframework.util.Assert;
* @see java.net.HttpURLConnection
* @see HttpComponentsClientHttpRequestFactory
*/
@SuppressWarnings("deprecation")
public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory, AsyncClientHttpRequestFactory {
public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory {
private static final int DEFAULT_CHUNK_SIZE = 4096;
@@ -56,9 +53,6 @@ public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory,
private boolean outputStreaming = true;
@Nullable
private AsyncListenableTaskExecutor taskExecutor;
/**
* Set the {@link Proxy} to use for this request factory.
@@ -130,15 +124,6 @@ public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory,
this.outputStreaming = outputStreaming;
}
/**
* Set the task executor for this request factory. Setting this property is required
* for {@linkplain #createAsyncRequest(URI, HttpMethod) creating asynchronous requests}.
* @param taskExecutor the task executor
*/
public void setTaskExecutor(AsyncListenableTaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
@Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
@@ -153,27 +138,6 @@ public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory,
}
}
/**
* {@inheritDoc}
* <p>Setting the {@link #setTaskExecutor taskExecutor} property is required before calling this method.
*/
@Override
public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) throws IOException {
Assert.state(this.taskExecutor != null, "Asynchronous execution requires TaskExecutor to be set");
HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);
prepareConnection(connection, httpMethod.name());
if (this.bufferRequestBody) {
return new SimpleBufferingAsyncClientHttpRequest(
connection, this.outputStreaming, this.taskExecutor);
}
else {
return new SimpleStreamingAsyncClientHttpRequest(
connection, this.chunkSize, this.outputStreaming, this.taskExecutor);
}
}
/**
* Opens and returns a connection to the given URL.
* <p>The default implementation uses the given {@linkplain #setProxy(java.net.Proxy) proxy} -

View File

@@ -1,125 +0,0 @@
/*
* Copyright 2002-2020 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
*
* https://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.http.client;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import org.springframework.core.task.AsyncListenableTaskExecutor;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.util.StreamUtils;
import org.springframework.util.concurrent.ListenableFuture;
/**
* {@link org.springframework.http.client.ClientHttpRequest} implementation
* that uses standard Java facilities to execute streaming requests. Created
* via the {@link org.springframework.http.client.SimpleClientHttpRequestFactory}.
*
* @author Arjen Poutsma
* @since 3.0
* @see org.springframework.http.client.SimpleClientHttpRequestFactory#createRequest
* @see org.springframework.http.client.support.AsyncHttpAccessor
* @see org.springframework.web.client.AsyncRestTemplate
* @deprecated as of Spring 5.0, with no direct replacement
*/
@Deprecated
final class SimpleStreamingAsyncClientHttpRequest extends AbstractAsyncClientHttpRequest {
private final HttpURLConnection connection;
private final int chunkSize;
@Nullable
private OutputStream body;
private final boolean outputStreaming;
private final AsyncListenableTaskExecutor taskExecutor;
SimpleStreamingAsyncClientHttpRequest(HttpURLConnection connection, int chunkSize,
boolean outputStreaming, AsyncListenableTaskExecutor taskExecutor) {
this.connection = connection;
this.chunkSize = chunkSize;
this.outputStreaming = outputStreaming;
this.taskExecutor = taskExecutor;
}
@Override
public String getMethodValue() {
return this.connection.getRequestMethod();
}
@Override
public URI getURI() {
try {
return this.connection.getURL().toURI();
}
catch (URISyntaxException ex) {
throw new IllegalStateException(
"Could not get HttpURLConnection URI: " + ex.getMessage(), ex);
}
}
@Override
protected OutputStream getBodyInternal(HttpHeaders headers) throws IOException {
if (this.body == null) {
if (this.outputStreaming) {
long contentLength = headers.getContentLength();
if (contentLength >= 0) {
this.connection.setFixedLengthStreamingMode(contentLength);
}
else {
this.connection.setChunkedStreamingMode(this.chunkSize);
}
}
SimpleBufferingClientHttpRequest.addHeaders(this.connection, headers);
this.connection.connect();
this.body = this.connection.getOutputStream();
}
return StreamUtils.nonClosing(this.body);
}
@Override
protected ListenableFuture<ClientHttpResponse> executeInternal(HttpHeaders headers) throws IOException {
return this.taskExecutor.submitListenable(() -> {
try {
if (this.body != null) {
this.body.close();
}
else {
SimpleBufferingClientHttpRequest.addHeaders(this.connection, headers);
this.connection.connect();
// Immediately trigger the request in a no-output scenario as well
this.connection.getResponseCode();
}
}
catch (IOException ex) {
// ignore
}
return new SimpleClientHttpResponse(this.connection);
});
}
}

View File

@@ -1,92 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.http.client.support;
import java.io.IOException;
import java.net.URI;
import org.apache.commons.logging.Log;
import org.springframework.http.HttpLogging;
import org.springframework.http.HttpMethod;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Base class for {@link org.springframework.web.client.AsyncRestTemplate}
* and other HTTP accessing gateway helpers, defining common properties
* such as the {@link org.springframework.http.client.AsyncClientHttpRequestFactory}
* to operate on.
*
* <p>Not intended to be used directly. See
* {@link org.springframework.web.client.AsyncRestTemplate}.
*
* @author Arjen Poutsma
* @since 4.0
* @see org.springframework.web.client.AsyncRestTemplate
* @deprecated as of Spring 5.0, with no direct replacement
*/
@Deprecated
public class AsyncHttpAccessor {
/** Logger available to subclasses. */
protected final Log logger = HttpLogging.forLogName(getClass());
@Nullable
private org.springframework.http.client.AsyncClientHttpRequestFactory asyncRequestFactory;
/**
* Set the request factory that this accessor uses for obtaining {@link
* org.springframework.http.client.ClientHttpRequest HttpRequests}.
*/
public void setAsyncRequestFactory(
org.springframework.http.client.AsyncClientHttpRequestFactory asyncRequestFactory) {
Assert.notNull(asyncRequestFactory, "AsyncClientHttpRequestFactory must not be null");
this.asyncRequestFactory = asyncRequestFactory;
}
/**
* Return the request factory that this accessor uses for obtaining {@link
* org.springframework.http.client.ClientHttpRequest HttpRequests}.
*/
public org.springframework.http.client.AsyncClientHttpRequestFactory getAsyncRequestFactory() {
Assert.state(this.asyncRequestFactory != null, "No AsyncClientHttpRequestFactory set");
return this.asyncRequestFactory;
}
/**
* Create a new {@link org.springframework.http.client.AsyncClientHttpRequest} via this template's
* {@link org.springframework.http.client.AsyncClientHttpRequestFactory}.
* @param url the URL to connect to
* @param method the HTTP method to execute (GET, POST, etc.)
* @return the created request
* @throws IOException in case of I/O errors
*/
protected org.springframework.http.client.AsyncClientHttpRequest createAsyncRequest(URI url, HttpMethod method)
throws IOException {
org.springframework.http.client.AsyncClientHttpRequest request =
getAsyncRequestFactory().createAsyncRequest(url, method);
if (logger.isDebugEnabled()) {
logger.debug("Created asynchronous " + method.name() + " request for \"" + url + "\"");
}
return request;
}
}

View File

@@ -1,67 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.http.client.support;
import java.util.ArrayList;
import java.util.List;
import org.springframework.util.CollectionUtils;
/**
* The HTTP accessor that extends the base {@link AsyncHttpAccessor} with
* request intercepting functionality.
*
* @author Jakub Narloch
* @author Rossen Stoyanchev
* @since 4.3
* @deprecated as of Spring 5.0, with no direct replacement
*/
@Deprecated
public abstract class InterceptingAsyncHttpAccessor extends AsyncHttpAccessor {
private List<org.springframework.http.client.AsyncClientHttpRequestInterceptor> interceptors =
new ArrayList<>();
/**
* Set the request interceptors that this accessor should use.
* @param interceptors the list of interceptors
*/
public void setInterceptors(List<org.springframework.http.client.AsyncClientHttpRequestInterceptor> interceptors) {
this.interceptors = interceptors;
}
/**
* Return the request interceptor that this accessor uses.
*/
public List<org.springframework.http.client.AsyncClientHttpRequestInterceptor> getInterceptors() {
return this.interceptors;
}
@Override
public org.springframework.http.client.AsyncClientHttpRequestFactory getAsyncRequestFactory() {
org.springframework.http.client.AsyncClientHttpRequestFactory delegate = super.getAsyncRequestFactory();
if (!CollectionUtils.isEmpty(getInterceptors())) {
return new org.springframework.http.client.InterceptingAsyncClientHttpRequestFactory(delegate, getInterceptors());
}
else {
return delegate;
}
}
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2002-2021 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
*
* https://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.web.client;
import java.io.IOException;
/**
* Callback interface for code that operates on an
* {@link org.springframework.http.client.AsyncClientHttpRequest}. Allows to
* manipulate the request headers, and write to the request body.
*
* <p>Used internally by the {@link AsyncRestTemplate}, but also useful for
* application code.
*
* @author Arjen Poutsma
* @since 4.0
* @see org.springframework.web.client.AsyncRestTemplate#execute
* @deprecated as of Spring 5.0, in favor of
* {@link org.springframework.web.reactive.function.client.ExchangeFilterFunction}
*/
@FunctionalInterface
@Deprecated
public interface AsyncRequestCallback {
/**
* Gets called by {@link AsyncRestTemplate#execute} with an opened {@code ClientHttpRequest}.
* Does not need to care about closing the request or about handling errors:
* this will all be handled by the {@code RestTemplate}.
* @param request the active HTTP request
* @throws java.io.IOException in case of I/O errors
*/
void doWithRequest(org.springframework.http.client.AsyncClientHttpRequest request) throws IOException;
}

View File

@@ -1,464 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.web.client;
import java.net.URI;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.Nullable;
import org.springframework.util.concurrent.ListenableFuture;
/**
* Interface specifying a basic set of asynchronous RESTful operations.
* Implemented by {@link AsyncRestTemplate}. Not often used directly, but a useful
* option to enhance testability, as it can easily be mocked or stubbed.
*
* @author Arjen Poutsma
* @since 4.0
* @see AsyncRestTemplate
* @see RestOperations
* @deprecated as of Spring 5.0, in favor of {@link org.springframework.web.reactive.function.client.WebClient}
*/
@Deprecated
public interface AsyncRestOperations {
/**
* Expose the synchronous Spring RestTemplate to allow synchronous invocation.
*/
RestOperations getRestOperations();
// GET
/**
* Asynchronously retrieve an entity by doing a GET on the specified URL.
* The response is converted and stored in an {@link ResponseEntity}.
* <p>URI Template variables are expanded using the given URI variables, if any.
* @param url the URL
* @param responseType the type of the return value
* @param uriVariables the variables to expand the template
* @return the entity wrapped in a {@link Future}
*/
<T> ListenableFuture<ResponseEntity<T>> getForEntity(String url, Class<T> responseType,
Object... uriVariables) throws RestClientException;
/**
* Asynchronously retrieve a representation by doing a GET on the URI template.
* The response is converted and stored in an {@link ResponseEntity}.
* <p>URI Template variables are expanded using the given map.
* @param url the URL
* @param responseType the type of the return value
* @param uriVariables the map containing variables for the URI template
* @return the entity wrapped in a {@link Future}
*/
<T> ListenableFuture<ResponseEntity<T>> getForEntity(String url, Class<T> responseType,
Map<String, ?> uriVariables) throws RestClientException;
/**
* Asynchronously retrieve a representation by doing a GET on the URL.
* The response is converted and stored in an {@link ResponseEntity}.
* @param url the URL
* @param responseType the type of the return value
* @return the entity wrapped in a {@link Future}
*/
<T> ListenableFuture<ResponseEntity<T>> getForEntity(URI url, Class<T> responseType)
throws RestClientException;
// HEAD
/**
* Asynchronously retrieve all headers of the resource specified by the URI template.
* <p>URI Template variables are expanded using the given URI variables, if any.
* @param url the URL
* @param uriVariables the variables to expand the template
* @return all HTTP headers of that resource wrapped in a {@link Future}
*/
ListenableFuture<HttpHeaders> headForHeaders(String url, Object... uriVariables)
throws RestClientException;
/**
* Asynchronously retrieve all headers of the resource specified by the URI template.
* <p>URI Template variables are expanded using the given map.
* @param url the URL
* @param uriVariables the map containing variables for the URI template
* @return all HTTP headers of that resource wrapped in a {@link Future}
*/
ListenableFuture<HttpHeaders> headForHeaders(String url, Map<String, ?> uriVariables)
throws RestClientException;
/**
* Asynchronously retrieve all headers of the resource specified by the URL.
* @param url the URL
* @return all HTTP headers of that resource wrapped in a {@link Future}
*/
ListenableFuture<HttpHeaders> headForHeaders(URI url) throws RestClientException;
// POST
/**
* Create a new resource by POSTing the given object to the URI template, and
* asynchronously returns the value of the {@code Location} header. This header
* typically indicates where the new resource is stored.
* <p>URI Template variables are expanded using the given URI variables, if any.
* @param url the URL
* @param request the Object to be POSTed (may be {@code null})
* @param uriVariables the variables to expand the template
* @return the value for the {@code Location} header wrapped in a {@link Future}
* @see org.springframework.http.HttpEntity
*/
ListenableFuture<URI> postForLocation(String url, @Nullable HttpEntity<?> request, Object... uriVariables)
throws RestClientException;
/**
* Create a new resource by POSTing the given object to the URI template, and
* asynchronously returns the value of the {@code Location} header. This header
* typically indicates where the new resource is stored.
* <p>URI Template variables are expanded using the given map.
* @param url the URL
* @param request the Object to be POSTed (may be {@code null})
* @param uriVariables the variables to expand the template
* @return the value for the {@code Location} header wrapped in a {@link Future}
* @see org.springframework.http.HttpEntity
*/
ListenableFuture<URI> postForLocation(String url, @Nullable HttpEntity<?> request, Map<String, ?> uriVariables)
throws RestClientException;
/**
* Create a new resource by POSTing the given object to the URL, and asynchronously
* returns the value of the {@code Location} header. This header typically indicates
* where the new resource is stored.
* @param url the URL
* @param request the Object to be POSTed (may be {@code null})
* @return the value for the {@code Location} header wrapped in a {@link Future}
* @see org.springframework.http.HttpEntity
*/
ListenableFuture<URI> postForLocation(URI url, @Nullable HttpEntity<?> request) throws RestClientException;
/**
* Create a new resource by POSTing the given object to the URI template,
* and asynchronously returns the response as {@link ResponseEntity}.
* <p>URI Template variables are expanded using the given URI variables, if any.
* @param url the URL
* @param request the Object to be POSTed (may be {@code null})
* @param uriVariables the variables to expand the template
* @return the entity wrapped in a {@link Future}
* @see org.springframework.http.HttpEntity
*/
<T> ListenableFuture<ResponseEntity<T>> postForEntity(String url, @Nullable HttpEntity<?> request,
Class<T> responseType, Object... uriVariables) throws RestClientException;
/**
* Create a new resource by POSTing the given object to the URI template,
* and asynchronously returns the response as {@link ResponseEntity}.
* <p>URI Template variables are expanded using the given map.
* @param url the URL
* @param request the Object to be POSTed (may be {@code null})
* @param uriVariables the variables to expand the template
* @return the entity wrapped in a {@link Future}
* @see org.springframework.http.HttpEntity
*/
<T> ListenableFuture<ResponseEntity<T>> postForEntity(String url, @Nullable HttpEntity<?> request,
Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;
/**
* Create a new resource by POSTing the given object to the URL,
* and asynchronously returns the response as {@link ResponseEntity}.
* @param url the URL
* @param request the Object to be POSTed (may be {@code null})
* @return the entity wrapped in a {@link Future}
* @see org.springframework.http.HttpEntity
*/
<T> ListenableFuture<ResponseEntity<T>> postForEntity(URI url, @Nullable HttpEntity<?> request,
Class<T> responseType) throws RestClientException;
// PUT
/**
* Create or update a resource by PUTting the given object to the URI.
* <p>URI Template variables are expanded using the given URI variables, if any.
* <p>The Future will return a {@code null} result upon completion.
* @param url the URL
* @param request the Object to be PUT (may be {@code null})
* @param uriVariables the variables to expand the template
* @see HttpEntity
*/
ListenableFuture<?> put(String url, @Nullable HttpEntity<?> request, Object... uriVariables)
throws RestClientException;
/**
* Creates a new resource by PUTting the given object to URI template.
* <p>URI Template variables are expanded using the given map.
* <p>The Future will return a {@code null} result upon completion.
* @param url the URL
* @param request the Object to be PUT (may be {@code null})
* @param uriVariables the variables to expand the template
* @see HttpEntity
*/
ListenableFuture<?> put(String url, @Nullable HttpEntity<?> request, Map<String, ?> uriVariables)
throws RestClientException;
/**
* Creates a new resource by PUTting the given object to URL.
* <p>The Future will return a {@code null} result upon completion.
* @param url the URL
* @param request the Object to be PUT (may be {@code null})
* @see HttpEntity
*/
ListenableFuture<?> put(URI url, @Nullable HttpEntity<?> request) throws RestClientException;
// DELETE
/**
* Asynchronously delete the resources at the specified URI.
* <p>URI Template variables are expanded using the given URI variables, if any.
* <p>The Future will return a {@code null} result upon completion.
* @param url the URL
* @param uriVariables the variables to expand in the template
*/
ListenableFuture<?> delete(String url, Object... uriVariables) throws RestClientException;
/**
* Asynchronously delete the resources at the specified URI.
* <p>URI Template variables are expanded using the given URI variables, if any.
* <p>The Future will return a {@code null} result upon completion.
* @param url the URL
* @param uriVariables the variables to expand in the template
*/
ListenableFuture<?> delete(String url, Map<String, ?> uriVariables) throws RestClientException;
/**
* Asynchronously delete the resources at the specified URI.
* <p>URI Template variables are expanded using the given URI variables, if any.
* <p>The Future will return a {@code null} result upon completion.
* @param url the URL
*/
ListenableFuture<?> delete(URI url) throws RestClientException;
// OPTIONS
/**
* Asynchronously return the value of the Allow header for the given URI.
* <p>URI Template variables are expanded using the given URI variables, if any.
* @param url the URL
* @param uriVariables the variables to expand in the template
* @return the value of the allow header wrapped in a {@link Future}
*/
ListenableFuture<Set<HttpMethod>> optionsForAllow(String url, Object... uriVariables)
throws RestClientException;
/**
* Asynchronously return the value of the Allow header for the given URI.
* <p>URI Template variables are expanded using the given map.
* @param url the URL
* @param uriVariables the variables to expand in the template
* @return the value of the allow header wrapped in a {@link Future}
*/
ListenableFuture<Set<HttpMethod>> optionsForAllow(String url, Map<String, ?> uriVariables)
throws RestClientException;
/**
* Asynchronously return the value of the Allow header for the given URL.
* @param url the URL
* @return the value of the allow header wrapped in a {@link Future}
*/
ListenableFuture<Set<HttpMethod>> optionsForAllow(URI url) throws RestClientException;
// exchange
/**
* Asynchronously execute the HTTP method to the given URI template, writing the
* given request entity to the request, and returns the response as
* {@link ResponseEntity}.
* <p>URI Template variables are expanded using the given URI variables, if any.
* @param url the URL
* @param method the HTTP method (GET, POST, etc)
* @param requestEntity the entity (headers and/or body) to write to the request
* (may be {@code null})
* @param responseType the type of the return value
* @param uriVariables the variables to expand in the template
* @return the response as entity wrapped in a {@link Future}
*/
<T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
@Nullable HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables)
throws RestClientException;
/**
* Asynchronously execute the HTTP method to the given URI template, writing the
* given request entity to the request, and returns the response as
* {@link ResponseEntity}.
* <p>URI Template variables are expanded using the given URI variables, if any.
* @param url the URL
* @param method the HTTP method (GET, POST, etc)
* @param requestEntity the entity (headers and/or body) to write to the request
* (may be {@code null})
* @param responseType the type of the return value
* @param uriVariables the variables to expand in the template
* @return the response as entity wrapped in a {@link Future}
*/
<T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
@Nullable HttpEntity<?> requestEntity, Class<T> responseType,
Map<String, ?> uriVariables) throws RestClientException;
/**
* Asynchronously execute the HTTP method to the given URI template, writing the
* given request entity to the request, and returns the response as
* {@link ResponseEntity}.
* @param url the URL
* @param method the HTTP method (GET, POST, etc)
* @param requestEntity the entity (headers and/or body) to write to the request
* (may be {@code null})
* @param responseType the type of the return value
* @return the response as entity wrapped in a {@link Future}
*/
<T> ListenableFuture<ResponseEntity<T>> exchange(URI url, HttpMethod method,
@Nullable HttpEntity<?> requestEntity, Class<T> responseType)
throws RestClientException;
/**
* Asynchronously execute the HTTP method to the given URI template, writing the given
* request entity to the request, and returns the response as {@link ResponseEntity}.
* The given {@link ParameterizedTypeReference} is used to pass generic type
* information:
* <pre class="code">
* ParameterizedTypeReference&lt;List&lt;MyBean&gt;&gt; myBean =
* new ParameterizedTypeReference&lt;List&lt;MyBean&gt;&gt;() {};
*
* ResponseEntity&lt;List&lt;MyBean&gt;&gt; response =
* template.exchange(&quot;https://example.com&quot;,HttpMethod.GET, null, myBean);
* </pre>
* @param url the URL
* @param method the HTTP method (GET, POST, etc)
* @param requestEntity the entity (headers and/or body) to write to the
* request (may be {@code null})
* @param responseType the type of the return value
* @param uriVariables the variables to expand in the template
* @return the response as entity wrapped in a {@link Future}
*/
<T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
@Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType,
Object... uriVariables) throws RestClientException;
/**
* Asynchronously execute the HTTP method to the given URI template, writing the given
* request entity to the request, and returns the response as {@link ResponseEntity}.
* The given {@link ParameterizedTypeReference} is used to pass generic type
* information:
* <pre class="code">
* ParameterizedTypeReference&lt;List&lt;MyBean&gt;&gt; myBean =
* new ParameterizedTypeReference&lt;List&lt;MyBean&gt;&gt;() {};
*
* ResponseEntity&lt;List&lt;MyBean&gt;&gt; response =
* template.exchange(&quot;https://example.com&quot;,HttpMethod.GET, null, myBean);
* </pre>
* @param url the URL
* @param method the HTTP method (GET, POST, etc)
* @param requestEntity the entity (headers and/or body) to write to the request
* (may be {@code null})
* @param responseType the type of the return value
* @param uriVariables the variables to expand in the template
* @return the response as entity wrapped in a {@link Future}
*/
<T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
@Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType,
Map<String, ?> uriVariables) throws RestClientException;
/**
* Asynchronously execute the HTTP method to the given URI template, writing the given
* request entity to the request, and returns the response as {@link ResponseEntity}.
* The given {@link ParameterizedTypeReference} is used to pass generic type
* information:
* <pre class="code">
* ParameterizedTypeReference&lt;List&lt;MyBean&gt;&gt; myBean =
* new ParameterizedTypeReference&lt;List&lt;MyBean&gt;&gt;() {};
*
* ResponseEntity&lt;List&lt;MyBean&gt;&gt; response =
* template.exchange(&quot;https://example.com&quot;,HttpMethod.GET, null, myBean);
* </pre>
* @param url the URL
* @param method the HTTP method (GET, POST, etc)
* @param requestEntity the entity (headers and/or body) to write to the request
* (may be {@code null})
* @param responseType the type of the return value
* @return the response as entity wrapped in a {@link Future}
*/
<T> ListenableFuture<ResponseEntity<T>> exchange(URI url, HttpMethod method,
@Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType)
throws RestClientException;
// general execution
/**
* Asynchronously execute the HTTP method to the given URI template, preparing the
* request with the {@link AsyncRequestCallback}, and reading the response with a
* {@link ResponseExtractor}.
* <p>URI Template variables are expanded using the given URI variables, if any.
* @param url the URL
* @param method the HTTP method (GET, POST, etc)
* @param requestCallback object that prepares the request
* @param responseExtractor object that extracts the return value from the response
* @param uriVariables the variables to expand in the template
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
*/
<T> ListenableFuture<T> execute(String url, HttpMethod method,
@Nullable AsyncRequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor,
Object... uriVariables) throws RestClientException;
/**
* Asynchronously execute the HTTP method to the given URI template, preparing the
* request with the {@link AsyncRequestCallback}, and reading the response with a
* {@link ResponseExtractor}.
* <p>URI Template variables are expanded using the given URI variables map.
* @param url the URL
* @param method the HTTP method (GET, POST, etc)
* @param requestCallback object that prepares the request
* @param responseExtractor object that extracts the return value from the response
* @param uriVariables the variables to expand in the template
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
*/
<T> ListenableFuture<T> execute(String url, HttpMethod method,
@Nullable AsyncRequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor,
Map<String, ?> uriVariables) throws RestClientException;
/**
* Asynchronously execute the HTTP method to the given URL, preparing the request
* with the {@link AsyncRequestCallback}, and reading the response with a
* {@link ResponseExtractor}.
* @param url the URL
* @param method the HTTP method (GET, POST, etc)
* @param requestCallback object that prepares the request
* @param responseExtractor object that extracts the return value from the response
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
*/
<T> ListenableFuture<T> execute(URI url, HttpMethod method,
@Nullable AsyncRequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor)
throws RestClientException;
}

View File

@@ -1,714 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.web.client;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.task.AsyncListenableTaskExecutor;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureAdapter;
import org.springframework.web.util.DefaultUriBuilderFactory;
import org.springframework.web.util.UriTemplateHandler;
/**
* <strong>Spring's central class for asynchronous client-side HTTP access.</strong>
* Exposes similar methods as {@link RestTemplate}, but returns {@link ListenableFuture}
* wrappers as opposed to concrete results.
*
* <p>The {@code AsyncRestTemplate} exposes a synchronous {@link RestTemplate} via the
* {@link #getRestOperations()} method and shares its {@linkplain #setErrorHandler error handler}
* and {@linkplain #setMessageConverters message converters} with that {@code RestTemplate}.
*
* <p><strong>Note:</strong> by default {@code AsyncRestTemplate} relies on
* standard JDK facilities to establish HTTP connections. You can switch to use
* a different HTTP library such as Apache HttpComponents, Netty, and OkHttp by
* using a constructor accepting an {@link org.springframework.http.client.AsyncClientHttpRequestFactory}.
*
* <p>For more information, please refer to the {@link RestTemplate} API documentation.
*
* @author Arjen Poutsma
* @since 4.0
* @see RestTemplate
* @deprecated as of Spring 5.0, in favor of {@link org.springframework.web.reactive.function.client.WebClient}
*/
@Deprecated
public class AsyncRestTemplate extends org.springframework.http.client.support.InterceptingAsyncHttpAccessor
implements AsyncRestOperations {
private final RestTemplate syncTemplate;
/**
* Create a new instance of the {@code AsyncRestTemplate} using default settings.
* <p>This constructor uses a {@link SimpleClientHttpRequestFactory} in combination
* with a {@link SimpleAsyncTaskExecutor} for asynchronous execution.
*/
public AsyncRestTemplate() {
this(new SimpleAsyncTaskExecutor());
}
/**
* Create a new instance of the {@code AsyncRestTemplate} using the given
* {@link AsyncTaskExecutor}.
* <p>This constructor uses a {@link SimpleClientHttpRequestFactory} in combination
* with the given {@code AsyncTaskExecutor} for asynchronous execution.
*/
public AsyncRestTemplate(AsyncListenableTaskExecutor taskExecutor) {
Assert.notNull(taskExecutor, "AsyncTaskExecutor must not be null");
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setTaskExecutor(taskExecutor);
this.syncTemplate = new RestTemplate(requestFactory);
setAsyncRequestFactory(requestFactory);
}
/**
* Create a new instance of the {@code AsyncRestTemplate} using the given
* {@link org.springframework.http.client.AsyncClientHttpRequestFactory}.
* <p>This constructor will cast the given asynchronous
* {@code AsyncClientHttpRequestFactory} to a {@link ClientHttpRequestFactory}. Since
* all implementations of {@code ClientHttpRequestFactory} provided in Spring also
* implement {@code AsyncClientHttpRequestFactory}, this should not result in a
* {@code ClassCastException}.
*/
public AsyncRestTemplate(org.springframework.http.client.AsyncClientHttpRequestFactory asyncRequestFactory) {
this(asyncRequestFactory, (ClientHttpRequestFactory) asyncRequestFactory);
}
/**
* Creates a new instance of the {@code AsyncRestTemplate} using the given
* asynchronous and synchronous request factories.
* @param asyncRequestFactory the asynchronous request factory
* @param syncRequestFactory the synchronous request factory
*/
public AsyncRestTemplate(org.springframework.http.client.AsyncClientHttpRequestFactory asyncRequestFactory,
ClientHttpRequestFactory syncRequestFactory) {
this(asyncRequestFactory, new RestTemplate(syncRequestFactory));
}
/**
* Create a new instance of the {@code AsyncRestTemplate} using the given
* {@link org.springframework.http.client.AsyncClientHttpRequestFactory} and synchronous {@link RestTemplate}.
* @param requestFactory the asynchronous request factory to use
* @param restTemplate the synchronous template to use
*/
public AsyncRestTemplate(org.springframework.http.client.AsyncClientHttpRequestFactory requestFactory,
RestTemplate restTemplate) {
Assert.notNull(restTemplate, "RestTemplate must not be null");
this.syncTemplate = restTemplate;
setAsyncRequestFactory(requestFactory);
}
/**
* Set the error handler.
* <p>By default, AsyncRestTemplate uses a
* {@link org.springframework.web.client.DefaultResponseErrorHandler}.
*/
public void setErrorHandler(ResponseErrorHandler errorHandler) {
this.syncTemplate.setErrorHandler(errorHandler);
}
/**
* Return the error handler.
*/
public ResponseErrorHandler getErrorHandler() {
return this.syncTemplate.getErrorHandler();
}
/**
* Configure default URI variable values. This is a shortcut for:
* <pre class="code">
* DefaultUriTemplateHandler handler = new DefaultUriTemplateHandler();
* handler.setDefaultUriVariables(...);
*
* AsyncRestTemplate restTemplate = new AsyncRestTemplate();
* restTemplate.setUriTemplateHandler(handler);
* </pre>
* @param defaultUriVariables the default URI variable values
* @since 4.3
*/
@SuppressWarnings("deprecation")
public void setDefaultUriVariables(Map<String, ?> defaultUriVariables) {
UriTemplateHandler handler = this.syncTemplate.getUriTemplateHandler();
if (handler instanceof DefaultUriBuilderFactory) {
((DefaultUriBuilderFactory) handler).setDefaultUriVariables(defaultUriVariables);
}
else if (handler instanceof org.springframework.web.util.AbstractUriTemplateHandler) {
((org.springframework.web.util.AbstractUriTemplateHandler) handler)
.setDefaultUriVariables(defaultUriVariables);
}
else {
throw new IllegalArgumentException(
"This property is not supported with the configured UriTemplateHandler.");
}
}
/**
* This property has the same purpose as the corresponding property on the
* {@code RestTemplate}. For more details see
* {@link RestTemplate#setUriTemplateHandler}.
* @param handler the URI template handler to use
*/
public void setUriTemplateHandler(UriTemplateHandler handler) {
this.syncTemplate.setUriTemplateHandler(handler);
}
/**
* Return the configured URI template handler.
*/
public UriTemplateHandler getUriTemplateHandler() {
return this.syncTemplate.getUriTemplateHandler();
}
@Override
public RestOperations getRestOperations() {
return this.syncTemplate;
}
/**
* Set the message body converters to use.
* <p>These converters are used to convert from and to HTTP requests and responses.
*/
public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
this.syncTemplate.setMessageConverters(messageConverters);
}
/**
* Return the message body converters.
*/
public List<HttpMessageConverter<?>> getMessageConverters() {
return this.syncTemplate.getMessageConverters();
}
// GET
@Override
public <T> ListenableFuture<ResponseEntity<T>> getForEntity(String url, Class<T> responseType, Object... uriVariables)
throws RestClientException {
AsyncRequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
}
@Override
public <T> ListenableFuture<ResponseEntity<T>> getForEntity(String url, Class<T> responseType,
Map<String, ?> uriVariables) throws RestClientException {
AsyncRequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
}
@Override
public <T> ListenableFuture<ResponseEntity<T>> getForEntity(URI url, Class<T> responseType)
throws RestClientException {
AsyncRequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, HttpMethod.GET, requestCallback, responseExtractor);
}
// HEAD
@Override
public ListenableFuture<HttpHeaders> headForHeaders(String url, Object... uriVariables)
throws RestClientException {
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
return execute(url, HttpMethod.HEAD, null, headersExtractor, uriVariables);
}
@Override
public ListenableFuture<HttpHeaders> headForHeaders(String url, Map<String, ?> uriVariables)
throws RestClientException {
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
return execute(url, HttpMethod.HEAD, null, headersExtractor, uriVariables);
}
@Override
public ListenableFuture<HttpHeaders> headForHeaders(URI url) throws RestClientException {
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
return execute(url, HttpMethod.HEAD, null, headersExtractor);
}
// POST
@Override
public ListenableFuture<URI> postForLocation(String url, @Nullable HttpEntity<?> request, Object... uriVars)
throws RestClientException {
AsyncRequestCallback callback = httpEntityCallback(request);
ResponseExtractor<HttpHeaders> extractor = headersExtractor();
ListenableFuture<HttpHeaders> future = execute(url, HttpMethod.POST, callback, extractor, uriVars);
return adaptToLocationHeader(future);
}
@Override
public ListenableFuture<URI> postForLocation(String url, @Nullable HttpEntity<?> request, Map<String, ?> uriVars)
throws RestClientException {
AsyncRequestCallback callback = httpEntityCallback(request);
ResponseExtractor<HttpHeaders> extractor = headersExtractor();
ListenableFuture<HttpHeaders> future = execute(url, HttpMethod.POST, callback, extractor, uriVars);
return adaptToLocationHeader(future);
}
@Override
public ListenableFuture<URI> postForLocation(URI url, @Nullable HttpEntity<?> request)
throws RestClientException {
AsyncRequestCallback callback = httpEntityCallback(request);
ResponseExtractor<HttpHeaders> extractor = headersExtractor();
ListenableFuture<HttpHeaders> future = execute(url, HttpMethod.POST, callback, extractor);
return adaptToLocationHeader(future);
}
private static ListenableFuture<URI> adaptToLocationHeader(ListenableFuture<HttpHeaders> future) {
return new ListenableFutureAdapter<URI, HttpHeaders>(future) {
@Override
@Nullable
protected URI adapt(HttpHeaders headers) throws ExecutionException {
return headers.getLocation();
}
};
}
@Override
public <T> ListenableFuture<ResponseEntity<T>> postForEntity(String url, @Nullable HttpEntity<?> request,
Class<T> responseType, Object... uriVariables) throws RestClientException {
AsyncRequestCallback requestCallback = httpEntityCallback(request, responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
}
@Override
public <T> ListenableFuture<ResponseEntity<T>> postForEntity(String url, @Nullable HttpEntity<?> request,
Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
AsyncRequestCallback requestCallback = httpEntityCallback(request, responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
}
@Override
public <T> ListenableFuture<ResponseEntity<T>> postForEntity(URI url,
@Nullable HttpEntity<?> request, Class<T> responseType) throws RestClientException {
AsyncRequestCallback requestCallback = httpEntityCallback(request, responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, HttpMethod.POST, requestCallback, responseExtractor);
}
// PUT
@Override
public ListenableFuture<?> put(String url, @Nullable HttpEntity<?> request, Object... uriVars)
throws RestClientException {
AsyncRequestCallback requestCallback = httpEntityCallback(request);
return execute(url, HttpMethod.PUT, requestCallback, null, uriVars);
}
@Override
public ListenableFuture<?> put(String url, @Nullable HttpEntity<?> request, Map<String, ?> uriVars)
throws RestClientException {
AsyncRequestCallback requestCallback = httpEntityCallback(request);
return execute(url, HttpMethod.PUT, requestCallback, null, uriVars);
}
@Override
public ListenableFuture<?> put(URI url, @Nullable HttpEntity<?> request) throws RestClientException {
AsyncRequestCallback requestCallback = httpEntityCallback(request);
return execute(url, HttpMethod.PUT, requestCallback, null);
}
// DELETE
@Override
public ListenableFuture<?> delete(String url, Object... uriVariables) throws RestClientException {
return execute(url, HttpMethod.DELETE, null, null, uriVariables);
}
@Override
public ListenableFuture<?> delete(String url, Map<String, ?> uriVariables) throws RestClientException {
return execute(url, HttpMethod.DELETE, null, null, uriVariables);
}
@Override
public ListenableFuture<?> delete(URI url) throws RestClientException {
return execute(url, HttpMethod.DELETE, null, null);
}
// OPTIONS
@Override
public ListenableFuture<Set<HttpMethod>> optionsForAllow(String url, Object... uriVars)
throws RestClientException {
ResponseExtractor<HttpHeaders> extractor = headersExtractor();
ListenableFuture<HttpHeaders> future = execute(url, HttpMethod.OPTIONS, null, extractor, uriVars);
return adaptToAllowHeader(future);
}
@Override
public ListenableFuture<Set<HttpMethod>> optionsForAllow(String url, Map<String, ?> uriVars)
throws RestClientException {
ResponseExtractor<HttpHeaders> extractor = headersExtractor();
ListenableFuture<HttpHeaders> future = execute(url, HttpMethod.OPTIONS, null, extractor, uriVars);
return adaptToAllowHeader(future);
}
@Override
public ListenableFuture<Set<HttpMethod>> optionsForAllow(URI url) throws RestClientException {
ResponseExtractor<HttpHeaders> extractor = headersExtractor();
ListenableFuture<HttpHeaders> future = execute(url, HttpMethod.OPTIONS, null, extractor);
return adaptToAllowHeader(future);
}
private static ListenableFuture<Set<HttpMethod>> adaptToAllowHeader(ListenableFuture<HttpHeaders> future) {
return new ListenableFutureAdapter<Set<HttpMethod>, HttpHeaders>(future) {
@Override
protected Set<HttpMethod> adapt(HttpHeaders headers) throws ExecutionException {
return headers.getAllow();
}
};
}
// exchange
@Override
public <T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
@Nullable HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables)
throws RestClientException {
AsyncRequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, method, requestCallback, responseExtractor, uriVariables);
}
@Override
public <T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
@Nullable HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables)
throws RestClientException {
AsyncRequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, method, requestCallback, responseExtractor, uriVariables);
}
@Override
public <T> ListenableFuture<ResponseEntity<T>> exchange(URI url, HttpMethod method,
@Nullable HttpEntity<?> requestEntity, Class<T> responseType) throws RestClientException {
AsyncRequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, method, requestCallback, responseExtractor);
}
@Override
public <T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
@Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType,
Object... uriVariables) throws RestClientException {
Type type = responseType.getType();
AsyncRequestCallback requestCallback = httpEntityCallback(requestEntity, type);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
return execute(url, method, requestCallback, responseExtractor, uriVariables);
}
@Override
public <T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
@Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType,
Map<String, ?> uriVariables) throws RestClientException {
Type type = responseType.getType();
AsyncRequestCallback requestCallback = httpEntityCallback(requestEntity, type);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
return execute(url, method, requestCallback, responseExtractor, uriVariables);
}
@Override
public <T> ListenableFuture<ResponseEntity<T>> exchange(URI url, HttpMethod method,
@Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType)
throws RestClientException {
Type type = responseType.getType();
AsyncRequestCallback requestCallback = httpEntityCallback(requestEntity, type);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
return execute(url, method, requestCallback, responseExtractor);
}
// general execution
@Override
public <T> ListenableFuture<T> execute(String url, HttpMethod method, @Nullable AsyncRequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException {
URI expanded = getUriTemplateHandler().expand(url, uriVariables);
return doExecute(expanded, method, requestCallback, responseExtractor);
}
@Override
public <T> ListenableFuture<T> execute(String url, HttpMethod method,
@Nullable AsyncRequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor,
Map<String, ?> uriVariables) throws RestClientException {
URI expanded = getUriTemplateHandler().expand(url, uriVariables);
return doExecute(expanded, method, requestCallback, responseExtractor);
}
@Override
public <T> ListenableFuture<T> execute(URI url, HttpMethod method,
@Nullable AsyncRequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
return doExecute(url, method, requestCallback, responseExtractor);
}
/**
* Execute the given method on the provided URI. The
* {@link org.springframework.http.client.ClientHttpRequest}
* is processed using the {@link RequestCallback}; the response with
* the {@link ResponseExtractor}.
* @param url the fully-expanded URL to connect to
* @param method the HTTP method to execute (GET, POST, etc.)
* @param requestCallback object that prepares the request (can be {@code null})
* @param responseExtractor object that extracts the return value from the response (can
* be {@code null})
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
*/
protected <T> ListenableFuture<T> doExecute(URI url, HttpMethod method,
@Nullable AsyncRequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
Assert.notNull(url, "'url' must not be null");
Assert.notNull(method, "'method' must not be null");
try {
org.springframework.http.client.AsyncClientHttpRequest request = createAsyncRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
}
ListenableFuture<ClientHttpResponse> responseFuture = request.executeAsync();
return new ResponseExtractorFuture<>(method, url, responseFuture, responseExtractor);
}
catch (IOException ex) {
throw new ResourceAccessException("I/O error on " + method.name() +
" request for \"" + url + "\":" + ex.getMessage(), ex);
}
}
private void logResponseStatus(HttpMethod method, URI url, ClientHttpResponse response) {
if (logger.isDebugEnabled()) {
try {
logger.debug("Async " + method.name() + " request for \"" + url + "\" resulted in " +
response.getRawStatusCode() + " (" + response.getStatusText() + ")");
}
catch (IOException ex) {
// ignore
}
}
}
private void handleResponseError(HttpMethod method, URI url, ClientHttpResponse response) throws IOException {
if (logger.isWarnEnabled()) {
try {
logger.warn("Async " + method.name() + " request for \"" + url + "\" resulted in " +
response.getRawStatusCode() + " (" + response.getStatusText() + "); invoking error handler");
}
catch (IOException ex) {
// ignore
}
}
getErrorHandler().handleError(url, method, response);
}
/**
* Returns a request callback implementation that prepares the request {@code Accept}
* headers based on the given response type and configured {@linkplain
* #getMessageConverters() message converters}.
*/
protected <T> AsyncRequestCallback acceptHeaderRequestCallback(Class<T> responseType) {
return new AsyncRequestCallbackAdapter(this.syncTemplate.acceptHeaderRequestCallback(responseType));
}
/**
* Returns a request callback implementation that writes the given object to the
* request stream.
*/
protected <T> AsyncRequestCallback httpEntityCallback(@Nullable HttpEntity<T> requestBody) {
return new AsyncRequestCallbackAdapter(this.syncTemplate.httpEntityCallback(requestBody));
}
/**
* Returns a request callback implementation that writes the given object to the
* request stream.
*/
protected <T> AsyncRequestCallback httpEntityCallback(@Nullable HttpEntity<T> request, Type responseType) {
return new AsyncRequestCallbackAdapter(this.syncTemplate.httpEntityCallback(request, responseType));
}
/**
* Returns a response extractor for {@link ResponseEntity}.
*/
protected <T> ResponseExtractor<ResponseEntity<T>> responseEntityExtractor(Type responseType) {
return this.syncTemplate.responseEntityExtractor(responseType);
}
/**
* Returns a response extractor for {@link HttpHeaders}.
*/
protected ResponseExtractor<HttpHeaders> headersExtractor() {
return this.syncTemplate.headersExtractor();
}
/**
* Future returned from
* {@link #doExecute(URI, HttpMethod, AsyncRequestCallback, ResponseExtractor)}.
*/
private class ResponseExtractorFuture<T> extends ListenableFutureAdapter<T, ClientHttpResponse> {
private final HttpMethod method;
private final URI url;
@Nullable
private final ResponseExtractor<T> responseExtractor;
public ResponseExtractorFuture(HttpMethod method, URI url,
ListenableFuture<ClientHttpResponse> clientHttpResponseFuture,
@Nullable ResponseExtractor<T> responseExtractor) {
super(clientHttpResponseFuture);
this.method = method;
this.url = url;
this.responseExtractor = responseExtractor;
}
@Override
@Nullable
protected final T adapt(ClientHttpResponse response) throws ExecutionException {
try {
if (!getErrorHandler().hasError(response)) {
logResponseStatus(this.method, this.url, response);
}
else {
handleResponseError(this.method, this.url, response);
}
return convertResponse(response);
}
catch (Throwable ex) {
throw new ExecutionException(ex);
}
finally {
response.close();
}
}
@Nullable
protected T convertResponse(ClientHttpResponse response) throws IOException {
return (this.responseExtractor != null ? this.responseExtractor.extractData(response) : null);
}
}
/**
* Adapts a {@link RequestCallback} to the {@link AsyncRequestCallback} interface.
*/
private static class AsyncRequestCallbackAdapter implements AsyncRequestCallback {
private final RequestCallback adaptee;
/**
* Create a new {@code AsyncRequestCallbackAdapter} from the given
* {@link RequestCallback}.
* @param requestCallback the callback to base this adapter on
*/
public AsyncRequestCallbackAdapter(RequestCallback requestCallback) {
this.adaptee = requestCallback;
}
@Override
public void doWithRequest(final org.springframework.http.client.AsyncClientHttpRequest request)
throws IOException {
this.adaptee.doWithRequest(new ClientHttpRequest() {
@Override
public ClientHttpResponse execute() throws IOException {
throw new UnsupportedOperationException("execute not supported");
}
@Override
public OutputStream getBody() throws IOException {
return request.getBody();
}
@Override
@Nullable
public HttpMethod getMethod() {
return request.getMethod();
}
@Override
public String getMethodValue() {
return request.getMethodValue();
}
@Override
public URI getURI() {
return request.getURI();
}
@Override
public HttpHeaders getHeaders() {
return request.getHeaders();
}
});
}
}
}