package net.jxta.impl.util.threads; import java.util.Collection; import java.util.Collections; import java.util.List; 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.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * ScheduledExecutorService implementation which performs the scheduling of * the tasks but then uses another ExecutorService implementation to actually * execute tasks. This allows for small, purpose-driven scheduled executors * to be created which then delegate to the more common application-level * thread pools. * * NOTE: This class is dynamically patched at build time by ant to support the * java 1.6 semantics for invokeAny and invokeAll if 1.6 is found. See the discussion * beginning at https://jxta.dev.java.net/servlets/ReadMsg?list=dev&msgNo=981 * */ public class ProxiedScheduledExecutorService implements ScheduledExecutorService { /** * ScheduledExecutorService instance used for task scheduling. */ private final ScheduledExecutorService schedExec; /** * ExecutorService used when we actually need to execute a task. */ private final ExecutorService targetExec; /** * Flag indicating whether or not shutdown commands should be forwarded * on to the wrapped ScheduledExecutorService instance. */ private final boolean forwardShutdown; /////////////////////////////////////////////////////////////////////////// // Constructors: /** * Creates a scheduled executor service which executes all tasks on the * specified executor service. This form creates an internal single * thread scheduled executor for scheduling purposes. * * @param targetExecutor executor service instance to use for task * execution */ public ProxiedScheduledExecutorService(final String name, final ExecutorService targetExecutor) { this(Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory(name + "-Local")), targetExecutor, true); } /** * Creates a scheduled executor service which executes all tasks on the * specified executor service. This form creates uses the provided * scheduled executor service instance for scheduling operations but * prevents the shutdown commands from impacting the underlying * scheduled executor service instance. * * @param schedExecutor scheduled executor service instance to use for * scheduling tasks * @param targetExecutor executor service instance to use for task * execution */ public ProxiedScheduledExecutorService( final ScheduledExecutorService schedExecutor, final ExecutorService targetExecutor) { this(schedExecutor, targetExecutor, false); } /** * Creates a scheduled executor service which executes all tasks on the * specified executor service. This form creates uses the provided * scheduled executor service instance for scheduling operations but * prevents the shutdown commands from impacting the underlying * scheduled executor service instance. * * @param schedExecutor scheduled executor service instance to use for * scheduling tasks * @param targetExecutor executor service instance to use for task * execution * @param forwardShutdownCommands flag indicating whether or not the * shutdown commands should impact the underlying scheduled executor * service instance. <code>true</code> if a call to * <code>shutdown()</code> or <code>shutdownNow()</code> should result * in the corresponding methods of the wrapped scheduled executor service * instance being called, <code>false</code> otherwise. */ public ProxiedScheduledExecutorService( final ScheduledExecutorService schedExecutor, final ExecutorService targetExecutor, final boolean forwardShutdownCommands) { schedExec = schedExecutor; targetExec = targetExecutor; forwardShutdown = forwardShutdownCommands; } /////////////////////////////////////////////////////////////////////////// // ScheduledExecutorService interface methods: /** * {@inheritDoc} * * This implementation wraps the provided Runnable in a proxy object which * then forwards the execution on to the target executor service instance * for execution. */ public ScheduledFuture<?> schedule( final Runnable command, final long delay, final TimeUnit unit) { ProxiedRunnable proxy = new ProxiedRunnable(targetExec, command); return schedExec.schedule(proxy, delay, unit); } /** * {@inheritDoc} * * This implementation wraps the provided Callable in a proxy object which * then forwards the execution on to the target executor service instance * for execution. * * @param <V> return type of the function */ public <V> ScheduledFuture<V> schedule( final Callable<V> callable, final long delay, final TimeUnit unit) { ProxiedCallable<V> proxy = new ProxiedCallable<V>(targetExec, callable); ScheduledFuture<V> schedFuture = schedExec.schedule(proxy, delay, unit); ProxiedScheduledFuture<V> proxyFuture = new ProxiedScheduledFuture<V>(schedFuture); proxy.setProxiedScheduledFuture(proxyFuture); return proxyFuture; } /** * {@inheritDoc} * * This implementation wraps the provided Runnable in a proxy object which * then forwards the execution on to the target executor service instance * for execution. */ public ScheduledFuture<?> scheduleAtFixedRate( final Runnable command, final long initialDelay, final long period, final TimeUnit unit) { ProxiedRunnable proxy = new ProxiedRunnable(targetExec, command); return schedExec.scheduleAtFixedRate( proxy, initialDelay, period, unit); } /** * {@inheritDoc} * * This implementation wraps the provided Runnable in a proxy object which * then forwards the execution on to the target executor service instance * for execution. */ public ScheduledFuture<?> scheduleWithFixedDelay( final Runnable command, final long initialDelay, final long delay, final TimeUnit unit) { ProxiedRunnable proxy = new ProxiedRunnable(targetExec, command); return schedExec.scheduleWithFixedDelay( proxy, initialDelay, delay, unit); } /////////////////////////////////////////////////////////////////////////// // ExecutorService interface methods: /** * {@inheritDoc} * * This implementation will call <code>shutdown()</code> on the wrapped * ScheduledExecutorService if requested during construction. Otherwise, * it does nothing. */ public void shutdown() { if (forwardShutdown) { schedExec.shutdown(); } } /** * {@inheritDoc} * * This implementation will call <code>shutdownNow()</code> on the wrapped * ScheduledExecutorService if requested during construction. Otherwise, * it always do nothing and return an empty list. */ public List<Runnable> shutdownNow() { if (forwardShutdown) { return schedExec.shutdownNow(); } else { return Collections.emptyList(); } } /** * {@inheritDoc} * * This implementation is equivalent to calling <code>isShutdown()</code> * on the wrapped ScheduledExecutorService. */ public boolean isShutdown() { return schedExec.isShutdown(); } /** * {@inheritDoc} * * This implementation is equivalent to calling <code>isShutdown()</code> * on the wrapped ScheduledExecutorService. */ public boolean isTerminated() { return schedExec.isTerminated(); } /** * {@inheritDoc} * * This implementation is equivalent to calling <code>isShutdown()</code> * on the wrapped ScheduledExecutorService. * * @throws InterruptedException if interrupted while waiting */ public boolean awaitTermination( final long timeout, final TimeUnit unit) throws InterruptedException { return schedExec.awaitTermination(timeout, unit); } /** * {@inheritDoc} * * This implementation is equivalent to calling the equivalent * <code>submit()</code> method on the wrapped ExecutorService instance. * * @param <T> return type of the function */ public <T> Future<T> submit(final Callable<T> task) { return targetExec.submit(task); } /** * {@inheritDoc} * * This implementation is equivalent to calling the equivalent * <code>submit()</code> method on the wrapped ExecutorService instance. * * @param <T> return type of the function */ public <T> Future<T> submit(final Runnable task, final T result) { return targetExec.submit(task, result); } /** * {@inheritDoc} * * This implementation is equivalent to calling the equivalent * <code>submit()</code> method on the wrapped ExecutorService instance. */ public Future<?> submit(final Runnable task) { return targetExec.submit(task); } /** * {@inheritDoc} */ public void execute(final Runnable command) { targetExec.execute(command); } /////////////////////////////////////////////////////////////////////////// // Public methods: /** * {@inheritDoc} * * This implementation calls <code>shutdownNow()</code>. */ @Override protected void finalize() throws Throwable { super.finalize(); shutdownNow(); } /** * {@inheritDoc} * * This implementation is equivalent to calling the equivalent * <code>invokeAll()</code> method on the wrapped ExecutorService instance. * * @param <T> return type of the function(s) * @throws InterruptedException if interrupted while waiting, in which * case unfinished tasks are cancelled */ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException { return targetExec.invokeAll(tasks); } /** * {@inheritDoc} * * This implementation is equivalent to calling the equivalent * <code>invokeAll()</code> method on the wrapped ExecutorService instance. * * @param <T> return type of the function(s) * @throws InterruptedException if interrupted while waiting, in which * case unfinished tasks are cancelled */ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException { return targetExec.invokeAll(tasks, timeout, unit); } /** * {@inheritDoc} * * This implementation is equivalent to calling the equivalent * <code>invokeAny()</code> method on the wrapped ExecutorService instance. * * @param <T> return type of the function(s) * @throws InterruptedException if interrupted while waiting, in which * case unfinished tasks are cancelled */ public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException { return targetExec.invokeAny(tasks); } /** * {@inheritDoc} * * This implementation is equivalent to calling the equivalent * <code>invokeAny()</code> method on the wrapped ExecutorService instance. * * @param <T> return type of the function(s) * @throws InterruptedException if interrupted while waiting */ public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return targetExec.invokeAny(tasks, timeout, unit); } }