Java tutorial
package com.cronutils.mapper; import com.cronutils.model.Cron; import com.cronutils.model.CronType; import com.cronutils.model.definition.CronDefinition; import com.cronutils.model.definition.CronDefinitionBuilder; import com.cronutils.model.field.CronField; import com.cronutils.model.field.CronFieldName; import com.cronutils.model.field.constraint.FieldConstraints; import com.cronutils.model.field.constraint.FieldConstraintsBuilder; import com.cronutils.model.field.definition.DayOfWeekFieldDefinition; import com.cronutils.model.field.definition.FieldDefinition; import com.cronutils.model.field.expression.Always; import com.cronutils.model.field.expression.FieldExpression; import com.cronutils.model.field.expression.On; import com.cronutils.model.field.expression.QuestionMark; import com.cronutils.model.field.expression.visitor.ValueMappingFieldExpressionVisitor; import com.cronutils.model.field.value.IntegerFieldValue; import com.cronutils.model.field.value.SpecialChar; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.apache.commons.lang3.Validate; import java.util.List; import java.util.Map; import java.util.function.Function; /* * 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. */ public class CronMapper { private Map<CronFieldName, Function<CronField, CronField>> mappings; private Function<Cron, Cron> cronRules; private CronDefinition to; /** * Constructor * @param from - source CronDefinition; * if null a NullPointerException will be raised * @param to - target CronDefinition; * if null a NullPointerException will be raised */ public CronMapper(CronDefinition from, CronDefinition to, Function<Cron, Cron> cronRules) { Validate.notNull(from, "Source CronDefinition must not be null"); this.to = Validate.notNull(to, "Destination CronDefinition must not be null"); this.cronRules = Validate.notNull(cronRules, "CronRules must not be null"); mappings = Maps.newHashMap(); buildMappings(from, to); } /** * Maps given cron to target cron definition * @param cron - Instance to be mapped; * if null a NullPointerException will be raised * @return new Cron instance, never null; */ public Cron map(Cron cron) { Validate.notNull(cron, "Cron must not be null"); List<CronField> fields = Lists.newArrayList(); for (CronFieldName name : CronFieldName.values()) { if (mappings.containsKey(name)) { fields.add(mappings.get(name).apply(cron.retrieve(name))); } } return cronRules.apply(new Cron(to, fields)).validate(); } public static CronMapper fromCron4jToQuartz() { return new CronMapper(CronDefinitionBuilder.instanceDefinitionFor(CronType.CRON4J), CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ), setQuestionMark()); } public static CronMapper fromQuartzToCron4j() { return new CronMapper(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ), CronDefinitionBuilder.instanceDefinitionFor(CronType.CRON4J), sameCron()); } public static CronMapper fromQuartzToUnix() { return new CronMapper(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ), CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX), sameCron()); } public static CronMapper fromUnixToQuartz() { return new CronMapper(CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX), CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ), setQuestionMark()); } public static CronMapper sameCron(CronDefinition cronDefinition) { return new CronMapper(cronDefinition, cronDefinition, sameCron()); } private static Function<Cron, Cron> sameCron() { return cron -> cron; } private static Function<Cron, Cron> setQuestionMark() { return cron -> { CronField dow = cron.retrieve(CronFieldName.DAY_OF_WEEK); CronField dom = cron.retrieve(CronFieldName.DAY_OF_MONTH); if (dow != null && dom != null) { if (dow.getExpression() instanceof QuestionMark || dom.getExpression() instanceof QuestionMark) { return cron; } else { Map<CronFieldName, CronField> fields = Maps.newHashMap(); fields.putAll(cron.retrieveFieldsAsMap()); if (dow.getExpression() instanceof Always) { fields.put(CronFieldName.DAY_OF_WEEK, new CronField(CronFieldName.DAY_OF_WEEK, new QuestionMark(), fields.get(CronFieldName.DAY_OF_WEEK).getConstraints())); } else { if (dom.getExpression() instanceof Always) { fields.put(CronFieldName.DAY_OF_MONTH, new CronField(CronFieldName.DAY_OF_MONTH, new QuestionMark(), fields.get(CronFieldName.DAY_OF_MONTH).getConstraints())); } else { cron.validate(); } } return new Cron(cron.getCronDefinition(), Lists.<CronField>newArrayList(fields.values())); } } return cron; }; } /** * Builds functions that map the fields from source CronDefinition to target * @param from - source CronDefinition * @param to - target CronDefinition */ private void buildMappings(CronDefinition from, CronDefinition to) { Map<CronFieldName, FieldDefinition> sourceFieldDefinitions = Maps.newHashMap(); Map<CronFieldName, FieldDefinition> destFieldDefinitions = Maps.newHashMap(); for (FieldDefinition fieldDefinition : from.getFieldDefinitions()) { sourceFieldDefinitions.put(fieldDefinition.getFieldName(), fieldDefinition); } for (FieldDefinition fieldDefinition : to.getFieldDefinitions()) { destFieldDefinitions.put(fieldDefinition.getFieldName(), fieldDefinition); } boolean startedDestMapping = false; boolean startedSourceMapping = false; for (CronFieldName name : CronFieldName.values()) { if (destFieldDefinitions.get(name) != null) { startedDestMapping = true; } if (sourceFieldDefinitions.get(name) != null) { startedSourceMapping = true; } if (startedDestMapping && destFieldDefinitions.get(name) == null) { break; } //destination has fields before source definition starts. We default them to zero. if (!startedSourceMapping && sourceFieldDefinitions.get(name) == null && destFieldDefinitions.get(name) != null) { mappings.put(name, returnOnZeroExpression(name)); } //destination has fields after source definition was processed. We default them to always. if (startedSourceMapping && sourceFieldDefinitions.get(name) == null && destFieldDefinitions.get(name) != null) { mappings.put(name, returnAlwaysExpression(name)); } if (sourceFieldDefinitions.get(name) != null && destFieldDefinitions.get(name) != null) { if (CronFieldName.DAY_OF_WEEK.equals(name)) { mappings.put(name, dayOfWeekMapping((DayOfWeekFieldDefinition) sourceFieldDefinitions.get(name), (DayOfWeekFieldDefinition) destFieldDefinitions.get(name))); } else { if (CronFieldName.DAY_OF_MONTH.equals(name)) { mappings.put(name, dayOfMonthMapping(sourceFieldDefinitions.get(name), destFieldDefinitions.get(name))); } else { mappings.put(name, returnSameExpression()); } } } } } /** * Creates a Function that returns same field * @return Function<CronField, CronField> instance, never null */ @VisibleForTesting static Function<CronField, CronField> returnSameExpression() { return field -> field; } /** * Creates a Function that returns a On instance with zero value * @param name - Cron field name * @return new Function<CronField, CronField> instance, never null */ @VisibleForTesting static Function<CronField, CronField> returnOnZeroExpression(final CronFieldName name) { return field -> { FieldConstraints constraints = FieldConstraintsBuilder.instance().forField(name) .createConstraintsInstance(); return new CronField(name, new On(new IntegerFieldValue(0)), constraints); }; } /** * Creates a Function that returns an Always instance * @param name - Cron field name * @return new Function<CronField, CronField> instance, never null */ @VisibleForTesting static Function<CronField, CronField> returnAlwaysExpression(final CronFieldName name) { return field -> new CronField(name, new Always(), FieldConstraintsBuilder.instance().forField(name).createConstraintsInstance()); } @VisibleForTesting static Function<CronField, CronField> dayOfWeekMapping(final DayOfWeekFieldDefinition sourceDef, final DayOfWeekFieldDefinition targetDef) { return field -> { FieldExpression expression = field.getExpression(); FieldExpression dest = null; dest = expression.accept(new ValueMappingFieldExpressionVisitor(fieldValue -> { if (fieldValue instanceof IntegerFieldValue) { return new IntegerFieldValue(ConstantsMapper.weekDayMapping(sourceDef.getMondayDoWValue(), targetDef.getMondayDoWValue(), ((IntegerFieldValue) fieldValue).getValue())); } return fieldValue; })); if (expression instanceof QuestionMark) { if (!targetDef.getConstraints().getSpecialChars().contains(SpecialChar.QUESTION_MARK)) { dest = new Always(); } } return new CronField(CronFieldName.DAY_OF_WEEK, dest, targetDef.getConstraints()); }; } @VisibleForTesting static Function<CronField, CronField> dayOfMonthMapping(final FieldDefinition sourceDef, final FieldDefinition targetDef) { return field -> { FieldExpression expression = field.getExpression(); FieldExpression dest = expression; if (expression instanceof QuestionMark) { if (!targetDef.getConstraints().getSpecialChars().contains(SpecialChar.QUESTION_MARK)) { dest = new Always(); } } return new CronField(CronFieldName.DAY_OF_MONTH, dest, targetDef.getConstraints()); }; } }