com.microsoft.bingads.v13.internal.bulk.PollingBulkOperationTracker Maven / Gradle / Ivy
package com.microsoft.bingads.v13.internal.bulk;
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;
import com.microsoft.bingads.internal.utilities.ThreadPool;
import com.microsoft.bingads.v13.bulk.AdApiFaultDetail_Exception;
import com.microsoft.bingads.v13.bulk.BulkOperationProgressInfo;
import com.microsoft.bingads.v13.bulk.BulkOperationStatus;
import com.microsoft.bingads.v13.bulk.CouldNotGetBulkOperationStatusException;
import com.microsoft.bingads.v13.bulk.IBulkService;
import com.microsoft.bingads.v13.bulk.Progress;
public class PollingBulkOperationTracker implements BulkOperationTracker {
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 BulkOperationStatusProvider statusProvider;
private Progress progress;
private boolean stopTracking;
protected int lastProgressReported;
private BulkOperationStatus currentStatus;
private final int statusCheckIntervalInMs;
private ResultFuture> trackResultFuture;
private ServiceClient serviceClient;
private OperationStatusRetry, BulkOperationStatusProvider, IBulkService> operationStatusRetry;
private int numberOfStatusRetry = 4;
private final Runnable pollExecutorTask = new Runnable() {
@Override
public void run() {
pollOperationStatus();
}
};
public PollingBulkOperationTracker(BulkOperationStatusProvider statusProvider,
ServiceClient serviceClient, Progress progress,
int statusCheckIntervalInMs) {
this.statusCheckIntervalInMs = statusCheckIntervalInMs;
this.statusProvider = statusProvider;
this.serviceClient = serviceClient;
this.progress = progress;
this.operationStatusRetry = new OperationStatusRetry, BulkOperationStatusProvider, IBulkService>(
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++;
reportProgressIfNeeded();
completeTaskIfOperationIsComplete();
} catch (InterruptedException ex) {
stopTracking();
propagateExceptionToCallingThread(new CouldNotGetBulkOperationStatusException(ex));
} catch (ExecutionException ex) {
stopTracking();
propagateExceptionToCallingThread(new CouldNotGetBulkOperationStatusException(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 reportProgressIfNeeded() {
if (!userRequestedProgressReports()) {
return;
}
if (progressChangedSinceLastReport()) {
reportProgress();
}
}
private void reportProgress() {
final int percentage = currentStatus.getPercentComplete();
ThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
progress.report(new BulkOperationProgressInfo(percentage));
updateLastProgressReported(percentage);
} catch (Exception ex) {
// ignore exceptions from progress update thread
}
}
});
}
private boolean userRequestedProgressReports() {
return this.progress != null;
}
private boolean progressChangedSinceLastReport() {
return currentStatus.getPercentComplete() != lastProgressReported;
}
private void updateLastProgressReported(int per) {
this.lastProgressReported = per;
}
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, ServiceClient, AsyncCallback>>() {
@Override
public void accept(BulkOperationStatusProvider statusProvider,
ServiceClient serviceClient,
AsyncCallback> callback) {
statusProvider.getCurrentStatus(serviceClient, callback);
}
}, statusProvider, serviceClient, new Consumer>() {
@Override
public void accept(BulkOperationStatus 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();
}
/*
* (non-Javadoc)
*
* @see
* com.microsoft.bingads.api.internal.bulk.operations.BulkOperationTracker#
* trackResultFileAsync()
*/
@Override
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