/* ================================================================== * NotificationScheduler.java - Jun 29, 2011 3:21:35 PM * * Copyright 2007-2011 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.central.scheduler.internal; import java.text.ParseException; import java.util.Date; import java.util.Map; import java.util.TimeZone; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; import org.quartz.CronScheduleBuilder; import org.quartz.CronTrigger; import org.quartz.JobBuilder; 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.TriggerBuilder; import org.quartz.TriggerKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.solarnetwork.central.scheduler.EventHandlerSupport; import net.solarnetwork.central.scheduler.SchedulerConstants; /** * OSGi {@link EventHandler} that schedules job requests. * * @author matt * @version 1.2 */ public class NotificationScheduler extends EventHandlerSupport { private static final String NOTIFICATION_JOB_NAME = "NotificationJob"; private static final String NOTIFICATION_JOB_GROUP = "Notification"; private final Logger log = LoggerFactory.getLogger(getClass()); private final Scheduler scheduler; private String cronTimeZoneId = TimeZone.getDefault().getID(); /** * Constructor. * * @param scheduler * the scheduler */ public NotificationScheduler(Scheduler scheduler) { this.scheduler = scheduler; } @Override protected void handleEventInternal(Event event) throws SchedulerException { final String jobId = (String) event.getProperty(SchedulerConstants.JOB_ID); if ( jobId == null ) { log.debug("Ignoring OSGi event without {}", SchedulerConstants.JOB_ID); return; } final String jobGroup = (String) event.getProperty(SchedulerConstants.JOB_GROUP); final Long jobDate = (Long) event.getProperty(SchedulerConstants.JOB_DATE); final String jobCron = (String) event.getProperty(SchedulerConstants.JOB_CRON_EXPRESSION); if ( jobDate == null && jobCron == null ) { log.debug("Ignoring OSGi event without {} or {} specified", SchedulerConstants.JOB_DATE, SchedulerConstants.JOB_CRON_EXPRESSION); return; } final String jobName = (jobCron != null ? jobId : NOTIFICATION_JOB_NAME); final String jobTopic = (String) event.getProperty(SchedulerConstants.JOB_TOPIC); if ( jobTopic == null ) { log.debug("Ignoring OSGi event without {}", SchedulerConstants.JOB_TOPIC); return; } @SuppressWarnings("unchecked") final Map<String, ?> jobProps = (Map<String, ?>) event .getProperty(SchedulerConstants.JOB_PROPERTIES); JobKey jobKey = new JobKey(jobName, NOTIFICATION_JOB_GROUP); // set up trigger properties, copying all job request properties final JobDataMap jobMap = new JobDataMap(); for ( String propName : event.getPropertyNames() ) { jobMap.put(propName, event.getProperty(propName)); } if ( jobProps != null ) { jobMap.putAll(jobProps); } final TriggerKey triggerKey = new TriggerKey(jobId, jobGroup); final Trigger trigger; if ( jobDate != null ) { trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).forJob(jobKey) .usingJobData(jobMap).startAt(new Date(jobDate)).build(); } else { try { CronScheduleBuilder cronBuilder = CronScheduleBuilder .cronScheduleNonvalidatedExpression(jobCron); if ( cronTimeZoneId != null ) { cronBuilder.inTimeZone(TimeZone.getTimeZone(cronTimeZoneId)); } CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey) .forJob(jobKey).usingJobData(jobMap).withSchedule(cronBuilder).build(); trigger = cronTrigger; } catch ( ParseException e ) { log.error("Bad cron expression [{}] for job {}: {}", jobName, jobCron, e.getMessage()); return; } } Trigger t = scheduler.getTrigger(triggerKey); if ( t != null ) { // job already scheduled, check for same time to re-schedule if ( t instanceof CronTrigger ) { CronTrigger ct = (CronTrigger) t; if ( !ct.getCronExpression().equals(jobCron) ) { log.debug("Re-scheduling cron job {}.{} for {}", new Object[] { jobGroup, jobId, jobCron }); scheduler.rescheduleJob(triggerKey, trigger); } } else { Date d = t.getStartTime(); if ( d.getTime() != jobDate ) { log.debug("Re-scheduling job {}.{} for {}", new Object[] { jobGroup, jobId, new Date(jobDate) }); scheduler.rescheduleJob(triggerKey, trigger); } } } else { log.debug("Scheduling job {}.{} for {}", new Object[] { jobGroup, jobId, (jobCron != null ? jobCron : new Date(jobDate).toString()) }); JobDetail job = JobBuilder .newJob((jobCron != null ? StatefulNotificationJob.class : NotificationJob.class)) .withIdentity(jobKey).requestRecovery().storeDurably(false).build(); scheduler.scheduleJob(job, trigger); } } public String getCronTimeZoneId() { return cronTimeZoneId; } public void setCronTimeZoneId(String cronTimeZoneId) { this.cronTimeZoneId = cronTimeZoneId; } }