Skip to content

Commit

Permalink
Merge 13fbc6b into d79facc
Browse files Browse the repository at this point in the history
  • Loading branch information
emmmile committed Nov 16, 2018
2 parents d79facc + 13fbc6b commit 36bc977
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 5 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@
<artifactId>guava</artifactId>
<version>26.0-jre</version>
</dependency>
<dependency>
<groupId>com.google.api</groupId>
<artifactId>gax</artifactId>
<version>1.35.0</version>
</dependency>

<!-- test dependencies -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2013-2014 Spotify AB
*
* 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.spotify.futures;

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.api.core.ApiFuture;
import com.google.common.util.concurrent.Uninterruptibles;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;

public class ApiFutureToCompletableFutureWrapper<V>
extends CompletableFuture<V>
implements Runnable {

private final ApiFuture<V> future;

ApiFutureToCompletableFutureWrapper(final ApiFuture<V> future, final Executor executor) {
this.future = checkNotNull(future, "future");
this.future.addListener(this, executor);
}

@Override
public boolean cancel(final boolean mayInterruptIfRunning) {
future.cancel(mayInterruptIfRunning);
return super.cancel(mayInterruptIfRunning);
}

public ApiFuture<V> unwrap() {
return future;
}

@Override
public void run() {
try {
complete(Uninterruptibles.getUninterruptibly(future));
} catch (final ExecutionException e) {
completeExceptionally(e.getCause());
} catch (final CancellationException e) {
cancel(false);
} catch (final RuntimeException e) {
completeExceptionally(e);
}
}
}
45 changes: 42 additions & 3 deletions src/main/java/com/spotify/futures/CompletableFuturesExtra.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
*/
package com.spotify.futures;

import com.google.api.core.ApiFuture;
import com.google.common.util.concurrent.ListenableFuture;

import com.google.common.util.concurrent.MoreExecutors;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import java.util.function.BiFunction;
import java.util.function.Function;

Expand Down Expand Up @@ -71,6 +73,45 @@ public static <V> ListenableFuture<V> toListenableFuture(
return new CompletableToListenableFutureWrapper<>(future);
}

/**
* Converts an {@link ApiFuture} to a {@link CompletableFuture}.
*
* @param future the {@link ApiFuture} to wrap.
* @return a {@link CompletableFuture} that completes when the original future completes.
*/
public static <V> CompletableFuture<V> toCompletableFuture(ApiFuture<V> future) {
return toCompletableFuture(future, MoreExecutors.directExecutor());
}

/**
* Converts an {@link ApiFuture} to a {@link CompletableFuture}.
*
* @param future the {@link ApiFuture} to wrap.
* @param executor the executor where the listener is running.
* @return a {@link CompletableFuture} that completes when the original future completes.
*/
public static <V> CompletableFuture<V> toCompletableFuture(ApiFuture<V> future,
Executor executor) {
if (future instanceof CompletableToApiFutureWrapper) {
return ((CompletableToApiFutureWrapper<V>) future).unwrap();
}
return new ApiFutureToCompletableFutureWrapper<>(future, executor);
}

/**
* Wrap a {@link CompletionStage} in a {@link ApiFuture}. The returned future will
* complete with the same result or failure as the original future.
*
* @param future The {@link CompletionStage} to wrap in a {@link ApiFuture}.
* @return A {@link ApiFuture} that completes when the original future completes.
*/
public static <V> ApiFuture<V> toApiFuture(CompletionStage<V> future) {
if (future instanceof ApiFutureToCompletableFutureWrapper) {
return ((ApiFutureToCompletableFutureWrapper<V>) future).unwrap();
}
return new CompletableToApiFutureWrapper<>(future);
}

/**
* Returns a new CompletableFuture that is already exceptionally completed with
* the given exception.
Expand Down Expand Up @@ -187,7 +228,6 @@ public Object apply(Object o) {
}
}


private enum WrapFunction implements Function {
INSTANCE;

Expand All @@ -196,5 +236,4 @@ public Object apply(Object o) {
return CompletableFuture.completedFuture(o);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2013-2014 Spotify AB
*
* 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.spotify.futures;

import com.google.api.core.ApiFuture;
import com.google.common.util.concurrent.AbstractFuture;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.function.BiConsumer;

public class CompletableToApiFutureWrapper<V> extends AbstractFuture<V>
implements ApiFuture<V>, BiConsumer<V, Throwable> {

private final CompletionStage<V> future;

CompletableToApiFutureWrapper(final CompletionStage<V> future) {
this.future = future;
}

public CompletableFuture<V> unwrap() {
return future.toCompletableFuture();
}

@Override
public void accept(V v, Throwable throwable) {
if (throwable != null) {
if (throwable instanceof CancellationException) {
cancel(false);
} else {
setException(CompletableToListenableFutureWrapper.unwrap(throwable));
}
} else {
set(v);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import com.google.common.util.concurrent.AbstractFuture;
import com.google.common.util.concurrent.ListenableFuture;

import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
Expand Down Expand Up @@ -58,7 +57,7 @@ public void accept(final V v, final Throwable throwable) {
}
}

private Throwable unwrap(Throwable throwable) {
static Throwable unwrap(Throwable throwable) {
// Don't go too deep in case there is recursive exceptions
for (int i = 0; i < 100; i++) {
if (throwable instanceof CompletionException) {
Expand Down

0 comments on commit 36bc977

Please sign in to comment.