com.github.kagkarlsson.shaded.cronutils.model.definition.CronDefinitionBuilder Maven / Gradle / Ivy
Show all versions of db-scheduler Show documentation
/*
* Copyright 2014 jmrozanec
* 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.shaded.cronutils.model.definition;
import com.github.kagkarlsson.shaded.cronutils.model.CronType;
import com.github.kagkarlsson.shaded.cronutils.model.field.CronFieldName;
import com.github.kagkarlsson.shaded.cronutils.model.field.definition.*;
import java.util.*;
/**
* Builder that allows to define and create CronDefinition instances.
*/
public class CronDefinitionBuilder {
private final Map fields = new EnumMap<>(CronFieldName.class);
private final Set cronConstraints = new HashSet<>();
private final Set cronNicknames = new HashSet<>();
private boolean matchDayOfWeekAndDayOfMonth;
/**
* Constructor.
*/
private CronDefinitionBuilder() {/*NOP*/}
/**
* Creates a builder instance.
*
* @return new CronDefinitionBuilder instance
*/
public static CronDefinitionBuilder defineCron() {
return new CronDefinitionBuilder();
}
/**
* Adds definition for seconds field.
*
* @return new FieldDefinitionBuilder instance
*/
public FieldDefinitionBuilder withSeconds() {
return new FieldDefinitionBuilder(this, CronFieldName.SECOND);
}
/**
* Adds definition for minutes field.
*
* @return new FieldDefinitionBuilder instance
*/
public FieldDefinitionBuilder withMinutes() {
return new FieldDefinitionBuilder(this, CronFieldName.MINUTE);
}
/**
* Adds definition for hours field.
*
* @return new FieldDefinitionBuilder instance
*/
public FieldDefinitionBuilder withHours() {
return new FieldDefinitionBuilder(this, CronFieldName.HOUR);
}
/**
* Adds definition for day of month field.
*
* @return new FieldSpecialCharsDefinitionBuilder instance
*/
public FieldSpecialCharsDefinitionBuilder withDayOfMonth() {
return new FieldSpecialCharsDefinitionBuilder(this, CronFieldName.DAY_OF_MONTH);
}
/**
* Adds definition for month field.
*
* @return new FieldDefinitionBuilder instance
*/
public FieldDefinitionBuilder withMonth() {
return new FieldDefinitionBuilder(this, CronFieldName.MONTH);
}
/**
* Adds definition for day of week field.
*
* @return new FieldSpecialCharsDefinitionBuilder instance
*/
public FieldDayOfWeekDefinitionBuilder withDayOfWeek() {
return new FieldDayOfWeekDefinitionBuilder(this, CronFieldName.DAY_OF_WEEK);
}
/**
* Adds definition for year field.
*
* @return new FieldDefinitionBuilder instance
*/
public FieldDefinitionBuilder withYear() {
return new FieldDefinitionBuilder(this, CronFieldName.YEAR);
}
/**
* Adds definition for day of year field.
*
* @return new FieldDefinitionBuilder instance
*/
public FieldQuestionMarkDefinitionBuilder withDayOfYear() {
return new FieldQuestionMarkDefinitionBuilder(this, CronFieldName.DAY_OF_YEAR);
}
/**
* Sets matchDayOfWeekAndDayOfMonth value to true.
*
* @return this CronDefinitionBuilder instance
*/
public CronDefinitionBuilder matchDayOfWeekAndDayOfMonth() {
matchDayOfWeekAndDayOfMonth = true;
return this;
}
/**
* Supports cron nickname @yearly
*
* @return this CronDefinitionBuilder instance
*/
public CronDefinitionBuilder withSupportedNicknameYearly() {
cronNicknames.add(CronNicknames.YEARLY);
return this;
}
/**
* Supports cron nickname @annually
*
* @return this CronDefinitionBuilder instance
*/
public CronDefinitionBuilder withSupportedNicknameAnnually() {
cronNicknames.add(CronNicknames.ANNUALLY);
return this;
}
/**
* Supports cron nickname @monthly
*
* @return this CronDefinitionBuilder instance
*/
public CronDefinitionBuilder withSupportedNicknameMonthly() {
cronNicknames.add(CronNicknames.MONTHLY);
return this;
}
/**
* Supports cron nickname @weekly
*
* @return this CronDefinitionBuilder instance
*/
public CronDefinitionBuilder withSupportedNicknameWeekly() {
cronNicknames.add(CronNicknames.WEEKLY);
return this;
}
/**
* Supports cron nickname @daily
*
* @return this CronDefinitionBuilder instance
*/
public CronDefinitionBuilder withSupportedNicknameDaily() {
cronNicknames.add(CronNicknames.DAILY);
return this;
}
/**
* Supports cron nickname @midnight
*
* @return this CronDefinitionBuilder instance
*/
public CronDefinitionBuilder withSupportedNicknameMidnight() {
cronNicknames.add(CronNicknames.MIDNIGHT);
return this;
}
/**
* Supports cron nickname @hourly
*
* @return this CronDefinitionBuilder instance
*/
public CronDefinitionBuilder withSupportedNicknameHourly() {
cronNicknames.add(CronNicknames.HOURLY);
return this;
}
/**
* Supports cron nickname @reboot
*
* @return this CronDefinitionBuilder instance
*/
public CronDefinitionBuilder withSupportedNicknameReboot() {
cronNicknames.add(CronNicknames.REBOOT);
return this;
}
/**
* Adds a cron validation.
* @param validation - constraint validation
* @return this CronDefinitionBuilder instance
*/
public CronDefinitionBuilder withCronValidation(final CronConstraint validation) {
cronConstraints.add(validation);
return this;
}
/**
* Registers a certain FieldDefinition.
*
* @param definition - FieldDefinition instance, never null
*/
public void register(final FieldDefinition definition) {
//ensure that we can't register a mandatory definition if there are already optional ones
boolean hasOptionalField = false;
for (final FieldDefinition fieldDefinition : fields.values()) {
if (fieldDefinition.isOptional()) {
hasOptionalField = true;
break;
}
}
if (!definition.isOptional() && hasOptionalField) {
throw new IllegalArgumentException("Can't register mandatory definition after a optional definition.");
}
fields.put(definition.getFieldName(), definition);
}
/**
* Creates a new CronDefinition instance with provided field definitions.
*
* @return returns CronDefinition instance, never null
*/
public CronDefinition instance() {
final Set validations = new HashSet<>();
validations.addAll(cronConstraints);
final List values = new ArrayList<>(fields.values());
values.sort(FieldDefinition.createFieldDefinitionComparator());
return new CronDefinition(values, validations, cronNicknames, matchDayOfWeekAndDayOfMonth);
}
/**
* Creates CronDefinition instance matching cron4j specification.
*
* @return CronDefinition instance, never null;
*/
private static CronDefinition cron4j() {
return CronDefinitionBuilder.defineCron()
.withMinutes().withValidRange(0, 59).withStrictRange().and()
.withHours().withValidRange(0, 23).withStrictRange().and()
.withDayOfMonth().withValidRange(0, 31).supportsL().withStrictRange().and()
.withMonth().withValidRange(1, 12).withStrictRange().and()
.withDayOfWeek().withValidRange(0, 6).withMondayDoWValue(1).withStrictRange().and()
.matchDayOfWeekAndDayOfMonth()
.instance();
}
/**
* Creates CronDefinition instance matching Quartz specification.
*
* The cron expression is expected to be a string comprised of 6 or 7
* fields separated by white space. Fields can contain any of the allowed
* values, along with various combinations of the allowed special characters
* for that field. The fields are as follows:
*
*
*
* Field Name
* Mandatory
* Allowed Values
* Allowed Special Characters
*
*
* Seconds
* YES
* 0-59
* * , - /
*
*
* Minutes
* YES
* 0-59
* * , - /
*
*
* Hours
* YES
* 0-23
* * , - /
*
*
* Day of month
* YES
* 1-31
* * ? , - / L W
*
*
* Month
* YES
* 1-12 or JAN-DEC
* * , -
*
*
* Day of week
* YES
* 1-7 or SUN-SAT
* * ? , - / L #
*
*
* Year
* NO
* empty, 1970-2099
* * , - /
*
*
*
* Thus in general Quartz cron expressions are as follows:
*
*
S M H DoM M DoW [Y]
*
* @return {@link CronDefinition} instance, never {@code null}
*/
private static CronDefinition quartz() {
return CronDefinitionBuilder.defineCron()
.withSeconds().withValidRange(0, 59).and()
.withMinutes().withValidRange(0, 59).and()
.withHours().withValidRange(0, 23).and()
.withDayOfMonth().withValidRange(1, 31).supportsL().supportsW().supportsLW().supportsQuestionMark().and()
.withMonth().withValidRange(1, 12).and()
.withDayOfWeek().withValidRange(1, 7).withMondayDoWValue(2).supportsHash().supportsL().supportsQuestionMark().and()
.withYear().withValidRange(1970, 2099).withStrictRange().optional().and()
.withCronValidation(CronConstraintsFactory.ensureEitherDayOfWeekOrDayOfMonth())
.instance();
}
/**
* Creates CronDefinition instance matching Spring (v5.2 and below) specification.
*
*
The cron expression is expected to be a string comprised of 6
* fields separated by white space. Fields can contain any of the allowed
* values, along with various combinations of the allowed special characters
* for that field. The fields are as follows:
*
*
*
* Field Name
* Mandatory
* Allowed Values
* Allowed Special Characters
*
*
* Seconds
* YES
* 0-59
* * , - /
*
*
* Minutes
* YES
* 0-59
* * , - /
*
*
* Hours
* YES
* 0-23
* * , - /
*
*
* Day of month
* YES
* 1-31
* * ? , - /
*
*
* Month
* YES
* 1-12 or JAN-DEC
* * , -
*
*
* Day of week
* YES
* 0-7 or SUN-SAT
* * ? , - /
*
*
*
* Thus in general Spring cron expressions are as follows (up to version 5.2):
*
*
S M H DoM M DoW
*
* @return {@link CronDefinition} instance, never {@code null}
*/
private static CronDefinition spring() {
return CronDefinitionBuilder.defineCron()
.withSeconds().withValidRange(0, 59).withStrictRange().and()
.withMinutes().withValidRange(0, 59).withStrictRange().and()
.withHours().withValidRange(0, 23).withStrictRange().and()
.withDayOfMonth().withValidRange(1, 31).supportsQuestionMark().and()
.withMonth().withValidRange(1, 12).and()
.withDayOfWeek().withValidRange(0, 7).withMondayDoWValue(1).withIntMapping(7,0)
.supportsHash().supportsQuestionMark().and()
.instance();
}
/**
* Creates CronDefinition instance matching Spring (v5.2 onwards) specification.
* https://spring.io/blog/2020/11/10/new-in-spring-5-3-improved-cron-expressions
*
*
The cron expression is expected to be a string comprised of 6
* fields separated by white space. Fields can contain any of the allowed
* values, along with various combinations of the allowed special characters
* for that field. The fields are as follows:
*
*
*
* Field Name
* Mandatory
* Allowed Values
* Allowed Special Characters
*
*
* Seconds
* YES
* 0-59
* * , - /
*
*
* Minutes
* YES
* 0-59
* * , - /
*
*
* Hours
* YES
* 0-23
* * , - /
*
*
* Day of month
* YES
* 1-31
* * ? , - / L W
*
*
* Month
* YES
* 1-12 or JAN-DEC
* * , -
*
*
* Day of week
* YES
* 0-7 or SUN-SAT
* * ? , - / L #
*
*
*
* Thus in general Spring cron expressions are as follows (from version 5.3 onwards):
*
*
S M H DoM M DoW
*
* @return {@link CronDefinition} instance, never {@code null}
*/
private static CronDefinition spring53() {
return CronDefinitionBuilder.defineCron()
.withSeconds().withValidRange(0, 59).withStrictRange().and()
.withMinutes().withValidRange(0, 59).withStrictRange().and()
.withHours().withValidRange(0, 23).withStrictRange().and()
.withDayOfMonth().withValidRange(1, 31).supportsL().supportsW().supportsLW().supportsQuestionMark().and()
.withMonth().withValidRange(1, 12).and()
.withDayOfWeek().withValidRange(0, 7).withMondayDoWValue(1).withIntMapping(7,0)
.supportsHash().supportsL().supportsQuestionMark().and()
.withSupportedNicknameYearly().withSupportedNicknameAnnually()
.withSupportedNicknameMonthly()
.withSupportedNicknameWeekly()
.withSupportedNicknameDaily().withSupportedNicknameMidnight()
.withSupportedNicknameHourly()
.instance();
}
/**
* Creates CronDefinition instance matching unix crontab specification.
*
* @return CronDefinition instance, never null;
*/
private static CronDefinition unixCrontab() {
return CronDefinitionBuilder.defineCron()
.withMinutes().withValidRange(0, 59).withStrictRange().and()
.withHours().withValidRange(0, 23).withStrictRange().and()
.withDayOfMonth().withValidRange(1, 31).withStrictRange().and()
.withMonth().withValidRange(1, 12).withStrictRange().and()
.withDayOfWeek().withValidRange(0, 7).withMondayDoWValue(1).withIntMapping(7, 0).withStrictRange().and()
.instance();
}
/**
* Creates CronDefinition instance matching cronType specification.
*
* @param cronType - some cron type. If null, a RuntimeException will be raised.
* @return CronDefinition instance if definition is found; a RuntimeException otherwise.
*/
public static CronDefinition instanceDefinitionFor(final CronType cronType) {
switch (cronType) {
case CRON4J:
return cron4j();
case QUARTZ:
return quartz();
case UNIX:
return unixCrontab();
case SPRING:
return spring();
case SPRING53:
return spring53();
default:
throw new IllegalArgumentException(String.format("No cron definition found for %s", cronType));
}
}
}