com.microsoft.tfs.core.clients.versioncontrol.internal.concurrent.AccountingCompletionService.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.tfs.core.clients.versioncontrol.internal.concurrent.AccountingCompletionService.java

Source

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See License.txt in the repository root.

package com.microsoft.tfs.core.clients.versioncontrol.internal.concurrent;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Extends {@link ExecutorCompletionService} to count the number of tasks that
 * have been submitted so they can be waited on in bulk. Each wait call (
 * {@link #waitForCompletions()} and friends) resets the count so it can be
 * called again later.
 * <p>
 * {@link #take()}, {@link #poll()}, and
 * {@link #poll(long, java.util.concurrent.TimeUnit)} throw
 * {@link IllegalStateException} in this class; you can only use
 * {@link #waitForCompletions()}.
 *
 * @threadsafety thread-safe
 */
public class AccountingCompletionService<V> extends ExecutorCompletionService<V> {
    private final static Log log = LogFactory.getLog(AccountingCompletionService.class);

    /**
     * Keeps a count of the submissions that have not been waited on with
     * {@link #waitForCompletions(ResultProcessor, ExecutionExceptionHandler)}.
     */
    private long unwaitedSubmissions = 0;
    private final Object unwaitedSubmissionsLock = new Object();

    public AccountingCompletionService(final Executor executor, final BlockingQueue<Future<V>> completionQueue) {
        super(executor, completionQueue);
    }

    public AccountingCompletionService(final Executor executor) {
        super(executor);
    }

    @Override
    public Future<V> submit(final Callable<V> task) {
        synchronized (unwaitedSubmissionsLock) {
            final Future<V> ret = super.submit(task);
            unwaitedSubmissions++;
            return ret;
        }
    }

    @Override
    public Future<V> submit(final Runnable task, final V result) {
        synchronized (unwaitedSubmissionsLock) {
            final Future<V> ret = super.submit(task, result);
            unwaitedSubmissions++;
            return ret;
        }
    }

    /**
     * Not available. Use {@link #waitForCompletions()} instead.
     */
    @Override
    public Future<V> take() throws InterruptedException {
        throw new IllegalStateException();
    }

    /**
     * Not available. Use {@link #waitForCompletions()} instead.
     */
    @Override
    public Future<V> poll() {
        throw new IllegalStateException();
    }

    /**
     * Not available. Use {@link #waitForCompletions()} instead.
     */
    @Override
    public Future<V> poll(final long timeout, final TimeUnit unit) throws InterruptedException {
        throw new IllegalStateException();
    }

    /**
     * @equivalence waitForCompletions(null)
     */
    public void waitForCompletions() {
        // Locks for us
        waitForCompletions(null);
    }

    /**
     * @equivalence waitForCompletions(resultProcessor, null)
     */
    public void waitForCompletions(final ResultProcessor<V> resultProcessor) {
        // Locks for us
        waitForCompletions(resultProcessor, null);
    }

    /**
     * Waits for all the tasks previously submitted to this completion service
     * to finish by calling {@link CompletionService#take()} once for each
     * submitted task. Each tasks result is passed to an optional
     * {@link ResultProcessor} for processing.
     * <p>
     * Thread interruption stops the wait.
     *
     * @param resultProcessor
     *        an object to process the task results (may be <code>null</code>)
     * @param exceptionHandler
     *        an object to handle {@link ExecutionException}s produced by tasks
     *        (may be <code>null</code>)
     */
    public void waitForCompletions(final ResultProcessor<V> resultProcessor,
            final ExecutionExceptionHandler exceptionHandler) {
        long submittedCountCopy;

        synchronized (unwaitedSubmissionsLock) {
            submittedCountCopy = unwaitedSubmissions;
            unwaitedSubmissions = 0;
        }

        try {
            for (int i = 0; i < submittedCountCopy; i++) {
                final Future<V> f = super.take();
                try {
                    if (resultProcessor != null) {
                        resultProcessor.processResult(f.get());
                    }
                } catch (final ExecutionException e) {
                    log.debug("Execution exception", e); //$NON-NLS-1$

                    if (exceptionHandler != null) {
                        exceptionHandler.handleException(e);
                    }
                }
            }
        } catch (final InterruptedException e) {
            log.debug("Interrupted waiting for completion service take", e); //$NON-NLS-1$

            Thread.currentThread().interrupt();
        }
    }

    public static interface ResultProcessor<V> {
        /**
         * Process one result obtained by {@link CompletionService#take()}.
         *
         * @param result
         *        the result, which may be <code>null</code>
         */
        void processResult(final V result);
    }

    public static interface ExecutionExceptionHandler {
        /**
         * Handles one {@link ExecutionException} obtained when calling
         * {@link Future#get()}. The implementation may rethrow the exception as
         * a runtime exception to stop processing in
         * {@link AccountingCompletionService#waitForCompletions(ResultProcessor, ExecutionExceptionHandler)}
         * .
         *
         * @param e
         *        the exception (must not be <code>null</code>)
         */
        void handleException(final ExecutionException e);
    }
}