001/* 002 * This is free and unencumbered software released into the public domain. 003 * 004 * Anyone is free to copy, modify, publish, use, compile, sell, or 005 * distribute this software, either in source code form or as a compiled 006 * binary, for any purpose, commercial or non-commercial, and by any 007 * means. 008 * 009 * In jurisdictions that recognize copyright laws, the author or authors 010 * of this software dedicate any and all copyright interest in the 011 * software to the public domain. We make this dedication for the benefit 012 * of the public at large and to the detriment of our heirs and 013 * successors. We intend this dedication to be an overt act of 014 * relinquishment in perpetuity of all present and future rights to this 015 * software under copyright law. 016 * 017 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 018 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 019 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 020 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 021 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 022 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 023 * OTHER DEALINGS IN THE SOFTWARE. 024 * 025 * For more information, please refer to <http://unlicense.org/>. 026 */ 027 028package hm.binkley.util.concurrent; 029 030import hm.binkley.util.Mixin; 031 032import javax.annotation.Nonnull; 033import javax.annotation.Nullable; 034import java.util.concurrent.Callable; 035import java.util.concurrent.CancellationException; 036import java.util.concurrent.CompletableFuture; 037import java.util.concurrent.ExecutorService; 038import java.util.concurrent.Future; 039 040import static hm.binkley.util.Mixin.newMixin; 041import static java.util.concurrent.Executors.callable; 042 043/** 044 * {@code CompleteableExecutors} are executors returning {@link 045 * CompletableFuture} rather than plain {@link Future}. 046 * 047 * @author <a href="mailto:binkley@alumni.rice.edu">B. K. Oxley (binkley)</a> 048 * @todo Think through completable for scheduled 049 */ 050public final class CompletableExecutors { 051 /** 052 * Mixes the given <var>threads</var> (execution service) with overrides to 053 * provide a completable exection service. 054 * 055 * @param threads the execution service, never missin 056 * 057 * @return the completable execution service, never missing 058 */ 059 @Nonnull 060 public static CompletableExecutorService completable( 061 @Nonnull final ExecutorService threads) { 062 return newMixin(CompletableExecutorService.class, 063 new Overrides(threads), threads); 064 } 065 066 /** 067 * Overrides {@code ExecutorService} to covariantly return {@code 068 * CompletableFuture} in place of {@code Future}. 069 */ 070 public interface CompletableExecutorService 071 extends ExecutorService { 072 /** 073 * @return a completable future representing pending completion of the 074 * task, never missing 075 */ 076 @Nonnull 077 @Override 078 <T> CompletableFuture<T> submit(@Nonnull final Callable<T> task); 079 080 /** 081 * @return a completable future representing pending completion of the 082 * task, never missing 083 */ 084 @Nonnull 085 @Override 086 <T> CompletableFuture<T> submit(@Nonnull final Runnable task, 087 @Nullable final T result); 088 089 /** 090 * @return a completable future representing pending completion of the 091 * task, never missing 092 */ 093 @Nonnull 094 @Override 095 CompletableFuture<?> submit(@Nonnull final Runnable task); 096 } 097 098 /** 099 * Implements the overriden methods of {@link CompletableExecutorService} 100 * making the usable in a mixin. {@link Mixin#newMixin(Class, Object...) Mixins} currently require public delegates. 101 */ 102 public static final class Overrides { 103 private final ExecutorService threads; 104 105 private Overrides(final ExecutorService threads) { 106 this.threads = threads; 107 } 108 109 @Nonnull 110 public <T> CompletableFuture<T> submit( 111 @Nonnull final Callable<T> task) { 112 final CompletableFuture<T> cf = new CompletableFuture<>(); 113 threads.submit(() -> { 114 try { 115 cf.complete(task.call()); 116 } catch (final CancellationException e) { 117 cf.cancel(true); 118 } catch (final Exception e) { 119 cf.completeExceptionally(e); 120 } 121 }); 122 return cf; 123 } 124 125 @Nonnull 126 public <T> CompletableFuture<T> submit(@Nonnull final Runnable task, 127 @Nullable final T result) { 128 return submit(callable(task, result)); 129 } 130 131 @Nonnull 132 public CompletableFuture<?> submit(@Nonnull final Runnable task) { 133 return submit(callable(task)); 134 } 135 } 136}