|
17 | 17 | package org.springframework.scheduling.support; |
18 | 18 |
|
19 | 19 | import java.util.ArrayList; |
20 | | -import java.util.Arrays; |
21 | 20 | import java.util.BitSet; |
22 | 21 | import java.util.Calendar; |
23 | 22 | import java.util.Collections; |
|
26 | 25 | import java.util.List; |
27 | 26 | import java.util.TimeZone; |
28 | 27 |
|
| 28 | +import org.springframework.lang.Nullable; |
29 | 29 | import org.springframework.util.StringUtils; |
30 | 30 |
|
31 | 31 | /** |
|
50 | 50 | * |
51 | 51 | * @author Dave Syer |
52 | 52 | * @author Juergen Hoeller |
| 53 | + * @author Ruslan Sibgatullin |
53 | 54 | * @since 3.0 |
54 | 55 | * @see CronTrigger |
55 | 56 | */ |
56 | 57 | public class CronSequenceGenerator { |
57 | 58 |
|
58 | 59 | private final String expression; |
59 | 60 |
|
| 61 | + @Nullable |
60 | 62 | private final TimeZone timeZone; |
61 | 63 |
|
62 | 64 | private final BitSet months = new BitSet(12); |
@@ -96,6 +98,12 @@ public CronSequenceGenerator(String expression, TimeZone timeZone) { |
96 | 98 | parse(expression); |
97 | 99 | } |
98 | 100 |
|
| 101 | + private CronSequenceGenerator(String expression, String[] fields) { |
| 102 | + this.expression = expression; |
| 103 | + this.timeZone = null; |
| 104 | + doParse(fields); |
| 105 | + } |
| 106 | + |
99 | 107 |
|
100 | 108 | /** |
101 | 109 | * Return the cron pattern that this sequence generator has been built for. |
@@ -234,7 +242,7 @@ private int findNext(BitSet bits, int value, Calendar calendar, int field, int n |
234 | 242 | // roll over if needed |
235 | 243 | if (nextValue == -1) { |
236 | 244 | calendar.add(nextField, 1); |
237 | | - reset(calendar, Arrays.asList(field)); |
| 245 | + reset(calendar, Collections.singletonList(field)); |
238 | 246 | nextValue = bits.nextSetBit(0); |
239 | 247 | } |
240 | 248 | if (nextValue != value) { |
@@ -265,12 +273,17 @@ private void parse(String expression) throws IllegalArgumentException { |
265 | 273 | throw new IllegalArgumentException(String.format( |
266 | 274 | "Cron expression must consist of 6 fields (found %d in \"%s\")", fields.length, expression)); |
267 | 275 | } |
| 276 | + doParse(fields); |
| 277 | + } |
| 278 | + |
| 279 | + private void doParse(String[] fields) { |
268 | 280 | setNumberHits(this.seconds, fields[0], 0, 60); |
269 | 281 | setNumberHits(this.minutes, fields[1], 0, 60); |
270 | 282 | setNumberHits(this.hours, fields[2], 0, 24); |
271 | 283 | setDaysOfMonth(this.daysOfMonth, fields[3]); |
272 | 284 | setMonths(this.months, fields[4]); |
273 | 285 | setDays(this.daysOfWeek, replaceOrdinals(fields[5], "SUN,MON,TUE,WED,THU,FRI,SAT"), 8); |
| 286 | + |
274 | 287 | if (this.daysOfWeek.get(7)) { |
275 | 288 | // Sunday can be represented as 0 or 7 |
276 | 289 | this.daysOfWeek.set(0); |
@@ -388,19 +401,29 @@ private int[] getRange(String field, int min, int max) { |
388 | 401 |
|
389 | 402 | /** |
390 | 403 | * Determine whether the specified expression represents a valid cron pattern. |
391 | | - * <p>Specifically, this method verifies that the expression contains six |
392 | | - * fields separated by single spaces. |
393 | 404 | * @param expression the expression to evaluate |
394 | 405 | * @return {@code true} if the given expression is a valid cron expression |
395 | 406 | * @since 4.3 |
396 | 407 | */ |
397 | | - public static boolean isValidExpression(String expression) { |
| 408 | + public static boolean isValidExpression(@Nullable String expression) { |
| 409 | + if (expression == null) { |
| 410 | + return false; |
| 411 | + } |
398 | 412 | String[] fields = StringUtils.tokenizeToStringArray(expression, " "); |
399 | | - return areValidCronFields(fields); |
| 413 | + if (!areValidCronFields(fields)) { |
| 414 | + return false; |
| 415 | + } |
| 416 | + try { |
| 417 | + new CronSequenceGenerator(expression, fields); |
| 418 | + return true; |
| 419 | + } |
| 420 | + catch (IllegalArgumentException ex) { |
| 421 | + return false; |
| 422 | + } |
400 | 423 | } |
401 | 424 |
|
402 | | - private static boolean areValidCronFields(String[] fields) { |
403 | | - return (fields.length == 6); |
| 425 | + private static boolean areValidCronFields(@Nullable String[] fields) { |
| 426 | + return (fields != null && fields.length == 6); |
404 | 427 | } |
405 | 428 |
|
406 | 429 |
|
|
0 commit comments