/*
* 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.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.Random;
import java.util.Set;
import java.util.Timer;
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.JobListener;
import org.quartz.JobPersistenceException;
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 org.quartz.Trigger;
import org.quartz.TriggerListener;
import org.quartz.UnableToInterruptJobException;
import org.quartz.spi.ThreadExecutor;
import org.quartz.core.jmx.QuartzSchedulerMBean;
import org.quartz.impl.SchedulerRepository;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.listeners.SchedulerListenerSupport;
import org.quartz.simpl.SimpleJobFactory;
import org.quartz.spi.JobFactory;
import org.quartz.spi.SchedulerPlugin;
import org.quartz.spi.SchedulerSignaler;
import org.quartz.utils.UpdateChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* The scheduler is not destroyed, and can be re-started at any time.
*
*/
public void standby() {
schedThread.togglePause(true);
getLog().info(
"Scheduler " + resources.getUniqueIdentifier() + " paused.");
notifySchedulerListenersInStandbyMode();
}
/**
* 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().getFullName(), 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 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(SchedulingContext ctxt, JobDetail jobDetail,
Trigger trigger) throws SchedulerException {
validateState();
if (jobDetail == null) {
throw new SchedulerException("JobDetail cannot be null",
SchedulerException.ERR_CLIENT_ERROR);
}
if (trigger == null) {
throw new SchedulerException("Trigger cannot be null",
SchedulerException.ERR_CLIENT_ERROR);
}
jobDetail.validate();
if (trigger.getJobName() == null) {
trigger.setJobName(jobDetail.getName());
trigger.setJobGroup(jobDetail.getGroup());
} else if (trigger.getJobName() != null
&& !trigger.getJobName().equals(jobDetail.getName())) {
throw new SchedulerException(
"Trigger does not reference given job!",
SchedulerException.ERR_CLIENT_ERROR);
} else if (trigger.getJobGroup() != null
&& !trigger.getJobGroup().equals(jobDetail.getGroup())) {
throw new SchedulerException(
"Trigger does not reference given job!",
SchedulerException.ERR_CLIENT_ERROR);
}
trigger.validate();
Calendar cal = null;
if (trigger.getCalendarName() != null) {
cal = resources.getJobStore().retrieveCalendar(ctxt,
trigger.getCalendarName());
}
Date ft = trigger.computeFirstFireTime(cal);
if (ft == null) {
throw new SchedulerException(
"Based on configured schedule, the given trigger will never fire.",
SchedulerException.ERR_CLIENT_ERROR);
}
resources.getJobStore().storeJobAndTrigger(ctxt, jobDetail, trigger);
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(SchedulingContext ctxt, Trigger trigger)
throws SchedulerException {
validateState();
if (trigger == null) {
throw new SchedulerException("Trigger cannot be null",
SchedulerException.ERR_CLIENT_ERROR);
}
trigger.validate();
Calendar cal = null;
if (trigger.getCalendarName() != null) {
cal = resources.getJobStore().retrieveCalendar(ctxt,
trigger.getCalendarName());
if(cal == null) {
throw new SchedulerException(
"Calendar not found: " + trigger.getCalendarName(),
SchedulerException.ERR_PERSISTENCE_CALENDAR_DOES_NOT_EXIST);
}
}
Date ft = trigger.computeFirstFireTime(cal);
if (ft == null) {
throw new SchedulerException(
"Based on configured schedule, the given trigger will never fire.",
SchedulerException.ERR_CLIENT_ERROR);
}
resources.getJobStore().storeTrigger(ctxt, trigger, 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(SchedulingContext ctxt, JobDetail jobDetail,
boolean replace) throws SchedulerException {
validateState();
if (!jobDetail.isDurable() && !replace) {
throw new SchedulerException(
"Jobs added with no trigger must be durable.",
SchedulerException.ERR_CLIENT_ERROR);
}
resources.getJobStore().storeJob(ctxt, jobDetail, replace);
notifySchedulerThread(0L);
notifySchedulerListenersJobAdded(jobDetail);
}
/**
*
* Delete the identified Job
from the Scheduler - and any
* associated Trigger
s.
*
*
* @return true if the Job was found and deleted.
* @throws SchedulerException
* if there is an internal Scheduler error.
*/
public boolean deleteJob(SchedulingContext ctxt, String jobName,
String groupName) throws SchedulerException {
validateState();
if (groupName == null) {
groupName = Scheduler.DEFAULT_GROUP;
}
boolean result = false;
Trigger[] triggers = getTriggersOfJob(ctxt, jobName, groupName);
for (Trigger trigger : triggers) {
if (!unscheduleJob(ctxt, trigger.getName(), trigger.getGroup())) {
StringBuilder sb = new StringBuilder().append(
"Unable to unschedule trigger [").append(
trigger.getKey()).append("] while deleting job [")
.append(groupName).append(".").append(jobName).append(
"]");
throw new SchedulerException(sb.toString());
}
result = true;
}
result = resources.getJobStore().removeJob(ctxt, jobName, groupName) || result;
if (result) {
notifySchedulerThread(0L);
notifySchedulerListenersJobDeleted(jobName, groupName);
}
return result;
}
/**
*
* Remove the indicated {@link org.quartz.Trigger}
from the
* scheduler.
*
*/
public boolean unscheduleJob(SchedulingContext ctxt, String triggerName,
String groupName) throws SchedulerException {
validateState();
if(groupName == null) {
groupName = Scheduler.DEFAULT_GROUP;
}
if (resources.getJobStore().removeTrigger(ctxt, triggerName, groupName)) {
notifySchedulerThread(0L);
notifySchedulerListenersUnscheduled(triggerName, groupName);
} 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 triggerName
* The name of the Trigger
to be removed.
* @param groupName
* The group name of the Trigger
to be removed.
* @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(SchedulingContext ctxt, String triggerName,
String groupName, Trigger newTrigger) throws SchedulerException {
validateState();
if(groupName == null) {
groupName = Scheduler.DEFAULT_GROUP;
}
newTrigger.validate();
Calendar cal = null;
if (newTrigger.getCalendarName() != null) {
cal = resources.getJobStore().retrieveCalendar(ctxt,
newTrigger.getCalendarName());
}
Date ft = newTrigger.computeFirstFireTime(cal);
if (ft == null) {
throw new SchedulerException(
"Based on configured schedule, the given trigger will never fire.",
SchedulerException.ERR_CLIENT_ERROR);
}
if (resources.getJobStore().replaceTrigger(ctxt, triggerName, groupName, newTrigger)) {
notifySchedulerThread(newTrigger.getNextFireTime().getTime());
notifySchedulerListenersUnscheduled(triggerName, groupName);
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.
*
*/
public void triggerJob(SchedulingContext ctxt, String jobName,
String groupName, JobDataMap data) throws SchedulerException {
validateState();
if(groupName == null) {
groupName = Scheduler.DEFAULT_GROUP;
}
Trigger trig = new org.quartz.SimpleTrigger(newTriggerId(),
Scheduler.DEFAULT_MANUAL_TRIGGERS, jobName, groupName,
new Date(), null, 0, 0);
trig.setVolatility(false);
trig.computeFirstFireTime(null);
if(data != null) {
trig.setJobDataMap(data);
}
boolean collision = true;
while (collision) {
try {
resources.getJobStore().storeTrigger(ctxt, trig, false);
collision = false;
} catch (ObjectAlreadyExistsException oaee) {
trig.setName(newTriggerId());
}
}
notifySchedulerThread(trig.getNextFireTime().getTime());
notifySchedulerListenersSchduled(trig);
}
/**
*
* Trigger the identified {@link org.quartz.Job}
(execute it
* now) - with a volatile trigger.
*
*/
public void triggerJobWithVolatileTrigger(SchedulingContext ctxt,
String jobName, String groupName, JobDataMap data) throws SchedulerException {
validateState();
if(groupName == null) {
groupName = Scheduler.DEFAULT_GROUP;
}
Trigger trig = new org.quartz.SimpleTrigger(newTriggerId(),
Scheduler.DEFAULT_MANUAL_TRIGGERS, jobName, groupName,
new Date(), null, 0, 0);
trig.setVolatility(true);
trig.computeFirstFireTime(null);
if(data != null) {
trig.setJobDataMap(data);
}
boolean collision = true;
while (collision) {
try {
resources.getJobStore().storeTrigger(ctxt, trig, false);
collision = false;
} catch (ObjectAlreadyExistsException oaee) {
trig.setName(newTriggerId());
}
}
notifySchedulerThread(trig.getNextFireTime().getTime());
notifySchedulerListenersSchduled(trig);
}
/**
*
* Pause the {@link Trigger}
with the given name.
*
*
*/
public void pauseTrigger(SchedulingContext ctxt, String triggerName,
String groupName) throws SchedulerException {
validateState();
if(groupName == null) {
groupName = Scheduler.DEFAULT_GROUP;
}
resources.getJobStore().pauseTrigger(ctxt, triggerName, groupName);
notifySchedulerThread(0L);
notifySchedulerListenersPausedTrigger(triggerName, groupName);
}
/**
*
* Pause all of the {@link Trigger}s
in the given group.
*
*
*/
public void pauseTriggerGroup(SchedulingContext ctxt, String groupName)
throws SchedulerException {
validateState();
if(groupName == null) {
groupName = Scheduler.DEFAULT_GROUP;
}
resources.getJobStore().pauseTriggerGroup(ctxt, groupName);
notifySchedulerThread(0L);
notifySchedulerListenersPausedTrigger(null, groupName);
}
/**
*
* Pause the {@link org.quartz.JobDetail}
with the given
* name - by pausing all of its current Trigger
s.
*
*
*/
public void pauseJob(SchedulingContext ctxt, String jobName,
String groupName) throws SchedulerException {
validateState();
if(groupName == null) {
groupName = Scheduler.DEFAULT_GROUP;
}
resources.getJobStore().pauseJob(ctxt, jobName, groupName);
notifySchedulerThread(0L);
notifySchedulerListenersPausedJob(jobName, groupName);
}
/**
*
* Pause all of the {@link org.quartz.JobDetail}s
in the
* given group - by pausing all of their Trigger
s.
*
*
*/
public void pauseJobGroup(SchedulingContext ctxt, String groupName)
throws SchedulerException {
validateState();
if(groupName == null) {
groupName = Scheduler.DEFAULT_GROUP;
}
resources.getJobStore().pauseJobGroup(ctxt, groupName);
notifySchedulerThread(0L);
notifySchedulerListenersPausedJob(null, groupName);
}
/**
*
* 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(SchedulingContext ctxt, String triggerName,
String groupName) throws SchedulerException {
validateState();
if(groupName == null) {
groupName = Scheduler.DEFAULT_GROUP;
}
resources.getJobStore().resumeTrigger(ctxt, triggerName, groupName);
notifySchedulerThread(0L);
notifySchedulerListenersResumedTrigger(triggerName, groupName);
}
/**
*
* Resume (un-pause) all of the {@link Trigger}s
in the
* given group.
*
*
*
* If any Trigger
missed one or more fire-times, then the
* Trigger
's misfire instruction will be applied.
*
*
*/
public void resumeTriggerGroup(SchedulingContext ctxt, String groupName)
throws SchedulerException {
validateState();
if(groupName == null) {
groupName = Scheduler.DEFAULT_GROUP;
}
resources.getJobStore().resumeTriggerGroup(ctxt, groupName);
notifySchedulerThread(0L);
notifySchedulerListenersResumedTrigger(null, groupName);
}
public Set getPausedTriggerGroups(SchedulingContext ctxt) throws SchedulerException {
return resources.getJobStore().getPausedTriggerGroups(ctxt);
}
/**
*
* 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(SchedulingContext ctxt, String jobName,
String groupName) throws SchedulerException {
validateState();
if(groupName == null) {
groupName = Scheduler.DEFAULT_GROUP;
}
resources.getJobStore().resumeJob(ctxt, jobName, groupName);
notifySchedulerThread(0L);
notifySchedulerListenersResumedJob(jobName, groupName);
}
/**
*
* Resume (un-pause) all of the {@link org.quartz.JobDetail}s
* in the given group.
*
*
*
* 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 resumeJobGroup(SchedulingContext ctxt, String groupName)
throws SchedulerException {
validateState();
if(groupName == null) {
groupName = Scheduler.DEFAULT_GROUP;
}
resources.getJobStore().resumeJobGroup(ctxt, groupName);
notifySchedulerThread(0L);
notifySchedulerListenersResumedJob(null, groupName);
}
/**
*
* Pause all triggers - equivalent of calling pauseTriggerGroup(group)
* on every group.
*
*
*
* When resumeAll()
is called (to un-pause), trigger misfire
* instructions WILL be applied.
*
*
* @see #resumeAll(SchedulingContext)
* @see #pauseTriggerGroup(SchedulingContext, String)
* @see #standby()
*/
public void pauseAll(SchedulingContext ctxt) throws SchedulerException {
validateState();
resources.getJobStore().pauseAll(ctxt);
notifySchedulerThread(0L);
notifySchedulerListenersPausedTrigger(null, 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(SchedulingContext)
*/
public void resumeAll(SchedulingContext ctxt) throws SchedulerException {
validateState();
resources.getJobStore().resumeAll(ctxt);
notifySchedulerThread(0L);
notifySchedulerListenersResumedTrigger(null, null);
}
/**
*
* Get the names of all known {@link org.quartz.Job}
groups.
*
*/
public String[] getJobGroupNames(SchedulingContext ctxt)
throws SchedulerException {
validateState();
return resources.getJobStore().getJobGroupNames(ctxt);
}
/**
*
* Get the names of all the {@link org.quartz.Job}s
in the
* given group.
*
*/
public String[] getJobNames(SchedulingContext ctxt, String groupName)
throws SchedulerException {
validateState();
if(groupName == null) {
groupName = Scheduler.DEFAULT_GROUP;
}
return resources.getJobStore().getJobNames(ctxt, groupName);
}
/**
*
* Get all {@link Trigger}
s that are associated with the
* identified {@link org.quartz.JobDetail}
.
*
*/
public Trigger[] getTriggersOfJob(SchedulingContext ctxt, String jobName,
String groupName) throws SchedulerException {
validateState();
if(groupName == null) {
groupName = Scheduler.DEFAULT_GROUP;
}
return resources.getJobStore().getTriggersForJob(ctxt, jobName,
groupName);
}
/**
*
* Get the names of all known {@link org.quartz.Trigger}
* groups.
*
*/
public String[] getTriggerGroupNames(SchedulingContext ctxt)
throws SchedulerException {
validateState();
return resources.getJobStore().getTriggerGroupNames(ctxt);
}
/**
*
* Get the names of all the {@link org.quartz.Trigger}s
in
* the given group.
*
*/
public String[] getTriggerNames(SchedulingContext ctxt, String groupName)
throws SchedulerException {
validateState();
if(groupName == null) {
groupName = Scheduler.DEFAULT_GROUP;
}
return resources.getJobStore().getTriggerNames(ctxt, groupName);
}
/**
*
* Get the {@link JobDetail}
for the Job
* instance with the given name and group.
*
*/
public JobDetail getJobDetail(SchedulingContext ctxt, String jobName,
String jobGroup) throws SchedulerException {
validateState();
if(jobGroup == null) {
jobGroup = Scheduler.DEFAULT_GROUP;
}
return resources.getJobStore().retrieveJob(ctxt, jobName, jobGroup);
}
/**
*
* Get the {@link Trigger}
instance with the given name and
* group.
*
*/
public Trigger getTrigger(SchedulingContext ctxt, String triggerName,
String triggerGroup) throws SchedulerException {
validateState();
if(triggerGroup == null) {
triggerGroup = Scheduler.DEFAULT_GROUP;
}
return resources.getJobStore().retrieveTrigger(ctxt, triggerName,
triggerGroup);
}
/**
*
* Get the current state of the identified {@link Trigger}
.
*
*
* @see Trigger#STATE_NORMAL
* @see Trigger#STATE_PAUSED
* @see Trigger#STATE_COMPLETE
* @see Trigger#STATE_ERROR
*/
public int getTriggerState(SchedulingContext ctxt, String triggerName,
String triggerGroup) throws SchedulerException {
validateState();
if(triggerGroup == null) {
triggerGroup = Scheduler.DEFAULT_GROUP;
}
return resources.getJobStore().getTriggerState(ctxt, triggerName,
triggerGroup);
}
/**
*
* 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(SchedulingContext ctxt, String calName,
Calendar calendar, boolean replace, boolean updateTriggers) throws SchedulerException {
validateState();
resources.getJobStore().storeCalendar(ctxt, 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(SchedulingContext ctxt, String calName)
throws SchedulerException {
validateState();
return resources.getJobStore().removeCalendar(ctxt, calName);
}
/**
*
* Get the {@link Calendar}
instance with the given name.
*
*/
public Calendar getCalendar(SchedulingContext ctxt, String calName)
throws SchedulerException {
validateState();
return resources.getJobStore().retrieveCalendar(ctxt, calName);
}
/**
*
* Get the names of all registered {@link Calendar}s
.
*
*/
public String[] getCalendarNames(SchedulingContext ctxt)
throws SchedulerException {
validateState();
return resources.getJobStore().getCalendarNames(ctxt);
}
/**
*
* Add the given {@link org.quartz.JobListener}
to the
* Scheduler
'sglobal list.
*
*
*
* Listeners in the 'global' list receive notification of execution events
* for ALL {@link org.quartz.Job}
s.
*
*/
public void addGlobalJobListener(JobListener jobListener) {
if (jobListener.getName() == null
|| jobListener.getName().length() == 0) {
throw new IllegalArgumentException(
"JobListener name cannot be empty.");
}
synchronized (globalJobListeners) {
globalJobListeners.put(jobListener.getName(), jobListener);
}
}
/**
*
* Add the given {@link org.quartz.JobListener}
to the
* Scheduler
's list, of registered JobListener
s.
*/
public void addJobListener(JobListener jobListener) {
if (jobListener.getName() == null
|| jobListener.getName().length() == 0) {
throw new IllegalArgumentException(
"JobListener name cannot be empty.");
}
synchronized (jobListeners) {
jobListeners.put(jobListener.getName(), jobListener);
}
}
/**
*
* Remove the identified {@link JobListener}
from the Scheduler
's
* list of global listeners.
*
*
* @return true if the identified listener was found in the list, and
* removed.
*/
public boolean removeGlobalJobListener(String name) {
synchronized (globalJobListeners) {
return (globalJobListeners.remove(name) != null);
}
}
/**
*
* Remove the identified {@link org.quartz.JobListener}
from
* the Scheduler
's list of registered listeners.
*
*
* @return true if the identifed listener was found in the list, and
* removed.
*/
public boolean removeJobListener(String name) {
synchronized (jobListeners) {
return (jobListeners.remove(name) != null);
}
}
/**
*
* Get a List containing all of the {@link org.quartz.JobListener}
* s in the Scheduler
'sglobal list.
*
*/
public List getGlobalJobListeners() {
synchronized (globalJobListeners) {
return new LinkedList(globalJobListeners.values());
}
}
/**
*
* Get a Set containing the names of all the non-global{@link org.quartz.JobListener}
* s registered with the Scheduler
.
*
*/
public Set getJobListenerNames() {
synchronized (jobListeners) {
return new HashSet(jobListeners.keySet());
}
}
/**
*
* Get the global{@link org.quartz.JobListener}
* that has the given name.
*
*/
public JobListener getGlobalJobListener(String name) {
synchronized (globalJobListeners) {
return (JobListener)globalJobListeners.get(name);
}
}
/**
*
* Get the non-global{@link org.quartz.JobListener}
* that has the given name.
*
*/
public JobListener getJobListener(String name) {
synchronized (jobListeners) {
return (JobListener) jobListeners.get(name);
}
}
/**
*
* Add the given {@link org.quartz.TriggerListener}
to the
* Scheduler
'sglobal list.
*
*
*
* Listeners in the 'global' list receive notification of execution events
* for ALL {@link org.quartz.Trigger}
s.
*
*/
public void addGlobalTriggerListener(TriggerListener triggerListener) {
if (triggerListener.getName() == null
|| triggerListener.getName().length() == 0) {
throw new IllegalArgumentException(
"TriggerListener name cannot be empty.");
}
synchronized (globalTriggerListeners) {
globalTriggerListeners.put(triggerListener.getName(), triggerListener);
}
}
/**
*
* Add the given {@link org.quartz.TriggerListener}
to the
* Scheduler
's list, of registered TriggerListener
s.
*/
public void addTriggerListener(TriggerListener triggerListener) {
if (triggerListener.getName() == null
|| triggerListener.getName().length() == 0) {
throw new IllegalArgumentException(
"TriggerListener name cannot be empty.");
}
synchronized (triggerListeners) {
triggerListeners.put(triggerListener.getName(), triggerListener);
}
}
/**
*
* Remove the identifed {@link TriggerListener}
from the Scheduler
's
* list of global listeners.
*
*
* @return true if the identifed listener was found in the list, and
* removed.
*/
public boolean removeGlobalTriggerListener(String name) {
synchronized (globalTriggerListeners) {
return (globalTriggerListeners.remove(name) != null);
}
}
/**
*
* Remove the identified {@link org.quartz.TriggerListener}
* from the Scheduler
's list of registered listeners.
*
*
* @return true if the identified listener was found in the list, and
* removed.
*/
public boolean removeTriggerListener(String name) {
synchronized (triggerListeners) {
return (triggerListeners.remove(name) != null);
}
}
/**
*
* Get a list containing all of the {@link org.quartz.TriggerListener}
* s in the Scheduler
'sglobal list.
*
*/
public List getGlobalTriggerListeners() {
synchronized (globalTriggerListeners) {
return new LinkedList(globalTriggerListeners.values());
}
}
/**
*
* Get a Set containing the names of all the non-global{@link org.quartz.TriggerListener}
* s registered with the Scheduler
.
*
*/
public Set getTriggerListenerNames() {
synchronized (triggerListeners) {
return new HashSet(triggerListeners.keySet());
}
}
/**
*
* Get the global{@link TriggerListener}
that
* has the given name.
*
*/
public TriggerListener getGlobalTriggerListener(String name) {
synchronized (globalTriggerListeners) {
return (TriggerListener)globalTriggerListeners.get(name);
}
}
/**
*
* Get the non-global{@link org.quartz.TriggerListener}
* that has the given name.
*
*/
public TriggerListener getTriggerListener(String name) {
synchronized (triggerListeners) {
return (TriggerListener) triggerListeners.get(name);
}
}
/**
*
* Register the given {@link SchedulerListener}
with the
* Scheduler
.
*
*/
public void addSchedulerListener(SchedulerListener schedulerListener) {
synchronized (schedulerListeners) {
schedulerListeners.add(schedulerListener);
}
}
/**
*
* Remove the given {@link SchedulerListener}
from the
* Scheduler
.
*
*
* @return true if the identified listener was found in the list, and
* removed.
*/
public boolean removeSchedulerListener(SchedulerListener schedulerListener) {
synchronized (schedulerListeners) {
return schedulerListeners.remove(schedulerListener);
}
}
/**
*
* Get a List containing all of the {@link SchedulerListener}
* s registered with the Scheduler
.
*
*/
public List getSchedulerListeners() {
synchronized (schedulerListeners) {
return (List)schedulerListeners.clone();
}
}
protected void notifyJobStoreJobComplete(SchedulingContext ctxt,
Trigger trigger, JobDetail detail, int instCode)
throws JobPersistenceException {
resources.getJobStore().triggeredJobComplete(ctxt, trigger, detail,
instCode);
}
protected void notifyJobStoreJobVetoed(SchedulingContext ctxt,
Trigger trigger, JobDetail detail, int instCode)
throws JobPersistenceException {
resources.getJobStore().triggeredJobComplete(ctxt, trigger, detail, instCode);
}
protected void notifySchedulerThread(long candidateNewNextFireTime) {
if (isSignalOnSchedulingChange()) {
signaler.signalSchedulingChange(candidateNewNextFireTime);
}
}
private List buildTriggerListenerList(String[] additionalLstnrs)
throws SchedulerException {
List triggerListeners = getGlobalTriggerListeners();
for (int i = 0; i < additionalLstnrs.length; i++) {
TriggerListener tl = getTriggerListener(additionalLstnrs[i]);
if (tl != null) {
triggerListeners.add(tl);
} else {
throw new SchedulerException("TriggerListener '"
+ additionalLstnrs[i] + "' not found.",
SchedulerException.ERR_TRIGGER_LISTENER_NOT_FOUND);
}
}
return triggerListeners;
}
private List buildJobListenerList(String[] additionalLstnrs)
throws SchedulerException {
List jobListeners = getGlobalJobListeners();
for (int i = 0; i < additionalLstnrs.length; i++) {
JobListener jl = getJobListener(additionalLstnrs[i]);
if (jl != null) {
jobListeners.add(jl);
} else {
throw new SchedulerException("JobListener '"
+ additionalLstnrs[i] + "' not found.",
SchedulerException.ERR_JOB_LISTENER_NOT_FOUND);
}
}
return jobListeners;
}
public boolean notifyTriggerListenersFired(JobExecutionContext jec)
throws SchedulerException {
// build a list of all trigger listeners that are to be notified...
List triggerListeners = buildTriggerListenerList(jec.getTrigger()
.getTriggerListenerNames());
boolean vetoedExecution = false;
// notify all trigger listeners in the list
java.util.Iterator itr = triggerListeners.iterator();
while (itr.hasNext()) {
TriggerListener tl = (TriggerListener) itr.next();
try {
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);
se.setErrorCode(SchedulerException.ERR_TRIGGER_LISTENER);
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(trigger
.getTriggerListenerNames());
// notify all trigger listeners in the list
java.util.Iterator itr = triggerListeners.iterator();
while (itr.hasNext()) {
TriggerListener tl = (TriggerListener) itr.next();
try {
tl.triggerMisfired(trigger);
} catch (Exception e) {
SchedulerException se = new SchedulerException(
"TriggerListener '" + tl.getName()
+ "' threw exception: " + e.getMessage(), e);
se.setErrorCode(SchedulerException.ERR_TRIGGER_LISTENER);
throw se;
}
}
}
public void notifyTriggerListenersComplete(JobExecutionContext jec,
int instCode) throws SchedulerException {
// build a list of all trigger listeners that are to be notified...
List triggerListeners = buildTriggerListenerList(jec.getTrigger()
.getTriggerListenerNames());
// notify all trigger listeners in the list
java.util.Iterator itr = triggerListeners.iterator();
while (itr.hasNext()) {
TriggerListener tl = (TriggerListener) itr.next();
try {
tl.triggerComplete(jec.getTrigger(), jec, instCode);
} catch (Exception e) {
SchedulerException se = new SchedulerException(
"TriggerListener '" + tl.getName()
+ "' threw exception: " + e.getMessage(), e);
se.setErrorCode(SchedulerException.ERR_TRIGGER_LISTENER);
throw se;
}
}
}
public void notifyJobListenersToBeExecuted(JobExecutionContext jec)
throws SchedulerException {
// build a list of all job listeners that are to be notified...
List jobListeners = buildJobListenerList(jec.getJobDetail()
.getJobListenerNames());
// notify all job listeners
java.util.Iterator itr = jobListeners.iterator();
while (itr.hasNext()) {
JobListener jl = (JobListener) itr.next();
try {
jl.jobToBeExecuted(jec);
} catch (Exception e) {
SchedulerException se = new SchedulerException(
"JobListener '" + jl.getName() + "' threw exception: "
+ e.getMessage(), e);
se.setErrorCode(SchedulerException.ERR_JOB_LISTENER);
throw se;
}
}
}
public void notifyJobListenersWasVetoed(JobExecutionContext jec)
throws SchedulerException {
// build a list of all job listeners that are to be notified...
List jobListeners = buildJobListenerList(jec.getJobDetail()
.getJobListenerNames());
// notify all job listeners
java.util.Iterator itr = jobListeners.iterator();
while (itr.hasNext()) {
JobListener jl = (JobListener) itr.next();
try {
jl.jobExecutionVetoed(jec);
} catch (Exception e) {
SchedulerException se = new SchedulerException(
"JobListener '" + jl.getName() + "' threw exception: "
+ e.getMessage(), e);
se.setErrorCode(SchedulerException.ERR_JOB_LISTENER);
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(jec.getJobDetail()
.getJobListenerNames());
// notify all job listeners
java.util.Iterator itr = jobListeners.iterator();
while (itr.hasNext()) {
JobListener jl = (JobListener) itr.next();
try {
jl.jobWasExecuted(jec, je);
} catch (Exception e) {
SchedulerException se = new SchedulerException(
"JobListener '" + jl.getName() + "' threw exception: "
+ e.getMessage(), e);
se.setErrorCode(SchedulerException.ERR_JOB_LISTENER);
throw se;
}
}
}
public void notifySchedulerListenersError(String msg, SchedulerException se) {
// build a list of all scheduler listeners that are to be notified...
List schedListeners = getSchedulerListeners();
// notify all scheduler listeners
java.util.Iterator itr = schedListeners.iterator();
while (itr.hasNext()) {
SchedulerListener sl = (SchedulerListener) itr.next();
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 = getSchedulerListeners();
// notify all scheduler listeners
java.util.Iterator itr = schedListeners.iterator();
while (itr.hasNext()) {
SchedulerListener sl = (SchedulerListener) itr.next();
try {
sl.jobScheduled(trigger);
} catch (Exception e) {
getLog().error(
"Error while notifying SchedulerListener of scheduled job."
+ " Triger=" + trigger.getFullName(), e);
}
}
}
public void notifySchedulerListenersUnscheduled(String triggerName,
String triggerGroup) {
// build a list of all scheduler listeners that are to be notified...
List schedListeners = getSchedulerListeners();
// notify all scheduler listeners
java.util.Iterator itr = schedListeners.iterator();
while (itr.hasNext()) {
SchedulerListener sl = (SchedulerListener) itr.next();
try {
sl.jobUnscheduled(triggerName, triggerGroup);
} catch (Exception e) {
getLog().error(
"Error while notifying SchedulerListener of unscheduled job."
+ " Triger=" + triggerGroup + "."
+ triggerName, e);
}
}
}
public void notifySchedulerListenersFinalized(Trigger trigger) {
// build a list of all scheduler listeners that are to be notified...
List schedListeners = getSchedulerListeners();
// notify all scheduler listeners
java.util.Iterator itr = schedListeners.iterator();
while (itr.hasNext()) {
SchedulerListener sl = (SchedulerListener) itr.next();
try {
sl.triggerFinalized(trigger);
} catch (Exception e) {
getLog().error(
"Error while notifying SchedulerListener of finalized trigger."
+ " Triger=" + trigger.getFullName(), e);
}
}
}
public void notifySchedulerListenersPausedTrigger(String name, String group) {
// build a list of all job listeners that are to be notified...
List schedListeners = getSchedulerListeners();
// notify all scheduler listeners
java.util.Iterator itr = schedListeners.iterator();
while (itr.hasNext()) {
SchedulerListener sl = (SchedulerListener) itr.next();
try {
sl.triggersPaused(name, group);
} catch (Exception e) {
getLog().error(
"Error while notifying SchedulerListener of paused trigger/group."
+ " Triger=" + group + "." + name, e);
}
}
}
public void notifySchedulerListenersResumedTrigger(String name, String group) {
// build a list of all job listeners that are to be notified...
List schedListeners = getSchedulerListeners();
// notify all scheduler listeners
java.util.Iterator itr = schedListeners.iterator();
while (itr.hasNext()) {
SchedulerListener sl = (SchedulerListener) itr.next();
try {
sl.triggersResumed(name, group);
} catch (Exception e) {
getLog().error(
"Error while notifying SchedulerListener of resumed trigger/group."
+ " Triger=" + group + "." + name, e);
}
}
}
public void notifySchedulerListenersPausedJob(String name, String group) {
// build a list of all job listeners that are to be notified...
List schedListeners = getSchedulerListeners();
// notify all scheduler listeners
java.util.Iterator itr = schedListeners.iterator();
while (itr.hasNext()) {
SchedulerListener sl = (SchedulerListener) itr.next();
try {
sl.jobsPaused(name, group);
} catch (Exception e) {
getLog().error(
"Error while notifying SchedulerListener of paused job/group."
+ " Job=" + group + "." + name, e);
}
}
}
public void notifySchedulerListenersResumedJob(String name, String group) {
// build a list of all job listeners that are to be notified...
List schedListeners = getSchedulerListeners();
// notify all scheduler listeners
java.util.Iterator itr = schedListeners.iterator();
while (itr.hasNext()) {
SchedulerListener sl = (SchedulerListener) itr.next();
try {
sl.jobsResumed(name, group);
} catch (Exception e) {
getLog().error(
"Error while notifying SchedulerListener of resumed job/group."
+ " Job=" + group + "." + name, e);
}
}
}
public void notifySchedulerListenersInStandbyMode() {
// build a list of all job listeners that are to be notified...
List schedListeners = getSchedulerListeners();
// notify all scheduler listeners
java.util.Iterator itr = schedListeners.iterator();
while (itr.hasNext()) {
SchedulerListener sl = (SchedulerListener) itr.next();
try {
sl.schedulerInStandbyMode();
} catch (Exception e) {
getLog().error(
"Error while notifying SchedulerListener of inStandByMode.",
e);
}
}
}
public void notifySchedulerListenersStarted() {
// build a list of all job listeners that are to be notified...
List schedListeners = getSchedulerListeners();
// notify all scheduler listeners
java.util.Iterator itr = schedListeners.iterator();
while (itr.hasNext()) {
SchedulerListener sl = (SchedulerListener) itr.next();
try {
sl.schedulerStarted();
} catch (Exception e) {
getLog().error(
"Error while notifying SchedulerListener of startup.",
e);
}
}
}
public void notifySchedulerListenersShutdown() {
// build a list of all job listeners that are to be notified...
List schedListeners = getSchedulerListeners();
// notify all scheduler listeners
java.util.Iterator itr = schedListeners.iterator();
while (itr.hasNext()) {
SchedulerListener sl = (SchedulerListener) itr.next();
try {
sl.schedulerShutdown();
} catch (Exception e) {
getLog().error(
"Error while notifying SchedulerListener of shutdown.",
e);
}
}
}
public void notifySchedulerListenersShuttingdown() {
// build a list of all job listeners that are to be notified...
List schedListeners = getSchedulerListeners();
// notify all scheduler listeners
java.util.Iterator itr = schedListeners.iterator();
while (itr.hasNext()) {
SchedulerListener sl = (SchedulerListener) itr.next();
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 job listeners that are to be notified...
List schedListeners = getSchedulerListeners();
// notify all scheduler listeners
java.util.Iterator itr = schedListeners.iterator();
while (itr.hasNext()) {
SchedulerListener sl = (SchedulerListener) itr.next();
try {
sl.jobAdded(jobDetail);
} catch (Exception e) {
getLog().error(
"Error while notifying SchedulerListener of JobAdded.",
e);
}
}
}
public void notifySchedulerListenersJobDeleted(String jobName, String groupName) {
// build a list of all job listeners that are to be notified...
List schedListeners = getSchedulerListeners();
// notify all scheduler listeners
java.util.Iterator itr = schedListeners.iterator();
while (itr.hasNext()) {
SchedulerListener sl = (SchedulerListener) itr.next();
try {
sl.jobDeleted(jobName, groupName);
} 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(org.quartz.core.SchedulingContext, java.lang.String, java.lang.String)
*/
public boolean interrupt(SchedulingContext ctxt, String jobName, String groupName) throws UnableToInterruptJobException {
if(groupName == null) {
groupName = Scheduler.DEFAULT_GROUP;
}
List jobs = getCurrentlyExecutingJobs();
java.util.Iterator it = jobs.iterator();
JobExecutionContext jec = null;
JobDetail jobDetail = null;
Job job = null;
boolean interrupted = false;
while (it.hasNext()) {
jec = (JobExecutionContext)it.next();
jobDetail = jec.getJobDetail();
if (jobName.equals(jobDetail.getName())
&& groupName.equals(jobDetail.getGroup())){
job = jec.getJobInstance();
if (job instanceof InterruptableJob) {
((InterruptableJob)job).interrupt();
interrupted = true;
} else {
throw new UnableToInterruptJobException(
"Job '"
+ jobName
+ "' of group '"
+ groupName
+ "' can not be interrupted, since it does not implement "
+ InterruptableJob.class.getName());
}
}
}
return interrupted;
}
private void shutdownPlugins() {
java.util.Iterator itr = resources.getSchedulerPlugins().iterator();
while (itr.hasNext()) {
SchedulerPlugin plugin = (SchedulerPlugin) itr.next();
plugin.shutdown();
}
}
private void startPlugins() {
java.util.Iterator itr = resources.getSchedulerPlugins().iterator();
while (itr.hasNext()) {
SchedulerPlugin plugin = (SchedulerPlugin) itr.next();
plugin.start();
}
}
}
/////////////////////////////////////////////////////////////////////////////
//
// ErrorLogger - Scheduler Listener Class
//
/////////////////////////////////////////////////////////////////////////////
class ErrorLogger extends SchedulerListenerSupport {
ErrorLogger() {
}
public void schedulerError(String msg, SchedulerException cause) {
getLog().error(msg, cause);
}
}
/////////////////////////////////////////////////////////////////////////////
//
// ExecutingJobsManager - Job Listener Class
//
/////////////////////////////////////////////////////////////////////////////
class ExecutingJobsManager implements JobListener {
HashMap executingJobs = new HashMap();
int numJobsFired = 0;
ExecutingJobsManager() {
}
public String getName() {
return getClass().getName();
}
public int getNumJobsCurrentlyExecuting() {
synchronized (executingJobs) {
return executingJobs.size();
}
}
public void jobToBeExecuted(JobExecutionContext context) {
numJobsFired++;
synchronized (executingJobs) {
executingJobs
.put(context.getTrigger().getFireInstanceId(), context);
}
}
public void jobWasExecuted(JobExecutionContext context,
JobExecutionException jobException) {
synchronized (executingJobs) {
executingJobs.remove(context.getTrigger().getFireInstanceId());
}
}
public int getNumJobsFired() {
return numJobsFired;
}
public List getExecutingJobs() {
synchronized (executingJobs) {
return java.util.Collections.unmodifiableList(new ArrayList(
executingJobs.values()));
}
}
public void jobExecutionVetoed(JobExecutionContext context) {
}
}