org.quartz.impl.triggers.SimpleTriggerImpl Maven / Gradle / Ivy
Show all versions of sundial Show documentation
/*
* 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;
}
}