001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.util.concurrent;
018
019import java.util.concurrent.CompletableFuture;
020import java.util.concurrent.CompletionStage;
021import java.util.concurrent.ExecutionException;
022import java.util.concurrent.TimeUnit;
023import java.util.concurrent.TimeoutException;
024
025/**
026 * Adapts a {@link CompletableFuture} or {@link CompletionStage} into a
027 * Spring {@link ListenableFuture}.
028 *
029 * @author Sebastien Deleuze
030 * @author Juergen Hoeller
031 * @since 4.2
032 * @param <T> the result type returned by this Future's {@code get} method
033 */
034public class CompletableToListenableFutureAdapter<T> implements ListenableFuture<T> {
035
036        private final CompletableFuture<T> completableFuture;
037
038        private final ListenableFutureCallbackRegistry<T> callbacks = new ListenableFutureCallbackRegistry<>();
039
040
041        /**
042         * Create a new adapter for the given {@link CompletionStage}.
043         * @since 4.3.7
044         */
045        public CompletableToListenableFutureAdapter(CompletionStage<T> completionStage) {
046                this(completionStage.toCompletableFuture());
047        }
048
049        /**
050         * Create a new adapter for the given {@link CompletableFuture}.
051         */
052        public CompletableToListenableFutureAdapter(CompletableFuture<T> completableFuture) {
053                this.completableFuture = completableFuture;
054                this.completableFuture.whenComplete((result, ex) -> {
055                        if (ex != null) {
056                                this.callbacks.failure(ex);
057                        }
058                        else {
059                                this.callbacks.success(result);
060                        }
061                });
062        }
063
064
065        @Override
066        public void addCallback(ListenableFutureCallback<? super T> callback) {
067                this.callbacks.addCallback(callback);
068        }
069
070        @Override
071        public void addCallback(SuccessCallback<? super T> successCallback, FailureCallback failureCallback) {
072                this.callbacks.addSuccessCallback(successCallback);
073                this.callbacks.addFailureCallback(failureCallback);
074        }
075
076        @Override
077        public CompletableFuture<T> completable() {
078                return this.completableFuture;
079        }
080
081
082        @Override
083        public boolean cancel(boolean mayInterruptIfRunning) {
084                return this.completableFuture.cancel(mayInterruptIfRunning);
085        }
086
087        @Override
088        public boolean isCancelled() {
089                return this.completableFuture.isCancelled();
090        }
091
092        @Override
093        public boolean isDone() {
094                return this.completableFuture.isDone();
095        }
096
097        @Override
098        public T get() throws InterruptedException, ExecutionException {
099                return this.completableFuture.get();
100        }
101
102        @Override
103        public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
104                return this.completableFuture.get(timeout, unit);
105        }
106
107}