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.el.ValueExpression;
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 serialuidtag = "-6592309048440572608L")
62 public abstract class AbstractTypedNumberConverter extends ConverterBase
63 {
64 public static final String CONVERTER_ID = "org.apache.myfaces.custom.convertNumber.TypedNumberConverter";
65
66 public AbstractTypedNumberConverter()
67 {
68 }
69
70 public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String value)
71 {
72 Object convertedValue = _getAsObject(facesContext, uiComponent, value);
73 if (convertedValue == null)
74 {
75 return null;
76 }
77
78 Class destType = getDestType();
79 if (destType == null)
80 {
81 ValueExpression valueBinding = uiComponent.getValueExpression("value");
82 if (valueBinding != null)
83 {
84 destType = valueBinding.getType(facesContext.getELContext());
85 }
86 }
87
88 if (destType != null)
89 {
90 Converter converter = ConvertUtils.lookup(destType);
91 if (converter == null)
92 {
93 throw new UnsupportedOperationException("cant deal with " + destType);
94 }
95
96
97 convertedValue = converter.convert(null, convertedValue);
98 }
99
100
101 return convertedValue;
102 }
103
104
105
106
107
108
109
110 @JSFProperty
111 public Class getDestType()
112 {
113 return (Class) getStateHelper().get(PropertyKeys.destType);
114 }
115
116 public void setDestType(Class destType)
117 {
118 getStateHelper().put(PropertyKeys.destType, destType);
119 }
120
121
122
123
124
125 public static final String STRING_ID = "javax.faces.converter.STRING";
126 public static final String CURRENCY_ID = "javax.faces.converter.NumberConverter.CURRENCY";
127 public static final String NUMBER_ID = "javax.faces.converter.NumberConverter.NUMBER";
128 public static final String PATTERN_ID = "javax.faces.converter.NumberConverter.PATTERN";
129 public static final String PERCENT_ID = "javax.faces.converter.NumberConverter.PERCENT";
130
131 private static final boolean JAVA_VERSION_14;
132
133 static
134 {
135 JAVA_VERSION_14 = checkJavaVersion14();
136 }
137
138 private boolean _transient;
139
140
141
142
143 public Object _getAsObject(FacesContext facesContext, UIComponent uiComponent, String value)
144 {
145 if (facesContext == null) throw new NullPointerException("facesContext");
146 if (uiComponent == null) throw new NullPointerException("uiComponent");
147
148 if (value != null)
149 {
150 value = value.trim();
151 if (value.length() > 0)
152 {
153 NumberFormat format = getNumberFormat(facesContext);
154 format.setParseIntegerOnly(isIntegerOnly());
155
156 DecimalFormat df = (DecimalFormat)format;
157
158
159
160
161
162
163 Class destType = getDestType();
164 if (destType == null)
165 {
166 ValueExpression valueBinding = uiComponent.getValueExpression("value");
167 if (valueBinding != null)
168 {
169 destType = valueBinding.getType(facesContext.getELContext());
170 }
171 }
172 if (destType != null && BigDecimal.class.isAssignableFrom(destType))
173 {
174 df.setParseBigDecimal(true);
175 }
176
177 DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
178 boolean changed = false;
179 if(dfs.getGroupingSeparator() == '\u00a0')
180 {
181 dfs.setGroupingSeparator(' ');
182 df.setDecimalFormatSymbols(dfs);
183 changed = true;
184 }
185
186 formatCurrency(format);
187
188 try
189 {
190 return format.parse(value);
191 }
192 catch (ParseException e)
193 {
194 if(changed)
195 {
196 dfs.setGroupingSeparator('\u00a0');
197 df.setDecimalFormatSymbols(dfs);
198 }
199 try
200 {
201 return format.parse(value);
202 }
203 catch (ParseException pe)
204 {
205
206 if(getPattern() != null)
207 throw new ConverterException(MessageUtils.getMessage(FacesMessage.FACES_MESSAGES, FacesMessage.SEVERITY_ERROR,
208 PATTERN_ID,
209 new Object[]{value,"$###,###",MessageUtils.getLabel(facesContext, uiComponent)},facesContext));
210 else if(getType().equals("number"))
211 throw new ConverterException(MessageUtils.getMessage(FacesMessage.FACES_MESSAGES, FacesMessage.SEVERITY_ERROR,
212 NUMBER_ID,
213 new Object[]{value,format.format(21),MessageUtils.getLabel(facesContext, uiComponent)},facesContext));
214 else if(getType().equals("currency"))
215 throw new ConverterException(MessageUtils.getMessage(FacesMessage.FACES_MESSAGES, FacesMessage.SEVERITY_ERROR,
216 CURRENCY_ID,
217 new Object[]{value,format.format(42.25),MessageUtils.getLabel(facesContext, uiComponent)},facesContext));
218 else if(getType().equals("percent"))
219 throw new ConverterException(MessageUtils.getMessage(FacesMessage.FACES_MESSAGES, FacesMessage.SEVERITY_ERROR,
220 PERCENT_ID,
221 new Object[]{value,format.format(.90),MessageUtils.getLabel(facesContext, uiComponent)},facesContext));
222 }
223 }
224 }
225 }
226 return null;
227 }
228
229 public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value)
230 {
231 if (facesContext == null) throw new NullPointerException("facesContext");
232 if (uiComponent == null) throw new NullPointerException("uiComponent");
233
234 if (value == null)
235 {
236 return "";
237 }
238 if (value instanceof String)
239 {
240 return (String)value;
241 }
242
243 NumberFormat format = getNumberFormat(facesContext);
244 format.setGroupingUsed(isGroupingUsed());
245 Integer maxFractionDigits = getMaxFractionDigits();
246 Integer maxIntegerDigits = getMaxIntegerDigits();
247 Integer minFractionDigits = getMinFractionDigits();
248 Integer minIntegerDigits = getMinIntegerDigits();
249 if (maxFractionDigits != null) format.setMaximumFractionDigits(maxFractionDigits);
250 if (maxIntegerDigits != null) format.setMaximumIntegerDigits(maxIntegerDigits);
251 if (minFractionDigits != null) format.setMinimumFractionDigits(minFractionDigits);
252 if (minIntegerDigits != null) format.setMinimumIntegerDigits(minIntegerDigits);
253 formatCurrency(format);
254 try
255 {
256 return format.format(value);
257 }
258 catch (Exception e)
259 {
260 throw new ConverterException(MessageUtils.getMessage(FacesMessage.FACES_MESSAGES, FacesMessage.SEVERITY_ERROR, STRING_ID, new Object[]{value,MessageUtils.getLabel(facesContext, uiComponent)}, facesContext),e);
261 }
262 }
263
264 private NumberFormat getNumberFormat(FacesContext facesContext)
265 {
266 Locale lokale = getLocale();
267
268 if (getPattern() == null && getType() == null)
269 {
270 throw new ConverterException("Cannot get NumberFormat, either type or pattern needed.");
271 }
272
273
274 if (getPattern() != null)
275 {
276 return new DecimalFormat(getPattern(), new DecimalFormatSymbols(lokale));
277 }
278
279
280 if (getType().equals("number"))
281 {
282 return NumberFormat.getNumberInstance(lokale);
283 }
284 else if (getType().equals("currency"))
285 {
286 return NumberFormat.getCurrencyInstance(lokale);
287 }
288 else if (getType().equals("percent"))
289 {
290 return NumberFormat.getPercentInstance(lokale);
291 }
292 throw new ConverterException("Cannot get NumberFormat, illegal type " + getType());
293 }
294
295 private void formatCurrency(NumberFormat format)
296 {
297 if (getLocalCurrencyCode() == null && getLocalCurrencySymbol() == null)
298 {
299 return;
300 }
301
302 boolean useCurrencyCode;
303 if (JAVA_VERSION_14)
304 {
305 useCurrencyCode = getLocalCurrencyCode() != null;
306 }
307 else
308 {
309 useCurrencyCode = getLocalCurrencySymbol() == null;
310 }
311
312 if (useCurrencyCode)
313 {
314
315 try
316 {
317 format.setCurrency(Currency.getInstance(getLocalCurrencyCode()));
318 }
319 catch (Exception e)
320 {
321 throw new ConverterException("Unable to get Currency instance for currencyCode " +
322 getLocalCurrencyCode());
323 }
324 }
325 else if (format instanceof DecimalFormat)
326
327 {
328 DecimalFormat dFormat = (DecimalFormat)format;
329 DecimalFormatSymbols symbols = dFormat.getDecimalFormatSymbols();
330 symbols.setCurrencySymbol(getLocalCurrencySymbol());
331 dFormat.setDecimalFormatSymbols(symbols);
332 }
333 }
334
335
336
337
338
339
340
341
342
343 @JSFProperty
344 public String getCurrencyCode()
345 {
346 String value = (String) getStateHelper().eval(PropertyKeys.currencyCode);
347 if (value != null)
348 {
349 return value;
350 }
351 return getDecimalFormatSymbols().getInternationalCurrencySymbol();
352 }
353
354 protected String getLocalCurrencyCode()
355 {
356 return (String) getStateHelper().eval(PropertyKeys.currencyCode);
357 }
358
359 public void setCurrencyCode(String currencyCode)
360 {
361 getStateHelper().put(PropertyKeys.currencyCode, currencyCode);
362 }
363
364
365
366
367
368
369
370 @JSFProperty
371 public String getCurrencySymbol()
372 {
373 String value = (String) getStateHelper().eval(PropertyKeys.currencySymbol);
374 if (value != null)
375 {
376 return value;
377 }
378 return getDecimalFormatSymbols().getCurrencySymbol();
379 }
380
381 protected String getLocalCurrencySymbol()
382 {
383 return (String) getStateHelper().eval(PropertyKeys.currencySymbol);
384 }
385
386 public void setCurrencySymbol(String currencySymbol)
387 {
388 getStateHelper().put(PropertyKeys.currencySymbol, currencySymbol);
389 }
390
391
392
393
394
395
396
397 @JSFProperty(defaultValue="true")
398 public abstract boolean isGroupingUsed();
399
400
401
402
403
404
405
406 @JSFProperty(defaultValue="false")
407 public abstract boolean isIntegerOnly();
408
409
410
411
412
413
414 @JSFProperty(deferredValueType="java.lang.Object")
415 public Locale getLocale()
416 {
417 Object value = getStateHelper().eval(PropertyKeys.locale);
418 if (value instanceof String)
419 {
420 value = org.apache.myfaces.commons.util.TagUtils.getLocale(value);
421 }
422 if (value != null)
423 {
424 return (Locale) value;
425 }
426 FacesContext context = FacesContext.getCurrentInstance();
427 return context.getViewRoot().getLocale();
428 }
429
430 public void setLocale(Locale locale)
431 {
432 getStateHelper().put(PropertyKeys.locale, locale);
433 }
434
435
436
437
438
439 @JSFProperty
440 public abstract Integer getMaxFractionDigits();
441
442
443
444
445
446 @JSFProperty
447 public abstract Integer getMaxIntegerDigits();
448
449
450
451
452
453 @JSFProperty
454 public abstract Integer getMinFractionDigits();
455
456
457
458
459
460 @JSFProperty
461 public abstract Integer getMinIntegerDigits();
462
463
464
465
466
467 @JSFProperty
468 public abstract String getPattern();
469
470 public boolean isTransient()
471 {
472 return _transient;
473 }
474
475 public void setTransient(boolean aTransient)
476 {
477 _transient = aTransient;
478 }
479
480
481
482
483
484
485
486 @JSFProperty(defaultValue="number")
487 public abstract String getType();
488
489 private static boolean checkJavaVersion14()
490 {
491 String version = System.getProperty("java.version");
492 if (version == null)
493 {
494 return false;
495 }
496 byte java14 = 0;
497 for (int idx = version.indexOf('.'), i = 0; idx > 0 || version != null; i++)
498 {
499 if (idx > 0)
500 {
501 byte value = Byte.parseByte(version.substring(0, 1));
502 version = version.substring(idx + 1, version.length());
503 idx = version.indexOf('.');
504 switch (i)
505 {
506 case 0:
507 if (value == 1)
508 {
509 java14 = 1;
510 break;
511 }
512 else if (value > 1)
513 {
514 java14 = 2;
515 }
516 case 1:
517 if (java14 > 0 && value >= 4)
518 {
519 java14 = 2;
520 }
521 ;
522 default:
523 idx = 0;
524 version = null;
525 break;
526 }
527 }
528 else
529 {
530 byte value = Byte.parseByte(version.substring(0, 1));
531 if (java14 > 0 && value >= 4)
532 {
533 java14 = 2;
534 }
535 break;
536 }
537 }
538 return java14 == 2;
539 }
540
541
542 private DecimalFormatSymbols getDecimalFormatSymbols()
543 {
544 return new DecimalFormatSymbols(getLocale());
545 }
546
547 enum PropertyKeys
548 {
549 destType,
550 currencyCode,
551 currencySymbol,
552 locale
553 }
554 }