/** * Copyright (c) 2010-2016 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.openhab.binding.weather.internal.scheduler; import static org.quartz.JobBuilder.newJob; import static org.quartz.SimpleScheduleBuilder.simpleSchedule; import static org.quartz.TriggerBuilder.newTrigger; import static org.quartz.impl.matchers.GroupMatcher.jobGroupEquals; import java.util.TimerTask; import org.openhab.binding.weather.WeatherBindingProvider; import org.openhab.binding.weather.internal.common.LocationConfig; import org.openhab.binding.weather.internal.common.WeatherContext; import org.openhab.binding.weather.internal.common.binding.WeatherBindingConfig; import org.openhab.binding.weather.internal.utils.DelayedExecutor; import org.openhab.binding.weather.internal.utils.ItemIterator; import org.openhab.binding.weather.internal.utils.ItemIterator.ItemIteratorCallback; 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.impl.StdSchedulerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Main class for scheduling weather jobs. * * @author Gerhard Riegler * @since 1.6.0 */ public class WeatherJobScheduler { private static final Logger logger = LoggerFactory.getLogger(WeatherJobScheduler.class); private static final String JOB_GROUP = "Weather"; private WeatherContext context; private Scheduler scheduler; private DelayedExecutor delayedExecutor = new DelayedExecutor(); public WeatherJobScheduler(WeatherContext context) { try { this.context = context; scheduler = StdSchedulerFactory.getDefaultScheduler(); } catch (SchedulerException ex) { logger.error(ex.getMessage(), ex); } } /** * Restarts the JobScheduler after a short delay. */ public synchronized void restart() { delayedExecutor.cancel(); delayedExecutor.schedule(new TimerTask() { @Override public void run() { stop(); start(); } }, 3000); } /** * Start the weather jobs if a binding is available. */ public void start() { validateItemLocationIds(); for (LocationConfig locationConfig : context.getConfig().getAllLocationConfigs()) { if (hasBinding(locationConfig.getLocationId())) { scheduleIntervalJob(locationConfig); } else { logger.info("Disabling weather locationId '{}', no binding available", locationConfig.getLocationId()); } } } /** * Validate the locationId in all items. */ private void validateItemLocationIds() { new ItemIterator().iterate(new ItemIteratorCallback() { @Override public void next(WeatherBindingConfig bindingConfig, String itemName) { if (context.getConfig().getLocationConfig(bindingConfig.getLocationId()) == null) { throw new RuntimeException( "Unknown locationId in item '" + itemName + "' with binding " + bindingConfig); } } }); } /** * Returns true, if a binding for the locationId is available. */ private boolean hasBinding(String locationId) { for (WeatherBindingProvider provider : context.getProviders()) { if (provider.hasBinding(locationId)) { return true; } } return false; } /** * Stops all scheduled jobs and clears the WeatherPublisher cache. */ public void stop() { try { for (JobKey jobKey : scheduler.getJobKeys(jobGroupEquals(JOB_GROUP))) { logger.info("Deleting " + jobKey.getName()); scheduler.deleteJob(jobKey); } } catch (SchedulerException ex) { logger.error(ex.getMessage(), ex); } } /** * Schedules the WeatherJob with the specified interval and starts it * immediately. */ public void scheduleIntervalJob(LocationConfig locationConfig) { String jobName = "weatherJob-" + locationConfig.getLocationId(); int interval = locationConfig.getUpdateInterval() * 60; JobDataMap jobDataMap = new JobDataMap(); jobDataMap.put("locationId", locationConfig.getLocationId()); try { Trigger trigger = newTrigger().withIdentity(jobName + "-Trigger", JOB_GROUP).startNow() .withSchedule(simpleSchedule().repeatForever().withIntervalInSeconds(interval)).build(); JobDetail jobDetail = newJob(WeatherJob.class).withIdentity(jobName, JOB_GROUP).usingJobData(jobDataMap) .build(); scheduler.scheduleJob(jobDetail, trigger); logger.info("Starting and scheduling {} with interval of {} minutes", jobName, locationConfig.getUpdateInterval()); } catch (SchedulerException ex) { logger.error(ex.getMessage(), ex); } } }