    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 */
    017package org.apache.commons.validator.routines;
    018
    019import java.text.Format;
    020import java.text.ParsePosition;
    021import java.util.Locale;
    022import java.io.Serializable;
    023
    024/**
    025 * <p>Abstract class for <i>Format</i> based Validation.</p>
    026 *
    027 * <p>This is a <i>base</i> class for building Date and Number
    028 *    Validators using format parsing.</p>
    029 *
    030 * @version $Revision$
    031 * @since Validator 1.3.0
    032 */
    033public abstract class AbstractFormatValidator implements Serializable {
    034
    035    private static final long serialVersionUID = -4690687565200568258L;
    036
    037    private final boolean strict;
    038
    039    /**
    040     * Construct an instance with the specified strict setting.
    041     *
    042     * @param strict <code>true</code> if strict
    043     *        <code>Format</code> parsing should be used.
    044     */
    045    public AbstractFormatValidator(boolean strict) {
    046        this.strict = strict;
    047    }
    048
    049    /**
    050     * <p>Indicates whether validated values should adhere
    051     *    strictly to the <code>Format</code> used.</p>
    052     *
    053     * <p>Typically implementations of <code>Format</code>
    054     *    ignore invalid characters at the end of the value
    055     *    and just stop parsing. For example parsing a date
    056     *    value of <code>01/01/20x0</code> using a pattern
    057     *    of <code>dd/MM/yyyy</code> will result in a year
    058     *    of <code>20</code> if <code>strict</code> is set
    059     *    to <code>false</code>, whereas setting <code>strict</code>
    060     *    to <code>true</code> will cause this value to fail
    061     *    validation.</p>
    062     *
    063     * @return <code>true</code> if strict <code>Format</code>
    064     *         parsing should be used.
    065     */
    066    public boolean isStrict() {
    067        return strict;
    068    }
    069
    070    /**
    071     * <p>Validate using the default <code>Locale</code>.
    072     *
    073     * @param value The value validation is being performed on.
    074     * @return <code>true</code> if the value is valid.
    075     */
    076    public boolean isValid(String value) {
    077        return isValid(value, (String)null, (Locale)null);
    078    }
    079
    080    /**
    081     * <p>Validate using the specified <i>pattern</i>.
    082     *
    083     * @param value The value validation is being performed on.
    084     * @param pattern The pattern used to validate the value against.
    085     * @return <code>true</code> if the value is valid.
    086     */
    087    public boolean isValid(String value, String pattern) {
    088        return isValid(value, pattern, (Locale)null);
    089    }
    090
    091    /**
    092     * <p>Validate using the specified <code>Locale</code>.
    093     *
    094     * @param value The value validation is being performed on.
    095     * @param locale The locale to use for the Format, defaults to the default
    096     * @return <code>true</code> if the value is valid.
    097     */
    098    public boolean isValid(String value, Locale locale) {
    099        return isValid(value, (String)null, locale);
    100    }
    101
    102    /**
    103     * <p>Validate using the specified pattern and/or <code>Locale</code>.
    104     *
    105     * @param value The value validation is being performed on.
    106     * @param pattern The pattern used to format the value.
    107     * @param locale The locale to use for the Format, defaults to the default
    108     * @return <code>true</code> if the value is valid.
    109     */
    110    public abstract boolean isValid(String value, String pattern, Locale locale);
    111
    112    /**
    113     * <p>Format an object into a <code>String</code> using
    114     * the default Locale.</p>
    115     *
    116     * @param value The value validation is being performed on.
    117     * @return The value formatted as a <code>String</code>.
    118     */
    119    public String format(Object value) {
    120        return format(value, (String)null, (Locale)null);
    121    }
    122
    123    /**
    124     * <p>Format an object into a <code>String</code> using
    125     * the specified pattern.</p>
    126     *
    127     * @param value The value validation is being performed on.
    128     * @param pattern The pattern used to format the value.
    129     * @return The value formatted as a <code>String</code>.
    130     */
    131    public String format(Object value, String pattern) {
    132        return format(value, pattern, (Locale)null);
    133    }
    134
    135    /**
    136     * <p>Format an object into a <code>String</code> using
    137     * the specified Locale.</p>
    138     *
    139     * @param value The value validation is being performed on.
    140     * @param locale The locale to use for the Format.
    141     * @return The value formatted as a <code>String</code>.
    142     */
    143    public String format(Object value, Locale locale) {
    144        return format(value, (String)null, locale);
    145    }
    146
    147    /**
    148     * <p>Format an object using the specified pattern and/or
    149     *    <code>Locale</code>.
    150     *
    151     * @param value The value validation is being performed on.
    152     * @param pattern The pattern used to format the value.
    153     * @param locale The locale to use for the Format.
    154     * @return The value formatted as a <code>String</code>.
    155     */
    156    public String format(Object value, String pattern, Locale locale) {
    157        Format formatter = getFormat(pattern, locale);
    158        return format(value, formatter);
    159    }
    160
    161    /**
    162     * <p>Format a value with the specified <code>Format</code>.</p>
    163     *
    164     * @param value The value to be formatted.
    165     * @param formatter The Format to use.
    166     * @return The formatted value.
    167     */
    168    protected String format(Object value, Format formatter) {
    169        return formatter.format(value);
    170    }
    171
    172    /**
    173     * <p>Parse the value with the specified <code>Format</code>.</p>
    174     *
    175     * @param value The value to be parsed.
    176     * @param formatter The Format to parse the value with.
    177     * @return The parsed value if valid or <code>null</code> if invalid.
    178     */
    179    protected Object parse(String value, Format formatter) {
    180
    181        ParsePosition pos = new ParsePosition(0);
    182        Object parsedValue = formatter.parseObject(value, pos);
    183        if (pos.getErrorIndex() > -1) {
    184            return null;
    185        }
    186
    187        if (isStrict() && pos.getIndex() < value.length()) {
    188            return null;
    189        }
    190
    191        if (parsedValue != null) {
    192            parsedValue = processParsedValue(parsedValue, formatter);
    193        }
    194
    195        return parsedValue;
    196
    197    }
    198
    199    /**
    200     * <p>Process the parsed value, performing any further validation
    201     *    and type conversion required.</p>
    202     *
    203     * @param value The parsed object created.
    204     * @param formatter The Format used to parse the value with.
    205     * @return The parsed value converted to the appropriate type
    206     *         if valid or <code>null</code> if invalid.
    207     */
    208    protected abstract Object processParsedValue(Object value, Format formatter);
    209
    210    /**
    211     * <p>Returns a <code>Format</code> for the specified <i>pattern</i>
    212     *    and/or <code>Locale</code>.</p>
    213     *
    214     * @param pattern The pattern used to validate the value against or
    215     *        <code>null</code> to use the default for the <code>Locale</code>.
    216     * @param locale The locale to use for the currency format, system default if null.
    217     * @return The <code>NumberFormat</code> to created.
    218     */
    219    protected abstract Format getFormat(String pattern, Locale locale);
    220
    221}