KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > quartz > SimpleTrigger


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;
23
24 import java.util.Date JavaDoc;
25
26
27 /**
28  * <p>
29  * A concrete <code>{@link Trigger}</code> that is used to fire a <code>{@link org.quartz.JobDetail}</code>
30  * at a given moment in time, and optionally repeated at a specified interval.
31  * </p>
32  *
33  * @see Trigger
34  * @see CronTrigger
35  * @see TriggerUtils
36  *
37  * @author James House
38  * @author contributions by Lieven Govaerts of Ebitec Nv, Belgium.
39  */

40 public class SimpleTrigger extends Trigger {
41
42     /*
43      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
44      *
45      * Constants.
46      *
47      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
48      */

49
50     /**
51      * <p>
52      * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire
53      * situation, the <code>{@link SimpleTrigger}</code> wants to be fired
54      * now by <code>Scheduler</code>.
55      * </p>
56      *
57      * <p>
58      * <i>NOTE:</i> This instruction should typically only be used for
59      * 'one-shot' (non-repeating) Triggers. If it is used on a trigger with a
60      * repeat count > 0 then it is equivalent to the instruction <code>{@link #MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT}
61      * </code>.
62      * </p>
63      */

64     public static final int MISFIRE_INSTRUCTION_FIRE_NOW = 1;
65
66     /**
67      * <p>
68      * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire
69      * situation, the <code>{@link SimpleTrigger}</code> wants to be
70      * re-scheduled to 'now' (even if the associated <code>{@link Calendar}</code>
71      * excludes 'now') with the repeat count left as-is. This does obey the
72      * <code>Trigger</code> end-time however, so if 'now' is after the
73      * end-time the <code>Trigger</code> will not fire again.
74      * </p>
75      *
76      * <p>
77      * <i>NOTE:</i> Use of this instruction causes the trigger to 'forget'
78      * the start-time and repeat-count that it was originally setup with (this
79      * is only an issue if you for some reason wanted to be able to tell what
80      * the original values were at some later time).
81      * </p>
82      *
83      * <p>
84      * <i>NOTE:</i> This instruction could cause the <code>Trigger</code>
85      * to go to the 'COMPLETE' state after firing 'now', if all the
86      * repeat-fire-times where missed.
87      * </p>
88      */

89     public static final int MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT = 2;
90
91     /**
92      * <p>
93      * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire
94      * situation, the <code>{@link SimpleTrigger}</code> wants to be
95      * re-scheduled to 'now' (even if the associated <code>{@link Calendar}</code>
96      * excludes 'now') with the repeat count set to what it would be, if it had
97      * not missed any firings. This does obey the <code>Trigger</code> end-time
98      * however, so if 'now' is after the end-time the <code>Trigger</code> will
99      * not fire again.
100      * </p>
101      *
102      * <p>
103      * <i>NOTE:</i> Use of this instruction causes the trigger to 'forget'
104      * the start-time and repeat-count that it was originally setup with (this
105      * is only an issue if you for some reason wanted to be able to tell what
106      * the original values were at some later time).
107      * </p>
108      *
109      * <p>
110      * <i>NOTE:</i> This instruction could cause the <code>Trigger</code>
111      * to go to the 'COMPLETE' state after firing 'now', if all the
112      * repeat-fire-times where missed.
113      * </p>
114      */

115     public static final int MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT = 3;
116
117     /**
118      * <p>
119      * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire
120      * situation, the <code>{@link SimpleTrigger}</code> wants to be
121      * re-scheduled to the next scheduled time after 'now' - taking into
122      * account any associated <code>{@link Calendar}</code>, and with the
123      * repeat count set to what it would be, if it had not missed any firings.
124      * </p>
125      *
126      * <p>
127      * <i>NOTE/WARNING:</i> This instruction could cause the <code>Trigger</code>
128      * to go directly to the 'COMPLETE' state if all fire-times where missed.
129      * </p>
130      */

131     public static final int MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT = 4;
132
133     /**
134      * <p>
135      * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire
136      * situation, the <code>{@link SimpleTrigger}</code> wants to be
137      * re-scheduled to the next scheduled time after 'now' - taking into
138      * account any associated <code>{@link Calendar}</code>, and with the
139      * repeat count left unchanged.
140      * </p>
141      *
142      * <p>
143      * <i>NOTE:</i> Use of this instruction causes the trigger to 'forget'
144      * the repeat-count that it was originally setup with (this is only an
145      * issue if you for some reason wanted to be able to tell what the original
146      * values were at some later time).
147      * </p>
148      *
149      * <p>
150      * <i>NOTE/WARNING:</i> This instruction could cause the <code>Trigger</code>
151      * to go directly to the 'COMPLETE' state if all fire-times where missed.
152      * </p>
153      */

154     public static final int MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT = 5;
155
156     /**
157      * <p>
158      * Used to indicate the 'repeat count' of the trigger is indefinite. Or in
159      * other words, the trigger should repeat continually until the trigger's
160      * ending timestamp.
161      * </p>
162      */

163     public static int REPEAT_INDEFINITELY = -1;
164
165     /*
166      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
167      *
168      * Data members.
169      *
170      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
171      */

172
173     private Date JavaDoc startTime = null;
174
175     private Date JavaDoc endTime = null;
176
177     private Date JavaDoc nextFireTime = null;
178
179     private Date JavaDoc previousFireTime = null;
180
181     private int repeatCount = 0;
182
183     private long repeatInterval = 0;
184
185     private int timesTriggered = 0;
186
187     private boolean complete = false;
188
189     /*
190      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
191      *
192      * Constructors.
193      *
194      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
195      */

196
197     /**
198      * <p>
199      * Create a <code>SimpleTrigger</code> with no settings.
200      * </p>
201      */

202     public SimpleTrigger() {
203         super();
204     }
205
206     /**
207      * <p>
208      * Create a <code>SimpleTrigger</code> that will occur immediately, and
209      * not repeat.
210      * </p>
211      */

212     public SimpleTrigger(String JavaDoc name, String JavaDoc group) {
213         this(name, group, new Date JavaDoc(), null, 0, 0);
214     }
215
216     /**
217      * <p>
218      * Create a <code>SimpleTrigger</code> that will occur immediately, and
219      * repeat at the the given interval the given number of times.
220      * </p>
221      */

222     public SimpleTrigger(String JavaDoc name, String JavaDoc group, int repeatCount,
223             long repeatInterval) {
224         this(name, group, new Date JavaDoc(), null, repeatCount, repeatInterval);
225     }
226
227     /**
228      * <p>
229      * Create a <code>SimpleTrigger</code> that will occur at the given time,
230      * and not repeat.
231      * </p>
232      */

233     public SimpleTrigger(String JavaDoc name, String JavaDoc group, Date JavaDoc startTime) {
234         this(name, group, startTime, null, 0, 0);
235     }
236
237     /**
238      * <p>
239      * Create a <code>SimpleTrigger</code> that will occur at the given time,
240      * and repeat at the the given interval the given number of times, or until
241      * the given end time.
242      * </p>
243      *
244      * @param startTime
245      * A <code>Date</code> set to the time for the <code>Trigger</code>
246      * to fire.
247      * @param endTime
248      * A <code>Date</code> set to the time for the <code>Trigger</code>
249      * to quit repeat firing.
250      * @param repeatCount
251      * The number of times for the <code>Trigger</code> to repeat
252      * firing, use {@link #REPEAT_INDEFINITELY}for unlimitted times.
253      * @param repeatInterval
254      * The number of milliseconds to pause between the repeat firing.
255      */

256     public SimpleTrigger(String JavaDoc name, String JavaDoc group, Date JavaDoc startTime,
257             Date JavaDoc endTime, int repeatCount, long repeatInterval) {
258         super(name, group);
259
260         setStartTime(startTime);
261         setEndTime(endTime);
262         setRepeatCount(repeatCount);
263         setRepeatInterval(repeatInterval);
264     }
265
266     /**
267      * <p>
268      * Create a <code>SimpleTrigger</code> that will occur at the given time,
269      * fire the identified <code>Job</code> and repeat at the the given
270      * interval the given number of times, or until the given end time.
271      * </p>
272      *
273      * @param startTime
274      * A <code>Date</code> set to the time for the <code>Trigger</code>
275      * to fire.
276      * @param endTime
277      * A <code>Date</code> set to the time for the <code>Trigger</code>
278      * to quit repeat firing.
279      * @param repeatCount
280      * The number of times for the <code>Trigger</code> to repeat
281      * firing, use {@link #REPEAT_INDEFINITELY}for unlimitted times.
282      * @param repeatInterval
283      * The number of milliseconds to pause between the repeat firing.
284      */

285     public SimpleTrigger(String JavaDoc name, String JavaDoc group, String JavaDoc jobName,
286             String JavaDoc jobGroup, Date JavaDoc startTime, Date JavaDoc endTime, int repeatCount,
287             long repeatInterval) {
288         super(name, group, jobName, jobGroup);
289
290         setStartTime(startTime);
291         setEndTime(endTime);
292         setRepeatCount(repeatCount);
293         setRepeatInterval(repeatInterval);
294     }
295
296     /*
297      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
298      *
299      * Interface.
300      *
301      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
302      */

303
304     /**
305      * <p>
306      * Get the time at which the <code>SimpleTrigger</code> should occur.
307      * </p>
308      */

309     public Date JavaDoc getStartTime() {
310         return startTime;
311     }
312
313     /**
314      * <p>
315      * Set the time at which the <code>SimpleTrigger</code> should occur.
316      * </p>
317      *
318      * @exception IllegalArgumentException
319      * if startTime is <code>null</code>.
320      */

321     public void setStartTime(Date JavaDoc startTime) {
322         if (startTime == null) {
323             throw new IllegalArgumentException JavaDoc("Start time cannot be null");
324         }
325
326         Date JavaDoc eTime = getEndTime();
327         if (eTime != null && startTime != null && eTime.before(startTime)) {
328             throw new IllegalArgumentException JavaDoc(
329                 "End time cannot be before start time");
330         }
331
332         this.startTime = startTime;
333     }
334
335     /**
336      * <p>
337      * Get the time at which the <code>SimpleTrigger</code> should quit
338      * repeating - even if repeastCount isn't yet satisfied.
339      * </p>
340      *
341      * @see #getFinalFireTime()
342      */

343     public Date JavaDoc getEndTime() {
344         return endTime;
345     }
346
347     /**
348      * <p>
349      * Set the time at which the <code>SimpleTrigger</code> should quit
350      * repeating (and be automatically deleted).
351      * </p>
352      *
353      * @exception IllegalArgumentException
354      * if endTime is before start time.
355      */

356     public void setEndTime(Date JavaDoc endTime) {
357         Date JavaDoc sTime = getStartTime();
358         if (sTime != null && endTime != null && sTime.after(endTime)) {
359             throw new IllegalArgumentException JavaDoc(
360                     "End time cannot be before start time");
361         }
362
363         this.endTime = endTime;
364     }
365
366     /**
367      * <p>
368      * Get the the number of times the <code>SimpleTrigger</code> should
369      * repeat, after which it will be automatically deleted.
370      * </p>
371      *
372      * @see #REPEAT_INDEFINITELY
373      */

374     public int getRepeatCount() {
375         return repeatCount;
376     }
377
378     /**
379      * <p>
380      * Set the the number of time the <code>SimpleTrigger</code> should
381      * repeat, after which it will be automatically deleted.
382      * </p>
383      *
384      * @see #REPEAT_INDEFINITELY
385      * @exception IllegalArgumentException
386      * if repeatCount is < 0
387      */

388     public void setRepeatCount(int repeatCount) {
389         if (repeatCount < 0 && repeatCount != REPEAT_INDEFINITELY) {
390             throw new IllegalArgumentException JavaDoc(
391                     "Repeat count must be >= 0, use the "
392                             + "constant REPEAT_INDEFINITELY for infinite.");
393         }
394
395         this.repeatCount = repeatCount;
396     }
397
398     /**
399      * <p>
400      * Get the the time interval (in milliseconds) at which the <code>SimpleTrigger</code>
401      * should repeat.
402      * </p>
403      */

404     public long getRepeatInterval() {
405         return repeatInterval;
406     }
407
408     /**
409      * <p>
410      * Set the the time interval (in milliseconds) at which the <code>SimpleTrigger</code>
411      * should repeat.
412      * </p>
413      *
414      * @exception IllegalArgumentException
415      * if repeatInterval is <= 0
416      */

417     public void setRepeatInterval(long repeatInterval) {
418         if (repeatInterval < 0) {
419             throw new IllegalArgumentException JavaDoc(
420                     "Repeat interval must be >= 0");
421         }
422
423         this.repeatInterval = repeatInterval;
424     }
425
426     /**
427      * <p>
428      * Get the number of times the <code>SimpleTrigger</code> has already
429      * fired.
430      * </p>
431      */

432     public int getTimesTriggered() {
433         return timesTriggered;
434     }
435
436     /**
437      * <p>
438      * Set the number of times the <code>SimpleTrigger</code> has already
439      * fired.
440      * </p>
441      */

442     public void setTimesTriggered(int timesTriggered) {
443         this.timesTriggered = timesTriggered;
444     }
445
446     protected boolean validateMisfireInstruction(int misfireInstruction) {
447         if (misfireInstruction < MISFIRE_INSTRUCTION_SMART_POLICY) {
448             return false;
449         }
450
451         if (misfireInstruction > MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT) {
452             return false;
453         }
454
455         return true;
456     }
457
458     /**
459      * <p>
460      * Updates the <code>SimpleTrigger</code>'s state based on the
461      * MISFIRE_INSTRUCTION_XXX that was selected when the <code>SimpleTrigger</code>
462      * was created.
463      * </p>
464      *
465      * <p>
466      * If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY,
467      * then the following scheme will be used: <br>
468      * <ul>
469      * <li>If the Repeat Count is <code>0</code>, then the instruction will
470      * be interpreted as <code>MISFIRE_INSTRUCTION_FIRE_NOW</code>.</li>
471      * <li>If the Repeat Count is <code>REPEAT_INDEFINITELY</code>, then
472      * the instruction will be interpreted as <code>MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT</code>.
473      * <b>WARNING:</b> using MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
474      * with a trigger that has a non-null end-time may cause the trigger to
475      * never fire again if the end-time arrived during the misfire time span.
476      * </li>
477      * <li>If the Repeat Count is <code>> 0</code>, then the instruction
478      * will be interpreted as <code>MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT</code>.
479      * </li>
480      * </ul>
481      * </p>
482      */

483     public void updateAfterMisfire(Calendar cal) {
484         int instr = getMisfireInstruction();
485         if (instr == Trigger.MISFIRE_INSTRUCTION_SMART_POLICY) {
486             if (getRepeatCount() == 0) {
487                 instr = MISFIRE_INSTRUCTION_FIRE_NOW;
488             } else if (getRepeatCount() == REPEAT_INDEFINITELY) {
489                 instr = MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT;
490             } else {
491                 // if (getRepeatCount() > 0)
492
instr = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT;
493             }
494         } else if (instr == MISFIRE_INSTRUCTION_FIRE_NOW && getRepeatCount() != 0) {
495             instr = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT;
496         }
497
498         if (instr == MISFIRE_INSTRUCTION_FIRE_NOW) {
499             setNextFireTime(new Date JavaDoc());
500         } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT) {
501             Date JavaDoc newFireTime = getFireTimeAfter(new Date JavaDoc());
502             while (newFireTime != null && cal != null
503                     && !cal.isTimeIncluded(newFireTime.getTime())) {
504                 newFireTime = getFireTimeAfter(newFireTime);
505             }
506             setNextFireTime(newFireTime);
507         } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT) {
508             Date JavaDoc newFireTime = getFireTimeAfter(new Date JavaDoc());
509             while (newFireTime != null && cal != null
510                     && !cal.isTimeIncluded(newFireTime.getTime())) {
511                 newFireTime = getFireTimeAfter(newFireTime);
512             }
513             if (newFireTime != null) {
514                 int timesMissed = computeNumTimesFiredBetween(nextFireTime,
515                         newFireTime);
516                 setTimesTriggered(getTimesTriggered() + timesMissed);
517             }
518
519             setNextFireTime(newFireTime);
520         } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT) {
521             Date JavaDoc newFireTime = new Date JavaDoc();
522             if (repeatCount != 0 && repeatCount != REPEAT_INDEFINITELY) {
523                 setRepeatCount(getRepeatCount() - getTimesTriggered());
524                 setTimesTriggered(0);
525             }
526             
527             if (getEndTime() != null && getEndTime().before(newFireTime)) {
528                 setNextFireTime(null); // We are past the end time
529
} else {
530                 setStartTime(newFireTime);
531                 setNextFireTime(newFireTime);
532             }
533         } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT) {
534             Date JavaDoc newFireTime = new Date JavaDoc();
535
536             int timesMissed = computeNumTimesFiredBetween(nextFireTime,
537                     newFireTime);
538
539             if (repeatCount != 0 && repeatCount != REPEAT_INDEFINITELY) {
540                 int remainingCount = getRepeatCount()
541                         - (getTimesTriggered() + timesMissed);
542                 if (remainingCount <= 0) {
543                     remainingCount = 0;
544                 }
545                 setRepeatCount(remainingCount);
546                 setTimesTriggered(0);
547             }
548
549             if (getEndTime() != null && getEndTime().before(newFireTime)) {
550                 setNextFireTime(null); // We are past the end time
551
} else {
552                 setStartTime(newFireTime);
553                 setNextFireTime(newFireTime);
554             }
555         }
556
557     }
558
559     /**
560      * <p>
561      * Called when the <code>{@link Scheduler}</code> has decided to 'fire'
562      * the trigger (execute the associated <code>Job</code>), in order to
563      * give the <code>Trigger</code> a chance to update itself for its next
564      * triggering (if any).
565      * </p>
566      *
567      * @see #executionComplete(JobExecutionContext, JobExecutionException)
568      */

569     public void triggered(Calendar calendar) {
570         timesTriggered++;
571         previousFireTime = nextFireTime;
572         nextFireTime = getFireTimeAfter(nextFireTime);
573
574         while (nextFireTime != null && calendar != null
575                 && !calendar.isTimeIncluded(nextFireTime.getTime())) {
576             nextFireTime = getFireTimeAfter(nextFireTime);
577         }
578     }
579
580     /**
581      *
582      * @see org.quartz.Trigger#updateWithNewCalendar(org.quartz.Calendar, long)
583      */

584     public void updateWithNewCalendar(Calendar calendar, long misfireThreshold)
585     {
586         nextFireTime = getFireTimeAfter(previousFireTime);
587         
588         Date JavaDoc now = new Date JavaDoc();
589         do {
590             while (nextFireTime != null && calendar != null
591                     && !calendar.isTimeIncluded(nextFireTime.getTime())) {
592                 nextFireTime = getFireTimeAfter(nextFireTime);
593             }
594             
595             if(nextFireTime != null && nextFireTime.before(now)) {
596                 long diff = now.getTime() - nextFireTime.getTime();
597                 if(diff >= misfireThreshold) {
598                     nextFireTime = getFireTimeAfter(nextFireTime);
599                     continue;
600                 }
601             }
602         }while(false);
603     }
604
605     /**
606      * <p>
607      * Called by the scheduler at the time a <code>Trigger</code> is first
608      * added to the scheduler, in order to have the <code>Trigger</code>
609      * compute its first fire time, based on any associated calendar.
610      * </p>
611      *
612      * <p>
613      * After this method has been called, <code>getNextFireTime()</code>
614      * should return a valid answer.
615      * </p>
616      *
617      * @return the first time at which the <code>Trigger</code> will be fired
618      * by the scheduler, which is also the same value <code>getNextFireTime()</code>
619      * will return (until after the first firing of the <code>Trigger</code>).
620      * </p>
621      */

622     public Date JavaDoc computeFirstFireTime(Calendar calendar) {
623         nextFireTime = getStartTime();
624
625         while (nextFireTime != null && calendar != null
626                 && !calendar.isTimeIncluded(nextFireTime.getTime())) {
627             nextFireTime = getFireTimeAfter(nextFireTime);
628         }
629
630         return nextFireTime;
631     }
632
633     /**
634      * <p>
635      * Called after the <code>{@link Scheduler}</code> has executed the
636      * <code>{@link org.quartz.JobDetail}</code> associated with the <code>Trigger</code>
637      * in order to get the final instruction code from the trigger.
638      * </p>
639      *
640      * @param context
641      * is the <code>JobExecutionContext</code> that was used by the
642      * <code>Job</code>'s<code>execute(xx)</code> method.
643      * @param result
644      * is the <code>JobExecutionException</code> thrown by the
645      * <code>Job</code>, if any (may be null).
646      * @return one of the Trigger.INSTRUCTION_XXX constants.
647      *
648      * @see #INSTRUCTION_NOOP
649      * @see #INSTRUCTION_RE_EXECUTE_JOB
650      * @see #INSTRUCTION_DELETE_TRIGGER
651      * @see #INSTRUCTION_SET_TRIGGER_COMPLETE
652      * @see #triggered(Calendar)
653      */

654     public int executionComplete(JobExecutionContext context,
655             JobExecutionException result) {
656         if (result != null && result.refireImmediately()) {
657             return INSTRUCTION_RE_EXECUTE_JOB;
658         }
659
660         if (result != null && result.unscheduleFiringTrigger()) {
661             return INSTRUCTION_SET_TRIGGER_COMPLETE;
662         }
663
664         if (result != null && result.unscheduleAllTriggers()) {
665             return INSTRUCTION_SET_ALL_JOB_TRIGGERS_COMPLETE;
666         }
667
668         if (!mayFireAgain()) {
669             return INSTRUCTION_DELETE_TRIGGER;
670         }
671
672         return INSTRUCTION_NOOP;
673     }
674
675     /**
676      * <p>
677      * Returns the next time at which the <code>SimpleTrigger</code> will
678      * fire. If the trigger will not fire again, <code>null</code> will be
679      * returned. The value returned is not guaranteed to be valid until after
680      * the <code>Trigger</code> has been added to the scheduler.
681      * </p>
682      */

683     public Date JavaDoc getNextFireTime() {
684         return nextFireTime;
685     }
686
687     /**
688      * <p>
689      * Returns the previous time at which the <code>SimpleTrigger</code> will
690      * fire. If the trigger has not yet fired, <code>null</code> will be
691      * returned.
692      */

693     public Date JavaDoc getPreviousFireTime() {
694         return previousFireTime;
695     }
696
697     /**
698      * <p>
699      * Set the next time at which the <code>SimpleTrigger</code> should fire.
700      * </p>
701      *
702      * <p>
703      * <b>This method should not be invoked by client code.</b>
704      * </p>
705      */

706     public void setNextFireTime(Date JavaDoc nextFireTime) {
707         this.nextFireTime = nextFireTime;
708     }
709
710     /**
711      * <p>
712      * Set the previous time at which the <code>SimpleTrigger</code> fired.
713      * </p>
714      *
715      * <p>
716      * <b>This method should not be invoked by client code.</b>
717      * </p>
718      */

719     public void setPreviousFireTime(Date JavaDoc previousFireTime) {
720         this.previousFireTime = previousFireTime;
721     }
722
723     /**
724      * <p>
725      * Returns the next time at which the <code>SimpleTrigger</code> will
726      * fire, after the given time. If the trigger will not fire after the given
727      * time, <code>null</code> will be returned.
728      * </p>
729      */

730     public Date JavaDoc getFireTimeAfter(Date JavaDoc afterTime) {
731         if (complete) {
732             return null;
733         }
734
735         if ((timesTriggered > repeatCount)
736                 && (repeatCount != REPEAT_INDEFINITELY)) {
737             return null;
738         }
739
740         if (afterTime == null) {
741             afterTime = new Date JavaDoc();
742         }
743
744         if (repeatCount == 0 && afterTime.compareTo(getStartTime()) >= 0) {
745             return null;
746         }
747
748         long startMillis = getStartTime().getTime();
749         long afterMillis = afterTime.getTime();
750         long endMillis = (getEndTime() == null) ? Long.MAX_VALUE : getEndTime()
751                 .getTime();
752
753         if (endMillis <= afterMillis) {
754             return null;
755         }
756
757         if (afterMillis < startMillis) {
758             return new Date JavaDoc(startMillis);
759         }
760
761         long numberOfTimesExecuted = ((afterMillis - startMillis) / repeatInterval) + 1;
762
763         if ((numberOfTimesExecuted > repeatCount) &&
764             (repeatCount != REPEAT_INDEFINITELY)) {
765             return null;
766         }
767
768         Date JavaDoc time = new Date JavaDoc(startMillis + (numberOfTimesExecuted * repeatInterval));
769
770         if (endMillis <= time.getTime()) {
771             return null;
772         }
773
774         return time;
775     }
776
777     /**
778      * <p>
779      * Returns the last time at which the <code>SimpleTrigger</code> will
780      * fire, before the given time. If the trigger will not fire before the
781      * given time, <code>null</code> will be returned.
782      * </p>
783      */

784     public Date JavaDoc getFireTimeBefore(Date JavaDoc end) {
785         if (end.getTime() < getStartTime().getTime()) {
786             return null;
787         }
788
789         int numFires = computeNumTimesFiredBetween(getStartTime(), end);
790
791         return new Date JavaDoc(getStartTime().getTime() + (numFires * repeatInterval));
792     }
793
794     public int computeNumTimesFiredBetween(Date JavaDoc start, Date JavaDoc end) {
795
796         if(repeatInterval < 1) {
797             return 0;
798         }
799         
800         long time = end.getTime() - start.getTime();
801
802         return (int) (time / repeatInterval);
803     }
804
805     /**
806      * <p>
807      * Returns the final time at which the <code>SimpleTrigger</code> will
808      * fire, if repeatCount is REPEAT_INDEFINITELY, null will be returned.
809      * </p>
810      *
811      * <p>
812      * Note that the return time may be in the past.
813      * </p>
814      */

815     public Date JavaDoc getFinalFireTime() {
816         if (repeatCount == 0) {
817             return startTime;
818         }
819
820         if (repeatCount == REPEAT_INDEFINITELY) {
821             return (getEndTime() == null) ? null : getFireTimeBefore(getEndTime());
822         }
823
824         long lastTrigger = startTime.getTime() + (repeatCount * repeatInterval);
825
826         if ((getEndTime() == null) || (lastTrigger < getEndTime().getTime())) {
827             return new Date JavaDoc(lastTrigger);
828         } else {
829             return getFireTimeBefore(getEndTime());
830         }
831     }
832
833     /**
834      * <p>
835      * Determines whether or not the <code>SimpleTrigger</code> will occur
836      * again.
837      * </p>
838      */

839     public boolean mayFireAgain() {
840         return (getNextFireTime() != null);
841     }
842
843     /**
844      * <p>
845      * Validates whether the properties of the <code>JobDetail</code> are
846      * valid for submission into a <code>Scheduler</code>.
847      *
848      * @throws IllegalStateException
849      * if a required property (such as Name, Group, Class) is not
850      * set.
851      */

852     public void validate() throws SchedulerException {
853         super.validate();
854
855         if (repeatCount != 0 && repeatInterval < 1) {
856             throw new SchedulerException("Repeat Interval cannot be zero.",
857                     SchedulerException.ERR_CLIENT_ERROR);
858         }
859     }
860
861     public static void main(String JavaDoc[] args) // TODO: remove method after good
862
// unit testing
863
throws Exception JavaDoc {
864
865         Date JavaDoc sdt = new Date JavaDoc();
866
867         Date JavaDoc edt = new Date JavaDoc(sdt.getTime() + 55000L);
868
869         SimpleTrigger st = new SimpleTrigger("t", "g", "j", "g", sdt, edt, 10,
870                 10000L);
871
872         System.err.println();
873
874         st.computeFirstFireTime(null);
875
876         System.err.println("lastTime=" + st.getFinalFireTime());
877
878         java.util.List JavaDoc times = TriggerUtils.computeFireTimes(st, null, 50);
879
880         for (int i = 0; i < times.size(); i++) {
881             System.err.println("firetime = " + times.get(i));
882         }
883     }
884
885 }
886
Popular Tags