com.github.kagkarlsson.scheduler.task.schedule.CronSchedule Maven / Gradle / Ivy
Show all versions of db-scheduler Show documentation
/*
* Copyright (C) Gustav Karlsson
*
* 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 com.github.kagkarlsson.scheduler.task.schedule;
import com.github.kagkarlsson.shaded.cronutils.model.Cron;
import com.github.kagkarlsson.shaded.cronutils.model.CronType;
import com.github.kagkarlsson.shaded.cronutils.model.definition.CronDefinitionBuilder;
import com.github.kagkarlsson.shaded.cronutils.model.time.ExecutionTime;
import com.github.kagkarlsson.shaded.cronutils.parser.CronParser;
import com.github.kagkarlsson.scheduler.task.ExecutionComplete;
import java.io.Serializable;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** Spring-style cron-pattern schedule */
public class CronSchedule implements Schedule, Serializable {
private static final long serialVersionUID = 1L;
private static final String DISABLED = "-";
private static final Logger LOG = LoggerFactory.getLogger(CronSchedule.class);
private final String pattern;
private final ZoneId zoneId;
private final CronStyle cronStyle;
private transient ExecutionTime cronExecutionTime; // lazily initialized
private CronSchedule() { // For serializers
pattern = null;
zoneId = ZoneId.systemDefault();
cronStyle = CronStyle.SPRING53;
}
public CronSchedule(String pattern) {
this(pattern, ZoneId.systemDefault());
}
public CronSchedule(String pattern, ZoneId zoneId) {
this(pattern, zoneId, CronStyle.SPRING53);
}
public CronSchedule(String pattern, ZoneId zoneId, CronStyle cronStyle) {
this.pattern = pattern;
this.cronStyle = cronStyle != null ? cronStyle : CronStyle.SPRING53;
if (zoneId == null) {
throw new IllegalArgumentException("zoneId may not be null");
}
this.zoneId = zoneId;
lazyInitExecutionTime();
}
@Override
public Instant getNextExecutionTime(ExecutionComplete executionComplete) {
lazyInitExecutionTime(); // for deserialized objects
ZonedDateTime lastDone =
ZonedDateTime.ofInstant(
executionComplete.getTimeDone(),
zoneId); // frame the 'last done' time in the context of the time zone for this schedule
// so that expressions like "0 05 13,20 * * ?" (New York) can operate in the
// context of the desired time zone
Optional nextTime = cronExecutionTime.nextExecution(lastDone);
if (!nextTime.isPresent()) {
LOG.error(
"Cron-pattern did not return any further execution-times. This behavior is currently not supported by the scheduler. Setting next execution-time to far-future.");
return Instant.now().plus(1000, ChronoUnit.YEARS);
}
return nextTime.get().toInstant();
}
private void lazyInitExecutionTime() {
if (cronExecutionTime != null) {
return;
}
synchronized (this) {
if (cronExecutionTime == null) {
if (isDisabled()) {
cronExecutionTime = new CronSchedule.DisabledScheduleExecutionTime();
} else {
CronParser parser =
new CronParser(
CronDefinitionBuilder.instanceDefinitionFor(
cronStyle == null
? getCronType(CronStyle.SPRING53)
: getCronType(cronStyle)));
Cron cron = parser.parse(pattern);
cronExecutionTime = ExecutionTime.forCron(cron);
}
}
}
}
private CronType getCronType(CronStyle cronStyle) {
switch (cronStyle) {
case CRON4J:
return CronType.CRON4J;
case QUARTZ:
return CronType.QUARTZ;
case UNIX:
return CronType.UNIX;
case SPRING:
return CronType.SPRING;
case SPRING53:
return CronType.SPRING53;
default:
throw new IllegalArgumentException(
String.format("No cron definition found for %s", this.cronStyle));
}
}
@Override
public boolean isDeterministic() {
return true;
}
@Override
public String toString() {
return "CronSchedule pattern=" + pattern + ", cronStyle=" + cronStyle + ", zone=" + zoneId;
}
public String getPattern() {
return pattern;
}
public ZoneId getZoneId() {
return zoneId;
}
private static class DisabledScheduleExecutionTime implements ExecutionTime {
@Override
public Optional nextExecution(ZonedDateTime date) {
throw unsupportedException();
}
@Override
public Optional timeToNextExecution(ZonedDateTime date) {
throw unsupportedException();
}
@Override
public Optional lastExecution(ZonedDateTime date) {
throw unsupportedException();
}
@Override
public Optional timeFromLastExecution(ZonedDateTime date) {
throw unsupportedException();
}
@Override
public boolean isMatch(ZonedDateTime date) {
throw unsupportedException();
}
private UnsupportedOperationException unsupportedException() {
return new UnsupportedOperationException(
"Schedule is marked as disabled. Method should never be called");
}
}
@Override
public boolean isDisabled() {
return DISABLED.equals(pattern);
}
}