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