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