1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package javax.faces.convert;
20
21 import java.math.BigDecimal;
22 import java.math.BigInteger;
23 import java.text.DecimalFormat;
24 import java.text.DecimalFormatSymbols;
25 import java.text.NumberFormat;
26 import java.text.ParseException;
27 import java.util.Currency;
28 import java.util.Locale;
29
30 import javax.el.ValueExpression;
31 import javax.faces.component.PartialStateHolder;
32 import javax.faces.component.UIComponent;
33 import javax.faces.context.FacesContext;
34
35 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFConverter;
36 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspProperty;
37 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
38
39
40
41
42
43
44
45
46
47 @JSFConverter(
48 name="f:convertNumber",
49 bodyContent="empty",
50 tagClass="org.apache.myfaces.taglib.core.ConvertNumberTag")
51 @JSFJspProperty(
52 name="binding",
53 returnType = "javax.faces.convert.NumberConverter",
54 longDesc = "A ValueExpression that evaluates to a NumberConverter.")
55 public class NumberConverter
56 implements Converter, PartialStateHolder
57 {
58
59 public static final String CONVERTER_ID = "javax.faces.Number";
60 public static final String STRING_ID = "javax.faces.converter.STRING";
61 public static final String CURRENCY_ID = "javax.faces.converter.NumberConverter.CURRENCY";
62 public static final String NUMBER_ID = "javax.faces.converter.NumberConverter.NUMBER";
63 public static final String PATTERN_ID = "javax.faces.converter.NumberConverter.PATTERN";
64 public static final String PERCENT_ID = "javax.faces.converter.NumberConverter.PERCENT";
65
66 private String _currencyCode;
67 private String _currencySymbol;
68 private Locale _locale;
69 private int _maxFractionDigits;
70 private int _maxIntegerDigits;
71 private int _minFractionDigits;
72 private int _minIntegerDigits;
73 private String _pattern;
74 private String _type = "number";
75 private boolean _groupingUsed = true;
76 private boolean _integerOnly = false;
77 private boolean _transient;
78
79 private boolean _maxFractionDigitsSet;
80 private boolean _maxIntegerDigitsSet;
81 private boolean _minFractionDigitsSet;
82 private boolean _minIntegerDigitsSet;
83
84
85
86 public NumberConverter()
87 {
88 }
89
90
91 public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String value)
92 {
93 if (facesContext == null)
94 {
95 throw new NullPointerException("facesContext");
96 }
97 if (uiComponent == null)
98 {
99 throw new NullPointerException("uiComponent");
100 }
101
102 if (value != null)
103 {
104 value = value.trim();
105 if (value.length() > 0)
106 {
107 NumberFormat format = getNumberFormat(facesContext);
108 format.setParseIntegerOnly(_integerOnly);
109
110 DecimalFormat df = (DecimalFormat)format;
111
112
113
114
115
116
117 ValueExpression valueBinding = uiComponent.getValueExpression("value");
118 Class<?> destType = null;
119 if (valueBinding != null)
120 {
121 destType = valueBinding.getType(facesContext.getELContext());
122 if (destType != null
123 && (BigDecimal.class.isAssignableFrom(destType) || BigInteger.class.isAssignableFrom(destType)))
124 {
125 df.setParseBigDecimal(true);
126 }
127 }
128
129 DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
130 boolean changed = false;
131 if(dfs.getGroupingSeparator() == '\u00a0')
132 {
133 dfs.setGroupingSeparator(' ');
134 df.setDecimalFormatSymbols(dfs);
135 value = value.replace('\u00a0', ' ');
136 changed = true;
137 }
138
139 formatCurrency(format);
140
141 try
142 {
143 return parse(value, format, destType);
144 }
145 catch (ParseException e)
146 {
147 if(changed)
148 {
149 dfs.setGroupingSeparator('\u00a0');
150 df.setDecimalFormatSymbols(dfs);
151 }
152 try
153 {
154 return parse(value, format, destType);
155 }
156 catch (ParseException pe)
157 {
158
159 if(getPattern() != null)
160 {
161 throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,
162 PATTERN_ID,
163 new Object[]{value, "$###,###", _MessageUtils.getLabel(facesContext, uiComponent)}));
164 }
165 else if(getType().equals("number"))
166 {
167 throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,
168 NUMBER_ID,
169 new Object[]{value, format.format(21),
170 _MessageUtils.getLabel(facesContext, uiComponent)}));
171 }
172 else if(getType().equals("currency"))
173 {
174 throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,
175 CURRENCY_ID,
176 new Object[]{value, format.format(42.25),
177 _MessageUtils.getLabel(facesContext, uiComponent)}));
178 }
179 else if(getType().equals("percent"))
180 {
181 throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,
182 PERCENT_ID,
183 new Object[]{value, format.format(.90),
184 _MessageUtils.getLabel(facesContext, uiComponent)}));
185 }
186 }
187 }
188 }
189 }
190 return null;
191 }
192
193 private Object parse(String value, NumberFormat format, Class<?> destType)
194 throws ParseException
195 {
196 if (destType == BigInteger.class)
197 {
198 return ((BigDecimal) format.parse(value)).toBigInteger();
199 }
200 else
201 {
202 return format.parse(value);
203 }
204 }
205
206 public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value)
207 {
208 if (facesContext == null)
209 {
210 throw new NullPointerException("facesContext");
211 }
212 if (uiComponent == null)
213 {
214 throw new NullPointerException("uiComponent");
215 }
216
217 if (value == null)
218 {
219 return "";
220 }
221 if (value instanceof String)
222 {
223 return (String)value;
224 }
225
226 NumberFormat format = getNumberFormat(facesContext);
227 format.setGroupingUsed(_groupingUsed);
228 if (_maxFractionDigitsSet)
229 {
230 format.setMaximumFractionDigits(_maxFractionDigits);
231 }
232 if (_maxIntegerDigitsSet)
233 {
234 format.setMaximumIntegerDigits(_maxIntegerDigits);
235 }
236 if (_minFractionDigitsSet)
237 {
238 format.setMinimumFractionDigits(_minFractionDigits);
239 }
240 if (_minIntegerDigitsSet)
241 {
242 format.setMinimumIntegerDigits(_minIntegerDigits);
243 }
244 formatCurrency(format);
245 try
246 {
247 return format.format(value);
248 }
249 catch (Exception e)
250 {
251 throw new ConverterException(_MessageUtils.getErrorMessage(facesContext, STRING_ID,
252 new Object[]{value,_MessageUtils.getLabel(facesContext, uiComponent)}),e);
253 }
254 }
255
256 private NumberFormat getNumberFormat(FacesContext facesContext)
257 {
258 Locale locale = _locale != null ? _locale : facesContext.getViewRoot().getLocale();
259
260 if (_pattern == null && _type == null)
261 {
262 throw new ConverterException("Cannot get NumberFormat, either type or pattern needed.");
263 }
264
265
266 if (_pattern != null)
267 {
268 return new DecimalFormat(_pattern, new DecimalFormatSymbols(locale));
269 }
270
271
272 if (_type.equals("number"))
273 {
274 return NumberFormat.getNumberInstance(locale);
275 }
276 else if (_type.equals("currency"))
277 {
278 return NumberFormat.getCurrencyInstance(locale);
279 }
280 else if (_type.equals("percent"))
281 {
282 return NumberFormat.getPercentInstance(locale);
283 }
284 throw new ConverterException("Cannot get NumberFormat, illegal type " + _type);
285 }
286
287 private void formatCurrency(NumberFormat format)
288 {
289 if (_currencyCode == null && _currencySymbol == null)
290 {
291 return;
292 }
293
294 boolean useCurrencyCode;
295 useCurrencyCode = _currencyCode != null;
296
297 if (useCurrencyCode)
298 {
299
300 try
301 {
302 format.setCurrency(Currency.getInstance(_currencyCode));
303 }
304 catch (Exception e)
305 {
306 throw new ConverterException("Unable to get Currency instance for currencyCode " +
307 _currencyCode);
308 }
309 }
310 else if (format instanceof DecimalFormat)
311
312 {
313 DecimalFormat dFormat = (DecimalFormat)format;
314 DecimalFormatSymbols symbols = dFormat.getDecimalFormatSymbols();
315 symbols.setCurrencySymbol(_currencySymbol);
316 dFormat.setDecimalFormatSymbols(symbols);
317 }
318 }
319
320
321 public void restoreState(FacesContext facesContext, Object state)
322 {
323 if (state != null)
324 {
325 Object values[] = (Object[])state;
326 _currencyCode = (String)values[0];
327 _currencySymbol = (String)values[1];
328 _locale = (Locale)values[2];
329 Integer value = (Integer)values[3];
330 _maxFractionDigits = value != null ? value.intValue() : 0;
331 value = (Integer)values[4];
332 _maxIntegerDigits = value != null ? value.intValue() : 0;
333 value = (Integer)values[5];
334 _minFractionDigits = value != null ? value.intValue() : 0;
335 value = (Integer)values[6];
336 _minIntegerDigits = value != null ? value.intValue() : 0;
337 _pattern = (String)values[7];
338 _type = (String)values[8];
339 _groupingUsed = ((Boolean)values[9]).booleanValue();
340 _integerOnly = ((Boolean)values[10]).booleanValue();
341 _maxFractionDigitsSet = ((Boolean)values[11]).booleanValue();
342 _maxIntegerDigitsSet = ((Boolean)values[12]).booleanValue();
343 _minFractionDigitsSet = ((Boolean)values[13]).booleanValue();
344 _minIntegerDigitsSet = ((Boolean)values[14]).booleanValue();
345 }
346 }
347
348 public Object saveState(FacesContext facesContext)
349 {
350 if (!initialStateMarked())
351 {
352 Object values[] = new Object[15];
353 values[0] = _currencyCode;
354 values[1] = _currencySymbol;
355 values[2] = _locale;
356 values[3] = _maxFractionDigitsSet ? Integer.valueOf(_maxFractionDigits) : null;
357 values[4] = _maxIntegerDigitsSet ? Integer.valueOf(_maxIntegerDigits) : null;
358 values[5] = _minFractionDigitsSet ? Integer.valueOf(_minFractionDigits) : null;
359 values[6] = _minIntegerDigitsSet ? Integer.valueOf(_minIntegerDigits) : null;
360 values[7] = _pattern;
361 values[8] = _type;
362 values[9] = _groupingUsed ? Boolean.TRUE : Boolean.FALSE;
363 values[10] = _integerOnly ? Boolean.TRUE : Boolean.FALSE;
364 values[11] = _maxFractionDigitsSet ? Boolean.TRUE : Boolean.FALSE;
365 values[12] = _maxIntegerDigitsSet ? Boolean.TRUE : Boolean.FALSE;
366 values[13] = _minFractionDigitsSet ? Boolean.TRUE : Boolean.FALSE;
367 values[14] = _minIntegerDigitsSet ? Boolean.TRUE : Boolean.FALSE;
368 return values;
369 }
370 return null;
371 }
372
373
374
375
376
377
378
379 @JSFProperty
380 public String getCurrencyCode()
381 {
382 return _currencyCode != null ?
383 _currencyCode :
384 getDecimalFormatSymbols().getInternationalCurrencySymbol();
385 }
386
387 public void setCurrencyCode(String currencyCode)
388 {
389 _currencyCode = currencyCode;
390 clearInitialState();
391 }
392
393
394
395
396
397
398 @JSFProperty
399 public String getCurrencySymbol()
400 {
401 return _currencySymbol != null ?
402 _currencySymbol :
403 getDecimalFormatSymbols().getCurrencySymbol();
404 }
405
406 public void setCurrencySymbol(String currencySymbol)
407 {
408 _currencySymbol = currencySymbol;
409 clearInitialState();
410 }
411
412
413
414
415
416 @JSFProperty(deferredValueType="java.lang.Boolean")
417 public boolean isGroupingUsed()
418 {
419 return _groupingUsed;
420 }
421
422 public void setGroupingUsed(boolean groupingUsed)
423 {
424 _groupingUsed = groupingUsed;
425 clearInitialState();
426 }
427
428
429
430
431
432 @JSFProperty(deferredValueType="java.lang.Boolean")
433 public boolean isIntegerOnly()
434 {
435 return _integerOnly;
436 }
437
438 public void setIntegerOnly(boolean integerOnly)
439 {
440 _integerOnly = integerOnly;
441 clearInitialState();
442 }
443
444
445
446
447
448
449 @JSFProperty(deferredValueType="java.lang.Object")
450 public Locale getLocale()
451 {
452 if (_locale != null)
453 {
454 return _locale;
455 }
456 FacesContext context = FacesContext.getCurrentInstance();
457 return context.getViewRoot().getLocale();
458 }
459
460 public void setLocale(Locale locale)
461 {
462 _locale = locale;
463 clearInitialState();
464 }
465
466
467
468
469
470 @JSFProperty(deferredValueType="java.lang.Integer")
471 public int getMaxFractionDigits()
472 {
473 return _maxFractionDigits;
474 }
475
476 public void setMaxFractionDigits(int maxFractionDigits)
477 {
478 _maxFractionDigitsSet = true;
479 _maxFractionDigits = maxFractionDigits;
480 clearInitialState();
481 }
482
483
484
485
486
487 @JSFProperty(deferredValueType="java.lang.Integer")
488 public int getMaxIntegerDigits()
489 {
490 return _maxIntegerDigits;
491 }
492
493 public void setMaxIntegerDigits(int maxIntegerDigits)
494 {
495 _maxIntegerDigitsSet = true;
496 _maxIntegerDigits = maxIntegerDigits;
497 clearInitialState();
498 }
499
500
501
502
503
504 @JSFProperty(deferredValueType="java.lang.Integer")
505 public int getMinFractionDigits()
506 {
507 return _minFractionDigits;
508 }
509
510 public void setMinFractionDigits(int minFractionDigits)
511 {
512 _minFractionDigitsSet = true;
513 _minFractionDigits = minFractionDigits;
514 clearInitialState();
515 }
516
517
518
519
520
521 @JSFProperty(deferredValueType="java.lang.Integer")
522 public int getMinIntegerDigits()
523 {
524 return _minIntegerDigits;
525 }
526
527 public void setMinIntegerDigits(int minIntegerDigits)
528 {
529 _minIntegerDigitsSet = true;
530 _minIntegerDigits = minIntegerDigits;
531 clearInitialState();
532 }
533
534
535
536
537
538 @JSFProperty
539 public String getPattern()
540 {
541 return _pattern;
542 }
543
544 public void setPattern(String pattern)
545 {
546 _pattern = pattern;
547 clearInitialState();
548 }
549
550 public boolean isTransient()
551 {
552 return _transient;
553 }
554
555 public void setTransient(boolean aTransient)
556 {
557 _transient = aTransient;
558 }
559
560
561
562
563
564
565 @JSFProperty
566 public String getType()
567 {
568 return _type;
569 }
570
571 public void setType(String type)
572 {
573
574 _type = type;
575 clearInitialState();
576 }
577
578 private DecimalFormatSymbols getDecimalFormatSymbols()
579 {
580 return new DecimalFormatSymbols(getLocale());
581 }
582
583 private boolean _initialStateMarked = false;
584
585 public void clearInitialState()
586 {
587 _initialStateMarked = false;
588 }
589
590 public boolean initialStateMarked()
591 {
592 return _initialStateMarked;
593 }
594
595 public void markInitialState()
596 {
597 _initialStateMarked = true;
598 }
599 }