/* * NOTE: This copyright does *not* cover user programs that use HQ * program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development * Kit or the Hyperic Client Development Kit - this is merely considered * normal use of the program, and does *not* fall under the heading of * "derived work". * * Copyright (C) [2004-2008], Hyperic, Inc. * This file is part of HQ. * * HQ is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License as * published by the Free Software Foundation. This program is distributed * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ package org.hyperic.hq.application; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.hyperic.util.thread.LoggingThreadGroup; import org.hyperic.util.thread.ThreadGroupFactory; import org.springframework.beans.factory.DisposableBean; /** * A scheduler that internally uses a thread pool to permit concurrent execution * of scheduled tasks. This scheduler is preferable to a {@link java.util.Timer} * when the execution of one task may block long enough to delay execution of * other tasks. */ public class Scheduler implements DisposableBean { /** * Specify no initial delay when scheduling a task. */ public static final long NO_INITIAL_DELAY = 0; private final ScheduledThreadPoolExecutor _executor; /** * Creates a scheduler. * * @param poolSize The thread pool size. * @throws IllegalArgumentException if the pool size is less than or equal * to zero. */ public Scheduler(int poolSize) { if (poolSize <= 0) { throw new IllegalArgumentException("illegal pool size: " + poolSize); } LoggingThreadGroup threadGroup = new LoggingThreadGroup("SchedulerGroup"); // set pool threads as daemons in case an orderly shutdown does not // occur ThreadGroupFactory tFactory = new ThreadGroupFactory(threadGroup, "Scheduler-"); tFactory.createDaemonThreads(true); _executor = new ScheduledThreadPoolExecutor(poolSize, tFactory, new ThreadPoolExecutor.DiscardPolicy()); // delayed tasks should not execute after shutdown _executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); // prestart one thread to make sure the first execution is timely _executor.prestartCoreThread(); } /** * Creates and executes a periodic action that becomes enabled first after * the given initial delay, and subsequently with the given period; that is * executions will commence after initialDelay then initialDelay+period, * then initialDelay + 2 * period, and so on. If any execution of the task * encounters an exception, subsequent executions are suppressed. Otherwise, * the task will only terminate via cancellation or termination of the * executor. If any execution of this task takes longer than its period, * then subsequent executions may start late, but will not concurrently * execute. * * @param task The task to execute. * @param initialDelay The initial delay (in msec) before the first * execution. * @param period The period (in msec) between successive executions. * @return A ScheduledFuture that may be used to cancel task execution. */ public ScheduledFuture scheduleAtFixedRate(Runnable task, long initialDelay, long period) { return _executor.scheduleAtFixedRate(task, initialDelay, period, TimeUnit.MILLISECONDS); } /** * Creates and executes a periodic action that becomes enabled first after * the given initial delay, and subsequently with the given delay between * the termination of one execution and the commencement of the next. If any * execution of the task encounters an exception, subsequent executions are * suppressed. Otherwise, the task will only terminate via cancellation or * termination of the executor. * * @param task The task to execute. * @param initialDelay The initial delay (in msec) before the first * execution. * @param delay The delay (in msec) between termination of one execution and * commencement of the next. * @return A ScheduledFuture that may be used to cancel task execution. */ public ScheduledFuture scheduleWithFixedDelay(Runnable task, long initialDelay, long delay) { return _executor.scheduleWithFixedDelay(task, initialDelay, delay, TimeUnit.MILLISECONDS); } /** * Tries to remove from the work queue all {@link Future} tasks that have * been cancelled. This method can be useful as a storage reclamation * operation, that has no other impact on functionality. Cancelled tasks are * never executed, but may accumulate in work queues until worker threads * can actively remove them. Invoking this method instead tries to remove * them now. However, this method may fail to remove tasks in the presence * of interference by other threads. */ public void purgeTasks() { _executor.purge(); } /** * Shut down the scheduler in an orderly manner, allowing any currently * executing tasks to complete. */ public void shutdown() { _executor.shutdown(); // block at most for 5 seconds for any currently executing task to // terminate try { _executor.awaitTermination(5, TimeUnit.SECONDS); } catch (InterruptedException e) { // do nothing } } public void destroy() throws Exception { shutdown(); } }