001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.scheduling.quartz; 018 019import org.quartz.SchedulerContext; 020import org.quartz.spi.TriggerFiredBundle; 021 022import org.springframework.beans.BeanWrapper; 023import org.springframework.beans.MutablePropertyValues; 024import org.springframework.beans.PropertyAccessorFactory; 025 026/** 027 * Subclass of {@link AdaptableJobFactory} that also supports Spring-style 028 * dependency injection on bean properties. This is essentially the direct 029 * equivalent of Spring's {@link QuartzJobBean} in the shape of a Quartz 030 * {@link org.quartz.spi.JobFactory}. 031 * 032 * <p>Applies scheduler context, job data map and trigger data map entries 033 * as bean property values. If no matching bean property is found, the entry 034 * is by default simply ignored. This is analogous to QuartzJobBean's behavior. 035 * 036 * <p>Compatible with Quartz 2.1.4 and higher, as of Spring 4.1. 037 * 038 * @author Juergen Hoeller 039 * @since 2.0 040 * @see SchedulerFactoryBean#setJobFactory 041 * @see QuartzJobBean 042 */ 043public class SpringBeanJobFactory extends AdaptableJobFactory implements SchedulerContextAware { 044 045 private String[] ignoredUnknownProperties; 046 047 private SchedulerContext schedulerContext; 048 049 050 /** 051 * Specify the unknown properties (not found in the bean) that should be ignored. 052 * <p>Default is {@code null}, indicating that all unknown properties 053 * should be ignored. Specify an empty array to throw an exception in case 054 * of any unknown properties, or a list of property names that should be 055 * ignored if there is no corresponding property found on the particular 056 * job class (all other unknown properties will still trigger an exception). 057 */ 058 public void setIgnoredUnknownProperties(String... ignoredUnknownProperties) { 059 this.ignoredUnknownProperties = ignoredUnknownProperties; 060 } 061 062 @Override 063 public void setSchedulerContext(SchedulerContext schedulerContext) { 064 this.schedulerContext = schedulerContext; 065 } 066 067 068 /** 069 * Create the job instance, populating it with property values taken 070 * from the scheduler context, job data map and trigger data map. 071 */ 072 @Override 073 protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { 074 Object job = super.createJobInstance(bundle); 075 if (isEligibleForPropertyPopulation(job)) { 076 BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(job); 077 MutablePropertyValues pvs = new MutablePropertyValues(); 078 if (this.schedulerContext != null) { 079 pvs.addPropertyValues(this.schedulerContext); 080 } 081 pvs.addPropertyValues(bundle.getJobDetail().getJobDataMap()); 082 pvs.addPropertyValues(bundle.getTrigger().getJobDataMap()); 083 if (this.ignoredUnknownProperties != null) { 084 for (String propName : this.ignoredUnknownProperties) { 085 if (pvs.contains(propName) && !bw.isWritableProperty(propName)) { 086 pvs.removePropertyValue(propName); 087 } 088 } 089 bw.setPropertyValues(pvs); 090 } 091 else { 092 bw.setPropertyValues(pvs, true); 093 } 094 } 095 return job; 096 } 097 098 /** 099 * Return whether the given job object is eligible for having 100 * its bean properties populated. 101 * <p>The default implementation ignores {@link QuartzJobBean} instances, 102 * which will inject bean properties themselves. 103 * @param jobObject the job object to introspect 104 * @see QuartzJobBean 105 */ 106 protected boolean isEligibleForPropertyPopulation(Object jobObject) { 107 return (!(jobObject instanceof QuartzJobBean)); 108 } 109 110}