1 package org.apache.turbine.services.intake.validator;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.text.DateFormat;
23 import java.text.ParseException;
24 import java.text.SimpleDateFormat;
25
26 import java.util.ArrayList;
27 import java.util.Date;
28 import java.util.List;
29 import java.util.Map;
30
31 import org.apache.commons.lang.StringUtils;
32
33 import org.apache.turbine.services.intake.IntakeException;
34
35 /***
36 * Validates numbers with the following constraints in addition to those
37 * listed in DefaultValidator.
38 *
39 * <table>
40 * <tr><th>Name</th><th>Valid Values</th><th>Default Value</th></tr>
41 * <tr><td>format</td><td>see SimpleDateFormat javadoc</td>
42 * <td> </td></tr>
43 * <tr><td>formatx</td><td>see SimpleDateFormat javadoc</td>
44 * <td> </td></tr>
45 * <tr><td colspan=3>where x is >= 1 to specify multiple date
46 * formats. Only one format rule should have a message</td></tr>
47 * <tr><td>flexible</td><td>true, as long as DateFormat can parse the date,
48 * allow it, and false</td>
49 * <td>false</td></tr>
50 * </table>
51 *
52 * @author <a href="mailto:jmcnally@collab.net">John McNally</a>
53 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
54 * @author <a href="mailto:Colin.Chalmers@maxware.nl">Colin Chalmers</a>
55 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
56 * @version $Id: DateStringValidator.java 534527 2007-05-02 16:10:59Z tv $
57 */
58 public class DateStringValidator
59 extends DefaultValidator
60 {
61 private static final String DEFAULT_DATE_MESSAGE =
62 "Date could not be parsed";
63
64 /*** */
65 private List dateFormats = null;
66
67 /*** */
68 private String dateFormatMessage = null;
69
70 /*** */
71 private boolean flexible = false;
72
73 /*** */
74 private DateFormat df = null;
75
76 /*** */
77 private SimpleDateFormat sdf = null;
78
79 public DateStringValidator(final Map paramMap)
80 throws IntakeException
81 {
82 init(paramMap);
83 }
84
85 /***
86 * Default Constructor
87 */
88 public DateStringValidator()
89 {
90 dateFormats = new ArrayList(5);
91 }
92
93 /***
94 * Constructor to use when initialising Object
95 *
96 * @param paramMap
97 * @throws InvalidMaskException
98 */
99 public void init(final Map paramMap)
100 throws InvalidMaskException
101 {
102 super.init(paramMap);
103
104 Constraint constraint = (Constraint) paramMap.get(FORMAT_RULE_NAME);
105
106 if (constraint != null)
107 {
108 dateFormats.add(constraint.getValue());
109 setDateFormatMessage(constraint.getMessage());
110 }
111
112 for(int i = 1 ;; i++)
113 {
114 constraint = (Constraint) paramMap.get(FORMAT_RULE_NAME + i);
115
116 if (constraint == null)
117 {
118 break;
119 }
120
121 dateFormats.add(constraint.getValue());
122 setDateFormatMessage(constraint.getMessage());
123 }
124
125 if (StringUtils.isEmpty(dateFormatMessage))
126 {
127 dateFormatMessage = DEFAULT_DATE_MESSAGE;
128 }
129
130 constraint = (Constraint) paramMap.get(FLEXIBLE_RULE_NAME);
131
132 if (constraint != null)
133 {
134 flexible = Boolean.valueOf(constraint.getValue()).booleanValue();
135 }
136
137 if (dateFormats.size() == 0)
138 {
139 df = DateFormat.getInstance();
140 sdf = null;
141 df.setLenient(flexible);
142 }
143 else
144 {
145 sdf = new SimpleDateFormat();
146 df = null;
147 sdf.setLenient(flexible);
148 }
149 }
150
151 /***
152 * Determine whether a testValue meets the criteria specified
153 * in the constraints defined for this validator
154 *
155 * @param testValue a <code>String</code> to be tested
156 * @exception ValidationException containing an error message if the
157 * testValue did not pass the validation tests.
158 */
159 public void assertValidity(final String testValue)
160 throws ValidationException
161 {
162 super.assertValidity(testValue);
163
164 if (required || StringUtils.isNotEmpty(testValue))
165 {
166 try
167 {
168 parse(testValue);
169 }
170 catch (ParseException e)
171 {
172 errorMessage = dateFormatMessage;
173 throw new ValidationException(dateFormatMessage);
174 }
175 }
176 }
177
178 /***
179 * Parses the String s according to the rules/formats for this validator.
180 * The formats provided by the "formatx" rules (where x is >= 1) are
181 * used <strong>before</strong> the "format" rules to allow for a display
182 * format that includes a 4 digit year, but that will parse the date using
183 * a format that accepts 2 digit years.
184 *
185 * @throws ParseException indicates that the string could not be
186 * parsed into a date.
187 */
188 public Date parse(final String s)
189 throws ParseException
190 {
191 Date date = null;
192
193 if (s == null)
194 {
195 throw new ParseException("Input string was null", -1);
196 }
197
198 if (sdf != null)
199 {
200
201
202 for (int i = 1 ; i < dateFormats.size() - 1; i++)
203 {
204 sdf.applyPattern((String) dateFormats.get(i));
205
206 try
207 {
208 date = sdf.parse(s);
209 break;
210 }
211 catch (ParseException e)
212 {
213
214 }
215 }
216
217
218
219
220
221 if (date == null)
222 {
223 sdf.applyPattern((String) dateFormats.get(0));
224
225 try
226 {
227 date = sdf.parse(s);
228 }
229 catch (ParseException e)
230 {
231
232 }
233 }
234 }
235
236
237
238
239 if (date == null && df != null)
240 {
241 date = df.parse(s);
242 }
243
244
245
246 if (date == null)
247 {
248 throw new ParseException("Could not parse the date", 0);
249 }
250
251 return date;
252 }
253
254 /***
255 * Formats a date into a String. The format used is from
256 * the first format rule found for the field.
257 *
258 * @param date the Date object to convert into a string.
259 * @return formatted date
260 */
261 public String format(final Date date)
262 {
263 String s = null;
264 if (date != null)
265 {
266 if (sdf != null)
267 {
268 sdf.applyPattern((String) dateFormats.get(0));
269 s = sdf.format(date);
270 }
271 else
272 {
273 s = df.format(date);
274 }
275 }
276 return s;
277 }
278
279
280
281
282
283
284 /***
285 * Get the value of minLengthMessage.
286 *
287 * @return value of minLengthMessage.
288 */
289 public String getDateFormatMessage()
290 {
291 return dateFormatMessage;
292 }
293
294 /***
295 * Only sets the message if the new message has some information.
296 * So the last setMessage call with valid data wins. But later calls
297 * with null or empty string will not affect a previous valid setting.
298 *
299 * @param message Value to assign to minLengthMessage.
300 */
301 public void setDateFormatMessage(final String message)
302 {
303 if (StringUtils.isNotEmpty(message))
304 {
305 dateFormatMessage = message;
306 }
307 }
308
309 /***
310 * Get the value of dateFormats.
311 *
312 * @return value of dateFormats.
313 */
314 public List getDateFormats()
315 {
316 return dateFormats;
317 }
318
319 /***
320 * Set the value of dateFormats.
321 *
322 * @param formats Value to assign to dateFormats.
323 */
324 public void setDateFormats(final List formats)
325 {
326 this.dateFormats = formats;
327 }
328
329 /***
330 * Get the value of flexible.
331 *
332 * @return value of flexible.
333 */
334 public boolean isFlexible()
335 {
336 return flexible;
337 }
338
339 /***
340 * Set the value of flexible.
341 *
342 * @param flexible Value to assign to flexible.
343 */
344 public void setFlexible(final boolean flexible)
345 {
346 this.flexible = flexible;
347 }
348 }