⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fastcronparser.java

📁 oscache-2.4.1-full
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
            break;
        }

        // OK, all done. Return the adjusted time value (adjusting this is faster than creating a new Calendar object)
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, month - 1); // Calendar is 0-based for this field, and we are 1-based
        cal.set(Calendar.DAY_OF_MONTH, dayOfMonth);
        cal.set(Calendar.HOUR_OF_DAY, hour);
        cal.set(Calendar.MINUTE, minute);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);

        return cal.getTime().getTime();
    }

    /**
    * Takes a cron expression as an input parameter, and extracts from it the
    * relevant minutes/hours/days/months that the expression matches.
    *
    * @param expression  A valid cron expression.
    * @throws ParseException If the supplied expression could not be parsed.
    */
    private void parseExpression(String expression) throws ParseException {
        try {
            // Reset all the lookup data
            for (int i = 0; i < lookup.length; lookup[i++] = 0) {
                lookupMin[i] = Integer.MAX_VALUE;
                lookupMax[i] = -1;
            }

            // Create some character arrays to hold the extracted field values
            char[][] token = new char[NUMBER_OF_CRON_FIELDS][];

            // Extract the supplied expression into another character array
            // for speed
            int length = expression.length();
            char[] expr = new char[length];
            expression.getChars(0, length, expr, 0);

            int field = 0;
            int startIndex = 0;
            boolean inWhitespace = true;

            // Extract the various cron fields from the expression
            for (int i = 0; (i < length) && (field < NUMBER_OF_CRON_FIELDS);
                    i++) {
                boolean haveChar = (expr[i] != ' ') && (expr[i] != '\t');

                if (haveChar) {
                    // We have a text character of some sort
                    if (inWhitespace) {
                        startIndex = i; // Remember the start of this token
                        inWhitespace = false;
                    }
                }

                if (i == (length - 1)) { // Adjustment for when we reach the end of the expression
                    i++;
                }

                if (!(haveChar || inWhitespace) || (i == length)) {
                    // We've reached the end of a token. Copy it into a new char array
                    token[field] = new char[i - startIndex];
                    System.arraycopy(expr, startIndex, token[field], 0, i - startIndex);
                    inWhitespace = true;
                    field++;
                }
            }

            if (field < NUMBER_OF_CRON_FIELDS) {
                throw new ParseException("Unexpected end of expression while parsing \"" + expression + "\". Cron expressions require 5 separate fields.", length);
            }

            // OK, we've broken the string up into the 5 cron fields, now lets add
            // each field to their lookup table.
            for (field = 0; field < NUMBER_OF_CRON_FIELDS; field++) {
                startIndex = 0;

                boolean inDelimiter = true;

                // We add each comma-delimited element seperately.
                int elementLength = token[field].length;

                for (int i = 0; i < elementLength; i++) {
                    boolean haveElement = token[field][i] != ',';

                    if (haveElement) {
                        // We have a character from an element in the token
                        if (inDelimiter) {
                            startIndex = i;
                            inDelimiter = false;
                        }
                    }

                    if (i == (elementLength - 1)) { // Adjustment for when we reach the end of the token
                        i++;
                    }

                    if (!(haveElement || inDelimiter) || (i == elementLength)) {
                        // We've reached the end of an element. Copy it into a new char array
                        char[] element = new char[i - startIndex];
                        System.arraycopy(token[field], startIndex, element, 0, i - startIndex);

                        // Add the element to our datastructure.
                        storeExpressionValues(element, field);

                        inDelimiter = true;
                    }
                }

                if (lookup[field] == 0) {
                    throw new ParseException("Token " + new String(token[field]) + " contains no valid entries for this field.", 0);
                }
            }

            // Remove any months that will never be valid
            switch (lookupMin[DAY_OF_MONTH]) {
                case 31:
                    lookup[MONTH] &= (0xFFF - 0x528); // Binary 010100101000 - the months that have 30 days
                case 30:
                    lookup[MONTH] &= (0xFFF - 0x2); // Binary 000000000010 - February

                    if (lookup[MONTH] == 0) {
                        throw new ParseException("The cron expression \"" + expression + "\" will never match any months - the day of month field is out of range.", 0);
                    }
            }

            // Check that we don't have both a day of month and a day of week field.
            if ((lookup[DAY_OF_MONTH] != Long.MAX_VALUE) && (lookup[DAY_OF_WEEK] != Long.MAX_VALUE)) {
                throw new ParseException("The cron expression \"" + expression + "\" is invalid. Having both a day-of-month and day-of-week field is not supported.", 0);
            }
        } catch (Exception e) {
            if (e instanceof ParseException) {
                throw (ParseException) e;
            } else {
                throw new ParseException("Illegal cron expression format (" + e.toString() + ")", 0);
            }
        }
    }

    /**
    * Stores the values for the supplied cron element into the specified field.
    *
    * @param element  The cron element to store. A cron element is a single component
    * of a cron expression. For example, the complete set of elements for the cron expression
    * <code>30 0,6,12,18 * * *</code> would be <code>{"30", "0", "6", "12", "18", "*", "*", "*"}</code>.
    * @param field  The field that this expression belongs to. Valid values are {@link #MINUTE},
    * {@link #HOUR}, {@link #DAY_OF_MONTH}, {@link #MONTH} and {@link #DAY_OF_WEEK}.
    *
    * @throws ParseException if there was a problem parsing the supplied element.
    */
    private void storeExpressionValues(char[] element, int field) throws ParseException {
        int i = 0;

        int start = -99;
        int end = -99;
        int interval = -1;
        boolean wantValue = true;
        boolean haveInterval = false;

        while ((interval < 0) && (i < element.length)) {
            char ch = element[i++];

            // Handle the wildcard character - it can only ever occur at the start of an element
            if ((i == 1) && (ch == '*')) {
                // Handle the special case where we have '*' and nothing else
                if (i >= element.length) {
                    addToLookup(-1, -1, field, 1);
                    return;
                }

                start = -1;
                end = -1;
                wantValue = false;
                continue;
            }

            if (wantValue) {
                // Handle any numbers
                if ((ch >= '0') && (ch <= '9')) {
                    ValueSet vs = getValue(ch - '0', element, i);

                    if (start == -99) {
                        start = vs.value;
                    } else if (!haveInterval) {
                        end = vs.value;
                    } else {
                        if (end == -99) {
                            end = MAX_VALUE[field];
                        }

                        interval = vs.value;
                    }

                    i = vs.pos;
                    wantValue = false;
                    continue;
                }

                if (!haveInterval && (end == -99)) {
                    // Handle any months that have been suplied as words
                    if (field == MONTH) {
                        if (start == -99) {
                            start = getMonthVal(ch, element, i++);
                        } else {
                            end = getMonthVal(ch, element, i++);
                        }

                        wantValue = false;

                        // Skip past the rest of the month name
                        while (++i < element.length) {
                            int c = element[i] | 0x20;

                            if ((c < 'a') || (c > 'z')) {
                                break;
                            }
                        }

                        continue;
                    } else if (field == DAY_OF_WEEK) {
                        if (start == -99) {
                            start = getDayOfWeekVal(ch, element, i++);
                        } else {
                            end = getDayOfWeekVal(ch, element, i++);
                        }

                        wantValue = false;

                        // Skip past the rest of the day name
                        while (++i < element.length) {
                            int c = element[i] | 0x20;

                            if ((c < 'a') || (c > 'z')) {
                                break;
                            }
                        }

                        continue;
                    }
                }
            } else {
                // Handle the range character. A range character is only valid if we have a start but no end value
                if ((ch == '-') && (start != -99) && (end == -99)) {
                    wantValue = true;
                    continue;
                }

                // Handle an interval. An interval is valid as long as we have a start value
                if ((ch == '/') && (start != -99)) {
                    wantValue = true;
                    haveInterval = true;
                    continue;
                }
            }

            throw makeParseException("Invalid character encountered while parsing element", element, i);
        }

        if (element.length > i) {
            throw makeParseException("Extraneous characters found while parsing element", element, i);
        }

        if (end == -99) {
            end = start;
        }

        if (interval < 0) {
            interval = 1;
        }

        addToLookup(start, end, field, interval);
    }

    /**
    * Extracts a numerical value from inside a character array.
    *
    * @param value    The value of the first character
    * @param element  The character array we're extracting the value from
    * @param i        The index into the array of the next character to process
    *
    * @return the new index and the extracted value
    */
    private ValueSet getValue(int value, char[] element, int i) {
        ValueSet result = new ValueSet();
        result.value = value;

        if (i >= element.length) {
            result.pos = i;
            return result;
        }

        char ch = element[i];

        while ((ch >= '0') && (ch <= '9')) {
            result.value = (result.value * 10) + (ch - '0');

            if (++i >= element.length) {
                break;
            }

            ch = element[i];
        }

        result.pos = i;

        return result;
    }

    /**
    * Adds a group of valid values to the lookup table for the specified field. This method
    * handles ranges that increase in arbitrary step sizes. It is also possible to add a single
    * value by specifying a range with the same start and end values.
    *
    * @param start The starting value for the range. Supplying a value that is less than zero
    * will cause the minimum allowable value for the specified field to be used as the start value.
    * @param end   The maximum value that can be added (ie the upper bound). If the step size is
    * greater than one, this maximum value may not necessarily end up being added. Supplying a
    * value that is less than zero will cause the maximum allowable value for the specified field
    * to be used as the upper bound.
    * @param field The field that the values should be added to.
    * @param interval Specifies the step size for the range. Any values less than one will be
    * treated as a single step interval.
    */
    private void addToLookup(int start, int end, int field, int interval) throws ParseException {
        // deal with the supplied range
        if (start == end) {
            if (start < 0) {
                // We're setting the entire range of values
                start = lookupMin[field] = MIN_VALUE[field];
                end = lookupMax[field] = MAX_VALUE[field];

                if (interval <= 1) {
                    lookup[field] = Long.MAX_VALUE;
                    return;
                }
            } else {
                // We're only setting a single value - check that it is in range
                if (start < MIN_VALUE[field]) {
                    throw new ParseException("Value " + start + " in field " + field + " is lower than the minimum allowable value for this field (min=" + MIN_VALUE[field] + ")", 0);
                } else if (start > MAX_VALUE[field]) {
                    throw new ParseException("Value " + start + " in field " + field + " is higher than the maximum allowable value for this field (max=" + MAX_VALUE[field] + ")", 0);
                }
            }
        } else {
            // For ranges, if the start is bigger than the end value then swap them over
            if (start > end) {
                end ^= start;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -