001/* 002 * Copyright 2002-2017 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; 024import java.util.function.BiFunction; 025 026import org.springframework.lang.UsesJava8; 027 028/** 029 * Adapts a {@link CompletableFuture} or {@link CompletionStage} into a 030 * Spring {@link ListenableFuture}. 031 * 032 * @author Sebastien Deleuze 033 * @author Juergen Hoeller 034 * @since 4.2 035 */ 036@UsesJava8 037public class CompletableToListenableFutureAdapter<T> implements ListenableFuture<T> { 038 039 private final CompletableFuture<T> completableFuture; 040 041 private final ListenableFutureCallbackRegistry<T> callbacks = new ListenableFutureCallbackRegistry<T>(); 042 043 044 /** 045 * Create a new adapter for the given {@link CompletionStage}. 046 * @since 4.3.7 047 */ 048 public CompletableToListenableFutureAdapter(CompletionStage<T> completionStage) { 049 this(completionStage.toCompletableFuture()); 050 } 051 052 /** 053 * Create a new adapter for the given {@link CompletableFuture}. 054 */ 055 public CompletableToListenableFutureAdapter(CompletableFuture<T> completableFuture) { 056 this.completableFuture = completableFuture; 057 this.completableFuture.handle(new BiFunction<T, Throwable, Object>() { 058 @Override 059 public Object apply(T result, Throwable ex) { 060 if (ex != null) { 061 callbacks.failure(ex); 062 } 063 else { 064 callbacks.success(result); 065 } 066 return null; 067 } 068 }); 069 } 070 071 072 @Override 073 public void addCallback(ListenableFutureCallback<? super T> callback) { 074 this.callbacks.addCallback(callback); 075 } 076 077 @Override 078 public void addCallback(SuccessCallback<? super T> successCallback, FailureCallback failureCallback) { 079 this.callbacks.addSuccessCallback(successCallback); 080 this.callbacks.addFailureCallback(failureCallback); 081 } 082 083 @Override 084 public boolean cancel(boolean mayInterruptIfRunning) { 085 return this.completableFuture.cancel(mayInterruptIfRunning); 086 } 087 088 @Override 089 public boolean isCancelled() { 090 return this.completableFuture.isCancelled(); 091 } 092 093 @Override 094 public boolean isDone() { 095 return this.completableFuture.isDone(); 096 } 097 098 @Override 099 public T get() throws InterruptedException, ExecutionException { 100 return this.completableFuture.get(); 101 } 102 103 @Override 104 public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { 105 return this.completableFuture.get(timeout, unit); 106 } 107 108}