001/*
002 * Copyright 2002-2014 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.scheduling.quartz;
018
019import java.util.concurrent.Executor;
020import java.util.concurrent.RejectedExecutionException;
021
022import org.apache.commons.logging.Log;
023import org.apache.commons.logging.LogFactory;
024import org.quartz.SchedulerConfigException;
025import org.quartz.spi.ThreadPool;
026
027/**
028 * Quartz ThreadPool adapter that delegates to a Spring-managed
029 * TaskExecutor instance, specified on SchedulerFactoryBean.
030 *
031 * @author Juergen Hoeller
032 * @since 2.0
033 * @see SchedulerFactoryBean#setTaskExecutor
034 */
035public class LocalTaskExecutorThreadPool implements ThreadPool {
036
037        /** Logger available to subclasses */
038        protected final Log logger = LogFactory.getLog(getClass());
039
040        private Executor taskExecutor;
041
042
043        @Override
044        public void setInstanceId(String schedInstId) {
045        }
046
047        @Override
048        public void setInstanceName(String schedName) {
049        }
050
051
052        @Override
053        public void initialize() throws SchedulerConfigException {
054                // Absolutely needs thread-bound TaskExecutor to initialize.
055                this.taskExecutor = SchedulerFactoryBean.getConfigTimeTaskExecutor();
056                if (this.taskExecutor == null) {
057                        throw new SchedulerConfigException(
058                                "No local TaskExecutor found for configuration - " +
059                                "'taskExecutor' property must be set on SchedulerFactoryBean");
060                }
061        }
062
063        @Override
064        public void shutdown(boolean waitForJobsToComplete) {
065        }
066
067        @Override
068        public int getPoolSize() {
069                return -1;
070        }
071
072
073        @Override
074        public boolean runInThread(Runnable runnable) {
075                if (runnable == null) {
076                        return false;
077                }
078                try {
079                        this.taskExecutor.execute(runnable);
080                        return true;
081                }
082                catch (RejectedExecutionException ex) {
083                        logger.error("Task has been rejected by TaskExecutor", ex);
084                        return false;
085                }
086        }
087
088        @Override
089        public int blockForAvailableThreads() {
090                // The present implementation always returns 1, making Quartz
091                // always schedule any tasks that it feels like scheduling.
092                // This could be made smarter for specific TaskExecutors,
093                // for example calling {@code getMaximumPoolSize() - getActiveCount()}
094                // on a {@code java.util.concurrent.ThreadPoolExecutor}.
095                return 1;
096        }
097
098}