1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.validator.routines;
19
20 import java.io.Serializable;
21 import java.text.Format;
22 import java.text.ParsePosition;
23 import java.util.Locale;
24
25 /**
26 * Abstracts class for <em>Format</em> based Validation.
27 * <p>
28 * This is a <em>base</em> class for building Date and Number Validators using format parsing.
29 * </p>
30 *
31 * @since 1.3.0
32 */
33 public abstract class AbstractFormatValidator implements Serializable {
34
35 private static final long serialVersionUID = -4690687565200568258L;
36
37 /**
38 * Whether to use strict format.
39 */
40 private final boolean strict;
41
42 /**
43 * Constructs an instance with the specified strict setting.
44 *
45 * @param strict {@code true} if strict {@code Format} parsing should be used.
46 */
47 public AbstractFormatValidator(final boolean strict) {
48 this.strict = strict;
49 }
50
51 /**
52 * Formats an object into a {@link String} using the default Locale.
53 *
54 * @param value The value validation is being performed on.
55 * @return The value formatted as a {@link String}.
56 */
57 public String format(final Object value) {
58 return format(value, (String) null, (Locale) null);
59 }
60
61 /**
62 * Formats a value with the specified {@code Format}.
63 *
64 * @param value The value to be formatted.
65 * @param formatter The Format to use.
66 * @return The formatted value.
67 */
68 protected String format(final Object value, final Format formatter) {
69 return formatter.format(value);
70 }
71
72 /**
73 * Formats an object into a {@link String} using the specified Locale.
74 *
75 * @param value The value validation is being performed on.
76 * @param locale The locale to use for the Format.
77 * @return The value formatted as a {@link String}.
78 */
79 public String format(final Object value, final Locale locale) {
80 return format(value, (String) null, locale);
81 }
82
83 /**
84 * Formats an object into a {@link String} using the specified pattern.
85 *
86 * @param value The value validation is being performed on.
87 * @param pattern The pattern used to format the value.
88 * @return The value formatted as a {@link String}.
89 */
90 public String format(final Object value, final String pattern) {
91 return format(value, pattern, (Locale) null);
92 }
93
94 /**
95 * Formats an object using the specified pattern and/or {@link Locale}.
96 *
97 * @param value The value validation is being performed on.
98 * @param pattern The pattern used to format the value.
99 * @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 }