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 org.quartz.Job;
020import org.quartz.JobExecutionContext;
021import org.quartz.JobExecutionException;
022import org.quartz.SchedulerException;
023
024import org.springframework.beans.BeanWrapper;
025import org.springframework.beans.MutablePropertyValues;
026import org.springframework.beans.PropertyAccessorFactory;
027
028/**
029 * Simple implementation of the Quartz Job interface, applying the
030 * passed-in JobDataMap and also the SchedulerContext as bean property
031 * values. This is appropriate because a new Job instance will be created
032 * for each execution. JobDataMap entries will override SchedulerContext
033 * entries with the same keys.
034 *
035 * <p>For example, let's assume that the JobDataMap contains a key
036 * "myParam" with value "5": The Job implementation can then expose
037 * a bean property "myParam" of type int to receive such a value,
038 * i.e. a method "setMyParam(int)". This will also work for complex
039 * types like business objects etc.
040 *
041 * <p><b>Note that the preferred way to apply dependency injection
042 * to Job instances is via a JobFactory:</b> that is, to specify
043 * {@link SpringBeanJobFactory} as Quartz JobFactory (typically via
044 * {@link SchedulerFactoryBean#setJobFactory} SchedulerFactoryBean's "jobFactory" property}).
045 * This allows to implement dependency-injected Quartz Jobs without
046 * a dependency on Spring base classes.
047 *
048 * @author Juergen Hoeller
049 * @since 18.02.2004
050 * @see org.quartz.JobExecutionContext#getMergedJobDataMap()
051 * @see org.quartz.Scheduler#getContext()
052 * @see SchedulerFactoryBean#setSchedulerContextAsMap
053 * @see SpringBeanJobFactory
054 * @see SchedulerFactoryBean#setJobFactory
055 */
056public abstract class QuartzJobBean implements Job {
057
058        /**
059         * This implementation applies the passed-in job data map as bean property
060         * values, and delegates to {@code executeInternal} afterwards.
061         * @see #executeInternal
062         */
063        @Override
064        public final void execute(JobExecutionContext context) throws JobExecutionException {
065                try {
066                        BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
067                        MutablePropertyValues pvs = new MutablePropertyValues();
068                        pvs.addPropertyValues(context.getScheduler().getContext());
069                        pvs.addPropertyValues(context.getMergedJobDataMap());
070                        bw.setPropertyValues(pvs, true);
071                }
072                catch (SchedulerException ex) {
073                        throw new JobExecutionException(ex);
074                }
075                executeInternal(context);
076        }
077
078        /**
079         * Execute the actual job. The job data map will already have been
080         * applied as bean property values by execute. The contract is
081         * exactly the same as for the standard Quartz execute method.
082         * @see #execute
083         */
084        protected abstract void executeInternal(JobExecutionContext context) throws JobExecutionException;
085
086}