KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > quartz > CronTrigger


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

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

21 package org.quartz;
22
23 import java.text.ParseException JavaDoc;
24 import java.util.Calendar JavaDoc;
25 import java.util.Date JavaDoc;
26 import java.util.TimeZone JavaDoc;
27
28
29 /**
30  * <p>
31  * A concrete <code>{@link Trigger}</code> that is used to fire a <code>{@link org.quartz.JobDetail}</code>
32  * at given moments in time, defined with Unix 'cron-like' definitions.
33  * </p>
34  *
35  * <p>
36  * For those unfamiliar with "cron", this means being able to create a firing
37  * schedule such as: "At 8:00am every Monday through Friday" or "At 1:30am
38  * every last Friday of the month".
39  * </p>
40  *
41  * <p>
42  * The format of a "Cron-Expression" string is documented on the
43  * {@link org.quartz.CronExpression} class.
44  * </p>
45  *
46  * <p>
47  * Here are some full examples: <br><table cellspacing="8">
48  * <tr>
49  * <th align="left">Expression</th>
50  * <th align="left">&nbsp;</th>
51  * <th align="left">Meaning</th>
52  * </tr>
53  * <tr>
54  * <td align="left"><code>"0 0 12 * * ?"</code></td>
55  * <td align="left">&nbsp;</th>
56  * <td align="left"><code>Fire at 12pm (noon) every day</code></td>
57  * </tr>
58  * <tr>
59  * <td align="left"><code>"0 15 10 ? * *"</code></td>
60  * <td align="left">&nbsp;</th>
61  * <td align="left"><code>Fire at 10:15am every day</code></td>
62  * </tr>
63  * <tr>
64  * <td align="left"><code>"0 15 10 * * ?"</code></td>
65  * <td align="left">&nbsp;</th>
66  * <td align="left"><code>Fire at 10:15am every day</code></td>
67  * </tr>
68  * <tr>
69  * <td align="left"><code>"0 15 10 * * ? *"</code></td>
70  * <td align="left">&nbsp;</th>
71  * <td align="left"><code>Fire at 10:15am every day</code></td>
72  * </tr>
73  * <tr>
74  * <td align="left"><code>"0 15 10 * * ? 2005"</code></td>
75  * <td align="left">&nbsp;</th>
76  * <td align="left"><code>Fire at 10:15am every day during the year 2005</code>
77  * </td>
78  * </tr>
79  * <tr>
80  * <td align="left"><code>"0 * 14 * * ?"</code></td>
81  * <td align="left">&nbsp;</th>
82  * <td align="left"><code>Fire every minute starting at 2pm and ending at 2:59pm, every day</code>
83  * </td>
84  * </tr>
85  * <tr>
86  * <td align="left"><code>"0 0/5 14 * * ?"</code></td>
87  * <td align="left">&nbsp;</th>
88  * <td align="left"><code>Fire every 5 minutes starting at 2pm and ending at 2:55pm, every day</code>
89  * </td>
90  * </tr>
91  * <tr>
92  * <td align="left"><code>"0 0/5 14,18 * * ?"</code></td>
93  * <td align="left">&nbsp;</th>
94  * <td align="left"><code>Fire every 5 minutes starting at 2pm and ending at 2:55pm, AND fire every 5 minutes starting at 6pm and ending at 6:55pm, every day</code>
95  * </td>
96  * </tr>
97  * <tr>
98  * <td align="left"><code>"0 0-5 14 * * ?"</code></td>
99  * <td align="left">&nbsp;</th>
100  * <td align="left"><code>Fire every minute starting at 2pm and ending at 2:05pm, every day</code>
101  * </td>
102  * </tr>
103  * <tr>
104  * <td align="left"><code>"0 10,44 14 ? 3 WED"</code></td>
105  * <td align="left">&nbsp;</th>
106  * <td align="left"><code>Fire at 2:10pm and at 2:44pm every Wednesday in the month of March.</code>
107  * </td>
108  * </tr>
109  * <tr>
110  * <td align="left"><code>"0 15 10 ? * MON-FRI"</code></td>
111  * <td align="left">&nbsp;</th>
112  * <td align="left"><code>Fire at 10:15am every Monday, Tuesday, Wednesday, Thursday and Friday</code>
113  * </td>
114  * </tr>
115  * <tr>
116  * <td align="left"><code>"0 15 10 15 * ?"</code></td>
117  * <td align="left">&nbsp;</th>
118  * <td align="left"><code>Fire at 10:15am on the 15th day of every month</code>
119  * </td>
120  * </tr>
121  * <tr>
122  * <td align="left"><code>"0 15 10 L * ?"</code></td>
123  * <td align="left">&nbsp;</th>
124  * <td align="left"><code>Fire at 10:15am on the last day of every month</code>
125  * </td>
126  * </tr>
127  * <tr>
128  * <td align="left"><code>"0 15 10 ? * 6L"</code></td>
129  * <td align="left">&nbsp;</th>
130  * <td align="left"><code>Fire at 10:15am on the last Friday of every month</code>
131  * </td>
132  * </tr>
133  * <tr>
134  * <td align="left"><code>"0 15 10 ? * 6L"</code></td>
135  * <td align="left">&nbsp;</th>
136  * <td align="left"><code>Fire at 10:15am on the last Friday of every month</code>
137  * </td>
138  * </tr>
139  * <tr>
140  * <td align="left"><code>"0 15 10 ? * 6L 2002-2005"</code></td>
141  * <td align="left">&nbsp;</th>
142  * <td align="left"><code>Fire at 10:15am on every last friday of every month during the years 2002, 2003, 2004 and 2005</code>
143  * </td>
144  * </tr>
145  * <tr>
146  * <td align="left"><code>"0 15 10 ? * 6#3"</code></td>
147  * <td align="left">&nbsp;</th>
148  * <td align="left"><code>Fire at 10:15am on the third Friday of every month</code>
149  * </td>
150  * </tr>
151  * </table>
152  * </p>
153  *
154  * <p>
155  * Pay attention to the effects of '?' and '*' in the day-of-week and
156  * day-of-month fields!
157  * </p>
158  *
159  * <p>
160  * <b>NOTES:</b>
161  * <ul>
162  * <li>Support for specifying both a day-of-week and a day-of-month value is
163  * not complete (you'll need to use the '?' character in on of these fields).
164  * </li>
165  * <li>Be careful when setting fire times between mid-night and 1:00 AM -
166  * "daylight savings" can cause a skip or a repeat depending on whether the
167  * time moves back or jumps forward.</li>
168  * </ul>
169  * </p>
170  *
171  * @see Trigger
172  * @see SimpleTrigger
173  * @see TriggerUtils
174  *
175  * @author Sharada Jambula, James House
176  * @author Contributions from Mads Henderson
177  */

178 public class CronTrigger extends Trigger {
179
180     /*
181      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
182      *
183      * Constants.
184      *
185      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
186      */

187
188     /**
189      * <p>
190      * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire
191      * situation, the <code>{@link CronTrigger}</code> wants to be fired now
192      * by <code>Scheduler</code>.
193      * </p>
194      */

195     public static final int MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1;
196
197     /**
198      * <p>
199      * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire
200      * situation, the <code>{@link CronTrigger}</code> wants to have it's
201      * next-fire-time updated to the next time in the schedule after the
202      * current time (taking into account any associated <code>{@link Calendar}</code>,
203      * but it does not want to be fired now.
204      * </p>
205      */

206     public static final int MISFIRE_INSTRUCTION_DO_NOTHING = 2;
207
208     /*
209      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
210      *
211      * Data members.
212      *
213      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
214      */

215
216     private CronExpression cronEx = null;
217     private Date JavaDoc startTime = null;
218     private Date JavaDoc endTime = null;
219     private Date JavaDoc nextFireTime = null;
220     private Date JavaDoc previousFireTime = null;
221     private transient TimeZone JavaDoc timeZone = null;
222
223     /*
224      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
225      *
226      * Constructors.
227      *
228      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
229      */

230
231     /**
232      * <p>
233      * Create a <code>CronTrigger</code> with no settings.
234      * </p>
235      *
236      * <p>
237      * The start-time will also be set to the current time, and the time zone
238      * will be set the the system's default time zone.
239      * </p>
240      */

241     public CronTrigger() {
242         super();
243         setStartTime(new Date JavaDoc());
244         setTimeZone(TimeZone.getDefault());
245     }
246
247     /**
248      * <p>
249      * Create a <code>CronTrigger</code> with the given name and group.
250      * </p>
251      *
252      * <p>
253      * The start-time will also be set to the current time, and the time zone
254      * will be set the the system's default time zone.
255      * </p>
256      */

257     public CronTrigger(String JavaDoc name, String JavaDoc group) {
258         super(name, group);
259         setStartTime(new Date JavaDoc());
260         setTimeZone(TimeZone.getDefault());
261     }
262
263     /**
264      * <p>
265      * Create a <code>CronTrigger</code> with the given name, group and
266      * expression.
267      * </p>
268      *
269      * <p>
270      * The start-time will also be set to the current time, and the time zone
271      * will be set the the system's default time zone.
272      * </p>
273      */

274     public CronTrigger(String JavaDoc name, String JavaDoc group, String JavaDoc cronExpression)
275         throws ParseException JavaDoc {
276         
277         super(name, group);
278
279         setCronExpression(cronExpression);
280
281         setStartTime(new Date JavaDoc());
282         setTimeZone(TimeZone.getDefault());
283     }
284
285     /**
286      * <p>
287      * Create a <code>CronTrigger</code> with the given name and group, and
288      * associated with the identified <code>{@link org.quartz.JobDetail}</code>.
289      * </p>
290      *
291      * <p>
292      * The start-time will also be set to the current time, and the time zone
293      * will be set the the system's default time zone.
294      * </p>
295      */

296     public CronTrigger(String JavaDoc name, String JavaDoc group, String JavaDoc jobName,
297             String JavaDoc jobGroup) {
298         super(name, group, jobName, jobGroup);
299         setStartTime(new Date JavaDoc());
300         setTimeZone(TimeZone.getDefault());
301     }
302
303     /**
304      * <p>
305      * Create a <code>CronTrigger</code> with the given name and group,
306      * associated with the identified <code>{@link org.quartz.JobDetail}</code>,
307      * and with the given "cron" expression.
308      * </p>
309      *
310      * <p>
311      * The start-time will also be set to the current time, and the time zone
312      * will be set the the system's default time zone.
313      * </p>
314      */

315     public CronTrigger(String JavaDoc name, String JavaDoc group, String JavaDoc jobName,
316             String JavaDoc jobGroup, String JavaDoc cronExpression) throws ParseException JavaDoc {
317         this(name, group, jobName, jobGroup, null, null, cronExpression,
318                 TimeZone.getDefault());
319     }
320
321     /**
322      * <p>
323      * Create a <code>CronTrigger</code> with the given name and group,
324      * associated with the identified <code>{@link org.quartz.JobDetail}</code>,
325      * and with the given "cron" expression resolved with respect to the <code>TimeZone</code>.
326      * </p>
327      */

328     public CronTrigger(String JavaDoc name, String JavaDoc group, String JavaDoc jobName,
329             String JavaDoc jobGroup, String JavaDoc cronExpression, TimeZone JavaDoc timeZone)
330         throws ParseException JavaDoc {
331         this(name, group, jobName, jobGroup, null, null, cronExpression,
332                 timeZone);
333     }
334
335     /**
336      * <p>
337      * Create a <code>CronTrigger</code> that will occur at the given time,
338      * until the given end time.
339      * </p>
340      *
341      * <p>
342      * If null, the start-time will also be set to the current time, the time
343      * zone will be set the the system's default.
344      * </p>
345      *
346      * @param startTime
347      * A <code>Date</code> set to the time for the <code>Trigger</code>
348      * to fire.
349      * @param endTime
350      * A <code>Date</code> set to the time for the <code>Trigger</code>
351      * to quit repeat firing.
352      */

353     public CronTrigger(String JavaDoc name, String JavaDoc group, String JavaDoc jobName,
354             String JavaDoc jobGroup, Date JavaDoc startTime, Date JavaDoc endTime, String JavaDoc cronExpression)
355         throws ParseException JavaDoc {
356         super(name, group, jobName, jobGroup);
357
358         setCronExpression(cronExpression);
359
360         if (startTime == null) {
361             startTime = new Date JavaDoc();
362         }
363         setStartTime(startTime);
364         if (endTime != null) {
365             setEndTime(endTime);
366         }
367         setTimeZone(TimeZone.getDefault());
368
369     }
370
371     /**
372      * <p>
373      * Create a <code>CronTrigger</code> with fire time dictated by the
374      * <code>cronExpression</code> resolved with respect to the specified
375      * <code>timeZone</code> occuring from the <code>startTime</code> until
376      * the given <code>endTime</code>.
377      * </p>
378      *
379      * <p>
380      * If null, the start-time will also be set to the current time. If null,
381      * the time zone will be set to the system's default.
382      * </p>
383      *
384      * @param name
385      * of the <code>Trigger</code>
386      * @param group
387      * of the <code>Trigger</code>
388      * @param jobName
389      * name of the <code>{@link org.quartz.JobDetail}</code>
390      * executed on firetime
391      * @param jobGroup
392      * group of the <code>{@link org.quartz.JobDetail}</code>
393      * executed on firetime
394      * @param startTime
395      * A <code>Date</code> set to the earliest time for the <code>Trigger</code>
396      * to start firing.
397      * @param endTime
398      * A <code>Date</code> set to the time for the <code>Trigger</code>
399      * to quit repeat firing.
400      * @param cronExpression
401      * A cron expression dictating the firing sequence of the <code>Trigger</code>
402      * @param timeZone
403      * Specifies for which time zone the <code>cronExpression</code>
404      * should be interprted, i.e. the expression 0 0 10 * * ?, is
405      * resolved to 10:00 am in this time zone.
406      * @throws ParseException
407      * if the <code>cronExpression</code> is invalid.
408      */

409     public CronTrigger(String JavaDoc name, String JavaDoc group, String JavaDoc jobName,
410             String JavaDoc jobGroup, Date JavaDoc startTime, Date JavaDoc endTime,
411             String JavaDoc cronExpression, TimeZone JavaDoc timeZone) throws ParseException JavaDoc {
412         super(name, group, jobName, jobGroup);
413
414         setCronExpression(cronExpression);
415
416         if (startTime == null) {
417             startTime = new Date JavaDoc();
418         }
419         setStartTime(startTime);
420         if (endTime != null) {
421             setEndTime(endTime);
422         }
423         if (timeZone == null) {
424             setTimeZone(TimeZone.getDefault());
425         } else {
426             setTimeZone(timeZone);
427         }
428     }
429
430     /*
431      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
432      *
433      * Interface.
434      *
435      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
436      */

437     
438     public Object JavaDoc clone() {
439         CronTrigger copy = (CronTrigger) super.clone();
440         copy.setCronExpression((CronExpression)cronEx.clone());
441         return copy;
442     }
443
444     public void setCronExpression(String JavaDoc cronExpression) throws ParseException JavaDoc {
445         this.cronEx = new CronExpression(cronExpression);
446         this.cronEx.setTimeZone(getTimeZone());
447     }
448
449     public String JavaDoc getCronExpression() {
450         return cronEx == null ? null : cronEx.getCronExpression();
451     }
452
453     public void setCronExpression(CronExpression cronExpression) {
454         this.cronEx = cronExpression;
455         this.timeZone = cronExpression.getTimeZone();
456     }
457     
458     /**
459      * <p>
460      * Get the time at which the <code>CronTrigger</code> should occur.
461      * </p>
462      */

463     public Date JavaDoc getStartTime() {
464         return this.startTime;
465     }
466
467     public void setStartTime(Date JavaDoc startTime) {
468         if (startTime == null) {
469             throw new IllegalArgumentException JavaDoc("Start time cannot be null");
470         }
471
472         Date JavaDoc eTime = getEndTime();
473         if (eTime != null && startTime != null && eTime.before(startTime)) {
474             throw new IllegalArgumentException JavaDoc(
475                 "End time cannot be before start time");
476         }
477         
478         // round off millisecond...
479
// Note timeZone is not needed here as parameter for
480
// Calendar.getInstance(),
481
// since time zone is implicit when using a Date in the setTime method.
482
Calendar cl = Calendar.getInstance();
483         cl.setTime(startTime);
484         cl.set(Calendar.MILLISECOND, 0);
485
486         this.startTime = cl.getTime();
487     }
488
489     /**
490      * <p>
491      * Get the time at which the <code>CronTrigger</code> should quit
492      * repeating - even if repeastCount isn't yet satisfied.
493      * </p>
494      *
495      * @see #getFinalFireTime()
496      */

497     public Date JavaDoc getEndTime() {
498         return this.endTime;
499     }
500
501     public void setEndTime(Date JavaDoc endTime) {
502         Date JavaDoc sTime = getStartTime();
503         if (sTime != null && endTime != null && sTime.after(endTime)) {
504             throw new IllegalArgumentException JavaDoc(
505                     "End time cannot be before start time");
506         }
507
508         this.endTime = endTime;
509     }
510
511     /**
512      * <p>
513      * Returns the next time at which the <code>CronTrigger</code> will fire.
514      * If the trigger will not fire again, <code>null</code> will be
515      * returned. The value returned is not guaranteed to be valid until after
516      * the <code>Trigger</code> has been added to the scheduler.
517      * </p>
518      */

519     public Date JavaDoc getNextFireTime() {
520         return this.nextFireTime;
521     }
522
523     /**
524      * <p>
525      * Returns the previous time at which the <code>CronTrigger</code> will
526      * fire. If the trigger has not yet fired, <code>null</code> will be
527      * returned.
528      */

529     public Date JavaDoc getPreviousFireTime() {
530         return this.previousFireTime;
531     }
532
533     /**
534      * <p>
535      * Sets the next time at which the <code>CronTrigger</code> will fire.
536      * <b>This method should not be invoked by client code.</b>
537      * </p>
538      */

539     public void setNextFireTime(Date JavaDoc nextFireTime) {
540         this.nextFireTime = nextFireTime;
541     }
542
543     /**
544      * <p>
545      * Set the previous time at which the <code>CronTrigger</code> fired.
546      * </p>
547      *
548      * <p>
549      * <b>This method should not be invoked by client code.</b>
550      * </p>
551      */

552     public void setPreviousFireTime(Date JavaDoc previousFireTime) {
553         this.previousFireTime = previousFireTime;
554     }
555
556     /**
557      * <p>
558      * Returns the time zone for which the <code>cronExpression</code> of
559      * this <code>CronTrigger</code> will be resolved.
560      * </p>
561      */

562     public TimeZone JavaDoc getTimeZone() {
563         
564         if(cronEx != null) {
565             return cronEx.getTimeZone();
566         }
567         
568         if (timeZone == null) {
569             timeZone = TimeZone.getDefault();
570         }
571         return timeZone;
572     }
573
574     /**
575      * <p>
576      * Sets the time zone for which the <code>cronExpression</code> of this
577      * <code>CronTrigger</code> will be resolved.
578      * </p>
579      */

580     public void setTimeZone(TimeZone JavaDoc timeZone) {
581         if(cronEx != null) {
582             cronEx.setTimeZone(timeZone);
583         }
584         this.timeZone = timeZone;
585     }
586
587     /**
588      * <p>
589      * Returns the next time at which the <code>CronTrigger</code> will fire,
590      * after the given time. If the trigger will not fire after the given time,
591      * <code>null</code> will be returned.
592      * </p>
593      *
594      * <p>
595      * Note that the date returned is NOT validated against the related
596      * org.quartz.Calendar (if any)
597      * </p>
598      */

599     public Date JavaDoc getFireTimeAfter(Date JavaDoc afterTime) {
600         if (afterTime == null) {
601             afterTime = new Date JavaDoc();
602         }
603
604         if (getStartTime().after(afterTime)) {
605             afterTime = new Date JavaDoc(getStartTime().getTime() - 1000l);
606         }
607
608         if (getEndTime() != null && (afterTime.compareTo(getEndTime()) >= 0)) {
609             return null;
610         }
611         
612         Date JavaDoc pot = getTimeAfter(afterTime);
613         if (getEndTime() != null && pot != null && pot.after(getEndTime())) {
614             return null;
615         }
616
617         return pot;
618     }
619
620     /**
621      * <p>
622      * NOT YET IMPLEMENTED: Returns the final time at which the
623      * <code>CronTrigger</code> will fire.
624      * </p>
625      *
626      * <p>
627      * Note that the return time *may* be in the past. and the date returned is
628      * not validated against org.quartz.calendar
629      * </p>
630      */

631     public Date JavaDoc getFinalFireTime() {
632         Date JavaDoc resultTime;
633         if (getEndTime() != null) {
634             resultTime = getTimeBefore(new Date JavaDoc(getEndTime().getTime() + 1000l));
635         } else {
636             resultTime = (cronEx == null) ? null : cronEx.getFinalFireTime();
637         }
638         
639         if ((resultTime != null) && (getStartTime() != null) && (resultTime.before(getStartTime()))) {
640             return null;
641         }
642         
643         return resultTime;
644     }
645
646     /**
647      * <p>
648      * Determines whether or not the <code>CronTrigger</code> will occur
649      * again.
650      * </p>
651      */

652     public boolean mayFireAgain() {
653         return (getNextFireTime() != null);
654     }
655
656     protected boolean validateMisfireInstruction(int misfireInstruction) {
657         if (misfireInstruction < MISFIRE_INSTRUCTION_SMART_POLICY) {
658             return false;
659         }
660
661         if (misfireInstruction > MISFIRE_INSTRUCTION_DO_NOTHING) {
662             return false;
663         }
664
665         return true;
666     }
667
668     /**
669      * <p>
670      * Updates the <code>CronTrigger</code>'s state based on the
671      * MISFIRE_INSTRUCTION_XXX that was selected when the <code>CronTrigger</code>
672      * was created.
673      * </p>
674      *
675      * <p>
676      * If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY,
677      * then the following scheme will be used: <br>
678      * <ul>
679      * <li>The instruction will be interpreted as <code>MISFIRE_INSTRUCTION_FIRE_ONCE_NOW</code>
680      * </ul>
681      * </p>
682      */

683     public void updateAfterMisfire(org.quartz.Calendar cal) {
684         int instr = getMisfireInstruction();
685
686         if (instr == MISFIRE_INSTRUCTION_SMART_POLICY) {
687             instr = MISFIRE_INSTRUCTION_FIRE_ONCE_NOW;
688         }
689
690         if (instr == MISFIRE_INSTRUCTION_DO_NOTHING) {
691             Date JavaDoc newFireTime = getFireTimeAfter(new Date JavaDoc());
692             while (newFireTime != null && cal != null
693                     && !cal.isTimeIncluded(newFireTime.getTime())) {
694                 newFireTime = getFireTimeAfter(newFireTime);
695             }
696             setNextFireTime(newFireTime);
697         } else if (instr == MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) {
698             setNextFireTime(new Date JavaDoc());
699         }
700     }
701
702     /**
703      * <p>
704      * Determines whether the date and (optionally) time of the given Calendar
705      * instance falls on a scheduled fire-time of this trigger.
706      * </p>
707      *
708      * <p>
709      * Equivalent to calling <code>willFireOn(cal, false)</code>.
710      * </p>
711      *
712      * @param test the date to compare
713      *
714      * @see #willFireOn(Calendar, boolean)
715      */

716     public boolean willFireOn(Calendar test) {
717         return willFireOn(test, false);
718     }
719     
720     /**
721      * <p>
722      * Determines whether the date and (optionally) time of the given Calendar
723      * instance falls on a scheduled fire-time of this trigger.
724      * </p>
725      *
726      * <p>
727      * Note that the value returned is NOT validated against the related
728      * org.quartz.Calendar (if any)
729      * </p>
730      *
731      * @param test the date to compare
732      * @param dayOnly if set to true, the method will only determine if the
733      * trigger will fire during the day represented by the given Calendar
734      * (hours, minutes and seconds will be ignored).
735      * @see #willFireOn(Calendar)
736      */

737     public boolean willFireOn(Calendar test, boolean dayOnly) {
738
739         test = (Calendar) test.clone();
740         
741         test.set(Calendar.MILLISECOND, 0); // don't compare millis.
742

743         if(dayOnly) {
744             test.set(Calendar.HOUR, 0);
745             test.set(Calendar.MINUTE, 0);
746             test.set(Calendar.SECOND, 0);
747         }
748         
749         Date JavaDoc testTime = test.getTime();
750         
751         Date JavaDoc fta = getFireTimeAfter(new Date JavaDoc(test.getTime().getTime() - 1000));
752
753         Calendar p = Calendar.getInstance(test.getTimeZone());
754         p.setTime(fta);
755         
756         int year = p.get(Calendar.YEAR);
757         int month = p.get(Calendar.MONTH);
758         int day = p.get(Calendar.DATE);
759         
760         if(dayOnly) {
761             return (year == test.get(Calendar.YEAR)
762                     && month == test.get(Calendar.MONTH)
763                     && day == test.get(Calendar.DATE));
764         }
765         
766         while(fta.before(testTime)) {
767             fta = getFireTimeAfter(fta);
768         }
769         
770         if(fta.equals(testTime)) {
771             return true;
772         }
773
774         return false;
775     }
776
777     /**
778      * <p>
779      * Called after the <code>{@link Scheduler}</code> has executed the
780      * <code>{@link org.quartz.JobDetail}</code> associated with the <code>Trigger</code>
781      * in order to get the final instruction code from the trigger.
782      * </p>
783      *
784      * @param context
785      * is the <code>JobExecutionContext</code> that was used by the
786      * <code>Job</code>'s<code>execute(xx)</code> method.
787      * @param result
788      * is the <code>JobExecutionException</code> thrown by the
789      * <code>Job</code>, if any (may be null).
790      * @return one of the Trigger.INSTRUCTION_XXX constants.
791      *
792      * @see #INSTRUCTION_NOOP
793      * @see #INSTRUCTION_RE_EXECUTE_JOB
794      * @see #INSTRUCTION_DELETE_TRIGGER
795      * @see #INSTRUCTION_SET_TRIGGER_COMPLETE
796      * @see #triggered(Calendar)
797      */

798     public int executionComplete(JobExecutionContext context,
799             JobExecutionException result) {
800         if (result != null && result.refireImmediately()) {
801             return INSTRUCTION_RE_EXECUTE_JOB;
802         }
803
804         if (result != null && result.unscheduleFiringTrigger()) {
805             return INSTRUCTION_SET_TRIGGER_COMPLETE;
806         }
807
808         if (result != null && result.unscheduleAllTriggers()) {
809             return INSTRUCTION_SET_ALL_JOB_TRIGGERS_COMPLETE;
810         }
811
812         if (!mayFireAgain()) {
813             return INSTRUCTION_DELETE_TRIGGER;
814         }
815
816         return INSTRUCTION_NOOP;
817     }
818
819     /**
820      * <p>
821      * Called when the <code>{@link Scheduler}</code> has decided to 'fire'
822      * the trigger (execute the associated <code>Job</code>), in order to
823      * give the <code>Trigger</code> a chance to update itself for its next
824      * triggering (if any).
825      * </p>
826      *
827      * @see #executionComplete(JobExecutionContext, JobExecutionException)
828      */

829     public void triggered(org.quartz.Calendar calendar) {
830         previousFireTime = nextFireTime;
831         nextFireTime = getFireTimeAfter(nextFireTime);
832
833         while (nextFireTime != null && calendar != null
834                 && !calendar.isTimeIncluded(nextFireTime.getTime())) {
835             nextFireTime = getFireTimeAfter(nextFireTime);
836         }
837     }
838
839     /**
840      *
841      * @see org.quartz.Trigger#updateWithNewCalendar(org.quartz.Calendar, long)
842      */

843     public void updateWithNewCalendar(org.quartz.Calendar calendar, long misfireThreshold)
844     {
845         nextFireTime = getFireTimeAfter(previousFireTime);
846         
847         Date JavaDoc now = new Date JavaDoc();
848         do {
849             while (nextFireTime != null && calendar != null
850                     && !calendar.isTimeIncluded(nextFireTime.getTime())) {
851                 nextFireTime = getFireTimeAfter(nextFireTime);
852             }
853             
854             if(nextFireTime != null && nextFireTime.before(now)) {
855                 long diff = now.getTime() - nextFireTime.getTime();
856                 if(diff >= misfireThreshold) {
857                     nextFireTime = getFireTimeAfter(nextFireTime);
858                     continue;
859                 }
860             }
861         }while(false);
862     }
863
864     /**
865      * <p>
866      * Called by the scheduler at the time a <code>Trigger</code> is first
867      * added to the scheduler, in order to have the <code>Trigger</code>
868      * compute its first fire time, based on any associated calendar.
869      * </p>
870      *
871      * <p>
872      * After this method has been called, <code>getNextFireTime()</code>
873      * should return a valid answer.
874      * </p>
875      *
876      * @return the first time at which the <code>Trigger</code> will be fired
877      * by the scheduler, which is also the same value <code>getNextFireTime()</code>
878      * will return (until after the first firing of the <code>Trigger</code>).
879      * </p>
880      */

881     public Date JavaDoc computeFirstFireTime(org.quartz.Calendar calendar) {
882         nextFireTime = getFireTimeAfter(new Date JavaDoc(getStartTime().getTime() - 1000l));
883
884         while (nextFireTime != null && calendar != null
885                 && !calendar.isTimeIncluded(nextFireTime.getTime())) {
886             nextFireTime = getFireTimeAfter(nextFireTime);
887         }
888
889         return nextFireTime;
890     }
891
892     public String JavaDoc getExpressionSummary() {
893         return cronEx == null ? null : cronEx.getExpressionSummary();
894     }
895
896     ////////////////////////////////////////////////////////////////////////////
897
//
898
// Computation Functions
899
//
900
////////////////////////////////////////////////////////////////////////////
901

902     protected Date JavaDoc getTimeAfter(Date JavaDoc afterTime) {
903         return (cronEx == null) ? null : cronEx.getTimeAfter(afterTime);
904     }
905
906     /**
907      * NOT YET IMPLEMENTED: Returns the time before the given time
908      * that this <code>CronTrigger</code> will fire.
909      */

910     protected Date JavaDoc getTimeBefore(Date JavaDoc endTime) {
911         return (cronEx == null) ? null : cronEx.getTimeBefore(endTime);
912     }
913
914     public static void main(String JavaDoc[] args) // TODO: remove method after good
915
// unit testing
916
throws Exception JavaDoc {
917
918         String JavaDoc expr = "15 10 0/4 * * ?";
919         if(args != null && args.length > 0 && args[0] != null) {
920             expr = args[0];
921         }
922     
923         CronTrigger ct = new CronTrigger("t", "g", "j", "g", new Date JavaDoc(), null, expr);
924         ct.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
925         System.err.println(ct.getExpressionSummary());
926         System.err.println("tz=" + ct.getTimeZone().getID());
927         System.err.println();
928     
929         java.util.List JavaDoc times = TriggerUtils.computeFireTimes(ct, null, 25);
930     
931         for (int i = 0; i < times.size(); i++) {
932             System.err.println("firetime = " + times.get(i));
933         }
934         
935         Calendar tt = Calendar.getInstance();
936         tt.set(Calendar.DATE, 17);
937         tt.set(Calendar.MONTH, 5 - 1);
938         tt.set(Calendar.HOUR, 11);
939         tt.set(Calendar.MINUTE, 0);
940         tt.set(Calendar.SECOND, 7);
941         
942         System.err.println("\nWill fire on: " + tt.getTime() + " -- " + ct.willFireOn(tt, false));
943         
944       
945 // CRON Expression: 0 0 9 * * ?
946
//
947
// TimeZone.getDefault().getDisplayName() = Central African Time
948
// TimeZone.getDefault().getID() = Africa/Harare
949
//
950
//// System.err.println();
951
//// System.err.println();
952
//// System.err.println();
953
//// System.err.println("Daylight test:");
954
////
955
//// CronTrigger trigger = new CronTrigger();
956
////
957
//// TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
958
//// // TimeZone timeZone = TimeZone.getDefault();
959
////
960
//// trigger.setTimeZone(timeZone);
961
//// trigger.setCronExpression("0 0 1 ? 4 *");
962
////
963
//// Date start = new Date(1056319200000L);
964
//// Date end = new Date(1087682399000L);
965
////
966
//// trigger.setStartTime(start);
967
//// trigger.setEndTime(end);
968
////
969
//// Date next = new Date(1056232800000L);
970
//// while (next != null) {
971
//// next = trigger.getFireTimeAfter(next);
972
//// if (next != null) {
973
//// Calendar cal = Calendar.getInstance();
974
//// cal.setTimeZone(timeZone);
975
//// cal.setTime(next);
976
//// System.err.println(cal.get(Calendar.MONTH) + "/"
977
//// + cal.get(Calendar.DATE) + "/" + cal.get(Calendar.YEAR)
978
//// + " - " + cal.get(Calendar.HOUR_OF_DAY) + ":"
979
//// + cal.get(Calendar.MINUTE));
980
//// }
981
//// }
982
////
983
//// System.err.println();
984
//// System.err.println();
985
//// System.err.println();
986
//// System.err.println("Midnight test:");
987
////
988
//// trigger = new CronTrigger();
989
////
990
//// timeZone = TimeZone.getTimeZone("Asia/Jerusalem");
991
//// // timeZone = TimeZone.getTimeZone("America/Los_Angeles");
992
//// // TimeZone timeZone = TimeZone.getDefault();
993
////
994
//// trigger.setTimeZone(timeZone);
995
//// trigger.setCronExpression("0 /15 * ? 4 *");
996
////
997
//// start = new Date(1056319200000L);
998
//// end = new Date(1087682399000L);
999
////
1000
//// trigger.setStartTime(start);
1001
//// trigger.setEndTime(end);
1002
////
1003
//// next = new Date(1056232800000L);
1004
//// while (next != null) {
1005
//// next = trigger.getFireTimeAfter(next);
1006
//// if (next != null) {
1007
//// Calendar cal = Calendar.getInstance();
1008
//// cal.setTimeZone(timeZone);
1009
//// cal.setTime(next);
1010
//// System.err.println(cal.get(Calendar.MONTH) + "/"
1011
//// + cal.get(Calendar.DATE) + "/" + cal.get(Calendar.YEAR)
1012
//// + " - " + cal.get(Calendar.HOUR_OF_DAY) + ":"
1013
//// + cal.get(Calendar.MINUTE));
1014
//// }
1015
//// }
1016

1017    }
1018}
1019
1020
Popular Tags