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

org.quartz.Trigger Maven / Gradle / Ivy


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

import java.util.Date;
import java.util.LinkedList;

import org.quartz.utils.Key;


/**
 * 

* The base abstract class to be extended by all Triggers. *

* *

* Triggers s have a name and group associated with them, which * should uniquely identify them within a single {@link Scheduler}. *

* *

* Triggers are the 'mechanism' by which Job s * are scheduled. Many Trigger s can point to the same Job, * but a single Trigger can only point to one Job. *

* *

* Triggers can 'send' parameters/data to Jobs by placing contents * into the JobDataMap on the Trigger. *

* * @see SimpleTrigger * @see CronTrigger * @see NthIncludedDayTrigger * @see TriggerUtils * @see JobDataMap * @see JobExecutionContext * * @author James House * @author Sharada Jambula */ public abstract class Trigger implements java.io.Serializable, Cloneable, Comparable { private static final long serialVersionUID = -3904243490805975570L; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Constants. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /** *

* Instructs the {@link Scheduler} that the {@link Trigger} * has no further instructions. *

*/ public static final int INSTRUCTION_NOOP = 0; /** *

* Instructs the {@link Scheduler} that the {@link Trigger} * wants the {@link org.quartz.JobDetail} to re-execute * immediately. If not in a 'RECOVERING' or 'FAILED_OVER' situation, the * execution context will be re-used (giving the Job the * ability to 'see' anything placed in the context by its last execution). *

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

* Instructs the {@link Scheduler} that the {@link Trigger} * should be put in the COMPLETE state. *

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

* Instructs the {@link Scheduler} that the {@link Trigger} * wants itself deleted. *

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

* Instructs the {@link Scheduler} that all Trigger * s referencing the same {@link org.quartz.JobDetail} as * this one should be put in the COMPLETE state. *

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

* Instructs the {@link Scheduler} that all Trigger * s referencing the same {@link org.quartz.JobDetail} as * this one should be put in the ERROR state. *

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

* Instructs the {@link Scheduler} that the Trigger * should be put in the ERROR state. *

*/ public static final int INSTRUCTION_SET_ALL_JOB_TRIGGERS_ERROR = 6; /** *

* Instructs the {@link Scheduler} that upon a mis-fire * situation, the updateAfterMisfire() method will be called * on the Trigger to determine the mis-fire instruction. *

* *

* In order to see if this instruction fits your needs, you should look at * the documentation for the getSmartMisfirePolicy() method * on the particular Trigger implementation you are using. *

*/ public static final int MISFIRE_INSTRUCTION_SMART_POLICY = 0; /** *

* Indicates that the Trigger is in the "normal" state. *

*/ public static final int STATE_NORMAL = 0; /** *

* Indicates that the Trigger is in the "paused" state. *

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

* Indicates that the Trigger is in the "complete" state. *

* *

* "Complete" indicates that the trigger has not remaining fire-times in * its schedule. *

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

* Indicates that the Trigger is in the "error" state. *

* *

* A Trigger arrives at the error state when the scheduler * attempts to fire it, but cannot due to an error creating and executing * its related job. Often this is due to the Job's * class not existing in the classpath. *

* *

* When the trigger is in the error state, the scheduler will make no * attempts to fire it. *

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

* Indicates that the Trigger is in the "blocked" state. *

* *

* A Trigger arrives at the blocked state when the job that * it is associated with is a StatefulJob and it is * currently executing. *

* * @see StatefulJob */ public static final int STATE_BLOCKED = 4; /** *

* Indicates that the Trigger does not exist. *

*/ public static final int STATE_NONE = -1; /** * The default value for priority. */ public static final int DEFAULT_PRIORITY = 5; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Data members. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ private String name; private String group = Scheduler.DEFAULT_GROUP; private String jobName; private String jobGroup = Scheduler.DEFAULT_GROUP; private String description; private JobDataMap jobDataMap; private boolean volatility = false; private String calendarName = null; private String fireInstanceId = null; private int misfireInstruction = MISFIRE_INSTRUCTION_SMART_POLICY; private LinkedList triggerListeners = new LinkedList(); private int priority = DEFAULT_PRIORITY; private transient Key key = null; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Constructors. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /** *

* Create a Trigger with no specified name, group, or {@link org.quartz.JobDetail}. *

* *

* Note that the {@link #setName(String)},{@link #setGroup(String)}and * the {@link #setJobName(String)}and {@link #setJobGroup(String)}methods * must be called before the Trigger can be placed into a * {@link Scheduler}. *

*/ public Trigger() { // do nothing... } /** *

* Create a Trigger with the given name, and default group. *

* *

* Note that the {@link #setJobName(String)}and * {@link #setJobGroup(String)}methods must be called before the Trigger * can be placed into a {@link Scheduler}. *

* * @param group if null, Scheduler.DEFAULT_GROUP will be used. * * @exception IllegalArgumentException * if name is null or empty, or the group is an empty string. */ public Trigger(String name) { setName(name); setGroup(null); } /** *

* Create a Trigger with the given name, and group. *

* *

* Note that the {@link #setJobName(String)}and * {@link #setJobGroup(String)}methods must be called before the Trigger * can be placed into a {@link Scheduler}. *

* * @param group if null, Scheduler.DEFAULT_GROUP will be used. * * @exception IllegalArgumentException * if name is null or empty, or the group is an empty string. */ public Trigger(String name, String group) { setName(name); setGroup(group); } /** *

* Create a Trigger with the given name, and group. *

* * @param group if null, Scheduler.DEFAULT_GROUP will be used. * * @exception IllegalArgumentException * if name is null or empty, or the group is an empty string. */ public Trigger(String name, String group, String jobName, String jobGroup) { setName(name); setGroup(group); setJobName(jobName); setJobGroup(jobGroup); } /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Interface. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /** *

* Get the name of this Trigger. *

*/ public String getName() { return name; } /** *

* Set the name of this Trigger. *

* * @exception IllegalArgumentException * if name is null or empty. */ public void setName(String name) { if (name == null || name.trim().length() == 0) { throw new IllegalArgumentException( "Trigger name cannot be null or empty."); } this.name = name; } /** *

* Get the group of this Trigger. *

*/ public String getGroup() { return group; } /** *

* Set the name of this Trigger. *

* * @param group if null, Scheduler.DEFAULT_GROUP will be used. * * @exception IllegalArgumentException * if group is an empty string. */ public void setGroup(String group) { if (group != null && group.trim().length() == 0) { throw new IllegalArgumentException( "Group name cannot be an empty string."); } if(group == null) { group = Scheduler.DEFAULT_GROUP; } this.group = group; } /** *

* Get the name of the associated {@link org.quartz.JobDetail}. *

*/ public String getJobName() { return jobName; } /** *

* Set the name of the associated {@link org.quartz.JobDetail}. *

* * @exception IllegalArgumentException * if jobName is null or empty. */ public void setJobName(String jobName) { if (jobName == null || jobName.trim().length() == 0) { throw new IllegalArgumentException( "Job name cannot be null or empty."); } this.jobName = jobName; } /** *

* Get the name of the associated {@link org.quartz.JobDetail}'s * group. *

*/ public String getJobGroup() { return jobGroup; } /** *

* Set the name of the associated {@link org.quartz.JobDetail}'s * group. *

* * @param jobGroup if null, Scheduler.DEFAULT_GROUP will be used. * * @exception IllegalArgumentException * if group is an empty string. */ public void setJobGroup(String jobGroup) { if (jobGroup != null && jobGroup.trim().length() == 0) { throw new IllegalArgumentException( "Group name cannot be null or empty."); } if(jobGroup == null) { jobGroup = Scheduler.DEFAULT_GROUP; } this.jobGroup = jobGroup; } /** *

* Returns the 'full name' of the Trigger in the format * "group.name". *

*/ public String getFullName() { return group + "." + name; } public Key getKey() { if(key == null) { key = new Key(getName(), getGroup()); } return key; } /** *

* Returns the 'full name' of the Job that the Trigger * points to, in the format "group.name". *

*/ public String getFullJobName() { return jobGroup + "." + jobName; } /** *

* Return the description given to the Trigger instance by * its creator (if any). *

* * @return null if no description was set. */ public String getDescription() { return description; } /** *

* Set a description for the Trigger instance - may be * useful for remembering/displaying the purpose of the trigger, though the * description has no meaning to Quartz. *

*/ public void setDescription(String description) { this.description = description; } /** *

* Set whether or not the Trigger should be persisted in the * {@link org.quartz.spi.JobStore} for re-use after program * restarts. *

*/ public void setVolatility(boolean volatility) { this.volatility = volatility; } /** *

* Associate the {@link Calendar} with the given name with * this Trigger. *

* * @param calendarName * use null to dis-associate a Calendar. */ public void setCalendarName(String calendarName) { this.calendarName = calendarName; } /** *

* Get the name of the {@link Calendar} associated with this * Trigger. *

* * @return null if there is no associated Calendar. */ public String getCalendarName() { return calendarName; } /** *

* Get the JobDataMap that is associated with the * Trigger. *

* *

* Changes made to this map during job execution are not re-persisted, and * in fact typically result in an IllegalStateException. *

*/ public JobDataMap getJobDataMap() { if (jobDataMap == null) { jobDataMap = new JobDataMap(); } return jobDataMap; } /** *

* Set the JobDataMap to be associated with the * Trigger. *

*/ public void setJobDataMap(JobDataMap jobDataMap) { this.jobDataMap = jobDataMap; } /** *

* Whether or not the Trigger should be persisted in the * {@link org.quartz.spi.JobStore} for re-use after program * restarts. *

* *

* If not explicitly set, the default value is false. *

* * @return true if the Trigger should be * garbage collected along with the {@link Scheduler}. */ public boolean isVolatile() { return volatility; } /** * The priority of a Trigger acts as a tiebreaker such that if * two Triggers have the same scheduled fire time, then the * one with the higher priority will get first access to a worker * thread. * *

* If not explicitly set, the default value is 5. *

* * @see #DEFAULT_PRIORITY */ public int getPriority() { return priority; } /** * The priority of a Trigger acts as a tie breaker such that if * two Triggers have the same scheduled fire time, then Quartz * will do its best to give the one with the higher priority first access * to a worker thread. * *

* If not explicitly set, the default value is 5. *

* * @see #DEFAULT_PRIORITY */ public void setPriority(int priority) { this.priority = priority; } /** *

* Add the specified name of a {@link TriggerListener} to * the end of the Trigger's list of listeners. *

*/ public void addTriggerListener(String name) { if (triggerListeners.contains(name)) { throw new IllegalArgumentException( "Trigger listener '" + name + "' is already registered for trigger: " + getFullName()); } triggerListeners.add(name); } /** *

* Remove the specified name of a {@link TriggerListener} * from the Trigger's list of listeners. *

* * @return true if the given name was found in the list, and removed */ public boolean removeTriggerListener(String name) { return triggerListeners.remove(name); } /** *

* Returns an array of String containing the names of all * {@link TriggerListener}s assigned to the Trigger, * in the order in which they should be notified. *

*/ public String[] getTriggerListenerNames() { return (String[])triggerListeners.toArray(new String[triggerListeners.size()]); } /** * Remove all {@link TriggerListener}s from the Trigger. */ public void clearAllTriggerListeners() { triggerListeners.clear(); } /** *

* This method should not be used by the Quartz client. *

* *

* 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 abstract void triggered(Calendar calendar); /** *

* This method should not be used by the Quartz client. *

* *

* 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 abstract Date computeFirstFireTime(Calendar calendar); /** *

* This method should not be used by the Quartz client. *

* *

* 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 abstract int executionComplete(JobExecutionContext context, JobExecutionException result); /** *

* Used by the {@link Scheduler} to determine whether or not * it is possible for this Trigger to fire again. *

* *

* If the returned value is false then the Scheduler * may remove the Trigger from the {@link org.quartz.spi.JobStore}. *

*/ public abstract boolean mayFireAgain(); /** *

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

*/ public abstract Date getStartTime(); /** *

* The time at which the trigger's scheduling should start. May or may not * be the first actual fire time of the trigger, depending upon the type of * trigger and the settings of the other properties of the trigger. However * the first actual first time will not be before this date. *

*

* Setting a value in the past may cause a new trigger to compute a first * fire time that is in the past, which may cause an immediate misfire * of the trigger. *

*/ public abstract void setStartTime(Date startTime); /** *

* Set the time at which the Trigger should quit repeating - * regardless of any remaining repeats (based on the trigger's particular * repeat settings). *

* * @see TriggerUtils#computeEndTimeToAllowParticularNumberOfFirings(Trigger, Calendar, int) */ public abstract void setEndTime(Date endTime); /** *

* Get the time at which the Trigger should quit repeating - * regardless of any remaining repeats (based on the trigger's particular * repeat settings). *

* * @see #getFinalFireTime() */ public abstract Date getEndTime(); /** *

* 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) */ public abstract Date getNextFireTime(); /** *

* Returns the previous time at which the Trigger fired. * If the trigger has not yet fired, null will be returned. */ public abstract Date getPreviousFireTime(); /** *

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

*/ public abstract Date getFireTimeAfter(Date afterTime); /** *

* Returns the last time at which the Trigger will fire, if * the Trigger will repeat indefinitely, null will be returned. *

* *

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

*/ public abstract Date getFinalFireTime(); /** *

* Set the instruction the Scheduler should be given for * handling misfire situations for this Trigger- the * concrete Trigger type that you are using will have * defined a set of additional MISFIRE_INSTRUCTION_XXX * constants that may be passed to this method. *

* *

* If not explicitly set, the default value is MISFIRE_INSTRUCTION_SMART_POLICY. *

* * @see #MISFIRE_INSTRUCTION_SMART_POLICY * @see #updateAfterMisfire(Calendar) * @see SimpleTrigger * @see CronTrigger */ public void setMisfireInstruction(int misfireInstruction) { if (!validateMisfireInstruction(misfireInstruction)) { throw new IllegalArgumentException( "The misfire instruction code is invalid for this type of trigger."); } this.misfireInstruction = misfireInstruction; } protected abstract boolean validateMisfireInstruction(int misfireInstruction); /** *

* Get the instruction the Scheduler should be given for * handling misfire situations for this Trigger- the * concrete Trigger type that you are using will have * defined a set of additional MISFIRE_INSTRUCTION_XXX * constants that may be passed to this method. *

* *

* If not explicitly set, the default value is MISFIRE_INSTRUCTION_SMART_POLICY. *

* * @see #MISFIRE_INSTRUCTION_SMART_POLICY * @see #updateAfterMisfire(Calendar) * @see SimpleTrigger * @see CronTrigger */ public int getMisfireInstruction() { return misfireInstruction; } /** *

* This method should not be used by the Quartz client. *

* *

* To be implemented by the concrete classes that extend this class. *

* *

* The implementation should update the Trigger's state * based on the MISFIRE_INSTRUCTION_XXX that was selected when the Trigger * was created. *

*/ public abstract void updateAfterMisfire(Calendar cal); /** *

* This method should not be used by the Quartz client. *

* *

* To be implemented by the concrete class. *

* *

* The implementation should update the Trigger's state * based on the given new version of the associated Calendar * (the state should be updated so that it's next fire time is appropriate * given the Calendar's new settings). *

* * @param cal */ public abstract void updateWithNewCalendar(Calendar cal, long misfireThreshold); /** *

* 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 { if (name == null) { throw new SchedulerException("Trigger's name cannot be null", SchedulerException.ERR_CLIENT_ERROR); } if (group == null) { throw new SchedulerException("Trigger's group cannot be null", SchedulerException.ERR_CLIENT_ERROR); } if (jobName == null) { throw new SchedulerException( "Trigger's related Job's name cannot be null", SchedulerException.ERR_CLIENT_ERROR); } if (jobGroup == null) { throw new SchedulerException( "Trigger's related Job's group cannot be null", SchedulerException.ERR_CLIENT_ERROR); } } /** *

* This method should not be used by the Quartz client. *

* *

* Usable by {@link org.quartz.spi.JobStore} * implementations, in order to facilitate 'recognizing' instances of fired * Trigger s as their jobs complete execution. *

* * */ public void setFireInstanceId(String id) { this.fireInstanceId = id; } /** *

* This method should not be used by the Quartz client. *

*/ public String getFireInstanceId() { return fireInstanceId; } /** *

* Return a simple string representation of this object. *

*/ public String toString() { return "Trigger '" + getFullName() + "': triggerClass: '" + getClass().getName() + " isVolatile: " + isVolatile() + " calendar: '" + getCalendarName() + "' misfireInstruction: " + getMisfireInstruction() + " nextFireTime: " + getNextFireTime(); } /** *

* Compare the next fire time of this Trigger to that of * another. *

*/ public int compareTo(Object obj) { Trigger other = (Trigger) obj; Date myTime = getNextFireTime(); Date otherTime = other.getNextFireTime(); if (myTime == null && otherTime == null) { return 0; } if (myTime == null) { return 1; } if (otherTime == null) { return -1; } if(myTime.before(otherTime)) { return -1; } if(myTime.after(otherTime)) { return 1; } return 0; } public boolean equals(Object obj) { if (!(obj instanceof Trigger)) { return false; } Trigger other = (Trigger) obj; if (other.getName() == null && getName() != null) { return false; } if (other.getName() != null && !other.getName().equals(getName())) { return false; } if (other.getGroup() == null && getGroup() != null) { return false; } if (other.getGroup() != null && !other.getGroup().equals(getGroup())) { return false; } return true; } public int hashCode() { return getFullName().hashCode(); } public Object clone() { Trigger copy; try { copy = (Trigger) super.clone(); copy.triggerListeners = (LinkedList)triggerListeners.clone(); // Shallow copy the jobDataMap. Note that this means that if a user // modifies a value object in this map from the cloned Trigger // they will also be modifying this Trigger. if (jobDataMap != null) { copy.jobDataMap = (JobDataMap)jobDataMap.clone(); } } catch (CloneNotSupportedException ex) { throw new IncompatibleClassChangeError("Not Cloneable."); } return copy; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy