| <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang=""><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>QuartzSchedulerService.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Apache Turbine</a> > <a href="index.source.html" class="el_package">org.apache.turbine.services.schedule</a> > <span class="el_source">QuartzSchedulerService.java</span></div><h1>QuartzSchedulerService.java</h1><pre class="source lang-java linenums">package org.apache.turbine.services.schedule; |
| |
| /* |
| * 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. |
| */ |
| |
| import java.text.ParseException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.apache.fulcrum.quartz.QuartzScheduler; |
| import org.apache.logging.log4j.LogManager; |
| import org.apache.logging.log4j.Logger; |
| import org.apache.turbine.services.InitializationException; |
| import org.apache.turbine.services.TurbineBaseService; |
| import org.apache.turbine.services.TurbineServices; |
| import org.apache.turbine.util.TurbineException; |
| import org.quartz.CronScheduleBuilder; |
| import org.quartz.JobBuilder; |
| 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.impl.matchers.GroupMatcher; |
| |
| /** |
| * Service for a quartz scheduler. |
| * |
| * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a> |
| */ |
| <span class="nc" id="L49">public class QuartzSchedulerService</span> |
| extends TurbineBaseService |
| implements ScheduleService |
| { |
| /** Logging */ |
| <span class="nc" id="L54"> protected static final Logger log = LogManager.getLogger(ScheduleService.LOGGER_NAME);</span> |
| |
| /** Current status of the scheduler */ |
| <span class="nc" id="L57"> protected boolean enabled = false;</span> |
| |
| /** The Quartz scheduler instance */ |
| private Scheduler scheduler; |
| |
| /** |
| * Initializes the SchedulerService. Retrieves the Quartz {@link #scheduler} from the Fulcrum {@link QuartzScheduler} service. |
| * |
| * @throws InitializationException Something went wrong in the init |
| * stage |
| */ |
| @Override |
| public void init() |
| throws InitializationException |
| { |
| <span class="nc" id="L72"> setEnabled(getConfiguration().getBoolean("enabled", true));</span> |
| <span class="nc" id="L73"> QuartzScheduler qs = (QuartzScheduler) TurbineServices.getInstance()</span> |
| <span class="nc" id="L74"> .getService(QuartzScheduler.class.getName());</span> |
| <span class="nc" id="L75"> this.scheduler = qs.getScheduler();</span> |
| |
| <span class="nc" id="L77"> restart();</span> |
| <span class="nc" id="L78"> setInit(true);</span> |
| <span class="nc" id="L79"> }</span> |
| |
| /** |
| * Shutdowns the service. |
| * |
| * This methods interrupts the housekeeping thread. |
| */ |
| @Override |
| public void shutdown() |
| { |
| try |
| { |
| <span class="nc" id="L91"> this.scheduler.shutdown();</span> |
| } |
| <span class="nc" id="L93"> catch (SchedulerException e)</span> |
| { |
| <span class="nc" id="L95"> log.error("Could not shut down the scheduler service", e);</span> |
| <span class="nc" id="L96"> }</span> |
| <span class="nc" id="L97"> }</span> |
| |
| /** |
| * @see org.apache.turbine.services.schedule.ScheduleService#newJob(int, int, int, int, int, java.lang.String) |
| */ |
| @Override |
| public JobEntry newJob(int sec, int min, int hour, int wd, int day_mo, String task) throws TurbineException |
| { |
| try |
| { |
| <span class="nc" id="L107"> JobDetail jd = JobBuilder.newJob(JobEntryQuartz.class)</span> |
| <span class="nc" id="L108"> .withIdentity(task, JobEntryQuartz.DEFAULT_JOB_GROUP_NAME)</span> |
| <span class="nc" id="L109"> .build();</span> |
| |
| <span class="nc" id="L111"> CronScheduleBuilder csb = createCronExpression(sec, min, hour, wd, day_mo);</span> |
| |
| <span class="nc" id="L113"> Trigger t = TriggerBuilder.newTrigger()</span> |
| <span class="nc" id="L114"> .withIdentity(task, JobEntryQuartz.DEFAULT_JOB_GROUP_NAME)</span> |
| <span class="nc" id="L115"> .withSchedule(csb)</span> |
| <span class="nc" id="L116"> .forJob(jd)</span> |
| <span class="nc" id="L117"> .build();</span> |
| |
| <span class="nc" id="L119"> JobEntryQuartz jeq = new JobEntryQuartz(t, jd);</span> |
| |
| <span class="nc" id="L121"> return jeq;</span> |
| } |
| <span class="nc" id="L123"> catch (ParseException e)</span> |
| { |
| <span class="nc" id="L125"> throw new TurbineException("Could not create scheduled job " + task, e);</span> |
| } |
| } |
| |
| /** |
| * Create a Cron expression from separate elements |
| * |
| * @param sec Value for entry "seconds". |
| * @param min Value for entry "minutes". |
| * @param hour Value for entry "hours". |
| * @param wd Value for entry "week days". |
| * @param day_mo Value for entry "month days". |
| * @return a CronScheduleBuilder |
| * @throws ParseException if the expression is invalid |
| */ |
| private CronScheduleBuilder createCronExpression(int sec, int min, int hour, int wd, int day_mo) throws ParseException |
| { |
| <span class="nc" id="L142"> StringBuilder sb = new StringBuilder();</span> |
| <span class="nc bnc" id="L143" title="All 2 branches missed."> sb.append(sec == -1 ? "*" : String.valueOf(sec)).append(' ');</span> |
| <span class="nc bnc" id="L144" title="All 2 branches missed."> sb.append(min == -1 ? "*" : String.valueOf(min)).append(' ');</span> |
| <span class="nc bnc" id="L145" title="All 2 branches missed."> sb.append(hour == -1 ? "*" : String.valueOf(hour)).append(' ');</span> |
| <span class="nc bnc" id="L146" title="All 2 branches missed."> if (day_mo == -1)</span> |
| { |
| <span class="nc bnc" id="L148" title="All 2 branches missed."> sb.append(wd == -1 ? "*" : "?").append(' ');</span> |
| } |
| else |
| { |
| <span class="nc" id="L152"> sb.append(day_mo).append(' ');</span> |
| } |
| <span class="nc" id="L154"> sb.append("* "); // Month not supported</span> |
| <span class="nc bnc" id="L155" title="All 2 branches missed."> if (day_mo == -1)</span> |
| { |
| <span class="nc bnc" id="L157" title="All 2 branches missed."> sb.append(wd == -1 ? "?" : String.valueOf(wd));</span> |
| } |
| else |
| { |
| <span class="nc" id="L161"> sb.append("*");</span> |
| } |
| |
| <span class="nc" id="L164"> return CronScheduleBuilder.cronSchedule(sb.toString());</span> |
| } |
| |
| /** |
| * Get a specific Job from Storage. |
| * |
| * @param oid The int id for the job. |
| * @return A JobEntry. |
| * @throws TurbineException job could not be retrieved. |
| */ |
| @Override |
| public JobEntry getJob(int oid) |
| throws TurbineException |
| { |
| <span class="nc bnc" id="L178" title="All 2 branches missed."> for (JobEntry je : listJobs())</span> |
| { |
| <span class="nc bnc" id="L180" title="All 2 branches missed."> if (je.getJobId() == oid)</span> |
| { |
| <span class="nc" id="L182"> return je;</span> |
| } |
| <span class="nc" id="L184"> }</span> |
| |
| <span class="nc" id="L186"> throw new TurbineException("Could not retrieve scheduled job with id " + oid);</span> |
| } |
| |
| /** |
| * Add a new job to the queue. |
| * |
| * @param je A JobEntry with the job to add. |
| * @throws TurbineException job could not be added |
| */ |
| @Override |
| public void addJob(JobEntry je) |
| throws TurbineException |
| { |
| try |
| { |
| // Update the scheduler. |
| <span class="nc" id="L202"> JobEntryQuartz jq = downCast(je);</span> |
| <span class="nc" id="L203"> this.scheduler.scheduleJob(jq.getJobDetail(), jq.getJobTrigger());</span> |
| } |
| <span class="nc" id="L205"> catch (SchedulerException e)</span> |
| { |
| <span class="nc" id="L207"> throw new TurbineException("Problem adding Scheduled Job: " + je.getTask(), e);</span> |
| <span class="nc" id="L208"> }</span> |
| <span class="nc" id="L209"> }</span> |
| |
| /** |
| * Remove a job from the queue. |
| * |
| * @param je A JobEntry with the job to remove. |
| * @throws TurbineException job could not be removed |
| */ |
| @Override |
| public void removeJob(JobEntry je) |
| throws TurbineException |
| { |
| try |
| { |
| <span class="nc" id="L223"> JobEntryQuartz jq = downCast(je);</span> |
| <span class="nc" id="L224"> this.scheduler.deleteJob(jq.getJobTrigger().getJobKey());</span> |
| |
| } |
| <span class="nc" id="L227"> catch (SchedulerException e)</span> |
| { |
| <span class="nc" id="L229"> throw new TurbineException("Problem removing Scheduled Job: " + je.getTask(), e);</span> |
| <span class="nc" id="L230"> }</span> |
| <span class="nc" id="L231"> }</span> |
| |
| /** |
| * Add or update a job. |
| * |
| * @param je A JobEntry with the job to modify |
| * @throws TurbineException job could not be updated |
| */ |
| @Override |
| public void updateJob(JobEntry je) |
| throws TurbineException |
| { |
| try |
| { |
| // Update the scheduler. |
| <span class="nc" id="L246"> JobEntryQuartz jq = downCast(je);</span> |
| <span class="nc" id="L247"> this.scheduler.rescheduleJob(jq.getJobTrigger().getKey(), jq.getJobTrigger());</span> |
| } |
| <span class="nc" id="L249"> catch (SchedulerException e)</span> |
| { |
| <span class="nc" id="L251"> throw new TurbineException("Problem updating Scheduled Job: " + je.getTask(), e);</span> |
| <span class="nc" id="L252"> }</span> |
| <span class="nc" id="L253"> }</span> |
| |
| /** |
| * List jobs in the queue. This is used by the scheduler UI. |
| * |
| * @return A List of jobs. |
| */ |
| @Override |
| public List<? extends JobEntry> listJobs() |
| { |
| <span class="nc" id="L263"> List<JobEntryQuartz> jobs = new ArrayList<>();</span> |
| |
| try |
| { |
| <span class="nc" id="L267"> GroupMatcher<JobKey> groupMatcher = GroupMatcher.groupEquals(JobEntryQuartz.DEFAULT_JOB_GROUP_NAME);</span> |
| <span class="nc" id="L268"> Set<JobKey> jobKeys = scheduler.getJobKeys(groupMatcher);</span> |
| <span class="nc bnc" id="L269" title="All 2 branches missed."> for (JobKey jk : jobKeys)</span> |
| { |
| <span class="nc" id="L271"> List<? extends Trigger> triggers = this.scheduler.getTriggersOfJob(jk);</span> |
| |
| <span class="nc bnc" id="L273" title="All 4 branches missed."> if (triggers == null || triggers.isEmpty())</span> |
| { |
| <span class="nc" id="L275"> continue; // skip</span> |
| } |
| <span class="nc" id="L277"> JobDetail jd = this.scheduler.getJobDetail(jk);</span> |
| <span class="nc" id="L278"> JobEntryQuartz job = new JobEntryQuartz(triggers.get(0), jd);</span> |
| <span class="nc" id="L279"> job.setJobId(jk.hashCode());</span> |
| <span class="nc" id="L280"> jobs.add(job);</span> |
| <span class="nc" id="L281"> }</span> |
| } |
| <span class="nc" id="L283"> catch (SchedulerException e)</span> |
| { |
| <span class="nc" id="L285"> log.error("Problem listing Scheduled Jobs", e);</span> |
| <span class="nc" id="L286"> }</span> |
| |
| <span class="nc" id="L288"> return jobs;</span> |
| } |
| |
| |
| /** |
| * Sets the enabled status of the scheduler |
| * |
| * @param enabled true if enabled |
| * |
| */ |
| protected void setEnabled(boolean enabled) |
| { |
| <span class="nc" id="L300"> this.enabled = enabled;</span> |
| <span class="nc" id="L301"> }</span> |
| |
| /** |
| * Determines if the scheduler service is currently enabled. |
| * |
| * @return Status of the scheduler service. |
| */ |
| @Override |
| public boolean isEnabled() |
| { |
| <span class="nc" id="L311"> return enabled;</span> |
| } |
| |
| /** |
| * Starts or restarts the scheduler if not already running. |
| */ |
| @Override |
| public synchronized void startScheduler() |
| { |
| <span class="nc" id="L320"> setEnabled(true);</span> |
| <span class="nc" id="L321"> restart();</span> |
| <span class="nc" id="L322"> }</span> |
| |
| /** |
| * Stops the scheduler if it is currently running. |
| */ |
| @Override |
| public synchronized void stopScheduler() |
| { |
| <span class="nc" id="L330"> log.info("Stopping job scheduler");</span> |
| try |
| { |
| <span class="nc" id="L333"> this.scheduler.standby();</span> |
| <span class="nc" id="L334"> enabled = false;</span> |
| } |
| <span class="nc" id="L336"> catch (SchedulerException e)</span> |
| { |
| <span class="nc" id="L338"> log.error("Could not stop scheduler", e);</span> |
| <span class="nc" id="L339"> }</span> |
| <span class="nc" id="L340"> }</span> |
| |
| /** |
| * Start (or restart) a thread to process commands, or wake up an |
| * existing thread if one is already running. This method can be |
| * invoked if the background thread crashed due to an |
| * unrecoverable exception in an executed command. |
| */ |
| public synchronized void restart() |
| { |
| <span class="nc bnc" id="L350" title="All 2 branches missed."> if (enabled)</span> |
| { |
| <span class="nc" id="L352"> log.info("Starting job scheduler");</span> |
| try |
| { |
| <span class="nc bnc" id="L355" title="All 2 branches missed."> if (!this.scheduler.isStarted())</span> |
| { |
| <span class="nc" id="L357"> this.scheduler.start();</span> |
| } |
| else |
| { |
| <span class="nc" id="L361"> notify();</span> |
| } |
| } |
| <span class="nc" id="L364"> catch (SchedulerException e)</span> |
| { |
| <span class="nc" id="L366"> log.error("Could not start scheduler", e);</span> |
| <span class="nc" id="L367"> }</span> |
| } |
| <span class="nc" id="L369"> }</span> |
| |
| /** |
| * @param je a generic job entry |
| * @throws TurbineException - If the cast fails. |
| * |
| * @return A downcasted JobEntry type |
| */ |
| private JobEntryQuartz downCast(JobEntry je) throws TurbineException |
| { |
| <span class="nc bnc" id="L379" title="All 2 branches missed."> if (je instanceof JobEntryQuartz)</span> |
| { |
| <span class="nc" id="L381"> return (JobEntryQuartz)je;</span> |
| } |
| else |
| { |
| <span class="nc" id="L385"> throw new TurbineException("Invalid job type for this scheduler " + je.getClass());</span> |
| } |
| } |
| |
| /** |
| * Exposing the Quartz scheduler to handle jobs/triggers in more detail. |
| * |
| * @return the {@link Scheduler} of this service. |
| */ |
| public Scheduler getScheduler() |
| { |
| <span class="nc" id="L396"> return scheduler;</span> |
| } |
| |
| /** |
| * Builds a {@link JobEntryQuartz} from Quartz trigger/job. |
| * |
| * The developer should be aware to set identity/context properly, i.e. to |
| * {@link JobEntryQuartz#DEFAULT_JOB_GROUP_NAME}, if adding triggers/jobs. |
| * |
| * @param trigger a Quartz {@link Trigger}. |
| * @param jd a Quartz {@link JobDetail} (built from a {@link org.quartz.Job} with {@link JobBuilder}). |
| * @return A JobEntryQuartz. |
| */ |
| public JobEntryQuartz buildJobEntry(Trigger trigger, JobDetail jd) { |
| <span class="nc" id="L410"> JobEntryQuartz job = new JobEntryQuartz(trigger, jd);</span> |
| <span class="nc" id="L411"> return job;</span> |
| } |
| } |
| |
| </pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html> |