com.microsoft.bingads.v13.reporting.ReportingOperationTracker Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of microsoft.bingads Show documentation
Show all versions of microsoft.bingads Show documentation
The Bing Ads Java SDK is a library improving developer experience when working with the Bing Ads services by providing high-level access to features such as Bulk API, OAuth Authorization and SOAP API.
package com.microsoft.bingads.v13.reporting;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import com.microsoft.bingads.AsyncCallback;
import com.microsoft.bingads.ServiceClient;
import com.microsoft.bingads.internal.OperationStatusRetry;
import com.microsoft.bingads.internal.ResultFuture;
import com.microsoft.bingads.internal.functionalinterfaces.Consumer;
import com.microsoft.bingads.internal.functionalinterfaces.TriConsumer;
/**
* Track the status of reporting operation.
*/
public class ReportingOperationTracker {
private static final int INITIAL_STATUS_CHECK_INTERVAL_IN_MS = 1000;
private static final int NUMBER_OF_INITIAL_STATUS_CHECKS = 5;
private int numberOfStatusChecks = 0;
private ScheduledExecutorService executorService;
private ReportingStatusProvider statusProvider;
private boolean stopTracking;
protected int lastProgressReported;
private ReportingOperationStatus currentStatus;
private final int statusCheckIntervalInMs;
private ResultFuture trackResultFuture;
private ServiceClient serviceClient;
private OperationStatusRetry operationStatusRetry;
private int numberOfStatusRetry = 4;
private final Runnable pollExecutorTask = new Runnable() {
@Override
public void run() {
pollOperationStatus();
}
};
public ReportingOperationTracker(ReportingStatusProvider statusProvider,
ServiceClient serviceClient, int statusCheckIntervalInMs) {
this.statusCheckIntervalInMs = statusCheckIntervalInMs;
this.statusProvider = statusProvider;
this.serviceClient = serviceClient;
this.operationStatusRetry = new OperationStatusRetry(
new Function() {
@Override
public Integer apply(Exception exception) {
Throwable cause = exception.getCause();
int errorCode = -1;
try {
errorCode = ((AdApiFaultDetail_Exception) cause).getFaultInfo().getErrors().getAdApiErrors()
.get(0).getCode();
} catch (Exception e) {
// Ignore
}
return errorCode;
}
});
}
AtomicBoolean statusUpdateInProgress = new AtomicBoolean(false);
public void pollOperationStatus() {
try {
if (!statusUpdateInProgress.compareAndSet(false, true)) {
return;
}
if (trackingWasStopped()) {
return;
}
if (cancelPollingIfRequestedByUser()) {
return;
}
refreshStatus(new AsyncCallback() {
@Override
public void onCompleted(Future result) {
try {
result.get();
numberOfStatusChecks++;
completeTaskIfOperationIsComplete();
} catch (InterruptedException ex) {
stopTracking();
propagateExceptionToCallingThread(new CouldNotGetReportingDownloadStatusException(ex));
} catch (ExecutionException ex) {
stopTracking();
propagateExceptionToCallingThread(new CouldNotGetReportingDownloadStatusException(ex));
} finally {
statusUpdateInProgress.set(false);
if (!stopTracking) {
int interval = INITIAL_STATUS_CHECK_INTERVAL_IN_MS;
if (numberOfStatusChecks >= NUMBER_OF_INITIAL_STATUS_CHECKS) {
interval = statusCheckIntervalInMs;
}
executorService.schedule(pollExecutorTask, interval, TimeUnit.MILLISECONDS);
}
}
}
});
} catch (Throwable ex) {
stopTracking();
propagateExceptionToCallingThread(ex);
}
}
private boolean cancelPollingIfRequestedByUser() {
if (trackResultFuture.isCancelled()) {
stopTracking();
return true;
}
return false;
}
private void propagateExceptionToCallingThread(Throwable ex) {
trackResultFuture.setException(ex);
}
private void completeTaskIfOperationIsComplete() {
if (operationIsComplete()) {
stopTracking();
completeTaskWithResult();
}
}
private void completeTaskWithResult() {
trackResultFuture.setResult(currentStatus);
}
private boolean operationIsComplete() {
return statusProvider.isFinalStatus(currentStatus);
}
private void refreshStatus(AsyncCallback callback) {
final ResultFuture resultFuture = new ResultFuture(
callback);
operationStatusRetry.executeWithRetry(
new TriConsumer, AsyncCallback>() {
@Override
public void accept(ReportingStatusProvider statusProvider,
ServiceClient serviceClient,
AsyncCallback callback) {
statusProvider.getCurrentStatus(serviceClient, callback);
}
}, statusProvider, serviceClient, new Consumer() {
@Override
public void accept(ReportingOperationStatus status) {
currentStatus = status;
resultFuture.setResult(currentStatus);
}
}, new Consumer() {
@Override
public void accept(Exception exception) {
resultFuture.setException(exception);
}
}, numberOfStatusRetry);
}
private boolean trackingWasStopped() {
return this.stopTracking;
}
private void stopTracking() {
this.stopTracking = true;
this.executorService.shutdown();
}
public Future trackResultFileAsync(AsyncCallback callback) {
this.trackResultFuture = new ResultFuture(callback);
this.startTracking();
return trackResultFuture;
}
private void startTracking() {
executorService = Executors.newSingleThreadScheduledExecutor();
executorService.schedule(pollExecutorTask, INITIAL_STATUS_CHECK_INTERVAL_IN_MS, TimeUnit.MILLISECONDS);
}
}