View Javadoc

1   package com.atlassian.scheduler.cron;
2   
3   import com.atlassian.scheduler.SchedulerServiceException;
4   
5   import javax.annotation.Nonnull;
6   import javax.annotation.Nullable;
7   
8   import static com.google.common.base.MoreObjects.firstNonNull;
9   
10  /**
11   * Signals that there is a syntax error in a given cron expression.
12   *
13   * @since v1.4
14   */
15  @SuppressWarnings("SerializableHasSerializationMethods")
16  public class CronSyntaxException extends SchedulerServiceException {
17      private static final long serialVersionUID = 5594187147397941674L;
18  
19      private final ErrorCode errorCode;
20      private final String cronExpression;
21      private final String value;
22      private final int errorOffset;
23  
24      /**
25       * Internal constructor.  Use a {@link #builder() builder} to construct these.
26       */
27      CronSyntaxException(final Builder builder) {
28          super(builder.toMessage());
29          this.errorCode = firstNonNull(builder.errorCode, ErrorCode.INTERNAL_PARSER_FAILURE);
30          this.cronExpression = firstNonNull(builder.cronExpression, "");
31          this.value = builder.value;
32          this.errorOffset = builder.errorOffset;
33          if (builder.cause != null) {
34              initCause(builder.cause);
35          }
36      }
37  
38      /**
39       * Returns the error code identifying the underlying cause of the parse failure.
40       *
41       * @return the error code identifying the underlying cause of the parse failure.
42       */
43      @Nonnull
44      public ErrorCode getErrorCode() {
45          return errorCode;
46      }
47  
48      /**
49       * Returns the cron expression that could not be parsed.
50       *
51       * @return the cron expression that could not be parsed.
52       */
53      @Nonnull
54      public String getCronExpression() {
55          return cronExpression;
56      }
57  
58      /**
59       * Returns the value that caused the exception to be thrown, if that information is available.
60       * For example, if the day-of-month field specified {@code 4,10-13,42-47}, then the value would be {@code "42"}
61       * because {@code 31} is the maximum value permitted for that field.
62       *
63       * @return the value that caused the exception to be thrown, or {@code null} if that is irrelevant to the
64       * error or if the cause is unknown
65       */
66      @Nullable
67      public String getValue() {
68          return value;
69      }
70  
71      /**
72       * Returns the {@code 0}-based index of the character at which the parse error was identified.
73       *
74       * @return the {@code 0}-based index of the character at which the parse error was identified,
75       * or {@code -1} if the index is not known.
76       */
77      public int getErrorOffset() {
78          return errorOffset;
79      }
80  
81      /**
82       * Returns a builder for constructing a {@code CronSyntaxExpression}.
83       *
84       * @return a builder for constructing a {@code CronSyntaxExpression}.
85       */
86      public static Builder builder() {
87          return new Builder();
88      }
89  
90  
91      /**
92       * A builder for constructing a {@link com.atlassian.scheduler.cron.CronSyntaxException}.
93       */
94      public static class Builder {
95          String cronExpression;
96          String value;
97          ErrorCode errorCode;
98          int errorOffset = -1;
99          Throwable cause;
100 
101         Builder() {
102         }
103 
104         /**
105          * Sets the cron expression that caused the exception.
106          * If left unspecified, then {@code ""} is used.
107          */
108         public Builder cronExpression(@Nullable String cronExpression) {
109             this.cronExpression = cronExpression;
110             return this;
111         }
112 
113         /**
114          * Sets the value that caused the exception.
115          * For example, if the month field contained {@code FEB-XYZ}, then {@code "XYZ"} should be set for the value.
116          */
117         public Builder value(@Nullable String value) {
118             this.value = value;
119             return this;
120         }
121 
122         /**
123          * Sets the value that caused the exception.
124          * This convenience method is equivalent to {@link #value(String) value(String.valueOf(value))}.
125          */
126         public Builder value(char value) {
127             this.value = String.valueOf(value);
128             return this;
129         }
130 
131         /**
132          * Sets the error code for the exception.
133          * If left unspecified, then {@link ErrorCode#INTERNAL_PARSER_FAILURE} is used.
134          */
135         public Builder errorCode(@Nullable ErrorCode errorCode) {
136             this.errorCode = errorCode;
137             return this;
138         }
139 
140         /**
141          * Sets the error code for the exception.
142          * If left unspecified, then {@code -1} is used.
143          */
144         public Builder errorOffset(int errorOffset) {
145             this.errorOffset = (errorOffset >= 0) ? errorOffset : -1;
146             return this;
147         }
148 
149         /**
150          * Sets the cause of the exception.
151          */
152         public Builder cause(@Nullable Throwable cause) {
153             this.cause = cause;
154             return this;
155         }
156 
157         /**
158          * Returns the completed exception.
159          *
160          * @return the completed exception.
161          */
162         public CronSyntaxException build() {
163             return new CronSyntaxException(this);
164         }
165 
166         @Nonnull
167         String toMessage() {
168             return errorCode.toMessage(value);
169         }
170     }
171 }