001/* 002 * Copyright 2002-2018 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.scheduling.annotation; 018 019import java.util.concurrent.CompletableFuture; 020import java.util.concurrent.ExecutionException; 021import java.util.concurrent.Future; 022import java.util.concurrent.TimeUnit; 023 024import org.springframework.lang.Nullable; 025import org.springframework.util.concurrent.FailureCallback; 026import org.springframework.util.concurrent.ListenableFuture; 027import org.springframework.util.concurrent.ListenableFutureCallback; 028import org.springframework.util.concurrent.SuccessCallback; 029 030/** 031 * A pass-through {@code Future} handle that can be used for method signatures 032 * which are declared with a {@code Future} return type for asynchronous execution. 033 * 034 * <p>As of Spring 4.1, this class implements {@link ListenableFuture}, not just 035 * plain {@link java.util.concurrent.Future}, along with the corresponding support 036 * in {@code @Async} processing. 037 * 038 * <p>As of Spring 4.2, this class also supports passing execution exceptions back 039 * to the caller. 040 * 041 * @author Juergen Hoeller 042 * @author Rossen Stoyanchev 043 * @since 3.0 044 * @param <V> the value type 045 * @see Async 046 * @see #forValue(Object) 047 * @see #forExecutionException(Throwable) 048 */ 049public class AsyncResult<V> implements ListenableFuture<V> { 050 051 @Nullable 052 private final V value; 053 054 @Nullable 055 private final Throwable executionException; 056 057 058 /** 059 * Create a new AsyncResult holder. 060 * @param value the value to pass through 061 */ 062 public AsyncResult(@Nullable V value) { 063 this(value, null); 064 } 065 066 /** 067 * Create a new AsyncResult holder. 068 * @param value the value to pass through 069 */ 070 private AsyncResult(@Nullable V value, @Nullable Throwable ex) { 071 this.value = value; 072 this.executionException = ex; 073 } 074 075 076 @Override 077 public boolean cancel(boolean mayInterruptIfRunning) { 078 return false; 079 } 080 081 @Override 082 public boolean isCancelled() { 083 return false; 084 } 085 086 @Override 087 public boolean isDone() { 088 return true; 089 } 090 091 @Override 092 @Nullable 093 public V get() throws ExecutionException { 094 if (this.executionException != null) { 095 throw (this.executionException instanceof ExecutionException ? 096 (ExecutionException) this.executionException : 097 new ExecutionException(this.executionException)); 098 } 099 return this.value; 100 } 101 102 @Override 103 @Nullable 104 public V get(long timeout, TimeUnit unit) throws ExecutionException { 105 return get(); 106 } 107 108 @Override 109 public void addCallback(ListenableFutureCallback<? super V> callback) { 110 addCallback(callback, callback); 111 } 112 113 @Override 114 public void addCallback(SuccessCallback<? super V> successCallback, FailureCallback failureCallback) { 115 try { 116 if (this.executionException != null) { 117 failureCallback.onFailure(exposedException(this.executionException)); 118 } 119 else { 120 successCallback.onSuccess(this.value); 121 } 122 } 123 catch (Throwable ex) { 124 // Ignore 125 } 126 } 127 128 @Override 129 public CompletableFuture<V> completable() { 130 if (this.executionException != null) { 131 CompletableFuture<V> completable = new CompletableFuture<>(); 132 completable.completeExceptionally(exposedException(this.executionException)); 133 return completable; 134 } 135 else { 136 return CompletableFuture.completedFuture(this.value); 137 } 138 } 139 140 141 /** 142 * Create a new async result which exposes the given value from {@link Future#get()}. 143 * @param value the value to expose 144 * @since 4.2 145 * @see Future#get() 146 */ 147 public static <V> ListenableFuture<V> forValue(V value) { 148 return new AsyncResult<>(value, null); 149 } 150 151 /** 152 * Create a new async result which exposes the given exception as an 153 * {@link ExecutionException} from {@link Future#get()}. 154 * @param ex the exception to expose (either an pre-built {@link ExecutionException} 155 * or a cause to be wrapped in an {@link ExecutionException}) 156 * @since 4.2 157 * @see ExecutionException 158 */ 159 public static <V> ListenableFuture<V> forExecutionException(Throwable ex) { 160 return new AsyncResult<>(null, ex); 161 } 162 163 /** 164 * Determine the exposed exception: either the cause of a given 165 * {@link ExecutionException}, or the original exception as-is. 166 * @param original the original as given to {@link #forExecutionException} 167 * @return the exposed exception 168 */ 169 private static Throwable exposedException(Throwable original) { 170 if (original instanceof ExecutionException) { 171 Throwable cause = original.getCause(); 172 if (cause != null) { 173 return cause; 174 } 175 } 176 return original; 177 } 178 179}