1 /*
2 * $Id: LongRangeValidator.java,v 1.46.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 /**
51 * <p><strong>LongRangeValidator</strong> is a {@link Validator} that checks
52 * the value of the corresponding component against specified minimum and
53 * maximum values. The following algorithm is implemented:</p>
54 * <ul>
55 * <li>If the passed value is <code>null</code>, exit immediately.</li>
56 * <li>If the current component value is not a floating point type, or
57 * a String that is convertible to long,
58 * throw a {@link ValidatorException} containing a
59 * TYPE_MESSAGE_ID message.</li>
60 * <li>If both a <code>maximum</code> and <code>minimum</code> property
61 * has been configured on this {@link Validator}, check the component
62 * value against both limits. If the component value is not within
63 * this specified range, throw a {@link ValidatorException} containing a
64 * {@link #NOT_IN_RANGE_MESSAGE_ID} message.</li>
65 * <li>If a <code>maximum</code> property has been configured on this
66 * {@link Validator}, check the component value against
67 * this limit. If the component value is greater than the
68 * specified maximum, throw a {@link ValidatorException} containing a
69 * MAXIMUM_MESSAGE_ID message.</li>
70 * <li>If a <code>minimum</code> property has been configured on this
71 * {@link Validator}, check the component value against
72 * this limit. If the component value is less than the
73 * specified minimum, throw a {@link ValidatorException} containing a
74 * MINIMUM_MESSAGE_ID message.</li>
75 * </ul>
76 * <p/>
77 * <p>For all of the above cases that cause a {@link ValidatorException}
78 * to be thrown, if there are parameters to the message that match up
79 * with validator parameters, the values of these parameters must be
80 * converted using the {@link Converter} registered in the application
81 * under the converter id <code>javax.faces.Number</code>. This allows
82 * the values to be localized according to the current
83 * <code>Locale</code>.</p>
84 */
85
86 public class LongRangeValidator implements Validator, StateHolder {
87
88 // ------------------------------------------------------ Manifest Constants
89
90
91 /**
92 * <p>The standard converter id for this converter.</p>
93 */
94 public static final String VALIDATOR_ID = "javax.faces.LongRange";
95
96
97 /**
98 * <p>The message identifier of the {@link javax.faces.application.FacesMessage} to be created if
99 * the maximum value check fails. The message format string for
100 * this message may optionally include the following placeholders:
101 * <ul>
102 * <li><code>{0}</code> replaced by the configured maximum value.</li>
103 * <li><code>{1}</code> replaced by a <code>String</code> whose value
104 * is the label of the input component that produced this message.</li>
105 * </ul></p>
106 */
107 public static final String MAXIMUM_MESSAGE_ID =
108 "javax.faces.validator.LongRangeValidator.MAXIMUM";
109
110
111 /**
112 * <p>The message identifier of the {@link javax.faces.application.FacesMessage} to be created if
113 * the minimum value check fails. The message format string for
114 * this message may optionally include the following placeholders:
115 * <ul>
116 * <li><code>{0}</code> replaced by the configured minimum value.</li>
117 * <li><code>{1}</code> replaced by a <code>String</code> whose value
118 * is the label of the input component that produced this message.</li>
119 * </ul></p>
120 */
121 public static final String MINIMUM_MESSAGE_ID =
122 "javax.faces.validator.LongRangeValidator.MINIMUM";
123
124 /**
125 * <p>The message identifier of the {@link javax.faces.application.FacesMessage} to be created if
126 * the maximum or minimum value check fails, and both the maximum
127 * and minimum values for this validator have been set. The message
128 * format string for this message may optionally include the following
129 * placeholders:
130 * <ul>
131 * <li><code>{0}</code> replaced by the configured minimum value.</li>
132 * <li><code>{1}</code> replaced by the configured maximum value.</li>
133 * <li><code>{2}</code> replaced by a <code>String</code> whose value
134 * is the label of the input component that produced this message.</li>
135 * </ul></p>
136 */
137 public static final String NOT_IN_RANGE_MESSAGE_ID =
138 "javax.faces.validator.LongRangeValidator.NOT_IN_RANGE";
139
140 /**
141 * <p>The message identifier of the {@link javax.faces.application.FacesMessage} to be created if
142 * the current value of this component is not of the correct type.
143 * The message format string for this message may
144 * optionally include a <code>{0}</code> placeholder that will be
145 * replaced by a <code>String</code> whose value is the label of
146 * the input component that produced this message.</p>
147 */
148 public static final String TYPE_MESSAGE_ID =
149 "javax.faces.validator.LongRangeValidator.TYPE";
150
151 // ------------------------------------------------------------ Constructors
152
153
154 /**
155 * <p>Construct a {@link Validator} with no preconfigured limits.</p>
156 */
157 public LongRangeValidator() {
158
159 super();
160
161 }
162
163
164 /**
165 * <p>Construct a {@link Validator} with the specified preconfigured
166 * limit.</p>
167 *
168 * @param maximum Maximum value to allow
169 */
170 public LongRangeValidator(long maximum) {
171
172 super();
173 setMaximum(maximum);
174
175 }
176
177
178 /**
179 * <p>Construct a {@link Validator} with the specified preconfigured
180 * limits.</p>
181 *
182 * @param maximum Maximum value to allow
183 * @param minimum Minimum value to allow
184 */
185 public LongRangeValidator(long maximum, long minimum) {
186
187 super();
188 setMaximum(maximum);
189 setMinimum(minimum);
190
191 }
192
193 // -------------------------------------------------------------- Properties
194
195
196 private Long maximum;
197
198
199 /**
200 * <p>Return the maximum value to be enforced by this {@link Validator}.</p>
201 */
202 public long getMaximum() {
203
204 return (this.maximum != null ? this.maximum : 0);
205
206 }
207
208
209 /**
210 * <p>Set the maximum value to be enforced by this {@link Validator}.</p>
211 *
212 * @param maximum The new maximum value
213 */
214 public void setMaximum(long maximum) {
215
216 this.maximum = maximum;
217
218 }
219
220
221 private Long minimum;
222
223
224 /**
225 * <p>Return the minimum value to be enforced by this {@link Validator}.</p>
226 */
227 public long getMinimum() {
228
229 return (this.minimum != null ? this.minimum : 0);
230
231 }
232
233
234 /**
235 * <p>Set the minimum value to be enforced by this {@link Validator}.</p>
236 *
237 * @param minimum The new minimum value
238 */
239 public void setMinimum(long minimum) {
240
241 this.minimum = minimum;
242
243 }
244
245 // ------------------------------------------------------- Validator Methods
246
247 /**
248 * @throws NullPointerException {@inheritDoc}
249 * @throws ValidatorException {@inheritDoc}
250 */
251 public void validate(FacesContext context,
252 UIComponent component,
253 Object value) throws ValidatorException {
254
255 if ((context == null) || (component == null)) {
256 throw new NullPointerException();
257 }
258 if (value != null) {
259 try {
260 long converted = longValue(value);
261 if (isMaximumSet() &&
262 (converted > maximum)) {
263 if (isMinimumSet()) {
264 throw new ValidatorException(MessageFactory.getMessage
265 (context,
266 NOT_IN_RANGE_MESSAGE_ID,
267 stringValue(component, minimum, context),
268 stringValue(component, maximum, context),
269 MessageFactory.getLabel(context, component)));
270
271 } else {
272 throw new ValidatorException(MessageFactory.getMessage
273 (context,
274 MAXIMUM_MESSAGE_ID,
275 stringValue(component, maximum, context),
276 MessageFactory.getLabel(context, component)));
277 }
278 }
279 if (isMinimumSet() &&
280 (converted < minimum)) {
281 if (isMaximumSet()) {
282 throw new ValidatorException(MessageFactory.getMessage
283 (context,
284 NOT_IN_RANGE_MESSAGE_ID,
285 stringValue(component, minimum, context),
286 stringValue(component, maximum, context),
287 MessageFactory.getLabel(context, component)));
288
289 } else {
290 throw new ValidatorException(MessageFactory.getMessage
291 (context,
292 MINIMUM_MESSAGE_ID,
293 stringValue(component, minimum, context),
294 MessageFactory.getLabel(context, component)));
295 }
296 }
297 } catch (NumberFormatException e) {
298 throw new ValidatorException(MessageFactory.getMessage
299 (context, TYPE_MESSAGE_ID,
300 MessageFactory.getLabel(context, component)));
301 }
302 }
303
304 }
305
306
307 public boolean equals(Object otherObj) {
308
309 if (!(otherObj instanceof LongRangeValidator)) {
310 return false;
311 }
312 LongRangeValidator other = (LongRangeValidator) otherObj;
313 return ((this.getMaximum() == other.getMaximum())
314 && (this.getMinimum() == other.getMinimum())
315 && (this.isMaximumSet() == other.isMaximumSet())
316 && (this.isMinimumSet() == other.isMinimumSet()));
317
318 }
319
320
321 public int hashCode() {
322
323 int hashCode = Long.valueOf(getMinimum()).hashCode()
324 + Long.valueOf(getMaximum()).hashCode()
325 + Boolean.valueOf(isMinimumSet()).hashCode()
326 + Boolean.valueOf(isMaximumSet()).hashCode();
327 return (hashCode);
328
329 }
330
331 // --------------------------------------------------------- Private Methods
332
333
334 /**
335 * <p>Return the specified attribute value, converted to a
336 * <code>long</code>.</p>
337 *
338 * @param attributeValue The attribute value to be converted
339 * @throws NumberFormatException if conversion is not possible
340 */
341 private static long longValue(Object attributeValue)
342 throws NumberFormatException {
343
344 if (attributeValue instanceof Number) {
345 return (((Number) attributeValue).longValue());
346 } else {
347 return (Long.parseLong(attributeValue.toString()));
348 }
349
350 }
351
352 private static String stringValue(UIComponent component,
353 Long toConvert,
354 FacesContext context) {
355
356 Converter converter =
357 context.getApplication().createConverter("javax.faces.Number");
358 return converter.getAsString(context, component, toConvert);
359
360 }
361
362 private boolean isMinimumSet() {
363
364 return (minimum != null);
365
366 }
367
368 private boolean isMaximumSet() {
369
370 return (maximum != null);
371
372 }
373
374 // ----------------------------------------------------- StateHolder Methods
375
376
377 public Object saveState(FacesContext context) {
378
379 Object values[] = new Object[2];
380 values[0] = maximum;
381 values[1] = minimum;
382 return (values);
383
384 }
385
386
387 public void restoreState(FacesContext context, Object state) {
388
389 Object values[] = (Object[]) state;
390 maximum = (Long) values[0];
391 minimum = (Long) values[1];
392
393 }
394
395
396 private boolean transientValue = false;
397
398
399 public boolean isTransient() {
400
401 return (this.transientValue);
402
403 }
404
405
406 public void setTransient(boolean transientValue) {
407
408 this.transientValue = transientValue;
409
410 }
411
412 }