/* * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * */ package org.quartz; import java.util.TimeZone; import org.quartz.DateBuilder.IntervalUnit; import org.quartz.impl.triggers.CalendarIntervalTriggerImpl; import org.quartz.spi.MutableTrigger; /** * <code>CalendarIntervalScheduleBuilder</code> is a {@link ScheduleBuilder} * that defines calendar time (day, week, month, year) interval-based * schedules for <code>Trigger</code>s. * * <p>Quartz provides a builder-style API for constructing scheduling-related * entities via a Domain-Specific Language (DSL). The DSL can best be * utilized through the usage of static imports of the methods on the classes * <code>TriggerBuilder</code>, <code>JobBuilder</code>, * <code>DateBuilder</code>, <code>JobKey</code>, <code>TriggerKey</code> * and the various <code>ScheduleBuilder</code> implementations.</p> * * <p>Client code can then use the DSL to write code such as this:</p> * <pre> * JobDetail job = newJob(MyJob.class) * .withIdentity("myJob") * .build(); * * Trigger trigger = newTrigger() * .withIdentity(triggerKey("myTrigger", "myTriggerGroup")) * .withSchedule(withIntervalInDays(3)) * .startAt(futureDate(10, MINUTES)) * .build(); * * scheduler.scheduleJob(job, trigger); * <pre> * * @see DailyTimeIntervalScheduleBuilder * @see CronScheduleBuilder * @see ScheduleBuilder * @see SimpleScheduleBuilder * @see TriggerBuilder */ public class CalendarIntervalScheduleBuilder extends ScheduleBuilder<CalendarIntervalTrigger> { private int interval = 1; private IntervalUnit intervalUnit = IntervalUnit.DAY; private int misfireInstruction = CalendarIntervalTrigger.MISFIRE_INSTRUCTION_SMART_POLICY; private TimeZone timeZone; private boolean preserveHourOfDayAcrossDaylightSavings; private boolean skipDayIfHourDoesNotExist; protected CalendarIntervalScheduleBuilder() { } /** * Create a CalendarIntervalScheduleBuilder. * * @return the new CalendarIntervalScheduleBuilder */ public static CalendarIntervalScheduleBuilder calendarIntervalSchedule() { return new CalendarIntervalScheduleBuilder(); } /** * Build the actual Trigger -- NOT intended to be invoked by end users, * but will rather be invoked by a TriggerBuilder which this * ScheduleBuilder is given to. * * @see TriggerBuilder#withSchedule(ScheduleBuilder) */ @Override public MutableTrigger build() { CalendarIntervalTriggerImpl st = new CalendarIntervalTriggerImpl(); st.setRepeatInterval(interval); st.setRepeatIntervalUnit(intervalUnit); st.setMisfireInstruction(misfireInstruction); st.setTimeZone(timeZone); st.setPreserveHourOfDayAcrossDaylightSavings(preserveHourOfDayAcrossDaylightSavings); st.setSkipDayIfHourDoesNotExist(skipDayIfHourDoesNotExist); return st; } /** * Specify the time unit and interval for the Trigger to be produced. * * @param timeInterval the interval at which the trigger should repeat. * @param unit the time unit (IntervalUnit) of the interval. * @return the updated CalendarIntervalScheduleBuilder * @see CalendarIntervalTrigger#getRepeatInterval() * @see CalendarIntervalTrigger#getRepeatIntervalUnit() */ public CalendarIntervalScheduleBuilder withInterval(int timeInterval, IntervalUnit unit) { if(unit == null) throw new IllegalArgumentException("TimeUnit must be specified."); validateInterval(timeInterval); this.interval = timeInterval; this.intervalUnit = unit; return this; } /** * Specify an interval in the IntervalUnit.SECOND that the produced * Trigger will repeat at. * * @param intervalInSeconds the number of seconds at which the trigger should repeat. * @return the updated CalendarIntervalScheduleBuilder * @see CalendarIntervalTrigger#getRepeatInterval() * @see CalendarIntervalTrigger#getRepeatIntervalUnit() */ public CalendarIntervalScheduleBuilder withIntervalInSeconds(int intervalInSeconds) { validateInterval(intervalInSeconds); this.interval = intervalInSeconds; this.intervalUnit = IntervalUnit.SECOND; return this; } /** * Specify an interval in the IntervalUnit.MINUTE that the produced * Trigger will repeat at. * * @param intervalInMinutes the number of minutes at which the trigger should repeat. * @return the updated CalendarIntervalScheduleBuilder * @see CalendarIntervalTrigger#getRepeatInterval() * @see CalendarIntervalTrigger#getRepeatIntervalUnit() */ public CalendarIntervalScheduleBuilder withIntervalInMinutes(int intervalInMinutes) { validateInterval(intervalInMinutes); this.interval = intervalInMinutes; this.intervalUnit = IntervalUnit.MINUTE; return this; } /** * Specify an interval in the IntervalUnit.HOUR that the produced * Trigger will repeat at. * * @param intervalInHours the number of hours at which the trigger should repeat. * @return the updated CalendarIntervalScheduleBuilder * @see CalendarIntervalTrigger#getRepeatInterval() * @see CalendarIntervalTrigger#getRepeatIntervalUnit() */ public CalendarIntervalScheduleBuilder withIntervalInHours(int intervalInHours) { validateInterval(intervalInHours); this.interval = intervalInHours; this.intervalUnit = IntervalUnit.HOUR; return this; } /** * Specify an interval in the IntervalUnit.DAY that the produced * Trigger will repeat at. * * @param intervalInDays the number of days at which the trigger should repeat. * @return the updated CalendarIntervalScheduleBuilder * @see CalendarIntervalTrigger#getRepeatInterval() * @see CalendarIntervalTrigger#getRepeatIntervalUnit() */ public CalendarIntervalScheduleBuilder withIntervalInDays(int intervalInDays) { validateInterval(intervalInDays); this.interval = intervalInDays; this.intervalUnit = IntervalUnit.DAY; return this; } /** * Specify an interval in the IntervalUnit.WEEK that the produced * Trigger will repeat at. * * @param intervalInWeeks the number of weeks at which the trigger should repeat. * @return the updated CalendarIntervalScheduleBuilder * @see CalendarIntervalTrigger#getRepeatInterval() * @see CalendarIntervalTrigger#getRepeatIntervalUnit() */ public CalendarIntervalScheduleBuilder withIntervalInWeeks(int intervalInWeeks) { validateInterval(intervalInWeeks); this.interval = intervalInWeeks; this.intervalUnit = IntervalUnit.WEEK; return this; } /** * Specify an interval in the IntervalUnit.MONTH that the produced * Trigger will repeat at. * * @param intervalInMonths the number of months at which the trigger should repeat. * @return the updated CalendarIntervalScheduleBuilder * @see CalendarIntervalTrigger#getRepeatInterval() * @see CalendarIntervalTrigger#getRepeatIntervalUnit() */ public CalendarIntervalScheduleBuilder withIntervalInMonths(int intervalInMonths) { validateInterval(intervalInMonths); this.interval = intervalInMonths; this.intervalUnit = IntervalUnit.MONTH; return this; } /** * Specify an interval in the IntervalUnit.YEAR that the produced * Trigger will repeat at. * * @param intervalInYears the number of years at which the trigger should repeat. * @return the updated CalendarIntervalScheduleBuilder * @see CalendarIntervalTrigger#getRepeatInterval() * @see CalendarIntervalTrigger#getRepeatIntervalUnit() */ public CalendarIntervalScheduleBuilder withIntervalInYears(int intervalInYears) { validateInterval(intervalInYears); this.interval = intervalInYears; this.intervalUnit = IntervalUnit.YEAR; return this; } /** * If the Trigger misfires, use the * {@link Trigger#MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY} instruction. * * @return the updated CronScheduleBuilder * @see Trigger#MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY */ public CalendarIntervalScheduleBuilder withMisfireHandlingInstructionIgnoreMisfires() { misfireInstruction = Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY; return this; } /** * If the Trigger misfires, use the * {@link CalendarIntervalTrigger#MISFIRE_INSTRUCTION_DO_NOTHING} instruction. * * @return the updated CalendarIntervalScheduleBuilder * @see CalendarIntervalTrigger#MISFIRE_INSTRUCTION_DO_NOTHING */ public CalendarIntervalScheduleBuilder withMisfireHandlingInstructionDoNothing() { misfireInstruction = CalendarIntervalTrigger.MISFIRE_INSTRUCTION_DO_NOTHING; return this; } /** * If the Trigger misfires, use the * {@link CalendarIntervalTrigger#MISFIRE_INSTRUCTION_FIRE_ONCE_NOW} instruction. * * @return the updated CalendarIntervalScheduleBuilder * @see CalendarIntervalTrigger#MISFIRE_INSTRUCTION_FIRE_ONCE_NOW */ public CalendarIntervalScheduleBuilder withMisfireHandlingInstructionFireAndProceed() { misfireInstruction = CalendarIntervalTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW; return this; } /** * The <code>TimeZone</code> in which to base the schedule. * * @param timezone the time-zone for the schedule. * @return the updated CalendarIntervalScheduleBuilder * @see CalendarIntervalTrigger#getTimeZone() */ public CalendarIntervalScheduleBuilder inTimeZone(TimeZone timezone) { this.timeZone = timezone; return this; } /** * If intervals are a day or greater, this property (set to true) will * cause the firing of the trigger to always occur at the same time of day, * (the time of day of the startTime) regardless of daylight saving time * transitions. Default value is false. * * <p> * For example, without the property set, your trigger may have a start * time of 9:00 am on March 1st, and a repeat interval of 2 days. But * after the daylight saving transition occurs, the trigger may start * firing at 8:00 am every other day. * </p> * * <p> * If however, the time of day does not exist on a given day to fire * (e.g. 2:00 am in the United States on the days of daylight saving * transition), the trigger will go ahead and fire one hour off on * that day, and then resume the normal hour on other days. If * you wish for the trigger to never fire at the "wrong" hour, then * you should set the property skipDayIfHourDoesNotExist. * </p> * * @see #skipDayIfHourDoesNotExist(boolean) * @see #inTimeZone(TimeZone) * @see TriggerBuilder#startAt(java.util.Date) */ public CalendarIntervalScheduleBuilder preserveHourOfDayAcrossDaylightSavings(boolean preserveHourOfDay) { this.preserveHourOfDayAcrossDaylightSavings = preserveHourOfDay; return this; } /** * If intervals are a day or greater, and * preserveHourOfDayAcrossDaylightSavings property is set to true, and the * hour of the day does not exist on a given day for which the trigger * would fire, the day will be skipped and the trigger advanced a second * interval if this property is set to true. Defaults to false. * * <p> * <b>CAUTION!</b> If you enable this property, and your hour of day happens * to be that of daylight savings transition (e.g. 2:00 am in the United * States) and the trigger's interval would have had the trigger fire on * that day, then you may actually completely miss a firing on the day of * transition if that hour of day does not exist on that day! In such a * case the next fire time of the trigger will be computed as double (if * the interval is 2 days, then a span of 4 days between firings will * occur). * </p> * * @see #preserveHourOfDayAcrossDaylightSavings(boolean) */ public CalendarIntervalScheduleBuilder skipDayIfHourDoesNotExist(boolean skipDay) { this.skipDayIfHourDoesNotExist = skipDay; return this; } private void validateInterval(int timeInterval) { if(timeInterval <= 0) throw new IllegalArgumentException("Interval must be a positive value."); } }