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

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

There is a newer version: 2.5.0
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.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.ScheduleBuilder;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.TriggerUtils;
import org.quartz.spi.OperableTrigger;


/**
 * 

* 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 AbstractTrigger implements OperableTrigger { private static final long serialVersionUID = -3904243490805975570L; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * 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; // still here for serialization backward compatibility private String calendarName = null; private String fireInstanceId = null; private int misfireInstruction = MISFIRE_INSTRUCTION_SMART_POLICY; private int priority = DEFAULT_PRIORITY; private transient TriggerKey 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 AbstractTrigger() { // 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 AbstractTrigger(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 AbstractTrigger(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 AbstractTrigger(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; this.key = null; } /** *

* 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; this.key = null; } public void setKey(TriggerKey key) { setName(key.getName()); setGroup(key.getGroup()); this.key = key; } /** *

* 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; } public void setJobKey(JobKey key) { setJobName(key.getName()); setJobGroup(key.getGroup()); } /** *

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

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

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

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

* 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 CompletedExecutionInstruction constants. * * @see CompletedExecutionInstruction * @see #triggered(Calendar) */ public CompletedExecutionInstruction executionComplete(JobExecutionContext context, JobExecutionException result) { if (result != null && result.refireImmediately()) { return CompletedExecutionInstruction.RE_EXECUTE_JOB; } if (result != null && result.unscheduleFiringTrigger()) { return CompletedExecutionInstruction.SET_TRIGGER_COMPLETE; } if (result != null && result.unscheduleAllTriggers()) { return CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_COMPLETE; } if (!mayFireAgain()) { return CompletedExecutionInstruction.DELETE_TRIGGER; } return CompletedExecutionInstruction.NOOP; } /** *

* 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(AbstractTrigger, 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(AbstractTrigger, 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 candidateMisfireInstruction); /** *

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

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

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

* Compare the next fire time of this Trigger to that of * another by comparing their keys, or in other words, sorts them * according to the natural (i.e. alphabetical) order of their keys. *

*/ public int compareTo(Trigger other) { if(other.getKey() == null && getKey() == null) return 0; if(other.getKey() == null) return -1; if(getKey() == null) return 1; return getKey().compareTo(other.getKey()); } /** * Trigger equality is based upon the equality of the TriggerKey. * * @return true if the key of this Trigger equals that of the given Trigger. */ @Override public boolean equals(Object o) { if(!(o instanceof Trigger)) return false; Trigger other = (Trigger)o; if (other.getKey() == null || getKey() == null) { return false; } return getKey().equals(other.getKey()); } @Override public int hashCode() { if(getKey() == null) return super.hashCode(); return getKey().hashCode(); } @Override public Object clone() { AbstractTrigger copy; try { copy = (AbstractTrigger) super.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; } public TriggerBuilder getTriggerBuilder() { TriggerBuilder b = TriggerBuilder.newTrigger() .forJob(getJobKey()) .modifiedByCalendar(getCalendarName()) .usingJobData(getJobDataMap()) .withDescription(getDescription()) .endAt(getEndTime()) .withIdentity(getKey()) .withPriority(getPriority()) .startAt(getStartTime()) .withSchedule(getScheduleBuilder()); return b; } public abstract ScheduleBuilder getScheduleBuilder(); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy