/************************************************************************************** * Copyright (C) 2008 EsperTech, Inc. All rights reserved. * * http://esper.codehaus.org * * 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.util.MetaDefItem; import com.espertech.esper.type.ScheduleUnit; import java.util.*; import java.io.Serializable; /** * Holds a schedule specification which consists of a set of integer values or a null * value for each schedule unit to indicate a wildcard. * There is always an element in the specification for each unit minutes, hours, day of month, month, and day of week. * There is optionally an element in the specification for the unit seconds. */ public final class ScheduleSpec implements MetaDefItem, Serializable { // Per unit hold the set of valid integer values, or null if wildcarded. // The seconds unit is optional. private final EnumMap<ScheduleUnit, SortedSet<Integer>> unitValues; private static final long serialVersionUID = -7050807714879367353L; /** * Constructor - validates that all mandatory schedule. * @param unitValues are the values for each minute, hour, day, month etc. * @throws IllegalArgumentException - if validation of value set per unit fails */ public ScheduleSpec(EnumMap<ScheduleUnit, SortedSet<Integer>> unitValues) throws IllegalArgumentException { validate(unitValues); // Reduce to wildcards any unit's values set, if possible compress(unitValues); this.unitValues = unitValues; } /** * Constructor - for unit testing, initialize to all wildcards but leave seconds empty. */ public ScheduleSpec() { unitValues = new EnumMap<ScheduleUnit, SortedSet<Integer>>(ScheduleUnit.class); unitValues.put(ScheduleUnit.MINUTES, null); unitValues.put(ScheduleUnit.HOURS, null); unitValues.put(ScheduleUnit.DAYS_OF_MONTH, null); unitValues.put(ScheduleUnit.MONTHS, null); unitValues.put(ScheduleUnit.DAYS_OF_WEEK, null); } /** * Return map of ordered set of valid schedule values for minute, hour, day, month etc. units * @return map of 5 or 6 entries each with a set of integers */ public final EnumMap<ScheduleUnit, SortedSet<Integer>> getUnitValues() { return unitValues; } /** * For unit testing, add a single value, changing wildcards to value sets. * @param element to add * @param value to add */ public final void addValue(ScheduleUnit element, int value) { SortedSet<Integer> set = unitValues.get(element); if (set == null) { set = new TreeSet<Integer>(); unitValues.put(element, set); } set.add(value); } @SuppressWarnings({"StringConcatenationInsideStringBufferAppend"}) public final String toString() { StringBuilder buffer = new StringBuilder(); for (ScheduleUnit element : ScheduleUnit.values()) { if (!unitValues.containsKey(element)) { continue; } Set<Integer> valueSet = unitValues.get(element); buffer.append(element + "={"); if (valueSet == null) { buffer.append("null"); } else { String delimiter = ""; for (int i : valueSet) { buffer.append(delimiter + i); delimiter = ","; } } buffer.append("} "); } return buffer.toString(); } public final boolean equals(Object otherObject) { if (otherObject == this) { return true; } if (otherObject == null) { return false; } if (getClass() != otherObject.getClass()) { return false; } ScheduleSpec other = (ScheduleSpec) otherObject; if (this.unitValues.size() != other.unitValues.size()) { return false; } for (Map.Entry<ScheduleUnit, SortedSet<Integer>> entry : unitValues.entrySet()) { Set<Integer> mySet = entry.getValue(); Set<Integer> otherSet = other.unitValues.get(entry.getKey()); if ((otherSet == null) && (mySet != null)) { return false; } if ((otherSet != null) && (mySet == null)) { return false; } if ((otherSet == null) && (mySet == null)) { continue; } if (mySet.size() != otherSet.size()) { return false; } // Commpare value by value for (int i : mySet) { if (!(otherSet.contains(i))) { return false; } } } return true; } public int hashCode() { int hashCode = 0; for (Map.Entry<ScheduleUnit, SortedSet<Integer>> entry : unitValues.entrySet()) { if (entry.getValue() != null) { hashCode *= 31; hashCode ^= entry.getValue().iterator().next(); } } return hashCode; } /** * Function to reduce value sets for unit that cover the whole range down to a wildcard. * I.e. reduce 0,1,2,3,4,5,6 for week value to 'null' indicating the wildcard. * @param unitValues is the set of valid values per unit */ protected static void compress(Map<ScheduleUnit, SortedSet<Integer>> unitValues) { for (Map.Entry<ScheduleUnit, SortedSet<Integer>> entry : unitValues.entrySet()) { int elementValueSetSize = entry.getKey().max() - entry.getKey().min() + 1; if (entry.getValue() != null) { if (entry.getValue().size() == elementValueSetSize) { unitValues.put(entry.getKey(), null); } } } } /** * Validate units and their value sets. * @param unitValues is the set of valid values per unit */ protected static void validate(Map<ScheduleUnit, SortedSet<Integer>> unitValues) { if ((!unitValues.containsKey(ScheduleUnit.MONTHS)) || (!unitValues.containsKey(ScheduleUnit.DAYS_OF_WEEK)) || (!unitValues.containsKey(ScheduleUnit.HOURS)) || (!unitValues.containsKey(ScheduleUnit.MINUTES)) || (!unitValues.containsKey(ScheduleUnit.DAYS_OF_MONTH))) { throw new IllegalArgumentException("Incomplete information for schedule specification, only the following keys are supplied=" + Arrays.toString(unitValues.keySet().toArray())); } for (ScheduleUnit unit : ScheduleUnit.values()) { if ((unit == ScheduleUnit.SECONDS) && (!unitValues.containsKey(unit))) // Seconds are optional { continue; } if (unitValues.get(unit) == null) // Wildcard - no validation for unit { continue; } SortedSet<Integer> values = unitValues.get(unit); for (Integer value : values) { if ((value < unit.min()) || (value > unit.max())) { throw new IllegalArgumentException("Invalid value found for schedule unit, value of " + value + " is not valid for unit " + unit); } } } } }