package com.norteksoft.product.util;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.quartz.CronExpression;
import org.quartz.CronScheduleBuilder;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.norteksoft.bs.options.entity.Timer;
import com.norteksoft.bs.options.entity.RestJob;
public class Scheduler {
public static final String every = "";
static Logger log = LoggerFactory.getLogger(Scheduler.class);
private static SchedulerFactory factory;
private static org.quartz.Scheduler scheduler;
public static final String TRIGGER_GROUP = "QuartzTriggers";
public static final String JOB_GROUP = "QuartzJobs";
public static final String JOB_PREFIX = "user-job-";
public static final String TRIGGER_PREFIX = "user-trig-";
static{
log.debug(" init scheduler start ... ");
factory = new StdSchedulerFactory();
try {
scheduler = factory.getScheduler();
scheduler.start();
log.debug(" ... init scheduler end. ");
} catch (SchedulerException e) {
log.error(" init quartz exception. ", e);
}
}
private Scheduler(){}
/**
* 添加任务, 使用默认的触发器, 在每天凌晨执行
* @param job 执行的任务, 继承自 com.norteksoft.quartz.Job
*/
public static <T extends Job> void addJob(T job){
addJob(job, null, null);
}
/**
* 添加任务, 使用默认的触发器, 在每天凌晨执行
* @param job 执行的任务, 继承自 com.norteksoft.quartz.Job
* @param jobId job需要动态更新时必须提供
*/
public static <T extends Job> void addJob(T job, String jobId){
addJob(job, null, jobId);
}
/**
* 使用给定的触发器添加任务
* @param job 执行的任务, 继承自 com.norteksoft.quartz.Job
* @param trigger
*/
public static <T extends Job> void addJob(T job, Trigger trigger){
addJob(job, trigger, null);
}
/**
* 使用给定的触发器添加任务
* @param job 执行的任务, 继承自 com.norteksoft.quartz.Job
* @param trigger 如果需要使用 replaceTrigger 方法,则此处 trigger 必须指定 ID(使用 withIdentity() 方法)
* @param jobId job需要动态更新时必须提供
*/
public synchronized static <T extends Job> void addJob(T job, Trigger trigger, String jobId){
if(StringUtils.isBlank(jobId)){
jobId = Count.triggerId();
}else{
jobId = JOB_PREFIX+jobId;
}
JobDetail jobDetail = JobBuilder.newJob(job.getClass())
.withIdentity(jobId, JOB_GROUP)
.usingJobData(new JobDataMap(getPorpMap(job)))
.build();
try {
if(trigger == null){
scheduler.scheduleJob(jobDetail, getDefaultTrigger());
}else{
scheduler.scheduleJob(jobDetail, trigger);
}
} catch (SchedulerException e) {
log.error(" schedule job exception. ", e);
}
}
private static Map<String, Object> getPorpMap(Job job){
Map<String, Object> map = new HashMap<String, Object>();
Method[] ms = job.getClass().getMethods();
String propName = null;
String firstChar = null;
Object value = null;
for(Method m : ms){
if(m.getName().startsWith("get")&&!"getClass".equals(m.getName())){
propName = m.getName().substring(3);
firstChar = propName.substring(0, 1);
propName = propName.replaceFirst(firstChar, firstChar.toLowerCase());
try {
value = m.invoke(job);
} catch (Exception e) {
log.error(" invoke get method error[ prop : "+propName+" ]. ", e);
throw new RuntimeException(e);
}
map.put(propName, value);
}
}
return map;
}
// =============================================================================
/**
* 更换JOB
*/
public static void replaceJob(Job job, String jobId){
JobDetail jobDetail = JobBuilder.newJob(job.getClass())
.withIdentity(JOB_PREFIX+jobId, JOB_GROUP)
.usingJobData(new JobDataMap(getPorpMap(job)))
.build();
try {
scheduler.addJob(jobDetail, true);
} catch (SchedulerException e) {
log.error(" replace job exception. ", e);
throw new RuntimeException(e);
}
}
/**
* 更换触发器,触发器的Identity和被替换的触发器的Identity必须相等
* @param newTrig
*/
public static void replaceTrigger(Trigger newTrig){
try {
scheduler.rescheduleJob(newTrig.getKey(), newTrig);
} catch (SchedulerException e) {
log.error(" replace trigger exception. ", e);
throw new RuntimeException(e);
}
}
/**
* 添加JOB
* @param info
*/
public static void addJob(Timer info){
addJob(new RestJob(info),
CornBuilder.builderByCornInfo(info),
info.getId().toString());
}
/**
* 删除JOB
*/
public static void deleteJob(Timer info){
try {
scheduler.deleteJob(JobKey.jobKey(JOB_PREFIX+info.getId(), JOB_GROUP));
} catch (SchedulerException e) {
log.error(" delete job exception. ", e);
throw new RuntimeException(e);
}
}
/**
* 暂停JOB
*/
public static void pauseJob(Timer info){
try {
scheduler.pauseJob(JobKey.jobKey(JOB_PREFIX+info.getId(), JOB_GROUP));
} catch (SchedulerException e) {
log.error(" pause job exception. ", e);
throw new RuntimeException(e);
}
}
public static void resumeJob(Timer info){
try {
scheduler.resumeJob(JobKey.jobKey(JOB_PREFIX+info.getId(), JOB_GROUP));
} catch (SchedulerException e) {
log.error(" pause job exception. ", e);
throw new RuntimeException(e);
}
}
// ============================ Trigger start ===================================
/**
* 根据corn获取Trigger
*/
public static Trigger cornTrigger(String corn){
try {
CronExpression ce = new CronExpression(corn);
return TriggerBuilder.newTrigger()
.withSchedule(CronScheduleBuilder.cronSchedule(ce))
.build();
} catch (ParseException e) {
log.error(" Parse corn=["+corn+"] exception. ", e);
throw new RuntimeException(e);
}
}
/**
* 只在给定的时间执行一次的Trigger
* <br/>
* 执行完成后,自动清除任务;在没有执行前,可以删除任务
* @return
*/
public static Trigger getOnceTrigger(Date date){
return TriggerBuilder.newTrigger()
.withIdentity(Count.triggerId(), TRIGGER_GROUP)
.startAt(date)
.build();
}
/**
* 默认Trigger,从今天起,每天凌晨运行
* @return
*/
public static Trigger getDefaultTrigger(){
return getDefaultTrigger(null);
}
/**
* 默认Trigger,每天凌晨运行
* @return
*/
public static Trigger getDefaultTrigger(String triggerId){
if(StringUtils.isBlank(triggerId)){
triggerId = Count.triggerId();
}else{
triggerId = TRIGGER_PREFIX+triggerId;
}
return TriggerBuilder.newTrigger()
.withIdentity(triggerId, TRIGGER_GROUP)
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 0 * * ?"))
.build();
}
// ============================ Trigger end ===================================
public static void shutdown(){
try {
scheduler.shutdown();
} catch (SchedulerException e) {
log.error(" shutdown schedule exception. ", e);
}
}
static class Count{
private static int jobCount = 0;
private static int triggerCount = 0;
public static String jobId(){
return "job-" + (++jobCount);
}
public static String triggerId(){
return "trig-" + (++triggerCount);
}
}
public static org.quartz.Scheduler getScheduler() {
return scheduler;
}
}