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<String> specifiedDays;
42
43
44
45
46
47
48 public CronDayOfWeekEntry(String dayOfWeekEntry)
49 {
50 specifiedDays = new ArrayList<String>();
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 StringBuilder result = new StringBuilder();
84 int i = 0;
85 for (Iterator<String> iterator = specifiedDays.iterator(); iterator.hasNext(); i++)
86 {
87 String day = 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 (String dayStr : days)
175 {
176 String day = getDayForValue(dayStr);
177 if (day != null)
178 {
179 specifiedDays.add(day);
180 }
181 else
182 {
183 log.debug("A day of week was specified that can not be mapped: " + dayStr);
184 valid = false;
185 break;
186 }
187 }
188 }
189 }
190
191 private void parseOrdinalValue(String dayOfWeekEntry)
192 {
193 String[] strings = StringUtils.split(dayOfWeekEntry, ORDINAL_SEPARATOR);
194 if (strings == null || strings.length != 2)
195 {
196 log.debug("The ordinal value specifed was not of the correct form: " + dayOfWeekEntry);
197 valid = false;
198 }
199 else
200 {
201
202 String dayString = getDayForValue(strings[0]);
203
204 if (dayString != null)
205 {
206 specifiedDays.add(dayString);
207
208
209 String secondString = strings[1].toUpperCase();
210 if (VALID_NUMERIC_ORDINAL_VALUES.contains(secondString))
211 {
212 ordinal = secondString;
213 }
214 else
215 {
216 log.debug("invalid ordinal value " + ordinal);
217 valid = false;
218 }
219 }
220 }
221 }
222
223 private String getDayForValue(String dayString)
224 {
225 if (VALID_DAYS_MAP.values().contains(dayString.toUpperCase()))
226 {
227 return dayString;
228 }
229 else if (VALID_DAYS_MAP.containsKey(dayString))
230 {
231 return (String) VALID_DAYS_MAP.get(dayString);
232 }
233 log.debug("Unable to resolve a day of week for the string: " + dayString);
234 valid = false;
235 return null;
236 }
237 }