/* ================================================================== * JobUtils.java - Jul 22, 2013 8:08:48 AM * * Copyright 2007-2013 SolarNetwork.net Dev Team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA * ================================================================== */ package net.solarnetwork.node.runtime; import java.text.ParseException; import org.quartz.CronTrigger; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.Trigger; import org.quartz.TriggerKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.quartz.CronTriggerFactoryBean; import net.solarnetwork.node.job.RandomizedCronTriggerFactoryBean; /** * Utility methods for dealing with Quartz jobs. * * @author matt * @version 2.0 */ public class JobUtils { private static final Logger log = LoggerFactory.getLogger(JobUtils.class); /** * Get a setting key for a Trigger. * * <p> * The key is named after these elements, joined with a period character: * </p> * * <ol> * <li>job group (omitted if set to {@link Scheduler#DEFAULT_GROUP})</li> * <li>job name</li> * <li>trigger group (omitted if set to * {@link Scheduler#DEFAULT_GROUP})</li> * <li>trigger name</li> * </ol> * * @param t * the trigger to generate the key from * @return the setting key */ public static String triggerKey(Trigger t) { StringBuilder buf = new StringBuilder(); final TriggerKey triggerKey = t.getKey(); final JobKey jobKey = t.getJobKey(); if ( jobKey != null && jobKey.getGroup() != null && !Scheduler.DEFAULT_GROUP.equals(jobKey.getGroup()) ) { buf.append(jobKey.getGroup()); } if ( jobKey != null && jobKey.getName() != null ) { if ( buf.length() > 0 ) { buf.append('.'); } buf.append(jobKey.getName()); } if ( triggerKey.getGroup() != null && !Scheduler.DEFAULT_GROUP.equals(triggerKey.getGroup()) ) { if ( buf.length() > 0 ) { buf.append('.'); } buf.append(triggerKey.getGroup()); } if ( buf.length() > 0 ) { buf.append('.'); } buf.append(triggerKey.getName()); return buf.toString(); } /** * Schedule a new job or re-schedule an existing job. * * @param scheduler * the scheduler * @param trigger * the Trigger to schedule * @param jobDetail * the JobDetail to schedule * @param newCronExpression * the cron expression to re-schedule the job with, if not currently * scheduled */ public static void scheduleCronJob(Scheduler scheduler, CronTrigger trigger, JobDetail jobDetail, String newCronExpression, JobDataMap newJobDataMap) { // has the trigger value actually changed? CronTrigger ct = trigger; boolean reschedule = false; try { Trigger runtimeTrigger = scheduler.getTrigger(trigger.getKey()); if ( runtimeTrigger != null ) { reschedule = true; ct = (CronTrigger) runtimeTrigger; } } catch ( SchedulerException e ) { log.warn("Error getting trigger {}.{}", new Object[] { trigger.getKey().getGroup(), trigger.getKey().getName(), e }); } String baseCronExpression = null; String currentCronExpression = ct.getCronExpression(); if ( ct.getJobDataMap() .containsKey(RandomizedCronTriggerFactoryBean.BASE_CRON_EXPRESSION_KEY) ) { baseCronExpression = ct.getJobDataMap() .getString(RandomizedCronTriggerFactoryBean.BASE_CRON_EXPRESSION_KEY); currentCronExpression = baseCronExpression; } boolean triggerChanged = false; if ( !newCronExpression.equals(currentCronExpression) ) { log.info("Trigger {} cron changed from {} to {}", new Object[] { triggerKey(trigger), currentCronExpression, newCronExpression }); triggerChanged = true; } if ( newJobDataMap != null && !newJobDataMap.equals(ct.getJobDataMap()) ) { log.info("Trigger {} job data changed", triggerKey(trigger)); triggerChanged = true; } if ( !reschedule || triggerChanged ) { if ( reschedule ) { CronTriggerFactoryBean newTrigger; if ( baseCronExpression != null ) { RandomizedCronTriggerFactoryBean r = new RandomizedCronTriggerFactoryBean(); r.setRandomSecond(true); newTrigger = r; } else { newTrigger = new CronTriggerFactoryBean(); } newTrigger.setName(ct.getKey().getName()); newTrigger.setGroup(ct.getKey().getGroup()); newTrigger.setDescription(ct.getDescription()); newTrigger.setMisfireInstruction(ct.getMisfireInstruction()); newTrigger.setCronExpression(newCronExpression); newTrigger.setJobDetail(jobDetail); if ( newJobDataMap != null ) { newTrigger.setJobDataMap(newJobDataMap); } try { newTrigger.afterPropertiesSet(); CronTrigger newCt = newTrigger.getObject(); scheduler.rescheduleJob(ct.getKey(), newCt); } catch ( ParseException e ) { log.error("Error in cron expression [{}]", newCronExpression, e); } catch ( SchedulerException e ) { log.error("Error re-scheduling trigger {} for job {}", new Object[] { ct.getKey().getName(), jobDetail.getKey().getName(), e }); } } else { log.info("Scheduling trigger {} as cron {}", new Object[] { triggerKey(trigger), currentCronExpression }); try { scheduler.scheduleJob(jobDetail, ct); } catch ( SchedulerException e ) { log.error("Error scheduling trigger {} for job {}", new Object[] { ct.getKey().getName(), jobDetail.getKey().getName(), e }); } } } } }