/**
* Copyright (c) Codice Foundation
* <p>
* This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or any later version.
* <p>
* 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
* Lesser General Public License for more details. A copy of the GNU Lesser General Public License
* is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*/
package ddf.platform.scheduler;
import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;
import java.util.Map;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.quartz.Job;
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;
/**
* Schedules a Command task
*
* @author Ashraf Barakat
* @author ddf.isgs@lmco.com
*/
public class ScheduledCommandTask implements ScheduledTask {
public static final String SECOND_INTERVAL = "secondInterval";
public static final String CRON_STRING = "cronString";
public static final String INTERVAL_STRING = "intervalString";
public static final String INTERVAL_TYPE = "intervalType";
public static final String ONE_DAY = "0 0 0 1/1 * ? *";
private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledCommandTask.class);
private Class<? extends Job> jobClass;
private String intervalString = ONE_DAY;
private String intervalType = CRON_STRING;
private String command;
private Scheduler scheduler;
private JobKey jobKey;
private TriggerKey triggerKey;
/**
* @param scheduler - A reference to the Quartz Scheduler
* @param jobClass - A reference to the Quartz Job Implementing Class
*/
public ScheduledCommandTask(Scheduler scheduler, Class jobClass) {
this.scheduler = scheduler;
this.jobClass = jobClass;
}
public void setCommand(String command) {
this.command = command;
}
public String getCommand() {
return command;
}
public void setIntervalString(String intervalString) {
if (StringUtils.isNotEmpty(intervalString)) {
this.intervalString = intervalString;
}
}
public String getIntervalString() {
return intervalString;
}
public void setIntervalType(String intervalType) {
if (StringUtils.isNotEmpty(intervalType)) {
this.intervalType = intervalType;
}
}
public String getIntervalType() {
return intervalType;
}
@Override
public void newTask() {
LOGGER.trace("Creating new Task.");
long identifier = System.currentTimeMillis();
this.jobKey = new JobKey("job" + identifier, jobClass.getSimpleName());
this.triggerKey = new TriggerKey("trigger" + identifier, jobClass.getSimpleName());
JobDetail jobDetail = createJob();
Trigger trigger = createTrigger();
if (trigger == null) {
return;
}
try {
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
LOGGER.info("Error with scheduling of task.", e);
}
}
@Override
public void deleteTask(int code) {
try {
scheduler.deleteJob(jobKey);
} catch (SchedulerException e) {
LOGGER.info("Error with deletion of task.", e);
}
}
@Override
public void updateTask(Map<String, Object> properties) {
if (MapUtils.isEmpty(properties)) {
LOGGER.info("Empty or null properties map. No action taken.");
return;
}
Object commandValue = properties.get(CommandJob.COMMAND_KEY);
if (commandValue != null) {
this.command = commandValue.toString();
}
Object intervalString = properties.get(INTERVAL_STRING);
if (intervalString != null) {
LOGGER.debug("Updating intervalString : {}", intervalString);
this.intervalString = (String) intervalString;
}
Object intervalType = properties.get(INTERVAL_TYPE);
if (intervalType != null) {
LOGGER.debug("Updating intervalType : {}", intervalType);
this.intervalType = (String) intervalType;
}
JobDetail newJob = createJob();
Trigger newTrigger = createTrigger();
if (newTrigger == null) {
return;
}
try {
scheduler.addJob(newJob, true);
scheduler.rescheduleJob(triggerKey, newTrigger);
} catch (SchedulerException e) {
LOGGER.info("Error with rescheduling of task.", e);
}
}
private JobDetail createJob() {
return newJob().ofType(jobClass)
.withIdentity(jobKey)
.storeDurably()
.usingJobData(CommandJob.COMMAND_KEY, command)
.build();
}
private Trigger createTrigger() {
Trigger newTrigger = null;
if (CRON_STRING.equals(this.intervalType)) {
newTrigger = createCronTrigger();
} else if (SECOND_INTERVAL.equals(this.intervalType)) {
try {
Integer secondsInterval = Integer.parseInt(this.intervalString);
newTrigger = createSimpleTrigger(secondsInterval);
} catch (NumberFormatException e) {
LOGGER.warn("Unable to update platform scheduler. Invalid second interval specified : {}",
this.intervalString,
e);
}
} else {
LOGGER.warn("Unable to update platform scheduler with given interval type : {}", this.intervalType);
}
return newTrigger;
}
private Trigger createSimpleTrigger(int secondsInterval) {
LOGGER.debug("Creating trigger with {} second interval", secondsInterval);
return newTrigger().withIdentity(triggerKey)
.startNow()
.withSchedule(simpleSchedule().withIntervalInSeconds(secondsInterval)
.repeatForever())
.build();
}
private Trigger createCronTrigger() {
LOGGER.debug("Creating trigger with cron string : {}", intervalString);
return newTrigger().withIdentity(triggerKey)
.startNow()
.withSchedule(cronSchedule(intervalString))
.build();
}
}