1 package com.atlassian.core.cron.parser;
2
3 import com.atlassian.core.util.collection.EasyList;
4 import com.atlassian.core.util.map.EasyMap;
5 import org.apache.commons.lang.StringUtils;
6 import org.apache.log4j.Logger;
7
8 import java.util.ArrayList;
9 import java.util.Iterator;
10 import java.util.List;
11 import java.util.Map;
12
13
14
15
16
17
18
19
20
21
22
23 public class CronDayOfWeekEntry
24 {
25
26 private static final Logger log = Logger.getLogger(CronDayOfWeekEntry.class);
27
28 private static final String ORDINAL_SEPARATOR = "#";
29 private static final String LIST_SEPARATOR = ",";
30
31 private static final String LAST = "L";
32
33 private static final Map VALID_DAYS_MAP = EasyMap.build("MON", "2", "TUE", "3", "WED", "4", "THU", "5", "FRI", "6", "SAT", "7", "SUN", "1");
34 private static final List VALID_NUMERIC_ORDINAL_VALUES = EasyList.build("1", "2", "3", "4");
35
36
37 private static final String VALID_CHARACTERS = "MONTUEWEDTHUFRISATSUN1234567L#,?*";
38
39 private boolean valid = true;
40 private String ordinal = null;
41 private final List specifiedDays;
42
43
44
45
46
47
48 public CronDayOfWeekEntry(String dayOfWeekEntry)
49 {
50 specifiedDays = new ArrayList();
51 parseEntry(dayOfWeekEntry);
52 }
53
54
55
56
57
58
59
60 public boolean isDaySpecified(String dayStr)
61 {
62 String day = getDayForValue(dayStr);
63 return day != null && specifiedDays.contains(day);
64 }
65
66
67
68
69
70
71 public String getDayInMonthOrdinal()
72 {
73 return ordinal;
74 }
75
76
77
78
79
80
81 public String getDaysAsNumbers()
82 {
83 StringBuffer result = new StringBuffer();
84 int i = 0;
85 for (Iterator iterator = specifiedDays.iterator(); iterator.hasNext(); i++)
86 {
87 String day = (String) iterator.next();
88 result.append(day);
89 if (i + 1 < specifiedDays.size())
90 {
91 result.append(",");
92 }
93 }
94 return result.toString();
95 }
96
97
98
99
100 public boolean isValid()
101 {
102 return valid;
103 }
104
105 private void parseEntry(String dayOfWeekEntry)
106 {
107 if (StringUtils.isBlank(dayOfWeekEntry))
108 {
109 log.debug("Tried to create a CronDayOfWeek with empty or null string.");
110 valid = false;
111 }
112 else if (!StringUtils.containsOnly(dayOfWeekEntry.toUpperCase(), VALID_CHARACTERS))
113 {
114 log.debug("Tried to create a CronDayOfWeek with invalid characters: " + dayOfWeekEntry);
115 valid = false;
116 }
117 else
118 {
119 dayOfWeekEntry = dayOfWeekEntry.toUpperCase();
120
121 if (StringUtils.contains(dayOfWeekEntry, ORDINAL_SEPARATOR))
122 {
123 parseOrdinalValue(dayOfWeekEntry);
124 }
125
126 else if (StringUtils.contains(dayOfWeekEntry, LIST_SEPARATOR))
127 {
128 parseDaysOfWeek(dayOfWeekEntry);
129 }
130 else if (StringUtils.contains(dayOfWeekEntry, LAST))
131 {
132 parseLastDayOfWeek(dayOfWeekEntry);
133 }
134 else {
135 specifiedDays.add(dayOfWeekEntry);
136 }
137 }
138 }
139
140 private void parseLastDayOfWeek(String dayOfWeekEntry)
141 {
142 if (!dayOfWeekEntry.endsWith(LAST))
143 {
144 log.debug("The L character which specifies last is not at the end of the day of week string.");
145 valid = false;
146 }
147 else
148 {
149 ordinal = LAST;
150 String dayOfWeekStr = dayOfWeekEntry.substring(0, dayOfWeekEntry.length() - 1);
151 String dayOfWeek = getDayForValue(dayOfWeekStr);
152 if (dayOfWeek != null)
153 {
154 specifiedDays.add(dayOfWeek);
155 }
156 else
157 {
158 log.debug("The value specfied as a day of week was invalid: " + dayOfWeekStr);
159 valid = false;
160 }
161 }
162 }
163
164 private void parseDaysOfWeek(String dayOfWeekEntry)
165 {
166 String[] days = StringUtils.split(dayOfWeekEntry, LIST_SEPARATOR);
167 if (days == null || days.length > 7)
168 {
169 log.debug("The days of week has specified more than 7, this is not valid: " + dayOfWeekEntry);
170 valid = false;
171 }
172 else
173 {
174 for (int i = 0; i < days.length; i++)
175 {
176 String dayStr = days[i];
177 String day = getDayForValue(dayStr);
178 if (day != null)
179 {
180 specifiedDays.add(day);
181 }
182 else
183 {
184 log.debug("A day of week was specified that can not be mapped: " + dayStr);
185 valid = false;
186 break;
187 }
188 }
189 }
190 }
191
192 private void parseOrdinalValue(String dayOfWeekEntry)
193 {
194 String[] strings = StringUtils.split(dayOfWeekEntry, ORDINAL_SEPARATOR);
195 if (strings == null || strings.length != 2)
196 {
197 log.debug("The ordinal value specifed was not of the correct form: " + dayOfWeekEntry);
198 valid = false;
199 }
200 else
201 {
202
203 String dayString = getDayForValue(strings[0]);
204
205 if (dayString != null)
206 {
207 specifiedDays.add(dayString);
208
209
210 String secondString = strings[1].toUpperCase();
211 if (VALID_NUMERIC_ORDINAL_VALUES.contains(secondString))
212 {
213 ordinal = secondString;
214 }
215 else
216 {
217 log.debug("invalid ordinal value " + ordinal);
218 valid = false;
219 }
220 }
221 }
222 }
223
224 private String getDayForValue(String dayString)
225 {
226 if (VALID_DAYS_MAP.values().contains(dayString.toUpperCase()))
227 {
228 return dayString;
229 }
230 else if (VALID_DAYS_MAP.containsKey(dayString))
231 {
232 return (String) VALID_DAYS_MAP.get(dayString);
233 }
234 log.debug("Unable to resolve a day of week for the string: " + dayString);
235 valid = false;
236 return null;
237 }
238 }