All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.quartz.core.QuartzScheduler Maven / Gradle / Ivy

There is a newer version: 2.5.0
Show newest version

/* 
 * Copyright 2001-2009 Terracotta, Inc. 
 * 
 * Licensed 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 org.quartz.core;

import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.Set;
import java.util.Timer;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;

import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.quartz.Calendar;
import org.quartz.InterruptableJob;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.JobListener;
import org.quartz.JobPersistenceException;
import org.quartz.ListenerManager;
import org.quartz.Matcher;
import org.quartz.ObjectAlreadyExistsException;
import org.quartz.Scheduler;
import org.quartz.SchedulerContext;
import org.quartz.SchedulerException;
import org.quartz.SchedulerListener;
import org.quartz.SchedulerMetaData;
import static org.quartz.SimpleScheduleBuilder.*;
import org.quartz.Trigger;
import static org.quartz.TriggerBuilder.*;
import org.quartz.TriggerKey;
import org.quartz.TriggerListener;
import org.quartz.UnableToInterruptJobException;
import org.quartz.Trigger.CompletedExecutionInstruction;
import org.quartz.Trigger.TriggerState;
import org.quartz.core.jmx.QuartzSchedulerMBean;
import org.quartz.impl.SchedulerRepository;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.listeners.SchedulerListenerSupport;
import org.quartz.simpl.PropertySettingJobFactory;
import org.quartz.spi.JobFactory;
import org.quartz.spi.OperableTrigger;
import org.quartz.spi.SchedulerPlugin;
import org.quartz.spi.SchedulerSignaler;
import org.quartz.spi.ThreadExecutor;
import org.quartz.utils.UpdateChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 

* This is the heart of Quartz, an indirect implementation of the {@link org.quartz.Scheduler} * interface, containing methods to schedule {@link org.quartz.Job}s, * register {@link org.quartz.JobListener} instances, etc. *

* * @see org.quartz.Scheduler * @see org.quartz.core.QuartzSchedulerThread * @see org.quartz.spi.JobStore * @see org.quartz.spi.ThreadPool * * @author James House */ public class QuartzScheduler implements RemotableQuartzScheduler { /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Constants. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ private static String VERSION_MAJOR = "UNKNOWN"; private static String VERSION_MINOR = "UNKNOWN"; private static String VERSION_ITERATION = "UNKNOWN"; static { Properties props = new Properties(); InputStream is = null; try { is = QuartzScheduler.class.getResourceAsStream("quartz-build.properties"); if(is != null) { props.load(is); String version = props.getProperty("version"); if (version != null) { String[] versionComponents = version.split("\\."); VERSION_MAJOR = versionComponents[0]; VERSION_MINOR = versionComponents[1]; if(versionComponents.length > 2) VERSION_ITERATION = versionComponents[2]; else VERSION_ITERATION = "0"; } else { (LoggerFactory.getLogger(QuartzScheduler.class)).error( "Can't parse Quartz version from quartz-build.properties"); } } } catch (Exception e) { (LoggerFactory.getLogger(QuartzScheduler.class)).error( "Error loading version info from quartz-build.properties.", e); } finally { if(is != null) { try { is.close(); } catch(Exception ignore) {} } } } /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Data members. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ private QuartzSchedulerResources resources; private QuartzSchedulerThread schedThread; private ThreadGroup threadGroup; private SchedulerContext context = new SchedulerContext(); private ListenerManager listenerManager = new ListenerManagerImpl(); private HashMap internalJobListeners = new HashMap(10); private HashMap internalTriggerListeners = new HashMap(10); private ArrayList internalSchedulerListeners = new ArrayList(10); private JobFactory jobFactory = new PropertySettingJobFactory(); ExecutingJobsManager jobMgr = null; ErrorLogger errLogger = null; private SchedulerSignaler signaler; private Random random = new Random(); private ArrayList holdToPreventGC = new ArrayList(5); private boolean signalOnSchedulingChange = true; private volatile boolean closed = false; private volatile boolean shuttingDown = false; private boolean boundRemotely = false; private QuartzSchedulerMBean jmxBean = null; private Date initialStart = null; /** Update timer that must be cancelled upon shutdown. */ private final Timer updateTimer; private final Logger log = LoggerFactory.getLogger(getClass()); private long dbRetryInterval; // private static final Map MGMT_SVR_BY_BIND = new // HashMap(); // private String registeredManagementServerBind; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Constructors. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /** *

* Create a QuartzScheduler with the given configuration * properties. *

* * @see QuartzSchedulerResources */ public QuartzScheduler(QuartzSchedulerResources resources, long idleWaitTime, long dbRetryInterval) throws SchedulerException { this.resources = resources; if (resources.getJobStore() instanceof JobListener) { addInternalJobListener((JobListener)resources.getJobStore()); } this.schedThread = new QuartzSchedulerThread(this, resources); ThreadExecutor schedThreadExecutor = resources.getThreadExecutor(); schedThreadExecutor.execute(this.schedThread); if (idleWaitTime > 0) { this.schedThread.setIdleWaitTime(idleWaitTime); } if (dbRetryInterval > 0) { this.schedThread.setDbFailureRetryInterval(dbRetryInterval); } jobMgr = new ExecutingJobsManager(); addInternalJobListener(jobMgr); errLogger = new ErrorLogger(); addInternalSchedulerListener(errLogger); signaler = new SchedulerSignalerImpl(this, this.schedThread); if(shouldRunUpdateCheck()) updateTimer = scheduleUpdateCheck(); else updateTimer = null; this.dbRetryInterval = dbRetryInterval; getLog().info("Quartz Scheduler v." + getVersion() + " created."); } public long getDbRetryInterval() { return dbRetryInterval; } public void initialize() throws SchedulerException { try { bind(); } catch (Exception re) { throw new SchedulerException( "Unable to bind scheduler to RMI Registry.", re); } if (resources.getJMXExport()) { try { registerJMX(); } catch (Exception e) { throw new SchedulerException( "Unable to register scheduler with MBeanServer.", e); } } // ManagementRESTServiceConfiguration managementRESTServiceConfiguration // = resources.getManagementRESTServiceConfiguration(); // // if (managementRESTServiceConfiguration != null && // managementRESTServiceConfiguration.isEnabled()) { // try { // /** // * ManagementServer will only be instantiated and started if one // * isn't already running on the configured port for this class // * loader space. // */ // synchronized (QuartzScheduler.class) { // if // (!MGMT_SVR_BY_BIND.containsKey(managementRESTServiceConfiguration.getBind())) // { // Class managementServerImplClass = // Class.forName("org.quartz.management.ManagementServerImpl"); // Class managementRESTServiceConfigurationClass[] = new Class[] { // managementRESTServiceConfiguration.getClass() }; // Constructor managementRESTServiceConfigurationConstructor = // managementServerImplClass // .getConstructor(managementRESTServiceConfigurationClass); // Object arglist[] = new Object[] { managementRESTServiceConfiguration // }; // ManagementServer embeddedRESTServer = ((ManagementServer) // managementRESTServiceConfigurationConstructor.newInstance(arglist)); // embeddedRESTServer.start(); // MGMT_SVR_BY_BIND.put(managementRESTServiceConfiguration.getBind(), // embeddedRESTServer); // } // registeredManagementServerBind = // managementRESTServiceConfiguration.getBind(); // ManagementServer embeddedRESTServer = // MGMT_SVR_BY_BIND.get(registeredManagementServerBind); // embeddedRESTServer.register(this); // } // } catch (Exception e) { // throw new // SchedulerException("Unable to start the scheduler management REST service", // e); // } // } getLog().info("Scheduler meta-data: " + (new SchedulerMetaData(getSchedulerName(), getSchedulerInstanceId(), getClass(), boundRemotely, runningSince() != null, isInStandbyMode(), isShutdown(), runningSince(), numJobsExecuted(), getJobStoreClass(), supportsPersistence(), isClustered(), getThreadPoolClass(), getThreadPoolSize(), getVersion())).toString()); } /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Interface. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ public String getVersion() { return getVersionMajor() + "." + getVersionMinor() + "." + getVersionIteration(); } public static String getVersionMajor() { return VERSION_MAJOR; } private boolean shouldRunUpdateCheck() { if(resources.isRunUpdateCheck() && !Boolean.getBoolean(StdSchedulerFactory.PROP_SCHED_SKIP_UPDATE_CHECK) && !Boolean.getBoolean("org.terracotta.quartz.skipUpdateCheck")) { return true; } return false; } public static String getVersionMinor() { return VERSION_MINOR; } public static String getVersionIteration() { return VERSION_ITERATION; } public SchedulerSignaler getSchedulerSignaler() { return signaler; } public Logger getLog() { return log; } /** * Update checker scheduler - fires every week */ private Timer scheduleUpdateCheck() { Timer rval = new Timer(true); rval.scheduleAtFixedRate(new UpdateChecker(), 1000, 7 * 24 * 60 * 60 * 1000L); return rval; } /** * Register the scheduler in the local MBeanServer. */ private void registerJMX() throws Exception { String jmxObjectName = resources.getJMXObjectName(); MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); jmxBean = new QuartzSchedulerMBeanImpl(this); mbs.registerMBean(jmxBean, new ObjectName(jmxObjectName)); } /** * Unregister the scheduler from the local MBeanServer. */ private void unregisterJMX() throws Exception { String jmxObjectName = resources.getJMXObjectName(); MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); mbs.unregisterMBean(new ObjectName(jmxObjectName)); jmxBean.setSampledStatisticsEnabled(false); getLog().info("Scheduler unregistered from name '" + jmxObjectName + "' in the local MBeanServer."); } /** *

* Bind the scheduler to an RMI registry. *

*/ private void bind() throws RemoteException { String host = resources.getRMIRegistryHost(); // don't export if we're not configured to do so... if (host == null || host.length() == 0) { return; } RemotableQuartzScheduler exportable = null; if(resources.getRMIServerPort() > 0) { exportable = (RemotableQuartzScheduler) UnicastRemoteObject .exportObject(this, resources.getRMIServerPort()); } else { exportable = (RemotableQuartzScheduler) UnicastRemoteObject .exportObject(this); } Registry registry = null; if (resources.getRMICreateRegistryStrategy().equals( QuartzSchedulerResources.CREATE_REGISTRY_AS_NEEDED)) { try { // First try to get an existing one, instead of creating it, // since if // we're in a web-app being 'hot' re-depoloyed, then the JVM // still // has the registry that we created above the first time... registry = LocateRegistry.getRegistry(resources .getRMIRegistryPort()); registry.list(); } catch (Exception e) { registry = LocateRegistry.createRegistry(resources .getRMIRegistryPort()); } } else if (resources.getRMICreateRegistryStrategy().equals( QuartzSchedulerResources.CREATE_REGISTRY_ALWAYS)) { try { registry = LocateRegistry.createRegistry(resources .getRMIRegistryPort()); } catch (Exception e) { // Fall back to an existing one, instead of creating it, since // if // we're in a web-app being 'hot' re-depoloyed, then the JVM // still // has the registry that we created above the first time... registry = LocateRegistry.getRegistry(resources .getRMIRegistryPort()); } } else { registry = LocateRegistry.getRegistry(resources .getRMIRegistryHost(), resources.getRMIRegistryPort()); } String bindName = resources.getRMIBindName(); registry.rebind(bindName, exportable); boundRemotely = true; getLog().info("Scheduler bound to RMI registry under name '" + bindName + "'"); } /** *

* Un-bind the scheduler from an RMI registry. *

*/ private void unBind() throws RemoteException { String host = resources.getRMIRegistryHost(); // don't un-export if we're not configured to do so... if (host == null || host.length() == 0) { return; } Registry registry = LocateRegistry.getRegistry(resources .getRMIRegistryHost(), resources.getRMIRegistryPort()); String bindName = resources.getRMIBindName(); try { registry.unbind(bindName); UnicastRemoteObject.unexportObject(this, true); } catch (java.rmi.NotBoundException nbe) { } getLog().info("Scheduler un-bound from name '" + bindName + "' in RMI registry"); } /** *

* Returns the name of the QuartzScheduler. *

*/ public String getSchedulerName() { return resources.getName(); } /** *

* Returns the instance Id of the QuartzScheduler. *

*/ public String getSchedulerInstanceId() { return resources.getInstanceId(); } /** *

* Returns the name of the thread group for Quartz's main threads. *

*/ public ThreadGroup getSchedulerThreadGroup() { if (threadGroup == null) { threadGroup = new ThreadGroup("QuartzScheduler:" + getSchedulerName()); if (resources.getMakeSchedulerThreadDaemon()) { threadGroup.setDaemon(true); } } return threadGroup; } public void addNoGCObject(Object obj) { holdToPreventGC.add(obj); } public boolean removeNoGCObject(Object obj) { return holdToPreventGC.remove(obj); } /** *

* Returns the SchedulerContext of the Scheduler. *

*/ public SchedulerContext getSchedulerContext() throws SchedulerException { return context; } public boolean isSignalOnSchedulingChange() { return signalOnSchedulingChange; } public void setSignalOnSchedulingChange(boolean signalOnSchedulingChange) { this.signalOnSchedulingChange = signalOnSchedulingChange; } /////////////////////////////////////////////////////////////////////////// /// /// Scheduler State Management Methods /// /////////////////////////////////////////////////////////////////////////// /** *

* Starts the QuartzScheduler's threads that fire {@link org.quartz.Trigger}s. *

* *

* All {@link org.quartz.Trigger}s that have misfired will * be passed to the appropriate TriggerListener(s). *

*/ public void start() throws SchedulerException { if (shuttingDown|| closed) { throw new SchedulerException( "The Scheduler cannot be restarted after shutdown() has been called."); } // QTZ-212 : calling new schedulerStarting() method on the listeners // right after entering start() notifySchedulerListenersStarting(); if (initialStart == null) { initialStart = new Date(); this.resources.getJobStore().schedulerStarted(); startPlugins(); } else { resources.getJobStore().schedulerResumed(); } schedThread.togglePause(false); getLog().info( "Scheduler " + resources.getUniqueIdentifier() + " started."); notifySchedulerListenersStarted(); } public void startDelayed(final int seconds) throws SchedulerException { if (shuttingDown || closed) { throw new SchedulerException( "The Scheduler cannot be restarted after shutdown() has been called."); } Thread t = new Thread(new Runnable() { public void run() { try { Thread.sleep(seconds * 1000L); } catch(InterruptedException ignore) {} try { start(); } catch(SchedulerException se) { getLog().error("Unable to start secheduler after startup delay.", se); } } }); t.start(); } /** *

* Temporarily halts the QuartzScheduler's firing of {@link org.quartz.Trigger}s. *

* *

* The scheduler is not destroyed, and can be re-started at any time. *

*/ public void standby() { resources.getJobStore().schedulerPaused(); schedThread.togglePause(true); getLog().info( "Scheduler " + resources.getUniqueIdentifier() + " paused."); notifySchedulerListenersInStandbyMode(); } /** *

* Reports whether the Scheduler is paused. *

*/ public boolean isInStandbyMode() { return schedThread.isPaused(); } public Date runningSince() { if(initialStart == null) return null; return new Date(initialStart.getTime()); } public int numJobsExecuted() { return jobMgr.getNumJobsFired(); } public Class getJobStoreClass() { return resources.getJobStore().getClass(); } public boolean supportsPersistence() { return resources.getJobStore().supportsPersistence(); } public boolean isClustered() { return resources.getJobStore().isClustered(); } public Class getThreadPoolClass() { return resources.getThreadPool().getClass(); } public int getThreadPoolSize() { return resources.getThreadPool().getPoolSize(); } /** *

* Halts the QuartzScheduler's firing of {@link org.quartz.Trigger}s, * and cleans up all resources associated with the QuartzScheduler. * Equivalent to shutdown(false). *

* *

* The scheduler cannot be re-started. *

*/ public void shutdown() { shutdown(false); } /** *

* Halts the QuartzScheduler's firing of {@link org.quartz.Trigger}s, * and cleans up all resources associated with the QuartzScheduler. *

* *

* The scheduler cannot be re-started. *

* * @param waitForJobsToComplete * if true the scheduler will not allow this method * to return until all currently executing jobs have completed. */ public void shutdown(boolean waitForJobsToComplete) { if(shuttingDown || closed) { return; } shuttingDown = true; getLog().info( "Scheduler " + resources.getUniqueIdentifier() + " shutting down."); // boolean removeMgmtSvr = false; // if (registeredManagementServerBind != null) { // ManagementServer standaloneRestServer = // MGMT_SVR_BY_BIND.get(registeredManagementServerBind); // // try { // standaloneRestServer.unregister(this); // // if (!standaloneRestServer.hasRegistered()) { // removeMgmtSvr = true; // standaloneRestServer.stop(); // } // } catch (Exception e) { // getLog().warn("Failed to shutdown the ManagementRESTService", e); // } finally { // if (removeMgmtSvr) { // MGMT_SVR_BY_BIND.remove(registeredManagementServerBind); // } // // registeredManagementServerBind = null; // } // } standby(); schedThread.halt(); notifySchedulerListenersShuttingdown(); if( (resources.isInterruptJobsOnShutdown() && !waitForJobsToComplete) || (resources.isInterruptJobsOnShutdownWithWait() && waitForJobsToComplete)) { List jobs = getCurrentlyExecutingJobs(); for(JobExecutionContext job: jobs) { if(job.getJobInstance() instanceof InterruptableJob) try { ((InterruptableJob)job.getJobInstance()).interrupt(); } catch (Throwable e) { // do nothing, this was just a courtesy effort getLog().warn("Encountered error when interrupting job {} during shutdown: {}", job.getJobDetail().getKey(), e); } } } resources.getThreadPool().shutdown(waitForJobsToComplete); if (waitForJobsToComplete) { while (jobMgr.getNumJobsCurrentlyExecuting() > 0) { try { Thread.sleep(100); } catch (Exception ignore) { } } } // Scheduler thread may have be waiting for the fire time of an acquired // trigger and need time to release the trigger once halted, so make sure // the thread is dead before continuing to shutdown the job store. try { schedThread.join(); } catch (InterruptedException ignore) { } closed = true; if (resources.getJMXExport()) { try { unregisterJMX(); } catch (Exception e) { } } if(boundRemotely) { try { unBind(); } catch (RemoteException re) { } } shutdownPlugins(); resources.getJobStore().shutdown(); notifySchedulerListenersShutdown(); SchedulerRepository.getInstance().remove(resources.getName()); holdToPreventGC.clear(); if(updateTimer != null) updateTimer.cancel(); getLog().info( "Scheduler " + resources.getUniqueIdentifier() + " shutdown complete."); } /** *

* Reports whether the Scheduler has been shutdown. *

*/ public boolean isShutdown() { return closed; } public boolean isShuttingDown() { return shuttingDown; } public boolean isStarted() { return !shuttingDown && !closed && !isInStandbyMode() && initialStart != null; } public void validateState() throws SchedulerException { if (isShutdown()) { throw new SchedulerException("The Scheduler has been shutdown."); } // other conditions to check (?) } /** *

* Return a list of JobExecutionContext objects that * represent all currently executing Jobs in this Scheduler instance. *

* *

* This method is not cluster aware. That is, it will only return Jobs * currently executing in this Scheduler instance, not across the entire * cluster. *

* *

* Note that the list returned is an 'instantaneous' snap-shot, and that as * soon as it's returned, the true list of executing jobs may be different. *

*/ public List getCurrentlyExecutingJobs() { return jobMgr.getExecutingJobs(); } /////////////////////////////////////////////////////////////////////////// /// /// Scheduling-related Methods /// /////////////////////////////////////////////////////////////////////////// /** *

* Add the {@link org.quartz.Job} identified by the given * {@link org.quartz.JobDetail} to the Scheduler, and * associate the given {@link org.quartz.Trigger} with it. *

* *

* If the given Trigger does not reference any Job, then it * will be set to reference the Job passed with it into this method. *

* * @throws SchedulerException * if the Job or Trigger cannot be added to the Scheduler, or * there is an internal Scheduler error. */ public Date scheduleJob(JobDetail jobDetail, Trigger trigger) throws SchedulerException { validateState(); if (jobDetail == null) { throw new SchedulerException("JobDetail cannot be null"); } if (trigger == null) { throw new SchedulerException("Trigger cannot be null"); } if (jobDetail.getKey() == null) { throw new SchedulerException("Job's key cannot be null"); } if (jobDetail.getJobClass() == null) { throw new SchedulerException("Job's class cannot be null"); } OperableTrigger trig = (OperableTrigger)trigger; if (trigger.getJobKey() == null) { trig.setJobKey(jobDetail.getKey()); } else if (!trigger.getJobKey().equals(jobDetail.getKey())) { throw new SchedulerException( "Trigger does not reference given job!"); } trig.validate(); Calendar cal = null; if (trigger.getCalendarName() != null) { cal = resources.getJobStore().retrieveCalendar(trigger.getCalendarName()); } Date ft = trig.computeFirstFireTime(cal); if (ft == null) { throw new SchedulerException( "Based on configured schedule, the given trigger '" + trigger.getKey() + "' will never fire."); } resources.getJobStore().storeJobAndTrigger(jobDetail, trig); notifySchedulerListenersJobAdded(jobDetail); notifySchedulerThread(trigger.getNextFireTime().getTime()); notifySchedulerListenersSchduled(trigger); return ft; } /** *

* Schedule the given {@link org.quartz.Trigger} with the * Job identified by the Trigger's settings. *

* * @throws SchedulerException * if the indicated Job does not exist, or the Trigger cannot be * added to the Scheduler, or there is an internal Scheduler * error. */ public Date scheduleJob(Trigger trigger) throws SchedulerException { validateState(); if (trigger == null) { throw new SchedulerException("Trigger cannot be null"); } OperableTrigger trig = (OperableTrigger)trigger; trig.validate(); Calendar cal = null; if (trigger.getCalendarName() != null) { cal = resources.getJobStore().retrieveCalendar(trigger.getCalendarName()); if(cal == null) { throw new SchedulerException( "Calendar not found: " + trigger.getCalendarName()); } } Date ft = trig.computeFirstFireTime(cal); if (ft == null) { throw new SchedulerException( "Based on configured schedule, the given trigger '" + trigger.getKey() + "' will never fire."); } resources.getJobStore().storeTrigger(trig, false); notifySchedulerThread(trigger.getNextFireTime().getTime()); notifySchedulerListenersSchduled(trigger); return ft; } /** *

* Add the given Job to the Scheduler - with no associated * Trigger. The Job will be 'dormant' until * it is scheduled with a Trigger, or Scheduler.triggerJob() * is called for it. *

* *

* The Job must by definition be 'durable', if it is not, * SchedulerException will be thrown. *

* * @throws SchedulerException * if there is an internal Scheduler error, or if the Job is not * durable, or a Job with the same name already exists, and * replace is false. */ public void addJob(JobDetail jobDetail, boolean replace) throws SchedulerException { addJob(jobDetail, replace, false); } public void addJob(JobDetail jobDetail, boolean replace, boolean storeNonDurableWhileAwaitingScheduling) throws SchedulerException { validateState(); if (!storeNonDurableWhileAwaitingScheduling && !jobDetail.isDurable()) { throw new SchedulerException( "Jobs added with no trigger must be durable."); } resources.getJobStore().storeJob(jobDetail, replace); notifySchedulerThread(0L); notifySchedulerListenersJobAdded(jobDetail); } /** *

* Delete the identified Job from the Scheduler - and any * associated Triggers. *

* * @return true if the Job was found and deleted. * @throws SchedulerException * if there is an internal Scheduler error. */ public boolean deleteJob(JobKey jobKey) throws SchedulerException { validateState(); boolean result = false; List triggers = getTriggersOfJob(jobKey); for (Trigger trigger : triggers) { if (!unscheduleJob(trigger.getKey())) { StringBuilder sb = new StringBuilder().append( "Unable to unschedule trigger [").append( trigger.getKey()).append("] while deleting job [") .append(jobKey).append( "]"); throw new SchedulerException(sb.toString()); } result = true; } result = resources.getJobStore().removeJob(jobKey) || result; if (result) { notifySchedulerThread(0L); notifySchedulerListenersJobDeleted(jobKey); } return result; } public boolean deleteJobs(List jobKeys) throws SchedulerException { validateState(); boolean result = false; result = resources.getJobStore().removeJobs(jobKeys); notifySchedulerThread(0L); for(JobKey key: jobKeys) notifySchedulerListenersJobDeleted(key); return result; } public void scheduleJobs(Map> triggersAndJobs, boolean replace) throws SchedulerException { validateState(); // make sure all triggers refer to their associated job for(Entry> e: triggersAndJobs.entrySet()) { JobDetail job = e.getKey(); if(job == null) // there can be one of these (for adding a bulk set of triggers for pre-existing jobs) continue; Set triggers = e.getValue(); if(triggers == null) // this is possible because the job may be durable, and not yet be having triggers continue; for(Trigger trigger: triggers) { OperableTrigger opt = (OperableTrigger)trigger; opt.setJobKey(job.getKey()); opt.validate(); Calendar cal = null; if (trigger.getCalendarName() != null) { cal = resources.getJobStore().retrieveCalendar(trigger.getCalendarName()); if(cal == null) { throw new SchedulerException( "Calendar '" + trigger.getCalendarName() + "' not found for trigger: " + trigger.getKey()); } } Date ft = opt.computeFirstFireTime(cal); if (ft == null) { throw new SchedulerException( "Based on configured schedule, the given trigger will never fire."); } } } resources.getJobStore().storeJobsAndTriggers(triggersAndJobs, replace); notifySchedulerThread(0L); for(JobDetail job: triggersAndJobs.keySet()) notifySchedulerListenersJobAdded(job); } public void scheduleJob(JobDetail jobDetail, Set triggersForJob, boolean replace) throws SchedulerException { Map> triggersAndJobs = new HashMap>(); triggersAndJobs.put(jobDetail, triggersForJob); scheduleJobs(triggersAndJobs, replace); } public boolean unscheduleJobs(List triggerKeys) throws SchedulerException { validateState(); boolean result = false; result = resources.getJobStore().removeTriggers(triggerKeys); notifySchedulerThread(0L); for(TriggerKey key: triggerKeys) notifySchedulerListenersUnscheduled(key); return result; } /** *

* Remove the indicated {@link org.quartz.Trigger} from the * scheduler. *

*/ public boolean unscheduleJob(TriggerKey triggerKey) throws SchedulerException { validateState(); if (resources.getJobStore().removeTrigger(triggerKey)) { notifySchedulerThread(0L); notifySchedulerListenersUnscheduled(triggerKey); } else { return false; } return true; } /** *

* Remove (delete) the {@link org.quartz.Trigger} with the * given name, and store the new given one - which must be associated * with the same job. *

* @param newTrigger * The new Trigger to be stored. * * @return null if a Trigger with the given * name & group was not found and removed from the store, otherwise * the first fire time of the newly scheduled trigger. */ public Date rescheduleJob(TriggerKey triggerKey, Trigger newTrigger) throws SchedulerException { validateState(); if (triggerKey == null) { throw new IllegalArgumentException("triggerKey cannot be null"); } if (newTrigger == null) { throw new IllegalArgumentException("newTrigger cannot be null"); } OperableTrigger trig = (OperableTrigger)newTrigger; Trigger oldTrigger = getTrigger(triggerKey); if (oldTrigger == null) { return null; } else { trig.setJobKey(oldTrigger.getJobKey()); } trig.validate(); Calendar cal = null; if (newTrigger.getCalendarName() != null) { cal = resources.getJobStore().retrieveCalendar( newTrigger.getCalendarName()); } Date ft = trig.computeFirstFireTime(cal); if (ft == null) { throw new SchedulerException( "Based on configured schedule, the given trigger will never fire."); } if (resources.getJobStore().replaceTrigger(triggerKey, trig)) { notifySchedulerThread(newTrigger.getNextFireTime().getTime()); notifySchedulerListenersUnscheduled(triggerKey); notifySchedulerListenersSchduled(newTrigger); } else { return null; } return ft; } private String newTriggerId() { long r = random.nextLong(); if (r < 0) { r = -r; } return "MT_" + Long.toString(r, 30 + (int) (System.currentTimeMillis() % 7)); } /** *

* Trigger the identified {@link org.quartz.Job} (execute it * now) - with a non-volatile trigger. *

*/ @SuppressWarnings("deprecation") public void triggerJob(JobKey jobKey, JobDataMap data) throws SchedulerException { validateState(); OperableTrigger trig = (OperableTrigger) newTrigger().withIdentity(newTriggerId(), Scheduler.DEFAULT_GROUP).forJob(jobKey).build(); trig.computeFirstFireTime(null); if(data != null) { trig.setJobDataMap(data); } boolean collision = true; while (collision) { try { resources.getJobStore().storeTrigger(trig, false); collision = false; } catch (ObjectAlreadyExistsException oaee) { trig.setKey(new TriggerKey(newTriggerId(), Scheduler.DEFAULT_GROUP)); } } notifySchedulerThread(trig.getNextFireTime().getTime()); notifySchedulerListenersSchduled(trig); } /** *

* Store and schedule the identified {@link org.quartz.spi.OperableTrigger} *

*/ public void triggerJob(OperableTrigger trig) throws SchedulerException { validateState(); trig.computeFirstFireTime(null); boolean collision = true; while (collision) { try { resources.getJobStore().storeTrigger(trig, false); collision = false; } catch (ObjectAlreadyExistsException oaee) { trig.setKey(new TriggerKey(newTriggerId(), Scheduler.DEFAULT_GROUP)); } } notifySchedulerThread(trig.getNextFireTime().getTime()); notifySchedulerListenersSchduled(trig); } /** *

* Pause the {@link Trigger} with the given name. *

* */ public void pauseTrigger(TriggerKey triggerKey) throws SchedulerException { validateState(); resources.getJobStore().pauseTrigger(triggerKey); notifySchedulerThread(0L); notifySchedulerListenersPausedTrigger(triggerKey); } /** *

* Pause all of the {@link Trigger}s in the matching groups. *

* */ public void pauseTriggers(GroupMatcher matcher) throws SchedulerException { validateState(); if(matcher == null) { matcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP); } Collection pausedGroups = resources.getJobStore().pauseTriggers(matcher); notifySchedulerThread(0L); for (String pausedGroup : pausedGroups) { notifySchedulerListenersPausedTriggers(pausedGroup); } } /** *

* Pause the {@link org.quartz.JobDetail} with the given * name - by pausing all of its current Triggers. *

* */ public void pauseJob(JobKey jobKey) throws SchedulerException { validateState(); resources.getJobStore().pauseJob(jobKey); notifySchedulerThread(0L); notifySchedulerListenersPausedJob(jobKey); } /** *

* Pause all of the {@link org.quartz.JobDetail}s in the * matching groups - by pausing all of their Triggers. *

* */ public void pauseJobs(GroupMatcher groupMatcher) throws SchedulerException { validateState(); if(groupMatcher == null) { groupMatcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP); } Collection pausedGroups = resources.getJobStore().pauseJobs(groupMatcher); notifySchedulerThread(0L); for (String pausedGroup : pausedGroups) { notifySchedulerListenersPausedJobs(pausedGroup); } } /** *

* Resume (un-pause) the {@link Trigger} with the given * name. *

* *

* If the Trigger missed one or more fire-times, then the * Trigger's misfire instruction will be applied. *

* */ public void resumeTrigger(TriggerKey triggerKey) throws SchedulerException { validateState(); resources.getJobStore().resumeTrigger(triggerKey); notifySchedulerThread(0L); notifySchedulerListenersResumedTrigger(triggerKey); } /** *

* Resume (un-pause) all of the {@link Trigger}s in the * matching groups. *

* *

* If any Trigger missed one or more fire-times, then the * Trigger's misfire instruction will be applied. *

* */ public void resumeTriggers(GroupMatcher matcher) throws SchedulerException { validateState(); if(matcher == null) { matcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP); } Collection pausedGroups = resources.getJobStore().resumeTriggers(matcher); notifySchedulerThread(0L); for (String pausedGroup : pausedGroups) { notifySchedulerListenersResumedTriggers(pausedGroup); } } public Set getPausedTriggerGroups() throws SchedulerException { return resources.getJobStore().getPausedTriggerGroups(); } /** *

* Resume (un-pause) the {@link org.quartz.JobDetail} with * the given name. *

* *

* If any of the Job'sTrigger s missed one * or more fire-times, then the Trigger's misfire * instruction will be applied. *

* */ public void resumeJob(JobKey jobKey) throws SchedulerException { validateState(); resources.getJobStore().resumeJob(jobKey); notifySchedulerThread(0L); notifySchedulerListenersResumedJob(jobKey); } /** *

* Resume (un-pause) all of the {@link org.quartz.JobDetail}s * in the matching groups. *

* *

* If any of the Job s had Trigger s that * missed one or more fire-times, then the Trigger's * misfire instruction will be applied. *

* */ public void resumeJobs(GroupMatcher matcher) throws SchedulerException { validateState(); if(matcher == null) { matcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP); } Collection resumedGroups = resources.getJobStore().resumeJobs(matcher); notifySchedulerThread(0L); for (String pausedGroup : resumedGroups) { notifySchedulerListenersResumedJobs(pausedGroup); } } /** *

* Pause all triggers - equivalent of calling pauseTriggers(GroupMatcher) * with a matcher matching all known groups. *

* *

* When resumeAll() is called (to un-pause), trigger misfire * instructions WILL be applied. *

* * @see #resumeAll() * @see #pauseTriggers(org.quartz.impl.matchers.GroupMatcher) * @see #standby() */ public void pauseAll() throws SchedulerException { validateState(); resources.getJobStore().pauseAll(); notifySchedulerThread(0L); notifySchedulerListenersPausedTriggers(null); } /** *

* Resume (un-pause) all triggers - equivalent of calling resumeTriggerGroup(group) * on every group. *

* *

* If any Trigger missed one or more fire-times, then the * Trigger's misfire instruction will be applied. *

* * @see #pauseAll() */ public void resumeAll() throws SchedulerException { validateState(); resources.getJobStore().resumeAll(); notifySchedulerThread(0L); notifySchedulerListenersResumedTrigger(null); } /** *

* Get the names of all known {@link org.quartz.Job} groups. *

*/ public List getJobGroupNames() throws SchedulerException { validateState(); return resources.getJobStore().getJobGroupNames(); } /** *

* Get the names of all the {@link org.quartz.Job}s in the * matching groups. *

*/ public Set getJobKeys(GroupMatcher matcher) throws SchedulerException { validateState(); if(matcher == null) { matcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP); } return resources.getJobStore().getJobKeys(matcher); } /** *

* Get all {@link Trigger} s that are associated with the * identified {@link org.quartz.JobDetail}. *

*/ public List getTriggersOfJob(JobKey jobKey) throws SchedulerException { validateState(); return resources.getJobStore().getTriggersForJob(jobKey); } /** *

* Get the names of all known {@link org.quartz.Trigger} * groups. *

*/ public List getTriggerGroupNames() throws SchedulerException { validateState(); return resources.getJobStore().getTriggerGroupNames(); } /** *

* Get the names of all the {@link org.quartz.Trigger}s in * the matching groups. *

*/ public Set getTriggerKeys(GroupMatcher matcher) throws SchedulerException { validateState(); if(matcher == null) { matcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP); } return resources.getJobStore().getTriggerKeys(matcher); } /** *

* Get the {@link JobDetail} for the Job * instance with the given name and group. *

*/ public JobDetail getJobDetail(JobKey jobKey) throws SchedulerException { validateState(); return resources.getJobStore().retrieveJob(jobKey); } /** *

* Get the {@link Trigger} instance with the given name and * group. *

*/ public Trigger getTrigger(TriggerKey triggerKey) throws SchedulerException { validateState(); return resources.getJobStore().retrieveTrigger(triggerKey); } /** * Determine whether a {@link Job} with the given identifier already * exists within the scheduler. * * @param jobKey the identifier to check for * @return true if a Job exists with the given identifier * @throws SchedulerException */ public boolean checkExists(JobKey jobKey) throws SchedulerException { validateState(); return resources.getJobStore().checkExists(jobKey); } /** * Determine whether a {@link Trigger} with the given identifier already * exists within the scheduler. * * @param triggerKey the identifier to check for * @return true if a Trigger exists with the given identifier * @throws SchedulerException */ public boolean checkExists(TriggerKey triggerKey) throws SchedulerException { validateState(); return resources.getJobStore().checkExists(triggerKey); } /** * Clears (deletes!) all scheduling data - all {@link Job}s, {@link Trigger}s * {@link Calendar}s. * * @throws SchedulerException */ public void clear() throws SchedulerException { validateState(); resources.getJobStore().clearAllSchedulingData(); notifySchedulerListenersUnscheduled(null); } /** *

* Get the current state of the identified {@link Trigger}. *

J * * @see TriggerState */ public TriggerState getTriggerState(TriggerKey triggerKey) throws SchedulerException { validateState(); return resources.getJobStore().getTriggerState(triggerKey); } /** *

* Add (register) the given Calendar to the Scheduler. *

* * @throws SchedulerException * if there is an internal Scheduler error, or a Calendar with * the same name already exists, and replace is * false. */ public void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers) throws SchedulerException { validateState(); resources.getJobStore().storeCalendar(calName, calendar, replace, updateTriggers); } /** *

* Delete the identified Calendar from the Scheduler. *

* * @return true if the Calendar was found and deleted. * @throws SchedulerException * if there is an internal Scheduler error. */ public boolean deleteCalendar(String calName) throws SchedulerException { validateState(); return resources.getJobStore().removeCalendar(calName); } /** *

* Get the {@link Calendar} instance with the given name. *

*/ public Calendar getCalendar(String calName) throws SchedulerException { validateState(); return resources.getJobStore().retrieveCalendar(calName); } /** *

* Get the names of all registered {@link Calendar}s. *

*/ public List getCalendarNames() throws SchedulerException { validateState(); return resources.getJobStore().getCalendarNames(); } public ListenerManager getListenerManager() { return listenerManager; } /** *

* Add the given {@link org.quartz.JobListener} to the * Scheduler's internal list. *

*/ public void addInternalJobListener(JobListener jobListener) { if (jobListener.getName() == null || jobListener.getName().length() == 0) { throw new IllegalArgumentException( "JobListener name cannot be empty."); } synchronized (internalJobListeners) { internalJobListeners.put(jobListener.getName(), jobListener); } } /** *

* Remove the identified {@link JobListener} from the Scheduler's * list of internal listeners. *

* * @return true if the identified listener was found in the list, and * removed. */ public boolean removeInternalJobListener(String name) { synchronized (internalJobListeners) { return (internalJobListeners.remove(name) != null); } } /** *

* Get a List containing all of the {@link org.quartz.JobListener}s * in the Scheduler's internal list. *

*/ public List getInternalJobListeners() { synchronized (internalJobListeners) { return java.util.Collections.unmodifiableList(new LinkedList(internalJobListeners.values())); } } /** *

* Get the internal {@link org.quartz.JobListener} * that has the given name. *

*/ public JobListener getInternalJobListener(String name) { synchronized (internalJobListeners) { return internalJobListeners.get(name); } } /** *

* Add the given {@link org.quartz.TriggerListener} to the * Scheduler's internal list. *

*/ public void addInternalTriggerListener(TriggerListener triggerListener) { if (triggerListener.getName() == null || triggerListener.getName().length() == 0) { throw new IllegalArgumentException( "TriggerListener name cannot be empty."); } synchronized (internalTriggerListeners) { internalTriggerListeners.put(triggerListener.getName(), triggerListener); } } /** *

* Remove the identified {@link TriggerListener} from the Scheduler's * list of internal listeners. *

* * @return true if the identified listener was found in the list, and * removed. */ public boolean removeinternalTriggerListener(String name) { synchronized (internalTriggerListeners) { return (internalTriggerListeners.remove(name) != null); } } /** *

* Get a list containing all of the {@link org.quartz.TriggerListener}s * in the Scheduler's internal list. *

*/ public List getInternalTriggerListeners() { synchronized (internalTriggerListeners) { return java.util.Collections.unmodifiableList(new LinkedList(internalTriggerListeners.values())); } } /** *

* Get the internal {@link TriggerListener} that * has the given name. *

*/ public TriggerListener getInternalTriggerListener(String name) { synchronized (internalTriggerListeners) { return internalTriggerListeners.get(name); } } /** *

* Register the given {@link SchedulerListener} with the * Scheduler's list of internal listeners. *

*/ public void addInternalSchedulerListener(SchedulerListener schedulerListener) { synchronized (internalSchedulerListeners) { internalSchedulerListeners.add(schedulerListener); } } /** *

* Remove the given {@link SchedulerListener} from the * Scheduler's list of internal listeners. *

* * @return true if the identified listener was found in the list, and * removed. */ public boolean removeInternalSchedulerListener(SchedulerListener schedulerListener) { synchronized (internalSchedulerListeners) { return internalSchedulerListeners.remove(schedulerListener); } } /** *

* Get a List containing all of the internal {@link SchedulerListener}s * registered with the Scheduler. *

*/ public List getInternalSchedulerListeners() { synchronized (internalSchedulerListeners) { return java.util.Collections.unmodifiableList(new ArrayList(internalSchedulerListeners)); } } protected void notifyJobStoreJobComplete(OperableTrigger trigger, JobDetail detail, CompletedExecutionInstruction instCode) throws JobPersistenceException { resources.getJobStore().triggeredJobComplete(trigger, detail, instCode); } protected void notifyJobStoreJobVetoed(OperableTrigger trigger, JobDetail detail, CompletedExecutionInstruction instCode) throws JobPersistenceException { resources.getJobStore().triggeredJobComplete(trigger, detail, instCode); } protected void notifySchedulerThread(long candidateNewNextFireTime) { if (isSignalOnSchedulingChange()) { signaler.signalSchedulingChange(candidateNewNextFireTime); } } private List buildTriggerListenerList() throws SchedulerException { List allListeners = new LinkedList(); allListeners.addAll(getListenerManager().getTriggerListeners()); allListeners.addAll(getInternalTriggerListeners()); return allListeners; } private List buildJobListenerList() throws SchedulerException { List allListeners = new LinkedList(); allListeners.addAll(getListenerManager().getJobListeners()); allListeners.addAll(getInternalJobListeners()); return allListeners; } private List buildSchedulerListenerList() { List allListeners = new LinkedList(); allListeners.addAll(getListenerManager().getSchedulerListeners()); allListeners.addAll(getInternalSchedulerListeners()); return allListeners; } private boolean matchJobListener(JobListener listener, JobKey key) { List> matchers = getListenerManager().getJobListenerMatchers(listener.getName()); if(matchers == null) return true; for(Matcher matcher: matchers) { if(matcher.isMatch(key)) return true; } return false; } private boolean matchTriggerListener(TriggerListener listener, TriggerKey key) { List> matchers = getListenerManager().getTriggerListenerMatchers(listener.getName()); if(matchers == null) return true; for(Matcher matcher: matchers) { if(matcher.isMatch(key)) return true; } return false; } public boolean notifyTriggerListenersFired(JobExecutionContext jec) throws SchedulerException { boolean vetoedExecution = false; // build a list of all trigger listeners that are to be notified... List triggerListeners = buildTriggerListenerList(); // notify all trigger listeners in the list for(TriggerListener tl: triggerListeners) { try { if(!matchTriggerListener(tl, jec.getTrigger().getKey())) continue; tl.triggerFired(jec.getTrigger(), jec); if(tl.vetoJobExecution(jec.getTrigger(), jec)) { vetoedExecution = true; } } catch (Exception e) { SchedulerException se = new SchedulerException( "TriggerListener '" + tl.getName() + "' threw exception: " + e.getMessage(), e); throw se; } } return vetoedExecution; } public void notifyTriggerListenersMisfired(Trigger trigger) throws SchedulerException { // build a list of all trigger listeners that are to be notified... List triggerListeners = buildTriggerListenerList(); // notify all trigger listeners in the list for(TriggerListener tl: triggerListeners) { try { if(!matchTriggerListener(tl, trigger.getKey())) continue; tl.triggerMisfired(trigger); } catch (Exception e) { SchedulerException se = new SchedulerException( "TriggerListener '" + tl.getName() + "' threw exception: " + e.getMessage(), e); throw se; } } } public void notifyTriggerListenersComplete(JobExecutionContext jec, CompletedExecutionInstruction instCode) throws SchedulerException { // build a list of all trigger listeners that are to be notified... List triggerListeners = buildTriggerListenerList(); // notify all trigger listeners in the list for(TriggerListener tl: triggerListeners) { try { if(!matchTriggerListener(tl, jec.getTrigger().getKey())) continue; tl.triggerComplete(jec.getTrigger(), jec, instCode); } catch (Exception e) { SchedulerException se = new SchedulerException( "TriggerListener '" + tl.getName() + "' threw exception: " + e.getMessage(), e); throw se; } } } public void notifyJobListenersToBeExecuted(JobExecutionContext jec) throws SchedulerException { // build a list of all job listeners that are to be notified... List jobListeners = buildJobListenerList(); // notify all job listeners for(JobListener jl: jobListeners) { try { if(!matchJobListener(jl, jec.getJobDetail().getKey())) continue; jl.jobToBeExecuted(jec); } catch (Exception e) { SchedulerException se = new SchedulerException( "JobListener '" + jl.getName() + "' threw exception: " + e.getMessage(), e); throw se; } } } public void notifyJobListenersWasVetoed(JobExecutionContext jec) throws SchedulerException { // build a list of all job listeners that are to be notified... List jobListeners = buildJobListenerList(); // notify all job listeners for(JobListener jl: jobListeners) { try { if(!matchJobListener(jl, jec.getJobDetail().getKey())) continue; jl.jobExecutionVetoed(jec); } catch (Exception e) { SchedulerException se = new SchedulerException( "JobListener '" + jl.getName() + "' threw exception: " + e.getMessage(), e); throw se; } } } public void notifyJobListenersWasExecuted(JobExecutionContext jec, JobExecutionException je) throws SchedulerException { // build a list of all job listeners that are to be notified... List jobListeners = buildJobListenerList(); // notify all job listeners for(JobListener jl: jobListeners) { try { if(!matchJobListener(jl, jec.getJobDetail().getKey())) continue; jl.jobWasExecuted(jec, je); } catch (Exception e) { SchedulerException se = new SchedulerException( "JobListener '" + jl.getName() + "' threw exception: " + e.getMessage(), e); throw se; } } } public void notifySchedulerListenersError(String msg, SchedulerException se) { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.schedulerError(msg, se); } catch (Exception e) { getLog() .error( "Error while notifying SchedulerListener of error: ", e); getLog().error( " Original error (for notification) was: " + msg, se); } } } public void notifySchedulerListenersSchduled(Trigger trigger) { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.jobScheduled(trigger); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of scheduled job." + " Triger=" + trigger.getKey(), e); } } } public void notifySchedulerListenersUnscheduled(TriggerKey triggerKey) { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { if(triggerKey == null) sl.schedulingDataCleared(); else sl.jobUnscheduled(triggerKey); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of unscheduled job." + " Triger=" + (triggerKey == null ? "ALL DATA" : triggerKey), e); } } } public void notifySchedulerListenersFinalized(Trigger trigger) { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.triggerFinalized(trigger); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of finalized trigger." + " Triger=" + trigger.getKey(), e); } } } public void notifySchedulerListenersPausedTrigger(TriggerKey triggerKey) { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.triggerPaused(triggerKey); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of paused trigger: " + triggerKey, e); } } } public void notifySchedulerListenersPausedTriggers(String group) { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.triggersPaused(group); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of paused trigger group." + group, e); } } } public void notifySchedulerListenersResumedTrigger(TriggerKey key) { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.triggerResumed(key); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of resumed trigger: " + key, e); } } } public void notifySchedulerListenersResumedTriggers(String group) { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.triggersResumed(group); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of resumed group: " + group, e); } } } public void notifySchedulerListenersPausedJob(JobKey key) { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.jobPaused(key); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of paused job: " + key, e); } } } public void notifySchedulerListenersPausedJobs(String group) { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.jobsPaused(group); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of paused job group: " + group, e); } } } public void notifySchedulerListenersResumedJob(JobKey key) { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.jobResumed(key); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of resumed job: " + key, e); } } } public void notifySchedulerListenersResumedJobs(String group) { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.jobsResumed(group); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of resumed job group: " + group, e); } } } public void notifySchedulerListenersInStandbyMode() { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.schedulerInStandbyMode(); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of inStandByMode.", e); } } } public void notifySchedulerListenersStarted() { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.schedulerStarted(); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of startup.", e); } } } public void notifySchedulerListenersStarting() { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for (SchedulerListener sl : schedListeners) { try { sl.schedulerStarting(); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of startup.", e); } } } public void notifySchedulerListenersShutdown() { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.schedulerShutdown(); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of shutdown.", e); } } } public void notifySchedulerListenersShuttingdown() { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.schedulerShuttingdown(); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of shutdown.", e); } } } public void notifySchedulerListenersJobAdded(JobDetail jobDetail) { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.jobAdded(jobDetail); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of JobAdded.", e); } } } public void notifySchedulerListenersJobDeleted(JobKey jobKey) { // build a list of all scheduler listeners that are to be notified... List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.jobDeleted(jobKey); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of JobAdded.", e); } } } public void setJobFactory(JobFactory factory) throws SchedulerException { if(factory == null) { throw new IllegalArgumentException("JobFactory cannot be set to null!"); } getLog().info("JobFactory set to: " + factory); this.jobFactory = factory; } public JobFactory getJobFactory() { return jobFactory; } /** * Interrupt all instances of the identified InterruptableJob executing in * this Scheduler instance. * *

* This method is not cluster aware. That is, it will only interrupt * instances of the identified InterruptableJob currently executing in this * Scheduler instance, not across the entire cluster. *

* * @see org.quartz.core.RemotableQuartzScheduler#interrupt(JobKey) */ public boolean interrupt(JobKey jobKey) throws UnableToInterruptJobException { List jobs = getCurrentlyExecutingJobs(); JobDetail jobDetail = null; Job job = null; boolean interrupted = false; for(JobExecutionContext jec : jobs) { jobDetail = jec.getJobDetail(); if (jobKey.equals(jobDetail.getKey())) { job = jec.getJobInstance(); if (job instanceof InterruptableJob) { ((InterruptableJob)job).interrupt(); interrupted = true; } else { throw new UnableToInterruptJobException( "Job " + jobDetail.getKey() + " can not be interrupted, since it does not implement " + InterruptableJob.class.getName()); } } } return interrupted; } /** * Interrupt the identified InterruptableJob executing in this Scheduler instance. * *

* This method is not cluster aware. That is, it will only interrupt * instances of the identified InterruptableJob currently executing in this * Scheduler instance, not across the entire cluster. *

* * @see org.quartz.core.RemotableQuartzScheduler#interrupt(JobKey) */ public boolean interrupt(String fireInstanceId) throws UnableToInterruptJobException { List jobs = getCurrentlyExecutingJobs(); Job job = null; for(JobExecutionContext jec : jobs) { if (jec.getFireInstanceId().equals(fireInstanceId)) { job = jec.getJobInstance(); if (job instanceof InterruptableJob) { ((InterruptableJob)job).interrupt(); return true; } else { throw new UnableToInterruptJobException( "Job " + jec.getJobDetail().getKey() + " can not be interrupted, since it does not implement " + InterruptableJob.class.getName()); } } } return false; } private void shutdownPlugins() { java.util.Iterator itr = resources.getSchedulerPlugins().iterator(); while (itr.hasNext()) { SchedulerPlugin plugin = itr.next(); plugin.shutdown(); } } private void startPlugins() { java.util.Iterator itr = resources.getSchedulerPlugins().iterator(); while (itr.hasNext()) { SchedulerPlugin plugin = itr.next(); plugin.start(); } } } ///////////////////////////////////////////////////////////////////////////// // // ErrorLogger - Scheduler Listener Class // ///////////////////////////////////////////////////////////////////////////// class ErrorLogger extends SchedulerListenerSupport { ErrorLogger() { } @Override public void schedulerError(String msg, SchedulerException cause) { getLog().error(msg, cause); } } ///////////////////////////////////////////////////////////////////////////// // // ExecutingJobsManager - Job Listener Class // ///////////////////////////////////////////////////////////////////////////// class ExecutingJobsManager implements JobListener { HashMap executingJobs = new HashMap(); AtomicInteger numJobsFired = new AtomicInteger(0); ExecutingJobsManager() { } public String getName() { return getClass().getName(); } public int getNumJobsCurrentlyExecuting() { synchronized (executingJobs) { return executingJobs.size(); } } public void jobToBeExecuted(JobExecutionContext context) { numJobsFired.incrementAndGet(); synchronized (executingJobs) { executingJobs .put(((OperableTrigger)context.getTrigger()).getFireInstanceId(), context); } } public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) { synchronized (executingJobs) { executingJobs.remove(((OperableTrigger)context.getTrigger()).getFireInstanceId()); } } public int getNumJobsFired() { return numJobsFired.get(); } public List getExecutingJobs() { synchronized (executingJobs) { return java.util.Collections.unmodifiableList(new ArrayList( executingJobs.values())); } } public void jobExecutionVetoed(JobExecutionContext context) { } }