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 package org.apache.commons.validator.routines;
18
19 import java.io.Serializable;
20 import java.text.Format;
21 import java.text.ParsePosition;
22 import java.util.Locale;
23
24 /**
25 * <p>Abstract class for <em>Format</em> based Validation.</p>
26 *
27 * <p>This is a <em>base</em> class for building Date and Number
28 * Validators using format parsing.</p>
29 *
30 * @since 1.3.0
31 */
32 public abstract class AbstractFormatValidator implements Serializable {
33
34 private static final long serialVersionUID = -4690687565200568258L;
35
36 /**
37 * Whether to use strict format.
38 */
39 private final boolean strict;
40
41 /**
42 * Constructs an instance with the specified strict setting.
43 *
44 * @param strict {@code true} if strict
45 * {@code Format} parsing should be used.
46 */
47 public AbstractFormatValidator(final boolean strict) {
48 this.strict = strict;
49 }
50
51 /**
52 * <p>Format an object into a {@link String} using
53 * the default Locale.</p>
54 *
55 * @param value The value validation is being performed on.
56 * @return The value formatted as a {@link String}.
57 */
58 public String format(final Object value) {
59 return format(value, (String) null, (Locale) null);
60 }
61
62 /**
63 * <p>Format a value with the specified {@code Format}.</p>
64 *
65 * @param value The value to be formatted.
66 * @param formatter The Format to use.
67 * @return The formatted value.
68 */
69 protected String format(final Object value, final Format formatter) {
70 return formatter.format(value);
71 }
72
73 /**
74 * <p>Format an object into a {@link String} using
75 * the specified Locale.</p>
76 *
77 * @param value The value validation is being performed on.
78 * @param locale The locale to use for the Format.
79 * @return The value formatted as a {@link String}.
80 */
81 public String format(final Object value, final Locale locale) {
82 return format(value, (String) null, locale);
83 }
84
85 /**
86 * <p>Format an object into a {@link String} using
87 * the specified pattern.</p>
88 *
89 * @param value The value validation is being performed on.
90 * @param pattern The pattern used to format the value.
91 * @return The value formatted as a {@link String}.
92 */
93 public String format(final Object value, final String pattern) {
94 return format(value, pattern, (Locale) null);
95 }
96
97 /**
98 * <p>Format an object using the specified pattern and/or
99 * {@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 }