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

org.quartz.SimpleTrigger Maven / Gradle / Ivy

Go to download

SDK for dev_appserver (local development) with some of the dependencies shaded (repackaged)

There is a newer version: 2.0.31
Show newest version

/* 
 * Copyright 2004-2005 OpenSymphony 
 * 
 * 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.
 * 
 */

/*
 * Previously Copyright (c) 2001-2004 James House
 */
package org.quartz;

import java.util.Date;


/**
 * 

* 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 SimpleTrigger extends Trigger { /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Constants. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /** *

* Instructs the {@link Scheduler} that upon a mis-fire * situation, the {@link SimpleTrigger} wants to be fired * now by Scheduler. *

* *

* NOTE: This instruction should typically only be used for * 'one-shot' (non-repeating) Triggers. If it is used on a trigger with a * repeat count > 0 then it is equivalent to the instruction {@link #MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT} * . *

*/ public static final int MISFIRE_INSTRUCTION_FIRE_NOW = 1; /** *

* Instructs the {@link Scheduler} that upon a mis-fire * situation, the {@link SimpleTrigger} wants to be * re-scheduled to 'now' (even if the associated {@link Calendar} * excludes 'now') with the repeat count left as-is. *

* *

* NOTE: Use of this instruction causes the trigger to 'forget' * the start-time and repeat-count that it was originally setup with (this * is only an issue if you for some reason wanted to be able to tell what * the original values were at some later time). *

* *

* NOTE: This instruction could cause the Trigger * to go to the 'COMPLETE' state after firing 'now', if all the * repeat-fire-times where missed. *

*/ public static final int MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT = 2; /** *

* Instructs the {@link Scheduler} that upon a mis-fire * situation, the {@link SimpleTrigger} wants to be * re-scheduled to 'now' (even if the associated {@link Calendar} * excludes 'now') with the repeat count set to what it would be, if it had * not missed any firings. *

* *

* NOTE: Use of this instruction causes the trigger to 'forget' * the start-time and repeat-count that it was originally setup with (this * is only an issue if you for some reason wanted to be able to tell what * the original values were at some later time). *

* *

* NOTE: This instruction could cause the Trigger * to go to the 'COMPLETE' state after firing 'now', if all the * repeat-fire-times where missed. *

*/ public static final int MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT = 3; /** *

* Instructs the {@link Scheduler} that upon a mis-fire * situation, the {@link SimpleTrigger} wants to be * re-scheduled to the next scheduled time after 'now' - taking into * account any associated {@link Calendar}, and with the * repeat count set to what it would be, if it had not missed any firings. *

* *

* NOTE/WARNING: This instruction could cause the Trigger * to go directly to the 'COMPLETE' state if all fire-times where missed. *

*/ public static final int MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT = 4; /** *

* Instructs the {@link Scheduler} that upon a mis-fire * situation, the {@link SimpleTrigger} wants to be * re-scheduled to the next scheduled time after 'now' - taking into * account any associated {@link Calendar}, and with the * repeat count left unchanged. *

* *

* NOTE: Use of this instruction causes the trigger to 'forget' * the repeat-count that it was originally setup with (this is only an * issue if you for some reason wanted to be able to tell what the original * values were at some later time). *

* *

* NOTE/WARNING: This instruction could cause the Trigger * to go directly to the 'COMPLETE' state if all fire-times where missed. *

*/ public static final int MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT = 5; /** *

* Used to indicate the 'repeat count' of the trigger is indefinite. Or in * other words, the trigger should repeat continually until the trigger's * ending timestamp. *

*/ public static int REPEAT_INDEFINITELY = -1; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * 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 SimpleTrigger() { super(); } /** *

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

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

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

*/ public SimpleTrigger(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 unlimitted times. * @param repeatInterval * The number of milliseconds to pause between the repeat firing. */ public SimpleTrigger(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. */ public SimpleTrigger(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. *

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

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

* * @exception IllegalArgumentException * if startTime is null. */ 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() */ 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. */ 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; } /** *

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

* * @see #REPEAT_INDEFINITELY */ 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; } /** *

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

*/ 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; } 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. *
  • *
*

*/ public void updateAfterMisfire(Calendar cal) { int instr = getMisfireInstruction(); 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); } 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) { 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); } 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)) setEndTime(new Date(newFireTime.getTime() + 50)); 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) */ public void triggered(Calendar calendar) { timesTriggered++; previousFireTime = nextFireTime; nextFireTime = getFireTimeAfter(nextFireTime); while (nextFireTime != null && calendar != null && !calendar.isTimeIncluded(nextFireTime.getTime())) { nextFireTime = getFireTimeAfter(nextFireTime); } } /** * * @see org.quartz.Trigger#updateWithNewCalendar(org.quartz.Calendar, long) */ public void updateWithNewCalendar(Calendar calendar, long misfireThreshold) { nextFireTime = getFireTimeAfter(previousFireTime); Date now = new Date(); do { while (nextFireTime != null && calendar != null && !calendar.isTimeIncluded(nextFireTime.getTime())) { nextFireTime = getFireTimeAfter(nextFireTime); } if(nextFireTime != null && nextFireTime.before(now)) { long diff = now.getTime() - nextFireTime.getTime(); if(diff >= misfireThreshold) { nextFireTime = getFireTimeAfter(nextFireTime); continue; } } }while(false); } /** *

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

*/ public Date computeFirstFireTime(Calendar calendar) { nextFireTime = getStartTime(); while (nextFireTime != null && calendar != null && !calendar.isTimeIncluded(nextFireTime.getTime())) { nextFireTime = getFireTimeAfter(nextFireTime); } return nextFireTime; } /** *

* Called after the {@link Scheduler} has executed the * {@link org.quartz.JobDetail} associated with the Trigger * in order to get the final instruction code from the trigger. *

* * @param context * is the JobExecutionContext that was used by the * Job'sexecute(xx) method. * @param result * is the JobExecutionException thrown by the * Job, if any (may be null). * @return one of the Trigger.INSTRUCTION_XXX constants. * * @see #INSTRUCTION_NOOP * @see #INSTRUCTION_RE_EXECUTE_JOB * @see #INSTRUCTION_DELETE_TRIGGER * @see #INSTRUCTION_SET_TRIGGER_COMPLETE * @see #triggered(Calendar) */ public int executionComplete(JobExecutionContext context, JobExecutionException result) { if (result != null && result.refireImmediately()) return INSTRUCTION_RE_EXECUTE_JOB; if (result != null && result.unscheduleFiringTrigger()) return INSTRUCTION_SET_TRIGGER_COMPLETE; if (result != null && result.unscheduleAllTriggers()) return INSTRUCTION_SET_ALL_JOB_TRIGGERS_COMPLETE; if (!mayFireAgain()) return INSTRUCTION_DELETE_TRIGGER; return INSTRUCTION_NOOP; } /** *

* Returns the next time at which the SimpleTrigger will * fire. If the trigger will not fire again, null will be * returned. The value returned is not guaranteed to be valid until after * the Trigger has been added to the scheduler. *

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

* Returns the previous time at which the SimpleTrigger will * fire. If the trigger has not yet fired, null will be * returned. */ 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. *

*/ 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 (startMillis < afterMillis && repeatCount == 0) return null; if (afterMillis < startMillis) return new Date(startMillis); long numberoftimesexecutedplusone = ((afterMillis - startMillis) / repeatInterval) + 1; if ((numberoftimesexecutedplusone > repeatCount) && (repeatCount != REPEAT_INDEFINITELY)) return null; Date time = new Date((numberoftimesexecutedplusone * repeatInterval) + startMillis); 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) { 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. *

*/ public Date getFinalFireTime() { if (repeatCount == 0) return startTime; if (repeatCount == REPEAT_INDEFINITELY && getEndTime() == null) return null; if (repeatCount == REPEAT_INDEFINITELY && getEndTime() == null) return null; else if (repeatCount == REPEAT_INDEFINITELY) return 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. *

*/ 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. */ public void validate() throws SchedulerException { super.validate(); if (repeatCount != 0 && repeatInterval < 1) throw new SchedulerException("Repeat Interval cannot be zero.", SchedulerException.ERR_CLIENT_ERROR); } public static void main(String[] args) // TODO: remove method after good // unit testing throws Exception { Date sdt = new Date(); Date edt = new Date(sdt.getTime() + 55000L); SimpleTrigger st = new SimpleTrigger("t", "g", "j", "g", sdt, edt, 10, 10000L); System.err.println(); st.computeFirstFireTime(null); System.err.println("lastTime=" + st.getFinalFireTime()); java.util.List times = TriggerUtils.computeFireTimes(st, null, 50); for (int i = 0; i < times.size(); i++) { System.err.println("firetime = " + times.get(i)); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy