0001: /*
0002: * Copyright 2004-2005 OpenSymphony
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
0005: * use this file except in compliance with the License. You may obtain a copy
0006: * of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
0012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
0013: * License for the specific language governing permissions and limitations
0014: * under the License.
0015: *
0016: */
0017:
0018: /*
0019: * Previously Copyright (c) 2001-2004 James House
0020: */
0021: package org.quartz.core;
0022:
0023: import java.io.IOException;
0024: import java.io.InputStream;
0025: import java.rmi.RemoteException;
0026: import java.rmi.registry.LocateRegistry;
0027: import java.rmi.registry.Registry;
0028: import java.rmi.server.UnicastRemoteObject;
0029: import java.util.ArrayList;
0030: import java.util.Date;
0031: import java.util.HashMap;
0032: import java.util.HashSet;
0033: import java.util.LinkedList;
0034: import java.util.List;
0035: import java.util.Properties;
0036: import java.util.Random;
0037: import java.util.Set;
0038:
0039: import org.apache.commons.logging.Log;
0040: import org.apache.commons.logging.LogFactory;
0041: import org.quartz.Calendar;
0042: import org.quartz.InterruptableJob;
0043: import org.quartz.Job;
0044: import org.quartz.JobDataMap;
0045: import org.quartz.JobDetail;
0046: import org.quartz.JobExecutionContext;
0047: import org.quartz.JobExecutionException;
0048: import org.quartz.JobListener;
0049: import org.quartz.JobPersistenceException;
0050: import org.quartz.ObjectAlreadyExistsException;
0051: import org.quartz.Scheduler;
0052: import org.quartz.SchedulerContext;
0053: import org.quartz.SchedulerException;
0054: import org.quartz.SchedulerListener;
0055: import org.quartz.listeners.SchedulerListenerSupport;
0056: import org.quartz.Trigger;
0057: import org.quartz.TriggerListener;
0058: import org.quartz.UnableToInterruptJobException;
0059: import org.quartz.impl.SchedulerRepository;
0060: import org.quartz.simpl.SimpleJobFactory;
0061: import org.quartz.spi.JobFactory;
0062: import org.quartz.spi.SchedulerPlugin;
0063: import org.quartz.spi.SchedulerSignaler;
0064:
0065: /**
0066: * <p>
0067: * This is the heart of Quartz, an indirect implementation of the <code>{@link org.quartz.Scheduler}</code>
0068: * interface, containing methods to schedule <code>{@link org.quartz.Job}</code>s,
0069: * register <code>{@link org.quartz.JobListener}</code> instances, etc.
0070: * </p>// TODO: more docs...
0071: *
0072: * @see org.quartz.Scheduler
0073: * @see org.quartz.core.QuartzSchedulerThread
0074: * @see org.quartz.spi.JobStore
0075: * @see org.quartz.spi.ThreadPool
0076: *
0077: * @author James House
0078: */
0079: public class QuartzScheduler implements RemotableQuartzScheduler {
0080:
0081: /*
0082: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0083: *
0084: * Constants.
0085: *
0086: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0087: */
0088:
0089: private static String VERSION_MAJOR = "UNKNOWN";
0090: private static String VERSION_MINOR = "UNKNOWN";
0091: private static String VERSION_ITERATION = "UNKNOWN";
0092:
0093: static {
0094: Properties props = new Properties();
0095: try {
0096: InputStream is = QuartzScheduler.class
0097: .getResourceAsStream("/build.properties");
0098: if (is != null) {
0099: props.load(is);
0100: VERSION_MAJOR = props.getProperty("version.major");
0101: VERSION_MINOR = props.getProperty("version.minor");
0102: VERSION_ITERATION = props.getProperty("version.iter");
0103: }
0104: } catch (IOException e) {
0105: (LogFactory.getLog(QuartzScheduler.class))
0106: .error(
0107: "Error loading version info from build.properties.",
0108: e);
0109: }
0110: }
0111:
0112: /*
0113: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0114: *
0115: * Data members.
0116: *
0117: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0118: */
0119:
0120: private QuartzSchedulerResources resources;
0121:
0122: private QuartzSchedulerThread schedThread;
0123:
0124: private ThreadGroup threadGroup;
0125:
0126: private SchedulerContext context = new SchedulerContext();
0127:
0128: private HashMap jobListeners = new HashMap(10);
0129:
0130: private HashMap globalJobListeners = new HashMap(10);
0131:
0132: private HashMap triggerListeners = new HashMap(10);
0133:
0134: private HashMap globalTriggerListeners = new HashMap(10);
0135:
0136: private ArrayList schedulerListeners = new ArrayList(10);
0137:
0138: private JobFactory jobFactory = new SimpleJobFactory();
0139:
0140: ExecutingJobsManager jobMgr = null;
0141:
0142: ErrorLogger errLogger = null;
0143:
0144: private SchedulerSignaler signaler;
0145:
0146: private Random random = new Random();
0147:
0148: private ArrayList holdToPreventGC = new ArrayList(5);
0149:
0150: private boolean signalOnSchedulingChange = true;
0151:
0152: private boolean closed = false;
0153:
0154: private Date initialStart = null;
0155:
0156: private final Log log = LogFactory.getLog(getClass());
0157:
0158: /*
0159: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0160: *
0161: * Constructors.
0162: *
0163: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0164: */
0165:
0166: /**
0167: * <p>
0168: * Create a <code>QuartzScheduler</code> with the given configuration
0169: * properties.
0170: * </p>
0171: *
0172: * @see QuartzSchedulerResources
0173: */
0174: public QuartzScheduler(QuartzSchedulerResources resources,
0175: SchedulingContext ctxt, long idleWaitTime,
0176: long dbRetryInterval) throws SchedulerException {
0177: this .resources = resources;
0178: try {
0179: bind();
0180: } catch (Exception re) {
0181: throw new SchedulerException(
0182: "Unable to bind scheduler to RMI Registry.", re);
0183: }
0184:
0185: if (resources.getJMXExport()) {
0186: try {
0187: registerJMX();
0188: } catch (Exception e) {
0189: throw new SchedulerException(
0190: "Unable to register scheduler with MBeanServer.",
0191: e);
0192: }
0193: }
0194:
0195: this .schedThread = new QuartzSchedulerThread(this , resources,
0196: ctxt);
0197: if (idleWaitTime > 0) {
0198: this .schedThread.setIdleWaitTime(idleWaitTime);
0199: }
0200: if (dbRetryInterval > 0) {
0201: this .schedThread.setDbFailureRetryInterval(dbRetryInterval);
0202: }
0203:
0204: jobMgr = new ExecutingJobsManager();
0205: addGlobalJobListener(jobMgr);
0206: errLogger = new ErrorLogger();
0207: addSchedulerListener(errLogger);
0208:
0209: signaler = new SchedulerSignalerImpl(this );
0210:
0211: getLog().info(
0212: "Quartz Scheduler v." + getVersion() + " created.");
0213: }
0214:
0215: /*
0216: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0217: *
0218: * Interface.
0219: *
0220: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0221: */
0222:
0223: public String getVersion() {
0224: return getVersionMajor() + "." + getVersionMinor() + "."
0225: + getVersionIteration();
0226: }
0227:
0228: public static String getVersionMajor() {
0229: return VERSION_MAJOR;
0230: }
0231:
0232: public static String getVersionMinor() {
0233: return VERSION_MINOR;
0234: }
0235:
0236: public static String getVersionIteration() {
0237: return VERSION_ITERATION;
0238: }
0239:
0240: public SchedulerSignaler getSchedulerSignaler() {
0241: return signaler;
0242: }
0243:
0244: public Log getLog() {
0245: return log;
0246: }
0247:
0248: /**
0249: * Register the scheduler in the local MBeanServer.
0250: */
0251: private void registerJMX() throws Exception {
0252: org.apache.commons.modeler.Registry registry = org.apache.commons.modeler.Registry
0253: .getRegistry(null, null);
0254:
0255: String jmxObjectName = resources.getJMXObjectName();
0256:
0257: registry.registerComponent(this , jmxObjectName, null);
0258:
0259: getLog().info(
0260: "Scheduler registered with local MBeanServer under name '"
0261: + jmxObjectName + "'");
0262: }
0263:
0264: /**
0265: * Unregister the scheduler from the local MBeanServer.
0266: */
0267: private void unregisterJMX() throws Exception {
0268: org.apache.commons.modeler.Registry registry = org.apache.commons.modeler.Registry
0269: .getRegistry(null, null);
0270:
0271: String jmxObjectName = resources.getJMXObjectName();
0272:
0273: registry.unregisterComponent(jmxObjectName);
0274:
0275: getLog().info(
0276: "Scheduler unregistered from name '" + jmxObjectName
0277: + "' in the local MBeanServer.");
0278: }
0279:
0280: /**
0281: * <p>
0282: * Bind the scheduler to an RMI registry.
0283: * </p>
0284: */
0285: private void bind() throws RemoteException {
0286: String host = resources.getRMIRegistryHost();
0287: // don't export if we're not configured to do so...
0288: if (host == null || host.length() == 0) {
0289: return;
0290: }
0291:
0292: RemotableQuartzScheduler exportable = null;
0293:
0294: if (resources.getRMIServerPort() > 0) {
0295: exportable = (RemotableQuartzScheduler) UnicastRemoteObject
0296: .exportObject(this , resources.getRMIServerPort());
0297: } else {
0298: exportable = (RemotableQuartzScheduler) UnicastRemoteObject
0299: .exportObject(this );
0300: }
0301:
0302: Registry registry = null;
0303:
0304: if (resources.getRMICreateRegistryStrategy().equals(
0305: QuartzSchedulerResources.CREATE_REGISTRY_AS_NEEDED)) {
0306: try {
0307: // First try to get an existing one, instead of creating it,
0308: // since if
0309: // we're in a web-app being 'hot' re-depoloyed, then the JVM
0310: // still
0311: // has the registry that we created above the first time...
0312: registry = LocateRegistry.getRegistry(resources
0313: .getRMIRegistryPort());
0314: registry.list();
0315: } catch (Exception e) {
0316: registry = LocateRegistry.createRegistry(resources
0317: .getRMIRegistryPort());
0318: }
0319: } else if (resources.getRMICreateRegistryStrategy().equals(
0320: QuartzSchedulerResources.CREATE_REGISTRY_ALWAYS)) {
0321: try {
0322: registry = LocateRegistry.createRegistry(resources
0323: .getRMIRegistryPort());
0324: } catch (Exception e) {
0325: // Fall back to an existing one, instead of creating it, since
0326: // if
0327: // we're in a web-app being 'hot' re-depoloyed, then the JVM
0328: // still
0329: // has the registry that we created above the first time...
0330: registry = LocateRegistry.getRegistry(resources
0331: .getRMIRegistryPort());
0332: }
0333: } else {
0334: registry = LocateRegistry.getRegistry(resources
0335: .getRMIRegistryHost(), resources
0336: .getRMIRegistryPort());
0337: }
0338:
0339: String bindName = resources.getRMIBindName();
0340:
0341: registry.rebind(bindName, exportable);
0342:
0343: getLog().info(
0344: "Scheduler bound to RMI registry under name '"
0345: + bindName + "'");
0346: }
0347:
0348: /**
0349: * <p>
0350: * Un-bind the scheduler from an RMI registry.
0351: * </p>
0352: */
0353: private void unBind() throws RemoteException {
0354: String host = resources.getRMIRegistryHost();
0355: // don't un-export if we're not configured to do so...
0356: if (host == null || host.length() == 0) {
0357: return;
0358: }
0359:
0360: Registry registry = LocateRegistry.getRegistry(resources
0361: .getRMIRegistryHost(), resources.getRMIRegistryPort());
0362:
0363: String bindName = resources.getRMIBindName();
0364:
0365: try {
0366: registry.unbind(bindName);
0367: UnicastRemoteObject.unexportObject(this , true);
0368: } catch (java.rmi.NotBoundException nbe) {
0369: }
0370:
0371: getLog().info(
0372: "Scheduler un-bound from name '" + bindName
0373: + "' in RMI registry");
0374: }
0375:
0376: /**
0377: * <p>
0378: * Returns the name of the <code>QuartzScheduler</code>.
0379: * </p>
0380: */
0381: public String getSchedulerName() {
0382: return resources.getName();
0383: }
0384:
0385: /**
0386: * <p>
0387: * Returns the instance Id of the <code>QuartzScheduler</code>.
0388: * </p>
0389: */
0390: public String getSchedulerInstanceId() {
0391: return resources.getInstanceId();
0392: }
0393:
0394: /**
0395: * <p>
0396: * Returns the name of the <code>QuartzScheduler</code>.
0397: * </p>
0398: */
0399: public ThreadGroup getSchedulerThreadGroup() {
0400: if (threadGroup == null) {
0401: threadGroup = new ThreadGroup("QuartzScheduler:"
0402: + getSchedulerName());
0403: if (resources.getMakeSchedulerThreadDaemon()) {
0404: threadGroup.setDaemon(true);
0405: }
0406: }
0407:
0408: return threadGroup;
0409: }
0410:
0411: public void addNoGCObject(Object obj) {
0412: holdToPreventGC.add(obj);
0413: }
0414:
0415: public boolean removeNoGCObject(Object obj) {
0416: return holdToPreventGC.remove(obj);
0417: }
0418:
0419: /**
0420: * <p>
0421: * Returns the <code>SchedulerContext</code> of the <code>Scheduler</code>.
0422: * </p>
0423: */
0424: public SchedulerContext getSchedulerContext()
0425: throws SchedulerException {
0426: return context;
0427: }
0428:
0429: public boolean isSignalOnSchedulingChange() {
0430: return signalOnSchedulingChange;
0431: }
0432:
0433: public void setSignalOnSchedulingChange(
0434: boolean signalOnSchedulingChange) {
0435: this .signalOnSchedulingChange = signalOnSchedulingChange;
0436: }
0437:
0438: ///////////////////////////////////////////////////////////////////////////
0439: ///
0440: /// Schedululer State Management Methods
0441: ///
0442: ///////////////////////////////////////////////////////////////////////////
0443:
0444: /**
0445: * <p>
0446: * Starts the <code>QuartzScheduler</code>'s threads that fire <code>{@link org.quartz.Trigger}s</code>.
0447: * </p>
0448: *
0449: * <p>
0450: * All <code>{@link org.quartz.Trigger}s</code> that have misfired will
0451: * be passed to the appropriate TriggerListener(s).
0452: * </p>
0453: */
0454: public void start() throws SchedulerException {
0455:
0456: if (closed) {
0457: throw new SchedulerException(
0458: "The Scheduler cannot be restarted after shutdown() has been called.");
0459: }
0460:
0461: if (initialStart == null) {
0462: initialStart = new Date();
0463: this .resources.getJobStore().schedulerStarted();
0464: startPlugins();
0465: }
0466:
0467: schedThread.togglePause(false);
0468:
0469: getLog().info(
0470: "Scheduler " + resources.getUniqueIdentifier()
0471: + " started.");
0472: }
0473:
0474: /**
0475: * <p>
0476: * Temporarily halts the <code>QuartzScheduler</code>'s firing of <code>{@link org.quartz.Trigger}s</code>.
0477: * </p>
0478: *
0479: * <p>
0480: * The scheduler is not destroyed, and can be re-started at any time.
0481: * </p>
0482: */
0483: public void standby() {
0484: schedThread.togglePause(true);
0485: getLog().info(
0486: "Scheduler " + resources.getUniqueIdentifier()
0487: + " paused.");
0488: }
0489:
0490: /**
0491: * <p>
0492: * Reports whether the <code>Scheduler</code> is paused.
0493: * </p>
0494: */
0495: public boolean isInStandbyMode() {
0496: return schedThread.isPaused();
0497: }
0498:
0499: public Date runningSince() {
0500: return initialStart;
0501: }
0502:
0503: public int numJobsExecuted() {
0504: return jobMgr.getNumJobsFired();
0505: }
0506:
0507: public Class getJobStoreClass() {
0508: return resources.getJobStore().getClass();
0509: }
0510:
0511: public boolean supportsPersistence() {
0512: return resources.getJobStore().supportsPersistence();
0513: }
0514:
0515: public Class getThreadPoolClass() {
0516: return resources.getThreadPool().getClass();
0517: }
0518:
0519: public int getThreadPoolSize() {
0520: return resources.getThreadPool().getPoolSize();
0521: }
0522:
0523: /**
0524: * <p>
0525: * Halts the <code>QuartzScheduler</code>'s firing of <code>{@link org.quartz.Trigger}s</code>,
0526: * and cleans up all resources associated with the QuartzScheduler.
0527: * Equivalent to <code>shutdown(false)</code>.
0528: * </p>
0529: *
0530: * <p>
0531: * The scheduler cannot be re-started.
0532: * </p>
0533: */
0534: public void shutdown() {
0535: shutdown(false);
0536: }
0537:
0538: /**
0539: * <p>
0540: * Halts the <code>QuartzScheduler</code>'s firing of <code>{@link org.quartz.Trigger}s</code>,
0541: * and cleans up all resources associated with the QuartzScheduler.
0542: * </p>
0543: *
0544: * <p>
0545: * The scheduler cannot be re-started.
0546: * </p>
0547: *
0548: * @param waitForJobsToComplete
0549: * if <code>true</code> the scheduler will not allow this method
0550: * to return until all currently executing jobs have completed.
0551: */
0552: public void shutdown(boolean waitForJobsToComplete) {
0553:
0554: if (closed == true) {
0555: return;
0556: }
0557:
0558: getLog().info(
0559: "Scheduler " + resources.getUniqueIdentifier()
0560: + " shutting down.");
0561: standby();
0562:
0563: closed = true;
0564:
0565: schedThread.halt();
0566:
0567: resources.getThreadPool().shutdown(waitForJobsToComplete);
0568:
0569: if (waitForJobsToComplete) {
0570: while (jobMgr.getNumJobsCurrentlyExecuting() > 0) {
0571: try {
0572: Thread.sleep(100);
0573: } catch (Exception ignore) {
0574: }
0575: }
0576: }
0577:
0578: // Scheduler thread may have be waiting for the fire time of an acquired
0579: // trigger and need time to release the trigger once halted, so make sure
0580: // the thread is dead before continuing to shutdown the job store.
0581: try {
0582: schedThread.join();
0583: } catch (InterruptedException ignore) {
0584: }
0585:
0586: resources.getJobStore().shutdown();
0587:
0588: notifySchedulerListenersShutdown();
0589:
0590: shutdownPlugins();
0591:
0592: SchedulerRepository.getInstance().remove(resources.getName());
0593:
0594: holdToPreventGC.clear();
0595:
0596: try {
0597: unBind();
0598: } catch (RemoteException re) {
0599: }
0600:
0601: if (resources.getJMXExport()) {
0602: try {
0603: unregisterJMX();
0604: } catch (Exception e) {
0605: }
0606: }
0607:
0608: getLog().info(
0609: "Scheduler " + resources.getUniqueIdentifier()
0610: + " shutdown complete.");
0611: }
0612:
0613: /**
0614: * <p>
0615: * Reports whether the <code>Scheduler</code> has been shutdown.
0616: * </p>
0617: */
0618: public boolean isShutdown() {
0619: return closed;
0620: }
0621:
0622: public void validateState() throws SchedulerException {
0623: if (isShutdown()) {
0624: throw new SchedulerException(
0625: "The Scheduler has been shutdown.");
0626: }
0627:
0628: // other conditions to check (?)
0629: }
0630:
0631: /**
0632: * <p>
0633: * Return a list of <code>JobExecutionContext</code> objects that
0634: * represent all currently executing Jobs in this Scheduler instance.
0635: * </p>
0636: *
0637: * <p>
0638: * This method is not cluster aware. That is, it will only return Jobs
0639: * currently executing in this Scheduler instance, not across the entire
0640: * cluster.
0641: * </p>
0642: *
0643: * <p>
0644: * Note that the list returned is an 'instantaneous' snap-shot, and that as
0645: * soon as it's returned, the true list of executing jobs may be different.
0646: * </p>
0647: */
0648: public List getCurrentlyExecutingJobs() {
0649: return jobMgr.getExecutingJobs();
0650: }
0651:
0652: ///////////////////////////////////////////////////////////////////////////
0653: ///
0654: /// Scheduling-related Methods
0655: ///
0656: ///////////////////////////////////////////////////////////////////////////
0657:
0658: /**
0659: * <p>
0660: * Add the <code>{@link org.quartz.Job}</code> identified by the given
0661: * <code>{@link org.quartz.JobDetail}</code> to the Scheduler, and
0662: * associate the given <code>{@link org.quartz.Trigger}</code> with it.
0663: * </p>
0664: *
0665: * <p>
0666: * If the given Trigger does not reference any <code>Job</code>, then it
0667: * will be set to reference the Job passed with it into this method.
0668: * </p>
0669: *
0670: * @throws SchedulerException
0671: * if the Job or Trigger cannot be added to the Scheduler, or
0672: * there is an internal Scheduler error.
0673: */
0674: public Date scheduleJob(SchedulingContext ctxt,
0675: JobDetail jobDetail, Trigger trigger)
0676: throws SchedulerException {
0677: validateState();
0678:
0679: if (jobDetail == null) {
0680: throw new SchedulerException("JobDetail cannot be null",
0681: SchedulerException.ERR_CLIENT_ERROR);
0682: }
0683:
0684: if (trigger == null) {
0685: throw new SchedulerException("Trigger cannot be null",
0686: SchedulerException.ERR_CLIENT_ERROR);
0687: }
0688:
0689: jobDetail.validate();
0690:
0691: if (trigger.getJobName() == null) {
0692: trigger.setJobName(jobDetail.getName());
0693: trigger.setJobGroup(jobDetail.getGroup());
0694: } else if (trigger.getJobName() != null
0695: && !trigger.getJobName().equals(jobDetail.getName())) {
0696: throw new SchedulerException(
0697: "Trigger does not reference given job!",
0698: SchedulerException.ERR_CLIENT_ERROR);
0699: } else if (trigger.getJobGroup() != null
0700: && !trigger.getJobGroup().equals(jobDetail.getGroup())) {
0701: throw new SchedulerException(
0702: "Trigger does not reference given job!",
0703: SchedulerException.ERR_CLIENT_ERROR);
0704: }
0705:
0706: trigger.validate();
0707:
0708: Calendar cal = null;
0709: if (trigger.getCalendarName() != null) {
0710: cal = resources.getJobStore().retrieveCalendar(ctxt,
0711: trigger.getCalendarName());
0712: }
0713: Date ft = trigger.computeFirstFireTime(cal);
0714:
0715: if (ft == null) {
0716: throw new SchedulerException(
0717: "Based on configured schedule, the given trigger will never fire.",
0718: SchedulerException.ERR_CLIENT_ERROR);
0719: }
0720:
0721: resources.getJobStore().storeJobAndTrigger(ctxt, jobDetail,
0722: trigger);
0723: notifySchedulerThread();
0724: notifySchedulerListenersSchduled(trigger);
0725:
0726: return ft;
0727: }
0728:
0729: /**
0730: * <p>
0731: * Schedule the given <code>{@link org.quartz.Trigger}</code> with the
0732: * <code>Job</code> identified by the <code>Trigger</code>'s settings.
0733: * </p>
0734: *
0735: * @throws SchedulerException
0736: * if the indicated Job does not exist, or the Trigger cannot be
0737: * added to the Scheduler, or there is an internal Scheduler
0738: * error.
0739: */
0740: public Date scheduleJob(SchedulingContext ctxt, Trigger trigger)
0741: throws SchedulerException {
0742: validateState();
0743:
0744: if (trigger == null) {
0745: throw new SchedulerException("Trigger cannot be null",
0746: SchedulerException.ERR_CLIENT_ERROR);
0747: }
0748:
0749: trigger.validate();
0750:
0751: Calendar cal = null;
0752: if (trigger.getCalendarName() != null) {
0753: cal = resources.getJobStore().retrieveCalendar(ctxt,
0754: trigger.getCalendarName());
0755: if (cal == null) {
0756: throw new SchedulerException(
0757: "Calendar not found: "
0758: + trigger.getCalendarName(),
0759: SchedulerException.ERR_PERSISTENCE_CALENDAR_DOES_NOT_EXIST);
0760: }
0761: }
0762: Date ft = trigger.computeFirstFireTime(cal);
0763:
0764: if (ft == null) {
0765: throw new SchedulerException(
0766: "Based on configured schedule, the given trigger will never fire.",
0767: SchedulerException.ERR_CLIENT_ERROR);
0768: }
0769:
0770: resources.getJobStore().storeTrigger(ctxt, trigger, false);
0771: notifySchedulerThread();
0772: notifySchedulerListenersSchduled(trigger);
0773:
0774: return ft;
0775: }
0776:
0777: /**
0778: * <p>
0779: * Add the given <code>Job</code> to the Scheduler - with no associated
0780: * <code>Trigger</code>. The <code>Job</code> will be 'dormant' until
0781: * it is scheduled with a <code>Trigger</code>, or <code>Scheduler.triggerJob()</code>
0782: * is called for it.
0783: * </p>
0784: *
0785: * <p>
0786: * The <code>Job</code> must by definition be 'durable', if it is not,
0787: * SchedulerException will be thrown.
0788: * </p>
0789: *
0790: * @throws SchedulerException
0791: * if there is an internal Scheduler error, or if the Job is not
0792: * durable, or a Job with the same name already exists, and
0793: * <code>replace</code> is <code>false</code>.
0794: */
0795: public void addJob(SchedulingContext ctxt, JobDetail jobDetail,
0796: boolean replace) throws SchedulerException {
0797: validateState();
0798:
0799: if (!jobDetail.isDurable() && !replace) {
0800: throw new SchedulerException(
0801: "Jobs added with no trigger must be durable.",
0802: SchedulerException.ERR_CLIENT_ERROR);
0803: }
0804:
0805: resources.getJobStore().storeJob(ctxt, jobDetail, replace);
0806: }
0807:
0808: /**
0809: * <p>
0810: * Delete the identified <code>Job</code> from the Scheduler - and any
0811: * associated <code>Trigger</code>s.
0812: * </p>
0813: *
0814: * @return true if the Job was found and deleted.
0815: * @throws SchedulerException
0816: * if there is an internal Scheduler error.
0817: */
0818: public boolean deleteJob(SchedulingContext ctxt, String jobName,
0819: String groupName) throws SchedulerException {
0820: validateState();
0821:
0822: if (groupName == null) {
0823: groupName = Scheduler.DEFAULT_GROUP;
0824: }
0825:
0826: return resources.getJobStore().removeJob(ctxt, jobName,
0827: groupName);
0828: }
0829:
0830: /**
0831: * <p>
0832: * Remove the indicated <code>{@link org.quartz.Trigger}</code> from the
0833: * scheduler.
0834: * </p>
0835: */
0836: public boolean unscheduleJob(SchedulingContext ctxt,
0837: String triggerName, String groupName)
0838: throws SchedulerException {
0839: validateState();
0840:
0841: if (groupName == null) {
0842: groupName = Scheduler.DEFAULT_GROUP;
0843: }
0844:
0845: if (resources.getJobStore().removeTrigger(ctxt, triggerName,
0846: groupName)) {
0847: notifySchedulerThread();
0848: notifySchedulerListenersUnschduled(triggerName, groupName);
0849: } else {
0850: return false;
0851: }
0852:
0853: return true;
0854: }
0855:
0856: /**
0857: * <p>
0858: * Remove (delete) the <code>{@link org.quartz.Trigger}</code> with the
0859: * given name, and store the new given one - which must be associated
0860: * with the same job.
0861: * </p>
0862: *
0863: * @param triggerName
0864: * The name of the <code>Trigger</code> to be removed.
0865: * @param groupName
0866: * The group name of the <code>Trigger</code> to be removed.
0867: * @param newTrigger
0868: * The new <code>Trigger</code> to be stored.
0869: * @return <code>null</code> if a <code>Trigger</code> with the given
0870: * name & group was not found and removed from the store, otherwise
0871: * the first fire time of the newly scheduled trigger.
0872: */
0873: public Date rescheduleJob(SchedulingContext ctxt,
0874: String triggerName, String groupName, Trigger newTrigger)
0875: throws SchedulerException {
0876: validateState();
0877:
0878: if (groupName == null) {
0879: groupName = Scheduler.DEFAULT_GROUP;
0880: }
0881:
0882: newTrigger.validate();
0883:
0884: Calendar cal = null;
0885: if (newTrigger.getCalendarName() != null) {
0886: cal = resources.getJobStore().retrieveCalendar(ctxt,
0887: newTrigger.getCalendarName());
0888: }
0889: Date ft = newTrigger.computeFirstFireTime(cal);
0890:
0891: if (ft == null) {
0892: throw new SchedulerException(
0893: "Based on configured schedule, the given trigger will never fire.",
0894: SchedulerException.ERR_CLIENT_ERROR);
0895: }
0896:
0897: if (resources.getJobStore().replaceTrigger(ctxt, triggerName,
0898: groupName, newTrigger)) {
0899: notifySchedulerThread();
0900: notifySchedulerListenersUnschduled(triggerName, groupName);
0901: notifySchedulerListenersSchduled(newTrigger);
0902: } else {
0903: return null;
0904: }
0905:
0906: return ft;
0907:
0908: }
0909:
0910: private String newTriggerId() {
0911: long r = random.nextLong();
0912: if (r < 0) {
0913: r = -r;
0914: }
0915: return "MT_"
0916: + Long.toString(r, 30 + (int) (System
0917: .currentTimeMillis() % 7));
0918: }
0919:
0920: /**
0921: * <p>
0922: * Trigger the identified <code>{@link org.quartz.Job}</code> (execute it
0923: * now) - with a non-volatile trigger.
0924: * </p>
0925: */
0926: public void triggerJob(SchedulingContext ctxt, String jobName,
0927: String groupName, JobDataMap data)
0928: throws SchedulerException {
0929: validateState();
0930:
0931: if (groupName == null) {
0932: groupName = Scheduler.DEFAULT_GROUP;
0933: }
0934:
0935: Trigger trig = new org.quartz.SimpleTrigger(newTriggerId(),
0936: Scheduler.DEFAULT_MANUAL_TRIGGERS, jobName, groupName,
0937: new Date(), null, 0, 0);
0938: trig.setVolatility(false);
0939: trig.computeFirstFireTime(null);
0940: if (data != null) {
0941: trig.setJobDataMap(data);
0942: }
0943:
0944: boolean collision = true;
0945: while (collision) {
0946: try {
0947: resources.getJobStore().storeTrigger(ctxt, trig, false);
0948: collision = false;
0949: } catch (ObjectAlreadyExistsException oaee) {
0950: trig.setName(newTriggerId());
0951: }
0952: }
0953:
0954: notifySchedulerThread();
0955: notifySchedulerListenersSchduled(trig);
0956: }
0957:
0958: /**
0959: * <p>
0960: * Trigger the identified <code>{@link org.quartz.Job}</code> (execute it
0961: * now) - with a volatile trigger.
0962: * </p>
0963: */
0964: public void triggerJobWithVolatileTrigger(SchedulingContext ctxt,
0965: String jobName, String groupName, JobDataMap data)
0966: throws SchedulerException {
0967: validateState();
0968:
0969: if (groupName == null) {
0970: groupName = Scheduler.DEFAULT_GROUP;
0971: }
0972:
0973: Trigger trig = new org.quartz.SimpleTrigger(newTriggerId(),
0974: Scheduler.DEFAULT_MANUAL_TRIGGERS, jobName, groupName,
0975: new Date(), null, 0, 0);
0976: trig.setVolatility(true);
0977: trig.computeFirstFireTime(null);
0978: if (data != null) {
0979: trig.setJobDataMap(data);
0980: }
0981:
0982: boolean collision = true;
0983: while (collision) {
0984: try {
0985: resources.getJobStore().storeTrigger(ctxt, trig, false);
0986: collision = false;
0987: } catch (ObjectAlreadyExistsException oaee) {
0988: trig.setName(newTriggerId());
0989: }
0990: }
0991:
0992: notifySchedulerThread();
0993: notifySchedulerListenersSchduled(trig);
0994: }
0995:
0996: /**
0997: * <p>
0998: * Pause the <code>{@link Trigger}</code> with the given name.
0999: * </p>
1000: *
1001: */
1002: public void pauseTrigger(SchedulingContext ctxt,
1003: String triggerName, String groupName)
1004: throws SchedulerException {
1005: validateState();
1006:
1007: if (groupName == null) {
1008: groupName = Scheduler.DEFAULT_GROUP;
1009: }
1010:
1011: resources.getJobStore().pauseTrigger(ctxt, triggerName,
1012: groupName);
1013: notifySchedulerThread();
1014: notifySchedulerListenersPausedTrigger(triggerName, groupName);
1015: }
1016:
1017: /**
1018: * <p>
1019: * Pause all of the <code>{@link Trigger}s</code> in the given group.
1020: * </p>
1021: *
1022: */
1023: public void pauseTriggerGroup(SchedulingContext ctxt,
1024: String groupName) throws SchedulerException {
1025: validateState();
1026:
1027: if (groupName == null) {
1028: groupName = Scheduler.DEFAULT_GROUP;
1029: }
1030:
1031: resources.getJobStore().pauseTriggerGroup(ctxt, groupName);
1032: notifySchedulerThread();
1033: notifySchedulerListenersPausedTrigger(null, groupName);
1034: }
1035:
1036: /**
1037: * <p>
1038: * Pause the <code>{@link org.quartz.JobDetail}</code> with the given
1039: * name - by pausing all of its current <code>Trigger</code>s.
1040: * </p>
1041: *
1042: */
1043: public void pauseJob(SchedulingContext ctxt, String jobName,
1044: String groupName) throws SchedulerException {
1045: validateState();
1046:
1047: if (groupName == null) {
1048: groupName = Scheduler.DEFAULT_GROUP;
1049: }
1050:
1051: resources.getJobStore().pauseJob(ctxt, jobName, groupName);
1052: notifySchedulerThread();
1053: notifySchedulerListenersPausedJob(jobName, groupName);
1054: }
1055:
1056: /**
1057: * <p>
1058: * Pause all of the <code>{@link org.quartz.JobDetail}s</code> in the
1059: * given group - by pausing all of their <code>Trigger</code>s.
1060: * </p>
1061: *
1062: */
1063: public void pauseJobGroup(SchedulingContext ctxt, String groupName)
1064: throws SchedulerException {
1065: validateState();
1066:
1067: if (groupName == null) {
1068: groupName = Scheduler.DEFAULT_GROUP;
1069: }
1070:
1071: resources.getJobStore().pauseJobGroup(ctxt, groupName);
1072: notifySchedulerThread();
1073: notifySchedulerListenersPausedJob(null, groupName);
1074: }
1075:
1076: /**
1077: * <p>
1078: * Resume (un-pause) the <code>{@link Trigger}</code> with the given
1079: * name.
1080: * </p>
1081: *
1082: * <p>
1083: * If the <code>Trigger</code> missed one or more fire-times, then the
1084: * <code>Trigger</code>'s misfire instruction will be applied.
1085: * </p>
1086: *
1087: */
1088: public void resumeTrigger(SchedulingContext ctxt,
1089: String triggerName, String groupName)
1090: throws SchedulerException {
1091: validateState();
1092:
1093: if (groupName == null) {
1094: groupName = Scheduler.DEFAULT_GROUP;
1095: }
1096:
1097: resources.getJobStore().resumeTrigger(ctxt, triggerName,
1098: groupName);
1099: notifySchedulerThread();
1100: notifySchedulerListenersResumedTrigger(triggerName, groupName);
1101: }
1102:
1103: /**
1104: * <p>
1105: * Resume (un-pause) all of the <code>{@link Trigger}s</code> in the
1106: * given group.
1107: * </p>
1108: *
1109: * <p>
1110: * If any <code>Trigger</code> missed one or more fire-times, then the
1111: * <code>Trigger</code>'s misfire instruction will be applied.
1112: * </p>
1113: *
1114: */
1115: public void resumeTriggerGroup(SchedulingContext ctxt,
1116: String groupName) throws SchedulerException {
1117: validateState();
1118:
1119: if (groupName == null) {
1120: groupName = Scheduler.DEFAULT_GROUP;
1121: }
1122:
1123: resources.getJobStore().resumeTriggerGroup(ctxt, groupName);
1124: notifySchedulerThread();
1125: notifySchedulerListenersResumedTrigger(null, groupName);
1126: }
1127:
1128: public Set getPausedTriggerGroups(SchedulingContext ctxt)
1129: throws SchedulerException {
1130: return resources.getJobStore().getPausedTriggerGroups(ctxt);
1131: }
1132:
1133: /**
1134: * <p>
1135: * Resume (un-pause) the <code>{@link org.quartz.JobDetail}</code> with
1136: * the given name.
1137: * </p>
1138: *
1139: * <p>
1140: * If any of the <code>Job</code>'s<code>Trigger</code> s missed one
1141: * or more fire-times, then the <code>Trigger</code>'s misfire
1142: * instruction will be applied.
1143: * </p>
1144: *
1145: */
1146: public void resumeJob(SchedulingContext ctxt, String jobName,
1147: String groupName) throws SchedulerException {
1148: validateState();
1149:
1150: if (groupName == null) {
1151: groupName = Scheduler.DEFAULT_GROUP;
1152: }
1153:
1154: resources.getJobStore().resumeJob(ctxt, jobName, groupName);
1155: notifySchedulerThread();
1156: notifySchedulerListenersResumedJob(jobName, groupName);
1157: }
1158:
1159: /**
1160: * <p>
1161: * Resume (un-pause) all of the <code>{@link org.quartz.JobDetail}s</code>
1162: * in the given group.
1163: * </p>
1164: *
1165: * <p>
1166: * If any of the <code>Job</code> s had <code>Trigger</code> s that
1167: * missed one or more fire-times, then the <code>Trigger</code>'s
1168: * misfire instruction will be applied.
1169: * </p>
1170: *
1171: */
1172: public void resumeJobGroup(SchedulingContext ctxt, String groupName)
1173: throws SchedulerException {
1174: validateState();
1175:
1176: if (groupName == null) {
1177: groupName = Scheduler.DEFAULT_GROUP;
1178: }
1179:
1180: resources.getJobStore().resumeJobGroup(ctxt, groupName);
1181: notifySchedulerThread();
1182: notifySchedulerListenersResumedJob(null, groupName);
1183: }
1184:
1185: /**
1186: * <p>
1187: * Pause all triggers - equivalent of calling <code>pauseTriggerGroup(group)</code>
1188: * on every group.
1189: * </p>
1190: *
1191: * <p>
1192: * When <code>resumeAll()</code> is called (to un-pause), trigger misfire
1193: * instructions WILL be applied.
1194: * </p>
1195: *
1196: * @see #resumeAll(SchedulingContext)
1197: * @see #pauseTriggerGroup(SchedulingContext, String)
1198: * @see #standby()
1199: */
1200: public void pauseAll(SchedulingContext ctxt)
1201: throws SchedulerException {
1202: validateState();
1203:
1204: resources.getJobStore().pauseAll(ctxt);
1205: notifySchedulerThread();
1206: notifySchedulerListenersPausedTrigger(null, null);
1207: }
1208:
1209: /**
1210: * <p>
1211: * Resume (un-pause) all triggers - equivalent of calling <code>resumeTriggerGroup(group)</code>
1212: * on every group.
1213: * </p>
1214: *
1215: * <p>
1216: * If any <code>Trigger</code> missed one or more fire-times, then the
1217: * <code>Trigger</code>'s misfire instruction will be applied.
1218: * </p>
1219: *
1220: * @see #pauseAll(SchedulingContext)
1221: */
1222: public void resumeAll(SchedulingContext ctxt)
1223: throws SchedulerException {
1224: validateState();
1225:
1226: resources.getJobStore().resumeAll(ctxt);
1227: notifySchedulerThread();
1228: notifySchedulerListenersResumedTrigger(null, null);
1229: }
1230:
1231: /**
1232: * <p>
1233: * Get the names of all known <code>{@link org.quartz.Job}</code> groups.
1234: * </p>
1235: */
1236: public String[] getJobGroupNames(SchedulingContext ctxt)
1237: throws SchedulerException {
1238: validateState();
1239:
1240: return resources.getJobStore().getJobGroupNames(ctxt);
1241: }
1242:
1243: /**
1244: * <p>
1245: * Get the names of all the <code>{@link org.quartz.Job}s</code> in the
1246: * given group.
1247: * </p>
1248: */
1249: public String[] getJobNames(SchedulingContext ctxt, String groupName)
1250: throws SchedulerException {
1251: validateState();
1252:
1253: if (groupName == null) {
1254: groupName = Scheduler.DEFAULT_GROUP;
1255: }
1256:
1257: return resources.getJobStore().getJobNames(ctxt, groupName);
1258: }
1259:
1260: /**
1261: * <p>
1262: * Get all <code>{@link Trigger}</code> s that are associated with the
1263: * identified <code>{@link org.quartz.JobDetail}</code>.
1264: * </p>
1265: */
1266: public Trigger[] getTriggersOfJob(SchedulingContext ctxt,
1267: String jobName, String groupName) throws SchedulerException {
1268: validateState();
1269:
1270: if (groupName == null) {
1271: groupName = Scheduler.DEFAULT_GROUP;
1272: }
1273:
1274: return resources.getJobStore().getTriggersForJob(ctxt, jobName,
1275: groupName);
1276: }
1277:
1278: /**
1279: * <p>
1280: * Get the names of all known <code>{@link org.quartz.Trigger}</code>
1281: * groups.
1282: * </p>
1283: */
1284: public String[] getTriggerGroupNames(SchedulingContext ctxt)
1285: throws SchedulerException {
1286: validateState();
1287:
1288: return resources.getJobStore().getTriggerGroupNames(ctxt);
1289: }
1290:
1291: /**
1292: * <p>
1293: * Get the names of all the <code>{@link org.quartz.Trigger}s</code> in
1294: * the given group.
1295: * </p>
1296: */
1297: public String[] getTriggerNames(SchedulingContext ctxt,
1298: String groupName) throws SchedulerException {
1299: validateState();
1300:
1301: if (groupName == null) {
1302: groupName = Scheduler.DEFAULT_GROUP;
1303: }
1304:
1305: return resources.getJobStore().getTriggerNames(ctxt, groupName);
1306: }
1307:
1308: /**
1309: * <p>
1310: * Get the <code>{@link JobDetail}</code> for the <code>Job</code>
1311: * instance with the given name and group.
1312: * </p>
1313: */
1314: public JobDetail getJobDetail(SchedulingContext ctxt,
1315: String jobName, String jobGroup) throws SchedulerException {
1316: validateState();
1317:
1318: if (jobGroup == null) {
1319: jobGroup = Scheduler.DEFAULT_GROUP;
1320: }
1321:
1322: return resources.getJobStore().retrieveJob(ctxt, jobName,
1323: jobGroup);
1324: }
1325:
1326: /**
1327: * <p>
1328: * Get the <code>{@link Trigger}</code> instance with the given name and
1329: * group.
1330: * </p>
1331: */
1332: public Trigger getTrigger(SchedulingContext ctxt,
1333: String triggerName, String triggerGroup)
1334: throws SchedulerException {
1335: validateState();
1336:
1337: if (triggerGroup == null) {
1338: triggerGroup = Scheduler.DEFAULT_GROUP;
1339: }
1340:
1341: return resources.getJobStore().retrieveTrigger(ctxt,
1342: triggerName, triggerGroup);
1343: }
1344:
1345: /**
1346: * <p>
1347: * Get the current state of the identified <code>{@link Trigger}</code>.
1348: * </p>
1349: *
1350: * @see Trigger#STATE_NORMAL
1351: * @see Trigger#STATE_PAUSED
1352: * @see Trigger#STATE_COMPLETE
1353: * @see Trigger#STATE_ERROR
1354: */
1355: public int getTriggerState(SchedulingContext ctxt,
1356: String triggerName, String triggerGroup)
1357: throws SchedulerException {
1358: validateState();
1359:
1360: if (triggerGroup == null) {
1361: triggerGroup = Scheduler.DEFAULT_GROUP;
1362: }
1363:
1364: return resources.getJobStore().getTriggerState(ctxt,
1365: triggerName, triggerGroup);
1366: }
1367:
1368: /**
1369: * <p>
1370: * Add (register) the given <code>Calendar</code> to the Scheduler.
1371: * </p>
1372: *
1373: * @throws SchedulerException
1374: * if there is an internal Scheduler error, or a Calendar with
1375: * the same name already exists, and <code>replace</code> is
1376: * <code>false</code>.
1377: */
1378: public void addCalendar(SchedulingContext ctxt, String calName,
1379: Calendar calendar, boolean replace, boolean updateTriggers)
1380: throws SchedulerException {
1381: validateState();
1382:
1383: resources.getJobStore().storeCalendar(ctxt, calName, calendar,
1384: replace, updateTriggers);
1385: }
1386:
1387: /**
1388: * <p>
1389: * Delete the identified <code>Calendar</code> from the Scheduler.
1390: * </p>
1391: *
1392: * @return true if the Calendar was found and deleted.
1393: * @throws SchedulerException
1394: * if there is an internal Scheduler error.
1395: */
1396: public boolean deleteCalendar(SchedulingContext ctxt, String calName)
1397: throws SchedulerException {
1398: validateState();
1399:
1400: return resources.getJobStore().removeCalendar(ctxt, calName);
1401: }
1402:
1403: /**
1404: * <p>
1405: * Get the <code>{@link Calendar}</code> instance with the given name.
1406: * </p>
1407: */
1408: public Calendar getCalendar(SchedulingContext ctxt, String calName)
1409: throws SchedulerException {
1410: validateState();
1411:
1412: return resources.getJobStore().retrieveCalendar(ctxt, calName);
1413: }
1414:
1415: /**
1416: * <p>
1417: * Get the names of all registered <code>{@link Calendar}s</code>.
1418: * </p>
1419: */
1420: public String[] getCalendarNames(SchedulingContext ctxt)
1421: throws SchedulerException {
1422: validateState();
1423:
1424: return resources.getJobStore().getCalendarNames(ctxt);
1425: }
1426:
1427: /**
1428: * <p>
1429: * Add the given <code>{@link org.quartz.JobListener}</code> to the
1430: * <code>Scheduler</code>'s<i>global</i> list.
1431: * </p>
1432: *
1433: * <p>
1434: * Listeners in the 'global' list receive notification of execution events
1435: * for ALL <code>{@link org.quartz.Job}</code>s.
1436: * </p>
1437: */
1438: public void addGlobalJobListener(JobListener jobListener) {
1439: if (jobListener.getName() == null
1440: || jobListener.getName().length() == 0) {
1441: throw new IllegalArgumentException(
1442: "JobListener name cannot be empty.");
1443: }
1444:
1445: synchronized (globalJobListeners) {
1446: globalJobListeners.put(jobListener.getName(), jobListener);
1447: }
1448: }
1449:
1450: /**
1451: * <p>
1452: * Add the given <code>{@link org.quartz.JobListener}</code> to the
1453: * <code>Scheduler</code>'s list, of registered <code>JobListener</code>s.
1454: */
1455: public void addJobListener(JobListener jobListener) {
1456: if (jobListener.getName() == null
1457: || jobListener.getName().length() == 0) {
1458: throw new IllegalArgumentException(
1459: "JobListener name cannot be empty.");
1460: }
1461:
1462: synchronized (jobListeners) {
1463: jobListeners.put(jobListener.getName(), jobListener);
1464: }
1465: }
1466:
1467: /**
1468: * <p>
1469: * Remove the given <code>{@link org.quartz.JobListener}</code> from the
1470: * <code>Scheduler</code>'s list of <i>global</i> listeners.
1471: * </p>
1472: *
1473: * @return true if the identifed listener was found in the list, and
1474: * removed.
1475: *
1476: * @deprecated Use <code>{@link #removeGlobalJobListener(String)}</code>
1477: */
1478: public boolean removeGlobalJobListener(JobListener jobListener) {
1479: return removeGlobalJobListener((jobListener == null) ? null
1480: : jobListener.getName());
1481: }
1482:
1483: /**
1484: * <p>
1485: * Remove the identifed <code>{@link JobListener}</code> from the <code>Scheduler</code>'s
1486: * list of <i>global</i> listeners.
1487: * </p>
1488: *
1489: * @return true if the identifed listener was found in the list, and
1490: * removed.
1491: */
1492: public boolean removeGlobalJobListener(String name) {
1493: synchronized (globalJobListeners) {
1494: return (globalJobListeners.remove(name) != null);
1495: }
1496: }
1497:
1498: /**
1499: * <p>
1500: * Remove the identifed <code>{@link org.quartz.JobListener}</code> from
1501: * the <code>Scheduler</code>'s list of registered listeners.
1502: * </p>
1503: *
1504: * @return true if the identifed listener was found in the list, and
1505: * removed.
1506: */
1507: public boolean removeJobListener(String name) {
1508: synchronized (jobListeners) {
1509: return (jobListeners.remove(name) != null);
1510: }
1511: }
1512:
1513: /**
1514: * <p>
1515: * Get a List containing all of the <code>{@link org.quartz.JobListener}</code>
1516: * s in the <code>Scheduler</code>'s<i>global</i> list.
1517: * </p>
1518: */
1519: public List getGlobalJobListeners() {
1520: synchronized (globalJobListeners) {
1521: return new LinkedList(globalJobListeners.values());
1522: }
1523: }
1524:
1525: /**
1526: * <p>
1527: * Get a Set containing the names of all the <i>non-global</i><code>{@link org.quartz.JobListener}</code>
1528: * s registered with the <code>Scheduler</code>.
1529: * </p>
1530: */
1531: public Set getJobListenerNames() {
1532: synchronized (jobListeners) {
1533: return new HashSet(jobListeners.keySet());
1534: }
1535: }
1536:
1537: /**
1538: * <p>
1539: * Get the <i>global</i><code>{@link org.quartz.JobListener}</code>
1540: * that has the given name.
1541: * </p>
1542: */
1543: public JobListener getGlobalJobListener(String name) {
1544: synchronized (globalJobListeners) {
1545: return (JobListener) globalJobListeners.get(name);
1546: }
1547: }
1548:
1549: /**
1550: * <p>
1551: * Get the <i>non-global</i><code>{@link org.quartz.JobListener}</code>
1552: * that has the given name.
1553: * </p>
1554: */
1555: public JobListener getJobListener(String name) {
1556: synchronized (jobListeners) {
1557: return (JobListener) jobListeners.get(name);
1558: }
1559: }
1560:
1561: /**
1562: * <p>
1563: * Add the given <code>{@link org.quartz.TriggerListener}</code> to the
1564: * <code>Scheduler</code>'s<i>global</i> list.
1565: * </p>
1566: *
1567: * <p>
1568: * Listeners in the 'global' list receive notification of execution events
1569: * for ALL <code>{@link org.quartz.Trigger}</code>s.
1570: * </p>
1571: */
1572: public void addGlobalTriggerListener(TriggerListener triggerListener) {
1573: if (triggerListener.getName() == null
1574: || triggerListener.getName().length() == 0) {
1575: throw new IllegalArgumentException(
1576: "TriggerListener name cannot be empty.");
1577: }
1578:
1579: synchronized (globalTriggerListeners) {
1580: globalTriggerListeners.put(triggerListener.getName(),
1581: triggerListener);
1582: }
1583: }
1584:
1585: /**
1586: * <p>
1587: * Add the given <code>{@link org.quartz.TriggerListener}</code> to the
1588: * <code>Scheduler</code>'s list, of registered <code>TriggerListener</code>s.
1589: */
1590: public void addTriggerListener(TriggerListener triggerListener) {
1591: if (triggerListener.getName() == null
1592: || triggerListener.getName().length() == 0) {
1593: throw new IllegalArgumentException(
1594: "TriggerListener name cannot be empty.");
1595: }
1596:
1597: synchronized (triggerListeners) {
1598: triggerListeners.put(triggerListener.getName(),
1599: triggerListener);
1600: }
1601: }
1602:
1603: /**
1604: * <p>
1605: * Remove the given <code>{@link org.quartz.TriggerListener}</code> from
1606: * the <code>Scheduler</code>'s list of <i>global</i> listeners.
1607: * </p>
1608: *
1609: * @return true if the identifed listener was found in the list, and
1610: * removed.
1611: *
1612: * @deprecated Use <code>{@link #removeGlobalTriggerListener(String)}</code>
1613: */
1614: public boolean removeGlobalTriggerListener(
1615: TriggerListener triggerListener) {
1616: return removeGlobalTriggerListener((triggerListener == null) ? null
1617: : triggerListener.getName());
1618: }
1619:
1620: /**
1621: * <p>
1622: * Remove the identifed <code>{@link TriggerListener}</code> from the <code>Scheduler</code>'s
1623: * list of <i>global</i> listeners.
1624: * </p>
1625: *
1626: * @return true if the identifed listener was found in the list, and
1627: * removed.
1628: */
1629: public boolean removeGlobalTriggerListener(String name) {
1630: synchronized (globalTriggerListeners) {
1631: return (globalTriggerListeners.remove(name) != null);
1632: }
1633: }
1634:
1635: /**
1636: * <p>
1637: * Remove the identifed <code>{@link org.quartz.TriggerListener}</code>
1638: * from the <code>Scheduler</code>'s list of registered listeners.
1639: * </p>
1640: *
1641: * @return true if the identifed listener was found in the list, and
1642: * removed.
1643: */
1644: public boolean removeTriggerListener(String name) {
1645: synchronized (triggerListeners) {
1646: return (triggerListeners.remove(name) != null);
1647: }
1648: }
1649:
1650: /**
1651: * <p>
1652: * Get a list containing all of the <code>{@link org.quartz.TriggerListener}</code>
1653: * s in the <code>Scheduler</code>'s<i>global</i> list.
1654: * </p>
1655: */
1656: public List getGlobalTriggerListeners() {
1657: synchronized (globalTriggerListeners) {
1658: return new LinkedList(globalTriggerListeners.values());
1659: }
1660: }
1661:
1662: /**
1663: * <p>
1664: * Get a Set containing the names of all the <i>non-global</i><code>{@link org.quartz.TriggerListener}</code>
1665: * s registered with the <code>Scheduler</code>.
1666: * </p>
1667: */
1668: public Set getTriggerListenerNames() {
1669: synchronized (triggerListeners) {
1670: return new HashSet(triggerListeners.keySet());
1671: }
1672: }
1673:
1674: /**
1675: * <p>
1676: * Get the <i>global</i><code>{@link TriggerListener}</code> that
1677: * has the given name.
1678: * </p>
1679: */
1680: public TriggerListener getGlobalTriggerListener(String name) {
1681: synchronized (globalTriggerListeners) {
1682: return (TriggerListener) globalTriggerListeners.get(name);
1683: }
1684: }
1685:
1686: /**
1687: * <p>
1688: * Get the <i>non-global</i><code>{@link org.quartz.TriggerListener}</code>
1689: * that has the given name.
1690: * </p>
1691: */
1692: public TriggerListener getTriggerListener(String name) {
1693: synchronized (triggerListeners) {
1694: return (TriggerListener) triggerListeners.get(name);
1695: }
1696: }
1697:
1698: /**
1699: * <p>
1700: * Register the given <code>{@link SchedulerListener}</code> with the
1701: * <code>Scheduler</code>.
1702: * </p>
1703: */
1704: public void addSchedulerListener(SchedulerListener schedulerListener) {
1705: synchronized (schedulerListeners) {
1706: schedulerListeners.add(schedulerListener);
1707: }
1708: }
1709:
1710: /**
1711: * <p>
1712: * Remove the given <code>{@link SchedulerListener}</code> from the
1713: * <code>Scheduler</code>.
1714: * </p>
1715: *
1716: * @return true if the identifed listener was found in the list, and
1717: * removed.
1718: */
1719: public boolean removeSchedulerListener(
1720: SchedulerListener schedulerListener) {
1721: synchronized (schedulerListeners) {
1722: return schedulerListeners.remove(schedulerListener);
1723: }
1724: }
1725:
1726: /**
1727: * <p>
1728: * Get a List containing all of the <code>{@link SchedulerListener}</code>
1729: * s registered with the <code>Scheduler</code>.
1730: * </p>
1731: */
1732: public List getSchedulerListeners() {
1733: synchronized (schedulerListeners) {
1734: return (List) schedulerListeners.clone();
1735: }
1736: }
1737:
1738: protected void notifyJobStoreJobComplete(SchedulingContext ctxt,
1739: Trigger trigger, JobDetail detail, int instCode)
1740: throws JobPersistenceException {
1741:
1742: resources.getJobStore().triggeredJobComplete(ctxt, trigger,
1743: detail, instCode);
1744: }
1745:
1746: protected void notifyJobStoreJobVetoed(SchedulingContext ctxt,
1747: Trigger trigger, JobDetail detail, int instCode)
1748: throws JobPersistenceException {
1749:
1750: resources.getJobStore().triggeredJobComplete(ctxt, trigger,
1751: detail, instCode);
1752: }
1753:
1754: protected void notifySchedulerThread() {
1755: if (isSignalOnSchedulingChange()) {
1756: schedThread.signalSchedulingChange();
1757: }
1758: }
1759:
1760: private List buildTriggerListenerList(String[] additionalLstnrs)
1761: throws SchedulerException {
1762: List triggerListeners = getGlobalTriggerListeners();
1763: for (int i = 0; i < additionalLstnrs.length; i++) {
1764: TriggerListener tl = getTriggerListener(additionalLstnrs[i]);
1765:
1766: if (tl != null) {
1767: triggerListeners.add(tl);
1768: } else {
1769: throw new SchedulerException(
1770: "TriggerListener '" + additionalLstnrs[i]
1771: + "' not found.",
1772: SchedulerException.ERR_TRIGGER_LISTENER_NOT_FOUND);
1773: }
1774: }
1775:
1776: return triggerListeners;
1777: }
1778:
1779: private List buildJobListenerList(String[] additionalLstnrs)
1780: throws SchedulerException {
1781: List jobListeners = getGlobalJobListeners();
1782: for (int i = 0; i < additionalLstnrs.length; i++) {
1783: JobListener jl = getJobListener(additionalLstnrs[i]);
1784:
1785: if (jl != null) {
1786: jobListeners.add(jl);
1787: } else {
1788: throw new SchedulerException("JobListener '"
1789: + additionalLstnrs[i] + "' not found.",
1790: SchedulerException.ERR_JOB_LISTENER_NOT_FOUND);
1791: }
1792: }
1793:
1794: return jobListeners;
1795: }
1796:
1797: public boolean notifyTriggerListenersFired(JobExecutionContext jec)
1798: throws SchedulerException {
1799: // build a list of all trigger listeners that are to be notified...
1800: List triggerListeners = buildTriggerListenerList(jec
1801: .getTrigger().getTriggerListenerNames());
1802:
1803: boolean vetoedExecution = false;
1804:
1805: // notify all trigger listeners in the list
1806: java.util.Iterator itr = triggerListeners.iterator();
1807: while (itr.hasNext()) {
1808: TriggerListener tl = (TriggerListener) itr.next();
1809: try {
1810: tl.triggerFired(jec.getTrigger(), jec);
1811:
1812: if (tl.vetoJobExecution(jec.getTrigger(), jec)) {
1813: vetoedExecution = true;
1814: }
1815: } catch (Exception e) {
1816: SchedulerException se = new SchedulerException(
1817: "TriggerListener '" + tl.getName()
1818: + "' threw exception: "
1819: + e.getMessage(), e);
1820: se
1821: .setErrorCode(SchedulerException.ERR_TRIGGER_LISTENER);
1822: throw se;
1823: }
1824: }
1825:
1826: return vetoedExecution;
1827: }
1828:
1829: public void notifyTriggerListenersMisfired(Trigger trigger)
1830: throws SchedulerException {
1831: // build a list of all trigger listeners that are to be notified...
1832: List triggerListeners = buildTriggerListenerList(trigger
1833: .getTriggerListenerNames());
1834:
1835: // notify all trigger listeners in the list
1836: java.util.Iterator itr = triggerListeners.iterator();
1837: while (itr.hasNext()) {
1838: TriggerListener tl = (TriggerListener) itr.next();
1839: try {
1840: tl.triggerMisfired(trigger);
1841: } catch (Exception e) {
1842: SchedulerException se = new SchedulerException(
1843: "TriggerListener '" + tl.getName()
1844: + "' threw exception: "
1845: + e.getMessage(), e);
1846: se
1847: .setErrorCode(SchedulerException.ERR_TRIGGER_LISTENER);
1848: throw se;
1849: }
1850: }
1851: }
1852:
1853: public void notifyTriggerListenersComplete(JobExecutionContext jec,
1854: int instCode) throws SchedulerException {
1855: // build a list of all trigger listeners that are to be notified...
1856: List triggerListeners = buildTriggerListenerList(jec
1857: .getTrigger().getTriggerListenerNames());
1858:
1859: // notify all trigger listeners in the list
1860: java.util.Iterator itr = triggerListeners.iterator();
1861: while (itr.hasNext()) {
1862: TriggerListener tl = (TriggerListener) itr.next();
1863: try {
1864: tl.triggerComplete(jec.getTrigger(), jec, instCode);
1865: } catch (Exception e) {
1866: SchedulerException se = new SchedulerException(
1867: "TriggerListener '" + tl.getName()
1868: + "' threw exception: "
1869: + e.getMessage(), e);
1870: se
1871: .setErrorCode(SchedulerException.ERR_TRIGGER_LISTENER);
1872: throw se;
1873: }
1874: }
1875: }
1876:
1877: public void notifyJobListenersToBeExecuted(JobExecutionContext jec)
1878: throws SchedulerException {
1879: // build a list of all job listeners that are to be notified...
1880: List jobListeners = buildJobListenerList(jec.getJobDetail()
1881: .getJobListenerNames());
1882:
1883: // notify all job listeners
1884: java.util.Iterator itr = jobListeners.iterator();
1885: while (itr.hasNext()) {
1886: JobListener jl = (JobListener) itr.next();
1887: try {
1888: jl.jobToBeExecuted(jec);
1889: } catch (Exception e) {
1890: SchedulerException se = new SchedulerException(
1891: "JobListener '" + jl.getName()
1892: + "' threw exception: "
1893: + e.getMessage(), e);
1894: se.setErrorCode(SchedulerException.ERR_JOB_LISTENER);
1895: throw se;
1896: }
1897: }
1898: }
1899:
1900: public void notifyJobListenersWasVetoed(JobExecutionContext jec)
1901: throws SchedulerException {
1902: // build a list of all job listeners that are to be notified...
1903: List jobListeners = buildJobListenerList(jec.getJobDetail()
1904: .getJobListenerNames());
1905:
1906: // notify all job listeners
1907: java.util.Iterator itr = jobListeners.iterator();
1908: while (itr.hasNext()) {
1909: JobListener jl = (JobListener) itr.next();
1910: try {
1911: jl.jobExecutionVetoed(jec);
1912: } catch (Exception e) {
1913: SchedulerException se = new SchedulerException(
1914: "JobListener '" + jl.getName()
1915: + "' threw exception: "
1916: + e.getMessage(), e);
1917: se.setErrorCode(SchedulerException.ERR_JOB_LISTENER);
1918: throw se;
1919: }
1920: }
1921: }
1922:
1923: public void notifyJobListenersWasExecuted(JobExecutionContext jec,
1924: JobExecutionException je) throws SchedulerException {
1925: // build a list of all job listeners that are to be notified...
1926: List jobListeners = buildJobListenerList(jec.getJobDetail()
1927: .getJobListenerNames());
1928:
1929: // notify all job listeners
1930: java.util.Iterator itr = jobListeners.iterator();
1931: while (itr.hasNext()) {
1932: JobListener jl = (JobListener) itr.next();
1933: try {
1934: jl.jobWasExecuted(jec, je);
1935: } catch (Exception e) {
1936: SchedulerException se = new SchedulerException(
1937: "JobListener '" + jl.getName()
1938: + "' threw exception: "
1939: + e.getMessage(), e);
1940: se.setErrorCode(SchedulerException.ERR_JOB_LISTENER);
1941: throw se;
1942: }
1943: }
1944: }
1945:
1946: public void notifySchedulerListenersError(String msg,
1947: SchedulerException se) {
1948: // build a list of all scheduler listeners that are to be notified...
1949: List schedListeners = getSchedulerListeners();
1950:
1951: // notify all scheduler listeners
1952: java.util.Iterator itr = schedListeners.iterator();
1953: while (itr.hasNext()) {
1954: SchedulerListener sl = (SchedulerListener) itr.next();
1955: try {
1956: sl.schedulerError(msg, se);
1957: } catch (Exception e) {
1958: getLog()
1959: .error(
1960: "Error while notifying SchedulerListener of error: ",
1961: e);
1962: getLog().error(
1963: " Original error (for notification) was: "
1964: + msg, se);
1965: }
1966: }
1967: }
1968:
1969: public void notifySchedulerListenersSchduled(Trigger trigger) {
1970: // build a list of all scheduler listeners that are to be notified...
1971: List schedListeners = getSchedulerListeners();
1972:
1973: // notify all scheduler listeners
1974: java.util.Iterator itr = schedListeners.iterator();
1975: while (itr.hasNext()) {
1976: SchedulerListener sl = (SchedulerListener) itr.next();
1977: try {
1978: sl.jobScheduled(trigger);
1979: } catch (Exception e) {
1980: getLog().error(
1981: "Error while notifying SchedulerListener of scheduled job."
1982: + " Triger=" + trigger.getFullName(),
1983: e);
1984: }
1985: }
1986: }
1987:
1988: public void notifySchedulerListenersUnschduled(String triggerName,
1989: String triggerGroup) {
1990: // build a list of all scheduler listeners that are to be notified...
1991: List schedListeners = getSchedulerListeners();
1992:
1993: // notify all scheduler listeners
1994: java.util.Iterator itr = schedListeners.iterator();
1995: while (itr.hasNext()) {
1996: SchedulerListener sl = (SchedulerListener) itr.next();
1997: try {
1998: sl.jobUnscheduled(triggerName, triggerGroup);
1999: } catch (Exception e) {
2000: getLog().error(
2001: "Error while notifying SchedulerListener of unscheduled job."
2002: + " Triger=" + triggerGroup + "."
2003: + triggerName, e);
2004: }
2005: }
2006: }
2007:
2008: public void notifySchedulerListenersFinalized(Trigger trigger) {
2009: // build a list of all scheduler listeners that are to be notified...
2010: List schedListeners = getSchedulerListeners();
2011:
2012: // notify all scheduler listeners
2013: java.util.Iterator itr = schedListeners.iterator();
2014: while (itr.hasNext()) {
2015: SchedulerListener sl = (SchedulerListener) itr.next();
2016: try {
2017: sl.triggerFinalized(trigger);
2018: } catch (Exception e) {
2019: getLog().error(
2020: "Error while notifying SchedulerListener of finalized trigger."
2021: + " Triger=" + trigger.getFullName(),
2022: e);
2023: }
2024: }
2025: }
2026:
2027: public void notifySchedulerListenersPausedTrigger(String name,
2028: String group) {
2029: // build a list of all job listeners that are to be notified...
2030: List schedListeners = getSchedulerListeners();
2031:
2032: // notify all scheduler listeners
2033: java.util.Iterator itr = schedListeners.iterator();
2034: while (itr.hasNext()) {
2035: SchedulerListener sl = (SchedulerListener) itr.next();
2036: try {
2037: sl.triggersPaused(name, group);
2038: } catch (Exception e) {
2039: getLog().error(
2040: "Error while notifying SchedulerListener of paused trigger/group."
2041: + " Triger=" + group + "." + name, e);
2042: }
2043: }
2044: }
2045:
2046: public void notifySchedulerListenersResumedTrigger(String name,
2047: String group) {
2048: // build a list of all job listeners that are to be notified...
2049: List schedListeners = getSchedulerListeners();
2050:
2051: // notify all scheduler listeners
2052: java.util.Iterator itr = schedListeners.iterator();
2053: while (itr.hasNext()) {
2054: SchedulerListener sl = (SchedulerListener) itr.next();
2055: try {
2056: sl.triggersResumed(name, group);
2057: } catch (Exception e) {
2058: getLog().error(
2059: "Error while notifying SchedulerListener of resumed trigger/group."
2060: + " Triger=" + group + "." + name, e);
2061: }
2062: }
2063: }
2064:
2065: public void notifySchedulerListenersPausedJob(String name,
2066: String group) {
2067: // build a list of all job listeners that are to be notified...
2068: List schedListeners = getSchedulerListeners();
2069:
2070: // notify all scheduler listeners
2071: java.util.Iterator itr = schedListeners.iterator();
2072: while (itr.hasNext()) {
2073: SchedulerListener sl = (SchedulerListener) itr.next();
2074: try {
2075: sl.jobsPaused(name, group);
2076: } catch (Exception e) {
2077: getLog().error(
2078: "Error while notifying SchedulerListener of paused job/group."
2079: + " Job=" + group + "." + name, e);
2080: }
2081: }
2082: }
2083:
2084: public void notifySchedulerListenersResumedJob(String name,
2085: String group) {
2086: // build a list of all job listeners that are to be notified...
2087: List schedListeners = getSchedulerListeners();
2088:
2089: // notify all scheduler listeners
2090: java.util.Iterator itr = schedListeners.iterator();
2091: while (itr.hasNext()) {
2092: SchedulerListener sl = (SchedulerListener) itr.next();
2093: try {
2094: sl.jobsResumed(name, group);
2095: } catch (Exception e) {
2096: getLog().error(
2097: "Error while notifying SchedulerListener of resumed job/group."
2098: + " Job=" + group + "." + name, e);
2099: }
2100: }
2101: }
2102:
2103: public void notifySchedulerListenersShutdown() {
2104: // build a list of all job listeners that are to be notified...
2105: List schedListeners = getSchedulerListeners();
2106:
2107: // notify all scheduler listeners
2108: java.util.Iterator itr = schedListeners.iterator();
2109: while (itr.hasNext()) {
2110: SchedulerListener sl = (SchedulerListener) itr.next();
2111: try {
2112: sl.schedulerShutdown();
2113: } catch (Exception e) {
2114: getLog()
2115: .error(
2116: "Error while notifying SchedulerListener of shutdown.",
2117: e);
2118: }
2119: }
2120: }
2121:
2122: public void setJobFactory(JobFactory factory)
2123: throws SchedulerException {
2124:
2125: if (factory == null) {
2126: throw new IllegalArgumentException(
2127: "JobFactory cannot be set to null!");
2128: }
2129:
2130: getLog().info("JobFactory set to: " + factory);
2131:
2132: this .jobFactory = factory;
2133: }
2134:
2135: public JobFactory getJobFactory() {
2136: return jobFactory;
2137: }
2138:
2139: /**
2140: * Interrupt all instances of the identified InterruptableJob executing in
2141: * this Scheduler instance.
2142: *
2143: * <p>
2144: * This method is not cluster aware. That is, it will only interrupt
2145: * instances of the identified InterruptableJob currently executing in this
2146: * Scheduler instance, not across the entire cluster.
2147: * </p>
2148: *
2149: * @see org.quartz.core.RemotableQuartzScheduler#interrupt(org.quartz.core.SchedulingContext, java.lang.String, java.lang.String)
2150: */
2151: public boolean interrupt(SchedulingContext ctxt, String jobName,
2152: String groupName) throws UnableToInterruptJobException {
2153:
2154: if (groupName == null) {
2155: groupName = Scheduler.DEFAULT_GROUP;
2156: }
2157:
2158: List jobs = getCurrentlyExecutingJobs();
2159: java.util.Iterator it = jobs.iterator();
2160:
2161: JobExecutionContext jec = null;
2162: JobDetail jobDetail = null;
2163: Job job = null;
2164:
2165: boolean interrupted = false;
2166:
2167: while (it.hasNext()) {
2168: jec = (JobExecutionContext) it.next();
2169: jobDetail = jec.getJobDetail();
2170: if (jobName.equals(jobDetail.getName())
2171: && groupName.equals(jobDetail.getGroup())) {
2172: job = jec.getJobInstance();
2173: if (job instanceof InterruptableJob) {
2174: ((InterruptableJob) job).interrupt();
2175: interrupted = true;
2176: } else {
2177: throw new UnableToInterruptJobException(
2178: "Job '"
2179: + jobName
2180: + "' of group '"
2181: + groupName
2182: + "' can not be interrupted, since it does not implement "
2183: + InterruptableJob.class.getName());
2184:
2185: }
2186: }
2187: }
2188:
2189: return interrupted;
2190: }
2191:
2192: private void shutdownPlugins() {
2193: java.util.Iterator itr = resources.getSchedulerPlugins()
2194: .iterator();
2195: while (itr.hasNext()) {
2196: SchedulerPlugin plugin = (SchedulerPlugin) itr.next();
2197: plugin.shutdown();
2198: }
2199: }
2200:
2201: private void startPlugins() {
2202: java.util.Iterator itr = resources.getSchedulerPlugins()
2203: .iterator();
2204: while (itr.hasNext()) {
2205: SchedulerPlugin plugin = (SchedulerPlugin) itr.next();
2206: plugin.start();
2207: }
2208: }
2209:
2210: }
2211:
2212: /////////////////////////////////////////////////////////////////////////////
2213: //
2214: // ErrorLogger - Scheduler Listener Class
2215: //
2216: /////////////////////////////////////////////////////////////////////////////
2217:
2218: class ErrorLogger extends SchedulerListenerSupport {
2219: ErrorLogger() {
2220: }
2221:
2222: public void schedulerError(String msg, SchedulerException cause) {
2223: getLog().error(msg, cause);
2224: }
2225: }
2226:
2227: /////////////////////////////////////////////////////////////////////////////
2228: //
2229: // ExecutingJobsManager - Job Listener Class
2230: //
2231: /////////////////////////////////////////////////////////////////////////////
2232:
2233: class ExecutingJobsManager implements JobListener {
2234: HashMap executingJobs = new HashMap();
2235:
2236: int numJobsFired = 0;
2237:
2238: ExecutingJobsManager() {
2239: }
2240:
2241: public String getName() {
2242: return getClass().getName();
2243: }
2244:
2245: public int getNumJobsCurrentlyExecuting() {
2246: synchronized (executingJobs) {
2247: return executingJobs.size();
2248: }
2249: }
2250:
2251: public void jobToBeExecuted(JobExecutionContext context) {
2252: numJobsFired++;
2253:
2254: synchronized (executingJobs) {
2255: executingJobs.put(context.getTrigger().getFireInstanceId(),
2256: context);
2257: }
2258: }
2259:
2260: public void jobWasExecuted(JobExecutionContext context,
2261: JobExecutionException jobException) {
2262: synchronized (executingJobs) {
2263: executingJobs.remove(context.getTrigger()
2264: .getFireInstanceId());
2265: }
2266: }
2267:
2268: public int getNumJobsFired() {
2269: return numJobsFired;
2270: }
2271:
2272: public List getExecutingJobs() {
2273: synchronized (executingJobs) {
2274: return java.util.Collections
2275: .unmodifiableList(new ArrayList(executingJobs
2276: .values()));
2277: }
2278: }
2279:
2280: public void jobExecutionVetoed(JobExecutionContext context) {
2281:
2282: }
2283: }
|