001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.validator;
018    
019    import java.io.Serializable;
020    import java.util.Date;
021    import java.util.Locale;
022    import java.text.DateFormat;
023    import java.text.SimpleDateFormat;
024    import java.text.NumberFormat;
025    import java.text.ParseException;
026    import java.text.ParsePosition;
027    import org.apache.commons.logging.Log;
028    import org.apache.commons.logging.LogFactory;
029    
030    /**
031     *  This class contains basic methods for performing validations that return the
032     *  correctly typed class based on the validation performed.
033     *
034     * @version $Revision: 493905 $ $Date: 2007-01-08 03:11:38 +0100 (Mo, 08. Jan 2007) $
035     */
036    public class GenericTypeValidator implements Serializable {
037    
038        /**
039         *  Checks if the value can safely be converted to a byte primitive.
040         *
041         *@param  value  The value validation is being performed on.
042         *@return the converted Byte value.
043         */
044        public static Byte formatByte(String value) {
045            if (value == null) {
046                return null;
047            }
048    
049            try {
050                return new Byte(value);
051            } catch (NumberFormatException e) {
052                return null;
053            }
054    
055        }
056    
057        /**
058         *  Checks if the value can safely be converted to a byte primitive.
059         *
060         *@param  value   The value validation is being performed on.
061         *@param  locale  The locale to use to parse the number (system default if
062         *      null)
063         *@return the converted Byte value.
064         */
065        public static Byte formatByte(String value, Locale locale) {
066            Byte result = null;
067    
068            if (value != null) {
069                NumberFormat formatter = null;
070                if (locale != null) {
071                    formatter = NumberFormat.getNumberInstance(locale);
072                } else {
073                    formatter = NumberFormat.getNumberInstance(Locale.getDefault());
074                }
075                formatter.setParseIntegerOnly(true);
076                ParsePosition pos = new ParsePosition(0);
077                Number num = formatter.parse(value, pos);
078    
079                // If there was no error      and we used the whole string
080                if (pos.getErrorIndex() == -1 && pos.getIndex() == value.length()) {
081                    if (num.doubleValue() >= Byte.MIN_VALUE &&
082                        num.doubleValue() <= Byte.MAX_VALUE) {
083                        result = new Byte(num.byteValue());
084                    }
085                }
086            }
087    
088            return result;
089        }
090    
091        /**
092         *  Checks if the value can safely be converted to a short primitive.
093         *
094         *@param  value  The value validation is being performed on.
095         *@return the converted Short value.
096         */
097        public static Short formatShort(String value) {
098            if (value == null) {
099                return null;
100            }
101    
102            try {
103                return new Short(value);
104            } catch (NumberFormatException e) {
105                return null;
106            }
107    
108        }
109    
110        /**
111         *  Checks if the value can safely be converted to a short primitive.
112         *
113         *@param  value   The value validation is being performed on.
114         *@param  locale  The locale to use to parse the number (system default if
115         *      null)vv
116         *@return the converted Short value.
117         */
118        public static Short formatShort(String value, Locale locale) {
119            Short result = null;
120    
121            if (value != null) {
122                NumberFormat formatter = null;
123                if (locale != null) {
124                    formatter = NumberFormat.getNumberInstance(locale);
125                } else {
126                    formatter = NumberFormat.getNumberInstance(Locale.getDefault());
127                }
128                formatter.setParseIntegerOnly(true);
129                ParsePosition pos = new ParsePosition(0);
130                Number num = formatter.parse(value, pos);
131    
132                // If there was no error      and we used the whole string
133                if (pos.getErrorIndex() == -1 && pos.getIndex() == value.length()) {
134                    if (num.doubleValue() >= Short.MIN_VALUE &&
135                        num.doubleValue() <= Short.MAX_VALUE) {
136                        result = new Short(num.shortValue());
137                    }
138                }
139            }
140    
141            return result;
142        }
143    
144        /**
145         *  Checks if the value can safely be converted to a int primitive.
146         *
147         *@param  value  The value validation is being performed on.
148         *@return the converted Integer value.
149         */
150        public static Integer formatInt(String value) {
151            if (value == null) {
152                return null;
153            }
154    
155            try {
156                return new Integer(value);
157            } catch (NumberFormatException e) {
158                return null;
159            }
160    
161        }
162    
163        /**
164         *  Checks if the value can safely be converted to an int primitive.
165         *
166         *@param  value   The value validation is being performed on.
167         *@param  locale  The locale to use to parse the number (system default if
168         *      null)
169         *@return the converted Integer value.
170         */
171        public static Integer formatInt(String value, Locale locale) {
172            Integer result = null;
173    
174            if (value != null) {
175                NumberFormat formatter = null;
176                if (locale != null) {
177                    formatter = NumberFormat.getNumberInstance(locale);
178                } else {
179                    formatter = NumberFormat.getNumberInstance(Locale.getDefault());
180                }
181                formatter.setParseIntegerOnly(true);
182                ParsePosition pos = new ParsePosition(0);
183                Number num = formatter.parse(value, pos);
184    
185                // If there was no error      and we used the whole string
186                if (pos.getErrorIndex() == -1 && pos.getIndex() == value.length()) {
187                    if (num.doubleValue() >= Integer.MIN_VALUE &&
188                        num.doubleValue() <= Integer.MAX_VALUE) {
189                        result = new Integer(num.intValue());
190                    }
191                }
192            }
193    
194            return result;
195        }
196    
197        /**
198         *  Checks if the value can safely be converted to a long primitive.
199         *
200         *@param  value  The value validation is being performed on.
201         *@return the converted Long value.
202         */
203        public static Long formatLong(String value) {
204            if (value == null) {
205                return null;
206            }
207    
208            try {
209                return new Long(value);
210            } catch (NumberFormatException e) {
211                return null;
212            }
213    
214        }
215    
216        /**
217         *  Checks if the value can safely be converted to a long primitive.
218         *
219         *@param  value   The value validation is being performed on.
220         *@param  locale  The locale to use to parse the number (system default if
221         *      null)
222         *@return the converted Long value.
223         */
224        public static Long formatLong(String value, Locale locale) {
225            Long result = null;
226    
227            if (value != null) {
228                NumberFormat formatter = null;
229                if (locale != null) {
230                    formatter = NumberFormat.getNumberInstance(locale);
231                } else {
232                    formatter = NumberFormat.getNumberInstance(Locale.getDefault());
233                }
234                formatter.setParseIntegerOnly(true);
235                ParsePosition pos = new ParsePosition(0);
236                Number num = formatter.parse(value, pos);
237    
238                // If there was no error      and we used the whole string
239                if (pos.getErrorIndex() == -1 && pos.getIndex() == value.length()) {
240                    if (num.doubleValue() >= Long.MIN_VALUE &&
241                        num.doubleValue() <= Long.MAX_VALUE) {
242                        result = new Long(num.longValue());
243                    }
244                }
245            }
246    
247            return result;
248        }
249    
250        /**
251         *  Checks if the value can safely be converted to a float primitive.
252         *
253         *@param  value  The value validation is being performed on.
254         *@return the converted Float value.
255         */
256        public static Float formatFloat(String value) {
257            if (value == null) {
258                return null;
259            }
260    
261            try {
262                return new Float(value);
263            } catch (NumberFormatException e) {
264                return null;
265            }
266    
267        }
268    
269        /**
270         *  Checks if the value can safely be converted to a float primitive.
271         *
272         *@param  value   The value validation is being performed on.
273         *@param  locale  The locale to use to parse the number (system default if
274         *      null)
275         *@return the converted Float value.
276         */
277        public static Float formatFloat(String value, Locale locale) {
278            Float result = null;
279    
280            if (value != null) {
281                NumberFormat formatter = null;
282                if (locale != null) {
283                    formatter = NumberFormat.getInstance(locale);
284                } else {
285                    formatter = NumberFormat.getInstance(Locale.getDefault());
286                }
287                ParsePosition pos = new ParsePosition(0);
288                Number num = formatter.parse(value, pos);
289    
290                // If there was no error      and we used the whole string
291                if (pos.getErrorIndex() == -1 && pos.getIndex() == value.length()) {
292                    if (num.doubleValue() >= (Float.MAX_VALUE * -1) &&
293                        num.doubleValue() <= Float.MAX_VALUE) {
294                        result = new Float(num.floatValue());
295                    }
296                }
297            }
298    
299            return result;
300        }
301    
302        /**
303         *  Checks if the value can safely be converted to a double primitive.
304         *
305         *@param  value  The value validation is being performed on.
306         *@return the converted Double value.
307         */
308        public static Double formatDouble(String value) {
309            if (value == null) {
310                return null;
311            }
312    
313            try {
314                return new Double(value);
315            } catch (NumberFormatException e) {
316                return null;
317            }
318    
319        }
320    
321        /**
322         *  Checks if the value can safely be converted to a double primitive.
323         *
324         *@param  value   The value validation is being performed on.
325         *@param  locale  The locale to use to parse the number (system default if
326         *      null)
327         *@return the converted Double value.
328         */
329        public static Double formatDouble(String value, Locale locale) {
330            Double result = null;
331    
332            if (value != null) {
333                NumberFormat formatter = null;
334                if (locale != null) {
335                    formatter = NumberFormat.getInstance(locale);
336                } else {
337                    formatter = NumberFormat.getInstance(Locale.getDefault());
338                }
339                ParsePosition pos = new ParsePosition(0);
340                Number num = formatter.parse(value, pos);
341    
342                // If there was no error      and we used the whole string
343                if (pos.getErrorIndex() == -1 && pos.getIndex() == value.length()) {
344                    if (num.doubleValue() >= (Double.MAX_VALUE * -1) &&
345                        num.doubleValue() <= Double.MAX_VALUE) {
346                        result = new Double(num.doubleValue());
347                    }
348                }
349            }
350    
351            return result;
352        }
353    
354        /**
355         *  <p>
356         *
357         *  Checks if the field is a valid date. The <code>Locale</code> is used
358         *  with <code>java.text.DateFormat</code>. The setLenient method is set to
359         *  <code>false</code> for all.</p>
360         *
361         *@param  value   The value validation is being performed on.
362         *@param  locale  The Locale to use to parse the date (system default if
363         *      null)
364         *@return the converted Date value.
365         */
366        public static Date formatDate(String value, Locale locale) {
367            Date date = null;
368    
369            if (value == null) {
370                return null;
371            }
372    
373            try {
374                DateFormat formatter = null;
375                if (locale != null) {
376                    formatter =
377                        DateFormat.getDateInstance(DateFormat.SHORT, locale);
378                } else {
379                    formatter =
380                        DateFormat.getDateInstance(
381                        DateFormat.SHORT,
382                        Locale.getDefault());
383                }
384    
385                formatter.setLenient(false);
386    
387                date = formatter.parse(value);
388            } catch (ParseException e) {
389                // Bad date so return null
390                Log log = LogFactory.getLog(GenericTypeValidator.class);
391                if (log.isDebugEnabled()) {
392                    log.debug("Date parse failed value=[" + value  + "], " +
393                                               "locale=[" + locale + "] "  + e);
394                }
395            }
396    
397            return date;
398        }
399    
400        /**
401         *  <p>
402         *  Checks if the field is a valid date. The pattern is used with <code>java.text.SimpleDateFormat</code>
403         *  . If strict is true, then the length will be checked so '2/12/1999' will
404         *  not pass validation with the format 'MM/dd/yyyy' because the month isn't
405         *  two digits. The setLenient method is set to <code>false</code> for all.
406         *  </p>
407         *
408         *@param  value        The value validation is being performed on.
409         *@param  datePattern  The pattern passed to <code>SimpleDateFormat</code>.
410         *@param  strict       Whether or not to have an exact match of the
411         *      datePattern.
412         *@return the converted Date value.
413         */
414        public static Date formatDate(String value, String datePattern, boolean strict) {
415            Date date = null;
416    
417            if (value == null
418                 || datePattern == null
419                 || datePattern.length() == 0) {
420                return null;
421            }
422    
423            try {
424                SimpleDateFormat formatter = new SimpleDateFormat(datePattern);
425                formatter.setLenient(false);
426    
427                date = formatter.parse(value);
428    
429                if (strict) {
430                    if (datePattern.length() != value.length()) {
431                        date = null;
432                    }
433                }
434            } catch (ParseException e) {
435                // Bad date so return null
436                Log log = LogFactory.getLog(GenericTypeValidator.class);
437                if (log.isDebugEnabled()) {
438                    log.debug("Date parse failed value=[" + value       + "], " +
439                                              "pattern=[" + datePattern + "], " +
440                                               "strict=[" + strict      + "] "  + e);
441                }
442            }
443    
444            return date;
445        }
446    
447        /**
448         *  <p>
449         *  Checks if the field is a valid credit card number.</p> <p>
450         *
451         *  Reference Sean M. Burke's <a href="http://www.ling.nwu.edu/~sburke/pub/luhn_lib.pl">
452         *  script</a> .</p>
453         *
454         *@param  value  The value validation is being performed on.
455         *@return the converted Credit Card number.
456         */
457        public static Long formatCreditCard(String value) {
458            return GenericValidator.isCreditCard(value) ? new Long(value) : null;
459        }
460    
461    }
462