/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ro.nextreports.server.schedule; import java.util.Date; import java.util.List; import java.util.Set; import java.util.UUID; import org.quartz.CronScheduleBuilder; 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.Trigger.TriggerState; import org.quartz.TriggerBuilder; import org.quartz.impl.matchers.GroupMatcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Required; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.security.core.context.SecurityContextHolder; import ro.nextreports.server.audit.AuditEvent; import ro.nextreports.server.audit.Auditor; import ro.nextreports.server.domain.ReportJobInfo; import ro.nextreports.server.domain.RunReportHistory; import ro.nextreports.server.domain.SchedulerJob; import ro.nextreports.server.domain.SchedulerTime; import ro.nextreports.server.domain.User; import ro.nextreports.server.service.DataSourceService; import ro.nextreports.server.service.ReportService; import ro.nextreports.server.service.SecurityService; import ro.nextreports.server.service.StorageService; import ro.nextreports.server.util.StorageUtil; /** * @author Decebal Suiu */ public class QuartzJobHandler { private static final Logger LOG = LoggerFactory.getLogger(QuartzJobHandler.class); private Scheduler scheduler; private JavaMailSender mailSender; private ReportService reportService; private StorageService storageService; private SecurityService securityService; private DataSourceService dataSourceService; private Auditor auditor; public void runMonitorJob(JobDetail jobDetail) throws Exception { SchedulerJob schedulerJob = (SchedulerJob) jobDetail.getJobDataMap().get(RunReportJob.SCHEDULER_JOB); schedulerJob.setRunNow(true); addJob(schedulerJob, jobDetail, false); } public void addJob(SchedulerJob job) throws Exception { addJob(job, null, false); } public void addJob(SchedulerJob job, JobDetail jobDetail, boolean synchronous) throws Exception { // TODO test for null/empty String key = UUID.randomUUID().toString(); String jobName= null; if (job.getPath() != null) { jobName = job.getPath(); } else { String path = ""; if (!StorageUtil.isVersion(job.getReport())) { path = job.getReport().getPath(); } else { try { path = storageService.getEntityById(StorageUtil.getVersionableId(job.getReport())).getPath(); } catch (Exception e) { path = "unknown"; e.printStackTrace(); LOG.error(e.getMessage(), e); } } jobName = path + ReportJobInfo.NAME_DELIMITER + key; } if (LOG.isDebugEnabled()) { LOG.debug("jobName = {}", jobName); } JobDataMap jobData = new JobDataMap(); jobData.put(RunReportJob.SCHEDULER_JOB, job); jobData.put(RunReportJob.MAIL_SENDER, mailSender); jobData.put(RunReportJob.REPORT_SERVICE, reportService); jobData.put(RunReportJob.STORAGE_SERVICE, storageService); jobData.put(RunReportJob.SECURITY_SERVICE, securityService); jobData.put(RunReportJob.DATASOURCE_SERVICE, dataSourceService); jobData.put(RunReportJob.AUDITOR, auditor); String runnerId = job.getId(); String runnerType = RunReportHistory.SCHEDULER; // jobDetail != null in case of runNow from monitor if ((runnerId == null) || (jobDetail != null)) { User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); String username = user.getUsername(); LOG.debug("username = {}" + username); runnerId = user.getId(); runnerType = RunReportHistory.USER; } jobData.put(RunReportJob.RUNNER_TYPE, runnerType); jobData.put(RunReportJob.RUNNER_ID, runnerId); jobData.put(RunReportJob.RUNNER_KEY, key); jobData.put(RunReportJob.REPORT_TYPE, job.getReport().getType()); LOG.debug("runnerType = {}", runnerType); LOG.debug("runnerId = {}", runnerId); AuditEvent auditEvent = new AuditEvent("Run report"); auditEvent.getContext().put("PATH", StorageUtil.getPathWithoutRoot(job.getReport().getPath())); jobData.put(RunReportJob.AUDIT_EVENT, auditEvent); boolean existingJobDetail = true; if (jobDetail == null) { existingJobDetail = false; jobDetail = JobBuilder.newJob(RunReportJob.class). withIdentity(jobName, Scheduler.DEFAULT_GROUP). usingJobData(jobData). build(); } Trigger trigger; SchedulerTime schedulerTime = job.getTime(); if (existingJobDetail) { trigger = TriggerBuilder.newTrigger(). forJob(jobDetail). usingJobData(jobData). startAt(new Date(System.currentTimeMillis() + 1000)). build(); scheduler.scheduleJob(trigger); if (synchronous) { try { // wait to finish TriggerState state = scheduler.getTriggerState(trigger.getKey()); while (state == TriggerState.NORMAL) { state = scheduler.getTriggerState(trigger.getKey()); } } catch (SchedulerException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } else { if ((schedulerTime != null) && (schedulerTime.getCronEntry() != null)) { trigger = TriggerBuilder.newTrigger(). // ?! (many triggers for the same job) withIdentity(jobDetail.getKey().getName(), jobDetail.getKey().getGroup()). startAt(schedulerTime.getStartActivationDate()). endAt(schedulerTime.getEndActivationDate()). // trigger.setMisfireInstruction(Trigger.INSTRUCTION_SET_TRIGGER_COMPLETE); withSchedule(CronScheduleBuilder.cronSchedule(schedulerTime.getCronEntry()).withMisfireHandlingInstructionDoNothing()). build(); } else { trigger = TriggerBuilder.newTrigger(). // ?! (many triggers for the same job) withIdentity(jobDetail.getKey().getName(), jobDetail.getKey().getGroup()). startAt(new Date(System.currentTimeMillis() + 1000)). // trigger.setMisfireInstruction(Trigger.INSTRUCTION_SET_TRIGGER_COMPLETE); //withSchedule(SimpleScheduleBuilder.simpleSchedule().withMisfireHandlingInstructionIgnoreMisfires()). build(); } scheduler.scheduleJob(jobDetail, trigger); } // FOR DEBUG ONLY ! listJobs(scheduler); } public void removeJob(String jobName) throws Exception { JobKey jobKey = new JobKey(jobName, Scheduler.DEFAULT_GROUP); scheduler.deleteJob(jobKey); // FOR DEBUG ONLY ! listJobs(scheduler); } public static void listJobs(Scheduler scheduler) throws SchedulerException { if (!LOG.isDebugEnabled()) { return; } List<String> jobGroups = scheduler.getJobGroupNames(); if (jobGroups.isEmpty()) { LOG.debug("No jobs !!!"); } for (String jobGroup : jobGroups) { LOG.debug("Group '{}' contains the following jobs:", jobGroup); Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(jobGroup)); for (JobKey jobKey : jobKeys) { LOG.debug("- {}", jobKey.getName()); } } } @Required public void setScheduler(Scheduler scheduler) { this.scheduler = scheduler; } @Required public void setMailSender(JavaMailSender mailSender) { this.mailSender = mailSender; } @Required public void setReportService(ReportService reportService) { this.reportService = reportService; } @Required public void setStorageService(StorageService storageService) { this.storageService = storageService; } @Required public void setSecurityService(SecurityService securityService) { this.securityService = securityService; } @Required public void setDataSourceService(DataSourceService dataSourceService) { this.dataSourceService = dataSourceService; } @Required public void setAuditor(Auditor auditor) { this.auditor = auditor; } }