Added ListenableFuture interface
Added extension to Future with capabilities for registering callbacks when the future is complete. - Added ListenableFuture, ListenableFutureCallback, ListenableFutureCallbackRegistry, and ListenableFutureTask. - Using ListenableFuture in AsyncRestOperations/AsyncRestTemplate. - Added AsyncListenableTaskExecutor, implemented in SimpleAsyncTaskExecutor. - Added FutureAdapter and ListenableFutureAdapter.
This commit is contained in:
@@ -18,10 +18,10 @@ package org.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
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
|
||||
@@ -49,15 +49,15 @@ abstract class AbstractAsyncClientHttpRequest implements AsyncClientHttpRequest
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<ClientHttpResponse> executeAsync() throws IOException {
|
||||
public ListenableFuture<ClientHttpResponse> executeAsync() throws IOException {
|
||||
assertNotExecuted();
|
||||
Future<ClientHttpResponse> result = executeInternal(this.headers);
|
||||
ListenableFuture<ClientHttpResponse> result = executeInternal(this.headers);
|
||||
this.executed = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that this request has not been {@linkplain #execute() executed} yet.
|
||||
* Asserts that this request has not been {@linkplain #executeAsync() executed} yet.
|
||||
*
|
||||
* @throws IllegalStateException if this request has been executed
|
||||
*/
|
||||
@@ -74,10 +74,12 @@ abstract class AbstractAsyncClientHttpRequest implements AsyncClientHttpRequest
|
||||
protected abstract OutputStream getBodyInternal(HttpHeaders headers) throws IOException;
|
||||
|
||||
/**
|
||||
* Abstract template method that writes the given headers and content to the HTTP request.
|
||||
* 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 Future<ClientHttpResponse> executeInternal(HttpHeaders headers) throws IOException;
|
||||
protected abstract ListenableFuture<ClientHttpResponse> executeInternal(
|
||||
HttpHeaders headers) throws IOException;
|
||||
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@ package org.springframework.http.client;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Abstract base for {@link org.springframework.http.client.ClientHttpRequest} that buffers output in a byte array before sending it over the wire.
|
||||
@@ -40,12 +40,13 @@ abstract class AbstractBufferingAsyncClientHttpRequest
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Future<ClientHttpResponse> executeInternal(HttpHeaders headers) throws IOException {
|
||||
protected ListenableFuture<ClientHttpResponse> executeInternal(HttpHeaders headers)
|
||||
throws IOException {
|
||||
byte[] bytes = this.bufferedOutput.toByteArray();
|
||||
if (headers.getContentLength() == -1) {
|
||||
headers.setContentLength(bytes.length);
|
||||
}
|
||||
Future<ClientHttpResponse> result = executeInternal(headers, bytes);
|
||||
ListenableFuture<ClientHttpResponse> result = executeInternal(headers, bytes);
|
||||
this.bufferedOutput = null;
|
||||
return result;
|
||||
}
|
||||
@@ -58,8 +59,8 @@ abstract class AbstractBufferingAsyncClientHttpRequest
|
||||
* @param bufferedOutput the body content
|
||||
* @return the response object for the executed request
|
||||
*/
|
||||
protected abstract Future<ClientHttpResponse> executeInternal(HttpHeaders headers,
|
||||
byte[] bufferedOutput) throws IOException;
|
||||
protected abstract ListenableFuture<ClientHttpResponse> executeInternal(
|
||||
HttpHeaders headers, byte[] bufferedOutput) throws IOException;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
package org.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
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
|
||||
@@ -41,7 +41,7 @@ public interface AsyncClientHttpRequest extends HttpRequest, HttpOutputMessage {
|
||||
* @return the future response result of the execution
|
||||
* @throws java.io.IOException in case of I/O errors
|
||||
*/
|
||||
Future<ClientHttpResponse> executeAsync() throws IOException;
|
||||
ListenableFuture<ClientHttpResponse> executeAsync() throws IOException;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -18,21 +18,23 @@ package org.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
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.http.HttpMethod;
|
||||
import org.springframework.util.concurrent.FutureAdapter;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallbackRegistry;
|
||||
|
||||
/**
|
||||
* {@link ClientHttpRequest} implementation that uses Apache HttpComponents HttpClient to
|
||||
@@ -72,7 +74,7 @@ final class HttpComponentsAsyncClientHttpRequest extends AbstractBufferingAsyncC
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Future<ClientHttpResponse> executeInternal(HttpHeaders headers,
|
||||
protected ListenableFuture<ClientHttpResponse> executeInternal(HttpHeaders headers,
|
||||
byte[] bufferedOutput) throws IOException {
|
||||
HttpComponentsClientHttpRequest.addHeaders(this.httpRequest, headers);
|
||||
|
||||
@@ -83,50 +85,61 @@ final class HttpComponentsAsyncClientHttpRequest extends AbstractBufferingAsyncC
|
||||
entityEnclosingRequest.setEntity(requestEntity);
|
||||
}
|
||||
|
||||
final HttpResponseFutureCallback callback = new HttpResponseFutureCallback();
|
||||
|
||||
final Future<HttpResponse> futureResponse =
|
||||
this.httpClient.execute(this.httpRequest, this.httpContext, null);
|
||||
return new ClientHttpResponseFuture(futureResponse);
|
||||
this.httpClient.execute(this.httpRequest, this.httpContext, callback);
|
||||
return new ClientHttpResponseFuture(futureResponse, callback);
|
||||
}
|
||||
|
||||
private static class HttpResponseFutureCallback implements FutureCallback<HttpResponse> {
|
||||
|
||||
private final ListenableFutureCallbackRegistry<ClientHttpResponse> callbacks =
|
||||
new ListenableFutureCallbackRegistry<ClientHttpResponse>();
|
||||
|
||||
public void addCallback(
|
||||
ListenableFutureCallback<? super ClientHttpResponse> callback) {
|
||||
callbacks.addCallback(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed(HttpResponse result) {
|
||||
callbacks.success(new HttpComponentsAsyncClientHttpResponse(result));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Exception ex) {
|
||||
callbacks.failure(ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelled() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static class ClientHttpResponseFuture implements Future<ClientHttpResponse> {
|
||||
private static class ClientHttpResponseFuture extends FutureAdapter<ClientHttpResponse, HttpResponse>
|
||||
implements ListenableFuture<ClientHttpResponse> {
|
||||
|
||||
private final Future<HttpResponse> futureResponse;
|
||||
private final HttpResponseFutureCallback callback;
|
||||
|
||||
|
||||
public ClientHttpResponseFuture(Future<HttpResponse> futureResponse) {
|
||||
this.futureResponse = futureResponse;
|
||||
private ClientHttpResponseFuture(Future<HttpResponse> futureResponse,
|
||||
HttpResponseFutureCallback callback) {
|
||||
super(futureResponse);
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return futureResponse.cancel(mayInterruptIfRunning);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return futureResponse.isCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return futureResponse.isDone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse get()
|
||||
throws InterruptedException, ExecutionException {
|
||||
HttpResponse response = futureResponse.get();
|
||||
protected ClientHttpResponse adapt(HttpResponse response) {
|
||||
return new HttpComponentsAsyncClientHttpResponse(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse get(long timeout, TimeUnit unit)
|
||||
throws InterruptedException, ExecutionException, TimeoutException {
|
||||
HttpResponse response = futureResponse.get(timeout, unit);
|
||||
return new HttpComponentsAsyncClientHttpResponse(response);
|
||||
public void addCallback(
|
||||
ListenableFutureCallback<? super ClientHttpResponse> callback) {
|
||||
this.callback.addCallback(callback);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -23,12 +23,12 @@ import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
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
|
||||
@@ -45,10 +45,10 @@ final class SimpleBufferingAsyncClientHttpRequest extends AbstractBufferingAsync
|
||||
|
||||
private final boolean outputStreaming;
|
||||
|
||||
private final AsyncTaskExecutor taskExecutor;
|
||||
private final AsyncListenableTaskExecutor taskExecutor;
|
||||
|
||||
SimpleBufferingAsyncClientHttpRequest(HttpURLConnection connection,
|
||||
boolean outputStreaming, AsyncTaskExecutor taskExecutor) {
|
||||
boolean outputStreaming, AsyncListenableTaskExecutor taskExecutor) {
|
||||
this.connection = connection;
|
||||
this.outputStreaming = outputStreaming;
|
||||
this.taskExecutor = taskExecutor;
|
||||
@@ -70,9 +70,9 @@ final class SimpleBufferingAsyncClientHttpRequest extends AbstractBufferingAsync
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Future<ClientHttpResponse> executeInternal(final HttpHeaders headers,
|
||||
final byte[] bufferedOutput) throws IOException {
|
||||
return taskExecutor.submit(new Callable<ClientHttpResponse>() {
|
||||
protected ListenableFuture<ClientHttpResponse> executeInternal(
|
||||
final HttpHeaders headers, final byte[] bufferedOutput) throws IOException {
|
||||
return taskExecutor.submitListenable(new Callable<ClientHttpResponse>() {
|
||||
@Override
|
||||
public ClientHttpResponse call() throws Exception {
|
||||
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -54,7 +54,7 @@ public class SimpleClientHttpRequestFactory
|
||||
|
||||
private boolean outputStreaming = true;
|
||||
|
||||
private AsyncTaskExecutor taskExecutor;
|
||||
private AsyncListenableTaskExecutor taskExecutor;
|
||||
|
||||
|
||||
/**
|
||||
@@ -131,7 +131,7 @@ public class SimpleClientHttpRequestFactory
|
||||
* request}.
|
||||
* @param taskExecutor the task executor
|
||||
*/
|
||||
public void setTaskExecutor(AsyncTaskExecutor taskExecutor) {
|
||||
public void setTaskExecutor(AsyncListenableTaskExecutor taskExecutor) {
|
||||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ public class SimpleClientHttpRequestFactory
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>Setting the {@link #setTaskExecutor(AsyncTaskExecutor) taskExecutor} property
|
||||
* <p>Setting the {@link #setTaskExecutor(org.springframework.core.task.AsyncListenableTaskExecutor) taskExecutor} property
|
||||
* is required before calling this method.
|
||||
*/
|
||||
@Override
|
||||
|
||||
@@ -24,12 +24,12 @@ import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.http.client.ClientHttpRequest} implementation that uses
|
||||
@@ -51,10 +51,10 @@ final class SimpleStreamingAsyncClientHttpRequest extends AbstractAsyncClientHtt
|
||||
|
||||
private final boolean outputStreaming;
|
||||
|
||||
private final AsyncTaskExecutor taskExecutor;
|
||||
private final AsyncListenableTaskExecutor taskExecutor;
|
||||
|
||||
SimpleStreamingAsyncClientHttpRequest(HttpURLConnection connection, int chunkSize,
|
||||
boolean outputStreaming, AsyncTaskExecutor taskExecutor) {
|
||||
boolean outputStreaming, AsyncListenableTaskExecutor taskExecutor) {
|
||||
this.connection = connection;
|
||||
this.chunkSize = chunkSize;
|
||||
this.outputStreaming = outputStreaming;
|
||||
@@ -106,9 +106,9 @@ final class SimpleStreamingAsyncClientHttpRequest extends AbstractAsyncClientHtt
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Future<ClientHttpResponse> executeInternal(final HttpHeaders headers)
|
||||
protected ListenableFuture<ClientHttpResponse> executeInternal(final HttpHeaders headers)
|
||||
throws IOException {
|
||||
return taskExecutor.submit(new Callable<ClientHttpResponse>() {
|
||||
return taskExecutor.submitListenable(new Callable<ClientHttpResponse>() {
|
||||
@Override
|
||||
public ClientHttpResponse call() throws Exception {
|
||||
try {
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Interface specifying a basic set of asynchronous RESTful operations. Implemented by
|
||||
@@ -54,7 +55,7 @@ public interface AsyncRestOperations {
|
||||
* @param uriVariables the variables to expand the template
|
||||
* @return the entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> Future<ResponseEntity<T>> getForEntity(String url, Class<T> responseType,
|
||||
<T> ListenableFuture<ResponseEntity<T>> getForEntity(String url, Class<T> responseType,
|
||||
Object... uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
@@ -66,7 +67,7 @@ public interface AsyncRestOperations {
|
||||
* @param uriVariables the map containing variables for the URI template
|
||||
* @return the entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> Future<ResponseEntity<T>> getForEntity(String url, Class<T> responseType,
|
||||
<T> ListenableFuture<ResponseEntity<T>> getForEntity(String url, Class<T> responseType,
|
||||
Map<String, ?> uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
@@ -76,7 +77,7 @@ public interface AsyncRestOperations {
|
||||
* @param responseType the type of the return value
|
||||
* @return the entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> Future<ResponseEntity<T>> getForEntity(URI url, Class<T> responseType)
|
||||
<T> ListenableFuture<ResponseEntity<T>> getForEntity(URI url, Class<T> responseType)
|
||||
throws RestClientException;
|
||||
|
||||
// HEAD
|
||||
@@ -88,7 +89,7 @@ public interface AsyncRestOperations {
|
||||
* @param uriVariables the variables to expand the template
|
||||
* @return all HTTP headers of that resource wrapped in a {@link Future}
|
||||
*/
|
||||
Future<HttpHeaders> headForHeaders(String url, Object... uriVariables)
|
||||
ListenableFuture<HttpHeaders> headForHeaders(String url, Object... uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
@@ -98,7 +99,7 @@ public interface AsyncRestOperations {
|
||||
* @param uriVariables the map containing variables for the URI template
|
||||
* @return all HTTP headers of that resource wrapped in a {@link Future}
|
||||
*/
|
||||
Future<HttpHeaders> headForHeaders(String url, Map<String, ?> uriVariables)
|
||||
ListenableFuture<HttpHeaders> headForHeaders(String url, Map<String, ?> uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
@@ -106,7 +107,7 @@ public interface AsyncRestOperations {
|
||||
* @param url the URL
|
||||
* @return all HTTP headers of that resource wrapped in a {@link Future}
|
||||
*/
|
||||
Future<HttpHeaders> headForHeaders(URI url) throws RestClientException;
|
||||
ListenableFuture<HttpHeaders> headForHeaders(URI url) throws RestClientException;
|
||||
|
||||
// POST
|
||||
|
||||
@@ -121,7 +122,7 @@ public interface AsyncRestOperations {
|
||||
* @return the value for the {@code Location} header wrapped in a {@link Future}
|
||||
* @see org.springframework.http.HttpEntity
|
||||
*/
|
||||
Future<URI> postForLocation(String url, HttpEntity<?> request, Object... uriVariables)
|
||||
ListenableFuture<URI> postForLocation(String url, HttpEntity<?> request, Object... uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
@@ -135,7 +136,7 @@ public interface AsyncRestOperations {
|
||||
* @return the value for the {@code Location} header wrapped in a {@link Future}
|
||||
* @see org.springframework.http.HttpEntity
|
||||
*/
|
||||
Future<URI> postForLocation(String url, HttpEntity<?> request, Map<String, ?> uriVariables)
|
||||
ListenableFuture<URI> postForLocation(String url, HttpEntity<?> request, Map<String, ?> uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
@@ -147,7 +148,7 @@ public interface AsyncRestOperations {
|
||||
* @return the value for the {@code Location} header wrapped in a {@link Future}
|
||||
* @see org.springframework.http.HttpEntity
|
||||
*/
|
||||
Future<URI> postForLocation(URI url, HttpEntity<?> request) throws RestClientException;
|
||||
ListenableFuture<URI> postForLocation(URI url, HttpEntity<?> request) throws RestClientException;
|
||||
|
||||
/**
|
||||
* Create a new resource by POSTing the given object to the URI template,
|
||||
@@ -159,7 +160,7 @@ public interface AsyncRestOperations {
|
||||
* @return the entity wrapped in a {@link Future}
|
||||
* @see org.springframework.http.HttpEntity
|
||||
*/
|
||||
<T> Future<ResponseEntity<T>> postForEntity(String url, HttpEntity<?> request,
|
||||
<T> ListenableFuture<ResponseEntity<T>> postForEntity(String url, HttpEntity<?> request,
|
||||
Class<T> responseType, Object... uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
@@ -172,7 +173,7 @@ public interface AsyncRestOperations {
|
||||
* @return the entity wrapped in a {@link Future}
|
||||
* @see org.springframework.http.HttpEntity
|
||||
*/
|
||||
<T> Future<ResponseEntity<T>> postForEntity(String url, HttpEntity<?> request,
|
||||
<T> ListenableFuture<ResponseEntity<T>> postForEntity(String url, HttpEntity<?> request,
|
||||
Class<T> responseType, Map<String, ?> uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
@@ -184,7 +185,7 @@ public interface AsyncRestOperations {
|
||||
* @return the entity wrapped in a {@link Future}
|
||||
* @see org.springframework.http.HttpEntity
|
||||
*/
|
||||
<T> Future<ResponseEntity<T>> postForEntity(URI url, HttpEntity<?> request,
|
||||
<T> ListenableFuture<ResponseEntity<T>> postForEntity(URI url, HttpEntity<?> request,
|
||||
Class<T> responseType) throws RestClientException;
|
||||
|
||||
// PUT
|
||||
@@ -198,7 +199,7 @@ public interface AsyncRestOperations {
|
||||
* @param uriVariables the variables to expand the template
|
||||
* @see HttpEntity
|
||||
*/
|
||||
Future<?> put(String url, HttpEntity<?> request, Object... uriVariables)
|
||||
ListenableFuture<?> put(String url, HttpEntity<?> request, Object... uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
@@ -210,7 +211,7 @@ public interface AsyncRestOperations {
|
||||
* @param uriVariables the variables to expand the template
|
||||
* @see HttpEntity
|
||||
*/
|
||||
Future<?> put(String url, HttpEntity<?> request, Map<String, ?> uriVariables)
|
||||
ListenableFuture<?> put(String url, HttpEntity<?> request, Map<String, ?> uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
@@ -220,7 +221,7 @@ public interface AsyncRestOperations {
|
||||
* @param request the Object to be PUT, may be {@code null}
|
||||
* @see HttpEntity
|
||||
*/
|
||||
Future<?> put(URI url, HttpEntity<?> request) throws RestClientException;
|
||||
ListenableFuture<?> put(URI url, HttpEntity<?> request) throws RestClientException;
|
||||
|
||||
// DELETE
|
||||
|
||||
@@ -231,7 +232,7 @@ public interface AsyncRestOperations {
|
||||
* @param url the URL
|
||||
* @param uriVariables the variables to expand in the template
|
||||
*/
|
||||
Future<?> delete(String url, Object... uriVariables) throws RestClientException;
|
||||
ListenableFuture<?> delete(String url, Object... uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
* Asynchronously delete the resources at the specified URI.
|
||||
@@ -240,7 +241,7 @@ public interface AsyncRestOperations {
|
||||
* @param url the URL
|
||||
* @param uriVariables the variables to expand in the template
|
||||
*/
|
||||
Future<?> delete(String url, Map<String, ?> uriVariables) throws RestClientException;
|
||||
ListenableFuture<?> delete(String url, Map<String, ?> uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
* Asynchronously delete the resources at the specified URI.
|
||||
@@ -248,7 +249,7 @@ public interface AsyncRestOperations {
|
||||
* <p>The Future will return a {@code null} result upon completion.
|
||||
* @param url the URL
|
||||
*/
|
||||
Future<?> delete(URI url) throws RestClientException;
|
||||
ListenableFuture<?> delete(URI url) throws RestClientException;
|
||||
|
||||
// OPTIONS
|
||||
|
||||
@@ -259,7 +260,7 @@ public interface AsyncRestOperations {
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return the value of the allow header wrapped in a {@link Future}
|
||||
*/
|
||||
Future<Set<HttpMethod>> optionsForAllow(String url, Object... uriVariables)
|
||||
ListenableFuture<Set<HttpMethod>> optionsForAllow(String url, Object... uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
@@ -269,7 +270,7 @@ public interface AsyncRestOperations {
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return the value of the allow header wrapped in a {@link Future}
|
||||
*/
|
||||
Future<Set<HttpMethod>> optionsForAllow(String url, Map<String, ?> uriVariables)
|
||||
ListenableFuture<Set<HttpMethod>> optionsForAllow(String url, Map<String, ?> uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
@@ -277,7 +278,7 @@ public interface AsyncRestOperations {
|
||||
* @param url the URL
|
||||
* @return the value of the allow header wrapped in a {@link Future}
|
||||
*/
|
||||
Future<Set<HttpMethod>> optionsForAllow(URI url) throws RestClientException;
|
||||
ListenableFuture<Set<HttpMethod>> optionsForAllow(URI url) throws RestClientException;
|
||||
|
||||
|
||||
// exchange
|
||||
@@ -295,7 +296,7 @@ public interface AsyncRestOperations {
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return the response as entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> Future<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
<T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
@@ -312,7 +313,7 @@ public interface AsyncRestOperations {
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return the response as entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> Future<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
<T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
HttpEntity<?> requestEntity, Class<T> responseType,
|
||||
Map<String, ?> uriVariables) throws RestClientException;
|
||||
|
||||
@@ -327,7 +328,7 @@ public interface AsyncRestOperations {
|
||||
* @param responseType the type of the return value
|
||||
* @return the response as entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> Future<ResponseEntity<T>> exchange(URI url, HttpMethod method,
|
||||
<T> ListenableFuture<ResponseEntity<T>> exchange(URI url, HttpMethod method,
|
||||
HttpEntity<?> requestEntity, Class<T> responseType)
|
||||
throws RestClientException;
|
||||
|
||||
@@ -348,7 +349,7 @@ public interface AsyncRestOperations {
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return the response as entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> Future<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
<T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType,
|
||||
Object... uriVariables) throws RestClientException;
|
||||
|
||||
@@ -368,7 +369,7 @@ public interface AsyncRestOperations {
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return the response as entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> Future<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
<T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType,
|
||||
Map<String, ?> uriVariables) throws RestClientException;
|
||||
|
||||
@@ -387,7 +388,7 @@ public interface AsyncRestOperations {
|
||||
* @param responseType the type of the return value
|
||||
* @return the response as entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> Future<ResponseEntity<T>> exchange(URI url, HttpMethod method,
|
||||
<T> ListenableFuture<ResponseEntity<T>> exchange(URI url, HttpMethod method,
|
||||
HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType)
|
||||
throws RestClientException;
|
||||
|
||||
@@ -406,7 +407,7 @@ public interface AsyncRestOperations {
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
|
||||
*/
|
||||
<T> Future<T> execute(String url, HttpMethod method,
|
||||
<T> ListenableFuture<T> execute(String url, HttpMethod method,
|
||||
AsyncRequestCallback requestCallback, ResponseExtractor<T> responseExtractor,
|
||||
Object... uriVariables) throws RestClientException;
|
||||
|
||||
@@ -422,7 +423,7 @@ public interface AsyncRestOperations {
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
|
||||
*/
|
||||
<T> Future<T> execute(String url, HttpMethod method,
|
||||
<T> ListenableFuture<T> execute(String url, HttpMethod method,
|
||||
AsyncRequestCallback requestCallback, ResponseExtractor<T> responseExtractor,
|
||||
Map<String, ?> uriVariables) throws RestClientException;
|
||||
|
||||
@@ -436,7 +437,7 @@ public interface AsyncRestOperations {
|
||||
* @param responseExtractor object that extracts the return value from the response
|
||||
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
|
||||
*/
|
||||
<T> Future<T> execute(URI url, HttpMethod method,
|
||||
<T> ListenableFuture<T> execute(URI url, HttpMethod method,
|
||||
AsyncRequestCallback requestCallback, ResponseExtractor<T> responseExtractor)
|
||||
throws RestClientException;
|
||||
|
||||
|
||||
@@ -24,11 +24,11 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
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;
|
||||
@@ -44,12 +44,15 @@ import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.http.client.support.AsyncHttpAccessor;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureAdapter;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
import org.springframework.web.util.UriTemplate;
|
||||
|
||||
/**
|
||||
* <strong>Spring's central class for asynchronous client-side HTTP access.</strong>
|
||||
* Exposes similar methods as {@link RestTemplate}, but returns {@link Future} wrappers
|
||||
* as opposed to concrete results.
|
||||
* 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 it shares its
|
||||
@@ -69,7 +72,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link AsyncRestTemplate} using default settings.
|
||||
* 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.
|
||||
*/
|
||||
@@ -78,21 +81,22 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link AsyncRestTemplate} using the given
|
||||
* 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(AsyncTaskExecutor taskExecutor) {
|
||||
public AsyncRestTemplate(AsyncListenableTaskExecutor taskExecutor) {
|
||||
Assert.notNull(taskExecutor, "AsyncTaskExecutor must not be null");
|
||||
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||
SimpleClientHttpRequestFactory requestFactory =
|
||||
new SimpleClientHttpRequestFactory();
|
||||
requestFactory.setTaskExecutor(taskExecutor);
|
||||
this.syncTemplate = new RestTemplate(requestFactory);
|
||||
setAsyncRequestFactory(requestFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link AsyncRestTemplate} using the given
|
||||
* Create a new instance of the {@code AsyncRestTemplate} using the given
|
||||
* {@link AsyncClientHttpRequestFactory}.
|
||||
* <p>This constructor will cast the given asynchronous
|
||||
* {@code AsyncClientHttpRequestFactory} to a {@link ClientHttpRequestFactory}. Since
|
||||
@@ -105,22 +109,24 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@link AsyncRestTemplate} using the given
|
||||
* 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(AsyncClientHttpRequestFactory asyncRequestFactory, ClientHttpRequestFactory syncRequestFactory) {
|
||||
public AsyncRestTemplate(AsyncClientHttpRequestFactory asyncRequestFactory,
|
||||
ClientHttpRequestFactory syncRequestFactory) {
|
||||
this(asyncRequestFactory, new RestTemplate(syncRequestFactory));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link AsyncRestTemplate} using the given
|
||||
* Create a new instance of the {@code AsyncRestTemplate} using the given
|
||||
* {@link AsyncClientHttpRequestFactory} and synchronous {@link RestTemplate}.
|
||||
* @param requestFactory the asynchronous request factory to use
|
||||
* @param restTemplate the synchronous template to use
|
||||
*/
|
||||
public AsyncRestTemplate(AsyncClientHttpRequestFactory requestFactory, RestTemplate restTemplate) {
|
||||
public AsyncRestTemplate(AsyncClientHttpRequestFactory requestFactory,
|
||||
RestTemplate restTemplate) {
|
||||
Assert.notNull(restTemplate, "'restTemplate' must not be null");
|
||||
this.syncTemplate = restTemplate;
|
||||
setAsyncRequestFactory(requestFactory);
|
||||
@@ -165,7 +171,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
// GET
|
||||
|
||||
@Override
|
||||
public <T> Future<ResponseEntity<T>> getForEntity(String url, Class<T> responseType, Object... uriVariables)
|
||||
public <T> ListenableFuture<ResponseEntity<T>> getForEntity(String url, Class<T> responseType, Object... uriVariables)
|
||||
throws RestClientException {
|
||||
|
||||
AsyncRequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
|
||||
@@ -174,7 +180,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<ResponseEntity<T>> getForEntity(String url, Class<T> responseType,
|
||||
public <T> ListenableFuture<ResponseEntity<T>> getForEntity(String url, Class<T> responseType,
|
||||
Map<String, ?> urlVariables) throws RestClientException {
|
||||
|
||||
AsyncRequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
|
||||
@@ -183,7 +189,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<ResponseEntity<T>> getForEntity(URI url, Class<T> responseType) throws RestClientException {
|
||||
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);
|
||||
@@ -192,19 +198,19 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
// HEAD
|
||||
|
||||
@Override
|
||||
public Future<HttpHeaders> headForHeaders(String url, Object... uriVariables) throws RestClientException {
|
||||
public ListenableFuture<HttpHeaders> headForHeaders(String url, Object... uriVariables) throws RestClientException {
|
||||
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
|
||||
return execute(url, HttpMethod.HEAD, null, headersExtractor, uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<HttpHeaders> headForHeaders(String url, Map<String, ?> uriVariables) throws RestClientException {
|
||||
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 Future<HttpHeaders> headForHeaders(URI url) throws RestClientException {
|
||||
public ListenableFuture<HttpHeaders> headForHeaders(URI url) throws RestClientException {
|
||||
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
|
||||
return execute(url, HttpMethod.HEAD, null, headersExtractor);
|
||||
}
|
||||
@@ -212,39 +218,55 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
// POST
|
||||
|
||||
@Override
|
||||
public Future<URI> postForLocation(String url, HttpEntity<?> request,
|
||||
public ListenableFuture<URI> postForLocation(String url, HttpEntity<?> request,
|
||||
Object... uriVariables) throws RestClientException {
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(request);
|
||||
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
|
||||
Future<HttpHeaders> headersFuture =
|
||||
ListenableFuture<HttpHeaders> headersFuture =
|
||||
execute(url, HttpMethod.POST, requestCallback, headersExtractor,
|
||||
uriVariables);
|
||||
return extractLocationHeader(headersFuture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<URI> postForLocation(String url, HttpEntity<?> request,
|
||||
public ListenableFuture<URI> postForLocation(String url, HttpEntity<?> request,
|
||||
Map<String, ?> uriVariables) throws RestClientException {
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(request);
|
||||
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
|
||||
Future<HttpHeaders> headersFuture =
|
||||
ListenableFuture<HttpHeaders> headersFuture =
|
||||
execute(url, HttpMethod.POST, requestCallback, headersExtractor,
|
||||
uriVariables);
|
||||
return extractLocationHeader(headersFuture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<URI> postForLocation(URI url, HttpEntity<?> request)
|
||||
public ListenableFuture<URI> postForLocation(URI url, HttpEntity<?> request)
|
||||
throws RestClientException {
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(request);
|
||||
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
|
||||
Future<HttpHeaders> headersFuture =
|
||||
ListenableFuture<HttpHeaders> headersFuture =
|
||||
execute(url, HttpMethod.POST, requestCallback, headersExtractor);
|
||||
return extractLocationHeader(headersFuture);
|
||||
}
|
||||
|
||||
private static Future<URI> extractLocationHeader(final Future<HttpHeaders> headersFuture) {
|
||||
return new Future<URI>() {
|
||||
private static ListenableFuture<URI> extractLocationHeader(final ListenableFuture<HttpHeaders> headersFuture) {
|
||||
return new ListenableFuture<URI>() {
|
||||
|
||||
@Override
|
||||
public void addCallback(final ListenableFutureCallback<? super URI> callback) {
|
||||
headersFuture.addCallback(new ListenableFutureCallback<HttpHeaders>() {
|
||||
@Override
|
||||
public void onSuccess(HttpHeaders result) {
|
||||
callback.onSuccess(result.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
callback.onFailure(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return headersFuture.cancel(mayInterruptIfRunning);
|
||||
@@ -272,7 +294,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<ResponseEntity<T>> postForEntity(String url, HttpEntity<?> request,
|
||||
public <T> ListenableFuture<ResponseEntity<T>> postForEntity(String url, HttpEntity<?> request,
|
||||
Class<T> responseType, Object... uriVariables) throws RestClientException {
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(request, responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor =
|
||||
@@ -282,7 +304,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<ResponseEntity<T>> postForEntity(String url, HttpEntity<?> request,
|
||||
public <T> ListenableFuture<ResponseEntity<T>> postForEntity(String url, HttpEntity<?> request,
|
||||
Class<T> responseType, Map<String, ?> uriVariables)
|
||||
throws RestClientException {
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(request, responseType);
|
||||
@@ -293,7 +315,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<ResponseEntity<T>> postForEntity(URI url, HttpEntity<?> request,
|
||||
public <T> ListenableFuture<ResponseEntity<T>> postForEntity(URI url, HttpEntity<?> request,
|
||||
Class<T> responseType) throws RestClientException {
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(request, responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor =
|
||||
@@ -304,21 +326,21 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
// PUT
|
||||
|
||||
@Override
|
||||
public Future<?> put(String url, HttpEntity<?> request, Object... uriVariables)
|
||||
public ListenableFuture<?> put(String url, HttpEntity<?> request, Object... uriVariables)
|
||||
throws RestClientException {
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(request);
|
||||
return execute(url, HttpMethod.PUT, requestCallback, null, uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<?> put(String url, HttpEntity<?> request,
|
||||
public ListenableFuture<?> put(String url, HttpEntity<?> request,
|
||||
Map<String, ?> uriVariables) throws RestClientException {
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(request);
|
||||
return execute(url, HttpMethod.PUT, requestCallback, null, uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<?> put(URI url, HttpEntity<?> request) throws RestClientException {
|
||||
public ListenableFuture<?> put(URI url, HttpEntity<?> request) throws RestClientException {
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(request);
|
||||
return execute(url, HttpMethod.PUT, requestCallback, null);
|
||||
}
|
||||
@@ -326,47 +348,64 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
// DELETE
|
||||
|
||||
@Override
|
||||
public Future<?> delete(String url, Object... urlVariables)
|
||||
public ListenableFuture<?> delete(String url, Object... urlVariables)
|
||||
throws RestClientException {
|
||||
return execute(url, HttpMethod.DELETE, null, null, urlVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<?> delete(String url, Map<String, ?> urlVariables)
|
||||
public ListenableFuture<?> delete(String url, Map<String, ?> urlVariables)
|
||||
throws RestClientException {
|
||||
return execute(url, HttpMethod.DELETE, null, null, urlVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<?> delete(URI url) throws RestClientException {
|
||||
public ListenableFuture<?> delete(URI url) throws RestClientException {
|
||||
return execute(url, HttpMethod.DELETE, null, null);
|
||||
}
|
||||
|
||||
// OPTIONS
|
||||
|
||||
@Override
|
||||
public Future<Set<HttpMethod>> optionsForAllow(String url, Object... uriVariables) throws RestClientException {
|
||||
public ListenableFuture<Set<HttpMethod>> optionsForAllow(String url, Object... uriVariables) throws RestClientException {
|
||||
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
|
||||
Future<HttpHeaders> headersFuture = execute(url, HttpMethod.OPTIONS, null, headersExtractor, uriVariables);
|
||||
ListenableFuture<HttpHeaders> headersFuture = execute(url, HttpMethod.OPTIONS, null, headersExtractor, uriVariables);
|
||||
return extractAllowHeader(headersFuture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Set<HttpMethod>> optionsForAllow(String url, Map<String, ?> uriVariables) throws RestClientException {
|
||||
public ListenableFuture<Set<HttpMethod>> optionsForAllow(String url, Map<String, ?> uriVariables) throws RestClientException {
|
||||
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
|
||||
Future<HttpHeaders> headersFuture = execute(url, HttpMethod.OPTIONS, null, headersExtractor, uriVariables);
|
||||
ListenableFuture<HttpHeaders> headersFuture = execute(url, HttpMethod.OPTIONS, null, headersExtractor, uriVariables);
|
||||
return extractAllowHeader(headersFuture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Set<HttpMethod>> optionsForAllow(URI url) throws RestClientException {
|
||||
public ListenableFuture<Set<HttpMethod>> optionsForAllow(URI url) throws RestClientException {
|
||||
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
|
||||
Future<HttpHeaders> headersFuture = execute(url, HttpMethod.OPTIONS, null, headersExtractor);
|
||||
ListenableFuture<HttpHeaders> headersFuture = execute(url, HttpMethod.OPTIONS, null, headersExtractor);
|
||||
return extractAllowHeader(headersFuture);
|
||||
}
|
||||
|
||||
private static Future<Set<HttpMethod>> extractAllowHeader(final Future<HttpHeaders> headersFuture) {
|
||||
return new Future<Set<HttpMethod>>() {
|
||||
private static ListenableFuture<Set<HttpMethod>> extractAllowHeader(final ListenableFuture<HttpHeaders> headersFuture) {
|
||||
return new ListenableFuture<Set<HttpMethod>>() {
|
||||
|
||||
@Override
|
||||
public void addCallback(
|
||||
final ListenableFutureCallback<? super Set<HttpMethod>> callback) {
|
||||
headersFuture.addCallback(new ListenableFutureCallback<HttpHeaders>() {
|
||||
@Override
|
||||
public void onSuccess(HttpHeaders result) {
|
||||
callback.onSuccess(result.getAllow());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
callback.onFailure(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return headersFuture.cancel(mayInterruptIfRunning);
|
||||
@@ -397,7 +436,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
// exchange
|
||||
|
||||
@Override
|
||||
public <T> Future<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
public <T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables)
|
||||
throws RestClientException {
|
||||
AsyncRequestCallback requestCallback =
|
||||
@@ -408,7 +447,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
public <T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
HttpEntity<?> requestEntity, Class<T> responseType,
|
||||
Map<String, ?> uriVariables) throws RestClientException {
|
||||
AsyncRequestCallback requestCallback =
|
||||
@@ -419,7 +458,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<ResponseEntity<T>> exchange(URI url, HttpMethod method,
|
||||
public <T> ListenableFuture<ResponseEntity<T>> exchange(URI url, HttpMethod method,
|
||||
HttpEntity<?> requestEntity, Class<T> responseType)
|
||||
throws RestClientException {
|
||||
AsyncRequestCallback requestCallback =
|
||||
@@ -430,7 +469,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
public <T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType,
|
||||
Object... uriVariables) throws RestClientException {
|
||||
Type type = responseType.getType();
|
||||
@@ -441,7 +480,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
public <T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType,
|
||||
Map<String, ?> uriVariables) throws RestClientException {
|
||||
Type type = responseType.getType();
|
||||
@@ -452,7 +491,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<ResponseEntity<T>> exchange(URI url, HttpMethod method,
|
||||
public <T> ListenableFuture<ResponseEntity<T>> exchange(URI url, HttpMethod method,
|
||||
HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType)
|
||||
throws RestClientException {
|
||||
Type type = responseType.getType();
|
||||
@@ -466,7 +505,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
// general execution
|
||||
|
||||
@Override
|
||||
public <T> Future<T> execute(String url, HttpMethod method,
|
||||
public <T> ListenableFuture<T> execute(String url, HttpMethod method,
|
||||
AsyncRequestCallback requestCallback, ResponseExtractor<T> responseExtractor,
|
||||
Object... urlVariables) throws RestClientException {
|
||||
|
||||
@@ -475,7 +514,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<T> execute(String url, HttpMethod method,
|
||||
public <T> ListenableFuture<T> execute(String url, HttpMethod method,
|
||||
AsyncRequestCallback requestCallback, ResponseExtractor<T> responseExtractor,
|
||||
Map<String, ?> urlVariables) throws RestClientException {
|
||||
|
||||
@@ -484,7 +523,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<T> execute(URI url, HttpMethod method,
|
||||
public <T> ListenableFuture<T> execute(URI url, HttpMethod method,
|
||||
AsyncRequestCallback requestCallback, ResponseExtractor<T> responseExtractor)
|
||||
throws RestClientException {
|
||||
|
||||
@@ -504,7 +543,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> Future<T> doExecute(URI url, HttpMethod method, AsyncRequestCallback requestCallback,
|
||||
protected <T> ListenableFuture<T> doExecute(URI url, HttpMethod method, AsyncRequestCallback requestCallback,
|
||||
ResponseExtractor<T> responseExtractor) throws RestClientException {
|
||||
|
||||
Assert.notNull(url, "'url' must not be null");
|
||||
@@ -514,13 +553,9 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
if (requestCallback != null) {
|
||||
requestCallback.doWithRequest(request);
|
||||
}
|
||||
Future<ClientHttpResponse> responseFuture = request.executeAsync();
|
||||
if (responseExtractor != null) {
|
||||
return new ResponseExtractorFuture<T>(method, url, responseFuture, responseExtractor);
|
||||
}
|
||||
else {
|
||||
return (Future<T>) new VoidResponseFuture(method, url, responseFuture);
|
||||
}
|
||||
ListenableFuture<ClientHttpResponse> responseFuture = request.executeAsync();
|
||||
return new ResponseExtractorFuture<T>(method, url, responseFuture,
|
||||
responseExtractor);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new ResourceAccessException("I/O error on " + method.name() +
|
||||
@@ -594,47 +629,30 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
return this.syncTemplate.headersExtractor();
|
||||
}
|
||||
|
||||
|
||||
private abstract class ResponseFuture<T> implements Future<T> {
|
||||
/**
|
||||
* 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;
|
||||
|
||||
private final Future<ClientHttpResponse> responseFuture;
|
||||
private final ResponseExtractor<T> responseExtractor;
|
||||
|
||||
public ResponseFuture(HttpMethod method, URI url, Future<ClientHttpResponse> responseFuture) {
|
||||
public ResponseExtractorFuture(HttpMethod method, URI url,
|
||||
ListenableFuture<ClientHttpResponse> clientHttpResponseFuture,
|
||||
ResponseExtractor<T> responseExtractor) {
|
||||
super(clientHttpResponseFuture);
|
||||
this.method = method;
|
||||
this.url = url;
|
||||
this.responseFuture = responseFuture;
|
||||
this.responseExtractor = responseExtractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return this.responseFuture.cancel(mayInterruptIfRunning);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.responseFuture.isCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return this.responseFuture.isDone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() throws InterruptedException, ExecutionException {
|
||||
return getInternal(this.responseFuture.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
return getInternal(this.responseFuture.get(timeout, unit));
|
||||
}
|
||||
|
||||
private T getInternal(ClientHttpResponse response) throws ExecutionException {
|
||||
protected final T adapt(ClientHttpResponse response) throws ExecutionException {
|
||||
try {
|
||||
if (!getErrorHandler().hasError(response)) {
|
||||
logResponseStatus(this.method, this.url, response);
|
||||
@@ -642,7 +660,7 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
else {
|
||||
handleResponseError(this.method, this.url, response);
|
||||
}
|
||||
return extractData(response);
|
||||
return convertResponse(response);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new ExecutionException(ex);
|
||||
@@ -654,42 +672,13 @@ public class AsyncRestTemplate extends AsyncHttpAccessor implements AsyncRestOpe
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract T extractData(ClientHttpResponse response)
|
||||
throws IOException;
|
||||
protected T convertResponse(ClientHttpResponse response) throws IOException {
|
||||
return responseExtractor != null ? responseExtractor.extractData(response) :
|
||||
null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class ResponseExtractorFuture<T> extends ResponseFuture<T> {
|
||||
|
||||
private final ResponseExtractor<T> responseExtractor;
|
||||
|
||||
public ResponseExtractorFuture(HttpMethod method, URI url, Future<ClientHttpResponse> responseFuture,
|
||||
ResponseExtractor<T> responseExtractor) {
|
||||
super(method, url, responseFuture);
|
||||
this.responseExtractor = responseExtractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T extractData(ClientHttpResponse response) throws IOException {
|
||||
return responseExtractor.extractData(response);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class VoidResponseFuture extends ResponseFuture<Void> {
|
||||
|
||||
public VoidResponseFuture(HttpMethod method, URI url, Future<ClientHttpResponse> responseFuture) {
|
||||
super(method, url, responseFuture);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void extractData(ClientHttpResponse response) throws IOException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adapts a {@link RequestCallback} to the {@link AsyncRequestCallback} interface.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user