com.github.kagkarlsson.shaded.cronutils.parser.CronParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of db-scheduler Show documentation
Show all versions of db-scheduler Show documentation
Simple persistent scheduler for scheduled tasks, recurring or ad-hoc.
The newest version!
/*
* 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.parser;
import com.github.kagkarlsson.shaded.cronutils.builder.CronBuilder;
import com.github.kagkarlsson.shaded.cronutils.model.CompositeCron;
import com.github.kagkarlsson.shaded.cronutils.model.Cron;
import com.github.kagkarlsson.shaded.cronutils.model.SingleCron;
import com.github.kagkarlsson.shaded.cronutils.model.definition.CronDefinition;
import com.github.kagkarlsson.shaded.cronutils.model.definition.CronNicknames;
import com.github.kagkarlsson.shaded.cronutils.model.field.CronField;
import com.github.kagkarlsson.shaded.cronutils.model.field.definition.FieldDefinition;
import com.github.kagkarlsson.shaded.cronutils.utils.Preconditions;
import com.github.kagkarlsson.shaded.cronutils.utils.StringUtils;
import java.util.*;
import java.util.stream.Collectors;
/**
* Parser for cron expressions.
* The class is thread safe.
*/
public class CronParser {
private final Map> expressions = new HashMap<>();
private final CronDefinition cronDefinition;
/**
* @param cronDefinition - cronDefinition of cron expressions to be parsed if null, a NullPointerException will be raised.
*/
public CronParser(final CronDefinition cronDefinition) {
this.cronDefinition = Preconditions.checkNotNull(cronDefinition, "CronDefinition must not be null");
buildPossibleExpressions(cronDefinition);
}
/**
* Build possible cron expressions from definitions. One is built for sure. A second one may be build if last field is optional.
*
* @param cronDefinition - cron definition instance
*/
private void buildPossibleExpressions(final CronDefinition cronDefinition) {
final List sortedExpression = cronDefinition.getFieldDefinitions().stream()
.map(this::toCronParserField)
.sorted(CronParserField.createFieldTypeComparator())
.collect(Collectors.toList());
List tempExpression = sortedExpression;
while(lastFieldIsOptional(tempExpression)) {
int expressionLength = tempExpression.size() - 1;
ArrayList possibleExpression = new ArrayList<>(tempExpression.subList(0, expressionLength));
expressions.put(expressionLength, possibleExpression);
tempExpression = possibleExpression;
}
expressions.put(sortedExpression.size(), sortedExpression);
}
private CronParserField toCronParserField(final FieldDefinition fieldDefinition) {
return new CronParserField(fieldDefinition.getFieldName(), fieldDefinition.getConstraints(), fieldDefinition.isOptional());
}
private boolean lastFieldIsOptional(final List fields) {
return !fields.isEmpty() && fields.get(fields.size() - 1).isOptional();
}
private Cron validateAndReturnSupportedCronNickname(String nickname, Set cronNicknames, CronNicknames cronNickname, Cron cron){
if(cronNicknames.contains(cronNickname)){
return cron;
}
throw new IllegalArgumentException(String.format("Nickname %s not supported!", nickname));
}
/**
* Parse string with cron expression.
*
* @param expression - cron expression, never null
* @return Cron instance, corresponding to cron expression received
* @throws java.lang.IllegalArgumentException if expression does not match cron definition
*/
public Cron parse(final String expression) {
Preconditions.checkNotNull(expression, "Expression must not be null");
final String replaced = expression.replaceAll("\\s+", " ").trim();
if (StringUtils.isEmpty(replaced)) {
throw new IllegalArgumentException("Empty expression!");
}
Set cronNicknames = cronDefinition.getCronNicknames();
if(expression.startsWith("@")){
if(cronNicknames.isEmpty()){
throw new IllegalArgumentException("Nicknames not supported!");
}
switch (expression){
case "@yearly":
return validateAndReturnSupportedCronNickname(expression, cronNicknames, CronNicknames.YEARLY, CronBuilder.yearly(cronDefinition));
case "@annually":
return validateAndReturnSupportedCronNickname(expression, cronNicknames, CronNicknames.ANNUALLY, CronBuilder.annually(cronDefinition));
case "@monthly":
return validateAndReturnSupportedCronNickname(expression, cronNicknames, CronNicknames.MONTHLY, CronBuilder.monthly(cronDefinition));
case "@weekly":
return validateAndReturnSupportedCronNickname(expression, cronNicknames, CronNicknames.WEEKLY, CronBuilder.weekly(cronDefinition));
case "@daily":
return validateAndReturnSupportedCronNickname(expression, cronNicknames, CronNicknames.DAILY, CronBuilder.daily(cronDefinition));
case "@midnight":
return validateAndReturnSupportedCronNickname(expression, cronNicknames, CronNicknames.MIDNIGHT, CronBuilder.midnight(cronDefinition));
case "@hourly":
return validateAndReturnSupportedCronNickname(expression, cronNicknames, CronNicknames.HOURLY, CronBuilder.hourly(cronDefinition));
case "@reboot":
return validateAndReturnSupportedCronNickname(expression, cronNicknames, CronNicknames.REBOOT, CronBuilder.reboot(cronDefinition));
}
}
if(expression.contains("||")) {
List crons = Arrays.stream(expression.split("\\|\\|")).map(this::parse).collect(Collectors.toList());
return new CompositeCron(crons);
}
if(expression.contains("|")){
List crons = new ArrayList<>();
int cronscount = Arrays.stream(expression.split("\\s+")).mapToInt(s->s.split("\\|").length).max().orElse(0);
for(int j=0; j x.endsWith(",")).findAny().orElse(null);
if(fieldWithTrailingCommas!=null){
throw new IllegalArgumentException(String.format("Invalid field value! Trailing commas not permitted! '%s'", fieldWithTrailingCommas));
}
final List fields = expressions.get(expressionLength);
if (fields == null) {
throw new IllegalArgumentException(
String.format("Cron expression contains %s parts but we expect one of %s", expressionLength, expressions.keySet()));
}
try {
final int size = expressionParts.length;
final List results = new ArrayList<>(size + 1);
for (int j = 0; j < size; j++) {
results.add(fields.get(j).parse(expressionParts[j]));
}
return new SingleCron(cronDefinition, results).validate();
} catch (final IllegalArgumentException e) {
throw new IllegalArgumentException(String.format("Failed to parse cron expression. %s", e.getMessage()), e);
}
}
}
}