Require Jackson 2.0+, EhCache 2.5+, Quartz 2.1.4+
Issue: SPR-11262
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -52,9 +52,8 @@ import org.springframework.util.ClassUtils;
|
||||
* <p>Note: If the named Cache instance is found, the properties will be ignored and the
|
||||
* Cache instance will be retrieved from the CacheManager.
|
||||
*
|
||||
* <p>Note: As of Spring 4.0, Spring's EhCache support requires EhCache 2.1 or higher.
|
||||
* We recommend the use of EhCache 2.5 or higher.
|
||||
|
||||
* <p>Note: As of Spring 4.1, Spring's EhCache support requires EhCache 2.5 or higher.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Dmitriy Kopylenko
|
||||
* @since 1.1.1
|
||||
@@ -92,10 +91,8 @@ public class EhCacheFactoryBean extends CacheConfiguration implements FactoryBea
|
||||
private Ehcache cache;
|
||||
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public EhCacheFactoryBean() {
|
||||
// Using deprecated setMaxElementsInMemory method for EhCache 2.1-2.4 compatibility
|
||||
setMaxElementsInMemory(10000);
|
||||
setMaxEntriesLocalHeap(10000);
|
||||
setMaxElementsOnDisk(10000000);
|
||||
setTimeToLiveSeconds(120);
|
||||
setTimeToIdleSeconds(120);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -44,8 +44,7 @@ import org.springframework.core.io.Resource;
|
||||
* and cares for proper shutdown of the CacheManager. EhCacheManagerFactoryBean is
|
||||
* also necessary for loading EhCache configuration from a non-default config location.
|
||||
*
|
||||
* <p>Note: As of Spring 4.0, Spring's EhCache support requires EhCache 2.1 or higher.
|
||||
* We recommend the use of EhCache 2.5 or higher.
|
||||
* <p>Note: As of Spring 4.1, Spring's EhCache support requires EhCache 2.5 or higher.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Dmitriy Kopylenko
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,22 +16,17 @@
|
||||
|
||||
package org.springframework.scheduling.quartz;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.quartz.Job;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.quartz.spi.JobFactory;
|
||||
import org.quartz.spi.TriggerFiredBundle;
|
||||
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* JobFactory implementation that supports {@link java.lang.Runnable}
|
||||
* objects as well as standard Quartz {@link org.quartz.Job} instances.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.8 as well as Quartz 2.0-2.2, as of Spring 4.0.
|
||||
* <b>Note:</b> Quartz 1.x support is deprecated - please upgrade to Quartz 2.0+.
|
||||
* <p>Compatible with Quartz 2.1.4 and higher, as of Spring 4.1.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
@@ -40,19 +35,8 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
public class AdaptableJobFactory implements JobFactory {
|
||||
|
||||
/**
|
||||
* Quartz 2.0 version of newJob: simply delegates to old newJob variant.
|
||||
* @see #newJob(org.quartz.spi.TriggerFiredBundle)
|
||||
*/
|
||||
public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException {
|
||||
return newJob(bundle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Quartz 1.x version of newJob: contains actual implementation code.
|
||||
*/
|
||||
@Override
|
||||
public Job newJob(TriggerFiredBundle bundle) throws SchedulerException {
|
||||
public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException {
|
||||
try {
|
||||
Object jobObject = createJobInstance(bundle);
|
||||
return adaptJob(jobObject);
|
||||
@@ -71,12 +55,7 @@ public class AdaptableJobFactory implements JobFactory {
|
||||
* @throws Exception if job instantiation failed
|
||||
*/
|
||||
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
|
||||
// Reflectively adapting to differences between Quartz 1.x and Quartz 2.0...
|
||||
Method getJobDetail = bundle.getClass().getMethod("getJobDetail");
|
||||
Object jobDetail = ReflectionUtils.invokeMethod(getJobDetail, bundle);
|
||||
Method getJobClass = jobDetail.getClass().getMethod("getJobClass");
|
||||
Class<?> jobClass = (Class<?>) ReflectionUtils.invokeMethod(getJobClass, jobDetail);
|
||||
return jobClass.newInstance();
|
||||
return bundle.getJobDetail().getJobClass().newInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.scheduling.quartz;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.quartz.CronTrigger;
|
||||
import org.quartz.JobDetail;
|
||||
import org.quartz.Scheduler;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.Constants;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Convenience subclass of Quartz's {@link org.quartz.CronTrigger} class,
|
||||
* making bean-style usage easier.
|
||||
*
|
||||
* <p>{@code CronTrigger} itself is already a JavaBean but lacks sensible defaults.
|
||||
* This class uses the Spring bean name as job name, the Quartz default group
|
||||
* ("DEFAULT") as job group, the current time as start time, and indefinite
|
||||
* repetition, if not specified.
|
||||
*
|
||||
* <p>This class will also register the trigger with the job name and group of
|
||||
* a given {@link org.quartz.JobDetail}. This allows {@link SchedulerFactoryBean}
|
||||
* to automatically register a trigger for the corresponding JobDetail,
|
||||
* instead of registering the JobDetail separately.
|
||||
*
|
||||
* <p><b>NOTE: This convenience subclass does not work against Quartz 2.0.</b>
|
||||
* Use Quartz 2.0's native {@code JobDetailImpl} class or the new Quartz 2.0
|
||||
* builder API instead. Alternatively, switch to Spring's {@link CronTriggerFactoryBean}
|
||||
* which largely is a drop-in replacement for this class and its properties and
|
||||
* consistently works against Quartz 1.x as well as Quartz 2.x.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 18.02.2004
|
||||
* @see #setName
|
||||
* @see #setGroup
|
||||
* @see #setStartTime
|
||||
* @see #setJobName
|
||||
* @see #setJobGroup
|
||||
* @see #setJobDetail
|
||||
* @see SchedulerFactoryBean#setTriggers
|
||||
* @see SchedulerFactoryBean#setJobDetails
|
||||
* @see SimpleTriggerBean
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CronTriggerBean extends CronTrigger
|
||||
implements JobDetailAwareTrigger, BeanNameAware, InitializingBean {
|
||||
|
||||
/** Constants for the CronTrigger class */
|
||||
private static final Constants constants = new Constants(CronTrigger.class);
|
||||
|
||||
|
||||
private JobDetail jobDetail;
|
||||
|
||||
private String beanName;
|
||||
|
||||
private long startDelay = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Register objects in the JobDataMap via a given Map.
|
||||
* <p>These objects will be available to this Trigger only,
|
||||
* in contrast to objects in the JobDetail's data map.
|
||||
* @param jobDataAsMap Map with String keys and any objects as values
|
||||
* (for example Spring-managed beans)
|
||||
* @see JobDetailBean#setJobDataAsMap
|
||||
*/
|
||||
public void setJobDataAsMap(Map<String, ?> jobDataAsMap) {
|
||||
getJobDataMap().putAll(jobDataAsMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the misfire instruction via the name of the corresponding
|
||||
* constant in the {@link org.quartz.CronTrigger} class.
|
||||
* Default is {@code MISFIRE_INSTRUCTION_SMART_POLICY}.
|
||||
* @see org.quartz.CronTrigger#MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
|
||||
* @see org.quartz.CronTrigger#MISFIRE_INSTRUCTION_DO_NOTHING
|
||||
* @see org.quartz.Trigger#MISFIRE_INSTRUCTION_SMART_POLICY
|
||||
*/
|
||||
public void setMisfireInstructionName(String constantName) {
|
||||
setMisfireInstruction(constants.asNumber(constantName).intValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a list of TriggerListener names for this job, referring to
|
||||
* non-global TriggerListeners registered with the Scheduler.
|
||||
* <p>A TriggerListener name always refers to the name returned
|
||||
* by the TriggerListener implementation.
|
||||
* @see SchedulerFactoryBean#setTriggerListeners
|
||||
* @see org.quartz.TriggerListener#getName
|
||||
* @deprecated as of Spring 4.0, since it only works on Quartz 1.x
|
||||
*/
|
||||
@Deprecated
|
||||
public void setTriggerListenerNames(String... names) {
|
||||
for (String name : names) {
|
||||
addTriggerListener(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the start delay in milliseconds.
|
||||
* <p>The start delay is added to the current system time (when the bean starts)
|
||||
* to control the {@link #setStartTime start time} of the trigger.
|
||||
* <p>If the start delay is non-zero, it will <strong>always</strong>
|
||||
* take precedence over start time.
|
||||
* @param startDelay the start delay, in milliseconds
|
||||
*/
|
||||
public void setStartDelay(long startDelay) {
|
||||
Assert.state(startDelay >= 0, "Start delay cannot be negative.");
|
||||
this.startDelay = startDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JobDetail that this trigger should be associated with.
|
||||
* <p>This is typically used with a bean reference if the JobDetail
|
||||
* is a Spring-managed bean. Alternatively, the trigger can also
|
||||
* be associated with a job by name and group.
|
||||
* @see #setJobName
|
||||
* @see #setJobGroup
|
||||
*/
|
||||
public void setJobDetail(JobDetail jobDetail) {
|
||||
this.jobDetail = jobDetail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JobDetail getJobDetail() {
|
||||
return this.jobDetail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanName(String beanName) {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (getName() == null) {
|
||||
setName(this.beanName);
|
||||
}
|
||||
if (getGroup() == null) {
|
||||
setGroup(Scheduler.DEFAULT_GROUP);
|
||||
}
|
||||
if (this.startDelay > 0 || getStartTime() == null) {
|
||||
setStartTime(new Date(System.currentTimeMillis() + this.startDelay));
|
||||
}
|
||||
if (getTimeZone() == null) {
|
||||
setTimeZone(TimeZone.getDefault());
|
||||
}
|
||||
if (this.jobDetail != null) {
|
||||
setJobName(this.jobDetail.getName());
|
||||
setJobGroup(this.jobDetail.getGroup());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package org.springframework.scheduling.quartz;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
@@ -25,16 +25,13 @@ import org.quartz.CronTrigger;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobDetail;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.impl.triggers.CronTriggerImpl;
|
||||
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.Constants;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* A Spring {@link FactoryBean} for creating a Quartz {@link org.quartz.CronTrigger}
|
||||
@@ -49,9 +46,6 @@ import org.springframework.util.ReflectionUtils;
|
||||
* to automatically register a trigger for the corresponding JobDetail,
|
||||
* instead of registering the JobDetail separately.
|
||||
*
|
||||
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.x,
|
||||
* in contrast to the older {@link CronTriggerBean} class.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @see #setName
|
||||
@@ -60,7 +54,6 @@ import org.springframework.util.ReflectionUtils;
|
||||
* @see #setJobDetail
|
||||
* @see SchedulerFactoryBean#setTriggers
|
||||
* @see SchedulerFactoryBean#setJobDetails
|
||||
* @see SimpleTriggerBean
|
||||
*/
|
||||
public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNameAware, InitializingBean {
|
||||
|
||||
@@ -139,7 +132,6 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
* in contrast to objects in the JobDetail's data map.
|
||||
* @param jobDataAsMap Map with String keys and any objects as values
|
||||
* (for example Spring-managed beans)
|
||||
* @see org.springframework.scheduling.quartz.JobDetailBean#setJobDataAsMap
|
||||
*/
|
||||
public void setJobDataAsMap(Map<String, ?> jobDataAsMap) {
|
||||
this.jobDataMap.putAll(jobDataAsMap);
|
||||
@@ -225,7 +217,7 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
public void afterPropertiesSet() throws ParseException {
|
||||
if (this.name == null) {
|
||||
this.name = this.beanName;
|
||||
}
|
||||
@@ -233,7 +225,7 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
this.group = Scheduler.DEFAULT_GROUP;
|
||||
}
|
||||
if (this.jobDetail != null) {
|
||||
this.jobDataMap.put(JobDetailAwareTrigger.JOB_DETAIL_KEY, this.jobDetail);
|
||||
this.jobDataMap.put("jobDetail", this.jobDetail);
|
||||
}
|
||||
if (this.startDelay > 0 || this.startTime == null) {
|
||||
this.startTime = new Date(System.currentTimeMillis() + this.startDelay);
|
||||
@@ -242,7 +234,6 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
this.timeZone = TimeZone.getDefault();
|
||||
}
|
||||
|
||||
/*
|
||||
CronTriggerImpl cti = new CronTriggerImpl();
|
||||
cti.setName(this.name);
|
||||
cti.setGroup(this.group);
|
||||
@@ -256,42 +247,6 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
cti.setMisfireInstruction(this.misfireInstruction);
|
||||
cti.setDescription(this.description);
|
||||
this.cronTrigger = cti;
|
||||
*/
|
||||
|
||||
Class<?> cronTriggerClass;
|
||||
Method jobKeyMethod;
|
||||
try {
|
||||
cronTriggerClass = getClass().getClassLoader().loadClass("org.quartz.impl.triggers.CronTriggerImpl");
|
||||
jobKeyMethod = JobDetail.class.getMethod("getKey");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
cronTriggerClass = CronTrigger.class;
|
||||
jobKeyMethod = null;
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("Incompatible Quartz version");
|
||||
}
|
||||
BeanWrapper bw = new BeanWrapperImpl(cronTriggerClass);
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
pvs.add("name", this.name);
|
||||
pvs.add("group", this.group);
|
||||
if (jobKeyMethod != null) {
|
||||
pvs.add("jobKey", ReflectionUtils.invokeMethod(jobKeyMethod, this.jobDetail));
|
||||
}
|
||||
else {
|
||||
pvs.add("jobName", this.jobDetail.getName());
|
||||
pvs.add("jobGroup", this.jobDetail.getGroup());
|
||||
}
|
||||
pvs.add("jobDataMap", this.jobDataMap);
|
||||
pvs.add("startTime", this.startTime);
|
||||
pvs.add("cronExpression", this.cronExpression);
|
||||
pvs.add("timeZone", this.timeZone);
|
||||
pvs.add("calendarName", this.calendarName);
|
||||
pvs.add("priority", this.priority);
|
||||
pvs.add("misfireInstruction", this.misfireInstruction);
|
||||
pvs.add("description", this.description);
|
||||
bw.setPropertyValues(pvs);
|
||||
this.cronTrigger = (CronTrigger) bw.getWrappedInstance();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.scheduling.quartz;
|
||||
|
||||
import org.quartz.JobDetail;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by Quartz Triggers that are aware
|
||||
* of the JobDetail object that they are associated with.
|
||||
*
|
||||
* <p>SchedulerFactoryBean will auto-detect Triggers that implement this
|
||||
* interface and register them for the respective JobDetail accordingly.
|
||||
*
|
||||
* <p>The alternative is to configure a Trigger for a Job name and group:
|
||||
* This involves the need to register the JobDetail object separately
|
||||
* with SchedulerFactoryBean.
|
||||
*
|
||||
* <p><b>NOTE: As of Quartz 2.0, the recommended strategy is to define an
|
||||
* entry of name "jobDetail" and type JobDetail in the trigger's JobDataMap.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 18.02.2004
|
||||
* @see SchedulerFactoryBean#setTriggers
|
||||
* @see SchedulerFactoryBean#setJobDetails
|
||||
* @see org.quartz.Trigger#setJobName
|
||||
* @see org.quartz.Trigger#setJobGroup
|
||||
*/
|
||||
public interface JobDetailAwareTrigger {
|
||||
|
||||
/**
|
||||
* Name of the key for the JobDetail value in the trigger's JobDataMap.
|
||||
* This is an alternative to implementing the JobDetailAwareTrigger interface.
|
||||
*/
|
||||
String JOB_DETAIL_KEY = "jobDetail";
|
||||
|
||||
/**
|
||||
* Return the JobDetail that this Trigger is associated with.
|
||||
* @return the associated JobDetail, or {@code null} if none
|
||||
*/
|
||||
JobDetail getJobDetail();
|
||||
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.scheduling.quartz;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobDetail;
|
||||
import org.quartz.Scheduler;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
|
||||
/**
|
||||
* Convenience subclass of Quartz's {@link org.quartz.JobDetail} class,
|
||||
* making bean-style usage easier.
|
||||
*
|
||||
* <p>{@code JobDetail} itself is already a JavaBean but lacks
|
||||
* sensible defaults. This class uses the Spring bean name as job name,
|
||||
* and the Quartz default group ("DEFAULT") as job group if not specified.
|
||||
*
|
||||
* <p><b>NOTE: This convenience subclass does not work against Quartz 2.0.</b>
|
||||
* Use Quartz 2.0's native {@code JobDetailImpl} class or the new Quartz 2.0
|
||||
* builder API instead. Alternatively, switch to Spring's {@link JobDetailFactoryBean}
|
||||
* which largely is a drop-in replacement for this class and its properties and
|
||||
* consistently works against Quartz 1.x as well as Quartz 2.x.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 18.02.2004
|
||||
* @see #setName
|
||||
* @see #setGroup
|
||||
* @see org.springframework.beans.factory.BeanNameAware
|
||||
* @see org.quartz.Scheduler#DEFAULT_GROUP
|
||||
*/
|
||||
@SuppressWarnings({"serial", "rawtypes"})
|
||||
public class JobDetailBean extends JobDetail
|
||||
implements BeanNameAware, ApplicationContextAware, InitializingBean {
|
||||
|
||||
private Class<?> actualJobClass;
|
||||
|
||||
private String beanName;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private String applicationContextJobDataKey;
|
||||
|
||||
|
||||
/**
|
||||
* Overridden to support any job class, to allow a custom JobFactory
|
||||
* to adapt the given job class to the Quartz Job interface.
|
||||
* @see SchedulerFactoryBean#setJobFactory
|
||||
*/
|
||||
@Override
|
||||
public void setJobClass(Class jobClass) {
|
||||
if (jobClass != null && !Job.class.isAssignableFrom(jobClass)) {
|
||||
super.setJobClass(DelegatingJob.class);
|
||||
this.actualJobClass = jobClass;
|
||||
}
|
||||
else {
|
||||
super.setJobClass(jobClass);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to support any job class, to allow a custom JobFactory
|
||||
* to adapt the given job class to the Quartz Job interface.
|
||||
*/
|
||||
@Override
|
||||
public Class getJobClass() {
|
||||
return (this.actualJobClass != null ? this.actualJobClass : super.getJobClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Register objects in the JobDataMap via a given Map.
|
||||
* <p>These objects will be available to this Job only,
|
||||
* in contrast to objects in the SchedulerContext.
|
||||
* <p>Note: When using persistent Jobs whose JobDetail will be kept in the
|
||||
* database, do not put Spring-managed beans or an ApplicationContext
|
||||
* reference into the JobDataMap but rather into the SchedulerContext.
|
||||
* @param jobDataAsMap Map with String keys and any objects as values
|
||||
* (for example Spring-managed beans)
|
||||
* @see SchedulerFactoryBean#setSchedulerContextAsMap
|
||||
*/
|
||||
public void setJobDataAsMap(Map<String, ?> jobDataAsMap) {
|
||||
getJobDataMap().putAll(jobDataAsMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a list of JobListener names for this job, referring to
|
||||
* non-global JobListeners registered with the Scheduler.
|
||||
* <p>A JobListener name always refers to the name returned
|
||||
* by the JobListener implementation.
|
||||
* @see SchedulerFactoryBean#setJobListeners
|
||||
* @see org.quartz.JobListener#getName
|
||||
* @deprecated as of Spring 4.0, since it only works on Quartz 1.x
|
||||
*/
|
||||
@Deprecated
|
||||
public void setJobListenerNames(String... names) {
|
||||
for (String name : names) {
|
||||
addJobListener(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanName(String beanName) {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the key of an ApplicationContext reference to expose in the JobDataMap,
|
||||
* for example "applicationContext". Default is none.
|
||||
* Only applicable when running in a Spring ApplicationContext.
|
||||
* <p>In case of a QuartzJobBean, the reference will be applied to the Job
|
||||
* instance as bean property. An "applicationContext" attribute will correspond
|
||||
* to a "setApplicationContext" method in that scenario.
|
||||
* <p>Note that BeanFactory callback interfaces like ApplicationContextAware
|
||||
* are not automatically applied to Quartz Job instances, because Quartz
|
||||
* itself is responsible for the lifecycle of its Jobs.
|
||||
* <p><b>Note: When using persistent job stores where JobDetail contents will
|
||||
* be kept in the database, do not put an ApplicationContext reference into
|
||||
* the JobDataMap but rather into the SchedulerContext.</b>
|
||||
* @see SchedulerFactoryBean#setApplicationContextSchedulerContextKey
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
*/
|
||||
public void setApplicationContextJobDataKey(String applicationContextJobDataKey) {
|
||||
this.applicationContextJobDataKey = applicationContextJobDataKey;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (getName() == null) {
|
||||
setName(this.beanName);
|
||||
}
|
||||
if (getGroup() == null) {
|
||||
setGroup(Scheduler.DEFAULT_GROUP);
|
||||
}
|
||||
if (this.applicationContextJobDataKey != null) {
|
||||
if (this.applicationContext == null) {
|
||||
throw new IllegalStateException(
|
||||
"JobDetailBean needs to be set up in an ApplicationContext " +
|
||||
"to be able to handle an 'applicationContextJobDataKey'");
|
||||
}
|
||||
getJobDataMap().put(this.applicationContextJobDataKey, this.applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,10 +21,8 @@ import java.util.Map;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobDetail;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.impl.JobDetailImpl;
|
||||
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
@@ -39,9 +37,6 @@ import org.springframework.context.ApplicationContextAware;
|
||||
* sensible defaults. This class uses the Spring bean name as job name,
|
||||
* and the Quartz default group ("DEFAULT") as job group if not specified.
|
||||
*
|
||||
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.x,
|
||||
* in contrast to the older {@link JobDetailBean} class.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @see #setName
|
||||
@@ -181,6 +176,7 @@ public class JobDetailFactoryBean
|
||||
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void afterPropertiesSet() {
|
||||
if (this.name == null) {
|
||||
this.name = this.beanName;
|
||||
@@ -197,35 +193,15 @@ public class JobDetailFactoryBean
|
||||
getJobDataMap().put(this.applicationContextJobDataKey, this.applicationContext);
|
||||
}
|
||||
|
||||
/*
|
||||
JobDetailImpl jdi = new JobDetailImpl();
|
||||
jdi.setName(this.name);
|
||||
jdi.setGroup(this.group);
|
||||
jdi.setJobClass(this.jobClass);
|
||||
jdi.setJobClass((Class) this.jobClass);
|
||||
jdi.setJobDataMap(this.jobDataMap);
|
||||
jdi.setDurability(this.durability);
|
||||
jdi.setRequestsRecovery(this.requestsRecovery);
|
||||
jdi.setDescription(this.description);
|
||||
this.jobDetail = jdi;
|
||||
*/
|
||||
|
||||
Class<?> jobDetailClass;
|
||||
try {
|
||||
jobDetailClass = getClass().getClassLoader().loadClass("org.quartz.impl.JobDetailImpl");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
jobDetailClass = JobDetail.class;
|
||||
}
|
||||
BeanWrapper bw = new BeanWrapperImpl(jobDetailClass);
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
pvs.add("name", this.name);
|
||||
pvs.add("group", this.group);
|
||||
pvs.add("jobClass", this.jobClass);
|
||||
pvs.add("jobDataMap", this.jobDataMap);
|
||||
pvs.add("durability", this.durability);
|
||||
pvs.add("requestsRecovery", this.requestsRecovery);
|
||||
pvs.add("description", this.description);
|
||||
bw.setPropertyValues(pvs);
|
||||
this.jobDetail = (JobDetail) bw.getWrappedInstance();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -87,7 +87,7 @@ public class LocalTaskExecutorThreadPool implements ThreadPool {
|
||||
|
||||
@Override
|
||||
public int blockForAvailableThreads() {
|
||||
// The present implementation always returns 1, making Quartz (1.6)
|
||||
// The present implementation always returns 1, making Quartz
|
||||
// always schedule any tasks that it feels like scheduling.
|
||||
// This could be made smarter for specific TaskExecutors,
|
||||
// for example calling {@code getMaximumPoolSize() - getActiveCount()}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,20 +17,17 @@
|
||||
package org.springframework.scheduling.quartz;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.DisallowConcurrentExecution;
|
||||
import org.quartz.JobDetail;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.quartz.PersistJobDataAfterExecution;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.StatefulJob;
|
||||
import org.quartz.impl.JobDetailImpl;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.PropertyAccessorFactory;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
@@ -41,7 +38,6 @@ import org.springframework.beans.support.ArgumentConvertingMethodInvoker;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.MethodInvoker;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.FactoryBean} that exposes a
|
||||
@@ -67,8 +63,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* You need to implement your own Quartz Job as a thin wrapper for each case
|
||||
* where you want a persistent job to delegate to a specific service method.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.8 as well as Quartz 2.0-2.2, as of Spring 4.0.
|
||||
* <b>Note:</b> Quartz 1.x support is deprecated - please upgrade to Quartz 2.0+.
|
||||
* <p>Compatible with Quartz 2.1.4 and higher, as of Spring 4.1.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Alef Arendsen
|
||||
@@ -81,28 +76,6 @@ import org.springframework.util.ReflectionUtils;
|
||||
public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethodInvoker
|
||||
implements FactoryBean<JobDetail>, BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean {
|
||||
|
||||
private static Class<?> jobDetailImplClass;
|
||||
|
||||
private static Method setResultMethod;
|
||||
|
||||
static {
|
||||
try {
|
||||
jobDetailImplClass = Class.forName("org.quartz.impl.JobDetailImpl");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
jobDetailImplClass = null;
|
||||
}
|
||||
try {
|
||||
Class<?> jobExecutionContextClass =
|
||||
QuartzJobBean.class.getClassLoader().loadClass("org.quartz.JobExecutionContext");
|
||||
setResultMethod = jobExecutionContextClass.getMethod("setResult", Object.class);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Incompatible Quartz API: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String name;
|
||||
|
||||
private String group = Scheduler.DEFAULT_GROUP;
|
||||
@@ -111,8 +84,6 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
|
||||
|
||||
private String targetBeanName;
|
||||
|
||||
private String[] jobListenerNames;
|
||||
|
||||
private String beanName;
|
||||
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
@@ -125,7 +96,6 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
|
||||
/**
|
||||
* Set the name of the job.
|
||||
* <p>Default is the bean name of this FactoryBean.
|
||||
* @see org.quartz.JobDetail#setName
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
@@ -134,7 +104,6 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
|
||||
/**
|
||||
* Set the group of the job.
|
||||
* <p>Default is the default group of the Scheduler.
|
||||
* @see org.quartz.JobDetail#setGroup
|
||||
* @see org.quartz.Scheduler#DEFAULT_GROUP
|
||||
*/
|
||||
public void setGroup(String group) {
|
||||
@@ -142,9 +111,10 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether or not multiple jobs should be run in a concurrent
|
||||
* fashion. The behavior when one does not want concurrent jobs to be
|
||||
* executed is realized through adding the {@link StatefulJob} interface.
|
||||
* Specify whether or not multiple jobs should be run in a concurrent fashion.
|
||||
* The behavior when one does not want concurrent jobs to be executed is
|
||||
* realized through adding the {@code @PersistJobDataAfterExecution} and
|
||||
* {@code @DisallowConcurrentExecution} markers.
|
||||
* More information on stateful versus stateless jobs can be found
|
||||
* <a href="http://www.quartz-scheduler.org/documentation/quartz-2.1.x/tutorials/tutorial-lesson-03">here</a>.
|
||||
* <p>The default setting is to run jobs concurrently.
|
||||
@@ -165,20 +135,6 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
|
||||
this.targetBeanName = targetBeanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a list of JobListener names for this job, referring to
|
||||
* non-global JobListeners registered with the Scheduler.
|
||||
* <p>A JobListener name always refers to the name returned
|
||||
* by the JobListener implementation.
|
||||
* @see SchedulerFactoryBean#setJobListeners
|
||||
* @see org.quartz.JobListener#getName
|
||||
* @deprecated as of Spring 4.0, since it only works on Quartz 1.x
|
||||
*/
|
||||
@Deprecated
|
||||
public void setJobListenerNames(String... names) {
|
||||
this.jobListenerNames = names;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanName(String beanName) {
|
||||
this.beanName = beanName;
|
||||
@@ -201,6 +157,7 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
|
||||
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void afterPropertiesSet() throws ClassNotFoundException, NoSuchMethodException {
|
||||
prepare();
|
||||
|
||||
@@ -211,34 +168,13 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
|
||||
Class<?> jobClass = (this.concurrent ? MethodInvokingJob.class : StatefulMethodInvokingJob.class);
|
||||
|
||||
// Build JobDetail instance.
|
||||
if (jobDetailImplClass != null) {
|
||||
// Using Quartz 2.0 JobDetailImpl class...
|
||||
this.jobDetail = (JobDetail) BeanUtils.instantiate(jobDetailImplClass);
|
||||
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this.jobDetail);
|
||||
bw.setPropertyValue("name", name);
|
||||
bw.setPropertyValue("group", this.group);
|
||||
bw.setPropertyValue("jobClass", jobClass);
|
||||
bw.setPropertyValue("durability", true);
|
||||
((JobDataMap) bw.getPropertyValue("jobDataMap")).put("methodInvoker", this);
|
||||
}
|
||||
else {
|
||||
// Using Quartz 1.x JobDetail class...
|
||||
this.jobDetail = new JobDetail(name, this.group, jobClass);
|
||||
this.jobDetail.setVolatility(true);
|
||||
this.jobDetail.setDurability(true);
|
||||
this.jobDetail.getJobDataMap().put("methodInvoker", this);
|
||||
}
|
||||
|
||||
// Register job listener names.
|
||||
if (this.jobListenerNames != null) {
|
||||
for (String jobListenerName : this.jobListenerNames) {
|
||||
if (jobDetailImplClass != null) {
|
||||
throw new IllegalStateException("Non-global JobListeners not supported on Quartz 2 - " +
|
||||
"manually register a Matcher against the Quartz ListenerManager instead");
|
||||
}
|
||||
this.jobDetail.addJobListener(jobListenerName);
|
||||
}
|
||||
}
|
||||
JobDetailImpl jdi = new JobDetailImpl();
|
||||
jdi.setName(name);
|
||||
jdi.setGroup(group);
|
||||
jdi.setJobClass((Class) jobClass);
|
||||
jdi.setDurability(true);
|
||||
jdi.getJobDataMap().put("methodInvoker", this);
|
||||
this.jobDetail = jdi;
|
||||
|
||||
postProcessJobDetail(this.jobDetail);
|
||||
}
|
||||
@@ -318,7 +254,7 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
|
||||
@Override
|
||||
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
|
||||
try {
|
||||
ReflectionUtils.invokeMethod(setResultMethod, context, this.methodInvoker.invoke());
|
||||
context.setResult(this.methodInvoker.invoke());
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
if (ex.getTargetException() instanceof JobExecutionException) {
|
||||
@@ -343,7 +279,9 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
|
||||
* Quartz checks whether or not jobs are stateful and if so,
|
||||
* won't let jobs interfere with each other.
|
||||
*/
|
||||
public static class StatefulMethodInvokingJob extends MethodInvokingJob implements StatefulJob {
|
||||
@PersistJobDataAfterExecution
|
||||
@DisallowConcurrentExecution
|
||||
public static class StatefulMethodInvokingJob extends MethodInvokingJob {
|
||||
|
||||
// No implementation, just an addition of the tag interface StatefulJob
|
||||
// in order to allow stateful method invoking jobs.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,19 +16,14 @@
|
||||
|
||||
package org.springframework.scheduling.quartz;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.PropertyAccessorFactory;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Simple implementation of the Quartz Job interface, applying the
|
||||
@@ -43,15 +38,9 @@ import org.springframework.util.ReflectionUtils;
|
||||
* i.e. a method "setMyParam(int)". This will also work for complex
|
||||
* types like business objects etc.
|
||||
*
|
||||
* <p>Note: The QuartzJobBean class itself only implements the standard
|
||||
* Quartz {@link org.quartz.Job} interface. Let your subclass explicitly
|
||||
* implement the Quartz {@link org.quartz.StatefulJob} interface to
|
||||
* mark your concrete job bean as stateful.
|
||||
*
|
||||
* <p><b>Note that as of Spring 2.0 and Quartz 1.5, the preferred way
|
||||
* to apply dependency injection to Job instances is via a JobFactory:</b>
|
||||
* that is, to specify {@link SpringBeanJobFactory} as Quartz JobFactory
|
||||
* (typically via
|
||||
* <p><b>Note that the preferred way to apply dependency injection
|
||||
* to Job instances is via a JobFactory:</b> that is, to specify
|
||||
* {@link SpringBeanJobFactory} as Quartz JobFactory (typically via
|
||||
* {@link SchedulerFactoryBean#setJobFactory} SchedulerFactoryBean's "jobFactory" property}).
|
||||
* This allows to implement dependency-injected Quartz Jobs without
|
||||
* a dependency on Spring base classes.
|
||||
@@ -60,33 +49,12 @@ import org.springframework.util.ReflectionUtils;
|
||||
* @since 18.02.2004
|
||||
* @see org.quartz.JobExecutionContext#getMergedJobDataMap()
|
||||
* @see org.quartz.Scheduler#getContext()
|
||||
* @see JobDetailBean#setJobDataAsMap
|
||||
* @see SimpleTriggerBean#setJobDataAsMap
|
||||
* @see CronTriggerBean#setJobDataAsMap
|
||||
* @see SchedulerFactoryBean#setSchedulerContextAsMap
|
||||
* @see SpringBeanJobFactory
|
||||
* @see SchedulerFactoryBean#setJobFactory
|
||||
*/
|
||||
public abstract class QuartzJobBean implements Job {
|
||||
|
||||
private static final Method getSchedulerMethod;
|
||||
|
||||
private static final Method getMergedJobDataMapMethod;
|
||||
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> jobExecutionContextClass =
|
||||
QuartzJobBean.class.getClassLoader().loadClass("org.quartz.JobExecutionContext");
|
||||
getSchedulerMethod = jobExecutionContextClass.getMethod("getScheduler");
|
||||
getMergedJobDataMapMethod = jobExecutionContextClass.getMethod("getMergedJobDataMap");
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Incompatible Quartz API: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation applies the passed-in job data map as bean property
|
||||
* values, and delegates to {@code executeInternal} afterwards.
|
||||
@@ -95,14 +63,10 @@ public abstract class QuartzJobBean implements Job {
|
||||
@Override
|
||||
public final void execute(JobExecutionContext context) throws JobExecutionException {
|
||||
try {
|
||||
// Reflectively adapting to differences between Quartz 1.x and Quartz 2.0...
|
||||
Scheduler scheduler = (Scheduler) ReflectionUtils.invokeMethod(getSchedulerMethod, context);
|
||||
Map<?, ?> mergedJobDataMap = (Map<?, ?>) ReflectionUtils.invokeMethod(getMergedJobDataMapMethod, context);
|
||||
|
||||
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
pvs.addPropertyValues(scheduler.getContext());
|
||||
pvs.addPropertyValues(mergedJobDataMap);
|
||||
pvs.addPropertyValues(context.getScheduler().getContext());
|
||||
pvs.addPropertyValues(context.getMergedJobDataMap());
|
||||
bw.setPropertyValues(pvs, true);
|
||||
}
|
||||
catch (SchedulerException ex) {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.scheduling.quartz;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
@@ -28,6 +27,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.quartz.Calendar;
|
||||
import org.quartz.JobDetail;
|
||||
import org.quartz.JobListener;
|
||||
import org.quartz.ListenerManager;
|
||||
import org.quartz.ObjectAlreadyExistsException;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
@@ -43,7 +43,6 @@ import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionException;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Common base class for accessing a Quartz Scheduler, i.e. for registering jobs,
|
||||
@@ -52,8 +51,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* <p>For concrete usage, check out the {@link SchedulerFactoryBean} and
|
||||
* {@link SchedulerAccessorBean} classes.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.8 as well as Quartz 2.0-2.2, as of Spring 4.0.
|
||||
* <b>Note:</b> Quartz 1.x support is deprecated - please upgrade to Quartz 2.0+.
|
||||
* <p>Compatible with Quartz 2.1.4 and higher, as of Spring 4.1.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
@@ -61,23 +59,6 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
|
||||
private static Class<?> jobKeyClass;
|
||||
|
||||
private static Class<?> triggerKeyClass;
|
||||
|
||||
static {
|
||||
// Quartz 2.0 job/trigger key available?
|
||||
try {
|
||||
jobKeyClass = Class.forName("org.quartz.JobKey");
|
||||
triggerKeyClass = Class.forName("org.quartz.TriggerKey");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
jobKeyClass = null;
|
||||
triggerKeyClass = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private boolean overwriteExistingJobs = false;
|
||||
@@ -94,24 +75,13 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
|
||||
private JobListener[] globalJobListeners;
|
||||
|
||||
private JobListener[] jobListeners;
|
||||
|
||||
private TriggerListener[] globalTriggerListeners;
|
||||
|
||||
private TriggerListener[] triggerListeners;
|
||||
|
||||
private PlatformTransactionManager transactionManager;
|
||||
|
||||
protected ResourceLoader resourceLoader;
|
||||
|
||||
|
||||
public SchedulerAccessor() {
|
||||
if (jobKeyClass == null && logger.isInfoEnabled()) {
|
||||
logger.info("Spring's Quartz 1.x support is deprecated - please upgrade to Quartz 2.0+");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set whether any jobs defined on this SchedulerFactoryBean should overwrite
|
||||
* existing job definitions. Default is "false", to not overwrite already
|
||||
@@ -151,8 +121,6 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* in combination with the Trigger.
|
||||
* @see #setTriggers
|
||||
* @see org.quartz.JobDetail
|
||||
* @see JobDetailBean
|
||||
* @see JobDetailAwareTrigger
|
||||
*/
|
||||
public void setJobDetails(JobDetail... jobDetails) {
|
||||
// Use modifiable ArrayList here, to allow for further adding of
|
||||
@@ -180,15 +148,11 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* "jobDetails" property of this FactoryBean.
|
||||
* @see #setJobDetails
|
||||
* @see org.quartz.JobDetail
|
||||
* @see JobDetailAwareTrigger
|
||||
* @see CronTriggerBean
|
||||
* @see SimpleTriggerBean
|
||||
*/
|
||||
public void setTriggers(Trigger... triggers) {
|
||||
this.triggers = Arrays.asList(triggers);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify Quartz SchedulerListeners to be registered with the Scheduler.
|
||||
*/
|
||||
@@ -204,21 +168,6 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
this.globalJobListeners = globalJobListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify named Quartz JobListeners to be registered with the Scheduler.
|
||||
* Such JobListeners will only apply to Jobs that explicitly activate
|
||||
* them via their name.
|
||||
* <p>Note that non-global JobListeners are not supported on Quartz 2.x -
|
||||
* manually register a Matcher against the Quartz ListenerManager instead.
|
||||
* @see org.quartz.JobListener#getName
|
||||
* @see JobDetailBean#setJobListenerNames
|
||||
* @deprecated as of Spring 4.0, since it only works on Quartz 1.x
|
||||
*/
|
||||
@Deprecated
|
||||
public void setJobListeners(JobListener... jobListeners) {
|
||||
this.jobListeners = jobListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify global Quartz TriggerListeners to be registered with the Scheduler.
|
||||
* Such TriggerListeners will apply to all Triggers in the Scheduler.
|
||||
@@ -227,23 +176,6 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
this.globalTriggerListeners = globalTriggerListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify named Quartz TriggerListeners to be registered with the Scheduler.
|
||||
* Such TriggerListeners will only apply to Triggers that explicitly activate
|
||||
* them via their name.
|
||||
* <p>Note that non-global TriggerListeners are not supported on Quartz 2.x -
|
||||
* manually register a Matcher against the Quartz ListenerManager instead.
|
||||
* @see org.quartz.TriggerListener#getName
|
||||
* @see CronTriggerBean#setTriggerListenerNames
|
||||
* @see SimpleTriggerBean#setTriggerListenerNames
|
||||
* @deprecated as of Spring 4.0, since it only works on Quartz 1.x
|
||||
*/
|
||||
@Deprecated
|
||||
public void setTriggerListeners(TriggerListener... triggerListeners) {
|
||||
this.triggerListeners = triggerListeners;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the transaction manager to be used for registering jobs and triggers
|
||||
* that are defined by this SchedulerFactoryBean. Default is none; setting
|
||||
@@ -338,7 +270,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* @see #setOverwriteExistingJobs
|
||||
*/
|
||||
private boolean addJobToScheduler(JobDetail jobDetail) throws SchedulerException {
|
||||
if (this.overwriteExistingJobs || !jobDetailExists(jobDetail)) {
|
||||
if (this.overwriteExistingJobs || getScheduler().getJobDetail(jobDetail.getKey()) == null) {
|
||||
getScheduler().addJob(jobDetail, true);
|
||||
return true;
|
||||
}
|
||||
@@ -356,10 +288,10 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* @see #setOverwriteExistingJobs
|
||||
*/
|
||||
private boolean addTriggerToScheduler(Trigger trigger) throws SchedulerException {
|
||||
boolean triggerExists = triggerExists(trigger);
|
||||
boolean triggerExists = (getScheduler().getTrigger(trigger.getKey()) != null);
|
||||
if (!triggerExists || this.overwriteExistingJobs) {
|
||||
// Check if the Trigger is aware of an associated JobDetail.
|
||||
JobDetail jobDetail = findJobDetail(trigger);
|
||||
JobDetail jobDetail = (JobDetail) trigger.getJobDataMap().remove("jobDetail");
|
||||
if (jobDetail != null) {
|
||||
// Automatically register the JobDetail too.
|
||||
if (!this.jobDetails.contains(jobDetail) && addJobToScheduler(jobDetail)) {
|
||||
@@ -376,12 +308,12 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
ex.getMessage() + " - can safely be ignored");
|
||||
}
|
||||
if (this.overwriteExistingJobs) {
|
||||
rescheduleJob(trigger);
|
||||
getScheduler().rescheduleJob(trigger.getKey(), trigger);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
rescheduleJob(trigger);
|
||||
getScheduler().rescheduleJob(trigger.getKey(), trigger);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -390,160 +322,25 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
}
|
||||
}
|
||||
|
||||
private JobDetail findJobDetail(Trigger trigger) {
|
||||
if (trigger instanceof JobDetailAwareTrigger) {
|
||||
return ((JobDetailAwareTrigger) trigger).getJobDetail();
|
||||
}
|
||||
else {
|
||||
try {
|
||||
Map<?, ?> jobDataMap =
|
||||
(Map<?, ?>) ReflectionUtils.invokeMethod(Trigger.class.getMethod("getJobDataMap"), trigger);
|
||||
return (JobDetail) jobDataMap.remove(JobDetailAwareTrigger.JOB_DETAIL_KEY);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("Inconsistent Quartz API: " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Reflectively adapting to differences between Quartz 1.x and Quartz 2.0...
|
||||
private boolean jobDetailExists(JobDetail jobDetail) throws SchedulerException {
|
||||
if (jobKeyClass != null) {
|
||||
try {
|
||||
Method getJobDetail = Scheduler.class.getMethod("getJobDetail", jobKeyClass);
|
||||
Object key = ReflectionUtils.invokeMethod(JobDetail.class.getMethod("getKey"), jobDetail);
|
||||
return (ReflectionUtils.invokeMethod(getJobDetail, getScheduler(), key) != null);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("Inconsistent Quartz 2.0 API: " + ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return (getScheduler().getJobDetail(jobDetail.getName(), jobDetail.getGroup()) != null);
|
||||
}
|
||||
}
|
||||
|
||||
// Reflectively adapting to differences between Quartz 1.x and Quartz 2.0...
|
||||
private boolean triggerExists(Trigger trigger) throws SchedulerException {
|
||||
if (triggerKeyClass != null) {
|
||||
try {
|
||||
Method getTrigger = Scheduler.class.getMethod("getTrigger", triggerKeyClass);
|
||||
Object key = ReflectionUtils.invokeMethod(Trigger.class.getMethod("getKey"), trigger);
|
||||
return (ReflectionUtils.invokeMethod(getTrigger, getScheduler(), key) != null);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("Inconsistent Quartz 2.0 API: " + ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return (getScheduler().getTrigger(trigger.getName(), trigger.getGroup()) != null);
|
||||
}
|
||||
}
|
||||
|
||||
// Reflectively adapting to differences between Quartz 1.x and Quartz 2.0...
|
||||
private void rescheduleJob(Trigger trigger) throws SchedulerException {
|
||||
if (triggerKeyClass != null) {
|
||||
try {
|
||||
Method rescheduleJob = Scheduler.class.getMethod("rescheduleJob", triggerKeyClass, Trigger.class);
|
||||
Object key = ReflectionUtils.invokeMethod(Trigger.class.getMethod("getKey"), trigger);
|
||||
ReflectionUtils.invokeMethod(rescheduleJob, getScheduler(), key, trigger);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("Inconsistent Quartz 2.0 API: " + ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
getScheduler().rescheduleJob(trigger.getName(), trigger.getGroup(), trigger);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register all specified listeners with the Scheduler.
|
||||
*/
|
||||
protected void registerListeners() throws SchedulerException {
|
||||
Object target;
|
||||
boolean quartz2;
|
||||
try {
|
||||
Method getListenerManager = Scheduler.class.getMethod("getListenerManager");
|
||||
target = ReflectionUtils.invokeMethod(getListenerManager, getScheduler());
|
||||
quartz2 = true;
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
target = getScheduler();
|
||||
quartz2 = false;
|
||||
}
|
||||
Class<?> targetClass = target.getClass();
|
||||
|
||||
try {
|
||||
if (this.schedulerListeners != null) {
|
||||
Method addSchedulerListener = targetClass.getMethod("addSchedulerListener", SchedulerListener.class);
|
||||
for (SchedulerListener listener : this.schedulerListeners) {
|
||||
ReflectionUtils.invokeMethod(addSchedulerListener, target, listener);
|
||||
}
|
||||
}
|
||||
if (this.globalJobListeners != null) {
|
||||
Method addJobListener;
|
||||
if (quartz2) {
|
||||
// addJobListener(JobListener) only introduced as late as Quartz 2.2, so we need
|
||||
// to fall back to the Quartz 2.0/2.1 compatible variant with an empty matchers List
|
||||
addJobListener = targetClass.getMethod("addJobListener", JobListener.class, List.class);
|
||||
}
|
||||
else {
|
||||
addJobListener = targetClass.getMethod("addGlobalJobListener", JobListener.class);
|
||||
}
|
||||
for (JobListener listener : this.globalJobListeners) {
|
||||
if (quartz2) {
|
||||
List<?> emptyMatchers = new LinkedList<Object>();
|
||||
ReflectionUtils.invokeMethod(addJobListener, target, listener, emptyMatchers);
|
||||
}
|
||||
else {
|
||||
ReflectionUtils.invokeMethod(addJobListener, target, listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.jobListeners != null) {
|
||||
for (JobListener listener : this.jobListeners) {
|
||||
if (quartz2) {
|
||||
throw new IllegalStateException("Non-global JobListeners not supported on Quartz 2 - " +
|
||||
"manually register a Matcher against the Quartz ListenerManager instead");
|
||||
}
|
||||
getScheduler().addJobListener(listener);
|
||||
}
|
||||
}
|
||||
if (this.globalTriggerListeners != null) {
|
||||
Method addTriggerListener;
|
||||
if (quartz2) {
|
||||
// addTriggerListener(TriggerListener) only introduced as late as Quartz 2.2, so we need
|
||||
// to fall back to the Quartz 2.0/2.1 compatible variant with an empty matchers List
|
||||
addTriggerListener = targetClass.getMethod("addTriggerListener", TriggerListener.class, List.class);
|
||||
}
|
||||
else {
|
||||
addTriggerListener = targetClass.getMethod("addGlobalTriggerListener", TriggerListener.class);
|
||||
}
|
||||
for (TriggerListener listener : this.globalTriggerListeners) {
|
||||
if (quartz2) {
|
||||
List<?> emptyMatchers = new LinkedList<Object>();
|
||||
ReflectionUtils.invokeMethod(addTriggerListener, target, listener, emptyMatchers);
|
||||
}
|
||||
else {
|
||||
ReflectionUtils.invokeMethod(addTriggerListener, target, listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.triggerListeners != null) {
|
||||
for (TriggerListener listener : this.triggerListeners) {
|
||||
if (quartz2) {
|
||||
throw new IllegalStateException("Non-global TriggerListeners not supported on Quartz 2 - " +
|
||||
"manually register a Matcher against the Quartz ListenerManager instead");
|
||||
}
|
||||
getScheduler().addTriggerListener(listener);
|
||||
}
|
||||
ListenerManager listenerManager = getScheduler().getListenerManager();
|
||||
if (this.schedulerListeners != null) {
|
||||
for (SchedulerListener listener : this.schedulerListeners) {
|
||||
listenerManager.addSchedulerListener(listener);
|
||||
}
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("Expected Quartz API not present: " + ex);
|
||||
if (this.globalJobListeners != null) {
|
||||
for (JobListener listener : this.globalJobListeners) {
|
||||
listenerManager.addJobListener(listener);
|
||||
}
|
||||
}
|
||||
if (this.globalTriggerListeners != null) {
|
||||
for (TriggerListener listener : this.globalTriggerListeners) {
|
||||
listenerManager.addTriggerListener(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,8 +29,7 @@ import org.springframework.beans.factory.ListableBeanFactory;
|
||||
* Spring bean-style class for accessing a Quartz Scheduler, i.e. for registering jobs,
|
||||
* triggers and listeners on a given {@link org.quartz.Scheduler} instance.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.8 as well as Quartz 2.0-2.2, as of Spring 4.0.
|
||||
* <b>Note:</b> Quartz 1.x support is deprecated - please upgrade to Quartz 2.0+.
|
||||
* <p>Compatible with Quartz 2.1.4 and higher, as of Spring 4.1.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.6
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -75,8 +75,7 @@ import org.springframework.util.CollectionUtils;
|
||||
* automatically apply to Scheduler operations performed within those scopes.
|
||||
* Alternatively, you may add transactional advice for the Scheduler itself.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.8 as well as Quartz 2.0-2.2, as of Spring 4.0.
|
||||
* <b>Note:</b> Quartz 1.x support is deprecated - please upgrade to Quartz 2.0+.
|
||||
* <p>Compatible with Quartz 2.1.4 and higher, as of Spring 4.1.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 18.02.2004
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.scheduling.quartz;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.quartz.JobDetail;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SimpleTrigger;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.Constants;
|
||||
|
||||
/**
|
||||
* Convenience subclass of Quartz's {@link org.quartz.SimpleTrigger} class,
|
||||
* making bean-style usage easier.
|
||||
*
|
||||
* <p>{@code SimpleTrigger} itself is already a JavaBean but lacks sensible defaults.
|
||||
* This class uses the Spring bean name as job name, the Quartz default group
|
||||
* ("DEFAULT") as job group, the current time as start time, and indefinite
|
||||
* repetition, if not specified.
|
||||
*
|
||||
* <p>This class will also register the trigger with the job name and group of
|
||||
* a given {@link org.quartz.JobDetail}. This allows {@link SchedulerFactoryBean}
|
||||
* to automatically register a trigger for the corresponding JobDetail,
|
||||
* instead of registering the JobDetail separately.
|
||||
*
|
||||
* <p><b>NOTE: This convenience subclass does not work against Quartz 2.0.</b>
|
||||
* Use Quartz 2.0's native {@code JobDetailImpl} class or the new Quartz 2.0
|
||||
* builder API instead. Alternatively, switch to Spring's {@link SimpleTriggerFactoryBean}
|
||||
* which largely is a drop-in replacement for this class and its properties and
|
||||
* consistently works against Quartz 1.x as well as Quartz 2.x.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 18.02.2004
|
||||
* @see #setName
|
||||
* @see #setGroup
|
||||
* @see #setStartTime
|
||||
* @see #setJobName
|
||||
* @see #setJobGroup
|
||||
* @see #setJobDetail
|
||||
* @see SchedulerFactoryBean#setTriggers
|
||||
* @see SchedulerFactoryBean#setJobDetails
|
||||
* @see CronTriggerBean
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class SimpleTriggerBean extends SimpleTrigger
|
||||
implements JobDetailAwareTrigger, BeanNameAware, InitializingBean {
|
||||
|
||||
/** Constants for the SimpleTrigger class */
|
||||
private static final Constants constants = new Constants(SimpleTrigger.class);
|
||||
|
||||
|
||||
private long startDelay = 0;
|
||||
|
||||
private JobDetail jobDetail;
|
||||
|
||||
private String beanName;
|
||||
|
||||
|
||||
public SimpleTriggerBean() {
|
||||
setRepeatCount(REPEAT_INDEFINITELY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register objects in the JobDataMap via a given Map.
|
||||
* <p>These objects will be available to this Trigger only,
|
||||
* in contrast to objects in the JobDetail's data map.
|
||||
* @param jobDataAsMap Map with String keys and any objects as values
|
||||
* (for example Spring-managed beans)
|
||||
* @see JobDetailBean#setJobDataAsMap
|
||||
*/
|
||||
public void setJobDataAsMap(Map<String, ?> jobDataAsMap) {
|
||||
getJobDataMap().putAll(jobDataAsMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the misfire instruction via the name of the corresponding
|
||||
* constant in the {@link org.quartz.SimpleTrigger} class.
|
||||
* Default is {@code MISFIRE_INSTRUCTION_SMART_POLICY}.
|
||||
* @see org.quartz.SimpleTrigger#MISFIRE_INSTRUCTION_FIRE_NOW
|
||||
* @see org.quartz.SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT
|
||||
* @see org.quartz.SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
|
||||
* @see org.quartz.SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
|
||||
* @see org.quartz.SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
|
||||
* @see org.quartz.Trigger#MISFIRE_INSTRUCTION_SMART_POLICY
|
||||
*/
|
||||
public void setMisfireInstructionName(String constantName) {
|
||||
setMisfireInstruction(constants.asNumber(constantName).intValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a list of TriggerListener names for this job, referring to
|
||||
* non-global TriggerListeners registered with the Scheduler.
|
||||
* <p>A TriggerListener name always refers to the name returned
|
||||
* by the TriggerListener implementation.
|
||||
* @see SchedulerFactoryBean#setTriggerListeners
|
||||
* @see org.quartz.TriggerListener#getName
|
||||
* @deprecated as of Spring 4.0, since it only works on Quartz 1.x
|
||||
*/
|
||||
@Deprecated
|
||||
public void setTriggerListenerNames(String... names) {
|
||||
for (String name : names) {
|
||||
addTriggerListener(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the start delay in milliseconds.
|
||||
* <p>The start delay is added to the current system time (when the bean starts)
|
||||
* to control the {@link #setStartTime start time} of the trigger.
|
||||
* <p>If the start delay is non-zero, it will <strong>always</strong>
|
||||
* take precedence over start time.
|
||||
* @param startDelay the start delay, in milliseconds
|
||||
*/
|
||||
public void setStartDelay(long startDelay) {
|
||||
this.startDelay = startDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JobDetail that this trigger should be associated with.
|
||||
* <p>This is typically used with a bean reference if the JobDetail
|
||||
* is a Spring-managed bean. Alternatively, the trigger can also
|
||||
* be associated with a job by name and group.
|
||||
* @see #setJobName
|
||||
* @see #setJobGroup
|
||||
*/
|
||||
public void setJobDetail(JobDetail jobDetail) {
|
||||
this.jobDetail = jobDetail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JobDetail getJobDetail() {
|
||||
return this.jobDetail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanName(String beanName) {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (getName() == null) {
|
||||
setName(this.beanName);
|
||||
}
|
||||
if (getGroup() == null) {
|
||||
setGroup(Scheduler.DEFAULT_GROUP);
|
||||
}
|
||||
if (this.startDelay > 0 || getStartTime() == null) {
|
||||
setStartTime(new Date(System.currentTimeMillis() + this.startDelay));
|
||||
}
|
||||
if (this.jobDetail != null) {
|
||||
setJobName(this.jobDetail.getName());
|
||||
setJobGroup(this.jobDetail.getGroup());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.scheduling.quartz;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -24,16 +23,13 @@ import org.quartz.JobDataMap;
|
||||
import org.quartz.JobDetail;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SimpleTrigger;
|
||||
import org.quartz.impl.triggers.SimpleTriggerImpl;
|
||||
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.Constants;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* A Spring {@link FactoryBean} for creating a Quartz {@link org.quartz.SimpleTrigger}
|
||||
@@ -48,9 +44,6 @@ import org.springframework.util.ReflectionUtils;
|
||||
* to automatically register a trigger for the corresponding JobDetail,
|
||||
* instead of registering the JobDetail separately.
|
||||
*
|
||||
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.x,
|
||||
* in contrast to the older {@link SimpleTriggerBean} class.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @see #setName
|
||||
@@ -59,7 +52,6 @@ import org.springframework.util.ReflectionUtils;
|
||||
* @see #setJobDetail
|
||||
* @see SchedulerFactoryBean#setTriggers
|
||||
* @see SchedulerFactoryBean#setJobDetails
|
||||
* @see CronTriggerBean
|
||||
*/
|
||||
public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, BeanNameAware, InitializingBean {
|
||||
|
||||
@@ -136,7 +128,6 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
* in contrast to objects in the JobDetail's data map.
|
||||
* @param jobDataAsMap Map with String keys and any objects as values
|
||||
* (for example Spring-managed beans)
|
||||
* @see org.springframework.scheduling.quartz.JobDetailBean#setJobDataAsMap
|
||||
*/
|
||||
public void setJobDataAsMap(Map<String, ?> jobDataAsMap) {
|
||||
this.jobDataMap.putAll(jobDataAsMap);
|
||||
@@ -228,13 +219,12 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
this.group = Scheduler.DEFAULT_GROUP;
|
||||
}
|
||||
if (this.jobDetail != null) {
|
||||
this.jobDataMap.put(JobDetailAwareTrigger.JOB_DETAIL_KEY, this.jobDetail);
|
||||
this.jobDataMap.put("jobDetail", this.jobDetail);
|
||||
}
|
||||
if (this.startDelay > 0 || this.startTime == null) {
|
||||
this.startTime = new Date(System.currentTimeMillis() + this.startDelay);
|
||||
}
|
||||
|
||||
/*
|
||||
SimpleTriggerImpl sti = new SimpleTriggerImpl();
|
||||
sti.setName(this.name);
|
||||
sti.setGroup(this.group);
|
||||
@@ -245,43 +235,8 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
sti.setRepeatCount(this.repeatCount);
|
||||
sti.setPriority(this.priority);
|
||||
sti.setMisfireInstruction(this.misfireInstruction);
|
||||
cti.setDescription(this.description);
|
||||
sti.setDescription(this.description);
|
||||
this.simpleTrigger = sti;
|
||||
*/
|
||||
|
||||
Class<?> simpleTriggerClass;
|
||||
Method jobKeyMethod;
|
||||
try {
|
||||
simpleTriggerClass = getClass().getClassLoader().loadClass("org.quartz.impl.triggers.SimpleTriggerImpl");
|
||||
jobKeyMethod = JobDetail.class.getMethod("getKey");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
simpleTriggerClass = SimpleTrigger.class;
|
||||
jobKeyMethod = null;
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("Incompatible Quartz version");
|
||||
}
|
||||
BeanWrapper bw = new BeanWrapperImpl(simpleTriggerClass);
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
pvs.add("name", this.name);
|
||||
pvs.add("group", this.group);
|
||||
if (jobKeyMethod != null) {
|
||||
pvs.add("jobKey", ReflectionUtils.invokeMethod(jobKeyMethod, this.jobDetail));
|
||||
}
|
||||
else {
|
||||
pvs.add("jobName", this.jobDetail.getName());
|
||||
pvs.add("jobGroup", this.jobDetail.getGroup());
|
||||
}
|
||||
pvs.add("jobDataMap", this.jobDataMap);
|
||||
pvs.add("startTime", this.startTime);
|
||||
pvs.add("repeatInterval", this.repeatInterval);
|
||||
pvs.add("repeatCount", this.repeatCount);
|
||||
pvs.add("priority", this.priority);
|
||||
pvs.add("misfireInstruction", this.misfireInstruction);
|
||||
pvs.add("description", this.description);
|
||||
bw.setPropertyValues(pvs);
|
||||
this.simpleTrigger = (SimpleTrigger) bw.getWrappedInstance();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,29 +16,24 @@
|
||||
|
||||
package org.springframework.scheduling.quartz;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.SchedulerContext;
|
||||
import org.quartz.spi.TriggerFiredBundle;
|
||||
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.PropertyAccessorFactory;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Subclass of {@link AdaptableJobFactory} that also supports Spring-style
|
||||
* dependency injection on bean properties. This is essentially the direct
|
||||
* equivalent of Spring's {@link QuartzJobBean} in the shape of a
|
||||
* Quartz 1.5 {@link org.quartz.spi.JobFactory}.
|
||||
* equivalent of Spring's {@link QuartzJobBean} in the shape of a Quartz
|
||||
* {@link org.quartz.spi.JobFactory}.
|
||||
*
|
||||
* <p>Applies scheduler context, job data map and trigger data map entries
|
||||
* as bean property values. If no matching bean property is found, the entry
|
||||
* is by default simply ignored. This is analogous to QuartzJobBean's behavior.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.8 as well as Quartz 2.0-2.2, as of Spring 4.0.
|
||||
* <b>Note:</b> Quartz 1.x support is deprecated - please upgrade to Quartz 2.0+.
|
||||
* <p>Compatible with Quartz 2.1.4 and higher, as of Spring 4.1.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
@@ -83,8 +78,8 @@ public class SpringBeanJobFactory extends AdaptableJobFactory implements Schedul
|
||||
if (this.schedulerContext != null) {
|
||||
pvs.addPropertyValues(this.schedulerContext);
|
||||
}
|
||||
pvs.addPropertyValues(getJobDetailDataMap(bundle));
|
||||
pvs.addPropertyValues(getTriggerDataMap(bundle));
|
||||
pvs.addPropertyValues(bundle.getJobDetail().getJobDataMap());
|
||||
pvs.addPropertyValues(bundle.getTrigger().getJobDataMap());
|
||||
if (this.ignoredUnknownProperties != null) {
|
||||
for (String propName : this.ignoredUnknownProperties) {
|
||||
if (pvs.contains(propName) && !bw.isWritableProperty(propName)) {
|
||||
@@ -112,20 +107,4 @@ public class SpringBeanJobFactory extends AdaptableJobFactory implements Schedul
|
||||
return (!(jobObject instanceof QuartzJobBean));
|
||||
}
|
||||
|
||||
// Reflectively adapting to differences between Quartz 1.x and Quartz 2.0...
|
||||
private JobDataMap getJobDetailDataMap(TriggerFiredBundle bundle) throws Exception {
|
||||
Method getJobDetail = bundle.getClass().getMethod("getJobDetail");
|
||||
Object jobDetail = ReflectionUtils.invokeMethod(getJobDetail, bundle);
|
||||
Method getJobDataMap = jobDetail.getClass().getMethod("getJobDataMap");
|
||||
return (JobDataMap) ReflectionUtils.invokeMethod(getJobDataMap, jobDetail);
|
||||
}
|
||||
|
||||
// Reflectively adapting to differences between Quartz 1.x and Quartz 2.0...
|
||||
private JobDataMap getTriggerDataMap(TriggerFiredBundle bundle) throws Exception {
|
||||
Method getTrigger = bundle.getClass().getMethod("getTrigger");
|
||||
Object trigger = ReflectionUtils.invokeMethod(getTrigger, bundle);
|
||||
Method getJobDataMap = trigger.getClass().getMethod("getJobDataMap");
|
||||
return (JobDataMap) ReflectionUtils.invokeMethod(getJobDataMap, trigger);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user