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}