All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hedera.hashgraph.sdk.FutureConverter Maven / Gradle / Ivy

The newest version!
/*-
 *
 * Hedera Java SDK
 *
 * Copyright (C) 2020 - 2024 Hedera Hashgraph, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.hedera.hashgraph.sdk;

import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

// Converts between ListenableFuture (Guava) and CompletableFuture (StreamSupport).
// https://github.com/lukas-krecan/future-converter/blob/master/java8-guava/src/main/java/net/javacrumbs/futureconverter/java8guava/FutureConverter.java#L28
final class FutureConverter {
    private FutureConverter() {
    }

    /**
     * Generate a T object from a listenable future.
     *
     * @param listenableFuture          the T object generator
     * @return                          the T type object
     */
    static  CompletableFuture toCompletableFuture(ListenableFuture listenableFuture) {
        return Java8FutureUtils.createCompletableFuture(
            GuavaFutureUtils.createValueSourceFuture(listenableFuture));
    }

    // https://github.com/lukas-krecan/future-converter/blob/master/common/src/main/java/net/javacrumbs/futureconverter/common/internal/ValueSource.java
    private interface ValueSource {
        void addCallbacks(Consumer successCallback, Consumer failureCallback);

        boolean cancel(boolean mayInterruptIfRunning);
    }

    // https://github.com/lukas-krecan/future-converter/blob/master/common/src/main/java/net/javacrumbs/futureconverter/common/internal/ValueSourceFuture.java
    private abstract static class ValueSourceFuture extends FutureWrapper
        implements ValueSource {
        ValueSourceFuture(Future wrappedFuture) {
            super(wrappedFuture);
        }
    }

    // https://github.com/lukas-krecan/future-converter/blob/652b845824de90b075cf5ddbbda6fdf440f3ed0a/common/src/main/java/net/javacrumbs/futureconverter/common/internal/FutureWrapper.java
    private static class FutureWrapper implements Future {
        private final Future wrappedFuture;

        FutureWrapper(Future wrappedFuture) {
            this.wrappedFuture = wrappedFuture;
        }

        @Override
        public boolean cancel(boolean mayInterruptIfRunning) {
            return wrappedFuture.cancel(mayInterruptIfRunning);
        }

        @Override
        public boolean isCancelled() {
            return wrappedFuture.isCancelled();
        }

        @Override
        public boolean isDone() {
            return wrappedFuture.isDone();
        }

        @Override
        public T get() throws InterruptedException, ExecutionException {
            return wrappedFuture.get();
        }

        @Override
        public T get(long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException {
            return wrappedFuture.get(timeout, unit);
        }

        Future getWrappedFuture() {
            return wrappedFuture;
        }
    }

    // https://github.com/lukas-krecan/future-converter/blob/master/guava-common/src/main/java/net/javacrumbs/futureconverter/guavacommon/GuavaFutureUtils.java
    private static class GuavaFutureUtils {
        public static  ValueSourceFuture createValueSourceFuture(
            ListenableFuture listenableFuture) {
            if (listenableFuture instanceof ValueSourceFutureBackedListenableFuture) {
                return ((ValueSourceFutureBackedListenableFuture) listenableFuture)
                    .getWrappedFuture();
            } else {
                return new ListenableFutureBackedValueSourceFuture<>(listenableFuture);
            }
        }

        private static class ValueSourceFutureBackedListenableFuture extends FutureWrapper
            implements ListenableFuture {
            ValueSourceFutureBackedListenableFuture(ValueSourceFuture valueSourceFuture) {
                super(valueSourceFuture);
            }

            @Override
            ValueSourceFuture getWrappedFuture() {
                return (ValueSourceFuture) super.getWrappedFuture();
            }

            @Override
            public void addListener(Runnable listener, Executor executor) {
                getWrappedFuture()
                    .addCallbacks(
                        value -> executor.execute(listener),
                        ex -> executor.execute(listener));
            }
        }

        private static class ListenableFutureBackedValueSourceFuture
            extends ValueSourceFuture {
            private ListenableFutureBackedValueSourceFuture(ListenableFuture wrappedFuture) {
                super(wrappedFuture);
            }

            @Override
            public void addCallbacks(
                Consumer successCallback, Consumer failureCallback) {
                Futures.addCallback(
                    getWrappedFuture(),
                    new FutureCallback() {
                        @Override
                        public void onSuccess(T result) {
                            successCallback.accept(result);
                        }

                        @Override
                        public void onFailure(Throwable t) {
                            failureCallback.accept(t);
                        }
                    },
                    MoreExecutors.directExecutor());
            }

            @Override
            ListenableFuture getWrappedFuture() {
                return (ListenableFuture) super.getWrappedFuture();
            }
        }
    }

    // https://github.com/lukas-krecan/future-converter/blob/master/java8-common/src/main/java/net/javacrumbs/futureconverter/java8common/Java8FutureUtils.java
    private static class Java8FutureUtils {
        public static  CompletableFuture createCompletableFuture(ValueSource valueSource) {
            if (valueSource instanceof CompletableFutureBackedValueSource) {
                return ((CompletableFutureBackedValueSource) valueSource).getWrappedFuture();
            } else {
                return new ValueSourceBackedCompletableFuture(valueSource);
            }
        }

        private static final class ValueSourceBackedCompletableFuture
            extends CompletableFuture {
            private final ValueSource valueSource;

            @SuppressWarnings("ConstructorLeaksThis")
            private ValueSourceBackedCompletableFuture(ValueSource valueSource) {
                this.valueSource = valueSource;
                valueSource.addCallbacks(this::complete, this::completeExceptionally);
            }

            @Override
            public boolean cancel(boolean mayInterruptIfRunning) {
                if (isDone()) {
                    return false;
                }
                boolean result = valueSource.cancel(mayInterruptIfRunning);
                super.cancel(mayInterruptIfRunning);
                return result;
            }
        }

        private static final class CompletableFutureBackedValueSource
            extends ValueSourceFuture {
            private CompletableFutureBackedValueSource(CompletableFuture completableFuture) {
                super(completableFuture);
            }

            @Override
            public void addCallbacks(
                Consumer successCallback, Consumer failureCallback) {
                getWrappedFuture()
                    .whenComplete(
                        (v, t) -> {
                            if (t == null) {
                                successCallback.accept(v);
                            } else {
                                failureCallback.accept(t);
                            }
                        });
            }

            @Override
            CompletableFuture getWrappedFuture() {
                return (CompletableFuture) super.getWrappedFuture();
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy