001/* 002 * Copyright (C) 2006 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 */ 014 015package com.google.common.util.concurrent; 016 017import static com.google.common.util.concurrent.Internal.toNanosSaturated; 018 019import com.google.common.annotations.GwtIncompatible; 020import com.google.common.annotations.J2ktIncompatible; 021import com.google.errorprone.annotations.CanIgnoreReturnValue; 022import com.google.errorprone.annotations.DoNotMock; 023import java.time.Duration; 024import java.util.concurrent.Callable; 025import java.util.concurrent.ExecutionException; 026import java.util.concurrent.TimeUnit; 027import java.util.concurrent.TimeoutException; 028import org.checkerframework.checker.nullness.qual.Nullable; 029 030/** 031 * Imposes a time limit on method calls. 032 * 033 * @author Kevin Bourrillion 034 * @author Jens Nyman 035 * @since 1.0 036 */ 037@DoNotMock("Use FakeTimeLimiter") 038@J2ktIncompatible 039@GwtIncompatible 040@ElementTypesAreNonnullByDefault 041public interface TimeLimiter { 042 043 /** 044 * Returns an instance of {@code interfaceType} that delegates all method calls to the {@code 045 * target} object, enforcing the specified time limit on each call. This time-limited delegation 046 * is also performed for calls to {@link Object#equals}, {@link Object#hashCode}, and {@link 047 * Object#toString}. 048 * 049 * <p>If the target method call finishes before the limit is reached, the return value or 050 * exception is propagated to the caller exactly as-is. If, on the other hand, the time limit is 051 * reached, the proxy will attempt to abort the call to the target, and will throw an {@link 052 * UncheckedTimeoutException} to the caller. 053 * 054 * <p>It is important to note that the primary purpose of the proxy object is to return control to 055 * the caller when the timeout elapses; aborting the target method call is of secondary concern. 056 * The particular nature and strength of the guarantees made by the proxy is 057 * implementation-dependent. However, it is important that each of the methods on the target 058 * object behaves appropriately when its thread is interrupted. 059 * 060 * <p>For example, to return the value of {@code target.someMethod()}, but substitute {@code 061 * DEFAULT_VALUE} if this method call takes over 50 ms, you can use this code: 062 * 063 * <pre> 064 * TimeLimiter limiter = . . .; 065 * TargetType proxy = limiter.newProxy( 066 * target, TargetType.class, 50, TimeUnit.MILLISECONDS); 067 * try { 068 * return proxy.someMethod(); 069 * } catch (UncheckedTimeoutException e) { 070 * return DEFAULT_VALUE; 071 * } 072 * </pre> 073 * 074 * @param target the object to proxy 075 * @param interfaceType the interface you wish the returned proxy to implement 076 * @param timeoutDuration with timeoutUnit, the maximum length of time that callers are willing to 077 * wait on each method call to the proxy 078 * @param timeoutUnit with timeoutDuration, the maximum length of time that callers are willing to 079 * wait on each method call to the proxy 080 * @return a time-limiting proxy 081 * @throws IllegalArgumentException if {@code interfaceType} is a regular class, enum, or 082 * annotation type, rather than an interface 083 */ 084 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 085 <T> T newProxy(T target, Class<T> interfaceType, long timeoutDuration, TimeUnit timeoutUnit); 086 087 /** 088 * Returns an instance of {@code interfaceType} that delegates all method calls to the {@code 089 * target} object, enforcing the specified time limit on each call. This time-limited delegation 090 * is also performed for calls to {@link Object#equals}, {@link Object#hashCode}, and {@link 091 * Object#toString}. 092 * 093 * <p>If the target method call finishes before the limit is reached, the return value or 094 * exception is propagated to the caller exactly as-is. If, on the other hand, the time limit is 095 * reached, the proxy will attempt to abort the call to the target, and will throw an {@link 096 * UncheckedTimeoutException} to the caller. 097 * 098 * <p>It is important to note that the primary purpose of the proxy object is to return control to 099 * the caller when the timeout elapses; aborting the target method call is of secondary concern. 100 * The particular nature and strength of the guarantees made by the proxy is 101 * implementation-dependent. However, it is important that each of the methods on the target 102 * object behaves appropriately when its thread is interrupted. 103 * 104 * <p>For example, to return the value of {@code target.someMethod()}, but substitute {@code 105 * DEFAULT_VALUE} if this method call takes over 50 ms, you can use this code: 106 * 107 * <pre> 108 * TimeLimiter limiter = . . .; 109 * TargetType proxy = limiter.newProxy(target, TargetType.class, Duration.ofMillis(50)); 110 * try { 111 * return proxy.someMethod(); 112 * } catch (UncheckedTimeoutException e) { 113 * return DEFAULT_VALUE; 114 * } 115 * </pre> 116 * 117 * @param target the object to proxy 118 * @param interfaceType the interface you wish the returned proxy to implement 119 * @param timeout the maximum length of time that callers are willing to wait on each method call 120 * to the proxy 121 * @return a time-limiting proxy 122 * @throws IllegalArgumentException if {@code interfaceType} is a regular class, enum, or 123 * annotation type, rather than an interface 124 * @since 28.0 125 */ 126 default <T> T newProxy(T target, Class<T> interfaceType, Duration timeout) { 127 return newProxy(target, interfaceType, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 128 } 129 130 /** 131 * Invokes a specified Callable, timing out after the specified time limit. If the target method 132 * call finishes before the limit is reached, the return value or a wrapped exception is 133 * propagated. If, on the other hand, the time limit is reached, we attempt to abort the call to 134 * the target, and throw a {@link TimeoutException} to the caller. 135 * 136 * @param callable the Callable to execute 137 * @param timeoutDuration with timeoutUnit, the maximum length of time to wait 138 * @param timeoutUnit with timeoutDuration, the maximum length of time to wait 139 * @return the result returned by the Callable 140 * @throws TimeoutException if the time limit is reached 141 * @throws InterruptedException if the current thread was interrupted during execution 142 * @throws ExecutionException if {@code callable} throws a checked exception 143 * @throws UncheckedExecutionException if {@code callable} throws a {@code RuntimeException} 144 * @throws ExecutionError if {@code callable} throws an {@code Error} 145 * @since 22.0 146 */ 147 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 148 @CanIgnoreReturnValue 149 @ParametricNullness 150 <T extends @Nullable Object> T callWithTimeout( 151 Callable<T> callable, long timeoutDuration, TimeUnit timeoutUnit) 152 throws TimeoutException, InterruptedException, ExecutionException; 153 154 /** 155 * Invokes a specified Callable, timing out after the specified time limit. If the target method 156 * call finishes before the limit is reached, the return value or a wrapped exception is 157 * propagated. If, on the other hand, the time limit is reached, we attempt to abort the call to 158 * the target, and throw a {@link TimeoutException} to the caller. 159 * 160 * @param callable the Callable to execute 161 * @param timeout the maximum length of time to wait 162 * @return the result returned by the Callable 163 * @throws TimeoutException if the time limit is reached 164 * @throws InterruptedException if the current thread was interrupted during execution 165 * @throws ExecutionException if {@code callable} throws a checked exception 166 * @throws UncheckedExecutionException if {@code callable} throws a {@code RuntimeException} 167 * @throws ExecutionError if {@code callable} throws an {@code Error} 168 * @since 28.0 169 */ 170 @CanIgnoreReturnValue 171 @ParametricNullness 172 default <T extends @Nullable Object> T callWithTimeout(Callable<T> callable, Duration timeout) 173 throws TimeoutException, InterruptedException, ExecutionException { 174 return callWithTimeout(callable, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 175 } 176 177 /** 178 * Invokes a specified Callable, timing out after the specified time limit. If the target method 179 * call finishes before the limit is reached, the return value or a wrapped exception is 180 * propagated. If, on the other hand, the time limit is reached, we attempt to abort the call to 181 * the target, and throw a {@link TimeoutException} to the caller. 182 * 183 * <p>The difference with {@link #callWithTimeout(Callable, long, TimeUnit)} is that this method 184 * will ignore interrupts on the current thread. 185 * 186 * @param callable the Callable to execute 187 * @param timeoutDuration with timeoutUnit, the maximum length of time to wait 188 * @param timeoutUnit with timeoutDuration, the maximum length of time to wait 189 * @return the result returned by the Callable 190 * @throws TimeoutException if the time limit is reached 191 * @throws ExecutionException if {@code callable} throws a checked exception 192 * @throws UncheckedExecutionException if {@code callable} throws a {@code RuntimeException} 193 * @throws ExecutionError if {@code callable} throws an {@code Error} 194 * @since 22.0 195 */ 196 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 197 @CanIgnoreReturnValue 198 @ParametricNullness 199 <T extends @Nullable Object> T callUninterruptiblyWithTimeout( 200 Callable<T> callable, long timeoutDuration, TimeUnit timeoutUnit) 201 throws TimeoutException, ExecutionException; 202 203 /** 204 * Invokes a specified Callable, timing out after the specified time limit. If the target method 205 * call finishes before the limit is reached, the return value or a wrapped exception is 206 * propagated. If, on the other hand, the time limit is reached, we attempt to abort the call to 207 * the target, and throw a {@link TimeoutException} to the caller. 208 * 209 * <p>The difference with {@link #callWithTimeout(Callable, Duration)} is that this method will 210 * ignore interrupts on the current thread. 211 * 212 * @param callable the Callable to execute 213 * @param timeout the maximum length of time to wait 214 * @return the result returned by the Callable 215 * @throws TimeoutException if the time limit is reached 216 * @throws ExecutionException if {@code callable} throws a checked exception 217 * @throws UncheckedExecutionException if {@code callable} throws a {@code RuntimeException} 218 * @throws ExecutionError if {@code callable} throws an {@code Error} 219 * @since 28.0 220 */ 221 @CanIgnoreReturnValue 222 @ParametricNullness 223 default <T extends @Nullable Object> T callUninterruptiblyWithTimeout( 224 Callable<T> callable, Duration timeout) throws TimeoutException, ExecutionException { 225 return callUninterruptiblyWithTimeout( 226 callable, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 227 } 228 229 /** 230 * Invokes a specified Runnable, timing out after the specified time limit. If the target method 231 * run finishes before the limit is reached, this method returns or a wrapped exception is 232 * propagated. If, on the other hand, the time limit is reached, we attempt to abort the run, and 233 * throw a {@link TimeoutException} to the caller. 234 * 235 * @param runnable the Runnable to execute 236 * @param timeoutDuration with timeoutUnit, the maximum length of time to wait 237 * @param timeoutUnit with timeoutDuration, the maximum length of time to wait 238 * @throws TimeoutException if the time limit is reached 239 * @throws InterruptedException if the current thread was interrupted during execution 240 * @throws UncheckedExecutionException if {@code runnable} throws a {@code RuntimeException} 241 * @throws ExecutionError if {@code runnable} throws an {@code Error} 242 * @since 22.0 243 */ 244 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 245 void runWithTimeout(Runnable runnable, long timeoutDuration, TimeUnit timeoutUnit) 246 throws TimeoutException, InterruptedException; 247 248 /** 249 * Invokes a specified Runnable, timing out after the specified time limit. If the target method 250 * run finishes before the limit is reached, this method returns or a wrapped exception is 251 * propagated. If, on the other hand, the time limit is reached, we attempt to abort the run, and 252 * throw a {@link TimeoutException} to the caller. 253 * 254 * @param runnable the Runnable to execute 255 * @param timeout the maximum length of time to wait 256 * @throws TimeoutException if the time limit is reached 257 * @throws InterruptedException if the current thread was interrupted during execution 258 * @throws UncheckedExecutionException if {@code runnable} throws a {@code RuntimeException} 259 * @throws ExecutionError if {@code runnable} throws an {@code Error} 260 * @since 28.0 261 */ 262 default void runWithTimeout(Runnable runnable, Duration timeout) 263 throws TimeoutException, InterruptedException { 264 runWithTimeout(runnable, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 265 } 266 267 /** 268 * Invokes a specified Runnable, timing out after the specified time limit. If the target method 269 * run finishes before the limit is reached, this method returns or a wrapped exception is 270 * propagated. If, on the other hand, the time limit is reached, we attempt to abort the run, and 271 * throw a {@link TimeoutException} to the caller. 272 * 273 * <p>The difference with {@link #runWithTimeout(Runnable, long, TimeUnit)} is that this method 274 * will ignore interrupts on the current thread. 275 * 276 * @param runnable the Runnable to execute 277 * @param timeoutDuration with timeoutUnit, the maximum length of time to wait 278 * @param timeoutUnit with timeoutDuration, the maximum length of time to wait 279 * @throws TimeoutException if the time limit is reached 280 * @throws UncheckedExecutionException if {@code runnable} throws a {@code RuntimeException} 281 * @throws ExecutionError if {@code runnable} throws an {@code Error} 282 * @since 22.0 283 */ 284 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 285 void runUninterruptiblyWithTimeout(Runnable runnable, long timeoutDuration, TimeUnit timeoutUnit) 286 throws TimeoutException; 287 288 /** 289 * Invokes a specified Runnable, timing out after the specified time limit. If the target method 290 * run finishes before the limit is reached, this method returns or a wrapped exception is 291 * propagated. If, on the other hand, the time limit is reached, we attempt to abort the run, and 292 * throw a {@link TimeoutException} to the caller. 293 * 294 * <p>The difference with {@link #runWithTimeout(Runnable, Duration)} is that this method will 295 * ignore interrupts on the current thread. 296 * 297 * @param runnable the Runnable to execute 298 * @param timeout the maximum length of time to wait 299 * @throws TimeoutException if the time limit is reached 300 * @throws UncheckedExecutionException if {@code runnable} throws a {@code RuntimeException} 301 * @throws ExecutionError if {@code runnable} throws an {@code Error} 302 * @since 28.0 303 */ 304 default void runUninterruptiblyWithTimeout(Runnable runnable, Duration timeout) 305 throws TimeoutException { 306 runUninterruptiblyWithTimeout(runnable, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 307 } 308}