// // ======================================================================== // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 // and Apache License v2.0 which accompanies this distribution. // // The Eclipse Public License is available at // http://www.eclipse.org/legal/epl-v10.html // // The Apache License v2.0 is available at // http://www.opensource.org/licenses/apache2.0.php // // You may elect to redistribute this code under either of these licenses. // ======================================================================== // package org.eclipse.jetty.util; import java.io.IOException; import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; public class FutureCallback implements Future<Void>,Callback { private static Throwable COMPLETED=new ConstantThrowable(); private final AtomicBoolean _done=new AtomicBoolean(false); private final CountDownLatch _latch=new CountDownLatch(1); private Throwable _cause; public FutureCallback() {} public FutureCallback(boolean completed) { if (completed) { _cause=COMPLETED; _done.set(true); _latch.countDown(); } } public FutureCallback(Throwable failed) { _cause=failed; _done.set(true); _latch.countDown(); } @Override public void succeeded() { if (_done.compareAndSet(false,true)) { _cause=COMPLETED; _latch.countDown(); } } @Override public void failed(Throwable cause) { if (_done.compareAndSet(false,true)) { _cause=cause; _latch.countDown(); } } @Override public boolean cancel(boolean mayInterruptIfRunning) { if (_done.compareAndSet(false,true)) { _cause=new CancellationException(); _latch.countDown(); return true; } return false; } @Override public boolean isCancelled() { if (_done.get()) { try { _latch.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } return _cause instanceof CancellationException; } return false; } @Override public boolean isDone() { return _done.get() && _latch.getCount()==0; } @Override public Void get() throws InterruptedException, ExecutionException { _latch.await(); if (_cause==COMPLETED) return null; if (_cause instanceof CancellationException) throw (CancellationException) new CancellationException().initCause(_cause); throw new ExecutionException(_cause); } @Override public Void get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { if (!_latch.await(timeout,unit)) throw new TimeoutException(); if (_cause==COMPLETED) return null; if (_cause instanceof TimeoutException) throw (TimeoutException)_cause; if (_cause instanceof CancellationException) throw (CancellationException) new CancellationException().initCause(_cause); throw new ExecutionException(_cause); } public static void rethrow(ExecutionException e) throws IOException { Throwable cause=e.getCause(); if (cause instanceof IOException) throw (IOException)cause; if (cause instanceof Error) throw (Error)cause; if (cause instanceof RuntimeException) throw (RuntimeException)cause; throw new RuntimeException(cause); } @Override public String toString() { return String.format("FutureCallback@%x{%b,%b}",hashCode(),_done.get(),_cause==COMPLETED); } }