1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.trinidad.validator;
20
21 import javax.el.ValueExpression;
22
23 import javax.faces.application.FacesMessage;
24 import javax.faces.component.UIComponent;
25 import javax.faces.context.FacesContext;
26 import javax.faces.el.ValueBinding;
27 import javax.faces.validator.Validator;
28 import javax.faces.validator.ValidatorException;
29
30 import org.apache.myfaces.trinidad.bean.FacesBean;
31 import org.apache.myfaces.trinidad.bean.PropertyKey;
32 import org.apache.myfaces.trinidad.util.ComponentUtils;
33 import org.apache.myfaces.trinidad.util.IntegerUtils;
34 import org.apache.myfaces.trinidad.util.MessageFactory;
35
36 /**
37 * <p>Implementation for <code>java.lang.Double</code> values.</p>
38 *
39 */
40 public class DoubleRangeValidator extends javax.faces.validator.DoubleRangeValidator
41 {
42
43 public static final String VALIDATOR_ID = "org.apache.myfaces.trinidad.DoubleRange";
44
45 /**
46 * <p>The message identifier of the {@link javax.faces.application.FacesMessage}
47 * to be created if the maximum value check fails. The message format
48 * string for this message may optionally include <code>{0}</code>,
49 * <code>{1}</code> and <code>{3}</code> placeholders,
50 * which will be replaced by user input, component label and configured
51 * maximum value.</p>
52 */
53 public static final String MAXIMUM_MESSAGE_ID =
54 "org.apache.myfaces.trinidad.validator.DoubleRangeValidator.MAXIMUM";
55
56 /**
57 * <p>The message identifier of the {@link javax.faces.application.FacesMessage}
58 * to be created if the minimum value check fails. The message format
59 * string for this message may optionally include <code>{0}</code>,
60 * <code>{1}</code> and <code>{2}</code> placeholders, which will be replaced
61 * by user input, component label and configured minimum value.</p>
62 */
63 public static final String MINIMUM_MESSAGE_ID =
64 "org.apache.myfaces.trinidad.validator.DoubleRangeValidator.MINIMUM";
65
66
67 /**
68 * <p>The message identifier of the {@link javax.faces.application.FacesMessage}
69 * to be created if the maximum or minimum value check fails, and both
70 * the maximum and minimum values for this validator have been set.
71 * The message format string for this message may optionally include
72 * <code>{0}</code>, <code>{1}</code>, <code>{2}</code> and <code>{3}</code>
73 * placeholders, which will be replaced by user input, component label,
74 * configured minimum value and configured maximum value.</p>
75 */
76 public static final String NOT_IN_RANGE_MESSAGE_ID =
77 "org.apache.myfaces.trinidad.validator.DoubleRangeValidator.NOT_IN_RANGE";
78
79 /**
80 * <p>The message identifier of the FacesMessage to be created if
81 * the value cannot be converted
82 */
83 public static final String CONVERT_MESSAGE_ID =
84 "org.apache.myfaces.trinidad.convert.DoubleConverter.CONVERT";
85
86 /**
87 * Construct a {@link Validator} with no preconfigured limits.
88 */
89 public DoubleRangeValidator()
90 {
91 super();
92 }
93
94 /**
95 * Construct a {@link Validator} with the specified preconfigured
96 * limit.
97 *
98 * @param maximum Maximum value to allow
99 */
100 public DoubleRangeValidator(double maximum)
101 {
102 super(maximum);
103 }
104
105 /**
106 * Construct a {@link Validator} with the specified preconfigured
107 * limits.
108 *
109 * @param maximum Maximum value to allow
110 * @param minimum Minimum value to allow
111 *
112 */
113 public DoubleRangeValidator(double maximum, double minimum)
114 {
115 super(maximum, minimum);
116 }
117
118 /**
119 * Return the maximum value to be enforced by this {@link
120 * Validator} or null if it has not been
121 * set.
122 */
123 @Override
124 public double getMaximum()
125 {
126 Object maxDouble = _facesBean.getProperty(_MAXIMUM_KEY);
127 if(maxDouble == null)
128 maxDouble = _MAXIMUM_KEY.getDefault();
129 return ComponentUtils.resolveDouble(maxDouble);
130 }
131
132 /**
133 * Set the maximum value to be enforced by this {@link Validator}.
134 *
135 * @param maximum The new maximum value
136 *
137 */
138 @Override
139 public void setMaximum(double maximum)
140 {
141 _facesBean.setProperty(_MAXIMUM_KEY, Double.valueOf(maximum));
142 }
143
144
145 /**
146 * Return the minimum value to be enforced by this {@link
147 * Validator}, or null if it has not been
148 * set.
149 */
150 @Override
151 public double getMinimum()
152 {
153 Object minDouble = _facesBean.getProperty(_MINIMUM_KEY);
154 if(minDouble == null)
155 minDouble = _MINIMUM_KEY.getDefault();
156 return ComponentUtils.resolveDouble(minDouble);
157 }
158
159 /**
160 * Set the minimum value to be enforced by this {@link Validator}.
161 *
162 * @param minimum The new minimum value
163 *
164 */
165 @Override
166 public void setMinimum(double minimum)
167 {
168 _facesBean.setProperty(_MINIMUM_KEY, Double.valueOf(minimum));
169 }
170
171 /**
172 * <p>Custom error message to be used, for creating detail part of the
173 * {@link FacesMessage}, when input value exceeds the maximum value set.</p>
174 * Overrides detail message identified by message id {@link #MAXIMUM_MESSAGE_ID}
175 * @param maximumMessageDetail Custom error message.
176 */
177 public void setMessageDetailMaximum(String maximumMessageDetail)
178 {
179 _facesBean.setProperty(_MAXIMUM_MESSAGE_DETAIL_KEY, maximumMessageDetail);
180 }
181
182 /**
183 * <p>Return custom detail error message that was set for creating {@link FacesMessage},
184 * for cases where input value exceeds the <code>maximum</code> value set.</p>
185 * @return Custom error message.
186 * @see #setMessageDetailMaximum(String)
187 */
188 public String getMessageDetailMaximum()
189 {
190 Object maxMsgDet = _facesBean.getProperty(_MAXIMUM_MESSAGE_DETAIL_KEY);
191 return ComponentUtils.resolveString(maxMsgDet);
192 }
193
194 /**
195 * <p>Custom error message to be used, for creating detail part of the
196 * {@link FacesMessage}, when input value is less the set
197 * <code>minimum</code> value.</p>
198 * Overrides detail message identified by message id {@link #MINIMUM_MESSAGE_ID}
199 * @param minimumMessageDetail Custom error message.
200 */
201 public void setMessageDetailMinimum(String minimumMessageDetail)
202 {
203 _facesBean.setProperty(_MINIMUM_MESSAGE_DETAIL_KEY, minimumMessageDetail);
204 }
205
206 /**
207 * <p>Return custom detail error message that was set for creating {@link FacesMessage},
208 * for cases where, input value is less than the <code>minimum</code> value set.</p>
209 * @return Custom error message.
210 * @see #setMessageDetailMinimum(String)
211 */
212 public String getMessageDetailMinimum()
213 {
214 Object minMsgDet = _facesBean.getProperty(_MINIMUM_MESSAGE_DETAIL_KEY);
215 return ComponentUtils.resolveString(minMsgDet);
216 }
217
218 /**
219 * <p>Custom error message to be used, for creating detail part of the
220 * {@link FacesMessage}, when input value is not with in the range,
221 * when <code>minimum</code> and <code>maximum</code> is set.</p>
222 * Overrides detail message identified by message id {@link #NOT_IN_RANGE_MESSAGE_ID}
223 * @param notInRangeMessageDetail Custom error message.
224 */
225 public void setMessageDetailNotInRange(String notInRangeMessageDetail)
226 {
227 _facesBean.setProperty(_NOT_IN_RANGE_MESSAGE_DETAIL_KEY, notInRangeMessageDetail);
228 }
229
230 /**
231 * <p>Return custom detail error message that was set for creating {@link FacesMessage},
232 * for cases where, input value exceeds the <code>maximum</code> value and is
233 * less than the <code>minimum</code> value set.</p>
234 * @return Custom error message.
235 * @see #setMessageDetailNotInRange(String)
236 */
237 public String getMessageDetailNotInRange()
238 {
239 Object notInRngMsg = _facesBean.getProperty(_NOT_IN_RANGE_MESSAGE_DETAIL_KEY);
240 return ComponentUtils.resolveString(notInRngMsg);
241 }
242
243 /**
244 * <p>Custom hint maximum message.</p>
245 * Overrides default hint message
246 * @param hintMaximum Custom hint message.
247 */
248 public void setHintMaximum(String hintMaximum)
249 {
250 _facesBean.setProperty(_HINT_MAXIMUM_KEY, hintMaximum);
251 }
252
253 /**
254 * <p>Return custom hint maximum message.</p>
255 * @return Custom hint message.
256 * @see #setHintMaximum(String)
257 */
258 public String getHintMaximum()
259 {
260 Object obj = _facesBean.getProperty(_HINT_MAXIMUM_KEY);
261 return ComponentUtils.resolveString(obj);
262 }
263
264 /**
265 * <p>Custom hint minimum message.</p>
266 * Overrides default hint message
267 * @param hintMinimum Custom hint message.
268 */
269 public void setHintMinimum(String hintMinimum)
270 {
271 _facesBean.setProperty(_HINT_MINIMUM_KEY, hintMinimum);
272 }
273
274 /**
275 * <p>Return custom hint minimum message.</p>
276 * @return Custom hint message.
277 * @see #setHintMinimum(String)
278 */
279 public String getHintMinimum()
280 {
281 Object obj = _facesBean.getProperty(_HINT_MINIMUM_KEY);
282 return ComponentUtils.resolveString(obj);
283 }
284
285 /**
286 * <p>Custom hint notInRange message.</p>
287 * Overrides default hint message
288 * @param hintNotInRange Custom hint message.
289 */
290 public void setHintNotInRange(String hintNotInRange)
291 {
292 _facesBean.setProperty(_HINT_NOT_IN_RANGE, hintNotInRange);
293 }
294
295 /**
296 * <p>Return custom hint notInRange message.</p>
297 * @return Custom hint message.
298 * @see #setHintNotInRange
299 */
300 public String getHintNotInRange()
301 {
302 Object obj = _facesBean.getProperty(_HINT_NOT_IN_RANGE);
303 return ComponentUtils.resolveString(obj);
304 }
305
306 @Override
307 public void validate(
308 FacesContext context,
309 UIComponent component,
310 Object value
311 ) throws ValidatorException
312 {
313 if ((context == null) || (component == null))
314 {
315 throw new NullPointerException();
316 }
317
318 if (value == null)
319 {
320 return;
321 }
322
323 try
324 {
325 double doubleValue = _convertValueToDouble(value);
326 double min = getMinimum();
327 double max = getMaximum();
328
329 if(isMaximumSet() && isMinimumSet())
330 {
331 if(doubleValue < min || doubleValue > max)
332 {
333 throw new ValidatorException(
334 _getNotInRangeMessage(context, component, value, min, max));
335 }
336 }
337
338 if(isMaximumSet())
339 {
340 if (doubleValue > max)
341 {
342 throw new ValidatorException(
343 _getMaximumMessage(context, component, value, max));
344 }
345 }
346
347 if(isMinimumSet())
348 {
349 if (doubleValue < min)
350 {
351 throw new ValidatorException(
352 _getMinimumMessage(context, component, value, min));
353 }
354 }
355 }
356 catch (NumberFormatException nfe)
357 {
358 FacesMessage msg = _getNotCorrectType(context);
359 throw new ValidatorException(msg);
360 }
361 }
362
363
364 @Override
365 public Object saveState(FacesContext context)
366 {
367 return _facesBean.saveState(context);
368 }
369
370
371 @Override
372 public void restoreState(FacesContext context, Object state)
373 {
374 _facesBean.restoreState(context, state);
375 }
376
377 /**
378 * <p>Set the {@link ValueExpression} used to calculate the value for the
379 * specified attribute if any.</p>
380 *
381 * @param name Name of the attribute for which to set a {@link ValueExpression}
382 * @param expression The {@link ValueExpression} to set, or <code>null</code>
383 * to remove any currently set {@link ValueExpression}
384 *
385 * @exception NullPointerException if <code>name</code>
386 * is <code>null</code>
387 * @exception IllegalArgumentException if <code>name</code> is not a valid
388 * attribute of this converter
389 */
390 public void setValueExpression(String name, ValueExpression expression)
391 {
392 ValidatorUtils.setValueExpression(_facesBean, name, expression) ;
393 }
394
395
396 /**
397 * <p>Return the {@link ValueExpression} used to calculate the value for the
398 * specified attribute name, if any.</p>
399 *
400 * @param name Name of the attribute or property for which to retrieve a
401 * {@link ValueExpression}
402 *
403 * @exception NullPointerException if <code>name</code>
404 * is <code>null</code>
405 * @exception IllegalArgumentException if <code>name</code> is not a valid
406 * attribute of this converter
407 */
408 public ValueExpression getValueExpression(String name)
409 {
410 return ValidatorUtils.getValueExpression(_facesBean, name);
411 }
412
413
414 /**
415 * <p>Set the {@link ValueBinding} used to calculate the value for the
416 * specified attribute if any.</p>
417 *
418 * @param name Name of the attribute for which to set a {@link ValueBinding}
419 * @param binding The {@link ValueBinding} to set, or <code>null</code>
420 * to remove any currently set {@link ValueBinding}
421 *
422 * @exception NullPointerException if <code>name</code>
423 * is <code>null</code>
424 * @exception IllegalArgumentException if <code>name</code> is not a valid
425 * attribute of this validator
426 * @deprecated
427 */
428 public void setValueBinding(String name, ValueBinding binding)
429 {
430 ValidatorUtils.setValueBinding(_facesBean, name, binding) ;
431 }
432
433 /**
434 * <p>Return the {@link ValueBinding} used to calculate the value for the
435 * specified attribute name, if any.</p>
436 *
437 * @param name Name of the attribute or property for which to retrieve a
438 * {@link ValueBinding}
439 *
440 * @exception NullPointerException if <code>name</code>
441 * is <code>null</code>
442 * @exception IllegalArgumentException if <code>name</code> is not a valid
443 * attribute of this validator
444 * @deprecated
445 */
446 public ValueBinding getValueBinding(String name)
447 {
448 return ValidatorUtils.getValueBinding(_facesBean, name);
449 }
450
451 @Override
452 public boolean isTransient()
453 {
454 return (_transientValue);
455 }
456
457
458 @Override
459 public void setTransient(boolean transientValue)
460 {
461 _transientValue = transientValue;
462 }
463
464 protected boolean isMaximumSet()
465 {
466 return _facesBean.getProperty(_MAXIMUM_KEY) != null;
467 }
468
469 protected boolean isMinimumSet()
470 {
471 return _facesBean.getProperty(_MINIMUM_KEY) != null;
472 }
473
474 private FacesMessage _getNotCorrectType(
475 FacesContext context)
476 {
477 return MessageFactory.getMessage(context, CONVERT_MESSAGE_ID);
478 }
479
480 /**
481 * Try to call doubleValue() from java.lang.Number. Since not all
482 * "number" implement java.lang.Number, we try to call string
483 * and parse the String representation of the "number". If that fails
484 * we aren't working with a number so we throw a NumberFormatException
485 *
486 * @param value the number value
487 * @return parsed number value
488 * @throws NumberFormatException if the value is not a number
489 */
490 private double _convertValueToDouble(Object value) throws NumberFormatException
491 {
492 if(value instanceof Number)
493 {
494 return ((Number)value).doubleValue();
495 }
496 else
497 {
498 return Double.parseDouble(value.toString());
499 }
500 }
501
502 private FacesMessage _getNotInRangeMessage(
503 FacesContext context,
504 UIComponent component,
505 Object value,
506 Object min,
507 Object max)
508 {
509 Object msg = _getRawNotInRangeMessageDetail();
510 Object label = ValidatorUtils.getComponentLabel(component);
511
512 Object[] params = {label, value, min, max};
513
514 return MessageFactory.getMessage(context, NOT_IN_RANGE_MESSAGE_ID,
515 msg, params, component);
516 }
517
518
519
520 private Object _getRawNotInRangeMessageDetail()
521 {
522 return _facesBean.getRawProperty(_NOT_IN_RANGE_MESSAGE_DETAIL_KEY);
523 }
524
525
526 private FacesMessage _getMaximumMessage(
527 FacesContext context,
528 UIComponent component,
529 Object value,
530 Object max)
531 {
532
533 Object msg = _getRawMaximumMessageDetail();
534 Object label = ValidatorUtils.getComponentLabel(component);
535
536 Object[] params = {label, value, max};
537
538 return MessageFactory.getMessage(context,
539 MAXIMUM_MESSAGE_ID,
540 msg,
541 params,
542 component);
543 }
544
545 private Object _getRawMaximumMessageDetail()
546 {
547 return _facesBean.getRawProperty(_MAXIMUM_MESSAGE_DETAIL_KEY);
548 }
549
550 private FacesMessage _getMinimumMessage(
551 FacesContext context,
552 UIComponent component,
553 Object value,
554 Object min)
555 {
556 Object msg = _getRawMinimumMessageDetail();
557 Object label = ValidatorUtils.getComponentLabel(component);
558
559 Object[] params = {label, value, min};
560
561 return MessageFactory.getMessage(context, MINIMUM_MESSAGE_ID,
562 msg, params, component);
563 }
564
565 private Object _getRawMinimumMessageDetail()
566 {
567 return _facesBean.getRawProperty(_MINIMUM_MESSAGE_DETAIL_KEY);
568 }
569
570 private static final FacesBean.Type _TYPE = new FacesBean.Type();
571
572 private static final PropertyKey _MINIMUM_KEY =
573 _TYPE.registerKey("minimum", Double.class,
574
575 Double.valueOf(Double.MIN_VALUE));
576
577 private static final PropertyKey _MAXIMUM_KEY =
578 _TYPE.registerKey("maximum", Double.class,
579
580 Double.valueOf(Double.MAX_VALUE));
581
582 private static final PropertyKey _MAXIMUM_MESSAGE_DETAIL_KEY =
583 _TYPE.registerKey("messageDetailMaximum", String.class);
584
585 private static final PropertyKey _MINIMUM_MESSAGE_DETAIL_KEY =
586 _TYPE.registerKey("messageDetailMinimum", String.class);
587
588 private static final PropertyKey _NOT_IN_RANGE_MESSAGE_DETAIL_KEY =
589 _TYPE.registerKey("messageDetailNotInRange", String.class);
590
591 private static final PropertyKey _HINT_MAXIMUM_KEY =
592 _TYPE.registerKey("hintMaximum", String.class);
593
594 private static final PropertyKey _HINT_MINIMUM_KEY =
595 _TYPE.registerKey("hintMinimum", String.class);
596
597 private static final PropertyKey _HINT_NOT_IN_RANGE =
598 _TYPE.registerKey("hintNotInRange", String.class);
599
600 private FacesBean _facesBean = ValidatorUtils.getFacesBean(_TYPE);
601
602 private boolean _transientValue = false;
603 }