KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > oddjob > schedules > ScheduleCalculator


1 package org.oddjob.schedules;
2
3 import java.util.ArrayList JavaDoc;
4 import java.util.Date JavaDoc;
5 import java.util.HashMap JavaDoc;
6 import java.util.Iterator JavaDoc;
7 import java.util.List JavaDoc;
8 import java.util.Map JavaDoc;
9 import java.util.TimeZone JavaDoc;
10
11 import org.apache.log4j.Logger;
12 import org.oddjob.util.Clock;
13
14 /**
15  * A class capable of calculating next due times for a job by using two
16  * schedules - a normal schedule for normal completion and a retry schedule
17  * for when a job hasn't completed.
18  *
19  * @author Rob Gordon
20  */

21 public class ScheduleCalculator {
22     private static final Logger logger = Logger.getLogger(ScheduleCalculator.class);
23     /**
24      * The normal schedule.
25      */

26     private final Schedule normalSchedule;
27
28     /**
29      * The Retry schedule.
30      */

31     private final Schedule retrySchedule;
32
33     
34     /** The current schedule being used. */
35     private Schedule currentSchedule;
36                 
37     /** The current/last interval in which schedule is due */
38     private Interval currentInterval;
39
40     /** last normal interval from the regular schedule */
41     private Interval normalInterval;
42
43     /** Initialised */
44     private boolean initialised;
45
46     /** Listeners. */
47     private final List JavaDoc listeners = new ArrayList JavaDoc();
48     
49     /** Current schedule context */
50     private ScheduleContext normalContext;
51     /** Retry schedule context */
52     private ScheduleContext retryContext;
53     
54     /** The time zone. */
55     private final TimeZone JavaDoc timeZone;
56     
57     private final Clock clock;
58     
59     /**
60      * Constructor for a calculator with no retry for the default time zone.
61      *
62      * @param clock The clock to use, may not be null.
63      * @param schedule The normal schedule, may not be null.
64      */

65     public ScheduleCalculator(Clock clock, Schedule schedule) {
66         this(clock, schedule, null, null);
67     }
68     
69     /**
70      * Constructor for a calculator with with a timeZone.
71      *
72      * @param clock The clock to use, may not be null.
73      * @param schedule The normal schedule, may not be null.
74      * @param timeZone The time zone. May be null
75      */

76     public ScheduleCalculator(Clock clock, Schedule schedule, TimeZone JavaDoc timeZone) {
77         this(clock, schedule, null, timeZone);
78     }
79     
80     /**
81      * Constructor for a calculator with a retry schedule using the default time zone.
82      *
83      * @param clock The clock to use, may not be null.
84      * @param schedule The normal schedule, may not be null.
85      * @param retry The retrySchedule. May be null.
86      */

87     public ScheduleCalculator(Clock clock, Schedule schedule, Schedule retry) {
88         this(clock, schedule, retry, null);
89     }
90     
91     /**
92      * Constructor for a calculator with a retry schedule and a timeZone.
93      *
94      * @param clock The clock to use, may not be null.
95      * @param schedule The normal schedule, may not be null.
96      * @param retry The retrySchedule. May be null.
97      * @param timeZone The time zone. May be null
98      */

99     public ScheduleCalculator(Clock clock, Schedule schedule, Schedule retry, TimeZone JavaDoc timeZone) {
100         if (clock == null) {
101             throw new IllegalStateException JavaDoc("Null clock not allowed.");
102         }
103         if (schedule == null) {
104             throw new IllegalStateException JavaDoc("Null schedule not allowed.");
105         }
106         this.clock = clock;
107         this.normalSchedule = schedule;
108         this.retrySchedule = retry;
109         this.timeZone = timeZone;
110     }
111     
112         
113     /**
114      * Getter for schedule.
115      *
116      * @return The schedule.
117      */

118     public Schedule getSchedule() {
119         return this.normalSchedule;
120     }
121     
122     /**
123      * Getter for retry.
124      *
125      * @return The retry schedule.
126      */

127     public Schedule getRetry() {
128         return this.retrySchedule;
129     }
130
131     public void initialise() {
132         initialise(null, new HashMap JavaDoc());
133     }
134     
135     /**
136      * Initialize the scheduler.
137      */

138     synchronized public void initialise(Interval lastComplete, Map JavaDoc contextData) {
139         if (initialised) {
140             throw new IllegalStateException JavaDoc("Already initialised.");
141         }
142         Date JavaDoc nowTime = clock.getDate();
143         logger.debug("Initialising, time now [" + nowTime + "], lastComplete [" + lastComplete + "]");
144
145         // always start on a normal schedule.
146
currentSchedule(normalSchedule);
147         // if the last complete time was persisted.
148
if (lastComplete != null) {
149             // work with a time that is one millisecond after the lastComplete
150
// interval.
151
Date JavaDoc useTime = DateUtils.oneMillisAfter(lastComplete.getToDate());
152             normalContext = new ScheduleContext(
153                     useTime, timeZone, contextData);
154             currentInterval = currentSchedule.nextDue(normalContext);
155             normalInterval = currentInterval;
156             fireInitialised();
157         }
158         else {
159             logger.debug("Starting up with no last complete date.");
160             normalContext = new ScheduleContext(
161                     nowTime, timeZone, contextData);
162             currentInterval = currentSchedule.nextDue(normalContext);
163             normalInterval = currentInterval;
164             fireInitialised();
165         }
166         initialised = true;
167     }
168
169     
170     /**
171      * Change the current schedule.
172      *
173      * @param schedule The current schedule.
174      */

175     private void currentSchedule(Schedule schedule) {
176         this.currentSchedule = schedule;
177     }
178     
179     /**
180      * Get the name of the current schedule.
181      *
182      * @return The name of the current schedule.
183      */

184     synchronized public String JavaDoc getCurrentScheduleType() {
185         if (currentSchedule == normalSchedule) {
186             return "Normal";
187         }
188         else if (currentSchedule == retrySchedule) {
189             return "Retry";
190         }
191         else {
192             return "Undefined";
193         }
194     }
195     
196     synchronized public void calculateComplete() {
197         
198         logger.debug("Calculate Complete");
199         currentSchedule(normalSchedule);
200         Interval lastComplete = normalInterval;
201         normalContext = normalContext.spawn(
202                 DateUtils.oneMillisAfter(currentInterval.getToDate()));
203         // calculate the next due time.
204
currentInterval = currentSchedule.nextDue(
205                 normalContext);
206         normalInterval = currentInterval;
207         
208         fireComplete(lastComplete);
209     }
210
211     /**
212      * Calculate the retry schedule.
213      *
214      */

215     synchronized public void calculateRetry() {
216         logger.debug("Calculate Retry");
217         if (currentSchedule == normalSchedule) {
218             // job just failed
219
if (retrySchedule != null) {
220                 logger.debug("Switching to retry schedule.");
221                 normalInterval = currentInterval;
222                 if (!normalInterval.isPoint()) {
223                     retrySchedule.setLimits(normalInterval);
224                 }
225                 currentSchedule(retrySchedule);
226                 // use the current time
227
retryContext = new ScheduleContext(clock.getDate(),
228                         timeZone);
229                 currentInterval = retrySchedule.nextDue(retryContext);
230                 if (currentInterval != null) {
231                     // there is a retry
232
fireRetry();
233                 }
234                 else {
235                     // else fail
236
currentSchedule(normalSchedule);
237                     normalContext = normalContext.spawn(DateUtils.oneMillisAfter(normalInterval.getToDate()));
238                     currentInterval = normalSchedule.nextDue(normalContext);
239                     normalInterval = currentInterval;
240                     fireFailed();
241                 }
242             } else {
243                 // no retry
244
normalContext = normalContext.spawn(DateUtils.oneMillisAfter(normalInterval.getToDate()));
245                 currentInterval = normalSchedule.nextDue(normalContext);
246                 normalInterval = currentInterval;
247                 fireFailed();
248             }
249         }
250         else {
251             retryContext = retryContext.spawn(DateUtils.oneMillisAfter(currentInterval.getToDate()));
252             currentInterval = retrySchedule.nextDue(retryContext);
253             if (currentInterval != null) {
254                 // there is a retry
255
fireRetry();
256             }
257             else {
258                 // switch back and fail
259
currentSchedule(normalSchedule);
260                 normalContext = normalContext.spawn(DateUtils.oneMillisAfter(normalInterval.getToDate()));
261                 currentInterval = normalSchedule.nextDue(normalContext);
262                 normalInterval = currentInterval;
263                 logger.debug("Switched back to normal schedule and next interval is [" + currentInterval + "]");
264                 fireFailed();
265             }
266             
267         }
268         logger.debug("Next inteval is [" + currentInterval + "]");
269     }
270     
271         
272     synchronized public void addScheduleListener(ScheduleListener l) {
273         listeners.add(l);
274     }
275     
276     synchronized public void removeScheduleListener(ScheduleListener l) {
277         listeners.remove(l);
278     }
279     
280     protected void fireInitialised() {
281         Date JavaDoc scheduleDate;
282         if (normalInterval == null) {
283             scheduleDate = null;
284         }
285         else {
286             scheduleDate = normalInterval.getFromDate();
287         }
288         
289         for (Iterator JavaDoc it = listeners.iterator(); it.hasNext(); ) {
290             ScheduleListener l = (ScheduleListener) it.next();
291             l.initialised(scheduleDate);
292         }
293     }
294         
295     protected void fireComplete(Interval lastComplete) {
296         Date JavaDoc scheduleDate;
297         if (normalInterval == null) {
298             scheduleDate = null;
299         }
300         else {
301             scheduleDate = normalInterval.getFromDate();
302         }
303         
304         for (Iterator JavaDoc it = listeners.iterator(); it.hasNext(); ) {
305             ScheduleListener l = (ScheduleListener) it.next();
306             l.complete(scheduleDate, lastComplete);
307         }
308     }
309     
310     protected void fireRetry() {
311         Date JavaDoc scheduleDate;
312         if (normalInterval == null) {
313             throw new IllegalStateException JavaDoc("Can't retry without have a normal interval!");
314         }
315         else {
316             scheduleDate = normalInterval.getFromDate();
317         }
318         Date JavaDoc retryDate;
319         if (currentInterval == null) {
320             throw new IllegalStateException JavaDoc("Can't retry without have an interval!");
321         }
322         else {
323             retryDate = DateUtils.oneMillisAfter(currentInterval.getToDate());
324         }
325         for (Iterator JavaDoc it = listeners.iterator(); it.hasNext(); ) {
326             ScheduleListener l = (ScheduleListener) it.next();
327             l.retry(scheduleDate, retryDate);
328         }
329     }
330     
331     protected void fireFailed() {
332         Date JavaDoc scheduleDate;
333         if (normalInterval == null) {
334             scheduleDate = null;
335         }
336         else {
337             scheduleDate = normalInterval.getFromDate();
338         }
339         for (Iterator JavaDoc it = listeners.iterator(); it.hasNext(); ) {
340             ScheduleListener l = (ScheduleListener) it.next();
341             l.failed(scheduleDate);
342         }
343     }
344 }
345
346
Popular Tags