|
| 1 | +/* |
| 2 | + * Copyright 2002-2011 the original author or authors. |
| 3 | + * |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | + * you may not use this file except in compliance with the License. |
| 6 | + * You may obtain a copy of the License at |
| 7 | + * |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | + * |
| 10 | + * Unless required by applicable law or agreed to in writing, software |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | + * See the License for the specific language governing permissions and |
| 14 | + * limitations under the License. |
| 15 | + */ |
| 16 | + |
| 17 | +package org.springframework.scheduling.quartz; |
| 18 | + |
| 19 | +import java.lang.reflect.Method; |
| 20 | +import java.util.Date; |
| 21 | +import java.util.Map; |
| 22 | +import java.util.TimeZone; |
| 23 | + |
| 24 | +import org.quartz.CronTrigger; |
| 25 | +import org.quartz.JobDataMap; |
| 26 | +import org.quartz.JobDetail; |
| 27 | +import org.quartz.Scheduler; |
| 28 | + |
| 29 | +import org.springframework.beans.BeanWrapper; |
| 30 | +import org.springframework.beans.BeanWrapperImpl; |
| 31 | +import org.springframework.beans.MutablePropertyValues; |
| 32 | +import org.springframework.beans.factory.BeanNameAware; |
| 33 | +import org.springframework.beans.factory.FactoryBean; |
| 34 | +import org.springframework.beans.factory.InitializingBean; |
| 35 | +import org.springframework.core.Constants; |
| 36 | +import org.springframework.util.Assert; |
| 37 | +import org.springframework.util.ReflectionUtils; |
| 38 | + |
| 39 | +/** |
| 40 | + * A Spring {@link FactoryBean} for creating a Quartz {@link org.quartz.CronTrigger} |
| 41 | + * instance, supporting bean-style usage for trigger configuration. |
| 42 | + * |
| 43 | + * <p><code>CronTrigger(Impl)</code> itself is already a JavaBean but lacks sensible defaults. |
| 44 | + * This class uses the Spring bean name as job name, the Quartz default group ("DEFAULT") |
| 45 | + * as job group, the current time as start time, and indefinite repetition, if not specified. |
| 46 | + * |
| 47 | + * <p>This class will also register the trigger with the job name and group of |
| 48 | + * a given {@link org.quartz.JobDetail}. This allows {@link SchedulerFactoryBean} |
| 49 | + * to automatically register a trigger for the corresponding JobDetail, |
| 50 | + * instead of registering the JobDetail separately. |
| 51 | + * |
| 52 | + * <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.0/2.1, |
| 53 | + * in contrast to the older {@link CronTriggerBean} class. |
| 54 | + * |
| 55 | + * @author Juergen Hoeller |
| 56 | + * @since 3.1 |
| 57 | + * @see #setName |
| 58 | + * @see #setGroup |
| 59 | + * @see #setStartTime |
| 60 | + * @see #setJobName |
| 61 | + * @see #setJobGroup |
| 62 | + * @see #setJobDetail |
| 63 | + * @see org.springframework.scheduling.quartz.SchedulerFactoryBean#setTriggers |
| 64 | + * @see org.springframework.scheduling.quartz.SchedulerFactoryBean#setJobDetails |
| 65 | + * @see org.springframework.scheduling.quartz.SimpleTriggerBean |
| 66 | + */ |
| 67 | +public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNameAware, InitializingBean { |
| 68 | + |
| 69 | + /** Constants for the CronTrigger class */ |
| 70 | + private static final Constants constants = new Constants(CronTrigger.class); |
| 71 | + |
| 72 | + |
| 73 | + private String name; |
| 74 | + |
| 75 | + private String group; |
| 76 | + |
| 77 | + private JobDetail jobDetail; |
| 78 | + |
| 79 | + private JobDataMap jobDataMap = new JobDataMap(); |
| 80 | + |
| 81 | + private Date startTime; |
| 82 | + |
| 83 | + private long startDelay; |
| 84 | + |
| 85 | + private String cronExpression; |
| 86 | + |
| 87 | + private TimeZone timeZone; |
| 88 | + |
| 89 | + private int priority; |
| 90 | + |
| 91 | + private int misfireInstruction; |
| 92 | + |
| 93 | + private String beanName; |
| 94 | + |
| 95 | + private CronTrigger cronTrigger; |
| 96 | + |
| 97 | + |
| 98 | + /** |
| 99 | + * Specify the trigger's name. |
| 100 | + */ |
| 101 | + public void setName(String name) { |
| 102 | + this.name = name; |
| 103 | + } |
| 104 | + |
| 105 | + /** |
| 106 | + * Specify the trigger's group. |
| 107 | + */ |
| 108 | + public void setGroup(String group) { |
| 109 | + this.group = group; |
| 110 | + } |
| 111 | + |
| 112 | + /** |
| 113 | + * Set the JobDetail that this trigger should be associated with. |
| 114 | + */ |
| 115 | + public void setJobDetail(JobDetail jobDetail) { |
| 116 | + this.jobDetail = jobDetail; |
| 117 | + } |
| 118 | + |
| 119 | + /** |
| 120 | + * Set the trigger's JobDataMap. |
| 121 | + * @see #setJobDataAsMap |
| 122 | + */ |
| 123 | + public void setJobDataMap(JobDataMap jobDataMap) { |
| 124 | + this.jobDataMap = jobDataMap; |
| 125 | + } |
| 126 | + |
| 127 | + /** |
| 128 | + * Return the trigger's JobDataMap. |
| 129 | + */ |
| 130 | + public JobDataMap getJobDataMap() { |
| 131 | + return this.jobDataMap; |
| 132 | + } |
| 133 | + |
| 134 | + /** |
| 135 | + * Register objects in the JobDataMap via a given Map. |
| 136 | + * <p>These objects will be available to this Trigger only, |
| 137 | + * in contrast to objects in the JobDetail's data map. |
| 138 | + * @param jobDataAsMap Map with String keys and any objects as values |
| 139 | + * (for example Spring-managed beans) |
| 140 | + * @see org.springframework.scheduling.quartz.JobDetailBean#setJobDataAsMap |
| 141 | + */ |
| 142 | + public void setJobDataAsMap(Map<String, ?> jobDataAsMap) { |
| 143 | + this.jobDataMap.putAll(jobDataAsMap); |
| 144 | + } |
| 145 | + |
| 146 | + /** |
| 147 | + * Set the start delay in milliseconds. |
| 148 | + * <p>The start delay is added to the current system time (when the bean starts) |
| 149 | + * to control the start time of the trigger. |
| 150 | + * @param startDelay the start delay, in milliseconds |
| 151 | + */ |
| 152 | + public void setStartDelay(long startDelay) { |
| 153 | + Assert.state(startDelay >= 0, "Start delay cannot be negative."); |
| 154 | + this.startDelay = startDelay; |
| 155 | + } |
| 156 | + |
| 157 | + /** |
| 158 | + * Specify the cron expression for this trigger. |
| 159 | + */ |
| 160 | + public void setCronExpression(String cronExpression) { |
| 161 | + this.cronExpression = cronExpression; |
| 162 | + } |
| 163 | + |
| 164 | + /** |
| 165 | + * Specify the time zone for this trigger's cron expression. |
| 166 | + */ |
| 167 | + public void setTimeZone(TimeZone timeZone) { |
| 168 | + this.timeZone = timeZone; |
| 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.CronTrigger} class. |
| 188 | + * Default is <code>MISFIRE_INSTRUCTION_SMART_POLICY</code>. |
| 189 | + * @see org.quartz.CronTrigger#MISFIRE_INSTRUCTION_FIRE_ONCE_NOW |
| 190 | + * @see org.quartz.CronTrigger#MISFIRE_INSTRUCTION_DO_NOTHING |
| 191 | + * @see org.quartz.Trigger#MISFIRE_INSTRUCTION_SMART_POLICY |
| 192 | + */ |
| 193 | + public void setMisfireInstructionName(String constantName) { |
| 194 | + this.misfireInstruction = constants.asNumber(constantName).intValue(); |
| 195 | + } |
| 196 | + |
| 197 | + public void setBeanName(String beanName) { |
| 198 | + this.beanName = beanName; |
| 199 | + } |
| 200 | + |
| 201 | + |
| 202 | + public void afterPropertiesSet() { |
| 203 | + if (this.name == null) { |
| 204 | + this.name = this.beanName; |
| 205 | + } |
| 206 | + if (this.group == null) { |
| 207 | + this.group = Scheduler.DEFAULT_GROUP; |
| 208 | + } |
| 209 | + if (this.jobDetail != null) { |
| 210 | + this.jobDataMap.put(JobDetailAwareTrigger.JOB_DETAIL_KEY, this.jobDetail); |
| 211 | + } |
| 212 | + if (this.startDelay > 0) { |
| 213 | + this.startTime = new Date(System.currentTimeMillis() + this.startDelay); |
| 214 | + } |
| 215 | + else if (this.startTime == null) { |
| 216 | + this.startTime = new Date(); |
| 217 | + } |
| 218 | + if (this.timeZone == null) { |
| 219 | + this.timeZone = TimeZone.getDefault(); |
| 220 | + } |
| 221 | + |
| 222 | + /* |
| 223 | + CronTriggerImpl cti = new CronTriggerImpl(); |
| 224 | + cti.setName(this.name); |
| 225 | + cti.setGroup(this.group); |
| 226 | + cti.setJobKey(this.jobDetail.getKey()); |
| 227 | + cti.setJobDataMap(this.jobDataMap); |
| 228 | + cti.setStartTime(this.startTime); |
| 229 | + cti.setCronExpression(this.cronExpression); |
| 230 | + cti.setTimeZone(this.timeZone); |
| 231 | + cti.setPriority(this.priority); |
| 232 | + cti.setMisfireInstruction(this.misfireInstruction); |
| 233 | + this.cronTrigger = cti; |
| 234 | + */ |
| 235 | + |
| 236 | + Class cronTriggerClass; |
| 237 | + Method jobKeyMethod; |
| 238 | + try { |
| 239 | + cronTriggerClass = getClass().getClassLoader().loadClass("org.quartz.impl.triggers.CronTriggerImpl"); |
| 240 | + jobKeyMethod = JobDetail.class.getMethod("getKey"); |
| 241 | + } |
| 242 | + catch (ClassNotFoundException ex) { |
| 243 | + cronTriggerClass = CronTrigger.class; |
| 244 | + jobKeyMethod = null; |
| 245 | + } |
| 246 | + catch (NoSuchMethodException ex) { |
| 247 | + throw new IllegalStateException("Incompatible Quartz version"); |
| 248 | + } |
| 249 | + BeanWrapper bw = new BeanWrapperImpl(cronTriggerClass); |
| 250 | + MutablePropertyValues pvs = new MutablePropertyValues(); |
| 251 | + pvs.add("name", this.name); |
| 252 | + pvs.add("group", this.group); |
| 253 | + if (jobKeyMethod != null) { |
| 254 | + pvs.add("jobKey", ReflectionUtils.invokeMethod(jobKeyMethod, this.jobDetail)); |
| 255 | + } |
| 256 | + else { |
| 257 | + pvs.add("jobName", this.jobDetail.getName()); |
| 258 | + pvs.add("jobGroup", this.jobDetail.getGroup()); |
| 259 | + } |
| 260 | + pvs.add("jobDataMap", this.jobDataMap); |
| 261 | + pvs.add("startTime", this.startTime); |
| 262 | + pvs.add("cronExpression", this.cronExpression); |
| 263 | + pvs.add("timeZone", this.timeZone); |
| 264 | + pvs.add("priority", this.priority); |
| 265 | + pvs.add("misfireInstruction", this.misfireInstruction); |
| 266 | + bw.setPropertyValues(pvs); |
| 267 | + this.cronTrigger = (CronTrigger) bw.getWrappedInstance(); |
| 268 | + } |
| 269 | + |
| 270 | + |
| 271 | + public CronTrigger getObject() { |
| 272 | + return this.cronTrigger; |
| 273 | + } |
| 274 | + |
| 275 | + public Class<?> getObjectType() { |
| 276 | + return CronTrigger.class; |
| 277 | + } |
| 278 | + |
| 279 | + public boolean isSingleton() { |
| 280 | + return true; |
| 281 | + } |
| 282 | + |
| 283 | +} |
0 commit comments