ImmediateExecutor.java

  1. /*
  2.  * Copyright (c) 2020, Stein Eldar Johnsen
  3.  *
  4.  * Licensed to the Apache Software Foundation (ASF) under one
  5.  * or more contributor license agreements. See the NOTICE file
  6.  * distributed with this work for additional information
  7.  * regarding copyright ownership. The ASF licenses this file
  8.  * to you under the Apache License, Version 2.0 (the
  9.  * "License"); you may not use this file except in compliance
  10.  * with the License. You may obtain a copy of the License at
  11.  *
  12.  *   http://www.apache.org/licenses/LICENSE-2.0
  13.  *
  14.  * Unless required by applicable law or agreed to in writing,
  15.  * software distributed under the License is distributed on an
  16.  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  17.  * KIND, either express or implied. See the License for the
  18.  * specific language governing permissions and limitations
  19.  * under the License.
  20.  */
  21. package net.morimekta.testing.concurrent;

  22. import java.util.ArrayList;
  23. import java.util.Collection;
  24. import java.util.Collections;
  25. import java.util.List;
  26. import java.util.concurrent.Callable;
  27. import java.util.concurrent.CompletableFuture;
  28. import java.util.concurrent.ExecutionException;
  29. import java.util.concurrent.ExecutorService;
  30. import java.util.concurrent.Future;
  31. import java.util.concurrent.TimeUnit;

  32. import static java.util.Objects.requireNonNull;

  33. /**
  34.  * Fake executor service that runs all tasks immediately. If you need a fake
  35.  * executor that delays execution, use {@link ImmediateScheduledExecutor}, and
  36.  * trigger executions by ticking the clock.
  37.  */
  38. public class ImmediateExecutor implements ExecutorService {
  39.     /**
  40.      * Create an immediate executor.
  41.      */
  42.     public ImmediateExecutor() {}

  43.     @Override
  44.     public void shutdown() {
  45.         this.shutdownCalled = true;
  46.     }

  47.     @Override
  48.     public List<Runnable> shutdownNow() {
  49.         this.shutdownCalled = true;
  50.         return Collections.emptyList();
  51.     }

  52.     @Override
  53.     public boolean isShutdown() {
  54.         return shutdownCalled;
  55.     }

  56.     @Override
  57.     public boolean isTerminated() {
  58.         return shutdownCalled;
  59.     }

  60.     @Override
  61.     public boolean awaitTermination(long l, TimeUnit timeUnit) {
  62.         requireNonNull(timeUnit, "timeUnit == null");
  63.         if (!shutdownCalled) {
  64.             throw new IllegalStateException("Shutdown not triggered");
  65.         }
  66.         return true;
  67.     }

  68.     @Override
  69.     public <T> Future<T> submit(Callable<T> callable) {
  70.         requireNonNull(callable, "callable == null");
  71.         if (isShutdown()) {
  72.             throw new IllegalStateException("Executor is shut down");
  73.         }
  74.         try {
  75.             return CompletableFuture.completedFuture(callable.call());
  76.         } catch (Exception e) {
  77.             return CompletableFuture.failedFuture(e);
  78.         }
  79.     }

  80.     @Override
  81.     public <T> Future<T> submit(Runnable runnable, T t) {
  82.         requireNonNull(runnable, "runnable == null");
  83.         if (isShutdown()) {
  84.             throw new IllegalStateException("Executor is shut down");
  85.         }
  86.         try {
  87.             runnable.run();
  88.         } catch (Exception e) {
  89.             return CompletableFuture.failedFuture(e);
  90.         }
  91.         return CompletableFuture.completedFuture(t);
  92.     }

  93.     @Override
  94.     public Future<?> submit(Runnable runnable) {
  95.         return submit(runnable, null);
  96.     }

  97.     @Override
  98.     public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> collection) {
  99.         requireNonNull(collection, "collection == null");
  100.         if (isShutdown()) {
  101.             throw new IllegalStateException("Executor is shut down");
  102.         }

  103.         List<Future<T>> results = new ArrayList<>();
  104.         for (Callable<T> c : collection) {
  105.             results.add(submit(c));
  106.         }
  107.         return results;
  108.     }

  109.     @Override
  110.     public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> collection, long l, TimeUnit timeUnit) {
  111.         requireNonNull(timeUnit, "timeUnit == null");
  112.         return invokeAll(collection);
  113.     }

  114.     @Override
  115.     public <T> T invokeAny(Collection<? extends Callable<T>> collection) throws ExecutionException {
  116.         requireNonNull(collection, "collection == null");
  117.         if (isShutdown()) {
  118.             throw new IllegalStateException("Executor is shut down");
  119.         }

  120.         ExecutionException ex = null;
  121.         for (Callable<T> c : collection) {
  122.             try {
  123.                 return c.call();
  124.             } catch (Exception e) {
  125.                 if (ex == null) {
  126.                     ex = new ExecutionException("All " + collection.size() + " tasks failed, first exception", e);
  127.                 } else {
  128.                     ex.addSuppressed(e);
  129.                 }
  130.             }
  131.         }
  132.         if (ex == null) {
  133.             // because the collection was empty.
  134.             throw new IllegalArgumentException("Empty invoke collection");
  135.         }
  136.         throw ex;
  137.     }

  138.     @Override
  139.     public <T> T invokeAny(Collection<? extends Callable<T>> collection, long l, TimeUnit timeUnit)
  140.             throws ExecutionException {
  141.         requireNonNull(timeUnit, "timeUnit == null");
  142.         return invokeAny(collection);
  143.     }

  144.     @Override
  145.     @SuppressWarnings("FutureReturnValueIgnored")
  146.     public void execute(Runnable runnable) {
  147.         submit(runnable, null);
  148.     }

  149.     // ---- Private ----

  150.     private boolean shutdownCalled = false;
  151. }