package io.dropwizard.client; import com.google.common.util.concurrent.ForwardingExecutorService; import io.dropwizard.util.Duration; import org.glassfish.jersey.client.ClientAsyncExecutor; import org.glassfish.jersey.spi.ExecutorServiceProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.ExecutorService; /** * An {@link ExecutorServiceProvider} implementation for use within * Dropwizard. * * With {DropwizardExecutorProvider.DisposableExecutorService}, one * can signal that an {ExecutorService} is to be gracefully shut down * upon its disposal by the Jersey runtime. It is used as a means of * signaling to {@link DropwizardExecutorProvider} that the executor * is not shared. */ @ClientAsyncExecutor class DropwizardExecutorProvider implements ExecutorServiceProvider { /** * An {@link ExecutorService} decorator used as a marker by * {@link DropwizardExecutorProvider#dispose} to induce service * shutdown. */ static class DisposableExecutorService extends ForwardingExecutorService { private final ExecutorService delegate; public DisposableExecutorService(ExecutorService delegate) { this.delegate = delegate; } @Override protected ExecutorService delegate() { return delegate; } } private static final Logger LOGGER = LoggerFactory.getLogger(DropwizardExecutorProvider.class); private final ExecutorService executor; private final Duration shutdownGracePeriod; DropwizardExecutorProvider(ExecutorService executor, Duration shutdownGracePeriod) { this.executor = executor; this.shutdownGracePeriod = shutdownGracePeriod; } @Override public ExecutorService getExecutorService() { return this.executor; } @Override public void dispose(ExecutorService executorService) { if (executorService instanceof DisposableExecutorService) { executorService.shutdown(); try { executorService.awaitTermination( shutdownGracePeriod.getQuantity(), shutdownGracePeriod.getUnit()); } catch (InterruptedException err) { LOGGER.warn("Interrupted while waiting for ExecutorService shutdown", err); } } } }