001/* 002 * Copyright 2002-2014 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.scheduling.quartz; 018 019import java.util.Map; 020 021import org.quartz.JobDataMap; 022import org.quartz.JobDetail; 023import org.quartz.Scheduler; 024import org.quartz.impl.JobDetailImpl; 025 026import org.springframework.beans.factory.BeanNameAware; 027import org.springframework.beans.factory.FactoryBean; 028import org.springframework.beans.factory.InitializingBean; 029import org.springframework.context.ApplicationContext; 030import org.springframework.context.ApplicationContextAware; 031 032/** 033 * A Spring {@link FactoryBean} for creating a Quartz {@link org.quartz.JobDetail} 034 * instance, supporting bean-style usage for JobDetail configuration. 035 * 036 * <p>{@code JobDetail(Impl)} itself is already a JavaBean but lacks 037 * sensible defaults. This class uses the Spring bean name as job name, 038 * and the Quartz default group ("DEFAULT") as job group if not specified. 039 * 040 * @author Juergen Hoeller 041 * @since 3.1 042 * @see #setName 043 * @see #setGroup 044 * @see org.springframework.beans.factory.BeanNameAware 045 * @see org.quartz.Scheduler#DEFAULT_GROUP 046 */ 047public class JobDetailFactoryBean 048 implements FactoryBean<JobDetail>, BeanNameAware, ApplicationContextAware, InitializingBean { 049 050 private String name; 051 052 private String group; 053 054 private Class<?> jobClass; 055 056 private JobDataMap jobDataMap = new JobDataMap(); 057 058 private boolean durability = false; 059 060 private boolean requestsRecovery = false; 061 062 private String description; 063 064 private String beanName; 065 066 private ApplicationContext applicationContext; 067 068 private String applicationContextJobDataKey; 069 070 private JobDetail jobDetail; 071 072 073 /** 074 * Specify the job's name. 075 */ 076 public void setName(String name) { 077 this.name = name; 078 } 079 080 /** 081 * Specify the job's group. 082 */ 083 public void setGroup(String group) { 084 this.group = group; 085 } 086 087 /** 088 * Specify the job's implementation class. 089 */ 090 public void setJobClass(Class<?> jobClass) { 091 this.jobClass = jobClass; 092 } 093 094 /** 095 * Set the job's JobDataMap. 096 * @see #setJobDataAsMap 097 */ 098 public void setJobDataMap(JobDataMap jobDataMap) { 099 this.jobDataMap = jobDataMap; 100 } 101 102 /** 103 * Return the job's JobDataMap. 104 */ 105 public JobDataMap getJobDataMap() { 106 return this.jobDataMap; 107 } 108 109 /** 110 * Register objects in the JobDataMap via a given Map. 111 * <p>These objects will be available to this Job only, 112 * in contrast to objects in the SchedulerContext. 113 * <p>Note: When using persistent Jobs whose JobDetail will be kept in the 114 * database, do not put Spring-managed beans or an ApplicationContext 115 * reference into the JobDataMap but rather into the SchedulerContext. 116 * @param jobDataAsMap Map with String keys and any objects as values 117 * (for example Spring-managed beans) 118 * @see org.springframework.scheduling.quartz.SchedulerFactoryBean#setSchedulerContextAsMap 119 */ 120 public void setJobDataAsMap(Map<String, ?> jobDataAsMap) { 121 getJobDataMap().putAll(jobDataAsMap); 122 } 123 124 /** 125 * Specify the job's durability, i.e. whether it should remain stored 126 * in the job store even if no triggers point to it anymore. 127 */ 128 public void setDurability(boolean durability) { 129 this.durability = durability; 130 } 131 132 /** 133 * Set the recovery flag for this job, i.e. whether or not the job should 134 * get re-executed if a 'recovery' or 'fail-over' situation is encountered. 135 */ 136 public void setRequestsRecovery(boolean requestsRecovery) { 137 this.requestsRecovery = requestsRecovery; 138 } 139 140 /** 141 * Set a textual description for this job. 142 */ 143 public void setDescription(String description) { 144 this.description = description; 145 } 146 147 @Override 148 public void setBeanName(String beanName) { 149 this.beanName = beanName; 150 } 151 152 @Override 153 public void setApplicationContext(ApplicationContext applicationContext) { 154 this.applicationContext = applicationContext; 155 } 156 157 /** 158 * Set the key of an ApplicationContext reference to expose in the JobDataMap, 159 * for example "applicationContext". Default is none. 160 * Only applicable when running in a Spring ApplicationContext. 161 * <p>In case of a QuartzJobBean, the reference will be applied to the Job 162 * instance as bean property. An "applicationContext" attribute will correspond 163 * to a "setApplicationContext" method in that scenario. 164 * <p>Note that BeanFactory callback interfaces like ApplicationContextAware 165 * are not automatically applied to Quartz Job instances, because Quartz 166 * itself is responsible for the lifecycle of its Jobs. 167 * <p><b>Note: When using persistent job stores where JobDetail contents will 168 * be kept in the database, do not put an ApplicationContext reference into 169 * the JobDataMap but rather into the SchedulerContext.</b> 170 * @see org.springframework.scheduling.quartz.SchedulerFactoryBean#setApplicationContextSchedulerContextKey 171 * @see org.springframework.context.ApplicationContext 172 */ 173 public void setApplicationContextJobDataKey(String applicationContextJobDataKey) { 174 this.applicationContextJobDataKey = applicationContextJobDataKey; 175 } 176 177 178 @Override 179 @SuppressWarnings("unchecked") 180 public void afterPropertiesSet() { 181 if (this.name == null) { 182 this.name = this.beanName; 183 } 184 if (this.group == null) { 185 this.group = Scheduler.DEFAULT_GROUP; 186 } 187 if (this.applicationContextJobDataKey != null) { 188 if (this.applicationContext == null) { 189 throw new IllegalStateException( 190 "JobDetailBean needs to be set up in an ApplicationContext " + 191 "to be able to handle an 'applicationContextJobDataKey'"); 192 } 193 getJobDataMap().put(this.applicationContextJobDataKey, this.applicationContext); 194 } 195 196 JobDetailImpl jdi = new JobDetailImpl(); 197 jdi.setName(this.name); 198 jdi.setGroup(this.group); 199 jdi.setJobClass((Class) this.jobClass); 200 jdi.setJobDataMap(this.jobDataMap); 201 jdi.setDurability(this.durability); 202 jdi.setRequestsRecovery(this.requestsRecovery); 203 jdi.setDescription(this.description); 204 this.jobDetail = jdi; 205 } 206 207 208 @Override 209 public JobDetail getObject() { 210 return this.jobDetail; 211 } 212 213 @Override 214 public Class<?> getObjectType() { 215 return JobDetail.class; 216 } 217 218 @Override 219 public boolean isSingleton() { 220 return true; 221 } 222 223}