At the moment it is possible to call a single method on a bean with the MethodInvokingJobDetailFactoryBean. I would like to see a new JobDetailFactoryBean that can do a sequence of calls. Without such a structure I must create a normal pojo just to chain the calls.
I took a look at the MethodInvokdingJobDetailFactoryBean and it wouldn`t be to hard to add such functionality.
Only the ArgumentConvertingMethodInvoker is missing.. but it would not be to hard to add it.Code:package org.springframework.scheduling.quartz; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.quartz.*; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.MethodInvoker; import java.lang.reflect.InvocationTargetException; import java.util.List; public class MethodInvokingSequenceJobDetailFactoryBean implements FactoryBean, BeanNameAware, InitializingBean { private String name; private String group = Scheduler.DEFAULT_GROUP; private boolean concurrent = true; private String beanName; private JobDetail jobDetail; private List methodInvokerList; /** * 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 * <a href="http://www.opensymphony.com/quartz/tutorial.html#jobsMore">here</a>. * <p>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; } public void setBeanName(String beanName) { this.beanName = beanName; } 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 ? MethodInvokingJob.class : StatefulMethodInvokingJob.class); this.jobDetail = new JobDetail(name, this.group, jobClass); this.jobDetail.getJobDataMap().put("methodInvokerList", methodInvokerList); this.jobDetail.setVolatility(true); } public Object getObject() { return this.jobDetail; } public Class getObjectType() { return (this.jobDetail != null) ? this.jobDetail.getClass() : JobDetail.class; } public boolean isSingleton() { return true; } public void setMethodInvokerList(List methodInvokerList){ if(methodInvokerList==null) throw new NullPointerException("methodInvokerList can`t be null"); this.methodInvokerList = methodInvokerList; } /** * 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 List methodInvokerList; /** * Set the MethodInvoker to use. */ public void setMethodInvokerList(List methodInvokerList) { this.methodInvokerList = methodInvokerList; } private String createErrorMsg(MethodInvoker methodInvoker){ return "Could not invoke method '" + methodInvoker.getTargetMethod() + "' on target object [" + methodInvoker.getTargetObject() + "]"; } /** * Invoke the method via the MethodInvoker. */ protected void executeInternal(JobExecutionContext context) throws JobExecutionException { MethodInvoker methodInvoker = null; try { for(int k=0;k<methodInvokerList.size();k++){ methodInvoker = (MethodInvoker)methodInvokerList.get(k); methodInvoker.prepare(); methodInvoker.invoke(); } } catch (InvocationTargetException ex) { String errorMsg = createErrorMsg(methodInvoker); logger.warn(errorMsg + ": " + ex.getTargetException().getMessage()); if (ex.getTargetException() instanceof JobExecutionException) { throw (JobExecutionException) ex.getTargetException(); } Exception jobEx = (ex.getTargetException() instanceof Exception) ? (Exception) ex.getTargetException() : ex; throw new JobExecutionException(errorMsg, jobEx, false); } catch (Exception ex) { String errorMsg = createErrorMsg(methodInvoker); logger.warn(errorMsg + ": " + ex.getMessage()); throw new JobExecutionException(errorMsg, 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. } }
example of usage:
Code:<bean id="indexWriterJobCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail"> <bean class="com.jph.spring.MethodInvokingSequenceJobDetailFactoryBean"> <property name="methodInvokerList"> <list> <bean class="org.springframework.util.MethodInvoker"> <property name="targetObject"> <ref bean="indexWriter"/> </property> <property name="targetMethod"> <value>processQueue</value> </property> </bean> <bean class="org.springframework.util.MethodInvoker"> <property name="targetObject"> <ref bean="baseSearcher"/> </property> <property name="targetMethod"> <value>refreshReader</value> </property> </bean> </list> </property> <property name="concurrent"> <value>false</value> </property> </bean> </property> <property name="cronExpression"> <!-- iedere minuut --> <value>0 0/1 * * * ?</value> </property> </bean>


Reply With Quote