| <?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>AbstractSchedulerService.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">AbstractSchedulerService.java</span></div><h1>AbstractSchedulerService.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.util.List; |
| import java.util.concurrent.ExecutorService; |
| import java.util.concurrent.Executors; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| |
| import org.apache.commons.lang3.concurrent.BasicThreadFactory; |
| 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.util.TurbineException; |
| |
| /** |
| * Service for a cron like scheduler. |
| * |
| * @author <a href="mailto:mbryson@mont.mindspring.com">Dave Bryson</a> |
| * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a> |
| * @version $Id: TorqueSchedulerService.java 534527 2007-05-02 16:10:59Z tv $ |
| */ |
| <span class="nc" id="L41">public abstract class AbstractSchedulerService extends TurbineBaseService implements ScheduleService</span> |
| { |
| /** Logging */ |
| <span class="nc" id="L44"> protected static final Logger log = LogManager.getLogger(ScheduleService.LOGGER_NAME);</span> |
| |
| /** The queue */ |
| <span class="nc" id="L47"> protected JobQueue<JobEntry> scheduleQueue = null;</span> |
| |
| /** Current status of the scheduler */ |
| <span class="nc" id="L50"> private AtomicBoolean enabled = new AtomicBoolean(false);</span> |
| |
| /** The housekeeping thread. */ |
| protected Thread houseKeepingThread; |
| |
| /** The thread pool used to process jobs. */ |
| protected ExecutorService threadPool; |
| |
| /** |
| * Initializes the SchedulerService. |
| * |
| * @throws InitializationException |
| * Something went wrong in the init stage |
| */ |
| @Override |
| public void init() throws InitializationException |
| { |
| try |
| { |
| <span class="nc" id="L69"> setEnabled(getConfiguration().getBoolean("enabled", true));</span> |
| <span class="nc" id="L70"> scheduleQueue = new JobQueue<>();</span> |
| <span class="nc" id="L71"> threadPool = Executors.newCachedThreadPool(</span> |
| new BasicThreadFactory.Builder() |
| <span class="nc" id="L73"> .namingPattern("Turbine-ScheduledJob-")</span> |
| <span class="nc" id="L74"> .daemon(true)</span> |
| <span class="nc" id="L75"> .build());</span> |
| |
| @SuppressWarnings("unchecked") // Why is this cast necessary? |
| <span class="nc" id="L78"> List<JobEntry> jobs = (List<JobEntry>)loadJobs();</span> |
| <span class="nc" id="L79"> scheduleQueue.batchLoad(jobs);</span> |
| <span class="nc" id="L80"> restart();</span> |
| |
| <span class="nc" id="L82"> setInit(true);</span> |
| } |
| <span class="nc" id="L84"> catch (Exception e)</span> |
| { |
| <span class="nc" id="L86"> throw new InitializationException("Could not initialize the scheduler service", e);</span> |
| <span class="nc" id="L87"> }</span> |
| <span class="nc" id="L88"> }</span> |
| |
| /** |
| * Load all jobs from configuration storage |
| * |
| * @return the list of pre-configured jobs |
| * @throws TurbineException if jobs could not be loaded |
| */ |
| protected abstract List<? extends JobEntry> loadJobs() throws TurbineException; |
| |
| /** |
| * Shutdowns the service. |
| * <p> |
| * This methods interrupts the housekeeping thread. |
| */ |
| @Override |
| public void shutdown() |
| { |
| <span class="nc bnc" id="L106" title="All 2 branches missed."> if (getThread() != null)</span> |
| { |
| <span class="nc" id="L108"> getThread().interrupt();</span> |
| } |
| |
| <span class="nc" id="L111"> threadPool.shutdownNow();</span> |
| <span class="nc" id="L112"> }</span> |
| |
| /** |
| * @see org.apache.turbine.services.schedule.ScheduleService#newJob(int, int, int, int, int, java.lang.String) |
| */ |
| @Override |
| public abstract JobEntry newJob(int sec, int min, int hour, int wd, int day_mo, String task) throws TurbineException; |
| |
| /** |
| * 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 abstract JobEntry getJob(int oid) throws TurbineException; |
| |
| /** |
| * 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 |
| { |
| <span class="nc" id="L143"> updateJob(je);</span> |
| <span class="nc" id="L144"> }</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 abstract void removeJob(JobEntry je) throws TurbineException; |
| |
| /** |
| * Add or update a job. |
| * |
| * @param je |
| * A JobEntry with the job to modify |
| * @throws TurbineException |
| * job could not be updated |
| */ |
| @Override |
| public abstract void updateJob(JobEntry je) throws TurbineException; |
| |
| /** |
| * List jobs in the queue. This is used by the scheduler UI. |
| * |
| * @return A List of jobs. |
| */ |
| @Override |
| public List<JobEntry> listJobs() |
| { |
| <span class="nc" id="L176"> return scheduleQueue.list();</span> |
| } |
| |
| /** |
| * Sets the enabled status of the scheduler |
| * |
| * @param enabled true to enable the scheduler |
| * |
| */ |
| protected void setEnabled(boolean enabled) |
| { |
| <span class="nc" id="L187"> this.enabled.set(enabled);</span> |
| <span class="nc" id="L188"> }</span> |
| |
| /** |
| * Determines if the scheduler service is currently enabled. |
| * |
| * @return Status of the scheduler service. |
| */ |
| @Override |
| public boolean isEnabled() |
| { |
| <span class="nc" id="L198"> return enabled.get();</span> |
| } |
| |
| /** |
| * Starts or restarts the scheduler if not already running. |
| */ |
| @Override |
| public synchronized void startScheduler() |
| { |
| <span class="nc" id="L207"> setEnabled(true);</span> |
| <span class="nc" id="L208"> restart();</span> |
| <span class="nc" id="L209"> }</span> |
| |
| /** |
| * Stops the scheduler if it is currently running. |
| */ |
| @Override |
| public synchronized void stopScheduler() |
| { |
| <span class="nc" id="L217"> log.info("Stopping job scheduler");</span> |
| <span class="nc" id="L218"> Thread thread = getThread();</span> |
| <span class="nc bnc" id="L219" title="All 2 branches missed."> if (thread != null)</span> |
| { |
| <span class="nc" id="L221"> thread.interrupt();</span> |
| } |
| <span class="nc" id="L223"> setEnabled(false);</span> |
| <span class="nc" id="L224"> }</span> |
| |
| /** |
| * Return the thread being used to process commands, or null if there is no |
| * such thread. You can use this to invoke any special methods on the |
| * thread, for example, to interrupt it. |
| * |
| * @return A Thread. |
| */ |
| public synchronized Thread getThread() |
| { |
| <span class="nc" id="L235"> return houseKeepingThread;</span> |
| } |
| |
| /** |
| * Set thread to null to indicate termination. |
| */ |
| protected synchronized void clearThread() |
| { |
| <span class="nc" id="L243"> houseKeepingThread = null;</span> |
| <span class="nc" id="L244"> }</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="L254" title="All 2 branches missed."> if (enabled.get())</span> |
| { |
| <span class="nc" id="L256"> log.info("Starting job scheduler");</span> |
| <span class="nc bnc" id="L257" title="All 2 branches missed."> if (houseKeepingThread == null)</span> |
| { |
| // Create the the housekeeping thread of the scheduler. It will |
| // wait for the time when the next task needs to be started, |
| // and then launch a worker thread to execute the task. |
| <span class="nc" id="L262"> houseKeepingThread = new Thread(this::houseKeeping, ScheduleService.SERVICE_NAME);</span> |
| // Indicate that this is a system thread. JVM will quit only |
| // when there are no more enabled user threads. Settings threads |
| // spawned internally by Turbine as daemons allows commandline |
| // applications using Turbine to terminate in an orderly manner. |
| <span class="nc" id="L267"> houseKeepingThread.setDaemon(true);</span> |
| <span class="nc" id="L268"> houseKeepingThread.start();</span> |
| } |
| else |
| { |
| <span class="nc" id="L272"> notify();</span> |
| } |
| } |
| <span class="nc" id="L275"> }</span> |
| |
| /** |
| * Return the next Job to execute, or null if thread is interrupted. |
| * |
| * @return A JobEntry. |
| * @throws TurbineException |
| * a generic exception. |
| */ |
| protected synchronized JobEntry nextJob() throws TurbineException |
| { |
| try |
| { |
| <span class="nc bnc" id="L288" title="All 2 branches missed."> while (!Thread.interrupted())</span> |
| { |
| // Grab the next job off the queue. |
| //JobEntry je = scheduleQueue.getNext(); |
| <span class="nc" id="L292"> JobEntry je = scheduleQueue.getFirst();</span> |
| |
| <span class="nc bnc" id="L294" title="All 2 branches missed."> if (je == null)</span> |
| { |
| // Queue must be empty. Wait on it. |
| <span class="nc" id="L297"> wait();</span> |
| } |
| else |
| { |
| <span class="nc" id="L301"> long now = System.currentTimeMillis();</span> |
| <span class="nc" id="L302"> long when = je.getNextRuntime();</span> |
| |
| <span class="nc bnc" id="L304" title="All 2 branches missed."> if (when > now)</span> |
| { |
| // Wait till next runtime. |
| <span class="nc" id="L307"> wait(when - now);</span> |
| } |
| else |
| { |
| // Update the next runtime for the job. |
| <span class="nc" id="L312"> scheduleQueue.updateQueue(je);</span> |
| // Return the job to run it. |
| <span class="nc" id="L314"> return je;</span> |
| } |
| } |
| <span class="nc" id="L317"> }</span> |
| } |
| <span class="nc" id="L319"> catch (InterruptedException ex)</span> |
| { |
| // ignore |
| <span class="nc" id="L322"> }</span> |
| |
| // On interrupt. |
| <span class="nc" id="L325"> return null;</span> |
| } |
| |
| /** |
| * Create the the housekeeping thread of the scheduler. It will |
| * wait for the time when the next task needs to be started, |
| * and then launch a worker thread to execute the task. |
| */ |
| private void houseKeeping() |
| { |
| <span class="nc" id="L335"> String taskName = null;</span> |
| try |
| { |
| <span class="nc bnc" id="L338" title="All 2 branches missed."> while (enabled.get())</span> |
| { |
| <span class="nc" id="L340"> JobEntry je = nextJob();</span> |
| <span class="nc bnc" id="L341" title="All 2 branches missed."> if (je != null)</span> |
| { |
| <span class="nc" id="L343"> taskName = je.getTask();</span> |
| |
| // Get a thread to run the job. |
| <span class="nc" id="L346"> threadPool.execute(new WorkerThread(je));</span> |
| } |
| else |
| { |
| break; |
| } |
| <span class="nc" id="L352"> }</span> |
| } |
| <span class="nc" id="L354"> catch (Exception e)</span> |
| { |
| <span class="nc" id="L356"> log.error("Error running a Scheduled Job: {}", taskName, e);</span> |
| <span class="nc" id="L357"> setEnabled(false);</span> |
| } |
| finally |
| { |
| <span class="nc" id="L361"> clearThread();</span> |
| } |
| <span class="nc" id="L363"> }</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> |