com.microsoft.bingads.v13.reporting.ReportingOperationTracker Maven / Gradle / Ivy
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);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy