All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.quartz.impl.triggers.CalendarOffsetTriggerImpl Maven / Gradle / Ivy

package org.quartz.impl.triggers;

import org.quartz.*;
import org.quartz.DateBuilder.IntervalUnit;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class CalendarOffsetTriggerImpl extends AbstractTrigger implements CalendarOffsetTrigger, CoreTrigger {

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     *
     * Constants.
     *
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    private static final long serialVersionUID = -2635982274232850343L;


    private static final int YEAR_TO_GIVEUP_SCHEDULING_AT = java.util.Calendar.getInstance().get(java.util.Calendar.YEAR) + 100;

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     *
     * Data members.
     *
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    private Date startTime = null;

    private Date endTime = null;

    private Date nextFireTime = null;

    private Date previousFireTime = null;

    private int repeatCount = REPEAT_INDEFINITELY;

    //private  int repeatInterval = 0;

    // WEEK/MONTH/SEAZON/HALF_YEAR/YEAR
    private IntervalUnit repeatIntervalUnit = IntervalUnit.WEEK;

    private int timesTriggered = 0;

    private boolean complete = false;

    private TimeOfDay startTimeOfDay;

    private int innerOffset;

    private int outerOffset;

    private boolean reversed;

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     *
     * Constructors.
     *
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    /**
     * 

* Create a DateIntervalTrigger with no settings. *

*/ public CalendarOffsetTriggerImpl() { super(); } /** *

* Create a DateIntervalTrigger that will occur immediately, and * repeat at the the given interval. *

*/ public CalendarOffsetTriggerImpl(String name, TimeOfDay startTimeOfDay, IntervalUnit intervalUnit) { this(name, null, startTimeOfDay, intervalUnit); } /** *

* Create a DateIntervalTrigger that will occur immediately, and * repeat at the the given interval. *

*/ public CalendarOffsetTriggerImpl(String name, String group, TimeOfDay startTimeOfDay, IntervalUnit intervalUnit) { this(name, group, new Date(), null, startTimeOfDay, intervalUnit); } /** *

* Create a DateIntervalTrigger that will occur at the given time, * and repeat at the the given interval until the given end time. *

* * @param startTime * A Date set to the time for the Trigger * to fire. * @param endTime * A Date set to the time for the Trigger * to quit repeat firing. * @param intervalUnit * The repeat interval unit (minutes, days, months, etc). */ public CalendarOffsetTriggerImpl(String name, Date startTime, Date endTime, TimeOfDay startTimeOfDay, IntervalUnit intervalUnit) { this(name, null, startTime, endTime, startTimeOfDay, intervalUnit); } /** *

* Create a DateIntervalTrigger that will occur at the given time, * and repeat at the the given interval until the given end time. *

* * @param startTime * A Date set to the time for the Trigger * to fire. * @param endTime * A Date set to the time for the Trigger * to quit repeat firing. * @param intervalUnit * The repeat interval unit (minutes, days, months, etc). */ public CalendarOffsetTriggerImpl(String name, String group, Date startTime, Date endTime, TimeOfDay startTimeOfDay, IntervalUnit intervalUnit) { super(name, group); setStartTime(startTime); setEndTime(endTime); setStartTimeOfDay(startTimeOfDay); setRepeatIntervalUnit(intervalUnit); } /** *

* Create a DateIntervalTrigger that will occur at the given time, * fire the identified Job and repeat at the the given * interval until the given end time. *

* * @param startTime * A Date set to the time for the Trigger * to fire. * @param endTime * A Date set to the time for the Trigger * to quit repeat firing. * @param intervalUnit * The repeat interval unit (minutes, days, months, etc). */ public CalendarOffsetTriggerImpl(String name, String group, String jobName, String jobGroup, Date startTime, Date endTime, TimeOfDay startTimeOfDay, IntervalUnit intervalUnit) { super(name, group, jobName, jobGroup); setStartTime(startTime); setEndTime(endTime); setStartTimeOfDay(startTimeOfDay); setRepeatIntervalUnit(intervalUnit); } /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Interface. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /** *

* Get the time at which the DateIntervalTrigger should occur. *

*/ @Override public Date getStartTime() { if(startTime == null) startTime = new Date(); return startTime; } /** *

* Set the time at which the DateIntervalTrigger should occur. *

* * @exception IllegalArgumentException * if startTime is null. */ @Override public void setStartTime(Date startTime) { if (startTime == null) { throw new IllegalArgumentException("Start time cannot be null"); } Date eTime = getEndTime(); if (eTime != null && eTime.before(startTime)) { throw new IllegalArgumentException( "End time cannot be before start time"); } this.startTime = startTime; } /** *

* Get the time at which the DateIntervalTrigger should quit * repeating. *

* * @see #getFinalFireTime() */ @Override public Date getEndTime() { return endTime; } /** *

* Set the time at which the DateIntervalTrigger should quit * repeating (and be automatically deleted). *

* * @exception IllegalArgumentException * if endTime is before start time. */ @Override public void setEndTime(Date endTime) { Date sTime = getStartTime(); if (sTime != null && endTime != null && sTime.after(endTime)) { throw new IllegalArgumentException( "End time cannot be before start time"); } this.endTime = endTime; } /* (non-Javadoc) * @see org.quartz.DateIntervalTriggerI#getIntervalUnit() */ public IntervalUnit getRepeatIntervalUnit() { return repeatIntervalUnit; } /** *

Set the interval unit - the time unit on with the interval applies.

*/ public void setRepeatIntervalUnit(IntervalUnit repeatIntervalUnit) { if (repeatIntervalUnit == null || !(repeatIntervalUnit.equals(IntervalUnit.WEEK) || repeatIntervalUnit.equals(IntervalUnit.MONTH) || repeatIntervalUnit.equals(IntervalUnit.SEASON) || repeatIntervalUnit.equals(IntervalUnit.HALF_YEAR) || repeatIntervalUnit.equals(IntervalUnit.YEAR))) { throw new IllegalArgumentException("TimeUnit is incorrect," + "it must be week,month,season,half year or year,but you set " + repeatIntervalUnit); } this.repeatIntervalUnit = repeatIntervalUnit; } /* (non-Javadoc) * @see org.quartz.DateIntervalTriggerI#getTimesTriggered() */ public int getTimesTriggered() { return timesTriggered; } /** *

* Set the number of times the DateIntervalTrigger has already * fired. *

*/ public void setTimesTriggered(int timesTriggered) { this.timesTriggered = timesTriggered; } @Override protected boolean validateMisfireInstruction(int misfireInstruction) { if (misfireInstruction < MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) { return false; } return misfireInstruction <= MISFIRE_INSTRUCTION_DO_NOTHING; } /** *

* Updates the DateIntervalTrigger's state based on the * MISFIRE_INSTRUCTION_XXX that was selected when the DateIntervalTrigger * was created. *

* *

* If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY, * then the following scheme will be used:
*

    *
  • The instruction will be interpreted as MISFIRE_INSTRUCTION_FIRE_ONCE_NOW *
*

*/ @Override public void updateAfterMisfire(Calendar cal) { int instr = getMisfireInstruction(); if(instr == MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) return; if (instr == MISFIRE_INSTRUCTION_SMART_POLICY) { instr = MISFIRE_INSTRUCTION_FIRE_ONCE_NOW; } if (instr == MISFIRE_INSTRUCTION_DO_NOTHING) { Date newFixedFireTime = getFireTimeAfter(new Date(), cal); setNextFireTime(new Date(newFixedFireTime.getTime() + outerOffset * 86400000)); } else if (instr == MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) { // fire once now... setNextFireTime(new Date()); // the new fire time afterward will magically preserve the original // time of day for firing for day/week/month interval triggers, // because of the way getFireTimeAfter() works - in its always restarting // computation from the start time. } } /** * * @see org.quartz.spi.OperableTrigger#updateWithNewCalendar(Calendar, long) */ @Override public void updateWithNewCalendar(Calendar calendar, long misfireThreshold) { if (calendar == null) { return; } Date fixedNextFireTime = getFireTimeAfter( new Date(previousFireTime.getTime() - outerOffset * 86400000), calendar); if (fixedNextFireTime == null) { return; } nextFireTime = new Date(fixedNextFireTime.getTime() + outerOffset * 86400000); Date now = new Date(); if(nextFireTime.before(now) && now.getTime() - nextFireTime.getTime() >= misfireThreshold) { fixedNextFireTime = computeNextPeriod(fixedNextFireTime, calendar); nextFireTime = fixedNextFireTime == null ? null : new Date(fixedNextFireTime.getTime() + outerOffset * 86400000); } } /** *

* Called by the scheduler at the time a Trigger is first * added to the scheduler, in order to have the Trigger * compute its first fire time, based on any associated calendar. *

* *

* After this method has been called, getNextFireTime() * should return a valid answer. *

* * @return the first time at which the Trigger will be fired * by the scheduler, which is also the same value getNextFireTime() * will return (until after the first firing of the Trigger). *

*/ @Override public Date computeFirstFireTime(Calendar calendar) { Date fixedStartTime = new Date(getStartTime().getTime() - outerOffset * 86400000); Date fixedNextFireTime = getFireTimeAfter(fixedStartTime, calendar); if(fixedNextFireTime.before(fixedStartTime)) { fixedNextFireTime = computeNextPeriod(fixedNextFireTime, calendar); nextFireTime = fixedNextFireTime == null ? null : new Date(fixedNextFireTime.getTime() + outerOffset * 86400000); } else { nextFireTime = fixedNextFireTime; } return nextFireTime; } private Date computeNextPeriod(Date fixedNextFireTime, Calendar calendar) { java.util.Calendar sTime = java.util.Calendar.getInstance(); sTime.setTime(fixedNextFireTime); if(repeatIntervalUnit.equals(IntervalUnit.WEEK)) { sTime.set(java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.SUNDAY); sTime.add(java.util.Calendar.WEEK_OF_YEAR, 1); } else if(repeatIntervalUnit.equals(IntervalUnit.MONTH)) { sTime.set(java.util.Calendar.DAY_OF_MONTH, 1); sTime.add(java.util.Calendar.MONTH, 1); } else if(repeatIntervalUnit.equals(IntervalUnit.SEASON)) { sTime.set(java.util.Calendar.DAY_OF_MONTH, 1); sTime.add(java.util.Calendar.MONTH, 3); } else if(repeatIntervalUnit.equals(IntervalUnit.HALF_YEAR)) { sTime.set(java.util.Calendar.DAY_OF_MONTH, 1); sTime.add(java.util.Calendar.MONTH, 6); } else if(repeatIntervalUnit.equals(IntervalUnit.YEAR)) { sTime.set(java.util.Calendar.DAY_OF_MONTH, 1); sTime.add(java.util.Calendar.YEAR, 1); } fixedNextFireTime = getFireTimeAfter(sTime.getTime(), calendar); return fixedNextFireTime; } private Date getFireTimeAfter(Date afterTime, Calendar calendar) { if (complete) { return null; } // Check repeatCount limit if (repeatCount != REPEAT_INDEFINITELY && timesTriggered > repeatCount) { return null; } // a. Increment afterTime by a second, so that we are comparing against a time after it! if (afterTime == null) { afterTime = new Date(); } java.util.Calendar sTime = java.util.Calendar.getInstance(); sTime.setTime(afterTime); sTime.setLenient(true); if (sTime.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) { return null; } Date lowerDate, upperDate, time; List maybeTriggeredDateList = new ArrayList(); if(repeatIntervalUnit.equals(IntervalUnit.WEEK)) { sTime.set(java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.SUNDAY); lowerDate = getDateWithStartTimeOfDay(sTime); sTime.set(java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.SATURDAY); upperDate = getDateWithStartTimeOfDay(sTime); maybeTriggeredDateList = createMaybeTriggeredDateList(7, lowerDate, upperDate, calendar); } else if(repeatIntervalUnit.equals(IntervalUnit.MONTH)) { sTime.set(java.util.Calendar.DAY_OF_MONTH, 1); lowerDate = getDateWithStartTimeOfDay(sTime); sTime.set(java.util.Calendar.DAY_OF_MONTH, sTime.getActualMaximum(java.util.Calendar.DAY_OF_MONTH)); upperDate = getDateWithStartTimeOfDay(sTime); maybeTriggeredDateList = createMaybeTriggeredDateList(31, lowerDate, upperDate, calendar); } else if(repeatIntervalUnit.equals(IntervalUnit.SEASON)) { int season = sTime.get(java.util.Calendar.MONTH)/3; // 0,1,2,3 sTime.set(java.util.Calendar.MONTH, season * 3); sTime.set(java.util.Calendar.DAY_OF_MONTH, 1); lowerDate = getDateWithStartTimeOfDay(sTime); sTime.set(java.util.Calendar.MONTH, season * 3 + 2); sTime.set(java.util.Calendar.DAY_OF_MONTH, sTime.getActualMaximum(java.util.Calendar.DAY_OF_MONTH)); upperDate = getDateWithStartTimeOfDay(sTime); maybeTriggeredDateList = createMaybeTriggeredDateList(92, lowerDate, upperDate, calendar); } else if(repeatIntervalUnit.equals(IntervalUnit.HALF_YEAR)) { int half = sTime.get(java.util.Calendar.MONTH)/6; // 0,1 sTime.set(java.util.Calendar.MONTH, half * 6); sTime.set(java.util.Calendar.DAY_OF_MONTH, 1); lowerDate = getDateWithStartTimeOfDay(sTime); sTime.set(java.util.Calendar.MONTH, half * 6 + 5); sTime.set(java.util.Calendar.DAY_OF_MONTH, sTime.getActualMaximum(java.util.Calendar.DAY_OF_MONTH)); upperDate = getDateWithStartTimeOfDay(sTime); maybeTriggeredDateList = createMaybeTriggeredDateList(184, lowerDate, upperDate, calendar); } else if(repeatIntervalUnit.equals(IntervalUnit.YEAR)) { sTime.set(java.util.Calendar.DAY_OF_YEAR, 1); lowerDate = getDateWithStartTimeOfDay(sTime); sTime.set(java.util.Calendar.DAY_OF_YEAR, sTime.getActualMaximum(java.util.Calendar.DAY_OF_YEAR)); upperDate = getDateWithStartTimeOfDay(sTime);; maybeTriggeredDateList = createMaybeTriggeredDateList(366, lowerDate, upperDate, calendar); } else { throw new IllegalArgumentException("TimeUnit is illegal:" + repeatIntervalUnit.toString()); } if (maybeTriggeredDateList.isEmpty() || maybeTriggeredDateList.size() <= innerOffset) { return computeNextPeriod(sTime.getTime(), calendar); } time = maybeTriggeredDateList.get(reversed ? maybeTriggeredDateList.size() - 1 - innerOffset : innerOffset); if (getEndTime() != null && getEndTime().before(new Date(time.getTime() + outerOffset * 86400000))) { return null; } return time; } private List createMaybeTriggeredDateList(int initialCapacity, Date lowerDate, Date upperDate, Calendar calendar) { List maybeTriggeredDateList = new ArrayList(initialCapacity); Date tempDate = lowerDate; while (!upperDate.before(tempDate)) { if (calendar == null || calendar.isTimeIncluded(tempDate.getTime())) { maybeTriggeredDateList.add((Date) tempDate.clone()); } tempDate.setTime(tempDate.getTime() + 86400000); } return maybeTriggeredDateList; } /** *

* Called when the {@link Scheduler} has decided to 'fire' * the trigger (execute the associated Job), in order to * give the Trigger a chance to update itself for its next * triggering (if any). *

* * @see #executionComplete(JobExecutionContext, JobExecutionException) */ @Override public void triggered(Calendar calendar) { timesTriggered++; previousFireTime = nextFireTime; Date fixedNextFireTime = computeNextPeriod(new Date(previousFireTime.getTime() - outerOffset * 86400000), calendar); nextFireTime = fixedNextFireTime == null ? null : new Date(fixedNextFireTime.getTime() + outerOffset * 86400000); } /** *

* Returns the final time at which the DateIntervalTrigger will * fire, if there is no end time set, null will be returned. *

* *

* Note that the return time may be in the past. * TODO bug *

*/ @Override public Date getFinalFireTime() { if (complete || getEndTime() == null) { return null; } return new Date(getEndTime().getTime()); } private Date getDateWithStartTimeOfDay(java.util.Calendar sTime) { sTime.set(java.util.Calendar.HOUR_OF_DAY, startTimeOfDay.getHour()); sTime.set(java.util.Calendar.MINUTE, startTimeOfDay.getMinute()); sTime.set(java.util.Calendar.SECOND, startTimeOfDay.getSecond()); return sTime.getTime(); } @Override public Date getFireTimeAfter(Date afterTime) { return null; } /** *

* Determines whether or not the DateIntervalTrigger will occur * again. *

*/ @Override public boolean mayFireAgain() { return (getNextFireTime() != null); } /** * Get a {@link ScheduleBuilder} that is configured to produce a * schedule identical to this trigger's schedule. * * @see #getTriggerBuilder() */ @Override public ScheduleBuilder getScheduleBuilder() { CalendarOffsetScheduleBuilder cb = CalendarOffsetScheduleBuilder.calendarOffsetSchedule() .withIntervalUnit(repeatIntervalUnit).startingDailyAt(getStartTimeOfDay()); switch(getMisfireInstruction()) { case MISFIRE_INSTRUCTION_DO_NOTHING : cb.withMisfireHandlingInstructionDoNothing(); break; case MISFIRE_INSTRUCTION_FIRE_ONCE_NOW : cb.withMisfireHandlingInstructionFireAndProceed(); break; } return cb; } public boolean hasAdditionalProperties() { return false; } /** *

* Returns the next time at which the Trigger is scheduled to fire. If * the trigger will not fire again, null will be returned. Note that * the time returned can possibly be in the past, if the time that was computed * for the trigger to next fire has already arrived, but the scheduler has not yet * been able to fire the trigger (which would likely be due to lack of resources * e.g. threads). *

* *

The value returned is not guaranteed to be valid until after the Trigger * has been added to the scheduler. *

*/ @Override public Date getNextFireTime() { return nextFireTime; } /** *

* Returns the previous time at which the DateIntervalTrigger * fired. If the trigger has not yet fired, null will be * returned. */ @Override public Date getPreviousFireTime() { return previousFireTime; } /** *

* Set the next time at which the DateIntervalTrigger should fire. *

* *

* This method should not be invoked by client code. *

*/ public void setNextFireTime(Date nextFireTime) { this.nextFireTime = nextFireTime; } /** *

* Set the previous time at which the DateIntervalTrigger fired. *

* *

* This method should not be invoked by client code. *

*/ public void setPreviousFireTime(Date previousFireTime) { this.previousFireTime = previousFireTime; } @Override public int getRepeatCount() { return repeatCount; } public void setRepeatCount(int repeatCount) { if (repeatCount < 0 && repeatCount != REPEAT_INDEFINITELY) { throw new IllegalArgumentException("Repeat count must be >= 0, use the " + "constant REPEAT_INDEFINITELY for infinite."); } this.repeatCount = repeatCount; } @Override public TimeOfDay getStartTimeOfDay() { return startTimeOfDay; } public void setStartTimeOfDay(TimeOfDay startTimeOfDay) { if (startTimeOfDay == null) { throw new IllegalArgumentException("Start time of day cannot be null"); } this.startTimeOfDay = startTimeOfDay; } @Override public int getInnerOffset() { return innerOffset; } public void setInnerOffset(int innerOffset) { if (repeatIntervalUnit.equals(IntervalUnit.WEEK) && innerOffset >= 7) { throw new IllegalArgumentException("Inner offset must be < 7"); } else if (repeatIntervalUnit.equals(IntervalUnit.MONTH) && innerOffset >= 31) { throw new IllegalArgumentException("Inner offset must be < 31"); } else if (repeatIntervalUnit.equals(IntervalUnit.SEASON) && innerOffset >= 92) { throw new IllegalArgumentException("Inner offset must be < 92"); } else if (repeatIntervalUnit.equals(IntervalUnit.HALF_YEAR) && innerOffset >= 184) { throw new IllegalArgumentException("Inner offset must be < 184"); } else if (repeatIntervalUnit.equals(IntervalUnit.YEAR) && innerOffset >= 366) { throw new IllegalArgumentException("Inner offset must be < 366"); } this.innerOffset = innerOffset; } @Override public int getOuterOffset() { return outerOffset; } public void setOuterOffset(int outerOffset) { this.outerOffset = outerOffset; } @Override public boolean isReversed() { return reversed; } public void setReversed(boolean reversed) { this.reversed = reversed; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy