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.5.0-rc1
Show newest version

/* 
 * 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.impl.triggers;

import java.util.Date;

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


/**
 * 

* 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, CoreTrigger { /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * 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 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) { this(name, (String)null); } /** *

* 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() */ 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() */ 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. *

*/ 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_IGNORE_MISFIRE_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. *
  • *
*/ @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.impl.triggers.AbstractTrigger#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(org.quartz.spi.OperableTrigger, org.quartz.Calendar, java.util.Date, java.util.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. *

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

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