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

com.viaoa.process.OACron Maven / Gradle / Ivy

The newest version!
package com.viaoa.process;

import java.util.Arrays;
import java.util.Calendar;

import com.viaoa.hub.HubEvent;
import com.viaoa.util.OAArray;
import com.viaoa.util.OAConv;
import com.viaoa.util.OADate;
import com.viaoa.util.OADateTime;
import com.viaoa.util.OAString;


/**
 * Used to define and find the next time a Cron-like entry should be ran.

        *     *     *   *    *        command to be executed
        -     -     -   -    -
        |     |     |   |    |
        |     |     |   |    +----- day of week (0-6) (Sunday=0) - Java: 1-7 (Sunday=1)
        |     |     |   +---------- month (1-12) - Java: 0-11    
        |     |     +-------------- day of month (1-31), also allows "last"
        |     +-------------------- hour (0 - 23)
        +-------------------------- min (0 - 59)

 Each field needs to be separate by space or tab.
 Field values can use a single number, "-" for a range, and commas to separate more then one.

 see OACronProcessor# to register cron to be processed

 @author vvia
 */
public abstract class OACron {
    // NOTE: all values are stored as cron values
    private OADateTime dtFrom;
    private String strMins;
    private String strHours;
    private String strDayOfMonth;
    private String strMonth;
    private String strDayOfWeek;

    // store sorted cron values (not Java)
    private int[] mins;
    private int[] hrs;
    private int[] monthDays;
    private int[] daysOfWeek;
    private int[] months;

    private boolean bIncludeLastDayOfMonth;

    private boolean bValid;

    private String name;
    private String description;
    
    private boolean bEnabled = true;
    private OADateTime dtCreated;
    private OADateTime dtLast;
    

    public OACron(String strMins, String strHours, String strDayOfMonth, String strMonth, String strDayOfWeek) {
        this.dtCreated = new OADateTime();
        this.strMins = strMins;
        this.strHours = strHours;
        this.strDayOfMonth = strDayOfMonth;
        this.strMonth = strMonth;
        this.strDayOfWeek = strDayOfWeek;

        // set to default, can get changed when calling getInts
        bValid = true;
        bIncludeLastDayOfMonth = false;
        
        mins = getInts(strMins);
        hrs = getInts(strHours);
        monthDays = getInts(strDayOfMonth, true);
        daysOfWeek = getInts(strDayOfWeek);
        months = getInts(strMonth);

        if (bValid) {
            for (int x : mins) {
                if (x < 0 || x > 59) bValid = false;
            }
            for (int x : hrs) {
                if (x < 0 || x > 23) bValid = false;
            }
            for (int x : monthDays) {
                if (x < 1 || x > 31) bValid = false;
            }
            for (int x : daysOfWeek) {
                if (x < 0 || x > 6) bValid = false;
            }
            
            if (months == null || months.length == 0) { // any month
                months = new int[12];
                for (int i=0; i<12; i++) months[i] = i+1; // store as cron month is 1-12, java is 0-11
            }
            for (int x : months) {
                if (x < 1 || x > 12) bValid = false;
            }
        }
    }

    /**
     * Called when it's time to process.
     */
    public abstract void process(final boolean bManuallyCalled);
    
    
    public int[] getMinutes() {
        return mins;
    }
    public int[] getHours() {
        return hrs;
    }
    public int[] getMonthDays() {
        return monthDays;
    }
    public int[] getDaysOfWeek() {
        return daysOfWeek;
    }
    public int[] getMonths() {
        return months;
    }
    public boolean getIncludeLastDayOfMonth() {
        return bIncludeLastDayOfMonth;
    }

    public boolean isValid() {
        return bValid;
    }

    public String getDescription() {
        if (description != null) return description;
        description = "";
        int x;

        if (months.length == 12) {
            //if (description.length() > 0) description += "; and ";
            //else description += "all months";
        }
        else if (months.length > 0) {
            if (description.length() > 0) description += "; and";
            else description += "when";
            description += " month is ";

            for (int i=0; i 0) description += " or ";
                if (x < 1 || x > 12) {
                    description += "Invalid:"+x;
                }
                else {
                    OADate d = new OADate(2017, x-1, 1);
                    description += d.toString("MMM");
                }
            }
        }

        if (monthDays.length > 0 || bIncludeLastDayOfMonth) {
            if (description.length() > 0) description += "; and";
            else description += "when";
            description += " day of month is ";
            for (int i=0; i 0) description += " or ";
                if (x < 0 || x > 31) description += "Invalid:"+x;
                else description += ""+x;
            }
            if (bIncludeLastDayOfMonth) {
                if (monthDays.length > 0) description += " or ";
                description += "last day";
            }
        }

        if (daysOfWeek.length > 0) {
            if (description.length() > 0) description += "; and";
            else description += "when";
            description += " day of week is ";


            for (int i=0; i 0) description += " or ";
                if (x < 0 || x > 6) description += "Invalid:"+x;
                else {
                    String s;
                    for (int j=0; j<7; j++) {
                        OADate d = new OADate(2017, 0, 1+j);
                        if (d.getDayOfWeek() != x+1) continue;
                        description += d.toString("EEE");
                        break;
                    }
                }
            }
        }

        if (hrs.length > 0) {
            if (description.length() > 0) description += "; and";
            else description += "when";
            description += " hour is ";
            for (int i=0; i 0) description += " or ";
                if (x < 0 || x > 23) description += "Invalid:"+x;
                else description += ""+x;
            }
        }


        if (mins.length > 0) {
            if (description.length() > 0) description += "; and";
            else description += "when";
            description += " minute is ";
            for (int i=0; i 0) description += ", ";
                if (x < 0 || x > 59) description += "Invalid:"+x;
                else description += ""+x;
            }
        }
        else {
            if (description.length() > 0) description += "; and ";
            description += "every minute";
        }


        if (!isValid()) description = "INVALID: "+description;

        return description;
    }

    public OADateTime getLast() {
        return dtLast;
    }
    public void setLast(OADateTime dt) {
        this.dtLast = dt;
    }
    
    public OADateTime getNext() {
        return findNext(new OADateTime());
    }
    public OADateTime getNext(OADateTime dtFrom) {
        return findNext(dtFrom);
    }
    
    public OADateTime findNext() {
        return findNext(new OADateTime());
    }
    public OADateTime findNext(OADateTime dtFrom) {
        if (!isValid()) return null;
        if (dtFrom == null) dtFrom = new OADateTime();
        this.dtFrom = dtFrom;

        OADateTime dtFound = findNextMonth();
        return dtFound;
    }

    private OADateTime findNextMonth() {
        OADateTime dtFound = null;

        final int fromMonth = dtFrom.getMonth();

        OADateTime dtCheck = new OADateTime(dtFrom.getTime());
        for (int i=0; ;i++) {
            if (i > 0) dtCheck = dtCheck.addYears(1);
            for (int m : months) {
                m--; // cron month is 1-12, java is 0-11

                if (i == 0 && m < dtFrom.getMonth()) continue;

                dtCheck.setDay(1);
                dtCheck.setMonth(m);
                dtCheck.clearTime();
                if (dtFound != null && dtFound.before(dtCheck)) continue;
                OADateTime dtTo = dtCheck.addMonths(1);

                if (dtCheck.before(dtFrom)) dtCheck = new OADateTime(dtFrom);

                dtFound = findNextMonthDay(dtFound, dtTo, dtCheck);
            }
            if (dtFound != null) break;
        }
        if (dtFound != null) {
            dtFound.clearSecondAndMilliSecond();            
        }
        return dtFound;
    }
    private OADateTime findNextMonthDay(OADateTime dtFound, OADateTime dtTo, OADateTime dtCheck) {
        if (!bIncludeLastDayOfMonth && (monthDays == null || monthDays.length == 0)) {
            dtFound = findClosestDayOfWeek(dtFound, dtTo, dtCheck);
        }
        else {
            OADateTime dtx = new OADateTime(dtFrom);
            dtx.clearTime();

            int max = dtCheck.getDaysInMonth();
            for (int i=0; i<=monthDays.length; i++) {
                int md;
                if (i == monthDays.length) {
                    if (!bIncludeLastDayOfMonth) continue;
                    md = max;
                }
                else md = monthDays[i];

                if (md > max) continue;

                dtCheck.setDay(md);
                if (dtCheck.before(dtx)) continue;
                if (dtFound != null && dtFound.before(dtCheck)) continue;

                OADateTime dtTo2 = dtCheck.addDays(1);
                dtTo2.clearTime();

                dtFound = findClosestDayOfWeek(dtFound, dtTo2, dtCheck);
            }
        }
        return dtFound;
    }

    // Java Sunday=1, cron Sunday=0
    private OADateTime findClosestDayOfWeek(OADateTime dtFound, OADateTime dtTo, OADateTime dtCheck) {
        if (daysOfWeek == null || daysOfWeek.length == 0) { // any dayOfWeek
            for (;;) {
                dtFound = findClosestHour(dtFound, dtTo, dtCheck);
                if (dtFound != null) break;
                dtCheck = dtCheck.addDays(1);
                dtCheck.clearTime();
                if (dtTo != null && dtTo.compareTo(dtCheck) <= 0) break;
            }
        }
        else {
            int fromDayOfWeek = dtCheck.getDayOfWeek();
            OADateTime dtHold = dtCheck;

            int fromWd = dtHold.getDayOfWeek();
            for (int i=0; i<2; i++) {
                for (int wd : daysOfWeek) {
                    wd++;  // cron day is 0 based, java 1 based

                    int diff;
                    if (i > 0) {
                        if (wd != fromWd) continue;
                        diff = 7;
                    }
                    else {
                        if (fromWd > wd) diff = (wd+7) - fromWd;
                        else diff = wd - fromWd;
                    }

                    if (diff != 0) dtCheck = dtHold.addDays(diff);
                    dtCheck.clearTime();

                    if (dtTo != null && dtTo.compareTo(dtCheck) <= 0) continue;

                    if (dtFound != null && dtFound.before(dtCheck)) continue;

                    dtFound = findClosestHour(dtFound, dtTo, dtCheck);
                }
                if (dtFound != null) break;
            }
        }
        return dtFound;
    }
    private OADateTime findClosestHour(OADateTime dtFound, OADateTime dtTo, OADateTime dtCheck) {
        if (hrs == null || hrs.length == 0) { // any hour
            dtFound = findClosestMinute(dtFound, dtTo, dtCheck);
            if (dtFound == null) {
                dtCheck = dtCheck.addHours(1);
                if (dtTo == null || dtTo.compareTo(dtCheck) > 0) {
                    dtFound = findClosestMinute(dtFound, dtTo, dtCheck);
                }
            }
        }
        else {
            dtCheck.setMinute(0);
            dtCheck.clearSecondAndMilliSecond();            
            OADateTime dtx = new OADateTime(dtFrom);
            dtx.clearTime();
            dtx.set24Hour(dtFrom.get24Hour());

            for (int hr : hrs) {
                dtCheck.set24Hour(hr);
                if (dtCheck.before(dtx)) continue;
                if (dtFound != null && dtFound.before(dtCheck)) continue;
                dtFound = findClosestMinute(dtFound, dtTo, dtCheck);
            }
        }
        return dtFound;
    }
    private OADateTime findClosestMinute(OADateTime dtFound, OADateTime dtTo, OADateTime dtCheck) {
        if (mins == null || mins.length == 0) {
            if (dtFound == null || dtCheck.before(dtFound)) {
                dtFound = new OADateTime(dtCheck);
                if (dtFound.equals(dtFrom)) dtFound = dtFound.addMinutes(1);
            }
            return dtFound;
        }
        else {
            for (int m : mins) {
                dtCheck.setMinute(m);
                if (dtCheck.compareTo(dtFrom) <= 0) continue;
                if (dtFound != null && dtFound.before(dtCheck)) continue;
                if (dtCheck.before(dtFrom)) continue;
                if (dtFound == null || dtCheck.before(dtFound)) {
                    dtFound = new OADateTime(dtCheck);
                }
            }
        }
        return dtFound;
    }


    /**
     * parses values from String
     * @param line
     * @return values to include or [0]=all
     */
    private int[] getInts(String line) {
        return getInts(line, false);
    }
    private int[] getInts(String line, boolean bAllowLast) {
        if (OAString.isEmpty(line)) return new int[0];
        if (line.indexOf('*') >= 0) return new int[0]; // all

        line = line.replace(',', ' ');
        line = line.replace(':', ' ');

        int[] ints = new int[0];
        for (String s : line.split("\\s+")) {
            String[] ss = s.split("\\-");
            if (ss == null || ss.length == 0) continue;
            s = ss[0];
            if (!OAString.isInteger(s)) {
                if (bAllowLast && s.equalsIgnoreCase("last")) {
                    bIncludeLastDayOfMonth = true;
                }
                else bValid = false;
                continue;
            }
            int x = OAConv.toInt(s);

            if (ss.length == 2) {
                if (!OAString.isInteger(ss[1])) {
                    bValid = false;
                    if (!OAArray.contains(ints, x)) {
                        ints = OAArray.add(ints, x);
                    }
                    continue;
                }
                int x2 = OAConv.toInt(ss[1]);
                for (int i=x; i<=x2; i++) {
                    if (!OAArray.contains(ints, i)) {
                        ints = OAArray.add(ints, i);
                    }
                }
            }
            else {
                ints = OAArray.add(ints, x);
            }
        }

        Arrays.sort(ints);
        return ints;
    }

    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return this.name;
    }

    public boolean getIsValid() {
        return bValid;
    }
    public void setEnabled(boolean b) {
        this.bEnabled = b;
    }
    public boolean getEnabled() {
        return bEnabled;
    }

    public OADateTime getCreated() {
        return dtCreated;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy