diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/AzureClient.java b/azure-client-runtime/src/main/java/com/microsoft/azure/AzureClient.java index 62a760acb4a0d..729a0a0320113 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/AzureClient.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/AzureClient.java @@ -156,7 +156,7 @@ public ServiceResponseWithHeaders getPutOrPatchResultWi * @param callback the user callback to call when operation terminates. * @return the task describing the asynchronous polling. */ - public AsyncPollingTask getPutOrPatchResultAsync(Response response, Type resourceType, ServiceCall serviceCall, ServiceCallback callback) { + public AsyncPollingTask getPutOrPatchResultAsync(Response response, Type resourceType, ServiceCall serviceCall, ServiceCallback callback) { if (response == null) { callback.failure(new ServiceException("response is null.")); return null; @@ -211,7 +211,7 @@ public AsyncPollingTask getPutOrPatchResultAsync(Response r * @param callback the user callback to call when operation terminates. * @return the task describing the asynchronous polling. */ - public AsyncPollingTask getPutOrPatchResultWithHeadersAsync(Response response, Type resourceType, final Class headerType, final ServiceCall serviceCall, final ServiceCallback callback) { + public AsyncPollingTask getPutOrPatchResultWithHeadersAsync(Response response, Type resourceType, final Class headerType, final ServiceCall serviceCall, final ServiceCallback callback) { return this.getPutOrPatchResultAsync(response, resourceType, serviceCall, new ServiceCallback() { @Override public void failure(Throwable t) { @@ -329,7 +329,7 @@ public ServiceResponseWithHeaders getPostOrDeleteResult * @param callback the user callback to call when operation terminates. * @return the task describing the asynchronous polling. */ - public AsyncPollingTask getPostOrDeleteResultAsync(Response response, Type resourceType, ServiceCall serviceCall, ServiceCallback callback) { + public AsyncPollingTask getPostOrDeleteResultAsync(Response response, Type resourceType, ServiceCall serviceCall, ServiceCallback callback) { if (response == null) { callback.failure(new ServiceException("response is null.")); return null; @@ -383,7 +383,7 @@ public AsyncPollingTask getPostOrDeleteResultAsync(Response * @param callback the user callback to call when operation terminates. * @return the task describing the asynchronous polling. */ - public AsyncPollingTask getPostOrDeleteResultWithHeadersAsync(Response response, Type resourceType, final Class headerType, final ServiceCall serviceCall, final ServiceCallback callback) { + public AsyncPollingTask getPostOrDeleteResultWithHeadersAsync(Response response, Type resourceType, final Class headerType, final ServiceCall serviceCall, final ServiceCallback callback) { return this.getPostOrDeleteResultAsync(response, resourceType, serviceCall, new ServiceCallback() { @Override public void failure(Throwable t) { @@ -689,7 +689,7 @@ private Call pollAsync(String url, final ServiceCallback call = service.get(endpoint.getFile(), serviceClientUserAgent); - call.enqueue(new ServiceResponseCallback(callback) { + call.enqueue(new ServiceResponseCallback(null, callback) { @Override public void onResponse(Call call, Response response) { try { @@ -750,7 +750,7 @@ private interface AsyncService { */ abstract class AsyncPollingTask implements Runnable { /** The {@link Call} object from Retrofit. */ - protected ServiceCall serviceCall; + protected ServiceCall serviceCall; /** The polling state for the current operation. */ protected PollingState pollingState; /** The callback used for asynchronous polling. */ @@ -776,7 +776,7 @@ class PutPatchPollingTask extends AsyncPollingTask { * @param serviceCall the ServiceCall object tracking Retrofit calls. * @param clientCallback the client callback to call when a terminal status is hit. */ - PutPatchPollingTask(final PollingState pollingState, final String url, final ServiceCall serviceCall, final ServiceCallback clientCallback) { + PutPatchPollingTask(final PollingState pollingState, final String url, final ServiceCall serviceCall, final ServiceCallback clientCallback) { this.serviceCall = serviceCall; this.pollingState = pollingState; this.url = url; @@ -833,14 +833,17 @@ class PostDeletePollingTask extends AsyncPollingTask { * @param serviceCall the ServiceCall object tracking Retrofit calls. * @param clientCallback the client callback to call when a terminal status is hit. */ - PostDeletePollingTask(final PollingState pollingState, final ServiceCall serviceCall, final ServiceCallback clientCallback) { + PostDeletePollingTask(final PollingState pollingState, final ServiceCall serviceCall, final ServiceCallback clientCallback) { this.serviceCall = serviceCall; this.pollingState = pollingState; this.clientCallback = clientCallback; this.pollingCallback = new ServiceCallback() { @Override public void failure(Throwable t) { - clientCallback.failure(t); + if (clientCallback != null) { + clientCallback.failure(t); + } + serviceCall.failure(t); } @Override @@ -861,14 +864,23 @@ public void run() { && !pollingState.getLocationHeaderLink().isEmpty()) { updateStateFromLocationHeaderOnPostOrDeleteAsync(pollingState, pollingCallback); } else { - pollingCallback.failure(new ServiceException("No header in response")); + ServiceException serviceException = new ServiceException("No async header in response"); + pollingCallback.failure(serviceException); } } else { // Check if operation failed if (AzureAsyncOperation.getFailedStatuses().contains(pollingState.getStatus())) { - clientCallback.failure(new ServiceException("Async operation failed")); + ServiceException serviceException = new ServiceException("Async operation failed"); + if (clientCallback != null) { + clientCallback.failure(serviceException); + } + serviceCall.failure(serviceException); } else { - clientCallback.success(new ServiceResponse<>(pollingState.getResource(), pollingState.getResponse())); + ServiceResponse serviceResponse = new ServiceResponse<>(pollingState.getResource(), pollingState.getResponse()); + if (clientCallback != null) { + clientCallback.success(serviceResponse); + } + serviceCall.success(serviceResponse); } } } diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/TaskGroupBase.java b/azure-client-runtime/src/main/java/com/microsoft/azure/TaskGroupBase.java index 8a5547cac373c..62bf4d2d7c639 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/TaskGroupBase.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/TaskGroupBase.java @@ -68,7 +68,7 @@ public void execute() throws Exception { } @Override - public ServiceCall executeAsync(final ServiceCallback callback) { + public ServiceCall executeAsync(final ServiceCallback callback) { executeReadyTasksAsync(callback); return parallelServiceCall; } @@ -107,13 +107,17 @@ private ServiceCallback taskCallback(final DAGNode taskNode, final Service @Override public void failure(Throwable t) { callback.failure(t); + parallelServiceCall.failure(t); } @Override public void success(ServiceResponse result) { self.dag().reportedCompleted(taskNode); if (self.dag().isRootNode(taskNode)) { - callback.success(result); + if (callback != null) { + callback.success(result); + } + parallelServiceCall.success(result); } else { self.executeReadyTasksAsync(callback); } @@ -124,8 +128,8 @@ public void success(ServiceResponse result) { /** * Type represents a set of REST calls running possibly in parallel. */ - private class ParallelServiceCall extends ServiceCall { - private ConcurrentLinkedQueue serviceCalls; + private class ParallelServiceCall extends ServiceCall { + private ConcurrentLinkedQueue> serviceCalls; /** * Creates a ParallelServiceCall. @@ -139,7 +143,7 @@ private class ParallelServiceCall extends ServiceCall { * Cancels all the service calls currently executing. */ public void cancel() { - for (ServiceCall call : this.serviceCalls) { + for (ServiceCall call : this.serviceCalls) { call.cancel(); } } @@ -148,7 +152,7 @@ public void cancel() { * @return true if the call has been canceled; false otherwise. */ public boolean isCancelled() { - for (ServiceCall call : this.serviceCalls) { + for (ServiceCall call : this.serviceCalls) { if (!call.isCanceled()) { return false; } diff --git a/client-runtime/src/main/java/com/microsoft/rest/ServiceCall.java b/client-runtime/src/main/java/com/microsoft/rest/ServiceCall.java index dcffd781c7c59..94b1abfb9bb63 100644 --- a/client-runtime/src/main/java/com/microsoft/rest/ServiceCall.java +++ b/client-runtime/src/main/java/com/microsoft/rest/ServiceCall.java @@ -7,14 +7,18 @@ package com.microsoft.rest; +import com.google.common.util.concurrent.AbstractFuture; + import retrofit2.Call; /** * An instance of this class provides access to the underlying REST call invocation. * This class wraps around the Retrofit Call object and allows updates to it in the * progress of a long running operation or a paging operation. + * + * @param the type of the returning object */ -public class ServiceCall { +public class ServiceCall extends AbstractFuture> { /** * The Retrofit method invocation. */ @@ -62,4 +66,26 @@ public void cancel() { public boolean isCanceled() { return call.isCanceled(); } + + /** + * Invoke this method to report completed, allowing + * {@link AbstractFuture#get()} to be unblocked. + * + * @param result the service response returned. + * @return true if successfully reported; false otherwise. + */ + public boolean success(ServiceResponse result) { + return set(result); + } + + /** + * Invoke this method to report a failure, allowing + * {@link AbstractFuture#get()} to throw the exception. + * + * @param t the exception thrown. + * @return true if successfully reported; false otherwise. + */ + public boolean failure(Throwable t) { + return setException(t); + } } diff --git a/client-runtime/src/main/java/com/microsoft/rest/ServiceResponseCallback.java b/client-runtime/src/main/java/com/microsoft/rest/ServiceResponseCallback.java index 8808bfac9639c..a808869960294 100644 --- a/client-runtime/src/main/java/com/microsoft/rest/ServiceResponseCallback.java +++ b/client-runtime/src/main/java/com/microsoft/rest/ServiceResponseCallback.java @@ -18,6 +18,11 @@ * @param the response body type */ public abstract class ServiceResponseCallback implements Callback { + /** + * The client service call object. + */ + private ServiceCall serviceCall; + /** * The client callback. */ @@ -26,14 +31,21 @@ public abstract class ServiceResponseCallback implements Callback serviceCallback) { + public ServiceResponseCallback(ServiceCall serviceCall, ServiceCallback serviceCallback) { + this.serviceCall = serviceCall; this.serviceCallback = serviceCallback; } @Override public void onFailure(Call call, Throwable t) { - serviceCallback.failure(new ServiceException(t)); + if (serviceCallback != null) { + serviceCallback.failure(t); + } + if (serviceCall != null) { + serviceCall.failure(t); + } } } diff --git a/client-runtime/src/main/java/com/microsoft/rest/ServiceResponseEmptyCallback.java b/client-runtime/src/main/java/com/microsoft/rest/ServiceResponseEmptyCallback.java index fe848128c57df..2a82667795b27 100644 --- a/client-runtime/src/main/java/com/microsoft/rest/ServiceResponseEmptyCallback.java +++ b/client-runtime/src/main/java/com/microsoft/rest/ServiceResponseEmptyCallback.java @@ -17,6 +17,11 @@ * @param the response body type */ public abstract class ServiceResponseEmptyCallback implements Callback { + /** + * The client service call object. + */ + private ServiceCall serviceCall; + /** * The client callback. */ @@ -25,14 +30,21 @@ public abstract class ServiceResponseEmptyCallback implements Callback /** * Creates an instance of ServiceResponseCallback. * + * @param serviceCall the client service call to call on a terminal state. * @param serviceCallback the client callback to call on a terminal state. */ - public ServiceResponseEmptyCallback(ServiceCallback serviceCallback) { + public ServiceResponseEmptyCallback(ServiceCall serviceCall, ServiceCallback serviceCallback) { + this.serviceCall = serviceCall; this.serviceCallback = serviceCallback; } @Override public void onFailure(Call call, Throwable t) { - serviceCallback.failure(new ServiceException(t)); + if (serviceCallback != null) { + serviceCallback.failure(t); + } + if (serviceCall != null) { + serviceCall.failure(t); + } } }