1 package com.atlassian.scheduler.cron;
2
3 import javax.annotation.Nonnull;
4 import javax.annotation.Nullable;
5
6 /**
7 * Clarifies the reason for failure when a cron expression cannot be parsed.
8 *
9 * @since v1.4
10 */
11 public enum ErrorCode {
12 /**
13 * The cron expression used multiple expressions for the day-of-month, at least one of which used the {@code L}
14 * flag.
15 * This is not supported; the {@code L} flag can only be used when a single expression is given.
16 */
17 COMMA_WITH_LAST_DOM("You cannot use 'L' or 'W' with multiple day-of-month values."),
18
19 /**
20 * The cron expression used multiple expressions for the day-of-week, at least one of which used the {@code L}
21 * flag.
22 * This is not supported; the {@code L} flag can only be used when a single expression is given.
23 */
24 COMMA_WITH_LAST_DOW("You cannot use 'L' with multiple day-of-week values."),
25
26 /**
27 * The cron expression used multiple expressions for the day-of-week, at least one of which used the {@code #}
28 * flag.
29 * This is not supported; the {@code #} flag can only be used when a single expression is given.
30 */
31 COMMA_WITH_NTH_DOW("You cannot use '#' with multiple day-of-week values."),
32
33 /**
34 * The cron expression used multiple expressions for the day-of-month, at least one of which used the {@code W}
35 * flag.
36 * This is not supported; the {@code W} flag can only be used when a single expression is given.
37 */
38 COMMA_WITH_WEEKDAY_DOM("You cannot use 'W' with multiple day-of-month values."),
39
40 /**
41 * The reason of the failure could not be determined.
42 * This indicates that the underlying cause is an unexpected runtime exception and indicates a programming
43 * error in the cron expression parsing.
44 * The {@code value} should be the message from {@code cause}.
45 */
46 INTERNAL_PARSER_FAILURE("Internal parser failure: ", ""),
47
48 /**
49 * The cron expression contained a character that is not legal in the cron expression syntax.
50 * The {@code value} should be the illegal character that was encountered.
51 */
52 ILLEGAL_CHARACTER("Unexpected character: '", "'"),
53
54 /**
55 * The cron expression contained a question-mark (<code>?</code>) followed by another non-whitespace character.
56 * This special value can only be used by itself in the day-of-month or day-of-week field; it cannot be combined
57 * with any other value.
58 * The {@code value} should be the illegal character that was encountered.
59 */
60 ILLEGAL_CHARACTER_AFTER_QM("Illegal character after '?': '", "'"),
61
62 /**
63 * The cron expression contained a hash (<code>#</code>) in the day-of-week column that was not followed by an
64 * integer value from {@code 1} to {@code 5}.
65 */
66 ILLEGAL_CHARACTER_AFTER_HASH("A numeric value between 1 and 5 must follow the '#' option."),
67
68 /**
69 * The cron expression contained a step interval (a value after {@code /}) that was followed by additional
70 * characters in the same field expression.
71 * The step interval must be the last part of a value. The slash (<code>/</code>) must be followed by an
72 * integer. After that, the only legal characters are whitespace or a comma (<code>,</code>) to separate
73 * it from the next value for that field.
74 */
75 ILLEGAL_CHARACTER_AFTER_INTERVAL("Illegal character after '/': '", "'"),
76
77 /**
78 * The cron expression contained a slash (<code>/</code>) that was not followed by an integer value.
79 * A step interval value must be specified, such as {@code /5} in the minutes column to indicate that
80 * the accept values are spaces five minutes apart.
81 */
82 INVALID_STEP("The step interval character '/' must be followed by a positive integer."),
83
84 /**
85 * The cron expression contained an interval step for the day-of-month that was greater than or equal to {@code 31}.
86 * Since this value is large enough to make it impossible to result in a second value with any starting
87 * value in any month, it is not permitted.
88 */
89 INVALID_STEP_DAY_OF_MONTH("The step interval for day-of-month must be less than 31: ", ""),
90
91 /**
92 * The cron expression contained an interval step for the day-of-week that was greater than or equal to {@code 7}.
93 * Since this value is large enough to make it impossible to result in a second value, it is not permitted.
94 */
95 INVALID_STEP_DAY_OF_WEEK("The step interval for day-of-week must be less than 7: ", ""),
96
97 /**
98 * The cron expression contained an interval step for the hour that was greater than or equal to {@code 24}.
99 * Since this value is large enough to make it impossible to result in a second value, it is not permitted.
100 */
101 INVALID_STEP_HOUR("The step interval for hour must be less than 24: ", ""),
102
103 /**
104 * The cron expression contained an interval step for the month that was greater than or equal to {@code 12}.
105 * Since this value is large enough to make it impossible to result in a second value, it is not permitted.
106 */
107 INVALID_STEP_MONTH("The step interval for month must be less than 12: ", ""),
108
109 /**
110 * The cron expression contained an interval step for the second or minute that was greater than or equal to
111 * {@code 60}.
112 * Since this value is large enough to make it impossible to result in a second value, it is not permitted.
113 */
114 INVALID_STEP_SECOND_OR_MINUTE("The step interval for second or minute must be less than 60: ", ""),
115
116 /**
117 * The cron expression contained a sequence of letters that appears to be meant as the name of a month or
118 * day-of-week, but it was malformed.
119 * For example, {@code MO} would be invalid because it is too short.
120 */
121 INVALID_NAME("Invalid name: '", "'"),
122
123 /**
124 * The cron expression contained a sequence of letters that appears to be meant as the name of a month or
125 * day-of-week, but it was specified in one of the other fields.
126 */
127 INVALID_NAME_FIELD("This field does not support names: '", "'"),
128
129 /**
130 * The cron expression contained a sequence that appears to be meant as a name-based range of a month or
131 * day-of-week values, but the end value of the sequence was malformed.
132 * Examples include {@code 3-FRI} or {@code MON-4} or {@code FEB-L}.
133 */
134 INVALID_NAME_RANGE("Cannot specify a range using month or day-of-week names unless a valid name is used"
135 + " for both bounds."),
136
137 /**
138 * The cron expression contained a sequence of letters that appears to be meant as the name of a month,
139 * but the name was not recognized.
140 * Only the three-letter English abbreviations for month names are supported, such as {@code FEB} for
141 * February or {@code SEP} for September.
142 */
143 INVALID_NAME_MONTH("Invalid month name: '", "'"),
144
145 /**
146 * The cron expression contained a sequence of letters that appears to be meant as the name of a day-of-week,
147 * but the name was not recognized.
148 * Only the three-letter English abbreviations for day-of-week names are supported, such as {@code MON} for
149 * Monday or {@code THU} for Thursday. Note that {@code THR} is not accepted.
150 */
151 INVALID_NAME_DAY_OF_WEEK("Invalid day-of-week name: '", "'"),
152
153 /**
154 * The cron expression contained a number in the minute or second field that was outside the supported range
155 * of {@code [0, 59]}.
156 */
157 INVALID_NUMBER_SEC_OR_MIN("The values for seconds and minutes must be from 0 to 59."),
158
159 /**
160 * The cron expression contained a number in the hour field that was outside the supported range
161 * of {@code [0, 23]}.
162 */
163 INVALID_NUMBER_HOUR("The values for hours must be from 0 to 23."),
164
165 /**
166 * The cron expression contained a number in the day-of-month field that was outside the supported range
167 * of {@code [0, 31]}.
168 */
169 INVALID_NUMBER_DAY_OF_MONTH("The values for day-of-month must be from 1 to 31."),
170
171 /**
172 * The cron expression contained an {@code L-x} or {@code L-xW} expression where the value of {@code x}
173 * was more than {@code 30}.
174 * Since {@code 31} or more days before the last day of the month is always in a different month, such
175 * an expression could not possibly ever match.
176 */
177 INVALID_NUMBER_DAY_OF_MONTH_OFFSET("The offset from the last day day of the month must be no more than 30."),
178
179 /**
180 * The cron expression contained a number in the month field that was outside the supported range
181 * of {@code [1, 12]}.
182 */
183 INVALID_NUMBER_MONTH("The values for month must be from 1 to 12."),
184
185 /**
186 * The cron expression contained a number in the day-of-week field that was outside the supported range
187 * of {@code [1, 7]}.
188 */
189 INVALID_NUMBER_DAY_OF_WEEK("The values for day-of-week must be from 1 to 7."),
190
191 /**
192 * The cron expression contained a number in the year field that was outside the supported range
193 * of {@code [1970, 2299]}.
194 */
195 // Note: Currently unused because Quartz does not consider this a problem until it tries to find
196 // the next matching date and gives up because it is more than 100 years in the future. It is
197 // not caught by the parser.
198 INVALID_NUMBER_YEAR("The values for year must be from 1970 to 2299."),
199
200 /**
201 * The cron expression contains a range in the year field that gave the years in reverse order,
202 * such as {@code 2036-2016}.
203 * Reversed ranges are permitted for the other fields and "wrap around" such that {@code NOV-FEB}
204 * means November, December, January, or February. There is no really meaningful way to do that
205 * for the year ranges, so that is not allowed for this field.
206 */
207 INVALID_NUMBER_YEAR_RANGE("Year ranges must specify the earlier year first."),
208
209 /**
210 * The cron expression contained a question-mark (<code>?</code>) in some field other than the day-of-month
211 * or day-of-week.
212 * This special value cannot be used in any other field.
213 */
214 QM_CANNOT_USE_HERE("You can only use '?' for the day-of-month or the day-of-week."),
215
216 /**
217 * The cron expression contained a question-mark (<code>?</code>) for both the day-of-month and the
218 * day-of-week.
219 * One of these fields must be specified, and it is likely that changing either one to {@code *} will
220 * give the intended result.
221 */
222 QM_CANNOT_USE_FOR_BOTH_DAYS("You cannot specify '?' for both the day-of-month and the day-of-week."),
223
224 /**
225 * The cron expression specified values other than {@code ?} for both the day-of-month and the
226 * day-of-week.
227 * Exactly one of these fields must be specified; the other must be disabled by giving {@code ?} as its value.
228 */
229 QM_MUST_USE_FOR_ONE_OF_DAYS("You must use '?' for either the day-of-month or day-of-week."),
230
231 /**
232 * The cron expression contained what looks like an {@code L} flag, but it is in a column that does not
233 * support it or is not in a place that makes sense. For example, you cannot specify {@code L}
234 * for the hour field, and while you could say {@code L-3} as the day-of-month to indicate the third-to-last
235 * day of the month, {@code 3-L} does not make sense.
236 */
237 UNEXPECTED_TOKEN_FLAG_L("The 'L' option was used incorrectly."),
238
239 /**
240 * The cron expression contained what looks like a {@code W} flag, but it is in a column that does not
241 * support it or is not in a place that makes sense. For example, you cannot specify {@code W}
242 * for the hour field, and while you could say {@code 3W} as the day-of-month to indicate the weekday
243 * closest to the third day of the month, {@code 3-W} does not make sense.
244 */
245 UNEXPECTED_TOKEN_FLAG_W("The 'W' option was used incorrectly."),
246
247 /**
248 * The cron expression contained what looks like a {@code #} flag, but it is in a column that does not
249 * support it or is not in a place that makes sense. For example, you cannot specify {@code #}
250 * in the hour field, and while you could say {@code MON#3} as the day-of-week to indicate the third
251 * Monday of the month, {@code #3} by itself does not make sense.
252 */
253 UNEXPECTED_TOKEN_HASH("The '#' option was used incorrectly."),
254
255 /**
256 * The cron expression contained an invalid hyphen (<code>-</code>).
257 * This can only be used for ranges that provide both a starting and ending value, such as {@code 5-8}
258 * or {@code MAY-AUG}, or in the special syntax {@code L-3} that is available for the day-of-month field.
259 */
260 UNEXPECTED_TOKEN_HYPHEN("Ranges specified with '-' must have both a starting and ending value."),
261
262 /**
263 * The cron expression ended without specifying all of the required fields or ended in a way that would
264 * require more characters.
265 * Only the year field is optional; all other fields must be included in the cron expression.
266 * This error code can also be used if the cron expression ended in a way that would have required
267 * more characters to follow, such as a comma (<code>,</code>) or hyphen (<code>-</code>).
268 */
269 UNEXPECTED_END_OF_EXPRESSION("Unexpected end of expression");
270
271 private final String message;
272 private final String suffix;
273
274 private ErrorCode(final String message) {
275 this(message, null);
276 }
277
278 private ErrorCode(final String message, @Nullable final String suffix) {
279 this.message = message;
280 this.suffix = suffix;
281 }
282
283 /**
284 * Renders the standard message for this error code and offending value.
285 */
286 @Nonnull
287 public String toMessage(@Nullable String value) {
288 if (suffix != null) {
289 return message + value + suffix;
290 }
291 return message;
292 }
293 }