001/*
002 * Copyright 2002-2016 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.Date;
020import java.util.Map;
021
022import org.quartz.JobDataMap;
023import org.quartz.JobDetail;
024import org.quartz.Scheduler;
025import org.quartz.SimpleTrigger;
026import org.quartz.impl.triggers.SimpleTriggerImpl;
027
028import org.springframework.beans.factory.BeanNameAware;
029import org.springframework.beans.factory.FactoryBean;
030import org.springframework.beans.factory.InitializingBean;
031import org.springframework.core.Constants;
032import org.springframework.util.Assert;
033
034/**
035 * A Spring {@link FactoryBean} for creating a Quartz {@link org.quartz.SimpleTrigger}
036 * instance, supporting bean-style usage for trigger configuration.
037 *
038 * <p>{@code SimpleTrigger(Impl)} itself is already a JavaBean but lacks sensible defaults.
039 * This class uses the Spring bean name as job name, the Quartz default group ("DEFAULT")
040 * as job group, the current time as start time, and indefinite repetition, if not specified.
041 *
042 * <p>This class will also register the trigger with the job name and group of
043 * a given {@link org.quartz.JobDetail}. This allows {@link SchedulerFactoryBean}
044 * to automatically register a trigger for the corresponding JobDetail,
045 * instead of registering the JobDetail separately.
046 *
047 * @author Juergen Hoeller
048 * @since 3.1
049 * @see #setName
050 * @see #setGroup
051 * @see #setStartDelay
052 * @see #setJobDetail
053 * @see SchedulerFactoryBean#setTriggers
054 * @see SchedulerFactoryBean#setJobDetails
055 */
056public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, BeanNameAware, InitializingBean {
057
058        /** Constants for the SimpleTrigger class */
059        private static final Constants constants = new Constants(SimpleTrigger.class);
060
061
062        private String name;
063
064        private String group;
065
066        private JobDetail jobDetail;
067
068        private JobDataMap jobDataMap = new JobDataMap();
069
070        private Date startTime;
071
072        private long startDelay;
073
074        private long repeatInterval;
075
076        private int repeatCount = -1;
077
078        private int priority;
079
080        private int misfireInstruction;
081
082        private String description;
083
084        private String beanName;
085
086        private SimpleTrigger simpleTrigger;
087
088
089        /**
090         * Specify the trigger's name.
091         */
092        public void setName(String name) {
093                this.name = name;
094        }
095
096        /**
097         * Specify the trigger's group.
098         */
099        public void setGroup(String group) {
100                this.group = group;
101        }
102
103        /**
104         * Set the JobDetail that this trigger should be associated with.
105         */
106        public void setJobDetail(JobDetail jobDetail) {
107                this.jobDetail = jobDetail;
108        }
109
110        /**
111         * Set the trigger's JobDataMap.
112         * @see #setJobDataAsMap
113         */
114        public void setJobDataMap(JobDataMap jobDataMap) {
115                this.jobDataMap = jobDataMap;
116        }
117
118        /**
119         * Return the trigger's JobDataMap.
120         */
121        public JobDataMap getJobDataMap() {
122                return this.jobDataMap;
123        }
124
125        /**
126         * Register objects in the JobDataMap via a given Map.
127         * <p>These objects will be available to this Trigger only,
128         * in contrast to objects in the JobDetail's data map.
129         * @param jobDataAsMap Map with String keys and any objects as values
130         * (for example Spring-managed beans)
131         */
132        public void setJobDataAsMap(Map<String, ?> jobDataAsMap) {
133                this.jobDataMap.putAll(jobDataAsMap);
134        }
135
136        /**
137         * Set a specific start time for the trigger.
138         * <p>Note that a dynamically computed {@link #setStartDelay} specification
139         * overrides a static timestamp set here.
140         */
141        public void setStartTime(Date startTime) {
142                this.startTime = startTime;
143        }
144
145        /**
146         * Set the start delay in milliseconds.
147         * <p>The start delay is added to the current system time (when the bean starts)
148         * to control the start time of the trigger.
149         * @see #setStartTime
150         */
151        public void setStartDelay(long startDelay) {
152                Assert.isTrue(startDelay >= 0, "Start delay cannot be negative");
153                this.startDelay = startDelay;
154        }
155
156        /**
157         * Specify the interval between execution times of this trigger.
158         */
159        public void setRepeatInterval(long repeatInterval) {
160                this.repeatInterval = repeatInterval;
161        }
162
163        /**
164         * Specify the number of times this trigger is supposed to fire.
165         * <p>Default is to repeat indefinitely.
166         */
167        public void setRepeatCount(int repeatCount) {
168                this.repeatCount = repeatCount;
169        }
170
171        /**
172         * Specify the priority of this trigger.
173         */
174        public void setPriority(int priority) {
175                this.priority = priority;
176        }
177
178        /**
179         * Specify a misfire instruction for this trigger.
180         */
181        public void setMisfireInstruction(int misfireInstruction) {
182                this.misfireInstruction = misfireInstruction;
183        }
184
185        /**
186         * Set the misfire instruction via the name of the corresponding
187         * constant in the {@link org.quartz.SimpleTrigger} class.
188         * Default is {@code MISFIRE_INSTRUCTION_SMART_POLICY}.
189         * @see org.quartz.SimpleTrigger#MISFIRE_INSTRUCTION_FIRE_NOW
190         * @see org.quartz.SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT
191         * @see org.quartz.SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
192         * @see org.quartz.SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
193         * @see org.quartz.SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
194         * @see org.quartz.Trigger#MISFIRE_INSTRUCTION_SMART_POLICY
195         */
196        public void setMisfireInstructionName(String constantName) {
197                this.misfireInstruction = constants.asNumber(constantName).intValue();
198        }
199
200        /**
201         * Associate a textual description with this trigger.
202         */
203        public void setDescription(String description) {
204                this.description = description;
205        }
206
207        @Override
208        public void setBeanName(String beanName) {
209                this.beanName = beanName;
210        }
211
212
213        @Override
214        public void afterPropertiesSet() {
215                if (this.name == null) {
216                        this.name = this.beanName;
217                }
218                if (this.group == null) {
219                        this.group = Scheduler.DEFAULT_GROUP;
220                }
221                if (this.jobDetail != null) {
222                        this.jobDataMap.put("jobDetail", this.jobDetail);
223                }
224                if (this.startDelay > 0 || this.startTime == null) {
225                        this.startTime = new Date(System.currentTimeMillis() + this.startDelay);
226                }
227
228                SimpleTriggerImpl sti = new SimpleTriggerImpl();
229                sti.setName(this.name);
230                sti.setGroup(this.group);
231                if (this.jobDetail != null) {
232                        sti.setJobKey(this.jobDetail.getKey());
233                }
234                sti.setJobDataMap(this.jobDataMap);
235                sti.setStartTime(this.startTime);
236                sti.setRepeatInterval(this.repeatInterval);
237                sti.setRepeatCount(this.repeatCount);
238                sti.setPriority(this.priority);
239                sti.setMisfireInstruction(this.misfireInstruction);
240                sti.setDescription(this.description);
241                this.simpleTrigger = sti;
242        }
243
244
245        @Override
246        public SimpleTrigger getObject() {
247                return this.simpleTrigger;
248        }
249
250        @Override
251        public Class<?> getObjectType() {
252                return SimpleTrigger.class;
253        }
254
255        @Override
256        public boolean isSingleton() {
257                return true;
258        }
259
260}