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

org.quartz.triggers.SimpleTriggerImpl Maven / Gradle / Ivy

There is a newer version: 2.3.0
Show newest version
/**
 * Copyright 2015 Knowm Inc. (http://knowm.org) and contributors.
 * Copyright 2013-2015 Xeiam LLC (http://xeiam.com) and contributors.
 * Copyright 2001-2011 Terracotta Inc. (http://terracotta.org).
 *
 * 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.triggers;

import java.util.Date;

import org.quartz.core.Calendar;
import org.quartz.core.JobExecutionContext;
import org.quartz.core.Scheduler;
import org.quartz.exceptions.JobExecutionException;
import org.quartz.exceptions.SchedulerException;

/**
 * 

* A concrete {@link Trigger} that is used to fire a {@link org.quartz.jobs.JobDetail} at a given moment in time, and * optionally repeated at a specified interval. *

* * @author James House * @author contributions by Lieven Govaerts of Ebitec Nv, Belgium. */ public class SimpleTriggerImpl extends AbstractTrigger implements SimpleTrigger { /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Constants. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ private static final int YEAR_TO_GIVEUP_SCHEDULING_AT = java.util.Calendar.getInstance().get(java.util.Calendar.YEAR) + 100; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Data members. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ private int repeatCount = 0; private long repeatInterval = 0; private int timesTriggered = 0; private final boolean complete = false; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Constructors. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /** *

* Create a SimpleTrigger with no settings. *

*/ public SimpleTriggerImpl() { super(); } /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Interface. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /** *

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

*/ @Override public Date getStartTime() { return startTime; } /** *

* Set the time at which the SimpleTrigger 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 && startTime != null && eTime.before(startTime)) { throw new IllegalArgumentException("End time cannot be before start time"); } this.startTime = startTime; } /** *

* Get the time at which the SimpleTrigger should quit repeating - even if repeastCount isn't yet satisfied. *

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

* Set the time at which the SimpleTrigger 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; } @Override public int getRepeatCount() { return repeatCount; } /** *

* Set the the number of time the SimpleTrigger should repeat, after which it will be automatically deleted. *

* * @see #REPEAT_INDEFINITELY * @exception IllegalArgumentException if repeatCount is < 0 */ 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 long getRepeatInterval() { return repeatInterval; } /** *

* Set the the time interval (in milliseconds) at which the SimpleTrigger should repeat. *

* * @exception IllegalArgumentException if repeatInterval is <= 0 */ public void setRepeatInterval(long repeatInterval) { if (repeatInterval < 0) { throw new IllegalArgumentException("Repeat interval must be >= 0"); } this.repeatInterval = repeatInterval; } /** *

* Get the number of times the SimpleTrigger has already fired. *

*/ @Override public int getTimesTriggered() { return timesTriggered; } /** *

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

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

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

*

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

    *
  • If the Repeat Count is 0, then the instruction will be interpreted as MISFIRE_INSTRUCTION_FIRE_NOW.
  • *
  • If the Repeat Count is REPEAT_INDEFINITELY, then the instruction will be interpreted as * MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT. WARNING: using * MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT with a trigger that has a non-null end-time may cause the trigger to never fire again if * the end-time arrived during the misfire time span.
  • *
  • If the Repeat Count is > 0, then the instruction will be interpreted as * MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT.
  • *
*

*

* If the misfire instruction is set to Trigger.MISFIRE_INSTRUCTION_SKIP_TO_NEXT_FIRE_AFTER_CURRENT_DATE then the behavior will be * identical to */ @Override public void updateAfterMisfire(Calendar cal) { int instr = getMisfireInstruction(); if (instr == Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) { return; } if (instr == Trigger.MISFIRE_INSTRUCTION_SMART_POLICY) { if (getRepeatCount() == 0) { instr = MISFIRE_INSTRUCTION_FIRE_NOW; } else if (getRepeatCount() == REPEAT_INDEFINITELY) { instr = MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT; } else { // if (getRepeatCount() > 0) instr = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT; } } else if (instr == MISFIRE_INSTRUCTION_FIRE_NOW && getRepeatCount() != 0) { instr = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT; } if (instr == MISFIRE_INSTRUCTION_FIRE_NOW) { setNextFireTime(new Date()); } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT) { Date newFireTime = getFireTimeAfter(new Date()); while (newFireTime != null && cal != null && !cal.isTimeIncluded(newFireTime.getTime())) { newFireTime = getFireTimeAfter(newFireTime); if (newFireTime == null) { break; } // avoid infinite loop java.util.Calendar c = java.util.Calendar.getInstance(); c.setTime(newFireTime); if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) { newFireTime = null; } } setNextFireTime(newFireTime); } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT) { Date newFireTime = getFireTimeAfter(new Date()); while (newFireTime != null && cal != null && !cal.isTimeIncluded(newFireTime.getTime())) { newFireTime = getFireTimeAfter(newFireTime); if (newFireTime == null) { break; } // avoid infinite loop java.util.Calendar c = java.util.Calendar.getInstance(); c.setTime(newFireTime); if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) { newFireTime = null; } } if (newFireTime != null) { int timesMissed = computeNumTimesFiredBetween(nextFireTime, newFireTime); setTimesTriggered(getTimesTriggered() + timesMissed); } setNextFireTime(newFireTime); } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT) { Date newFireTime = new Date(); if (repeatCount != 0 && repeatCount != REPEAT_INDEFINITELY) { setRepeatCount(getRepeatCount() - getTimesTriggered()); setTimesTriggered(0); } if (getEndTime() != null && getEndTime().before(newFireTime)) { setNextFireTime(null); // We are past the end time } else { setStartTime(newFireTime); setNextFireTime(newFireTime); } } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT) { Date newFireTime = new Date(); int timesMissed = computeNumTimesFiredBetween(nextFireTime, newFireTime); if (repeatCount != 0 && repeatCount != REPEAT_INDEFINITELY) { int remainingCount = getRepeatCount() - (getTimesTriggered() + timesMissed); if (remainingCount <= 0) { remainingCount = 0; } setRepeatCount(remainingCount); setTimesTriggered(0); } if (getEndTime() != null && getEndTime().before(newFireTime)) { setNextFireTime(null); // We are past the end time } else { setStartTime(newFireTime); setNextFireTime(newFireTime); } } } /** *

* 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; nextFireTime = getFireTimeAfter(nextFireTime); while (nextFireTime != null && calendar != null && !calendar.isTimeIncluded(nextFireTime.getTime())) { nextFireTime = getFireTimeAfter(nextFireTime); if (nextFireTime == null) { break; } // avoid infinite loop java.util.Calendar c = java.util.Calendar.getInstance(); c.setTime(nextFireTime); if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) { nextFireTime = null; } } } /** *

* 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) { nextFireTime = getStartTime(); while (nextFireTime != null && calendar != null && !calendar.isTimeIncluded(nextFireTime.getTime())) { nextFireTime = getFireTimeAfter(nextFireTime); if (nextFireTime == null) { break; } // avoid infinite loop java.util.Calendar c = java.util.Calendar.getInstance(); c.setTime(nextFireTime); if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) { return null; } } return nextFireTime; } /** *

* 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. *

* * @see TriggerUtils#computeFireTimesBetween(Trigger, Calendar, Date, Date) */ @Override public Date getNextFireTime() { return nextFireTime; } /** *

* Returns the previous time at which the SimpleTrigger 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 SimpleTrigger should fire. *

*

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

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

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

*

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

*/ @Override public void setPreviousFireTime(Date previousFireTime) { this.previousFireTime = previousFireTime; } /** *

* Returns the next time at which the SimpleTrigger will fire, after the given time. If the trigger will not fire after the given time, * null will be returned. *

*/ @Override public Date getFireTimeAfter(Date afterTime) { if (complete) { return null; } if ((timesTriggered > repeatCount) && (repeatCount != REPEAT_INDEFINITELY)) { return null; } if (afterTime == null) { afterTime = new Date(); } if (repeatCount == 0 && afterTime.compareTo(getStartTime()) >= 0) { return null; } long startMillis = getStartTime().getTime(); long afterMillis = afterTime.getTime(); long endMillis = (getEndTime() == null) ? Long.MAX_VALUE : getEndTime().getTime(); if (endMillis <= afterMillis) { return null; } if (afterMillis < startMillis) { return new Date(startMillis); } long numberOfTimesExecuted = ((afterMillis - startMillis) / repeatInterval) + 1; if ((numberOfTimesExecuted > repeatCount) && (repeatCount != REPEAT_INDEFINITELY)) { return null; } Date time = new Date(startMillis + (numberOfTimesExecuted * repeatInterval)); if (endMillis <= time.getTime()) { return null; } return time; } /** *

* Returns the last time at which the SimpleTrigger will fire, before the given time. If the trigger will not fire before the given * time, null will be returned. *

*/ private Date getFireTimeBefore(Date end) { if (end.getTime() < getStartTime().getTime()) { return null; } int numFires = computeNumTimesFiredBetween(getStartTime(), end); return new Date(getStartTime().getTime() + (numFires * repeatInterval)); } private int computeNumTimesFiredBetween(Date start, Date end) { if (repeatInterval < 1) { return 0; } long time = end.getTime() - start.getTime(); return (int) (time / repeatInterval); } /** *

* Returns the final time at which the SimpleTrigger will fire, if repeatCount is REPEAT_INDEFINITELY, null will be returned. *

*

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

*/ @Override public Date getFinalFireTime() { if (repeatCount == 0) { return startTime; } if (repeatCount == REPEAT_INDEFINITELY) { return (getEndTime() == null) ? null : getFireTimeBefore(getEndTime()); } long lastTrigger = startTime.getTime() + (repeatCount * repeatInterval); if ((getEndTime() == null) || (lastTrigger < getEndTime().getTime())) { return new Date(lastTrigger); } else { return getFireTimeBefore(getEndTime()); } } /** *

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

*/ @Override public boolean mayFireAgain() { return (getNextFireTime() != null); } /** *

* Validates whether the properties of the JobDetail are valid for submission into a Scheduler. * * @throws IllegalStateException if a required property (such as Name, Group, Class) is not set. */ @Override public void validate() throws SchedulerException { super.validate(); if (repeatCount != 0 && repeatInterval < 1) { throw new SchedulerException("Repeat Interval cannot be zero."); } } @Override public String toString() { return super.toString() + ", repeatCount: " + getRepeatCount() + ", repeatInterval: " + getRepeatInterval(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy