Package winterwell.utils.threads

Source Code of winterwell.utils.threads.SafeExecutor

package winterwell.utils.threads;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import winterwell.utils.NoisyCallableTest;
import winterwell.utils.TodoException;
import winterwell.utils.WrappedException;
import winterwell.utils.reporting.Log;

/**
* An executor which will report any exceptions via {@link Log}
* <p>
* Executors will quietly swallow exceptions (though {@link Future}s will throw
* exceptions). This strikes me as dangerous.
*
* @author daniel
*
* @param <T>
* @testedby {@link NoisyCallableTest}
*/
public class SafeExecutor implements ExecutorService {

  /**
   * Makes sure that exceptions get reported via {@link Log}
   *
   * @author daniel
   *
   */
  final class NoisyCallable<T> implements Callable<T> {

    private final Callable<T> base;

    public NoisyCallable(Callable<T> base) {
      this.base = base;
    }

    @Override
    public T call() throws Exception {
      try {
        return base.call();
      } catch (Exception e) {
        report(this, e);
        throw e;
      } catch (Throwable e) {
        report(this, e);
        throw new WrappedException(e);
      }
    }

  }

  /**
   * Makes sure that exceptions get reported via {@link Log}
   *
   * @author daniel
   *
   */
  final class NoisyRunnable implements Runnable {

    private final Runnable base;

    public NoisyRunnable(Runnable base) {
      this.base = base;
    }

    @Override
    public void run() throws WrappedException {
      try {
        base.run();
      } catch (Exception e) {
        report(this, e);
        throw new WrappedException(e);
      }
    }

  }

  private final ExecutorService base;

  public SafeExecutor(ExecutorService base) {
    this.base = base;
  }

  @Override
  public boolean awaitTermination(long timeout, TimeUnit unit)
      throws InterruptedException {
    // TODO do we need a shutdown flag here, & shutdown if necc?
    return base.awaitTermination(timeout, unit);
  }

  @Override
  public void execute(Runnable command) {
    base.execute(new NoisyRunnable(command));
  }

  @Override
  public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
      throws InterruptedException {
    throw new TodoException();
  }

  @Override
  public <T> List<Future<T>> invokeAll(
      Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
      throws InterruptedException {
    throw new TodoException();
  }

  @Override
  public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
      throws InterruptedException, ExecutionException {
    throw new TodoException();
  }

  @Override
  public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
      long timeout, TimeUnit unit) throws InterruptedException,
      ExecutionException, TimeoutException {
    throw new TodoException();
  }

  @Override
  public boolean isShutdown() {
    return base.isShutdown();
  }

  @Override
  public boolean isTerminated() {
    return base.isTerminated();
  }

  /**
   * Called when a task throws an exception. Reports it to {@link Log}. Can be
   * over-ridden.
   * <p>
   * Note that the {@link Future} object will also still throw an exception.
   *
   * @param noisyRunnable
   * @param e
   */
  public void report(Object runnableOrCallable, Throwable e) {
    Log.report(e);
  }

  @Override
  public void shutdown() {
    base.shutdown();
  }

  @Override
  public List<Runnable> shutdownNow() {
    return base.shutdownNow();
  }

  @Override
  public <T> Future<T> submit(Callable<T> task) {
    NoisyCallable<T> safeTask = new NoisyCallable<T>(task);
    return base.submit(safeTask);
  }

  @Override
  public Future<?> submit(Runnable task) {
    return base.submit(new NoisyRunnable(task));
  }

  @Override
  public <T> Future<T> submit(Runnable task, T result) {
    return base.submit(new NoisyRunnable(task), result);
  }

}
TOP

Related Classes of winterwell.utils.threads.SafeExecutor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.