View Javadoc

1   package org.apache.turbine.services.intake.validator;
2   
3   /*
4    * Copyright 2001-2004 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License")
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
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>&nbsp;</td></tr>
40   * <tr><td>formatx</td><td>see SimpleDateFormat javadoc</td>
41   * <td>&nbsp;</td></tr>
42   * <tr><td colspan=3>where x is &gt;= 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; // for
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 &gt;= 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                 // ignore
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                 // ignore
217             }
218         }
219 
220         if (date == null && df != null)
221         {
222             date = df.parse(s);
223         }
224 
225         // if the date still has not been parsed at this point, throw
226         // a ParseException.
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     // **                Bean accessor methods                   **
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 }