Remove AsyncRestTemplate and related types
This commit is contained in:
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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...
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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} -
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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<List<MyBean>> myBean =
|
||||
* new ParameterizedTypeReference<List<MyBean>>() {};
|
||||
*
|
||||
* ResponseEntity<List<MyBean>> response =
|
||||
* template.exchange("https://example.com",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<List<MyBean>> myBean =
|
||||
* new ParameterizedTypeReference<List<MyBean>>() {};
|
||||
*
|
||||
* ResponseEntity<List<MyBean>> response =
|
||||
* template.exchange("https://example.com",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<List<MyBean>> myBean =
|
||||
* new ParameterizedTypeReference<List<MyBean>>() {};
|
||||
*
|
||||
* ResponseEntity<List<MyBean>> response =
|
||||
* template.exchange("https://example.com",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;
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user