com.hedera.hashgraph.sdk.FutureConverter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sdk-full Show documentation
Show all versions of sdk-full Show documentation
Hedera™ Hashgraph SDK for Java
/*-
*
* 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();
}
}
}
}