/* * The MIT License (MIT) * * Copyright (c) 2013 Anders Wisch * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package cron; import com.google.common.collect.ImmutableSortedSet; import java.util.NavigableSet; public class DefaultField implements TimeField { private final boolean fullRange; protected final NavigableSet<Integer> numbers; protected DefaultField(Builder b) { fullRange = b.fullRange; numbers = fullRange ? null : b.numbers.build(); } public static DefaultField parse(Tokens s, int min, int max) { return new Builder(min, max).parse(s).build(); } @Override public boolean contains(int number) { return fullRange || numbers.contains(number); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; DefaultField that = (DefaultField) o; if (fullRange != that.fullRange) return false; if (numbers != null ? !numbers.equals(that.numbers) : that.numbers != null) return false; return true; } @Override public int hashCode() { int result = (fullRange ? 1 : 0); result = 31 * result + (numbers != null ? numbers.hashCode() : 0); return result; } public static class Builder { private final ImmutableSortedSet.Builder<Integer> numbers; private final int min, max; private boolean fullRange; public Builder(int min, int max) { this.min = min; this.max = max; numbers = ImmutableSortedSet.naturalOrder(); } protected Builder parse(Tokens tokens) { Token token; while (!endOfField(token = tokens.next())) if (parseValue(tokens, token, min, max)) break; return this; } protected boolean parseValue(Tokens tokens, Token token, int first, int last) { if (token == Token.NUMBER) { if (parseNumber(tokens, tokens.next(), tokens.number(), last)) { return true; } } else if (token == Token.MATCH_ALL) { token = tokens.next(); if (token == Token.SKIP) { rangeSkip(first, last, nextNumber(tokens)); } else if (token == Token.VALUE_SEPARATOR) { range(first, last); } else if (endOfField(token)) { range(first, last); return true; } } return false; } /** * Returns true if the end of this field has been reached. */ protected boolean parseNumber(Tokens tokens, Token token, int first, int last) { if (token == Token.SKIP) { rangeSkip(first, last, nextNumber(tokens)); } else if (token == Token.RANGE) { last = nextNumber(tokens); token = tokens.next(); if (token == Token.SKIP) { rangeSkip(first, last, nextNumber(tokens)); } else if (token == Token.VALUE_SEPARATOR) { range(first, last); } else if (endOfField(token)) { range(first, last); return true; } } else if (token == Token.VALUE_SEPARATOR) { add(first); } else if (endOfField(token)) { add(first); return true; } return false; } protected int nextNumber(Tokens tokens) { if (tokens.next() == Token.NUMBER) return tokens.number(); throw new IllegalStateException("Expected number"); } private boolean endOfField(Token token) { return token == Token.FIELD_SEPARATOR || token == Token.END_OF_INPUT; } protected void rangeSkip(int first, int last, int skip) { for (int i = first; i <= last; i++) if ((i - min) % skip == 0) add(i); } protected void range(int first, int last) { if (first == min && last == max) { fullRange = true; } else { for (int i = first; i <= last; i++) add(i); } } protected void add(int value) { numbers.add(value); } public DefaultField build() { return new DefaultField(this); } } }