/**
* Copyright 2009-2016 the original author or authors.
*
* 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 net.javacrumbs.futureconverter.java8common;
import net.javacrumbs.futureconverter.common.internal.ValueSource;
import net.javacrumbs.futureconverter.common.internal.ValueSourceFuture;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
public class Java8FutureUtils {
public static <T> CompletableFuture<T> createCompletableFuture(ValueSource<T> valueSource) {
if (valueSource instanceof CompletableFuturebackedValueSource) {
return ((CompletableFuturebackedValueSource<T>) valueSource).getWrappedFuture();
} else {
return new ValueSourcebackedCompletableFuture<T>(valueSource);
}
}
public static <T> ValueSourceFuture<T> createValueSourceFuture(CompletableFuture<T> completableFuture) {
if (completableFuture instanceof ValueSourcebackedCompletableFuture &&
((ValueSourcebackedCompletableFuture<T>) completableFuture).getValueSource() instanceof ValueSourceFuture) {
return (ValueSourceFuture<T>) ((ValueSourcebackedCompletableFuture<T>) completableFuture).getValueSource();
} else {
return new CompletableFuturebackedValueSource<>(completableFuture);
}
}
public static <T> ValueSource<T> createValueSource(CompletableFuture<T> completableFuture) {
if (completableFuture instanceof ValueSourcebackedCompletableFuture) {
return ((ValueSourcebackedCompletableFuture<T>) completableFuture).getValueSource();
} else {
return new CompletableFuturebackedValueSource<>(completableFuture);
}
}
/**
* CompletableFuture that takes values from the ValueSource. CompletableFuture is a class, not
* an interface so we can not just forward events from the ValueSource, we to always instantiate the class.
*/
private static final class ValueSourcebackedCompletableFuture<T> extends CompletableFuture<T> {
private final ValueSource<T> valueSource;
private ValueSourcebackedCompletableFuture(ValueSource<T> 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 ValueSource<T> getValueSource() {
return valueSource;
}
}
private static final class CompletableFuturebackedValueSource<T> extends ValueSourceFuture<T> {
private CompletableFuturebackedValueSource(CompletableFuture<T> completableFuture) {
super(completableFuture);
}
@Override
public void addCallbacks(Consumer<T> successCallback, Consumer<Throwable> failureCallback) {
getWrappedFuture().whenComplete((v, t) -> {
if (t == null) {
successCallback.accept(v);
} else {
failureCallback.accept(t);
}
});
}
@Override
protected CompletableFuture<T> getWrappedFuture() {
return (CompletableFuture<T>) super.getWrappedFuture();
}
}
}