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