From ba036319aa2e924d2cde3a66e5b583cc51a44162 Mon Sep 17 00:00:00 2001
From: Chris Ridd <chris.ridd@forgerock.com>
Date: Thu, 27 Nov 2014 13:20:50 +0000
Subject: [PATCH] Fix OPENDJ-1614 (CR-5290) Improve crontab(5) support in recurring tasks
---
opendj3-server-dev/src/server/org/opends/server/backends/task/RecurringTask.java | 127 +++++++++++++++++++++++++-----------------
1 files changed, 76 insertions(+), 51 deletions(-)
diff --git a/opendj3-server-dev/src/server/org/opends/server/backends/task/RecurringTask.java b/opendj3-server-dev/src/server/org/opends/server/backends/task/RecurringTask.java
index 7280893..de0431b 100644
--- a/opendj3-server-dev/src/server/org/opends/server/backends/task/RecurringTask.java
+++ b/opendj3-server-dev/src/server/org/opends/server/backends/task/RecurringTask.java
@@ -25,6 +25,7 @@
* Portions Copyright 2014 ForgeRock AS
*/
package org.opends.server.backends.task;
+
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
@@ -37,6 +38,7 @@
import java.util.List;
import java.util.StringTokenizer;
+import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.Attribute;
@@ -108,23 +110,20 @@
*/
private static enum TaskTab {MINUTE, HOUR, DAY, MONTH, WEEKDAY};
- private final static int MINUTE_INDEX = 0;
- private final static int HOUR_INDEX = 1;
- private final static int DAY_INDEX = 2;
- private final static int MONTH_INDEX = 3;
- private final static int WEEKDAY_INDEX = 4;
+ private static final int MINUTE_INDEX = 0;
+ private static final int HOUR_INDEX = 1;
+ private static final int DAY_INDEX = 2;
+ private static final int MONTH_INDEX = 3;
+ private static final int WEEKDAY_INDEX = 4;
+
+ // Wildcard match pattern.
+ private static final Pattern wildcardPattern = Pattern.compile("^\\*(?:/(\\d+))?");
// Exact match pattern.
- private static final Pattern exactPattern =
- Pattern.compile("\\d+");
+ private static final Pattern exactPattern = Pattern.compile("(\\d+)");
// Range match pattern.
- private static final Pattern rangePattern =
- Pattern.compile("\\d+[-]\\d+");
-
- // List match pattern.
- private static final Pattern listPattern =
- Pattern.compile("^(\\d+,)(.*)(\\d+)$");
+ private static final Pattern rangePattern = Pattern.compile("(\\d+)-(\\d+)(?:/(\\d+))?");
// Boolean arrays holding task tab slots.
private final boolean[] minutesArray;
@@ -588,6 +587,7 @@
/**
* Parse and validate recurring task schedule field.
+ *
* @param tabField recurring task schedule field in crontab(5) format.
* @param minValue minimum value allowed for this field.
* @param maxValue maximum value allowed for this field.
@@ -601,58 +601,83 @@
boolean[] valueList = new boolean[maxValue + 1];
Arrays.fill(valueList, false);
- // Blanket.
- if (tabField.equals("*")) {
- for (int i = minValue; i <= maxValue; i++) {
+ // Wildcard with optional increment.
+ Matcher m = wildcardPattern.matcher(tabField);
+ if (m.matches() && m.groupCount() == 1)
+ {
+ String stepString = m.group(1);
+ int increment = isValueAbsent(stepString) ? 1 : Integer.parseInt(stepString);
+ for (int i = minValue; i <= maxValue; i += increment)
+ {
valueList[i] = true;
}
return valueList;
}
- // Exact.
- if (exactPattern.matcher(tabField).matches()) {
- int value = Integer.parseInt(tabField);
- if ((value >= minValue) && (value <= maxValue)) {
- valueList[value] = true;
- return valueList;
- }
- throw new IllegalArgumentException();
- }
-
- // Range.
- if (rangePattern.matcher(tabField).matches()) {
- StringTokenizer st = new StringTokenizer(tabField, "-");
- int startValue = Integer.parseInt(st.nextToken());
- int endValue = Integer.parseInt(st.nextToken());
- if ((startValue < endValue) &&
- ((startValue >= minValue) && (endValue <= maxValue)))
- {
- for (int i = startValue; i <= endValue; i++) {
- valueList[i] = true;
- }
- return valueList;
- }
- throw new IllegalArgumentException();
- }
-
// List.
- if (listPattern.matcher(tabField).matches()) {
- StringTokenizer st = new StringTokenizer(tabField, ",");
- while (st.hasMoreTokens()) {
- int value = Integer.parseInt(st.nextToken());
- if ((value >= minValue) && (value <= maxValue)) {
- valueList[value] = true;
- } else {
+ for (String listVal : tabField.split(","))
+ {
+ // Single number.
+ m = exactPattern.matcher(listVal);
+ if (m.matches() && m.groupCount() == 1)
+ {
+ String exactValue = m.group(1);
+ if (isValueAbsent(exactValue))
+ {
throw new IllegalArgumentException();
}
+ int value = Integer.parseInt(exactValue);
+ if (value < minValue || value > maxValue)
+ {
+ throw new IllegalArgumentException();
+ }
+ valueList[value] = true;
+ continue;
}
- return valueList;
+
+ // Range of numbers with optional increment.
+ m = rangePattern.matcher(listVal);
+ if (m.matches() && m.groupCount() == 3) {
+ String startString = m.group(1);
+ String endString = m.group(2);
+ String stepString = m.group(3);
+ int increment = isValueAbsent(stepString) ? 1 : Integer.parseInt(stepString);
+ if (isValueAbsent(startString) || isValueAbsent(endString))
+ {
+ throw new IllegalArgumentException();
+ }
+ int startValue = Integer.parseInt(startString);
+ int endValue = Integer.parseInt(endString);
+ if (startValue > endValue || startValue < minValue || endValue > maxValue)
+ {
+ throw new IllegalArgumentException();
+ }
+ for (int i = startValue; i <= endValue; i += increment)
+ {
+ valueList[i] = true;
+ }
+ continue;
+ }
+
+ // Can only have a list of numbers and ranges.
+ throw new IllegalArgumentException();
}
- throw new IllegalArgumentException();
+ return valueList;
}
/**
+ * Check if a String from a Matcher group is absent. Matcher returns empty strings
+ * for optional groups that are absent.
+ *
+ * @param s A string returned from Matcher.group()
+ * @return true if the string is unusable, false if it is usable.
+ */
+ private static boolean isValueAbsent(String s)
+ {
+ return (s == null || s.length() == 0) ? true : false;
+ }
+ /**
* Get next recurring slot from the range.
* @param timesList the range.
* @param fromNow the current slot.
--
Gitblit v1.10.0