All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.freedomotic.plugins.CronSchedule Maven / Gradle / Ivy

The newest version!
/**
 *
 * Copyright (c) 2009-2014 Freedomotic team
 * http://freedomotic.com
 *
 * This file is part of Freedomotic
 *
 * This Program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This Program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Freedomotic; see the file COPYING.  If not, see
 * .
 */

package com.freedomotic.plugins;

import java.util.Calendar;
import java.util.GregorianCalendar;

/**
 * Provides cron-like scheduling information. This class implements cron-like
 * definition of scheduling information. Various methods can be used to check
 * whether a timestamp matches the schedule or not. However, there is a slight
 * difference between cron and this class. Cron describes a match when either
 * the day of month and month or the day of week are met. This class requires
 * both to be met for a match. Also note that Calendar defines Sunday through
 * Saturday with 1 through 7 respectively
 *
 * @author RalphSchuster
 * http://techblog.ralph-schuster.eu/2008/02/01/handling-unix-cron-like-information-in-java/
 */
public class CronSchedule {

    /**
     * Types being used. This array defines the types and their indices.
     */
    protected static int[] TYPES =
            new int[]{Calendar.MINUTE, Calendar.HOUR_OF_DAY, Calendar.DAY_OF_MONTH, Calendar.MONTH, Calendar.DAY_OF_WEEK};
    private AbstractTimeValue[][] timeValues = new AbstractTimeValue[TYPES.length][];

    /**
     * Default constructor Constructor with all terms set to "*".
     */
    public CronSchedule() {
        this("*", "*", "*", "*", "*");
    }

    /**
     * Constructor with cron-style string initialization. The cron style is:
     * $minute $hour $dayOfMonth $month $dayOfWeek
     *
     * @param schedule
     */
    public CronSchedule(String schedule) {
        set(schedule);
    }

    /**
     * Constructor with separate initialization values.
     *
     * @param min - minute definition
     * @param hour - hour definition
     * @param dom - day of month definition
     * @param mon - month definition
     * @param dow - day of week definition
     */
    public CronSchedule(String min, String hour, String dom, String mon, String dow) {
        set(Calendar.MINUTE, min);
        set(Calendar.HOUR_OF_DAY, hour);
        set(Calendar.DAY_OF_MONTH, dom);
        set(Calendar.MONTH, mon);
        set(Calendar.DAY_OF_WEEK, dow);
    }

    /**
     * Sets the cron schedule. The cron style is: $minute $hour $dayOfMonth
     * $month $dayOfWeek The function will return any characters that follow the
     * cron definition
     *
     * @param schedule - cron-like schedule definition
     * @return characters following the cron definition.
     */
    public String set(String schedule) {
        String[] parts = schedule.split(" ", TYPES.length + 1);

        if (parts.length < TYPES.length) {
            throw new IllegalArgumentException("Invalid cron format: " + schedule);
        }

        for (int i = 0; i < TYPES.length; i++) {
            set(getType(i),
                    parts[i]);
        }

        return (parts.length > TYPES.length) ? parts[TYPES.length] : null;
    }

    /**
     * Sets the time values accordingly
     *
     * @param type - Calendar constant to define what values will be set
     * @param values - comma-separated list of definitions for that type
     */
    public void set(int type, String values) {
        // Split the values
        String[] parts = values.split(",");
        AbstractTimeValue[] result = new AbstractTimeValue[parts.length];

        // Iterate over entries
        for (int i = 0; i < parts.length; i++) {
            // Decide what time value is set and create it
            if (parts[i].indexOf("/") > 0) {
                result[i] = new TimeSteps(parts[i]);
            } else if (parts[i].indexOf("-") > 0) {
                result[i] = new TimeRange(parts[i]);
            } else if (parts[i].equals("*")) {
                result[i] = new TimeAll();
            } else {
                result[i] = new SingleTimeValue(parts[i]);
            }
        }

        // Save the array
        set(type, result);
    }

    /**
     * Sets the values for a specific type
     *
     * @param type - Calendar constant defining the time type
     * @param values - values to be set
     */
    protected void set(int type, AbstractTimeValue[] values) {
        timeValues[getIndex(type)] = values;
    }

    /**
     * Returns the values for a specific time type
     *
     * @param type - Calendar constant defining the type
     * @return time value definitions
     */
    protected AbstractTimeValue[] getValues(int type) {
        return timeValues[getIndex(type)];
    }

    /**
     * Returns the cron-like definition string for the given time value
     *
     * @param type - Calendar constant defining time type
     * @return cron-like definition
     */
    public String get(int type) {
        AbstractTimeValue[] values = getValues(type);
        StringBuilder buff = new StringBuilder();

        for (int i = 0; i < values.length; i++) {
            buff.append(",").append(values[i].toString());
        }

        return buff.substring(1);
    }

    /**
     * Returns the cron-like definition of the schedule.
     * @return 
     */
    @Override
    public String toString() {
        StringBuilder buff = new StringBuilder();

        for (int i = 0; i < TYPES.length; i++) {
            buff.append(" ").append(get(getType(i)));
        }

        return buff.toString().trim();
    }

    /**
     * Checks whether given timestamp matches with defined schedule. This is
     * default check method. All criteria must be met including seconds to be 0.
     *
     * @param timeStamp - time in ms since Epoch time
     * @return true when schedule matches
     */
    public boolean matches(long timeStamp) {
        return matches(getCalendar(timeStamp));
    }

    /**
     * Checks whether given timestamp matches with defined schedule. This is
     * default check method. All criteria must be met including seconds to be 0.
     *
     * @param cal - calendar date
     * @return true when schedule matches
     */
    public boolean matches(Calendar cal) {
        return isMinute(cal) && (cal.get(Calendar.SECOND) == 0);
    }

    /**
     * Checks whether given timestamp matches with defined schedule. This method
     * can be used when seconds are not relevant for matching. This is default
     * check method.
     *
     * @param timeStamp - time in ms since Epoch time
     * @return true when schedule matches
     */
    public boolean isMinute(long timeStamp) {
        return isMinute(getCalendar(timeStamp));
    }

    /**
     * Checks whether given calendar date matches with defined schedule. This
     * method can be used when seconds are not relevant for matching.
     *
     * @param cal - calendar date
     * @return true when schedule matches
     */
    public boolean isMinute(Calendar cal) {
        return matches(Calendar.MINUTE, cal) && isHour(cal);
    }

    /**
     * Checks whether given timestamp matches with defined hour schedule. This
     * method can be used when minute definition is not relevant for matching.
     *
     * @param timeStamp
     * @param timestamp - time in ms since Epoch time
     * @return true when schedule matches
     */
    public boolean isHour(long timeStamp) {
        return isHour(getCalendar(timeStamp));
    }

    /**
     * Checks whether given calendar date matches with defined hour schedule.
     * This method can be used when minute definition is not relevant for
     * matching.
     *
     * @param cal - calendar date
     * @return true when schedule matches
     */
    public boolean isHour(Calendar cal) {
        return matches(Calendar.HOUR_OF_DAY, cal) && isDay(cal);
    }

    /**
     * Checks whether given timestamp matches with defined day schedule. This
     * method can be used when minute and hour definitions are not relevant for
     * matching.
     *
     * @param timeStamp
     * @param timestamp - time in ms since Epoch time
     * @return true when schedule matches
     */
    public boolean isDay(long timeStamp) {
        return isDay(getCalendar(timeStamp));
    }

    /**
     * Checks whether given calendar date matches with defined day schedule.
     * This method can be used when minute and hour definitions are not relevant
     * for matching.
     *
     * @param cal - calendar date
     * @return true when schedule matches
     */
    public boolean isDay(Calendar cal) {
        return matches(Calendar.DAY_OF_WEEK, cal) && matches(Calendar.DAY_OF_MONTH, cal)
                && matches(Calendar.MONTH, cal);
    }

    /**
     * Checks whether specific schedule definition matches against the given
     * calendar date.
     *
     * @param type - Calendar constant defining time type to check for
     * @param calendar - calendar representing the date to check
     * @return true when definition matches
     */
    protected boolean matches(int type, Calendar calendar) {
        // get the definitions and the comparison value
        AbstractTimeValue[] defs = timeValues[getIndex(type)];
        int value = calendar.get(type);

        // Any of the criteria must be met
        for (int i = 0; i < defs.length; i++) {
            if (defs[i].matches(value)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Creates the calendar for a timestamp.
     *
     * @param timeStamp - timestamp
     * @return calendar
     */
    protected Calendar getCalendar(long timeStamp) {
        Calendar rc = new GregorianCalendar();
        rc.setTimeInMillis(timeStamp);

        return rc;
    }

    /**
     * Returns the type at the specified index
     *
     * @param index - index
     * @return Calendar constant of type
     */
    protected static int getType(int index) {
        return TYPES[index];
    }

    /**
     * Returns the index for the specified Calendar type.
     *
     * @param type - Calendar constant for type
     * @return internal index
     */
    protected static int getIndex(int type) {
        for (int i = 0; i < TYPES.length; i++) {
            if (TYPES[i] == type) {
                return i;
            }
        }

        throw new IllegalArgumentException("No such time type: " + type);
    }

    /**
     * Base class for timing values.
     *
     * @author RalphSchuster
     */
    public static abstract class AbstractTimeValue {

        /**
         * Returns true when given time value matches defined time.
         *
         * @param timeValue - time value to evaluate
         * @return true when time matches
         */
        public abstract boolean matches(int timeValue);
    }

    /**
     * Represents a single time value, e.g. 9
     *
     * @author RalphSchuster
     */
    public static class SingleTimeValue
            extends AbstractTimeValue {

        private int value;

        /**
         *
         * @param value
         */
        public SingleTimeValue(int value) {
            setValue(value);
        }

        /**
         *
         * @param value
         */
        public SingleTimeValue(String value) {
            setValue(Integer.parseInt(value));
        }

        /**
         * @return the value
         */
        public int getValue() {
            return value;
        }

        /**
         * @param value the value to set
         */
        public void setValue(int value) {
            this.value = value;
        }

        /**
         * Returns true when given time value matches defined value.
         *
         * @param timeValue - time value to evaluate
         * @return true when time matches
         */
        public boolean matches(int timeValue) {
            return timeValue == getValue();
        }

        /**
         * Returns cron-like string of this definition.
         * @return 
         */
        public String toString() {
            return "" + getValue();
        }
    }

    /**
     * Represents a time range, e.g. 5-9
     *
     * @author RalphSchuster
     */
    public static class TimeRange
            extends AbstractTimeValue {

        private int startValue;
        private int endValue;

        /**
         *
         * @param startValue
         * @param endValue
         */
        public TimeRange(int startValue, int endValue) {
            setStartValue(startValue);
            setEndValue(endValue);
        }

        /**
         *
         * @param range
         */
        public TimeRange(String range) {
            int dashPos = range.indexOf("-");
            setStartValue(Integer.parseInt(range.substring(0, dashPos)));
            setEndValue(Integer.parseInt(range.substring(dashPos + 1)));
        }

        /**
         * @return the endValue
         */
        public int getEndValue() {
            return endValue;
        }

        /**
         * @param endValue the endValue to set
         */
        public void setEndValue(int endValue) {
            this.endValue = endValue;
        }

        /**
         * @return the startValue
         */
        public int getStartValue() {
            return startValue;
        }

        /**
         * @param startValue the startValue to set
         */
        public void setStartValue(int startValue) {
            this.startValue = startValue;
        }

        /**
         * Returns true when given time value falls in range.
         *
         * @param timeValue - time value to evaluate
         * @return true when time falls in range
         */
        public boolean matches(int timeValue) {
            return (getStartValue() <= timeValue) && (timeValue <= getEndValue());
        }

        /**
         * Returns cron-like string of this definition.
         * @return 
         */
        public String toString() {
            return getStartValue() + "-" + getEndValue();
        }
    }

    /**
     * Represents a time interval, e.g. 0-4/10
     *
     * @author RalphSchuster
     */
    public static class TimeSteps
            extends AbstractTimeValue {

        private AbstractTimeValue range;
        private int steps;

        /**
         *
         * @param range
         * @param steps
         */
        public TimeSteps(AbstractTimeValue range, int steps) {
            setRange(range);
            setSteps(steps);
        }

        /**
         *
         * @param def
         */
        public TimeSteps(String def) {
            int divPos = def.indexOf("/");
            String r = def.substring(0, divPos);

            if (r.equals("*")) {
                setRange(new TimeAll());
            } else if (r.indexOf("-") > 0) {
                setRange(new TimeRange(r));
            } else {
                throw new IllegalArgumentException("Invalid range: " + def);
            }

            setSteps(Integer.parseInt(def.substring(divPos + 1)));
        }

        /**
         * Returns true when given time value matches the interval.
         *
         * @param timeValue - time value to evaluate
         * @return true when time matches the interval
         */
        public boolean matches(int timeValue) {
            boolean rc = getRange().matches(timeValue);

            if (rc) {
                rc = (timeValue % getSteps()) == 0;
            }

            return rc;
        }

        /**
         * @return the range
         */
        public AbstractTimeValue getRange() {
            return range;
        }

        /**
         * @param range the range to set
         */
        public void setRange(AbstractTimeValue range) {
            this.range = range;
        }

        /**
         * @return the steps
         */
        public int getSteps() {
            return steps;
        }

        /**
         * @param steps the steps to set
         */
        public void setSteps(int steps) {
            this.steps = steps;
        }

        /**
         * Returns cron-like string of this definition.
         * @return 
         */
        public String toString() {
            return getRange() + "/" + getSteps();
        }
    }

    /**
     * Represents the ALL time, *.
     *
     * @author RalphSchuster
     */
    public static class TimeAll
            extends AbstractTimeValue {

        /**
         *
         */
        public TimeAll() {
        }

        /**
         * Returns always true.
         *
         * @param timeValue - time value to evaluate
         * @return true
         */
        public boolean matches(int timeValue) {
            return true;
        }

        /**
         * Returns cron-like string of this definition.
         * @return 
         */
        public String toString() {
            return "*";
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy