package org.oddjob.schedules.schedules; import org.oddjob.schedules.Interval; import org.oddjob.schedules.IntervalHelper; import org.oddjob.schedules.Schedule; import org.oddjob.schedules.ScheduleContext; import org.oddjob.schedules.ScheduleResult; import org.oddjob.schedules.SimpleScheduleResult; /** * A help class for resolving a single parent/child schedule. * * @author rob * */ public class ParentChildSchedule implements Schedule { private final Schedule parent; private final Schedule child; public ParentChildSchedule(Schedule parent, Schedule child) { this.parent = parent; this.child = child; } /** * Provides the next due interval for the parent and child. */ public ScheduleResult nextDue(ScheduleContext context) { ScheduleResult parentResult = limitedParentResult(context); if (parentResult == null) { return null; } if (child == null) { return parentResult; } ScheduleResult childResult = childResult(context, parentResult); if (childResult != null) { if (childResult.getUseNext() == null) { return new SimpleScheduleResult( childResult, childResult.getToDate()); } else { return childResult; } } parentResult = limitedParentResult(context.move( parentResult.getToDate())); if (parentResult == null) { return null; } childResult = childResult(context, parentResult); if (childResult != null && childResult.getUseNext() == null) { return new SimpleScheduleResult( childResult, childResult.getToDate()); } else { return childResult; } } /** * Find the next due parent interval for the current context * and if one exists check it isn't limited by the context. * * @param context * * @return The next parent interval. */ private ScheduleResult limitedParentResult(ScheduleContext context) { ScheduleResult parentInterval = parent.nextDue(context); if (parentInterval == null) { return null; } if (context.getParentInterval() != null) { IntervalHelper contextParentIntervalHelper = new IntervalHelper( context.getParentInterval()); if (contextParentIntervalHelper.limit( parentInterval) == null) { // One more try. Maybe the child interval was an eager refinement. // I.e. one that spans midnight - so we want to give it a chance // to be an extended refinement. parentInterval = parent.nextDue(context.move( parentInterval.getToDate())); if (parentInterval == null) { return null; } if (contextParentIntervalHelper.limit(parentInterval) == null) { return null; } } } return parentInterval; } /** * Calculate the next child interval. * * @param context The current context. * @param parentInterval The parent interval. * * @return The next child interval. */ private ScheduleResult childResult(ScheduleContext context, Interval parentInterval) { // if now is before the start of the next interval // pass the start of the next interval to the child, // otherwise use now to find the next child interval. if (context.getDate().compareTo(parentInterval.getFromDate()) < 0) { return child.nextDue( context.spawn( parentInterval.getFromDate(), parentInterval)); } else { return child.nextDue( context.spawn( parentInterval)); } } }