/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2009-2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) 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 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) 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 OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.netmgt.reporting.service;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Iterator;
import org.opennms.core.utils.BeanUtils;
import org.opennms.core.utils.LogUtils;
import org.opennms.netmgt.config.reportd.Report;
import org.opennms.netmgt.dao.ReportdConfigurationDao;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.spi.JobFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.util.StringUtils;
/**
* <p>ReportScheduler class.</p>
*
* @author ranger
* @version $Id: $
*/
public class ReportScheduler implements InitializingBean, DisposableBean {
/** Constant <code>JOB_GROUP="Reportd"</code> */
protected static final String JOB_GROUP = "Reportd";
@Autowired
private ReportdConfigurationDao m_configDao;
@Autowired
private Scheduler m_scheduler;
private JobFactory m_reportJobFactory;
private Object m_lock = new Object();
/**
* <p>afterPropertiesSet</p>
*
* @throws java.lang.Exception if any.
*/
@Override
public void afterPropertiesSet() throws Exception {
BeanUtils.assertAutowiring(this);
try {
getScheduler().setJobFactory(getReportJobFactory());
} catch (SchedulerException e) {
LogUtils.errorf(this, e, "afterPropertiesSet: couldn't set proper JobFactory for scheduler: %s", e.getMessage());
}
}
ReportScheduler(Scheduler sched){
m_scheduler = sched;
}
/**
* <p>rebuildReportSchedule</p>
*/
public void rebuildReportSchedule() {
LogUtils.infof(this,"rebuildReportSchedule: obtaining lock...");
synchronized (m_lock) {
LogUtils.debugf(this,"rebuildReportSchedule: lock acquired. reloading configuration...");
try {
m_configDao.reloadConfiguration();
LogUtils.debugf(this,"rebuildReportSchedule: removing current report jobs from schedule...");
removeCurrentJobsFromSchedule();
LogUtils.debugf(this,"rebuildReportSchedule: recreating report schedule based on configuration...");
buildReportSchedule();
printCurrentSchedule();
} catch (DataAccessResourceFailureException e) {
LogUtils.errorf(this, e, "rebuildReportSchedule: %s", e.getMessage());
throw new IllegalStateException(e);
}
}
LogUtils.infof(this,"rebuildReportSchedule: schedule rebuilt and lock released.");
}
private void printCurrentSchedule() {
try {
LogUtils.infof(this,"calendarNames: %s", StringUtils.arrayToCommaDelimitedString(getScheduler().getCalendarNames()));
LogUtils.infof(this,"current executing jobs: %s", StringUtils.arrayToCommaDelimitedString(getScheduler().getCurrentlyExecutingJobs().toArray()));
LogUtils.infof(this,"current job names: %s", StringUtils.arrayToCommaDelimitedString(getScheduler().getJobNames(JOB_GROUP)));
LogUtils.infof(this,"scheduler metadata: %s", getScheduler().getMetaData());
LogUtils.infof(this,"trigger names: %s", StringUtils.arrayToCommaDelimitedString(getScheduler().getTriggerNames(JOB_GROUP)));
Iterator<String> it = Arrays.asList(getScheduler().getTriggerNames(JOB_GROUP)).iterator();
while (it.hasNext()) {
String triggerName = it.next();
CronTrigger t = (CronTrigger) getScheduler().getTrigger(triggerName, JOB_GROUP);
StringBuilder sb = new StringBuilder("trigger: ");
sb.append(triggerName);
sb.append(", calendar name: ");
sb.append(t.getCalendarName());
sb.append(", cron expression: ");
sb.append(t.getCronExpression());
sb.append(", URL: ");
sb.append(t.getJobDataMap().get(ReportJob.KEY));
sb.append(", next fire time: ");
sb.append(t.getNextFireTime());
sb.append(", previous fire time: ");
sb.append(t.getPreviousFireTime());
sb.append(", time zone: ");
sb.append(t.getTimeZone());
sb.append(", priority: ");
sb.append(t.getPriority());
LogUtils.infof(this, sb.toString());
}
} catch (Throwable e) {
LogUtils.errorf(this, e, "printCurrentSchedule: %s", e.getMessage());
}
}
private void buildReportSchedule() {
synchronized (m_lock) {
for(Report report : m_configDao.getReports()) {
JobDetail detail = null;
Trigger trigger = null;
try {
detail = new JobDetail(report.getReportName(), JOB_GROUP, ReportJob.class, false, false, false);
detail.getJobDataMap().put(ReportJob.KEY, report);
trigger = new CronTrigger(report.getReportName(), JOB_GROUP, report.getCronSchedule());
trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);
getScheduler().scheduleJob(detail, trigger);
} catch (ParseException e) {
LogUtils.errorf(this, e, "buildReportSchedule: %s", e.getMessage());
} catch (SchedulerException e) {
LogUtils.errorf(this, e, "buildReportSchedule: %s", e.getMessage());
}
}
}
}
private void removeCurrentJobsFromSchedule() {
synchronized (m_lock) {
try {
Iterator<String> it = Arrays.asList(m_scheduler.getJobNames(JOB_GROUP)).iterator();
while (it.hasNext()) {
String jobName = it.next();
getScheduler().deleteJob(jobName, JOB_GROUP);
}
} catch (SchedulerException e) {
LogUtils.errorf(this, e, "removeCurrentJobsFromSchedule: %s", e.getMessage());
}
}
}
/**
* <p>getConfigDao</p>
*
* @return a {@link org.opennms.netmgt.dao.ReportdConfigurationDao} object.
*/
public ReportdConfigurationDao getConfigDao() {
return m_configDao;
}
/**
* <p>setConfigDao</p>
*
* @param configDao a {@link org.opennms.netmgt.dao.ReportdConfigurationDao} object.
*/
public void setConfigDao(ReportdConfigurationDao configDao) {
m_configDao = configDao;
}
/**
* <p>getScheduler</p>
*
* @return a {@link org.quartz.Scheduler} object.
*/
public Scheduler getScheduler() {
return m_scheduler;
}
/**
* <p>setScheduler</p>
*
* @param scheduler a {@link org.quartz.Scheduler} object.
*/
public void setScheduler(Scheduler scheduler) {
m_scheduler = scheduler;
}
/**
* <p>setReportJobFactory</p>
*
* @param reportJobFactory a {@link org.quartz.spi.JobFactory} object.
*/
public void setReportJobFactory(JobFactory reportJobFactory) {
m_reportJobFactory = reportJobFactory;
}
/**
* <p>getReportJobFactory</p>
*
* @return a {@link org.quartz.spi.JobFactory} object.
*/
public JobFactory getReportJobFactory() {
return m_reportJobFactory;
}
/**
* <p>start</p>
*
* @throws org.quartz.SchedulerException if any.
*/
public void start() throws SchedulerException {
getScheduler().start();
buildReportSchedule();
printCurrentSchedule();
}
/**
* <p>destroy</p>
*
* @throws org.quartz.SchedulerException if any.
*/
@Override
public void destroy() throws SchedulerException {
getScheduler().shutdown();
}
}