Announcement Announcement Module
Collapse
No announcement yet.
quartz: do sequence of calls. Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • quartz: do sequence of calls.

    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.

    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&#58;//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&#40;boolean concurrent&#41; &#123;
    		this.concurrent = concurrent;
    	&#125;
    
    	public void setBeanName&#40;String beanName&#41; &#123;
    		this.beanName = beanName;
    	&#125;
    
    
    	public void afterPropertiesSet&#40;&#41; throws ClassNotFoundException, NoSuchMethodException &#123;
    	//	prepare&#40;&#41;;
    
    		// Use specific name if given, else fall back to bean name.
    		String name = &#40;this.name != null ? this.name &#58; this.beanName&#41;;
    
    		// Consider the concurrent flag to choose between stateful and stateless job.
    		Class jobClass = &#40;this.concurrent ? MethodInvokingJob.class &#58; StatefulMethodInvokingJob.class&#41;;
    
    		this.jobDetail = new JobDetail&#40;name, this.group, jobClass&#41;;
    		this.jobDetail.getJobDataMap&#40;&#41;.put&#40;"methodInvokerList", methodInvokerList&#41;;
    		this.jobDetail.setVolatility&#40;true&#41;;
    	&#125;
    
    	public Object getObject&#40;&#41; &#123;
    		return this.jobDetail;
    	&#125;
    
    	public Class getObjectType&#40;&#41; &#123;
    		return &#40;this.jobDetail != null&#41; ? this.jobDetail.getClass&#40;&#41; &#58; JobDetail.class;
    	&#125;
    
    	public boolean isSingleton&#40;&#41; &#123;
    		return true;
    	&#125;
    
    	public void setMethodInvokerList&#40;List methodInvokerList&#41;&#123;
    		if&#40;methodInvokerList==null&#41;
    		    throw new NullPointerException&#40;"methodInvokerList can`t be null"&#41;;
    		this.methodInvokerList = methodInvokerList;
    	&#125;
    
    	/**
    	 * Quartz Job implementation that invokes a specified method.
    	 * Automatically applied by MethodInvokingJobDetailFactoryBean.
    	 */
    	public static class MethodInvokingJob extends QuartzJobBean &#123;
    
    		protected static final Log logger = LogFactory.getLog&#40;MethodInvokingJob.class&#41;;
    
    		private List methodInvokerList;
    
    		/**
    		 * Set the MethodInvoker to use.
    		 */
    		public void setMethodInvokerList&#40;List  methodInvokerList&#41; &#123;
    			this.methodInvokerList = methodInvokerList;
    			
    		&#125;
    
    		private String createErrorMsg&#40;MethodInvoker methodInvoker&#41;&#123;
    			return "Could not invoke method '" + methodInvoker.getTargetMethod&#40;&#41; +
    					"' on target object &#91;" + methodInvoker.getTargetObject&#40;&#41; + "&#93;";
    		&#125;
    		
    		/**
    		 * Invoke the method via the MethodInvoker.
    		 */
    		protected void executeInternal&#40;JobExecutionContext context&#41; throws JobExecutionException &#123;
    			MethodInvoker methodInvoker = null;
    			try &#123;
    				for&#40;int k=0;k<methodInvokerList.size&#40;&#41;;k++&#41;&#123;
    					methodInvoker = &#40;MethodInvoker&#41;methodInvokerList.get&#40;k&#41;;
    					methodInvoker.prepare&#40;&#41;;
    					methodInvoker.invoke&#40;&#41;;
    				&#125;
    			&#125;
    			catch &#40;InvocationTargetException ex&#41; &#123;
    				String errorMsg = createErrorMsg&#40;methodInvoker&#41;;
    				logger.warn&#40;errorMsg + "&#58; " + ex.getTargetException&#40;&#41;.getMessage&#40;&#41;&#41;;
    				if &#40;ex.getTargetException&#40;&#41; instanceof JobExecutionException&#41; &#123;
    					throw &#40;JobExecutionException&#41; ex.getTargetException&#40;&#41;;
    				&#125;
    				Exception jobEx = &#40;ex.getTargetException&#40;&#41; instanceof Exception&#41; ?
    						&#40;Exception&#41; ex.getTargetException&#40;&#41; &#58; ex;
    				throw new JobExecutionException&#40;errorMsg, jobEx, false&#41;;
    			&#125;
    			catch &#40;Exception ex&#41; &#123;
    				String errorMsg = createErrorMsg&#40;methodInvoker&#41;;
    				logger.warn&#40;errorMsg + "&#58; " + ex.getMessage&#40;&#41;&#41;;
    				throw new JobExecutionException&#40;errorMsg, ex, false&#41;;
    			&#125;
    		&#125;
    	&#125;
    
    
    	/**
    	 * 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 &#123;
    		// No implementation, just a addition of the tag interface StatefulJob
    		// in order to allow stateful method invoking jobs.
    	&#125;
    
    &#125;
    Only the ArgumentConvertingMethodInvoker is missing.. but it would not be to hard to add it.

    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>

  • #2
    Make an issue on JIRA.

    Comment

    Working...
    X