/* * Created on 16.06.2015 */ package com.github.dockerjava.core.async; import java.io.Closeable; import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import javax.annotation.CheckForNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.github.dockerjava.api.async.ResultCallback; import com.google.common.base.Throwables; /** * Abstract template implementation of {@link ResultCallback} * * @author Marcus Linke * */ public abstract class ResultCallbackTemplate<RC_T extends ResultCallback<A_RES_T>, A_RES_T> implements ResultCallback<A_RES_T> { private static final Logger LOGGER = LoggerFactory.getLogger(ResultCallbackTemplate.class); private final CountDownLatch started = new CountDownLatch(1); private final CountDownLatch completed = new CountDownLatch(1); private Closeable stream; private boolean closed = false; private Throwable firstError = null; @Override public void onStart(Closeable stream) { this.stream = stream; this.closed = false; started.countDown(); } @Override public void onError(Throwable throwable) { if (closed) return; if (this.firstError == null) { this.firstError = throwable; } try { LOGGER.error("Error during callback", throwable); } finally { try { close(); } catch (IOException e) { throw new RuntimeException(e); } } } @Override public void onComplete() { try { close(); } catch (IOException e) { throw new RuntimeException(e); } } @Override public void close() throws IOException { if (!closed) { closed = true; if (stream != null) { stream.close(); } completed.countDown(); } } /** * Blocks until {@link ResultCallback#onComplete()} was called */ @SuppressWarnings("unchecked") public RC_T awaitCompletion() throws InterruptedException { completed.await(); // eventually (re)throws RuntimeException getFirstError(); return (RC_T) this; } /** * Blocks until {@link ResultCallback#onComplete()} was called or the given timeout occurs * @return {@code true} if completed and {@code false} if the waiting time elapsed * before {@link ResultCallback#onComplete()} was called. */ public boolean awaitCompletion(long timeout, TimeUnit timeUnit) throws InterruptedException { boolean result = completed.await(timeout, timeUnit); getFirstError(); return result; } /** * Blocks until {@link ResultCallback#onStart()} was called. {@link ResultCallback#onStart()} is called when the request was processed * on the server side and the response is incoming. */ @SuppressWarnings("unchecked") public RC_T awaitStarted() throws InterruptedException { started.await(); return (RC_T) this; } /** * Blocks until {@link ResultCallback#onStart()} was called or the given timeout occurs. {@link ResultCallback#onStart()} is called when * the request was processed on the server side and the response is incoming. * @return {@code true} if started and {@code false} if the waiting time elapsed * before {@link ResultCallback#onStart()} was called. */ public boolean awaitStarted(long timeout, TimeUnit timeUnit) throws InterruptedException { return started.await(timeout, timeUnit); } @CheckForNull protected RuntimeException getFirstError() { if (firstError != null) { // this call throws a RuntimeException return Throwables.propagate(firstError); } else { return null; } } }