All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.bingads.v13.internal.bulk.PollingBulkOperationTracker Maven / Gradle / Ivy

Go to download

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.

There is a newer version: 13.0.22.1
Show newest version
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 - 2024 Weber Informatics LLC | Privacy Policy