All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean Maven / Gradle / Ivy

/*
 * Copyright 2002-2006 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.lang.reflect.InvocationTargetException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.StatefulJob;

import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.support.ArgumentConvertingMethodInvoker;
import org.springframework.util.ClassUtils;
import org.springframework.util.MethodInvoker;

/**
 * FactoryBean that exposes a JobDetail object that delegates job execution
 * to a specified (static or non-static) method. Avoids the need to implement
 * a one-line Quartz Job that just invokes an existing service method.
 *
 * 

Derived from MethodInvoker to share common properties and behavior * with MethodInvokingFactoryBean. * *

Supports both concurrently running jobs and non-currently running * ones through the "concurrent" property. * *

Note: JobDetails created via this FactoryBean are not * serializable and thus not suitable for persistent job stores. * 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. * * @author Juergen Hoeller * @author Alef Arendsen * @since 18.02.2004 * @see #setTargetObject * @see #setTargetMethod * @see #setConcurrent * @see org.springframework.beans.factory.config.MethodInvokingFactoryBean */ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethodInvoker implements FactoryBean, BeanNameAware, BeanClassLoaderAware, InitializingBean { private String name; private String group = Scheduler.DEFAULT_GROUP; private boolean concurrent = true; private String[] jobListenerNames; private String beanName; private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); private JobDetail jobDetail; /** * Set the name of the job. * Default is the bean name of this FactoryBean. * @see org.quartz.JobDetail#setName */ public void setName(String name) { this.name = name; } /** * Set the group of the job. * Default is the default group of the Scheduler. * @see org.quartz.JobDetail#setGroup * @see org.quartz.Scheduler#DEFAULT_GROUP */ public void setGroup(String group) { this.group = group; } /** * 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. * More information on stateful versus stateless jobs can be found * here. *

The default setting is to run jobs concurrently. * @param concurrent whether one wants to execute multiple jobs created * by this bean concurrently */ public void setConcurrent(boolean concurrent) { this.concurrent = concurrent; } /** * Set a list of JobListener names for this job, referring to * non-global JobListeners registered with the Scheduler. *

A JobListener name always refers to the name returned * by the JobListener implementation. * @see SchedulerFactoryBean#setJobListeners * @see org.quartz.JobListener#getName */ public void setJobListenerNames(String[] names) { this.jobListenerNames = names; } public void setBeanName(String beanName) { this.beanName = beanName; } public void setBeanClassLoader(ClassLoader classLoader) { this.beanClassLoader = classLoader; } protected Class resolveClassName(String className) throws ClassNotFoundException { return ClassUtils.forName(className, this.beanClassLoader); } public void afterPropertiesSet() throws ClassNotFoundException, NoSuchMethodException { prepare(); // Use specific name if given, else fall back to bean name. String name = (this.name != null ? this.name : this.beanName); // Consider the concurrent flag to choose between stateful and stateless job. Class jobClass = (this.concurrent ? (Class) MethodInvokingJob.class : StatefulMethodInvokingJob.class); // Build JobDetail instance. this.jobDetail = new JobDetail(name, this.group, jobClass); this.jobDetail.getJobDataMap().put("methodInvoker", this); this.jobDetail.setVolatility(true); // Register job listener names. if (this.jobListenerNames != null) { for (int i = 0; i < this.jobListenerNames.length; i++) { this.jobDetail.addJobListener(this.jobListenerNames[i]); } } } public Object getObject() { return this.jobDetail; } public Class getObjectType() { return JobDetail.class; } public boolean isSingleton() { return true; } /** * Quartz Job implementation that invokes a specified method. * Automatically applied by MethodInvokingJobDetailFactoryBean. */ public static class MethodInvokingJob extends QuartzJobBean { protected static final Log logger = LogFactory.getLog(MethodInvokingJob.class); private MethodInvoker methodInvoker; private String errorMessage; /** * Set the MethodInvoker to use. */ public void setMethodInvoker(MethodInvoker methodInvoker) { this.methodInvoker = methodInvoker; this.errorMessage = "Could not invoke method '" + this.methodInvoker.getTargetMethod() + "' on target object [" + this.methodInvoker.getTargetObject() + "]"; } /** * Invoke the method via the MethodInvoker. */ protected void executeInternal(JobExecutionContext context) throws JobExecutionException { try { this.methodInvoker.invoke(); } catch (InvocationTargetException ex) { logger.warn(this.errorMessage, ex.getTargetException()); if (ex.getTargetException() instanceof JobExecutionException) { throw (JobExecutionException) ex.getTargetException(); } Exception jobEx = (ex.getTargetException() instanceof Exception) ? (Exception) ex.getTargetException() : ex; throw new JobExecutionException(this.errorMessage, jobEx, false); } catch (Exception ex) { logger.warn(this.errorMessage, ex); throw new JobExecutionException(this.errorMessage, ex, false); } } } /** * Extension of the MethodInvokingJob, implementing the StatefulJob interface. * 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 { // No implementation, just a addition of the tag interface StatefulJob // in order to allow stateful method invoking jobs. } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy