obsidian-launcher/src/com/google/common/util/concurrent/SimpleTimeLimiter.java
2022-08-09 23:00:29 -07:00

137 lines
5.2 KiB
Java

/*
* Decompiled with CFR 0.152.
*/
package com.google.common.util.concurrent;
import com.google.common.annotations.Beta;
import com.google.common.base.Preconditions;
import com.google.common.collect.ObjectArrays;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.TimeLimiter;
import com.google.common.util.concurrent.UncheckedTimeoutException;
import com.google.common.util.concurrent.Uninterruptibles;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@Beta
public final class SimpleTimeLimiter
implements TimeLimiter {
private final ExecutorService executor;
public SimpleTimeLimiter(ExecutorService executor) {
this.executor = Preconditions.checkNotNull(executor);
}
public SimpleTimeLimiter() {
this(Executors.newCachedThreadPool());
}
@Override
public <T> T newProxy(final T target, Class<T> interfaceType, final long timeoutDuration, final TimeUnit timeoutUnit) {
Preconditions.checkNotNull(target);
Preconditions.checkNotNull(interfaceType);
Preconditions.checkNotNull(timeoutUnit);
Preconditions.checkArgument(timeoutDuration > 0L, "bad timeout: %s", timeoutDuration);
Preconditions.checkArgument(interfaceType.isInterface(), "interfaceType must be an interface type");
final Set<Method> interruptibleMethods = SimpleTimeLimiter.findInterruptibleMethods(interfaceType);
InvocationHandler handler = new InvocationHandler(){
@Override
public Object invoke(Object obj, final Method method, final Object[] args) throws Throwable {
Callable<Object> callable = new Callable<Object>(){
@Override
public Object call() throws Exception {
try {
return method.invoke(target, args);
}
catch (InvocationTargetException e) {
SimpleTimeLimiter.throwCause(e, false);
throw new AssertionError((Object)"can't get here");
}
}
};
return SimpleTimeLimiter.this.callWithTimeout(callable, timeoutDuration, timeoutUnit, interruptibleMethods.contains(method));
}
};
return SimpleTimeLimiter.newProxy(interfaceType, handler);
}
@Override
public <T> T callWithTimeout(Callable<T> callable, long timeoutDuration, TimeUnit timeoutUnit, boolean amInterruptible) throws Exception {
Preconditions.checkNotNull(callable);
Preconditions.checkNotNull(timeoutUnit);
Preconditions.checkArgument(timeoutDuration > 0L, "timeout must be positive: %s", timeoutDuration);
Future<T> future = this.executor.submit(callable);
try {
if (amInterruptible) {
try {
return future.get(timeoutDuration, timeoutUnit);
}
catch (InterruptedException e) {
future.cancel(true);
throw e;
}
}
return Uninterruptibles.getUninterruptibly(future, timeoutDuration, timeoutUnit);
}
catch (ExecutionException e) {
throw SimpleTimeLimiter.throwCause(e, true);
}
catch (TimeoutException e) {
future.cancel(true);
throw new UncheckedTimeoutException(e);
}
}
private static Exception throwCause(Exception e, boolean combineStackTraces) throws Exception {
Throwable cause = e.getCause();
if (cause == null) {
throw e;
}
if (combineStackTraces) {
StackTraceElement[] combined = ObjectArrays.concat(cause.getStackTrace(), e.getStackTrace(), StackTraceElement.class);
cause.setStackTrace(combined);
}
if (cause instanceof Exception) {
throw (Exception)cause;
}
if (cause instanceof Error) {
throw (Error)cause;
}
throw e;
}
private static Set<Method> findInterruptibleMethods(Class<?> interfaceType) {
HashSet<Method> set = Sets.newHashSet();
for (Method m : interfaceType.getMethods()) {
if (!SimpleTimeLimiter.declaresInterruptedEx(m)) continue;
set.add(m);
}
return set;
}
private static boolean declaresInterruptedEx(Method method) {
for (Class<?> exType : method.getExceptionTypes()) {
if (exType != InterruptedException.class) continue;
return true;
}
return false;
}
private static <T> T newProxy(Class<T> interfaceType, InvocationHandler handler) {
Object object = Proxy.newProxyInstance(interfaceType.getClassLoader(), new Class[]{interfaceType}, handler);
return interfaceType.cast(object);
}
}