1 package org.oddjob.schedules; 2 3 import java.util.ArrayList ; 4 import java.util.Date ; 5 import java.util.HashMap ; 6 import java.util.Iterator ; 7 import java.util.List ; 8 import java.util.Map ; 9 import java.util.TimeZone ; 10 11 import org.apache.log4j.Logger; 12 import org.oddjob.util.Clock; 13 14 21 public class ScheduleCalculator { 22 private static final Logger logger = Logger.getLogger(ScheduleCalculator.class); 23 26 private final Schedule normalSchedule; 27 28 31 private final Schedule retrySchedule; 32 33 34 35 private Schedule currentSchedule; 36 37 38 private Interval currentInterval; 39 40 41 private Interval normalInterval; 42 43 44 private boolean initialised; 45 46 47 private final List listeners = new ArrayList (); 48 49 50 private ScheduleContext normalContext; 51 52 private ScheduleContext retryContext; 53 54 55 private final TimeZone timeZone; 56 57 private final Clock clock; 58 59 65 public ScheduleCalculator(Clock clock, Schedule schedule) { 66 this(clock, schedule, null, null); 67 } 68 69 76 public ScheduleCalculator(Clock clock, Schedule schedule, TimeZone timeZone) { 77 this(clock, schedule, null, timeZone); 78 } 79 80 87 public ScheduleCalculator(Clock clock, Schedule schedule, Schedule retry) { 88 this(clock, schedule, retry, null); 89 } 90 91 99 public ScheduleCalculator(Clock clock, Schedule schedule, Schedule retry, TimeZone timeZone) { 100 if (clock == null) { 101 throw new IllegalStateException ("Null clock not allowed."); 102 } 103 if (schedule == null) { 104 throw new IllegalStateException ("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 118 public Schedule getSchedule() { 119 return this.normalSchedule; 120 } 121 122 127 public Schedule getRetry() { 128 return this.retrySchedule; 129 } 130 131 public void initialise() { 132 initialise(null, new HashMap ()); 133 } 134 135 138 synchronized public void initialise(Interval lastComplete, Map contextData) { 139 if (initialised) { 140 throw new IllegalStateException ("Already initialised."); 141 } 142 Date nowTime = clock.getDate(); 143 logger.debug("Initialising, time now [" + nowTime + "], lastComplete [" + lastComplete + "]"); 144 145 currentSchedule(normalSchedule); 147 if (lastComplete != null) { 149 Date 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 175 private void currentSchedule(Schedule schedule) { 176 this.currentSchedule = schedule; 177 } 178 179 184 synchronized public String 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 currentInterval = currentSchedule.nextDue( 205 normalContext); 206 normalInterval = currentInterval; 207 208 fireComplete(lastComplete); 209 } 210 211 215 synchronized public void calculateRetry() { 216 logger.debug("Calculate Retry"); 217 if (currentSchedule == normalSchedule) { 218 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 retryContext = new ScheduleContext(clock.getDate(), 228 timeZone); 229 currentInterval = retrySchedule.nextDue(retryContext); 230 if (currentInterval != null) { 231 fireRetry(); 233 } 234 else { 235 currentSchedule(normalSchedule); 237 normalContext = normalContext.spawn(DateUtils.oneMillisAfter(normalInterval.getToDate())); 238 currentInterval = normalSchedule.nextDue(normalContext); 239 normalInterval = currentInterval; 240 fireFailed(); 241 } 242 } else { 243 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 fireRetry(); 256 } 257 else { 258 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 scheduleDate; 282 if (normalInterval == null) { 283 scheduleDate = null; 284 } 285 else { 286 scheduleDate = normalInterval.getFromDate(); 287 } 288 289 for (Iterator 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 scheduleDate; 297 if (normalInterval == null) { 298 scheduleDate = null; 299 } 300 else { 301 scheduleDate = normalInterval.getFromDate(); 302 } 303 304 for (Iterator 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 scheduleDate; 312 if (normalInterval == null) { 313 throw new IllegalStateException ("Can't retry without have a normal interval!"); 314 } 315 else { 316 scheduleDate = normalInterval.getFromDate(); 317 } 318 Date retryDate; 319 if (currentInterval == null) { 320 throw new IllegalStateException ("Can't retry without have an interval!"); 321 } 322 else { 323 retryDate = DateUtils.oneMillisAfter(currentInterval.getToDate()); 324 } 325 for (Iterator 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 scheduleDate; 333 if (normalInterval == null) { 334 scheduleDate = null; 335 } 336 else { 337 scheduleDate = normalInterval.getFromDate(); 338 } 339 for (Iterator it = listeners.iterator(); it.hasNext(); ) { 340 ScheduleListener l = (ScheduleListener) it.next(); 341 l.failed(scheduleDate); 342 } 343 } 344 } 345 346 | Popular Tags |