/*
***************************************************************************************
* Copyright (C) 2006 EsperTech, Inc. All rights reserved. *
* http://www.espertech.com/esper *
* http://www.espertech.com *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license *
* a copy of which has been included with this distribution in the license.txt file. *
***************************************************************************************
*/
package com.espertech.esper.schedule;
import com.espertech.esper.type.CronParameter;
import com.espertech.esper.type.NumberSetParameter;
import com.espertech.esper.type.ScheduleUnit;
import com.espertech.esper.type.WildcardParameter;
import java.util.EnumMap;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
/**
* Utility for computing from a set of parameter objects a schedule specification carry a
* crontab-like schedule definition.
*/
public class ScheduleSpecUtil {
/**
* Compute from parameters a crontab schedule.
*
* @param args parameters
* @return crontab schedule
* @throws ScheduleParameterException if the parameters are invalid
*/
public static ScheduleSpec computeValues(Object[] args) throws ScheduleParameterException {
if (args.length <= 4 || args.length >= 8) {
throw new ScheduleParameterException(getExpressionCountException(args.length));
}
EnumMap<ScheduleUnit, SortedSet<Integer>> unitMap = new EnumMap<ScheduleUnit, SortedSet<Integer>>(ScheduleUnit.class);
Object minutes = args[0];
Object hours = args[1];
Object daysOfMonth = args[2];
Object months = args[3];
Object daysOfWeek = args[4];
unitMap.put(ScheduleUnit.MINUTES, computeValues(minutes, ScheduleUnit.MINUTES));
unitMap.put(ScheduleUnit.HOURS, computeValues(hours, ScheduleUnit.HOURS));
SortedSet<Integer> resultMonths = computeValues(months, ScheduleUnit.MONTHS);
if (daysOfWeek instanceof CronParameter && daysOfMonth instanceof CronParameter) {
throw new ScheduleParameterException("Invalid combination between days of week and days of month fields for timer:at");
}
if (resultMonths != null && resultMonths.size() == 1 && (resultMonths.first() instanceof Integer)) {
// If other arguments are cronParameters, use it for later computations
CronParameter parameter = null;
if (daysOfMonth instanceof CronParameter) {
parameter = (CronParameter) daysOfMonth;
} else if (daysOfWeek instanceof CronParameter) {
parameter = (CronParameter) daysOfWeek;
}
if (parameter != null) {
parameter.setMonth(resultMonths.first());
}
}
SortedSet<Integer> resultDaysOfWeek = computeValues(daysOfWeek, ScheduleUnit.DAYS_OF_WEEK);
SortedSet<Integer> resultDaysOfMonth = computeValues(daysOfMonth, ScheduleUnit.DAYS_OF_MONTH);
if (resultDaysOfWeek != null && resultDaysOfWeek.size() == 1 && (resultDaysOfWeek.first() instanceof Integer)) {
// The result is in the form "last xx of the month
// Days of week is replaced by a wildcard and days of month is updated with
// the computation of "last xx day of month".
// In this case "days of month" parameter has to be a wildcard.
if (resultDaysOfWeek.first() > 6) {
if (resultDaysOfMonth != null) {
throw new ScheduleParameterException("Invalid combination between days of week and days of month fields for timer:at");
}
resultDaysOfMonth = resultDaysOfWeek;
resultDaysOfWeek = null;
}
}
if (resultDaysOfMonth != null && resultDaysOfMonth.size() == 1 && (resultDaysOfMonth.first() instanceof Integer)) {
if (resultDaysOfWeek != null) {
throw new ScheduleParameterException("Invalid combination between days of week and days of month fields for timer:at");
}
}
unitMap.put(ScheduleUnit.DAYS_OF_WEEK, resultDaysOfWeek);
unitMap.put(ScheduleUnit.DAYS_OF_MONTH, resultDaysOfMonth);
unitMap.put(ScheduleUnit.MONTHS, resultMonths);
if (args.length > 5) {
unitMap.put(ScheduleUnit.SECONDS, computeValues(args[5], ScheduleUnit.SECONDS));
}
String timezone = null;
if (args.length > 6) {
if (!(args[6] instanceof WildcardParameter)) {
if (!(args[6] instanceof String)) {
throw new ScheduleParameterException("Invalid timezone parameter '" + args[6] + "' for timer:at, expected a string-type value");
}
timezone = (String) args[6];
}
}
CronParameter optionalDayOfMonthOp = getOptionalSpecialOp(daysOfMonth);
CronParameter optionalDayOfWeekOp = getOptionalSpecialOp(daysOfWeek);
return new ScheduleSpec(unitMap, timezone, optionalDayOfMonthOp, optionalDayOfWeekOp);
}
public static String getExpressionCountException(int length) {
return "Invalid number of crontab parameters, expecting between 5 and 7 parameters, received " + length;
}
private static CronParameter getOptionalSpecialOp(Object unitParameter) {
if (!(unitParameter instanceof CronParameter)) {
return null;
}
return (CronParameter) unitParameter;
}
private static SortedSet<Integer> computeValues(Object unitParameter, ScheduleUnit unit) throws ScheduleParameterException {
if (unitParameter instanceof Integer) {
SortedSet<Integer> result = new TreeSet<Integer>();
result.add((Integer) unitParameter);
return result;
}
// cron parameters not handled as number sets
if (unitParameter instanceof CronParameter) {
return null;
}
NumberSetParameter numberSet = (NumberSetParameter) unitParameter;
if (numberSet.isWildcard(unit.min(), unit.max())) {
return null;
}
Set<Integer> result = numberSet.getValuesInRange(unit.min(), unit.max());
SortedSet<Integer> resultSorted = new TreeSet<Integer>();
resultSorted.addAll(result);
return resultSorted;
}
}