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

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

There is a newer version: 2.0.1
Show newest version
/* 
 * Copyright 2001-2009 Terracotta, Inc. 
 * 
 * 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.impl.triggers;

import java.util.Date;

import org.quartz.Calendar;
import org.quartz.CronTrigger;
import org.quartz.JobExecutionContext;
import org.quartz.ScheduleBuilder;
import org.quartz.Scheduler;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerUtils;
import org.quartz.exceptions.JobExecutionException;
import org.quartz.exceptions.SchedulerException;

/**
 * 

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

* * @see Trigger * @see CronTrigger * @see TriggerUtils * @author James House * @author contributions by Lieven Govaerts of Ebitec Nv, Belgium. */ public class SimpleTriggerImpl extends AbstractTrigger implements SimpleTrigger { /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Constants. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /** * Required for serialization support. Introduced in Quartz 1.6.1 to maintain compatibility after the introduction of hasAdditionalProperties method. * * @see java.io.Serializable */ private static final long serialVersionUID = -3735980074222850397L; 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 = 0; private long repeatInterval = 0; private int timesTriggered = 0; private final boolean complete = false; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Constructors. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /** *

* Create a SimpleTrigger with no settings. *

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

* Create a SimpleTrigger that will occur immediately, and not repeat. *

* * @deprecated use a TriggerBuilder instead */ @Deprecated public SimpleTriggerImpl(String name, String group) { this(name, group, new Date(), null, 0, 0); } /** *

* Create a SimpleTrigger that will occur immediately, and repeat at the the given interval the given number of times. *

* * @deprecated use a TriggerBuilder instead */ @Deprecated public SimpleTriggerImpl(String name, int repeatCount, long repeatInterval) { this(name, null, repeatCount, repeatInterval); } /** *

* Create a SimpleTrigger that will occur immediately, and repeat at the the given interval the given number of times. *

* * @deprecated use a TriggerBuilder instead */ @Deprecated public SimpleTriggerImpl(String name, String group, int repeatCount, long repeatInterval) { this(name, group, new Date(), null, repeatCount, repeatInterval); } /** *

* Create a SimpleTrigger that will occur at the given time, and not repeat. *

* * @deprecated use a TriggerBuilder instead */ @Deprecated public SimpleTriggerImpl(String name, Date startTime) { this(name, null, startTime); } /** *

* Create a SimpleTrigger that will occur at the given time, and not repeat. *

* * @deprecated use a TriggerBuilder instead */ @Deprecated public SimpleTriggerImpl(String name, String group, Date startTime) { this(name, group, startTime, null, 0, 0); } /** *

* Create a SimpleTrigger that will occur at the given time, and repeat at the the given interval the given number of times, or 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 repeatCount The number of times for the Trigger to repeat firing, use {@link #REPEAT_INDEFINITELY} for unlimited times. * @param repeatInterval The number of milliseconds to pause between the repeat firing. * @deprecated use a TriggerBuilder instead */ @Deprecated public SimpleTriggerImpl(String name, Date startTime, Date endTime, int repeatCount, long repeatInterval) { this(name, null, startTime, endTime, repeatCount, repeatInterval); } /** *

* Create a SimpleTrigger that will occur at the given time, and repeat at the the given interval the given number of times, or 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 repeatCount The number of times for the Trigger to repeat firing, use {@link #REPEAT_INDEFINITELY} for unlimited times. * @param repeatInterval The number of milliseconds to pause between the repeat firing. * @deprecated use a TriggerBuilder instead */ @Deprecated public SimpleTriggerImpl(String name, String group, Date startTime, Date endTime, int repeatCount, long repeatInterval) { super(name, group); setStartTime(startTime); setEndTime(endTime); setRepeatCount(repeatCount); setRepeatInterval(repeatInterval); } /** *

* Create a SimpleTrigger that will occur at the given time, fire the identified Job and repeat at the the given interval the given number of times, or 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 repeatCount The number of times for the Trigger to repeat firing, use {@link #REPEAT_INDEFINITELY}for unlimitted times. * @param repeatInterval The number of milliseconds to pause between the repeat firing. * @deprecated use a TriggerBuilder instead */ @Deprecated public SimpleTriggerImpl(String name, String group, String jobName, String jobGroup, Date startTime, Date endTime, int repeatCount, long repeatInterval) { super(name, group, jobName, jobGroup); setStartTime(startTime); setEndTime(endTime); setRepeatCount(repeatCount); setRepeatInterval(repeatInterval); } /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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; } /* * (non-Javadoc) * @see org.quartz.SimpleTriggerI#getRepeatCount() */ @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; } /* * (non-Javadoc) * @see org.quartz.SimpleTriggerI#getRepeatInterval() */ @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; } } } /** * @see org.quartz.Trigger#updateWithNewCalendar(org.quartz.Calendar, long) */ @Override public void updateWithNewCalendar(Calendar calendar, long misfireThreshold) { nextFireTime = getFireTimeAfter(previousFireTime); if (nextFireTime == null || calendar == null) { return; } Date now = new Date(); while (nextFireTime != 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; } if (nextFireTime != null && nextFireTime.before(now)) { long diff = now.getTime() - nextFireTime.getTime(); if (diff >= misfireThreshold) { nextFireTime = getFireTimeAfter(nextFireTime); } } } } /** *

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

*/ public Date getFireTimeBefore(Date end) { if (end.getTime() < getStartTime().getTime()) { return null; } int numFires = computeNumTimesFiredBetween(getStartTime(), end); return new Date(getStartTime().getTime() + (numFires * repeatInterval)); } public 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."); } } /** * Used by extensions of SimpleTrigger to imply that there are additional properties, specifically so that extensions can choose whether to be stored as a serialized blob, or as a flattened SimpleTrigger table. */ public boolean hasAdditionalProperties() { return false; } /** * Get a {@link ScheduleBuilder} that is configured to produce a schedule identical to this trigger's schedule. * * @see #getTriggerBuilder() */ @Override public ScheduleBuilder getScheduleBuilder() { SimpleScheduleBuilder sb = SimpleScheduleBuilder.simpleSchedule().withIntervalInMilliseconds(getRepeatInterval()).withRepeatCount(getRepeatCount()); switch (getMisfireInstruction()) { case MISFIRE_INSTRUCTION_FIRE_NOW: sb.withMisfireHandlingInstructionFireNow(); break; case MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT: sb.withMisfireHandlingInstructionNextWithExistingCount(); break; case MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT: sb.withMisfireHandlingInstructionNextWithRemainingCount(); break; case MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT: sb.withMisfireHandlingInstructionNowWithExistingCount(); break; case MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT: sb.withMisfireHandlingInstructionNowWithRemainingCount(); break; } return sb; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy