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