1 /*
2 * $Id: LengthValidator.java,v 1.50.4.1 2007/09/26 19:22:44 rlubke Exp $
3 */
4
5 /*
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
7 *
8 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
9 *
10 * The contents of this file are subject to the terms of either the GNU
11 * General Public License Version 2 only ("GPL") or the Common Development
12 * and Distribution License("CDDL") (collectively, the "License"). You
13 * may not use this file except in compliance with the License. You can obtain
14 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
15 * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
16 * language governing permissions and limitations under the License.
17 *
18 * When distributing the software, include this License Header Notice in each
19 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
20 * Sun designates this particular file as subject to the "Classpath" exception
21 * as provided by Sun in the GPL Version 2 section of the License file that
22 * accompanied this code. If applicable, add the following below the License
23 * Header, with the fields enclosed by brackets [] replaced by your own
24 * identifying information: "Portions Copyrighted [year]
25 * [name of copyright owner]"
26 *
27 * Contributor(s):
28 *
29 * If you wish your version of this file to be governed by only the CDDL or
30 * only the GPL Version 2, indicate your decision by adding "[Contributor]
31 * elects to include this software in this distribution under the [CDDL or GPL
32 * Version 2] license." If you don't indicate a single choice of license, a
33 * recipient has the option to distribute your version of this file under
34 * either the CDDL, the GPL Version 2 or to extend the choice of license to
35 * its licensees as provided above. However, if you add GPL Version 2 code
36 * and therefore, elected the GPL Version 2 license, then the option applies
37 * only if the new code is made subject to such option by the copyright
38 * holder.
39 */
40
41 package javax.faces.validator;
42
43
44 import javax.faces.component.StateHolder;
45 import javax.faces.component.UIComponent;
46 import javax.faces.context.FacesContext;
47 import javax.faces.convert.Converter;
48
49 /**
50 * <p><strong>LengthValidator</strong> is a {@link Validator} that checks
51 * the number of characters in the String representation of the value of the
52 * associated component. The following algorithm is implemented:</p>
53 * <ul>
54 * <li>Convert the passed value to a String, if necessary, by calling its
55 * <code>toString()</code> method.</li>
56 * <li>If a <code>maximum</code> property has been configured on this
57 * {@link Validator}, check the length of the converted
58 * String against this limit. If the String length is larger than the
59 * specified maximum, throw a {@link ValidatorException} containing a
60 * a MAXIMUM_MESSAGE_ID message.</li>
61 * <li>If a <code>minimum</code> property has been configured on this
62 * {@link Validator}, check the length of the converted
63 * String against this limit. If the String length is less than the
64 * specified minimum, throw a {@link ValidatorException} containing a
65 * a MINIMUM_MESSAGE_ID message.</li>
66 * </ul>
67 * <p/>
68 * <p>For all of the above cases that cause a {@link ValidatorException}
69 * to be thrown, if there are parameters to the message that match up
70 * with validator parameters, the values of these parameters must be
71 * converted using the {@link Converter} registered in the application
72 * under the converter id <code>javax.faces.Number</code>. This allows
73 * the values to be localized according to the current
74 * <code>Locale</code>.</p>
75 */
76
77 public class LengthValidator implements Validator, StateHolder {
78
79 // ------------------------------------------------------ Manifest Constants
80
81
82 /**
83 * <p>The standard validator id for this validator.</p>
84 */
85 public static final String VALIDATOR_ID = "javax.faces.Length";
86
87
88 /**
89 * <p>The message identifier of the {@link javax.faces.application.FacesMessage} to be created if
90 * the maximum length check fails. The message format string for
91 * this message may optionally include the following placeholders:
92 * <ul>
93 * <li><code>{0}</code> replaced by the configured maximum length.</li>
94 * <li><code>{1}</code> replaced by a <code>String</code> whose value
95 * is the label of the input component that produced this message.</li>
96 * </ul></p>
97 */
98 public static final String MAXIMUM_MESSAGE_ID =
99 "javax.faces.validator.LengthValidator.MAXIMUM";
100
101
102 /**
103 * <p>The message identifier of the {@link javax.faces.application.FacesMessage} to be created if
104 * the minimum length check fails. The message format string for
105 * this message may optionally include the following placeholders:
106 * <ul>
107 * <li><code>{0}</code> replaced by the configured minimum length.</li>
108 * <li><code>{1}</code> replaced by a <code>String</code> whose value
109 * is the label of the input component that produced this message.</li>
110 * </ul></p>
111 */
112 public static final String MINIMUM_MESSAGE_ID =
113 "javax.faces.validator.LengthValidator.MINIMUM";
114
115 // ------------------------------------------------------------ Constructors
116
117
118 /**
119 * <p>Construct a {@link Validator} with no preconfigured limits.</p>
120 */
121 public LengthValidator() {
122
123 super();
124
125 }
126
127
128 /**
129 * <p>Construct a {@link Validator} with the specified preconfigured
130 * limit.</p>
131 *
132 * @param maximum Maximum value to allow
133 */
134 public LengthValidator(int maximum) {
135
136 super();
137 setMaximum(maximum);
138
139 }
140
141
142 /**
143 * <p>Construct a {@link Validator} with the specified preconfigured
144 * limits.</p>
145 *
146 * @param maximum Maximum value to allow
147 * @param minimum Minimum value to allow
148 */
149 public LengthValidator(int maximum, int minimum) {
150
151 super();
152 setMaximum(maximum);
153 setMinimum(minimum);
154
155 }
156
157 // -------------------------------------------------------------- Properties
158
159
160 private Integer maximum;
161
162
163 /**
164 * <p>Return the maximum length to be enforced by this {@link
165 * Validator}, or <code>0</code> if the maximum has not been
166 * set.</p>
167 */
168 public int getMaximum() {
169
170 return (this.maximum != null ? this.maximum : 0);
171
172 }
173
174
175 /**
176 * <p>Set the maximum length to be enforced by this {@link Validator}.</p>
177 *
178 * @param maximum The new maximum value
179 */
180 public void setMaximum(int maximum) {
181
182 this.maximum = maximum;
183 }
184
185
186 private Integer minimum;
187
188
189 /**
190 * <p>Return the minimum length to be enforced by this {@link
191 * Validator}, or <code>0</code> if the minimum has not been
192 * set.</p>
193 */
194 public int getMinimum() {
195
196 return (this.minimum != null ? this.minimum : 0);
197
198 }
199
200
201 /**
202 * <p>Set the minimum length to be enforced by this {@link Validator}.</p>
203 *
204 * @param minimum The new minimum value
205 */
206 public void setMinimum(int minimum) {
207
208 this.minimum = minimum;
209
210 }
211
212 // ------------------------------------------------------- Validator Methods
213
214 /**
215 * @throws NullPointerException {@inheritDoc}
216 * @throws ValidatorException {@inheritDoc}
217 */
218 public void validate(FacesContext context,
219 UIComponent component,
220 Object value) throws ValidatorException {
221
222 if ((context == null) || (component == null)) {
223 throw new NullPointerException();
224 }
225 if (value != null) {
226 String converted = stringValue(value);
227 if (isMaximumSet() &&
228 (converted.length() > maximum)) {
229 throw new ValidatorException(MessageFactory.getMessage
230 (context,
231 MAXIMUM_MESSAGE_ID,
232 integerToString(component, maximum, context),
233 MessageFactory.getLabel(context, component)));
234 }
235 if (isMinimumSet() &&
236 (converted.length() < minimum)) {
237 throw new ValidatorException(MessageFactory.getMessage
238 (context,
239 MINIMUM_MESSAGE_ID,
240 integerToString(component, minimum, context),
241 MessageFactory.getLabel(context, component)));
242 }
243 }
244
245 }
246
247
248 public boolean equals(Object otherObj) {
249
250 if (!(otherObj instanceof LengthValidator)) {
251 return false;
252 }
253 LengthValidator other = (LengthValidator) otherObj;
254 return ((this.getMaximum() == other.getMaximum())
255 && (this.getMinimum() == other.getMinimum())
256 && (this.isMinimumSet() == other.isMinimumSet())
257 && (this.isMaximumSet() == other.isMaximumSet()));
258
259 }
260
261 public int hashCode() {
262
263 int hashCode = (Integer.valueOf(getMinimum()).hashCode()
264 + Integer.valueOf(getMaximum()).hashCode()
265 + Boolean.valueOf(isMaximumSet()).hashCode()
266 + Boolean.valueOf(isMinimumSet()).hashCode());
267 return (hashCode);
268
269 }
270
271 // -------------------------------------------------------- Private Methods
272
273
274 /**
275 * <p>Return the specified attribute value, converted to a
276 * <code>String</code>.</p>
277 *
278 * @param attributeValue The attribute value to be converted
279 */
280 private static String stringValue(Object attributeValue) {
281
282 if (attributeValue == null) {
283 return (null);
284 } else if (attributeValue instanceof String) {
285 return ((String) attributeValue);
286 } else {
287 return (attributeValue.toString());
288 }
289
290 }
291
292 private static String integerToString(UIComponent component,
293 Integer toConvert,
294 FacesContext context) {
295
296 Converter converter =
297 context.getApplication().createConverter("javax.faces.Number");
298 return converter.getAsString(context, component, toConvert);
299
300 }
301
302
303 private boolean isMaximumSet() {
304
305 return (maximum != null);
306
307 }
308
309
310 private boolean isMinimumSet() {
311
312 return (minimum != null);
313
314 }
315
316 // ----------------------------------------------------- StateHolder Methods
317
318
319 public Object saveState(FacesContext context) {
320
321 Object values[] = new Object[2];
322 values[0] = maximum;
323 values[1] = minimum;
324 return (values);
325
326 }
327
328
329 public void restoreState(FacesContext context, Object state) {
330
331 Object values[] = (Object[]) state;
332 maximum = (Integer) values[0];
333 minimum = (Integer) values[1];
334
335 }
336
337
338 private boolean transientValue = false;
339
340
341 public boolean isTransient() {
342
343 return (this.transientValue);
344
345 }
346
347
348 public void setTransient(boolean transientValue) {
349
350 this.transientValue = transientValue;
351
352 }
353
354 }