Skip to content

Commit 16933a5

Browse files
committed
introduced JobDetail/CronTrigger/SimpleTriggerFactoryBean variants for Quartz 2.0/2.1 support (SPR-8275?)
1 parent 68f61f3 commit 16933a5

13 files changed

+836
-45
lines changed

org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/AdaptableJobFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
* JobFactory implementation that supports {@link java.lang.Runnable}
3131
* objects as well as standard Quartz {@link org.quartz.Job} instances.
3232
*
33-
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0, as of Spring 3.1.
33+
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
3434
*
3535
* @author Juergen Hoeller
3636
* @since 2.0

org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/CronTriggerBean.java

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
* Convenience subclass of Quartz's {@link org.quartz.CronTrigger} class,
3434
* making bean-style usage easier.
3535
*
36-
* <p>CronTrigger itself is already a JavaBean but lacks sensible defaults.
36+
* <p><code>CronTrigger</code> itself is already a JavaBean but lacks sensible defaults.
3737
* This class uses the Spring bean name as job name, the Quartz default group
3838
* ("DEFAULT") as job group, the current time as start time, and indefinite
3939
* repetition, if not specified.
@@ -44,8 +44,10 @@
4444
* instead of registering the JobDetail separately.
4545
*
4646
* <p><b>NOTE: This convenience subclass does not work against Quartz 2.0.</b>
47-
* Use Quartz 2.0's native <code>CronTriggerImpl</code> class or the new
48-
* Quartz 2.0 builder API instead.
47+
* Use Quartz 2.0's native <code>JobDetailImpl</code> class or the new Quartz 2.0
48+
* builder API instead. Alternatively, switch to Spring's {@link CronTriggerFactoryBean}
49+
* which largely is a drop-in replacement for this class and its properties and
50+
* consistently works against Quartz 1.x as well as Quartz 2.0/2.1.
4951
*
5052
* @author Juergen Hoeller
5153
* @since 18.02.2004
@@ -72,6 +74,7 @@ public class CronTriggerBean extends CronTrigger
7274

7375
private long startDelay;
7476

77+
7578
/**
7679
* Register objects in the JobDataMap via a given Map.
7780
* <p>These objects will be available to this Trigger only,
@@ -80,7 +83,7 @@ public class CronTriggerBean extends CronTrigger
8083
* (for example Spring-managed beans)
8184
* @see JobDetailBean#setJobDataAsMap
8285
*/
83-
public void setJobDataAsMap(Map jobDataAsMap) {
86+
public void setJobDataAsMap(Map<String, ?> jobDataAsMap) {
8487
getJobDataMap().putAll(jobDataAsMap);
8588
}
8689

@@ -110,6 +113,19 @@ public void setTriggerListenerNames(String[] names) {
110113
}
111114
}
112115

116+
/**
117+
* Set the start delay in milliseconds.
118+
* <p>The start delay is added to the current system time (when the bean starts)
119+
* to control the {@link #setStartTime start time} of the trigger.
120+
* <p>If the start delay is non-zero, it will <strong>always</strong>
121+
* take precedence over start time.
122+
* @param startDelay the start delay, in milliseconds
123+
*/
124+
public void setStartDelay(long startDelay) {
125+
Assert.state(startDelay >= 0, "Start delay cannot be negative.");
126+
this.startDelay = startDelay;
127+
}
128+
113129
/**
114130
* Set the JobDetail that this trigger should be associated with.
115131
* <p>This is typically used with a bean reference if the JobDetail
@@ -122,20 +138,6 @@ public void setJobDetail(JobDetail jobDetail) {
122138
this.jobDetail = jobDetail;
123139
}
124140

125-
/**
126-
* Set the start delay in milliseconds.
127-
* <p>The start delay is added to the current system time
128-
* (when the bean starts) to control the {@link #setStartTime start time}
129-
* of the trigger.
130-
* <p>If the start delay is non-zero it will <strong>always</strong>
131-
* take precedence over start time.
132-
* @param startDelay the start delay, in milliseconds.
133-
*/
134-
public void setStartDelay(long startDelay) {
135-
Assert.state(startDelay >= 0, "Start delay cannot be negative.");
136-
this.startDelay = startDelay;
137-
}
138-
139141
public JobDetail getJobDetail() {
140142
return this.jobDetail;
141143
}
@@ -146,7 +148,7 @@ public void setBeanName(String beanName) {
146148

147149

148150
public void afterPropertiesSet() throws Exception {
149-
if(this.startDelay > 0) {
151+
if (this.startDelay > 0) {
150152
setStartTime(new Date(System.currentTimeMillis() + this.startDelay));
151153
}
152154

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
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

Comments
 (0)