001: /*
002: * Copyright 2004-2005 OpenSymphony
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy
006: * of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations
014: * under the License.
015: *
016: */
017:
018: /*
019: * Previously Copyright (c) 2001-2004 James House
020: */
021: package org.quartz.spi;
022:
023: import java.util.Set;
024:
025: import org.quartz.Calendar;
026: import org.quartz.JobDetail;
027: import org.quartz.JobPersistenceException;
028: import org.quartz.ObjectAlreadyExistsException;
029: import org.quartz.SchedulerConfigException;
030: import org.quartz.SchedulerException;
031: import org.quartz.Trigger;
032: import org.quartz.core.SchedulingContext;
033:
034: /**
035: * <p>
036: * The interface to be implemented by classes that want to provide a <code>{@link org.quartz.Job}</code>
037: * and <code>{@link org.quartz.Trigger}</code> storage mechanism for the
038: * <code>{@link org.quartz.core.QuartzScheduler}</code>'s use.
039: * </p>
040: *
041: * <p>
042: * Storage of <code>Job</code> s and <code>Trigger</code> s should be keyed
043: * on the combination of their name and group for uniqueness.
044: * </p>
045: *
046: * @see org.quartz.core.QuartzScheduler
047: * @see org.quartz.Trigger
048: * @see org.quartz.Job
049: * @see org.quartz.JobDetail
050: * @see org.quartz.JobDataMap
051: * @see org.quartz.Calendar
052: *
053: * @author James House
054: * @author Eric Mueller
055: */
056: public interface JobStore {
057:
058: /*
059: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
060: *
061: * Interface.
062: *
063: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
064: */
065:
066: /**
067: * <p>
068: * Called by the QuartzScheduler before the <code>JobStore</code> is
069: * used, in order to give the it a chance to initialize.
070: * </p>
071: */
072: void initialize(ClassLoadHelper loadHelper,
073: SchedulerSignaler signaler) throws SchedulerConfigException;
074:
075: /**
076: * <p>
077: * Called by the QuartzScheduler to inform the <code>JobStore</code> that
078: * the scheduler has started.
079: * </p>
080: */
081: void schedulerStarted() throws SchedulerException;
082:
083: /**
084: * <p>
085: * Called by the QuartzScheduler to inform the <code>JobStore</code> that
086: * it should free up all of it's resources because the scheduler is
087: * shutting down.
088: * </p>
089: */
090: void shutdown();
091:
092: boolean supportsPersistence();
093:
094: /////////////////////////////////////////////////////////////////////////////
095: //
096: // Job & Trigger Storage methods
097: //
098: /////////////////////////////////////////////////////////////////////////////
099:
100: /**
101: * <p>
102: * Store the given <code>{@link org.quartz.JobDetail}</code> and <code>{@link org.quartz.Trigger}</code>.
103: * </p>
104: *
105: * @param newJob
106: * The <code>JobDetail</code> to be stored.
107: * @param newTrigger
108: * The <code>Trigger</code> to be stored.
109: * @throws ObjectAlreadyExistsException
110: * if a <code>Job</code> with the same name/group already
111: * exists.
112: */
113: void storeJobAndTrigger(SchedulingContext ctxt, JobDetail newJob,
114: Trigger newTrigger) throws ObjectAlreadyExistsException,
115: JobPersistenceException;
116:
117: /**
118: * <p>
119: * Store the given <code>{@link org.quartz.JobDetail}</code>.
120: * </p>
121: *
122: * @param newJob
123: * The <code>JobDetail</code> to be stored.
124: * @param replaceExisting
125: * If <code>true</code>, any <code>Job</code> existing in the
126: * <code>JobStore</code> with the same name & group should be
127: * over-written.
128: * @throws ObjectAlreadyExistsException
129: * if a <code>Job</code> with the same name/group already
130: * exists, and replaceExisting is set to false.
131: */
132: void storeJob(SchedulingContext ctxt, JobDetail newJob,
133: boolean replaceExisting)
134: throws ObjectAlreadyExistsException,
135: JobPersistenceException;
136:
137: /**
138: * <p>
139: * Remove (delete) the <code>{@link org.quartz.Job}</code> with the given
140: * name, and any <code>{@link org.quartz.Trigger}</code> s that reference
141: * it.
142: * </p>
143: *
144: * <p>
145: * If removal of the <code>Job</code> results in an empty group, the
146: * group should be removed from the <code>JobStore</code>'s list of
147: * known group names.
148: * </p>
149: *
150: * @param jobName
151: * The name of the <code>Job</code> to be removed.
152: * @param groupName
153: * The group name of the <code>Job</code> to be removed.
154: * @return <code>true</code> if a <code>Job</code> with the given name &
155: * group was found and removed from the store.
156: */
157: boolean removeJob(SchedulingContext ctxt, String jobName,
158: String groupName) throws JobPersistenceException;
159:
160: /**
161: * <p>
162: * Retrieve the <code>{@link org.quartz.JobDetail}</code> for the given
163: * <code>{@link org.quartz.Job}</code>.
164: * </p>
165: *
166: * @param jobName
167: * The name of the <code>Job</code> to be retrieved.
168: * @param groupName
169: * The group name of the <code>Job</code> to be retrieved.
170: * @return The desired <code>Job</code>, or null if there is no match.
171: */
172: JobDetail retrieveJob(SchedulingContext ctxt, String jobName,
173: String groupName) throws JobPersistenceException;
174:
175: /**
176: * <p>
177: * Store the given <code>{@link org.quartz.Trigger}</code>.
178: * </p>
179: *
180: * @param newTrigger
181: * The <code>Trigger</code> to be stored.
182: * @param replaceExisting
183: * If <code>true</code>, any <code>Trigger</code> existing in
184: * the <code>JobStore</code> with the same name & group should
185: * be over-written.
186: * @throws ObjectAlreadyExistsException
187: * if a <code>Trigger</code> with the same name/group already
188: * exists, and replaceExisting is set to false.
189: *
190: * @see #pauseTriggerGroup(SchedulingContext, String)
191: */
192: void storeTrigger(SchedulingContext ctxt, Trigger newTrigger,
193: boolean replaceExisting)
194: throws ObjectAlreadyExistsException,
195: JobPersistenceException;
196:
197: /**
198: * <p>
199: * Remove (delete) the <code>{@link org.quartz.Trigger}</code> with the
200: * given name.
201: * </p>
202: *
203: * <p>
204: * If removal of the <code>Trigger</code> results in an empty group, the
205: * group should be removed from the <code>JobStore</code>'s list of
206: * known group names.
207: * </p>
208: *
209: * <p>
210: * If removal of the <code>Trigger</code> results in an 'orphaned' <code>Job</code>
211: * that is not 'durable', then the <code>Job</code> should be deleted
212: * also.
213: * </p>
214: *
215: * @param triggerName
216: * The name of the <code>Trigger</code> to be removed.
217: * @param groupName
218: * The group name of the <code>Trigger</code> to be removed.
219: * @return <code>true</code> if a <code>Trigger</code> with the given
220: * name & group was found and removed from the store.
221: */
222: boolean removeTrigger(SchedulingContext ctxt, String triggerName,
223: String groupName) throws JobPersistenceException;
224:
225: /**
226: * <p>
227: * Remove (delete) the <code>{@link org.quartz.Trigger}</code> with the
228: * given name, and store the new given one - which must be associated
229: * with the same job.
230: * </p>
231: *
232: * @param triggerName
233: * The name of the <code>Trigger</code> to be removed.
234: * @param groupName
235: * The group name of the <code>Trigger</code> to be removed.
236: * @param newTrigger
237: * The new <code>Trigger</code> to be stored.
238: * @return <code>true</code> if a <code>Trigger</code> with the given
239: * name & group was found and removed from the store.
240: */
241: boolean replaceTrigger(SchedulingContext ctxt, String triggerName,
242: String groupName, Trigger newTrigger)
243: throws JobPersistenceException;
244:
245: /**
246: * <p>
247: * Retrieve the given <code>{@link org.quartz.Trigger}</code>.
248: * </p>
249: *
250: * @param triggerName
251: * The name of the <code>Trigger</code> to be retrieved.
252: * @param groupName
253: * The group name of the <code>Trigger</code> to be retrieved.
254: * @return The desired <code>Trigger</code>, or null if there is no
255: * match.
256: */
257: Trigger retrieveTrigger(SchedulingContext ctxt, String triggerName,
258: String groupName) throws JobPersistenceException;
259:
260: /**
261: * <p>
262: * Store the given <code>{@link org.quartz.Calendar}</code>.
263: * </p>
264: *
265: * @param calendar
266: * The <code>Calendar</code> to be stored.
267: * @param replaceExisting
268: * If <code>true</code>, any <code>Calendar</code> existing
269: * in the <code>JobStore</code> with the same name & group
270: * should be over-written.
271: * @param updateTriggers
272: * If <code>true</code>, any <code>Trigger</code>s existing
273: * in the <code>JobStore</code> that reference an existing
274: * Calendar with the same name with have their next fire time
275: * re-computed with the new <code>Calendar</code>.
276: * @throws ObjectAlreadyExistsException
277: * if a <code>Calendar</code> with the same name already
278: * exists, and replaceExisting is set to false.
279: */
280: void storeCalendar(SchedulingContext ctxt, String name,
281: Calendar calendar, boolean replaceExisting,
282: boolean updateTriggers)
283: throws ObjectAlreadyExistsException,
284: JobPersistenceException;
285:
286: /**
287: * <p>
288: * Remove (delete) the <code>{@link org.quartz.Calendar}</code> with the
289: * given name.
290: * </p>
291: *
292: * <p>
293: * If removal of the <code>Calendar</code> would result in
294: * <code.Trigger</code>s pointing to non-existent calendars, then a
295: * <code>JobPersistenceException</code> will be thrown.</p>
296: * *
297: * @param calName The name of the <code>Calendar</code> to be removed.
298: * @return <code>true</code> if a <code>Calendar</code> with the given name
299: * was found and removed from the store.
300: */
301: boolean removeCalendar(SchedulingContext ctxt, String calName)
302: throws JobPersistenceException;
303:
304: /**
305: * <p>
306: * Retrieve the given <code>{@link org.quartz.Trigger}</code>.
307: * </p>
308: *
309: * @param calName
310: * The name of the <code>Calendar</code> to be retrieved.
311: * @return The desired <code>Calendar</code>, or null if there is no
312: * match.
313: */
314: Calendar retrieveCalendar(SchedulingContext ctxt, String calName)
315: throws JobPersistenceException;
316:
317: /////////////////////////////////////////////////////////////////////////////
318: //
319: // Informational methods
320: //
321: /////////////////////////////////////////////////////////////////////////////
322:
323: /**
324: * <p>
325: * Get the number of <code>{@link org.quartz.Job}</code> s that are
326: * stored in the <code>JobsStore</code>.
327: * </p>
328: */
329: int getNumberOfJobs(SchedulingContext ctxt)
330: throws JobPersistenceException;
331:
332: /**
333: * <p>
334: * Get the number of <code>{@link org.quartz.Trigger}</code> s that are
335: * stored in the <code>JobsStore</code>.
336: * </p>
337: */
338: int getNumberOfTriggers(SchedulingContext ctxt)
339: throws JobPersistenceException;
340:
341: /**
342: * <p>
343: * Get the number of <code>{@link org.quartz.Calendar}</code> s that are
344: * stored in the <code>JobsStore</code>.
345: * </p>
346: */
347: int getNumberOfCalendars(SchedulingContext ctxt)
348: throws JobPersistenceException;
349:
350: /**
351: * <p>
352: * Get the names of all of the <code>{@link org.quartz.Job}</code> s that
353: * have the given group name.
354: * </p>
355: *
356: * <p>
357: * If there are no jobs in the given group name, the result should be a
358: * zero-length array (not <code>null</code>).
359: * </p>
360: */
361: String[] getJobNames(SchedulingContext ctxt, String groupName)
362: throws JobPersistenceException;
363:
364: /**
365: * <p>
366: * Get the names of all of the <code>{@link org.quartz.Trigger}</code> s
367: * that have the given group name.
368: * </p>
369: *
370: * <p>
371: * If there are no triggers in the given group name, the result should be a
372: * zero-length array (not <code>null</code>).
373: * </p>
374: */
375: String[] getTriggerNames(SchedulingContext ctxt, String groupName)
376: throws JobPersistenceException;
377:
378: /**
379: * <p>
380: * Get the names of all of the <code>{@link org.quartz.Job}</code>
381: * groups.
382: * </p>
383: *
384: * <p>
385: * If there are no known group names, the result should be a zero-length
386: * array (not <code>null</code>).
387: * </p>
388: */
389: String[] getJobGroupNames(SchedulingContext ctxt)
390: throws JobPersistenceException;
391:
392: /**
393: * <p>
394: * Get the names of all of the <code>{@link org.quartz.Trigger}</code>
395: * groups.
396: * </p>
397: *
398: * <p>
399: * If there are no known group names, the result should be a zero-length
400: * array (not <code>null</code>).
401: * </p>
402: */
403: String[] getTriggerGroupNames(SchedulingContext ctxt)
404: throws JobPersistenceException;
405:
406: /**
407: * <p>
408: * Get the names of all of the <code>{@link org.quartz.Calendar}</code> s
409: * in the <code>JobStore</code>.
410: * </p>
411: *
412: * <p>
413: * If there are no Calendars in the given group name, the result should be
414: * a zero-length array (not <code>null</code>).
415: * </p>
416: */
417: String[] getCalendarNames(SchedulingContext ctxt)
418: throws JobPersistenceException;
419:
420: /**
421: * <p>
422: * Get all of the Triggers that are associated to the given Job.
423: * </p>
424: *
425: * <p>
426: * If there are no matches, a zero-length array should be returned.
427: * </p>
428: */
429: Trigger[] getTriggersForJob(SchedulingContext ctxt, String jobName,
430: String groupName) throws JobPersistenceException;
431:
432: /**
433: * <p>
434: * Get the current state of the identified <code>{@link Trigger}</code>.
435: * </p>
436: *
437: * @see Trigger#STATE_NORMAL
438: * @see Trigger#STATE_PAUSED
439: * @see Trigger#STATE_COMPLETE
440: * @see Trigger#STATE_ERROR
441: * @see Trigger#STATE_NONE
442: */
443: int getTriggerState(SchedulingContext ctxt, String triggerName,
444: String triggerGroup) throws JobPersistenceException;
445:
446: /////////////////////////////////////////////////////////////////////////////
447: //
448: // Trigger State manipulation methods
449: //
450: /////////////////////////////////////////////////////////////////////////////
451:
452: /**
453: * <p>
454: * Pause the <code>{@link org.quartz.Trigger}</code> with the given name.
455: * </p>
456: *
457: * @see #resumeTrigger(SchedulingContext, String, String)
458: */
459: void pauseTrigger(SchedulingContext ctxt, String triggerName,
460: String groupName) throws JobPersistenceException;
461:
462: /**
463: * <p>
464: * Pause all of the <code>{@link org.quartz.Trigger}s</code> in the
465: * given group.
466: * </p>
467: *
468: *
469: * <p>
470: * The JobStore should "remember" that the group is paused, and impose the
471: * pause on any new triggers that are added to the group while the group is
472: * paused.
473: * </p>
474: *
475: * @see #resumeTriggerGroup(SchedulingContext, String)
476: */
477: void pauseTriggerGroup(SchedulingContext ctxt, String groupName)
478: throws JobPersistenceException;
479:
480: /**
481: * <p>
482: * Pause the <code>{@link org.quartz.Job}</code> with the given name - by
483: * pausing all of its current <code>Trigger</code>s.
484: * </p>
485: *
486: * @see #resumeJob(SchedulingContext, String, String)
487: */
488: void pauseJob(SchedulingContext ctxt, String jobName,
489: String groupName) throws JobPersistenceException;
490:
491: /**
492: * <p>
493: * Pause all of the <code>{@link org.quartz.Job}s</code> in the given
494: * group - by pausing all of their <code>Trigger</code>s.
495: * </p>
496: *
497: * <p>
498: * The JobStore should "remember" that the group is paused, and impose the
499: * pause on any new jobs that are added to the group while the group is
500: * paused.
501: * </p>
502: *
503: * @see #resumeJobGroup(SchedulingContext, String)
504: */
505: void pauseJobGroup(SchedulingContext ctxt, String groupName)
506: throws JobPersistenceException;
507:
508: /**
509: * <p>
510: * Resume (un-pause) the <code>{@link org.quartz.Trigger}</code> with the
511: * given name.
512: * </p>
513: *
514: * <p>
515: * If the <code>Trigger</code> missed one or more fire-times, then the
516: * <code>Trigger</code>'s misfire instruction will be applied.
517: * </p>
518: *
519: * @see #pauseTrigger(SchedulingContext, String, String)
520: */
521: void resumeTrigger(SchedulingContext ctxt, String triggerName,
522: String groupName) throws JobPersistenceException;
523:
524: /**
525: * <p>
526: * Resume (un-pause) all of the <code>{@link org.quartz.Trigger}s</code>
527: * in the given group.
528: * </p>
529: *
530: * <p>
531: * If any <code>Trigger</code> missed one or more fire-times, then the
532: * <code>Trigger</code>'s misfire instruction will be applied.
533: * </p>
534: *
535: * @see #pauseTriggerGroup(SchedulingContext, String)
536: */
537: void resumeTriggerGroup(SchedulingContext ctxt, String groupName)
538: throws JobPersistenceException;
539:
540: Set getPausedTriggerGroups(SchedulingContext ctxt)
541: throws JobPersistenceException;
542:
543: /**
544: * <p>
545: * Resume (un-pause) the <code>{@link org.quartz.Job}</code> with the
546: * given name.
547: * </p>
548: *
549: * <p>
550: * If any of the <code>Job</code>'s<code>Trigger</code> s missed one
551: * or more fire-times, then the <code>Trigger</code>'s misfire
552: * instruction will be applied.
553: * </p>
554: *
555: * @see #pauseJob(SchedulingContext, String, String)
556: */
557: void resumeJob(SchedulingContext ctxt, String jobName,
558: String groupName) throws JobPersistenceException;
559:
560: /**
561: * <p>
562: * Resume (un-pause) all of the <code>{@link org.quartz.Job}s</code> in
563: * the given group.
564: * </p>
565: *
566: * <p>
567: * If any of the <code>Job</code> s had <code>Trigger</code> s that
568: * missed one or more fire-times, then the <code>Trigger</code>'s
569: * misfire instruction will be applied.
570: * </p>
571: *
572: * @see #pauseJobGroup(SchedulingContext, String)
573: */
574: void resumeJobGroup(SchedulingContext ctxt, String groupName)
575: throws JobPersistenceException;
576:
577: /**
578: * <p>
579: * Pause all triggers - equivalent of calling <code>pauseTriggerGroup(group)</code>
580: * on every group.
581: * </p>
582: *
583: * <p>
584: * When <code>resumeAll()</code> is called (to un-pause), trigger misfire
585: * instructions WILL be applied.
586: * </p>
587: *
588: * @see #resumeAll(SchedulingContext)
589: * @see #pauseTriggerGroup(SchedulingContext, String)
590: */
591: void pauseAll(SchedulingContext ctxt)
592: throws JobPersistenceException;
593:
594: /**
595: * <p>
596: * Resume (un-pause) all triggers - equivalent of calling <code>resumeTriggerGroup(group)</code>
597: * on every group.
598: * </p>
599: *
600: * <p>
601: * If any <code>Trigger</code> missed one or more fire-times, then the
602: * <code>Trigger</code>'s misfire instruction will be applied.
603: * </p>
604: *
605: * @see #pauseAll(SchedulingContext)
606: */
607: void resumeAll(SchedulingContext ctxt)
608: throws JobPersistenceException;
609:
610: /////////////////////////////////////////////////////////////////////////////
611: //
612: // Trigger-Firing methods
613: //
614: /////////////////////////////////////////////////////////////////////////////
615:
616: /**
617: * <p>
618: * Get a handle to the next trigger to be fired, and mark it as 'reserved'
619: * by the calling scheduler.
620: * </p>
621: *
622: * @param noLaterThan If > 0, the JobStore should only return a Trigger
623: * that will fire no later than the time represented in this value as
624: * milliseconds.
625: * @see #releaseAcquiredTrigger(SchedulingContext, Trigger)
626: */
627: Trigger acquireNextTrigger(SchedulingContext ctxt, long noLaterThan)
628: throws JobPersistenceException;
629:
630: /**
631: * <p>
632: * Inform the <code>JobStore</code> that the scheduler no longer plans to
633: * fire the given <code>Trigger</code>, that it had previously acquired
634: * (reserved).
635: * </p>
636: */
637: void releaseAcquiredTrigger(SchedulingContext ctxt, Trigger trigger)
638: throws JobPersistenceException;
639:
640: /**
641: * <p>
642: * Inform the <code>JobStore</code> that the scheduler is now firing the
643: * given <code>Trigger</code> (executing its associated <code>Job</code>),
644: * that it had previously acquired (reserved).
645: * </p>
646: *
647: * @return null if the trigger or it's job or calendar no longer exist, or
648: * if the trigger was not successfully put into the 'executing'
649: * state.
650: */
651: TriggerFiredBundle triggerFired(SchedulingContext ctxt,
652: Trigger trigger) throws JobPersistenceException;
653:
654: /**
655: * <p>
656: * Inform the <code>JobStore</code> that the scheduler has completed the
657: * firing of the given <code>Trigger</code> (and the execution of its
658: * associated <code>Job</code> completed, threw an exception, or was vetoed),
659: * and that the <code>{@link org.quartz.JobDataMap}</code>
660: * in the given <code>JobDetail</code> should be updated if the <code>Job</code>
661: * is stateful.
662: * </p>
663: */
664: void triggeredJobComplete(SchedulingContext ctxt, Trigger trigger,
665: JobDetail jobDetail, int triggerInstCode)
666: throws JobPersistenceException;
667:
668: }
|