KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > quartz > core > QuartzScheduler


1
2 /*
3  * Copyright 2004-2005 OpenSymphony
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6  * use this file except in compliance with the License. You may obtain a copy
7  * of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14  * License for the specific language governing permissions and limitations
15  * under the License.
16  *
17  */

18
19 /*
20  * Previously Copyright (c) 2001-2004 James House
21  */

22 package org.quartz.core;
23
24 import java.io.IOException JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.rmi.RemoteException JavaDoc;
27 import java.rmi.registry.LocateRegistry JavaDoc;
28 import java.rmi.registry.Registry JavaDoc;
29 import java.rmi.server.UnicastRemoteObject JavaDoc;
30 import java.util.ArrayList JavaDoc;
31 import java.util.Date JavaDoc;
32 import java.util.HashMap JavaDoc;
33 import java.util.HashSet JavaDoc;
34 import java.util.LinkedList JavaDoc;
35 import java.util.List JavaDoc;
36 import java.util.Properties JavaDoc;
37 import java.util.Random JavaDoc;
38 import java.util.Set JavaDoc;
39
40 import org.apache.commons.logging.Log;
41 import org.apache.commons.logging.LogFactory;
42 import org.quartz.Calendar;
43 import org.quartz.InterruptableJob;
44 import org.quartz.Job;
45 import org.quartz.JobDataMap;
46 import org.quartz.JobDetail;
47 import org.quartz.JobExecutionContext;
48 import org.quartz.JobExecutionException;
49 import org.quartz.JobListener;
50 import org.quartz.JobPersistenceException;
51 import org.quartz.ObjectAlreadyExistsException;
52 import org.quartz.Scheduler;
53 import org.quartz.SchedulerContext;
54 import org.quartz.SchedulerException;
55 import org.quartz.SchedulerListener;
56 import org.quartz.listeners.SchedulerListenerSupport;
57 import org.quartz.Trigger;
58 import org.quartz.TriggerListener;
59 import org.quartz.UnableToInterruptJobException;
60 import org.quartz.impl.SchedulerRepository;
61 import org.quartz.simpl.SimpleJobFactory;
62 import org.quartz.spi.JobFactory;
63 import org.quartz.spi.SchedulerPlugin;
64 import org.quartz.spi.SchedulerSignaler;
65
66 /**
67  * <p>
68  * This is the heart of Quartz, an indirect implementation of the <code>{@link org.quartz.Scheduler}</code>
69  * interface, containing methods to schedule <code>{@link org.quartz.Job}</code>s,
70  * register <code>{@link org.quartz.JobListener}</code> instances, etc.
71  * </p>// TODO: more docs...
72  *
73  * @see org.quartz.Scheduler
74  * @see org.quartz.core.QuartzSchedulerThread
75  * @see org.quartz.spi.JobStore
76  * @see org.quartz.spi.ThreadPool
77  *
78  * @author James House
79  */

80 public class QuartzScheduler implements RemotableQuartzScheduler {
81
82     /*
83      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
84      *
85      * Constants.
86      *
87      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
88      */

89
90     private static String JavaDoc VERSION_MAJOR = "UNKNOWN";
91     private static String JavaDoc VERSION_MINOR = "UNKNOWN";
92     private static String JavaDoc VERSION_ITERATION = "UNKNOWN";
93
94     static {
95         Properties JavaDoc props = new Properties JavaDoc();
96         try {
97             InputStream JavaDoc is =
98                 QuartzScheduler.class.getResourceAsStream("/build.properties");
99             if(is != null) {
100                 props.load(is);
101                 VERSION_MAJOR = props.getProperty("version.major");
102                 VERSION_MINOR = props.getProperty("version.minor");
103                 VERSION_ITERATION = props.getProperty("version.iter");
104             }
105         } catch (IOException JavaDoc e) {
106             (LogFactory.getLog(QuartzScheduler.class)).error(
107                 "Error loading version info from build.properties.", e);
108         }
109     }
110     
111
112     /*
113      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
114      *
115      * Data members.
116      *
117      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
118      */

119
120     private QuartzSchedulerResources resources;
121
122     private QuartzSchedulerThread schedThread;
123
124     private ThreadGroup JavaDoc threadGroup;
125
126     private SchedulerContext context = new SchedulerContext();
127
128     private HashMap JavaDoc jobListeners = new HashMap JavaDoc(10);
129
130     private HashMap JavaDoc globalJobListeners = new HashMap JavaDoc(10);
131
132     private HashMap JavaDoc triggerListeners = new HashMap JavaDoc(10);
133
134     private HashMap JavaDoc globalTriggerListeners = new HashMap JavaDoc(10);
135
136     private ArrayList JavaDoc schedulerListeners = new ArrayList JavaDoc(10);
137
138     private JobFactory jobFactory = new SimpleJobFactory();
139     
140     ExecutingJobsManager jobMgr = null;
141
142     ErrorLogger errLogger = null;
143
144     private SchedulerSignaler signaler;
145
146     private Random JavaDoc random = new Random JavaDoc();
147
148     private ArrayList JavaDoc holdToPreventGC = new ArrayList JavaDoc(5);
149
150     private boolean signalOnSchedulingChange = true;
151
152     private boolean closed = false;
153
154     private Date JavaDoc initialStart = null;
155
156     private final Log log = LogFactory.getLog(getClass());
157
158     /*
159      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
160      *
161      * Constructors.
162      *
163      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
164      */

165
166     /**
167      * <p>
168      * Create a <code>QuartzScheduler</code> with the given configuration
169      * properties.
170      * </p>
171      *
172      * @see QuartzSchedulerResources
173      */

174     public QuartzScheduler(QuartzSchedulerResources resources,
175             SchedulingContext ctxt, long idleWaitTime, long dbRetryInterval)
176         throws SchedulerException {
177         this.resources = resources;
178         try {
179             bind();
180         } catch (Exception JavaDoc re) {
181             throw new SchedulerException(
182                     "Unable to bind scheduler to RMI Registry.", re);
183         }
184
185         if (resources.getJMXExport()) {
186             try {
187                 registerJMX();
188             } catch (Exception JavaDoc e) {
189                 throw new SchedulerException(
190                         "Unable to register scheduler with MBeanServer.", e);
191             }
192         }
193         
194         this.schedThread = new QuartzSchedulerThread(this, resources, ctxt);
195         if (idleWaitTime > 0) {
196             this.schedThread.setIdleWaitTime(idleWaitTime);
197         }
198         if (dbRetryInterval > 0) {
199             this.schedThread.setDbFailureRetryInterval(dbRetryInterval);
200         }
201
202         jobMgr = new ExecutingJobsManager();
203         addGlobalJobListener(jobMgr);
204         errLogger = new ErrorLogger();
205         addSchedulerListener(errLogger);
206
207         signaler = new SchedulerSignalerImpl(this);
208         
209         getLog().info("Quartz Scheduler v." + getVersion() + " created.");
210     }
211
212     /*
213      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
214      *
215      * Interface.
216      *
217      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
218      */

219
220     public String JavaDoc getVersion() {
221         return getVersionMajor() + "." + getVersionMinor() + "."
222                 + getVersionIteration();
223     }
224
225     public static String JavaDoc getVersionMajor() {
226         return VERSION_MAJOR;
227     }
228
229     public static String JavaDoc getVersionMinor() {
230         return VERSION_MINOR;
231     }
232
233     public static String JavaDoc getVersionIteration() {
234         return VERSION_ITERATION;
235     }
236
237     public SchedulerSignaler getSchedulerSignaler() {
238         return signaler;
239     }
240
241     public Log getLog() {
242         return log;
243     }
244
245     /**
246      * Register the scheduler in the local MBeanServer.
247      */

248     private void registerJMX() throws Exception JavaDoc {
249         org.apache.commons.modeler.Registry registry =
250             org.apache.commons.modeler.Registry.getRegistry(null, null);
251         
252         String JavaDoc jmxObjectName = resources.getJMXObjectName();
253         
254         registry.registerComponent(this, jmxObjectName, null);
255         
256         getLog().info("Scheduler registered with local MBeanServer under name '" + jmxObjectName + "'");
257     }
258
259     /**
260      * Unregister the scheduler from the local MBeanServer.
261      */

262     private void unregisterJMX() throws Exception JavaDoc {
263         org.apache.commons.modeler.Registry registry =
264             org.apache.commons.modeler.Registry.getRegistry(null, null);
265         
266         String JavaDoc jmxObjectName = resources.getJMXObjectName();
267         
268         registry.unregisterComponent(jmxObjectName);
269         
270         getLog().info("Scheduler unregistered from name '" + jmxObjectName + "' in the local MBeanServer.");
271     }
272
273     /**
274      * <p>
275      * Bind the scheduler to an RMI registry.
276      * </p>
277      */

278     private void bind() throws RemoteException JavaDoc {
279         String JavaDoc host = resources.getRMIRegistryHost();
280         // don't export if we're not configured to do so...
281
if (host == null || host.length() == 0) {
282             return;
283         }
284
285         RemotableQuartzScheduler exportable = null;
286
287         if(resources.getRMIServerPort() > 0) {
288             exportable = (RemotableQuartzScheduler) UnicastRemoteObject
289                 .exportObject(this, resources.getRMIServerPort());
290         } else {
291             exportable = (RemotableQuartzScheduler) UnicastRemoteObject
292                 .exportObject(this);
293         }
294
295         Registry JavaDoc registry = null;
296
297         if (resources.getRMICreateRegistryStrategy().equals(
298                 QuartzSchedulerResources.CREATE_REGISTRY_AS_NEEDED)) {
299             try {
300                 // First try to get an existing one, instead of creating it,
301
// since if
302
// we're in a web-app being 'hot' re-depoloyed, then the JVM
303
// still
304
// has the registry that we created above the first time...
305
registry = LocateRegistry.getRegistry(resources
306                         .getRMIRegistryPort());
307                 registry.list();
308             } catch (Exception JavaDoc e) {
309                 registry = LocateRegistry.createRegistry(resources
310                         .getRMIRegistryPort());
311             }
312         } else if (resources.getRMICreateRegistryStrategy().equals(
313                 QuartzSchedulerResources.CREATE_REGISTRY_ALWAYS)) {
314             try {
315                 registry = LocateRegistry.createRegistry(resources
316                         .getRMIRegistryPort());
317             } catch (Exception JavaDoc e) {
318                 // Fall back to an existing one, instead of creating it, since
319
// if
320
// we're in a web-app being 'hot' re-depoloyed, then the JVM
321
// still
322
// has the registry that we created above the first time...
323
registry = LocateRegistry.getRegistry(resources
324                         .getRMIRegistryPort());
325             }
326         } else {
327             registry = LocateRegistry.getRegistry(resources
328                     .getRMIRegistryHost(), resources.getRMIRegistryPort());
329         }
330
331         String JavaDoc bindName = resources.getRMIBindName();
332         
333         registry.rebind(bindName, exportable);
334
335         getLog().info("Scheduler bound to RMI registry under name '" + bindName + "'");
336     }
337
338     /**
339      * <p>
340      * Un-bind the scheduler from an RMI registry.
341      * </p>
342      */

343     private void unBind() throws RemoteException JavaDoc {
344         String JavaDoc host = resources.getRMIRegistryHost();
345         // don't un-export if we're not configured to do so...
346
if (host == null || host.length() == 0) {
347             return;
348         }
349
350         Registry JavaDoc registry = LocateRegistry.getRegistry(resources
351                 .getRMIRegistryHost(), resources.getRMIRegistryPort());
352
353         String JavaDoc bindName = resources.getRMIBindName();
354         
355         try {
356             registry.unbind(bindName);
357             UnicastRemoteObject.unexportObject(this, true);
358         } catch (java.rmi.NotBoundException JavaDoc nbe) {
359         }
360
361         getLog().info("Scheduler un-bound from name '" + bindName + "' in RMI registry");
362     }
363
364     /**
365      * <p>
366      * Returns the name of the <code>QuartzScheduler</code>.
367      * </p>
368      */

369     public String JavaDoc getSchedulerName() {
370         return resources.getName();
371     }
372
373     /**
374      * <p>
375      * Returns the instance Id of the <code>QuartzScheduler</code>.
376      * </p>
377      */

378     public String JavaDoc getSchedulerInstanceId() {
379         return resources.getInstanceId();
380     }
381
382     /**
383      * <p>
384      * Returns the name of the <code>QuartzScheduler</code>.
385      * </p>
386      */

387     public ThreadGroup JavaDoc getSchedulerThreadGroup() {
388         if (threadGroup == null) {
389             threadGroup = new ThreadGroup JavaDoc("QuartzScheduler:"
390                     + getSchedulerName());
391             if (resources.getMakeSchedulerThreadDaemon()) {
392                 threadGroup.setDaemon(true);
393             }
394         }
395
396         return threadGroup;
397     }
398
399     public void addNoGCObject(Object JavaDoc obj) {
400         holdToPreventGC.add(obj);
401     }
402
403     public boolean removeNoGCObject(Object JavaDoc obj) {
404         return holdToPreventGC.remove(obj);
405     }
406
407     /**
408      * <p>
409      * Returns the <code>SchedulerContext</code> of the <code>Scheduler</code>.
410      * </p>
411      */

412     public SchedulerContext getSchedulerContext() throws SchedulerException {
413         return context;
414     }
415
416     public boolean isSignalOnSchedulingChange() {
417         return signalOnSchedulingChange;
418     }
419
420     public void setSignalOnSchedulingChange(boolean signalOnSchedulingChange) {
421         this.signalOnSchedulingChange = signalOnSchedulingChange;
422     }
423
424     ///////////////////////////////////////////////////////////////////////////
425
///
426
/// Schedululer State Management Methods
427
///
428
///////////////////////////////////////////////////////////////////////////
429

430     /**
431      * <p>
432      * Starts the <code>QuartzScheduler</code>'s threads that fire <code>{@link org.quartz.Trigger}s</code>.
433      * </p>
434      *
435      * <p>
436      * All <code>{@link org.quartz.Trigger}s</code> that have misfired will
437      * be passed to the appropriate TriggerListener(s).
438      * </p>
439      */

440     public void start() throws SchedulerException {
441
442         if (closed) {
443             throw new SchedulerException(
444                     "The Scheduler cannot be restarted after shutdown() has been called.");
445         }
446
447         if (initialStart == null) {
448             initialStart = new Date JavaDoc();
449             this.resources.getJobStore().schedulerStarted();
450             startPlugins();
451         }
452
453         schedThread.togglePause(false);
454
455         getLog().info(
456                 "Scheduler " + resources.getUniqueIdentifier() + " started.");
457     }
458
459     /**
460      * <p>
461      * Temporarily halts the <code>QuartzScheduler</code>'s firing of <code>{@link org.quartz.Trigger}s</code>.
462      * </p>
463      *
464      * <p>
465      * The scheduler is not destroyed, and can be re-started at any time.
466      * </p>
467      */

468     public void standby() {
469         schedThread.togglePause(true);
470         getLog().info(
471                 "Scheduler " + resources.getUniqueIdentifier() + " paused.");
472     }
473
474     /**
475      * <p>
476      * Reports whether the <code>Scheduler</code> is paused.
477      * </p>
478      */

479     public boolean isInStandbyMode() {
480         return schedThread.isPaused();
481     }
482
483     public Date JavaDoc runningSince() {
484         return initialStart;
485     }
486
487     public int numJobsExecuted() {
488         return jobMgr.getNumJobsFired();
489     }
490
491     public Class JavaDoc getJobStoreClass() {
492         return resources.getJobStore().getClass();
493     }
494
495     public boolean supportsPersistence() {
496         return resources.getJobStore().supportsPersistence();
497     }
498
499     public Class JavaDoc getThreadPoolClass() {
500         return resources.getThreadPool().getClass();
501     }
502
503     public int getThreadPoolSize() {
504         return resources.getThreadPool().getPoolSize();
505     }
506
507     /**
508      * <p>
509      * Halts the <code>QuartzScheduler</code>'s firing of <code>{@link org.quartz.Trigger}s</code>,
510      * and cleans up all resources associated with the QuartzScheduler.
511      * Equivalent to <code>shutdown(false)</code>.
512      * </p>
513      *
514      * <p>
515      * The scheduler cannot be re-started.
516      * </p>
517      */

518     public void shutdown() {
519         shutdown(false);
520     }
521
522     /**
523      * <p>
524      * Halts the <code>QuartzScheduler</code>'s firing of <code>{@link org.quartz.Trigger}s</code>,
525      * and cleans up all resources associated with the QuartzScheduler.
526      * </p>
527      *
528      * <p>
529      * The scheduler cannot be re-started.
530      * </p>
531      *
532      * @param waitForJobsToComplete
533      * if <code>true</code> the scheduler will not allow this method
534      * to return until all currently executing jobs have completed.
535      */

536     public void shutdown(boolean waitForJobsToComplete) {
537         
538         if(closed == true) {
539             return;
540         }
541         
542         getLog().info(
543                 "Scheduler " + resources.getUniqueIdentifier()
544                         + " shutting down.");
545         standby();
546
547         closed = true;
548
549         schedThread.halt();
550         
551         resources.getThreadPool().shutdown(waitForJobsToComplete);
552
553         if (waitForJobsToComplete) {
554             while (jobMgr.getNumJobsCurrentlyExecuting() > 0) {
555                 try {
556                     Thread.sleep(100);
557                 } catch (Exception JavaDoc ignore) {
558                 }
559             }
560         }
561
562         // Scheduler thread may have be waiting for the fire time of an acquired
563
// trigger and need time to release the trigger once halted, so make sure
564
// the thread is dead before continuing to shutdown the job store.
565
try {
566             schedThread.join();
567         } catch (InterruptedException JavaDoc ignore) {
568         }
569
570         resources.getJobStore().shutdown();
571
572         notifySchedulerListenersShutdown();
573
574         shutdownPlugins();
575
576         SchedulerRepository.getInstance().remove(resources.getName());
577
578         holdToPreventGC.clear();
579
580         try {
581             unBind();
582         } catch (RemoteException JavaDoc re) {
583         }
584         
585         if (resources.getJMXExport()) {
586             try {
587                 unregisterJMX();
588             } catch (Exception JavaDoc e) {
589             }
590         }
591
592         getLog().info(
593                 "Scheduler " + resources.getUniqueIdentifier()
594                         + " shutdown complete.");
595     }
596
597     /**
598      * <p>
599      * Reports whether the <code>Scheduler</code> has been shutdown.
600      * </p>
601      */

602     public boolean isShutdown() {
603         return closed;
604     }
605
606     public void validateState() throws SchedulerException {
607         if (isShutdown()) {
608             throw new SchedulerException("The Scheduler has been shutdown.");
609         }
610
611         // other conditions to check (?)
612
}
613
614     /**
615      * <p>
616      * Return a list of <code>JobExecutionContext</code> objects that
617      * represent all currently executing Jobs in this Scheduler instance.
618      * </p>
619      *
620      * <p>
621      * This method is not cluster aware. That is, it will only return Jobs
622      * currently executing in this Scheduler instance, not across the entire
623      * cluster.
624      * </p>
625      *
626      * <p>
627      * Note that the list returned is an 'instantaneous' snap-shot, and that as
628      * soon as it's returned, the true list of executing jobs may be different.
629      * </p>
630      */

631     public List JavaDoc getCurrentlyExecutingJobs() {
632         return jobMgr.getExecutingJobs();
633     }
634
635     ///////////////////////////////////////////////////////////////////////////
636
///
637
/// Scheduling-related Methods
638
///
639
///////////////////////////////////////////////////////////////////////////
640

641     /**
642      * <p>
643      * Add the <code>{@link org.quartz.Job}</code> identified by the given
644      * <code>{@link org.quartz.JobDetail}</code> to the Scheduler, and
645      * associate the given <code>{@link org.quartz.Trigger}</code> with it.
646      * </p>
647      *
648      * <p>
649      * If the given Trigger does not reference any <code>Job</code>, then it
650      * will be set to reference the Job passed with it into this method.
651      * </p>
652      *
653      * @throws SchedulerException
654      * if the Job or Trigger cannot be added to the Scheduler, or
655      * there is an internal Scheduler error.
656      */

657     public Date JavaDoc scheduleJob(SchedulingContext ctxt, JobDetail jobDetail,
658             Trigger trigger) throws SchedulerException {
659         validateState();
660
661         if (jobDetail == null) {
662             throw new SchedulerException("JobDetail cannot be null",
663                     SchedulerException.ERR_CLIENT_ERROR);
664         }
665         
666         if (trigger == null) {
667             throw new SchedulerException("Trigger cannot be null",
668                     SchedulerException.ERR_CLIENT_ERROR);
669         }
670         
671         jobDetail.validate();
672
673         if (trigger.getJobName() == null) {
674             trigger.setJobName(jobDetail.getName());
675             trigger.setJobGroup(jobDetail.getGroup());
676         } else if (trigger.getJobName() != null
677                 && !trigger.getJobName().equals(jobDetail.getName())) {
678             throw new SchedulerException(
679                 "Trigger does not reference given job!",
680                 SchedulerException.ERR_CLIENT_ERROR);
681         } else if (trigger.getJobGroup() != null
682                 && !trigger.getJobGroup().equals(jobDetail.getGroup())) {
683             throw new SchedulerException(
684                 "Trigger does not reference given job!",
685                 SchedulerException.ERR_CLIENT_ERROR);
686         }
687
688         trigger.validate();
689
690         Calendar cal = null;
691         if (trigger.getCalendarName() != null) {
692             cal = resources.getJobStore().retrieveCalendar(ctxt,
693                     trigger.getCalendarName());
694         }
695         Date JavaDoc ft = trigger.computeFirstFireTime(cal);
696
697         if (ft == null) {
698             throw new SchedulerException(
699                     "Based on configured schedule, the given trigger will never fire.",
700                     SchedulerException.ERR_CLIENT_ERROR);
701         }
702
703         resources.getJobStore().storeJobAndTrigger(ctxt, jobDetail, trigger);
704         notifySchedulerThread();
705         notifySchedulerListenersSchduled(trigger);
706
707         return ft;
708     }
709
710     /**
711      * <p>
712      * Schedule the given <code>{@link org.quartz.Trigger}</code> with the
713      * <code>Job</code> identified by the <code>Trigger</code>'s settings.
714      * </p>
715      *
716      * @throws SchedulerException
717      * if the indicated Job does not exist, or the Trigger cannot be
718      * added to the Scheduler, or there is an internal Scheduler
719      * error.
720      */

721     public Date JavaDoc scheduleJob(SchedulingContext ctxt, Trigger trigger)
722         throws SchedulerException {
723         validateState();
724
725         if (trigger == null) {
726             throw new SchedulerException("Trigger cannot be null",
727                     SchedulerException.ERR_CLIENT_ERROR);
728         }
729
730         trigger.validate();
731
732         Calendar cal = null;
733         if (trigger.getCalendarName() != null) {
734             cal = resources.getJobStore().retrieveCalendar(ctxt,
735                     trigger.getCalendarName());
736             if(cal == null) {
737                 throw new SchedulerException(
738                     "Calendar not found: " + trigger.getCalendarName(),
739                     SchedulerException.ERR_PERSISTENCE_CALENDAR_DOES_NOT_EXIST);
740             }
741         }
742         Date JavaDoc ft = trigger.computeFirstFireTime(cal);
743
744         if (ft == null) {
745             throw new SchedulerException(
746                     "Based on configured schedule, the given trigger will never fire.",
747                     SchedulerException.ERR_CLIENT_ERROR);
748         }
749
750         resources.getJobStore().storeTrigger(ctxt, trigger, false);
751         notifySchedulerThread();
752         notifySchedulerListenersSchduled(trigger);
753
754         return ft;
755     }
756
757     /**
758      * <p>
759      * Add the given <code>Job</code> to the Scheduler - with no associated
760      * <code>Trigger</code>. The <code>Job</code> will be 'dormant' until
761      * it is scheduled with a <code>Trigger</code>, or <code>Scheduler.triggerJob()</code>
762      * is called for it.
763      * </p>
764      *
765      * <p>
766      * The <code>Job</code> must by definition be 'durable', if it is not,
767      * SchedulerException will be thrown.
768      * </p>
769      *
770      * @throws SchedulerException
771      * if there is an internal Scheduler error, or if the Job is not
772      * durable, or a Job with the same name already exists, and
773      * <code>replace</code> is <code>false</code>.
774      */

775     public void addJob(SchedulingContext ctxt, JobDetail jobDetail,
776             boolean replace) throws SchedulerException {
777         validateState();
778
779         if (!jobDetail.isDurable() && !replace) {
780             throw new SchedulerException(
781                     "Jobs added with no trigger must be durable.",
782                     SchedulerException.ERR_CLIENT_ERROR);
783         }
784
785         resources.getJobStore().storeJob(ctxt, jobDetail, replace);
786     }
787
788     /**
789      * <p>
790      * Delete the identified <code>Job</code> from the Scheduler - and any
791      * associated <code>Trigger</code>s.
792      * </p>
793      *
794      * @return true if the Job was found and deleted.
795      * @throws SchedulerException
796      * if there is an internal Scheduler error.
797      */

798     public boolean deleteJob(SchedulingContext ctxt, String JavaDoc jobName,
799             String JavaDoc groupName) throws SchedulerException {
800         validateState();
801
802         if(groupName == null) {
803             groupName = Scheduler.DEFAULT_GROUP;
804         }
805         
806         return resources.getJobStore().removeJob(ctxt, jobName, groupName);
807     }
808
809     /**
810      * <p>
811      * Remove the indicated <code>{@link org.quartz.Trigger}</code> from the
812      * scheduler.
813      * </p>
814      */

815     public boolean unscheduleJob(SchedulingContext ctxt, String JavaDoc triggerName,
816             String JavaDoc groupName) throws SchedulerException {
817         validateState();
818
819         if(groupName == null) {
820             groupName = Scheduler.DEFAULT_GROUP;
821         }
822         
823         if (resources.getJobStore().removeTrigger(ctxt, triggerName, groupName)) {
824             notifySchedulerThread();
825             notifySchedulerListenersUnschduled(triggerName, groupName);
826         } else {
827             return false;
828         }
829
830         return true;
831     }
832
833
834     /**
835      * <p>
836      * Remove (delete) the <code>{@link org.quartz.Trigger}</code> with the
837      * given name, and store the new given one - which must be associated
838      * with the same job.
839      * </p>
840      *
841      * @param triggerName
842      * The name of the <code>Trigger</code> to be removed.
843      * @param groupName
844      * The group name of the <code>Trigger</code> to be removed.
845      * @param newTrigger
846      * The new <code>Trigger</code> to be stored.
847      * @return <code>null</code> if a <code>Trigger</code> with the given
848      * name & group was not found and removed from the store, otherwise
849      * the first fire time of the newly scheduled trigger.
850      */

851     public Date JavaDoc rescheduleJob(SchedulingContext ctxt, String JavaDoc triggerName,
852             String JavaDoc groupName, Trigger newTrigger) throws SchedulerException {
853         validateState();
854
855         if(groupName == null) {
856             groupName = Scheduler.DEFAULT_GROUP;
857         }
858
859         newTrigger.validate();
860
861         Calendar cal = null;
862         if (newTrigger.getCalendarName() != null) {
863             cal = resources.getJobStore().retrieveCalendar(ctxt,
864                     newTrigger.getCalendarName());
865         }
866         Date JavaDoc ft = newTrigger.computeFirstFireTime(cal);
867
868         if (ft == null) {
869             throw new SchedulerException(
870                     "Based on configured schedule, the given trigger will never fire.",
871                     SchedulerException.ERR_CLIENT_ERROR);
872         }
873         
874         if (resources.getJobStore().replaceTrigger(ctxt, triggerName, groupName, newTrigger)) {
875             notifySchedulerThread();
876             notifySchedulerListenersUnschduled(triggerName, groupName);
877             notifySchedulerListenersSchduled(newTrigger);
878         } else {
879             return null;
880         }
881
882         return ft;
883         
884     }
885     
886     
887     private String JavaDoc newTriggerId() {
888         long r = random.nextLong();
889         if (r < 0) {
890             r = -r;
891         }
892         return "MT_"
893                 + Long.toString(r, 30 + (int) (System.currentTimeMillis() % 7));
894     }
895
896     /**
897      * <p>
898      * Trigger the identified <code>{@link org.quartz.Job}</code> (execute it
899      * now) - with a non-volatile trigger.
900      * </p>
901      */

902     public void triggerJob(SchedulingContext ctxt, String JavaDoc jobName,
903             String JavaDoc groupName, JobDataMap data) throws SchedulerException {
904         validateState();
905
906         if(groupName == null) {
907             groupName = Scheduler.DEFAULT_GROUP;
908         }
909         
910         Trigger trig = new org.quartz.SimpleTrigger(newTriggerId(),
911                 Scheduler.DEFAULT_MANUAL_TRIGGERS, jobName, groupName,
912                 new Date JavaDoc(), null, 0, 0);
913         trig.setVolatility(false);
914         trig.computeFirstFireTime(null);
915         if(data != null) {
916             trig.setJobDataMap(data);
917         }
918
919         boolean collision = true;
920         while (collision) {
921             try {
922                 resources.getJobStore().storeTrigger(ctxt, trig, false);
923                 collision = false;
924             } catch (ObjectAlreadyExistsException oaee) {
925                 trig.setName(newTriggerId());
926             }
927         }
928
929         notifySchedulerThread();
930         notifySchedulerListenersSchduled(trig);
931     }
932
933     /**
934      * <p>
935      * Trigger the identified <code>{@link org.quartz.Job}</code> (execute it
936      * now) - with a volatile trigger.
937      * </p>
938      */

939     public void triggerJobWithVolatileTrigger(SchedulingContext ctxt,
940             String JavaDoc jobName, String JavaDoc groupName, JobDataMap data) throws SchedulerException {
941         validateState();
942
943         if(groupName == null) {
944             groupName = Scheduler.DEFAULT_GROUP;
945         }
946         
947         Trigger trig = new org.quartz.SimpleTrigger(newTriggerId(),
948                 Scheduler.DEFAULT_MANUAL_TRIGGERS, jobName, groupName,
949                 new Date JavaDoc(), null, 0, 0);
950         trig.setVolatility(true);
951         trig.computeFirstFireTime(null);
952         if(data != null) {
953             trig.setJobDataMap(data);
954         }
955         
956         boolean collision = true;
957         while (collision) {
958             try {
959                 resources.getJobStore().storeTrigger(ctxt, trig, false);
960                 collision = false;
961             } catch (ObjectAlreadyExistsException oaee) {
962                 trig.setName(newTriggerId());
963             }
964         }
965
966         notifySchedulerThread();
967         notifySchedulerListenersSchduled(trig);
968     }
969
970     /**
971      * <p>
972      * Pause the <code>{@link Trigger}</code> with the given name.
973      * </p>
974      *
975      */

976     public void pauseTrigger(SchedulingContext ctxt, String JavaDoc triggerName,
977             String JavaDoc groupName) throws SchedulerException {
978         validateState();
979
980         if(groupName == null) {
981             groupName = Scheduler.DEFAULT_GROUP;
982         }
983         
984         resources.getJobStore().pauseTrigger(ctxt, triggerName, groupName);
985         notifySchedulerThread();
986         notifySchedulerListenersPausedTrigger(triggerName, groupName);
987     }
988
989     /**
990      * <p>
991      * Pause all of the <code>{@link Trigger}s</code> in the given group.
992      * </p>
993      *
994      */

995     public void pauseTriggerGroup(SchedulingContext ctxt, String JavaDoc groupName)
996         throws SchedulerException {
997         validateState();
998
999         if(groupName == null) {
1000            groupName = Scheduler.DEFAULT_GROUP;
1001        }
1002        
1003        resources.getJobStore().pauseTriggerGroup(ctxt, groupName);
1004        notifySchedulerThread();
1005        notifySchedulerListenersPausedTrigger(null, groupName);
1006    }
1007
1008    /**
1009     * <p>
1010     * Pause the <code>{@link org.quartz.JobDetail}</code> with the given
1011     * name - by pausing all of its current <code>Trigger</code>s.
1012     * </p>
1013     *
1014     */

1015    public void pauseJob(SchedulingContext ctxt, String JavaDoc jobName,
1016            String JavaDoc groupName) throws SchedulerException {
1017        validateState();
1018
1019        if(groupName == null) {
1020            groupName = Scheduler.DEFAULT_GROUP;
1021        }
1022
1023        resources.getJobStore().pauseJob(ctxt, jobName, groupName);
1024        notifySchedulerThread();
1025        notifySchedulerListenersPausedJob(jobName, groupName);
1026    }
1027
1028    /**
1029     * <p>
1030     * Pause all of the <code>{@link org.quartz.JobDetail}s</code> in the
1031     * given group - by pausing all of their <code>Trigger</code>s.
1032     * </p>
1033     *
1034     */

1035    public void pauseJobGroup(SchedulingContext ctxt, String JavaDoc groupName)
1036        throws SchedulerException {
1037        validateState();
1038
1039        if(groupName == null) {
1040            groupName = Scheduler.DEFAULT_GROUP;
1041        }
1042        
1043        resources.getJobStore().pauseJobGroup(ctxt, groupName);
1044        notifySchedulerThread();
1045        notifySchedulerListenersPausedJob(null, groupName);
1046    }
1047
1048    /**
1049     * <p>
1050     * Resume (un-pause) the <code>{@link Trigger}</code> with the given
1051     * name.
1052     * </p>
1053     *
1054     * <p>
1055     * If the <code>Trigger</code> missed one or more fire-times, then the
1056     * <code>Trigger</code>'s misfire instruction will be applied.
1057     * </p>
1058     *
1059     */

1060    public void resumeTrigger(SchedulingContext ctxt, String JavaDoc triggerName,
1061            String JavaDoc groupName) throws SchedulerException {
1062        validateState();
1063
1064        if(groupName == null) {
1065            groupName = Scheduler.DEFAULT_GROUP;
1066        }
1067        
1068        resources.getJobStore().resumeTrigger(ctxt, triggerName, groupName);
1069        notifySchedulerThread();
1070        notifySchedulerListenersResumedTrigger(triggerName, groupName);
1071    }
1072
1073    /**
1074     * <p>
1075     * Resume (un-pause) all of the <code>{@link Trigger}s</code> in the
1076     * given group.
1077     * </p>
1078     *
1079     * <p>
1080     * If any <code>Trigger</code> missed one or more fire-times, then the
1081     * <code>Trigger</code>'s misfire instruction will be applied.
1082     * </p>
1083     *
1084     */

1085    public void resumeTriggerGroup(SchedulingContext ctxt, String JavaDoc groupName)
1086        throws SchedulerException {
1087        validateState();
1088
1089        if(groupName == null) {
1090            groupName = Scheduler.DEFAULT_GROUP;
1091        }
1092        
1093        resources.getJobStore().resumeTriggerGroup(ctxt, groupName);
1094        notifySchedulerThread();
1095        notifySchedulerListenersResumedTrigger(null, groupName);
1096    }
1097
1098    public Set JavaDoc getPausedTriggerGroups(SchedulingContext ctxt) throws SchedulerException {
1099        return resources.getJobStore().getPausedTriggerGroups(ctxt);
1100    }
1101    
1102    /**
1103     * <p>
1104     * Resume (un-pause) the <code>{@link org.quartz.JobDetail}</code> with
1105     * the given name.
1106     * </p>
1107     *
1108     * <p>
1109     * If any of the <code>Job</code>'s<code>Trigger</code> s missed one
1110     * or more fire-times, then the <code>Trigger</code>'s misfire
1111     * instruction will be applied.
1112     * </p>
1113     *
1114     */

1115    public void resumeJob(SchedulingContext ctxt, String JavaDoc jobName,
1116            String JavaDoc groupName) throws SchedulerException {
1117        validateState();
1118
1119        if(groupName == null) {
1120            groupName = Scheduler.DEFAULT_GROUP;
1121        }
1122        
1123        resources.getJobStore().resumeJob(ctxt, jobName, groupName);
1124        notifySchedulerThread();
1125        notifySchedulerListenersResumedJob(jobName, groupName);
1126    }
1127
1128    /**
1129     * <p>
1130     * Resume (un-pause) all of the <code>{@link org.quartz.JobDetail}s</code>
1131     * in the given group.
1132     * </p>
1133     *
1134     * <p>
1135     * If any of the <code>Job</code> s had <code>Trigger</code> s that
1136     * missed one or more fire-times, then the <code>Trigger</code>'s
1137     * misfire instruction will be applied.
1138     * </p>
1139     *
1140     */

1141    public void resumeJobGroup(SchedulingContext ctxt, String JavaDoc groupName)
1142        throws SchedulerException {
1143        validateState();
1144
1145        if(groupName == null) {
1146            groupName = Scheduler.DEFAULT_GROUP;
1147        }
1148        
1149        resources.getJobStore().resumeJobGroup(ctxt, groupName);
1150        notifySchedulerThread();
1151        notifySchedulerListenersResumedJob(null, groupName);
1152    }
1153
1154    /**
1155     * <p>
1156     * Pause all triggers - equivalent of calling <code>pauseTriggerGroup(group)</code>
1157     * on every group.
1158     * </p>
1159     *
1160     * <p>
1161     * When <code>resumeAll()</code> is called (to un-pause), trigger misfire
1162     * instructions WILL be applied.
1163     * </p>
1164     *
1165     * @see #resumeAll(SchedulingContext)
1166     * @see #pauseTriggerGroup(SchedulingContext, String)
1167     * @see #standby()
1168     */

1169    public void pauseAll(SchedulingContext ctxt) throws SchedulerException {
1170        validateState();
1171
1172        resources.getJobStore().pauseAll(ctxt);
1173        notifySchedulerThread();
1174        notifySchedulerListenersPausedTrigger(null, null);
1175    }
1176
1177    /**
1178     * <p>
1179     * Resume (un-pause) all triggers - equivalent of calling <code>resumeTriggerGroup(group)</code>
1180     * on every group.
1181     * </p>
1182     *
1183     * <p>
1184     * If any <code>Trigger</code> missed one or more fire-times, then the
1185     * <code>Trigger</code>'s misfire instruction will be applied.
1186     * </p>
1187     *
1188     * @see #pauseAll(SchedulingContext)
1189     */

1190    public void resumeAll(SchedulingContext ctxt) throws SchedulerException {
1191        validateState();
1192
1193        resources.getJobStore().resumeAll(ctxt);
1194        notifySchedulerThread();
1195        notifySchedulerListenersResumedTrigger(null, null);
1196    }
1197
1198    /**
1199     * <p>
1200     * Get the names of all known <code>{@link org.quartz.Job}</code> groups.
1201     * </p>
1202     */

1203    public String JavaDoc[] getJobGroupNames(SchedulingContext ctxt)
1204        throws SchedulerException {
1205        validateState();
1206
1207        return resources.getJobStore().getJobGroupNames(ctxt);
1208    }
1209
1210    /**
1211     * <p>
1212     * Get the names of all the <code>{@link org.quartz.Job}s</code> in the
1213     * given group.
1214     * </p>
1215     */

1216    public String JavaDoc[] getJobNames(SchedulingContext ctxt, String JavaDoc groupName)
1217        throws SchedulerException {
1218        validateState();
1219
1220        if(groupName == null) {
1221            groupName = Scheduler.DEFAULT_GROUP;
1222        }
1223        
1224        return resources.getJobStore().getJobNames(ctxt, groupName);
1225    }
1226
1227    /**
1228     * <p>
1229     * Get all <code>{@link Trigger}</code> s that are associated with the
1230     * identified <code>{@link org.quartz.JobDetail}</code>.
1231     * </p>
1232     */

1233    public Trigger[] getTriggersOfJob(SchedulingContext ctxt, String JavaDoc jobName,
1234            String JavaDoc groupName) throws SchedulerException {
1235        validateState();
1236
1237        if(groupName == null) {
1238            groupName = Scheduler.DEFAULT_GROUP;
1239        }
1240        
1241        return resources.getJobStore().getTriggersForJob(ctxt, jobName,
1242                groupName);
1243    }
1244
1245    /**
1246     * <p>
1247     * Get the names of all known <code>{@link org.quartz.Trigger}</code>
1248     * groups.
1249     * </p>
1250     */

1251    public String JavaDoc[] getTriggerGroupNames(SchedulingContext ctxt)
1252        throws SchedulerException {
1253        validateState();
1254
1255        return resources.getJobStore().getTriggerGroupNames(ctxt);
1256    }
1257
1258    /**
1259     * <p>
1260     * Get the names of all the <code>{@link org.quartz.Trigger}s</code> in
1261     * the given group.
1262     * </p>
1263     */

1264    public String JavaDoc[] getTriggerNames(SchedulingContext ctxt, String JavaDoc groupName)
1265        throws SchedulerException {
1266        validateState();
1267
1268        if(groupName == null) {
1269            groupName = Scheduler.DEFAULT_GROUP;
1270        }
1271        
1272        return resources.getJobStore().getTriggerNames(ctxt, groupName);
1273    }
1274
1275    /**
1276     * <p>
1277     * Get the <code>{@link JobDetail}</code> for the <code>Job</code>
1278     * instance with the given name and group.
1279     * </p>
1280     */

1281    public JobDetail getJobDetail(SchedulingContext ctxt, String JavaDoc jobName,
1282            String JavaDoc jobGroup) throws SchedulerException {
1283        validateState();
1284
1285        if(jobGroup == null) {
1286            jobGroup = Scheduler.DEFAULT_GROUP;
1287        }
1288        
1289        return resources.getJobStore().retrieveJob(ctxt, jobName, jobGroup);
1290    }
1291
1292    /**
1293     * <p>
1294     * Get the <code>{@link Trigger}</code> instance with the given name and
1295     * group.
1296     * </p>
1297     */

1298    public Trigger getTrigger(SchedulingContext ctxt, String JavaDoc triggerName,
1299            String JavaDoc triggerGroup) throws SchedulerException {
1300        validateState();
1301
1302        if(triggerGroup == null) {
1303            triggerGroup = Scheduler.DEFAULT_GROUP;
1304        }
1305        
1306        return resources.getJobStore().retrieveTrigger(ctxt, triggerName,
1307                triggerGroup);
1308    }
1309
1310    /**
1311     * <p>
1312     * Get the current state of the identified <code>{@link Trigger}</code>.
1313     * </p>
1314     *
1315     * @see Trigger#STATE_NORMAL
1316     * @see Trigger#STATE_PAUSED
1317     * @see Trigger#STATE_COMPLETE
1318     * @see Trigger#STATE_ERROR
1319     */

1320    public int getTriggerState(SchedulingContext ctxt, String JavaDoc triggerName,
1321            String JavaDoc triggerGroup) throws SchedulerException {
1322        validateState();
1323
1324        if(triggerGroup == null) {
1325            triggerGroup = Scheduler.DEFAULT_GROUP;
1326        }
1327        
1328        return resources.getJobStore().getTriggerState(ctxt, triggerName,
1329                triggerGroup);
1330    }
1331
1332    /**
1333     * <p>
1334     * Add (register) the given <code>Calendar</code> to the Scheduler.
1335     * </p>
1336     *
1337     * @throws SchedulerException
1338     * if there is an internal Scheduler error, or a Calendar with
1339     * the same name already exists, and <code>replace</code> is
1340     * <code>false</code>.
1341     */

1342    public void addCalendar(SchedulingContext ctxt, String JavaDoc calName,
1343            Calendar calendar, boolean replace, boolean updateTriggers) throws SchedulerException {
1344        validateState();
1345
1346        resources.getJobStore().storeCalendar(ctxt, calName, calendar, replace, updateTriggers);
1347    }
1348
1349    /**
1350     * <p>
1351     * Delete the identified <code>Calendar</code> from the Scheduler.
1352     * </p>
1353     *
1354     * @return true if the Calendar was found and deleted.
1355     * @throws SchedulerException
1356     * if there is an internal Scheduler error.
1357     */

1358    public boolean deleteCalendar(SchedulingContext ctxt, String JavaDoc calName)
1359        throws SchedulerException {
1360        validateState();
1361
1362        return resources.getJobStore().removeCalendar(ctxt, calName);
1363    }
1364
1365    /**
1366     * <p>
1367     * Get the <code>{@link Calendar}</code> instance with the given name.
1368     * </p>
1369     */

1370    public Calendar getCalendar(SchedulingContext ctxt, String JavaDoc calName)
1371        throws SchedulerException {
1372        validateState();
1373
1374        return resources.getJobStore().retrieveCalendar(ctxt, calName);
1375    }
1376
1377    /**
1378     * <p>
1379     * Get the names of all registered <code>{@link Calendar}s</code>.
1380     * </p>
1381     */

1382    public String JavaDoc[] getCalendarNames(SchedulingContext ctxt)
1383        throws SchedulerException {
1384        validateState();
1385
1386        return resources.getJobStore().getCalendarNames(ctxt);
1387    }
1388
1389    /**
1390     * <p>
1391     * Add the given <code>{@link org.quartz.JobListener}</code> to the
1392     * <code>Scheduler</code>'s<i>global</i> list.
1393     * </p>
1394     *
1395     * <p>
1396     * Listeners in the 'global' list receive notification of execution events
1397     * for ALL <code>{@link org.quartz.Job}</code>s.
1398     * </p>
1399     */

1400    public void addGlobalJobListener(JobListener jobListener) {
1401        if (jobListener.getName() == null
1402                || jobListener.getName().length() == 0) {
1403            throw new IllegalArgumentException JavaDoc(
1404                    "JobListener name cannot be empty.");
1405        }
1406        
1407        synchronized (globalJobListeners) {
1408            globalJobListeners.put(jobListener.getName(), jobListener);
1409        }
1410    }
1411
1412    /**
1413     * <p>
1414     * Add the given <code>{@link org.quartz.JobListener}</code> to the
1415     * <code>Scheduler</code>'s list, of registered <code>JobListener</code>s.
1416     */

1417    public void addJobListener(JobListener jobListener) {
1418        if (jobListener.getName() == null
1419                || jobListener.getName().length() == 0) {
1420            throw new IllegalArgumentException JavaDoc(
1421                    "JobListener name cannot be empty.");
1422        }
1423
1424        synchronized (jobListeners) {
1425            jobListeners.put(jobListener.getName(), jobListener);
1426        }
1427    }
1428
1429    /**
1430     * <p>
1431     * Remove the given <code>{@link org.quartz.JobListener}</code> from the
1432     * <code>Scheduler</code>'s list of <i>global</i> listeners.
1433     * </p>
1434     *
1435     * @return true if the identifed listener was found in the list, and
1436     * removed.
1437     *
1438     * @deprecated Use <code>{@link #removeGlobalJobListener(String)}</code>
1439     */

1440    public boolean removeGlobalJobListener(JobListener jobListener) {
1441        return removeGlobalJobListener((jobListener == null) ? null : jobListener.getName());
1442    }
1443
1444    /**
1445     * <p>
1446     * Remove the identifed <code>{@link JobListener}</code> from the <code>Scheduler</code>'s
1447     * list of <i>global</i> listeners.
1448     * </p>
1449     *
1450     * @return true if the identifed listener was found in the list, and
1451     * removed.
1452     */

1453    public boolean removeGlobalJobListener(String JavaDoc name) {
1454        synchronized (globalJobListeners) {
1455            return (globalJobListeners.remove(name) != null);
1456        }
1457    }
1458    
1459    /**
1460     * <p>
1461     * Remove the identifed <code>{@link org.quartz.JobListener}</code> from
1462     * the <code>Scheduler</code>'s list of registered listeners.
1463     * </p>
1464     *
1465     * @return true if the identifed listener was found in the list, and
1466     * removed.
1467     */

1468    public boolean removeJobListener(String JavaDoc name) {
1469        synchronized (jobListeners) {
1470            return (jobListeners.remove(name) != null);
1471        }
1472    }
1473
1474    /**
1475     * <p>
1476     * Get a List containing all of the <code>{@link org.quartz.JobListener}</code>
1477     * s in the <code>Scheduler</code>'s<i>global</i> list.
1478     * </p>
1479     */

1480    public List JavaDoc getGlobalJobListeners() {
1481        synchronized (globalJobListeners) {
1482            return new LinkedList JavaDoc(globalJobListeners.values());
1483        }
1484    }
1485
1486    /**
1487     * <p>
1488     * Get a Set containing the names of all the <i>non-global</i><code>{@link org.quartz.JobListener}</code>
1489     * s registered with the <code>Scheduler</code>.
1490     * </p>
1491     */

1492    public Set JavaDoc getJobListenerNames() {
1493        synchronized (jobListeners) {
1494            return new HashSet JavaDoc(jobListeners.keySet());
1495        }
1496    }
1497
1498    /**
1499     * <p>
1500     * Get the <i>global</i><code>{@link org.quartz.JobListener}</code>
1501     * that has the given name.
1502     * </p>
1503     */

1504    public JobListener getGlobalJobListener(String JavaDoc name) {
1505        synchronized (globalJobListeners) {
1506            return (JobListener)globalJobListeners.get(name);
1507        }
1508    }
1509
1510    /**
1511     * <p>
1512     * Get the <i>non-global</i><code>{@link org.quartz.JobListener}</code>
1513     * that has the given name.
1514     * </p>
1515     */

1516    public JobListener getJobListener(String JavaDoc name) {
1517        synchronized (jobListeners) {
1518            return (JobListener) jobListeners.get(name);
1519        }
1520    }
1521
1522    /**
1523     * <p>
1524     * Add the given <code>{@link org.quartz.TriggerListener}</code> to the
1525     * <code>Scheduler</code>'s<i>global</i> list.
1526     * </p>
1527     *
1528     * <p>
1529     * Listeners in the 'global' list receive notification of execution events
1530     * for ALL <code>{@link org.quartz.Trigger}</code>s.
1531     * </p>
1532     */

1533    public void addGlobalTriggerListener(TriggerListener triggerListener) {
1534        if (triggerListener.getName() == null
1535                || triggerListener.getName().length() == 0) {
1536            throw new IllegalArgumentException JavaDoc(
1537                    "TriggerListener name cannot be empty.");
1538        }
1539
1540        synchronized (globalTriggerListeners) {
1541            globalTriggerListeners.put(triggerListener.getName(), triggerListener);
1542        }
1543    }
1544
1545    /**
1546     * <p>
1547     * Add the given <code>{@link org.quartz.TriggerListener}</code> to the
1548     * <code>Scheduler</code>'s list, of registered <code>TriggerListener</code>s.
1549     */

1550    public void addTriggerListener(TriggerListener triggerListener) {
1551        if (triggerListener.getName() == null
1552                || triggerListener.getName().length() == 0) {
1553            throw new IllegalArgumentException JavaDoc(
1554                    "TriggerListener name cannot be empty.");
1555        }
1556
1557        synchronized (triggerListeners) {
1558            triggerListeners.put(triggerListener.getName(), triggerListener);
1559        }
1560    }
1561
1562    /**
1563     * <p>
1564     * Remove the given <code>{@link org.quartz.TriggerListener}</code> from
1565     * the <code>Scheduler</code>'s list of <i>global</i> listeners.
1566     * </p>
1567     *
1568     * @return true if the identifed listener was found in the list, and
1569     * removed.
1570     *
1571     * @deprecated Use <code>{@link #removeGlobalTriggerListener(String)}</code>
1572     */

1573    public boolean removeGlobalTriggerListener(TriggerListener triggerListener) {
1574        return removeGlobalTriggerListener((triggerListener == null) ? null : triggerListener.getName());
1575    }
1576
1577    /**
1578     * <p>
1579     * Remove the identifed <code>{@link TriggerListener}</code> from the <code>Scheduler</code>'s
1580     * list of <i>global</i> listeners.
1581     * </p>
1582     *
1583     * @return true if the identifed listener was found in the list, and
1584     * removed.
1585     */

1586    public boolean removeGlobalTriggerListener(String JavaDoc name) {
1587        synchronized (globalTriggerListeners) {
1588            return (globalTriggerListeners.remove(name) != null);
1589        }
1590    }
1591    
1592    /**
1593     * <p>
1594     * Remove the identifed <code>{@link org.quartz.TriggerListener}</code>
1595     * from the <code>Scheduler</code>'s list of registered listeners.
1596     * </p>
1597     *
1598     * @return true if the identifed listener was found in the list, and
1599     * removed.
1600     */

1601    public boolean removeTriggerListener(String JavaDoc name) {
1602        synchronized (triggerListeners) {
1603            return (triggerListeners.remove(name) != null);
1604        }
1605    }
1606
1607    /**
1608     * <p>
1609     * Get a list containing all of the <code>{@link org.quartz.TriggerListener}</code>
1610     * s in the <code>Scheduler</code>'s<i>global</i> list.
1611     * </p>
1612     */

1613    public List JavaDoc getGlobalTriggerListeners() {
1614        synchronized (globalTriggerListeners) {
1615            return new LinkedList JavaDoc(globalTriggerListeners.values());
1616        }
1617    }
1618
1619    /**
1620     * <p>
1621     * Get a Set containing the names of all the <i>non-global</i><code>{@link org.quartz.TriggerListener}</code>
1622     * s registered with the <code>Scheduler</code>.
1623     * </p>
1624     */

1625    public Set JavaDoc getTriggerListenerNames() {
1626        synchronized (triggerListeners) {
1627            return new HashSet JavaDoc(triggerListeners.keySet());
1628        }
1629    }
1630
1631    /**
1632     * <p>
1633     * Get the <i>global</i><code>{@link TriggerListener}</code> that
1634     * has the given name.
1635     * </p>
1636     */

1637    public TriggerListener getGlobalTriggerListener(String JavaDoc name) {
1638        synchronized (globalTriggerListeners) {
1639            return (TriggerListener)globalTriggerListeners.get(name);
1640        }
1641    }
1642    
1643    /**
1644     * <p>
1645     * Get the <i>non-global</i><code>{@link org.quartz.TriggerListener}</code>
1646     * that has the given name.
1647     * </p>
1648     */

1649    public TriggerListener getTriggerListener(String JavaDoc name) {
1650        synchronized (triggerListeners) {
1651            return (TriggerListener) triggerListeners.get(name);
1652        }
1653    }
1654
1655    /**
1656     * <p>
1657     * Register the given <code>{@link SchedulerListener}</code> with the
1658     * <code>Scheduler</code>.
1659     * </p>
1660     */

1661    public void addSchedulerListener(SchedulerListener schedulerListener) {
1662        synchronized (schedulerListeners) {
1663            schedulerListeners.add(schedulerListener);
1664        }
1665    }
1666
1667    /**
1668     * <p>
1669     * Remove the given <code>{@link SchedulerListener}</code> from the
1670     * <code>Scheduler</code>.
1671     * </p>
1672     *
1673     * @return true if the identifed listener was found in the list, and
1674     * removed.
1675     */

1676    public boolean removeSchedulerListener(SchedulerListener schedulerListener) {
1677        synchronized (schedulerListeners) {
1678            return schedulerListeners.remove(schedulerListener);
1679        }
1680    }
1681
1682    /**
1683     * <p>
1684     * Get a List containing all of the <code>{@link SchedulerListener}</code>
1685     * s registered with the <code>Scheduler</code>.
1686     * </p>
1687     */

1688    public List JavaDoc getSchedulerListeners() {
1689        synchronized (schedulerListeners) {
1690            return (List JavaDoc)schedulerListeners.clone();
1691        }
1692    }
1693
1694    protected void notifyJobStoreJobComplete(SchedulingContext ctxt,
1695            Trigger trigger, JobDetail detail, int instCode)
1696        throws JobPersistenceException {
1697
1698        resources.getJobStore().triggeredJobComplete(ctxt, trigger, detail,
1699                instCode);
1700    }
1701
1702    protected void notifyJobStoreJobVetoed(SchedulingContext ctxt,
1703            Trigger trigger, JobDetail detail, int instCode)
1704        throws JobPersistenceException {
1705
1706        resources.getJobStore().triggeredJobComplete(ctxt, trigger, detail, instCode);
1707    }
1708
1709    protected void notifySchedulerThread() {
1710        if (isSignalOnSchedulingChange()) {
1711            schedThread.signalSchedulingChange();
1712        }
1713    }
1714
1715    private List JavaDoc buildTriggerListenerList(String JavaDoc[] additionalLstnrs)
1716        throws SchedulerException {
1717        List JavaDoc triggerListeners = getGlobalTriggerListeners();
1718        for (int i = 0; i < additionalLstnrs.length; i++) {
1719            TriggerListener tl = getTriggerListener(additionalLstnrs[i]);
1720
1721            if (tl != null) {
1722                triggerListeners.add(tl);
1723            } else {
1724                throw new SchedulerException("TriggerListener '"
1725                        + additionalLstnrs[i] + "' not found.",
1726                        SchedulerException.ERR_TRIGGER_LISTENER_NOT_FOUND);
1727            }
1728        }
1729
1730        return triggerListeners;
1731    }
1732
1733    private List JavaDoc buildJobListenerList(String JavaDoc[] additionalLstnrs)
1734        throws SchedulerException {
1735        List JavaDoc jobListeners = getGlobalJobListeners();
1736        for (int i = 0; i < additionalLstnrs.length; i++) {
1737            JobListener jl = getJobListener(additionalLstnrs[i]);
1738
1739            if (jl != null) {
1740                jobListeners.add(jl);
1741            } else {
1742                throw new SchedulerException("JobListener '"
1743                        + additionalLstnrs[i] + "' not found.",
1744                        SchedulerException.ERR_JOB_LISTENER_NOT_FOUND);
1745            }
1746        }
1747
1748        return jobListeners;
1749    }
1750
1751    public boolean notifyTriggerListenersFired(JobExecutionContext jec)
1752        throws SchedulerException {
1753        // build a list of all trigger listeners that are to be notified...
1754
List JavaDoc triggerListeners = buildTriggerListenerList(jec.getTrigger()
1755                .getTriggerListenerNames());
1756
1757        boolean vetoedExecution = false;
1758        
1759        // notify all trigger listeners in the list
1760
java.util.Iterator JavaDoc itr = triggerListeners.iterator();
1761        while (itr.hasNext()) {
1762            TriggerListener tl = (TriggerListener) itr.next();
1763            try {
1764                tl.triggerFired(jec.getTrigger(), jec);
1765                
1766                if(tl.vetoJobExecution(jec.getTrigger(), jec)) {
1767                    vetoedExecution = true;
1768                }
1769            } catch (Exception JavaDoc e) {
1770                SchedulerException se = new SchedulerException(
1771                        "TriggerListener '" + tl.getName()
1772                                + "' threw exception: " + e.getMessage(), e);
1773                se.setErrorCode(SchedulerException.ERR_TRIGGER_LISTENER);
1774                throw se;
1775            }
1776        }
1777        
1778        return vetoedExecution;
1779    }
1780    
1781
1782    public void notifyTriggerListenersMisfired(Trigger trigger)
1783        throws SchedulerException {
1784        // build a list of all trigger listeners that are to be notified...
1785
List JavaDoc triggerListeners = buildTriggerListenerList(trigger
1786                .getTriggerListenerNames());
1787
1788        // notify all trigger listeners in the list
1789
java.util.Iterator JavaDoc itr = triggerListeners.iterator();
1790        while (itr.hasNext()) {
1791            TriggerListener tl = (TriggerListener) itr.next();
1792            try {
1793                tl.triggerMisfired(trigger);
1794            } catch (Exception JavaDoc e) {
1795                SchedulerException se = new SchedulerException(
1796                        "TriggerListener '" + tl.getName()
1797                                + "' threw exception: " + e.getMessage(), e);
1798                se.setErrorCode(SchedulerException.ERR_TRIGGER_LISTENER);
1799                throw se;
1800            }
1801        }
1802    }
1803
1804    public void notifyTriggerListenersComplete(JobExecutionContext jec,
1805            int instCode) throws SchedulerException {
1806        // build a list of all trigger listeners that are to be notified...
1807
List JavaDoc triggerListeners = buildTriggerListenerList(jec.getTrigger()
1808                .getTriggerListenerNames());
1809
1810        // notify all trigger listeners in the list
1811
java.util.Iterator JavaDoc itr = triggerListeners.iterator();
1812        while (itr.hasNext()) {
1813            TriggerListener tl = (TriggerListener) itr.next();
1814            try {
1815                tl.triggerComplete(jec.getTrigger(), jec, instCode);
1816            } catch (Exception JavaDoc e) {
1817                SchedulerException se = new SchedulerException(
1818                        "TriggerListener '" + tl.getName()
1819                                + "' threw exception: " + e.getMessage(), e);
1820                se.setErrorCode(SchedulerException.ERR_TRIGGER_LISTENER);
1821                throw se;
1822            }
1823        }
1824    }
1825
1826    public void notifyJobListenersToBeExecuted(JobExecutionContext jec)
1827        throws SchedulerException {
1828        // build a list of all job listeners that are to be notified...
1829
List JavaDoc jobListeners = buildJobListenerList(jec.getJobDetail()
1830                .getJobListenerNames());
1831
1832        // notify all job listeners
1833
java.util.Iterator JavaDoc itr = jobListeners.iterator();
1834        while (itr.hasNext()) {
1835            JobListener jl = (JobListener) itr.next();
1836            try {
1837                jl.jobToBeExecuted(jec);
1838            } catch (Exception JavaDoc e) {
1839                SchedulerException se = new SchedulerException(
1840                        "JobListener '" + jl.getName() + "' threw exception: "
1841                                + e.getMessage(), e);
1842                se.setErrorCode(SchedulerException.ERR_JOB_LISTENER);
1843                throw se;
1844            }
1845        }
1846    }
1847
1848    public void notifyJobListenersWasVetoed(JobExecutionContext jec)
1849        throws SchedulerException {
1850        // build a list of all job listeners that are to be notified...
1851
List JavaDoc jobListeners = buildJobListenerList(jec.getJobDetail()
1852                .getJobListenerNames());
1853
1854        // notify all job listeners
1855
java.util.Iterator JavaDoc itr = jobListeners.iterator();
1856        while (itr.hasNext()) {
1857            JobListener jl = (JobListener) itr.next();
1858            try {
1859                jl.jobExecutionVetoed(jec);
1860            } catch (Exception JavaDoc e) {
1861                SchedulerException se = new SchedulerException(
1862                        "JobListener '" + jl.getName() + "' threw exception: "
1863                        + e.getMessage(), e);
1864                se.setErrorCode(SchedulerException.ERR_JOB_LISTENER);
1865                throw se;
1866            }
1867        }
1868    }
1869
1870    public void notifyJobListenersWasExecuted(JobExecutionContext jec,
1871            JobExecutionException je) throws SchedulerException {
1872        // build a list of all job listeners that are to be notified...
1873
List JavaDoc jobListeners = buildJobListenerList(jec.getJobDetail()
1874                .getJobListenerNames());
1875
1876        // notify all job listeners
1877
java.util.Iterator JavaDoc itr = jobListeners.iterator();
1878        while (itr.hasNext()) {
1879            JobListener jl = (JobListener) itr.next();
1880            try {
1881                jl.jobWasExecuted(jec, je);
1882            } catch (Exception JavaDoc e) {
1883                SchedulerException se = new SchedulerException(
1884                        "JobListener '" + jl.getName() + "' threw exception: "
1885                                + e.getMessage(), e);
1886                se.setErrorCode(SchedulerException.ERR_JOB_LISTENER);
1887                throw se;
1888            }
1889        }
1890    }
1891
1892    public void notifySchedulerListenersError(String JavaDoc msg, SchedulerException se) {
1893        // build a list of all scheduler listeners that are to be notified...
1894
List JavaDoc schedListeners = getSchedulerListeners();
1895
1896        // notify all scheduler listeners
1897
java.util.Iterator JavaDoc itr = schedListeners.iterator();
1898        while (itr.hasNext()) {
1899            SchedulerListener sl = (SchedulerListener) itr.next();
1900            try {
1901                sl.schedulerError(msg, se);
1902            } catch (Exception JavaDoc e) {
1903                getLog()
1904                        .error(
1905                                "Error while notifying SchedulerListener of error: ",
1906                                e);
1907                getLog().error(
1908                        " Original error (for notification) was: " + msg, se);
1909            }
1910        }
1911    }
1912
1913    public void notifySchedulerListenersSchduled(Trigger trigger) {
1914        // build a list of all scheduler listeners that are to be notified...
1915
List JavaDoc schedListeners = getSchedulerListeners();
1916
1917        // notify all scheduler listeners
1918
java.util.Iterator JavaDoc itr = schedListeners.iterator();
1919        while (itr.hasNext()) {
1920            SchedulerListener sl = (SchedulerListener) itr.next();
1921            try {
1922                sl.jobScheduled(trigger);
1923            } catch (Exception JavaDoc e) {
1924                getLog().error(
1925                        "Error while notifying SchedulerListener of scheduled job."
1926                                + " Triger=" + trigger.getFullName(), e);
1927            }
1928        }
1929    }
1930
1931    public void notifySchedulerListenersUnschduled(String JavaDoc triggerName,
1932            String JavaDoc triggerGroup) {
1933        // build a list of all scheduler listeners that are to be notified...
1934
List JavaDoc schedListeners = getSchedulerListeners();
1935
1936        // notify all scheduler listeners
1937
java.util.Iterator JavaDoc itr = schedListeners.iterator();
1938        while (itr.hasNext()) {
1939            SchedulerListener sl = (SchedulerListener) itr.next();
1940            try {
1941                sl.jobUnscheduled(triggerName, triggerGroup);
1942            } catch (Exception JavaDoc e) {
1943                getLog().error(
1944                        "Error while notifying SchedulerListener of unscheduled job."
1945                                + " Triger=" + triggerGroup + "."
1946                                + triggerName, e);
1947            }
1948        }
1949    }
1950
1951    public void notifySchedulerListenersFinalized(Trigger trigger) {
1952        // build a list of all scheduler listeners that are to be notified...
1953
List JavaDoc schedListeners = getSchedulerListeners();
1954
1955        // notify all scheduler listeners
1956
java.util.Iterator JavaDoc itr = schedListeners.iterator();
1957        while (itr.hasNext()) {
1958            SchedulerListener sl = (SchedulerListener) itr.next();
1959            try {
1960                sl.triggerFinalized(trigger);
1961            } catch (Exception JavaDoc e) {
1962                getLog().error(
1963                        "Error while notifying SchedulerListener of finalized trigger."
1964                                + " Triger=" + trigger.getFullName(), e);
1965            }
1966        }
1967    }
1968
1969    public void notifySchedulerListenersPausedTrigger(String JavaDoc name, String JavaDoc group) {
1970        // build a list of all job listeners that are to be notified...
1971
List JavaDoc schedListeners = getSchedulerListeners();
1972
1973        // notify all scheduler listeners
1974
java.util.Iterator JavaDoc itr = schedListeners.iterator();
1975        while (itr.hasNext()) {
1976            SchedulerListener sl = (SchedulerListener) itr.next();
1977            try {
1978                sl.triggersPaused(name, group);
1979            } catch (Exception JavaDoc e) {
1980                getLog().error(
1981                        "Error while notifying SchedulerListener of paused trigger/group."
1982                                + " Triger=" + group + "." + name, e);
1983            }
1984        }
1985    }
1986
1987    public void notifySchedulerListenersResumedTrigger(String JavaDoc name, String JavaDoc group) {
1988        // build a list of all job listeners that are to be notified...
1989
List JavaDoc schedListeners = getSchedulerListeners();
1990
1991        // notify all scheduler listeners
1992
java.util.Iterator JavaDoc itr = schedListeners.iterator();
1993        while (itr.hasNext()) {
1994            SchedulerListener sl = (SchedulerListener) itr.next();
1995            try {
1996                sl.triggersResumed(name, group);
1997            } catch (Exception JavaDoc e) {
1998                getLog().error(
1999                        "Error while notifying SchedulerListener of resumed trigger/group."
2000                                + " Triger=" + group + "." + name, e);
2001            }
2002        }
2003    }
2004
2005    public void notifySchedulerListenersPausedJob(String JavaDoc name, String JavaDoc group) {
2006        // build a list of all job listeners that are to be notified...
2007
List JavaDoc schedListeners = getSchedulerListeners();
2008
2009        // notify all scheduler listeners
2010
java.util.Iterator JavaDoc itr = schedListeners.iterator();
2011        while (itr.hasNext()) {
2012            SchedulerListener sl = (SchedulerListener) itr.next();
2013            try {
2014                sl.jobsPaused(name, group);
2015            } catch (Exception JavaDoc e) {
2016                getLog().error(
2017                        "Error while notifying SchedulerListener of paused job/group."
2018                                + " Job=" + group + "." + name, e);
2019            }
2020        }
2021    }
2022
2023    public void notifySchedulerListenersResumedJob(String JavaDoc name, String JavaDoc group) {
2024        // build a list of all job listeners that are to be notified...
2025
List JavaDoc schedListeners = getSchedulerListeners();
2026
2027        // notify all scheduler listeners
2028
java.util.Iterator JavaDoc itr = schedListeners.iterator();
2029        while (itr.hasNext()) {
2030            SchedulerListener sl = (SchedulerListener) itr.next();
2031            try {
2032                sl.jobsResumed(name, group);
2033            } catch (Exception JavaDoc e) {
2034                getLog().error(
2035                        "Error while notifying SchedulerListener of resumed job/group."
2036                                + " Job=" + group + "." + name, e);
2037            }
2038        }
2039    }
2040
2041    public void notifySchedulerListenersShutdown() {
2042        // build a list of all job listeners that are to be notified...
2043
List JavaDoc schedListeners = getSchedulerListeners();
2044
2045        // notify all scheduler listeners
2046
java.util.Iterator JavaDoc itr = schedListeners.iterator();
2047        while (itr.hasNext()) {
2048            SchedulerListener sl = (SchedulerListener) itr.next();
2049            try {
2050                sl.schedulerShutdown();
2051            } catch (Exception JavaDoc e) {
2052                getLog().error(
2053                        "Error while notifying SchedulerListener of shutdown.",
2054                        e);
2055            }
2056        }
2057    }
2058
2059    public void setJobFactory(JobFactory factory) throws SchedulerException {
2060
2061        if(factory == null) {
2062            throw new IllegalArgumentException JavaDoc("JobFactory cannot be set to null!");
2063        }
2064
2065        getLog().info("JobFactory set to: " + factory);
2066
2067        this.jobFactory = factory;
2068    }
2069    
2070    public JobFactory getJobFactory() {
2071        return jobFactory;
2072    }
2073    
2074    
2075    /**
2076     * Interrupt all instances of the identified InterruptableJob executing in
2077     * this Scheduler instance.
2078     *
2079     * <p>
2080     * This method is not cluster aware. That is, it will only interrupt
2081     * instances of the identified InterruptableJob currently executing in this
2082     * Scheduler instance, not across the entire cluster.
2083     * </p>
2084     *
2085     * @see org.quartz.core.RemotableQuartzScheduler#interrupt(org.quartz.core.SchedulingContext, java.lang.String, java.lang.String)
2086     */

2087    public boolean interrupt(SchedulingContext ctxt, String JavaDoc jobName, String JavaDoc groupName) throws UnableToInterruptJobException {
2088
2089        if(groupName == null) {
2090            groupName = Scheduler.DEFAULT_GROUP;
2091        }
2092        
2093        List JavaDoc jobs = getCurrentlyExecutingJobs();
2094        java.util.Iterator JavaDoc it = jobs.iterator();
2095        
2096        JobExecutionContext jec = null;
2097        JobDetail jobDetail = null;
2098        Job job = null;
2099        
2100        boolean interrupted = false;
2101        
2102        while (it.hasNext()) {
2103            jec = (JobExecutionContext)it.next();
2104            jobDetail = jec.getJobDetail();
2105            if (jobName.equals(jobDetail.getName())
2106                && groupName.equals(jobDetail.getGroup())){
2107                job = jec.getJobInstance();
2108                if (job instanceof InterruptableJob) {
2109                    ((InterruptableJob)job).interrupt();
2110                    interrupted = true;
2111                } else {
2112                    throw new UnableToInterruptJobException(
2113                        "Job '"
2114                        + jobName
2115                        + "' of group '"
2116                        + groupName
2117                        + "' can not be interrupted, since it does not implement "
2118                        + InterruptableJob.class.getName());
2119                    
2120                }
2121            }
2122        }
2123        
2124        return interrupted;
2125    }
2126    
2127    private void shutdownPlugins() {
2128        java.util.Iterator JavaDoc itr = resources.getSchedulerPlugins().iterator();
2129        while (itr.hasNext()) {
2130            SchedulerPlugin plugin = (SchedulerPlugin) itr.next();
2131            plugin.shutdown();
2132        }
2133    }
2134
2135    private void startPlugins() {
2136        java.util.Iterator JavaDoc itr = resources.getSchedulerPlugins().iterator();
2137        while (itr.hasNext()) {
2138            SchedulerPlugin plugin = (SchedulerPlugin) itr.next();
2139            plugin.start();
2140        }
2141    }
2142
2143}
2144
2145/////////////////////////////////////////////////////////////////////////////
2146
//
2147
// ErrorLogger - Scheduler Listener Class
2148
//
2149
/////////////////////////////////////////////////////////////////////////////
2150

2151class ErrorLogger extends SchedulerListenerSupport {
2152    ErrorLogger() {
2153    }
2154    
2155    public void schedulerError(String JavaDoc msg, SchedulerException cause) {
2156        getLog().error(msg, cause);
2157    }
2158}
2159
2160/////////////////////////////////////////////////////////////////////////////
2161
//
2162
// ExecutingJobsManager - Job Listener Class
2163
//
2164
/////////////////////////////////////////////////////////////////////////////
2165

2166class ExecutingJobsManager implements JobListener {
2167    HashMap JavaDoc executingJobs = new HashMap JavaDoc();
2168
2169    int numJobsFired = 0;
2170
2171    ExecutingJobsManager() {
2172    }
2173
2174    public String JavaDoc getName() {
2175        return getClass().getName();
2176    }
2177
2178    public int getNumJobsCurrentlyExecuting() {
2179        synchronized (executingJobs) {
2180            return executingJobs.size();
2181        }
2182    }
2183
2184    public void jobToBeExecuted(JobExecutionContext context) {
2185        numJobsFired++;
2186
2187        synchronized (executingJobs) {
2188            executingJobs
2189                    .put(context.getTrigger().getFireInstanceId(), context);
2190        }
2191    }
2192
2193    public void jobWasExecuted(JobExecutionContext context,
2194            JobExecutionException jobException) {
2195        synchronized (executingJobs) {
2196            executingJobs.remove(context.getTrigger().getFireInstanceId());
2197        }
2198    }
2199
2200    public int getNumJobsFired() {
2201        return numJobsFired;
2202    }
2203
2204    public List JavaDoc getExecutingJobs() {
2205        synchronized (executingJobs) {
2206            return java.util.Collections.unmodifiableList(new ArrayList JavaDoc(
2207                    executingJobs.values()));
2208        }
2209    }
2210
2211    public void jobExecutionVetoed(JobExecutionContext context) {
2212        
2213    }
2214}
2215
Popular Tags