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