001/*
002 * Copyright 2012-2018 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 *      http://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.boot.task;
018
019import java.util.Arrays;
020import java.util.Collections;
021import java.util.LinkedHashSet;
022import java.util.Set;
023
024import org.springframework.boot.context.properties.PropertyMapper;
025import org.springframework.scheduling.TaskScheduler;
026import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
027import org.springframework.util.Assert;
028import org.springframework.util.CollectionUtils;
029
030/**
031 * Builder that can be used to configure and create a {@link TaskScheduler}. Provides
032 * convenience methods to set common {@link ThreadPoolTaskScheduler} settings. For
033 * advanced configuration, consider using {@link TaskSchedulerCustomizer}.
034 * <p>
035 * In a typical auto-configured Spring Boot application this builder is available as a
036 * bean and can be injected whenever a {@link TaskScheduler} is needed.
037 *
038 * @author Stephane Nicoll
039 * @since 2.1.0
040 */
041public class TaskSchedulerBuilder {
042
043        private final Integer poolSize;
044
045        private final String threadNamePrefix;
046
047        private final Set<TaskSchedulerCustomizer> customizers;
048
049        public TaskSchedulerBuilder() {
050                this.poolSize = null;
051                this.threadNamePrefix = null;
052                this.customizers = null;
053        }
054
055        public TaskSchedulerBuilder(Integer poolSize, String threadNamePrefix,
056                        Set<TaskSchedulerCustomizer> taskSchedulerCustomizers) {
057                this.poolSize = poolSize;
058                this.threadNamePrefix = threadNamePrefix;
059                this.customizers = taskSchedulerCustomizers;
060        }
061
062        /**
063         * Set the maximum allowed number of threads.
064         * @param poolSize the pool size to set
065         * @return a new builder instance
066         */
067        public TaskSchedulerBuilder poolSize(int poolSize) {
068                return new TaskSchedulerBuilder(poolSize, this.threadNamePrefix,
069                                this.customizers);
070        }
071
072        /**
073         * Set the prefix to use for the names of newly created threads.
074         * @param threadNamePrefix the thread name prefix to set
075         * @return a new builder instance
076         */
077        public TaskSchedulerBuilder threadNamePrefix(String threadNamePrefix) {
078                return new TaskSchedulerBuilder(this.poolSize, threadNamePrefix,
079                                this.customizers);
080        }
081
082        /**
083         * Set the {@link TaskSchedulerCustomizer TaskSchedulerCustomizers} that should be
084         * applied to the {@link ThreadPoolTaskScheduler}. Customizers are applied in the
085         * order that they were added after builder configuration has been applied. Setting
086         * this value will replace any previously configured customizers.
087         * @param customizers the customizers to set
088         * @return a new builder instance
089         * @see #additionalCustomizers(TaskSchedulerCustomizer...)
090         */
091        public TaskSchedulerBuilder customizers(TaskSchedulerCustomizer... customizers) {
092                Assert.notNull(customizers, "Customizers must not be null");
093                return customizers(Arrays.asList(customizers));
094        }
095
096        /**
097         * Set the {@link TaskSchedulerCustomizer taskSchedulerCustomizers} that should be
098         * applied to the {@link ThreadPoolTaskScheduler}. Customizers are applied in the
099         * order that they were added after builder configuration has been applied. Setting
100         * this value will replace any previously configured customizers.
101         * @param customizers the customizers to set
102         * @return a new builder instance
103         * @see #additionalCustomizers(TaskSchedulerCustomizer...)
104         */
105        public TaskSchedulerBuilder customizers(
106                        Iterable<TaskSchedulerCustomizer> customizers) {
107                Assert.notNull(customizers, "Customizers must not be null");
108                return new TaskSchedulerBuilder(this.poolSize, this.threadNamePrefix,
109                                append(null, customizers));
110        }
111
112        /**
113         * Add {@link TaskSchedulerCustomizer taskSchedulerCustomizers} that should be applied
114         * to the {@link ThreadPoolTaskScheduler}. Customizers are applied in the order that
115         * they were added after builder configuration has been applied.
116         * @param customizers the customizers to add
117         * @return a new builder instance
118         * @see #customizers(TaskSchedulerCustomizer...)
119         */
120        public TaskSchedulerBuilder additionalCustomizers(
121                        TaskSchedulerCustomizer... customizers) {
122                Assert.notNull(customizers, "Customizers must not be null");
123                return additionalCustomizers(Arrays.asList(customizers));
124        }
125
126        /**
127         * Add {@link TaskSchedulerCustomizer taskSchedulerCustomizers} that should be applied
128         * to the {@link ThreadPoolTaskScheduler}. Customizers are applied in the order that
129         * they were added after builder configuration has been applied.
130         * @param customizers the customizers to add
131         * @return a new builder instance
132         * @see #customizers(TaskSchedulerCustomizer...)
133         */
134        public TaskSchedulerBuilder additionalCustomizers(
135                        Iterable<TaskSchedulerCustomizer> customizers) {
136                Assert.notNull(customizers, "Customizers must not be null");
137                return new TaskSchedulerBuilder(this.poolSize, this.threadNamePrefix,
138                                append(this.customizers, customizers));
139        }
140
141        /**
142         * Build a new {@link ThreadPoolTaskScheduler} instance and configure it using this
143         * builder.
144         * @return a configured {@link ThreadPoolTaskScheduler} instance.
145         * @see #configure(ThreadPoolTaskScheduler)
146         */
147        public ThreadPoolTaskScheduler build() {
148                return configure(new ThreadPoolTaskScheduler());
149        }
150
151        /**
152         * Configure the provided {@link ThreadPoolTaskScheduler} instance using this builder.
153         * @param <T> the type of task scheduler
154         * @param taskScheduler the {@link ThreadPoolTaskScheduler} to configure
155         * @return the task scheduler instance
156         * @see #build()
157         */
158        public <T extends ThreadPoolTaskScheduler> T configure(T taskScheduler) {
159                PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
160                map.from(this.poolSize).to(taskScheduler::setPoolSize);
161                map.from(this.threadNamePrefix).to(taskScheduler::setThreadNamePrefix);
162                if (!CollectionUtils.isEmpty(this.customizers)) {
163                        this.customizers.forEach((customizer) -> customizer.customize(taskScheduler));
164                }
165                return taskScheduler;
166        }
167
168        private <T> Set<T> append(Set<T> set, Iterable<? extends T> additions) {
169                Set<T> result = new LinkedHashSet<>((set != null) ? set : Collections.emptySet());
170                additions.forEach(result::add);
171                return Collections.unmodifiableSet(result);
172        }
173
174}