public <T> ListenableFuture<T> scopeCallbacks(final ListenableFuture<T> callback) { final ScopedObjects scope = getScope(); return new ForwardingListenableFuture<T>() { @Override protected ListenableFuture<T> delegate() { return callback; } @Override public void addListener(Runnable listener, Executor exec) { super.addListener(listener, scope(exec, scope)); } }; }
private <T> ListenableFuture<T> wrapListenableFuture(final ListenableFuture<T> delegate) { /* * This creates a forwarding Future that overrides calls to get(...) to check, via the * ThreadLocal, if the caller is doing a blocking call on a thread from this executor. If * so, we detect this as a deadlock and throw an ExecutionException even though it may not * be a deadlock if there are more than 1 thread in the pool. Either way, there's bad * practice somewhere, either on the client side for doing a blocking call or in the * framework's threading model. */ return new ForwardingListenableFuture.SimpleForwardingListenableFuture<T>(delegate) { @Override public T get() throws InterruptedException, ExecutionException { checkDeadLockDetectorTL(); return super.get(); } @Override public T get(final long timeout, @Nonnull final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { checkDeadLockDetectorTL(); return super.get(timeout, unit); } void checkDeadLockDetectorTL() throws ExecutionException { if (deadlockDetector.get().isSet()) { throw new ExecutionException("A potential deadlock was detected.", deadlockExceptionFunction.get()); } } }; }