package org.ovirt.engine.core.utils.timer; import static org.apache.commons.lang.StringUtils.isEmpty; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.quartz.SchedulerConfigException; import org.quartz.spi.ThreadPool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SchedulerThreadPool implements ThreadPool { private final Logger log = LoggerFactory.getLogger(getClass()); private ExecutorService executorService = null; private String schedulerName; private int count = -1; private int threadPriority = Thread.NORM_PRIORITY; private int queueSize = 50; private boolean inheritLoader; private boolean reject; public SchedulerThreadPool() { } @Override public boolean runInThread(Runnable runnable) { try { executorService.submit(runnable); return true; } catch (RejectedExecutionException e) { log.error("Task rejected due to: ", e); return false; } } @Override public int blockForAvailableThreads() { return 1; } @Override public void initialize() throws SchedulerConfigException { executorService = new ThreadPoolExecutor(10, count, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(queueSize), new SchedulerThreadFactory(this), isReject() ? new ThreadPoolExecutor.AbortPolicy() : new BlockedRejectedExecutionHandler(log)); } public void setThreadCount(int count) { this.count = count; } public int getThreadCount() { return count; } public void setThreadPriority(int prio) { this.threadPriority = prio; } public int getThreadPriority() { return threadPriority; } public void setReject(boolean reject) { this.reject = reject; } public boolean isReject() { return reject; } public boolean isThreadsInheritContextClassLoaderOfInitializingThread() { return inheritLoader; } public void setThreadsInheritContextClassLoaderOfInitializingThread( boolean inheritLoader) { this.inheritLoader = inheritLoader; } public int getQueueSize() { return queueSize; } public void setQueueSize(int queueSize) { this.queueSize = queueSize; } @Override public void shutdown(boolean waitForJobsToComplete) { if (waitForJobsToComplete) { try { executorService.awaitTermination(3600, TimeUnit.SECONDS); } catch (InterruptedException e) { log.error("there is a problem with cleanly shutdown the pool due to: {}", e.getMessage()); } } else { executorService.shutdownNow(); } } @Override public int getPoolSize() { return count; } @Override public void setInstanceId(String schedInstId) { } @Override public void setInstanceName(String schedName) { this.schedulerName = schedName; } public String getInstanceName() { if (isEmpty(this.schedulerName)) { return "SchedulerThreadPool"; } return this.schedulerName; } static class SchedulerThreadFactory implements ThreadFactory { private final AtomicInteger threadNumber = new AtomicInteger(1); private final ThreadGroup group; private SchedulerThreadPool pool; SchedulerThreadFactory(SchedulerThreadPool pool) { this.pool = pool; SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); } @Override public Thread newThread(Runnable r) { Thread t = new Thread(group, r, pool.getInstanceName() + threadNumber.getAndIncrement(), 0); t.setDaemon(false); t.setPriority(pool.getThreadPriority()); return t; } } /** * {@link BlockedRejectedExecutionHandler} waits on the queue to have space. * We do not want to reject any tasks. * */ static class BlockedRejectedExecutionHandler implements RejectedExecutionHandler { private Logger log; public BlockedRejectedExecutionHandler(Logger log) { this.log = log; } @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { if (!executor.isShutdown()) { try { executor.getQueue().put(r); } catch (InterruptedException e) { log.error("Thread was interrupted while waiting for space to schedule: {}", r); } } } } }