package org.oddjob.framework; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; /** * Helper class for things that execute jobs in parallel. This class * ensures that all simultaneous executions are tracked, can be stopped, * can be waited for and allows an action to be run on completion of * all the simultaneous jobs. * * * @see SimultaneousStructural * * @author rob * */ public class AsyncExecutionSupport { /** The job threads. */ private final List<Future<?>> futures = Collections.synchronizedList( new ArrayList<Future<?>>()); /** Watch execution to start the state reflector when all children * have finished. */ private final ExecutionWatcher executionWatcher; /** * Create a new instance. * * @param onCompleteAction */ public AsyncExecutionSupport(Runnable onCompleteAction) { executionWatcher = new ExecutionWatcher(onCompleteAction); } public void submitJob(ExecutorService executorService, Runnable job) { Future<?> future = executorService.submit( executionWatcher.addJob(job)); futures.add(future); } public void joinOnAllJobs() throws InterruptedException, ExecutionException { for (Future<?> future : futures) { future.get(); } } /** * Start watching jobs for them to finish executing. */ public void startWatchingJobs() { executionWatcher.start(); } /** * Cancel all pending jobs. This will not stop jobs already executing * but will cancel pending jobs. Stopping jobs is left to calling * code. * <p> * Also stop watching executing jobs. */ public void cancelAllPendingJobs() { for (Future<?> future : futures) { future.cancel(false); } executionWatcher.stop(); } /** * Reset the internal state so that it can be used again with * a new set of jobs. */ public void reset() { executionWatcher.reset(); futures.clear(); } /** * The number of simultaneous job currently being tracked. * * @return */ public int size() { return futures.size(); } }