1 4 package org.oddjob.scheduling; 5 6 import java.util.Date ; 7 8 import org.oddjob.Resetable; 9 import org.oddjob.Stateful; 10 import org.oddjob.Stoppable; 11 import org.oddjob.framework.StructuralJob; 12 import org.oddjob.schedules.Interval; 13 import org.oddjob.schedules.Schedule; 14 import org.oddjob.schedules.ScheduleCalculator; 15 import org.oddjob.schedules.ScheduleListener; 16 import org.oddjob.schedules.schedules.NowSchedule; 17 import org.oddjob.state.AbstractJobStateListener; 18 import org.oddjob.util.Clock; 19 import org.oddjob.util.DefaultClock; 20 import org.oddjob.util.OddjobConfigException; 21 22 95 public class RepeatJob extends StructuralJob 96 implements Stoppable, ScheduleListener { 97 private static final long serialVersionUID = 20051121; 98 99 105 private transient Schedule normalSchedule = new NowSchedule(); 106 107 114 private transient Schedule retrySchedule; 115 116 121 private transient Runnable child; 122 123 128 private Runnable exceptionJob; 129 130 132 private transient Clock clock; 133 134 135 private transient Date nextDue; 136 137 138 private transient boolean retry; 139 140 141 private transient boolean failed; 142 143 152 private transient Date scheduleDate; 153 154 155 private transient ScheduleCalculator scheduleCalculator; 156 157 163 public void addComponentChild(Runnable child) { 164 if (!(child instanceof Stateful)) { 165 throw new IllegalArgumentException ("Child must be Stateful."); 166 } 167 this.child = child; 168 } 169 170 180 public void addComponentException(Runnable exceptionJob) { 181 this.exceptionJob = exceptionJob; 182 } 183 184 189 public void setSchedule(Schedule schedule) { 190 this.normalSchedule = schedule; 191 } 192 193 198 public Schedule getSchedule() { 199 return this.normalSchedule; 200 } 201 202 207 public void setRetry(Schedule retry) { 208 this.retrySchedule = retry; 209 } 210 211 216 public Schedule getRetry() { 217 return this.retrySchedule; 218 } 219 220 225 Clock getClock() { 226 if (clock == null) { 227 clock = new DefaultClock(); 228 logger().debug("Using default clock."); 229 } 230 return clock; 231 } 232 233 238 void setClock(Clock clock) { 239 this.clock = clock; 240 logger().debug("set clock [" + clock + "]"); 241 } 242 243 248 public void init() { 249 if (child == null) { 250 throw new OddjobConfigException("Child job is missing."); 251 } 252 childHelper.addChild(child); 253 if (exceptionJob != null) { 254 childHelper.addChild(exceptionJob); 255 } 256 childHelper.initialise(); 257 } 258 259 263 protected void execute() { 264 Object [] children = childHelper.getChildren(); 265 if (children.length == 0) { 266 throw new IllegalStateException ("Call init() first!"); 267 } 268 269 scheduleCalculator = new ScheduleCalculator(getClock(), 271 normalSchedule, retrySchedule, null); 272 scheduleCalculator.addScheduleListener(this); 273 scheduleCalculator.initialise(); 274 275 Runnable job = (Runnable ) children[0]; 276 while (!stop) { 277 Date timeNow = getClock().getDate(); 278 logger().debug("Time now is " + timeNow); 279 280 if (failed) { 281 if (children.length > 1) { 282 Runnable ej = (Runnable ) children[1]; 283 if (ej instanceof Resetable) { 284 ((Resetable) ej).hardReset(); 285 } 286 ej.run(); 287 } 288 failed = false; 289 } 290 else { 291 if (nextDue == null) { 292 logger().debug("Schedule finished."); 293 break; 294 } 295 296 long sleepTime = nextDue.getTime() - timeNow.getTime(); 297 298 if (sleepTime <= 0) { 299 logger().debug("Executing at [" + timeNow + "]"); 301 if (job instanceof Resetable) { 302 if (retry) { 303 ((Resetable) job).softReset(); 304 } 305 else { 306 ((Resetable) job).hardReset(); 307 } 308 } 309 ScheduleStateListener ssl = new ScheduleStateListener(); 310 ((Stateful) job).addJobStateListener(ssl); 311 312 job.run(); 313 314 ((Stateful) job).removeJobStateListener(ssl); 315 } 316 else { 317 logger().debug(getName() + " next due at " 318 + getNextDue()); 319 sleep(sleepTime); 320 } 321 } } scheduleCalculator.removeScheduleListener(this); 324 } 325 326 329 public void initialised(Date scheduleDate) { 330 this.scheduleDate = scheduleDate; 331 this.nextDue = scheduleDate; 332 this.retry = false; 333 this.failed = false; 334 } 335 336 339 public void complete(Date scheduleDate, Interval lastComplete) { 340 this.scheduleDate = scheduleDate; 341 this.nextDue = scheduleDate; 342 this.retry = false; 343 this.failed = false; 344 } 345 346 349 public void retry(Date scheduleDate, Date retryDate) { 350 this.scheduleDate = scheduleDate; 351 this.nextDue = retryDate; 352 this.retry = true; 353 this.failed = false; 354 } 355 356 359 public void failed(Date scheduleDate) { 360 this.scheduleDate = scheduleDate; 361 this.nextDue = scheduleDate; 362 this.retry = false; 363 this.failed = true; 364 } 365 366 class ScheduleStateListener extends AbstractJobStateListener { 367 368 protected void jobStateComplete(Stateful source, Date time) { 370 logger().debug("Job Complete"); 371 scheduleCalculator.calculateComplete(); 372 } 373 374 protected void jobStateNotComplete(Stateful source, Date time) { 377 logger().debug("Job Not Complete"); 378 scheduleCalculator.calculateRetry(); 379 } 380 381 383 protected void jobStateException(Stateful source, Date time, Throwable t) { 384 logger().debug("Job Exception"); 385 scheduleCalculator.calculateRetry(); 386 } 387 } 388 391 public Date getNextDue() { 392 return nextDue; 393 } 394 397 public Date getScheduleDate() { 398 return scheduleDate; 399 } 400 403 public void setScheduleDate(Date schduleDate) { 404 this.scheduleDate = schduleDate; 405 } 406 } 407
| Popular Tags
|