/** * Copyright (c)2010-2011 Enterprise Website Content Management System(EWCMS), All rights reserved. * EWCMS PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * http://www.ewcms.com */ package com.ewcms.scheduling.generate.quartz; import static org.quartz.JobBuilder.newJob; import java.lang.reflect.InvocationTargetException; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.JobKey; import org.quartz.Matcher; import org.quartz.Scheduler; import org.quartz.impl.JobDetailImpl; import org.quartz.impl.matchers.KeyMatcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanWrapper; import org.springframework.beans.PropertyAccessorFactory; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.BeanFactory; 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.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.MethodInvoker; /** * * @author wuzhijun * */ public class EwcmsMethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethodInvoker implements FactoryBean<JobDetail>, BeanNameAware, BeanClassLoaderAware, InitializingBean { static{ try{ jobDetailImplClass = Class.forName("org.quartz.impl.JobDetailImpl"); }catch(ClassNotFoundException e){ jobDetailImplClass = null; } } private Scheduler scheduler; private static Class<?> jobDetailImplClass; private String name; private String group; private boolean concurrent; private String targetBeanName; private String jobListenerNames[]; private String beanName; private ClassLoader beanClassLoader; private BeanFactory beanFactory; private JobDetail jobDetail; public Scheduler getScheduler() throws JobExecutionException { if (scheduler == null){ throw new JobExecutionException("Fatal Error: bean '" + this.getClass().getName()+"' does not have its QuartzScheduler bean set and it is required to be."); } return scheduler; } public void setScheduler(Scheduler scheduler){ this.scheduler = scheduler; } public EwcmsMethodInvokingJobDetailFactoryBean(){ group = "DEFAULT"; concurrent = true; beanClassLoader = ClassUtils.getDefaultClassLoader(); } public void setName(String name){ this.name = name; } public void setGroup(String group){ this.group = group; } public void setConcurrent(Boolean concurrent){ this.concurrent = concurrent; } public void setTargetBeanName(String targetBeanName){ this.targetBeanName = targetBeanName; } public void setJobListenerNames(String names[]){ jobListenerNames = names; } public void setBeanFactory(BeanFactory beanFactory){ this.beanFactory = beanFactory; } @Override public void afterPropertiesSet() throws ClassNotFoundException, NoSuchMethodException { prepare(); String name = this.name == null ? beanName : this.name; Class<? extends MethodInvokingJob> jobClass = concurrent ? EwcmsMethodInvokingJobDetailFactoryBean.MethodInvokingJob.class : EwcmsMethodInvokingJobDetailFactoryBean.StatefulMethodInvokingJob.class; if(jobDetailImplClass != null){ jobDetail = (JobDetail)BeanUtils.instantiate(jobDetailImplClass); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(jobDetail); bw.setPropertyValue("name", name); bw.setPropertyValue("group", group); bw.setPropertyValue("jobClass", jobClass); bw.setPropertyValue("durability", Boolean.valueOf(true)); ((JobDataMap)bw.getPropertyValue("jobDataMap")).put("methodInvoker", this); }else{ jobDetail = newJob(jobClass).withIdentity(name, group).build(); if (!(jobDetail instanceof JobDetailImpl)) throw new RuntimeException("Expected JobDetail to be an instance of '" + JobDetailImpl.class + "' but instead we got '"+jobDetail.getClass().getName()+"'"); ((JobDetailImpl)jobDetail).setDurability(true); jobDetail.getJobDataMap().put("methodInvoker", this); } if(jobListenerNames != null){ String as[]; int j = (as = jobListenerNames).length; for(int i = 0; i < j; i++){ String jobListenerName = as[i]; if(jobDetailImplClass != null) throw new IllegalStateException("Non-global JobListeners not supported on Quartz 2 - manually register a Matcher against the Quartz ListenerManager instead"); JobKey jk = jobDetail.getKey(); Matcher<JobKey> matcher = KeyMatcher.keyEquals(jk); try { getScheduler().getListenerManager().addJobListenerMatcher(jobListenerName, matcher); } catch (org.quartz.SchedulerException e) { throw new RuntimeException("Error adding Quartz Trigger Listener: "+e.getMessage()); } //jobDetail.addJobListener(jobListenerName); } } postProcessJobDetail(jobDetail); } @Override public void setBeanClassLoader(ClassLoader classLoader) { beanClassLoader = classLoader; } @Override public void setBeanName(String beanName) { this.beanName = beanName; } protected void postProcessJobDetail(JobDetail jobdetail){ } @Override public Class<?> getTargetClass(){ Class<?> targetClass = super.getTargetClass(); if(targetClass == null && targetBeanName != null){ Assert.state(beanFactory != null, "BeanFactory must be set when using 'targetBeanName'"); targetClass = beanFactory.getType(targetBeanName); } return targetClass; } @Override public Object getTargetObject(){ Object targetObject = super.getTargetObject(); if(targetObject == null && targetBeanName != null){ Assert.state(beanFactory != null, "BeanFactory must be set when using 'targetBeanName'"); targetObject = beanFactory.getBean(targetBeanName); } return targetObject; } @Override public JobDetail getObject() throws Exception { return jobDetail; } @Override public Class<? extends JobDetail> getObjectType() { return jobDetail == null ? org.quartz.impl.JobDetailImpl.class : jobDetail.getClass(); } @Override public boolean isSingleton() { return true; } @Override protected Class<?> resolveClassName(String className) throws ClassNotFoundException{ return ClassUtils.forName(className, beanClassLoader); } public static class MethodInvokingJob extends EwcmsQuartzJobBean{ protected static final Logger logger = LoggerFactory.getLogger(EwcmsMethodInvokingJobDetailFactoryBean.MethodInvokingJob.class); private MethodInvoker methodInvoker; public MethodInvokingJob(){ } @Override protected void executeInternal(JobExecutionContext jobexecutioncontext) throws JobExecutionException { try{ jobexecutioncontext.setResult(methodInvoker.invoke()); } catch(InvocationTargetException ex){ if(ex.getTargetException() instanceof JobExecutionException) throw (JobExecutionException)ex.getTargetException(); else throw new EwcmsJobMethodInvocationFailedException(methodInvoker, ex.getTargetException()); } catch(Exception ex){ throw new EwcmsJobMethodInvocationFailedException(methodInvoker, ex); } } } @SuppressWarnings("deprecation") public static class StatefulMethodInvokingJob extends MethodInvokingJob implements org.quartz.StatefulJob{ public StatefulMethodInvokingJob(){ } } }