1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.trinidad.convert;
20
21 import java.text.DateFormat;
22 import java.text.DateFormatSymbols;
23 import java.text.ParseException;
24 import java.text.SimpleDateFormat;
25
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Calendar;
29 import java.util.Date;
30 import java.util.GregorianCalendar;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Locale;
34 import java.util.Map;
35 import java.util.MissingResourceException;
36 import java.util.ResourceBundle;
37 import java.util.TimeZone;
38
39 import javax.el.ValueExpression;
40
41 import javax.faces.application.FacesMessage;
42 import javax.faces.component.StateHolder;
43 import javax.faces.component.UIComponent;
44 import javax.faces.component.ValueHolder;
45 import javax.faces.context.FacesContext;
46 import javax.faces.convert.Converter;
47 import javax.faces.convert.ConverterException;
48 import javax.faces.el.ValueBinding;
49
50 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFConverter;
51 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
52 import org.apache.myfaces.trinidad.bean.FacesBean;
53 import org.apache.myfaces.trinidad.bean.PropertyKey;
54 import org.apache.myfaces.trinidad.context.RequestContext;
55 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
56 import org.apache.myfaces.trinidad.util.ComponentUtils;
57 import org.apache.myfaces.trinidad.util.MessageFactory;
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177 @JSFConverter(configExcluded=true)
178 public class DateTimeConverter extends javax.faces.convert.DateTimeConverter
179 implements Converter, StateHolder
180
181 {
182
183
184
185
186 public static final String CONVERTER_ID = "org.apache.myfaces.trinidad.DateTime";
187
188
189
190
191
192
193
194
195
196
197
198
199 public static final String CONVERT_DATE_MESSAGE_ID =
200 "org.apache.myfaces.trinidad.convert.DateTimeConverter.CONVERT_DATE";
201
202
203
204
205
206
207
208
209
210
211
212 public static final String CONVERT_TIME_MESSAGE_ID =
213 "org.apache.myfaces.trinidad.convert.DateTimeConverter.CONVERT_TIME";
214
215
216
217
218
219
220
221
222
223
224
225 public static final String CONVERT_BOTH_MESSAGE_ID =
226 "org.apache.myfaces.trinidad.convert.DateTimeConverter.CONVERT_BOTH";
227
228
229
230
231 public DateTimeConverter()
232 {
233 }
234
235
236
237
238
239
240
241 public DateTimeConverter(String pattern)
242 {
243 this();
244 setPattern(pattern);
245 }
246
247
248
249
250
251
252
253
254
255
256 public DateTimeConverter(String pattern, String secondaryPattern)
257 {
258 this(pattern);
259 setSecondaryPattern(secondaryPattern);
260
261 }
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285 @Override
286 public Object getAsObject(
287 FacesContext context,
288 UIComponent component,
289 String value)
290 {
291 if (isDisabled())
292 return value;
293
294 Date date = _getParsedDate(context, component, value);
295 if (date != null)
296 {
297 _fillTimePortion(context, component, date);
298 }
299
300 return date;
301 }
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320 @Override
321 public String getAsString(
322 FacesContext context,
323 UIComponent component,
324 Object value
325 )
326 {
327 if (context == null || component == null)
328 throw new NullPointerException(_LOG.getMessage(
329 "NULL_FACESCONTEXT_OR_UICOMPONENT"));
330
331 if (null == value)
332 return "";
333
334 if (value instanceof String)
335 return (String)value;
336
337 if (isDisabled())
338 return value.toString();
339
340 if (!(value instanceof Date))
341 throw new ClassCastException(_LOG.getMessage(
342 "VALUE_IS_NOT_DATE_TYPE_IT_IS", new Object[]{value,value.getClass()}));
343
344 DateFormat format = _getDateFormat(context, getPattern(), false, (Date)value);
345 return format.format(value);
346 }
347
348
349
350
351
352
353
354
355
356
357 public void setMessageDetailConvertDate(String convertDateMessageDetail)
358 {
359 _facesBean.setProperty(_CONVERT_DATE_MESSAGE_DETAIL_KEY, convertDateMessageDetail);
360 }
361
362
363
364
365
366
367
368
369
370 @JSFProperty
371 public String getMessageDetailConvertDate()
372 {
373 Object msg = _facesBean.getProperty(_CONVERT_DATE_MESSAGE_DETAIL_KEY);
374 return ComponentUtils.resolveString(msg);
375 }
376
377
378
379
380
381
382
383
384 public void setMessageDetailConvertTime(String convertTimeMessageDetail)
385 {
386 _facesBean.setProperty(_CONVERT_TIME_MESSAGE_DETAIL_KEY, convertTimeMessageDetail);
387 }
388
389
390
391
392
393
394
395
396 @JSFProperty
397 public String getMessageDetailConvertTime()
398 {
399 Object msg =_facesBean.getProperty(_CONVERT_TIME_MESSAGE_DETAIL_KEY);
400 return ComponentUtils.resolveString(msg);
401 }
402
403
404
405
406
407
408
409
410
411 public void setMessageDetailConvertBoth(String convertBothMessageDetail)
412 {
413 _facesBean.setProperty(_CONVERT_BOTH_MESSAGE_DETAIL_KEY, convertBothMessageDetail);
414 }
415
416
417
418
419
420
421
422
423 @JSFProperty
424 public String getMessageDetailConvertBoth()
425 {
426 Object msg = _facesBean.getProperty(_CONVERT_BOTH_MESSAGE_DETAIL_KEY);
427 return ComponentUtils.resolveString(msg);
428 }
429
430
431
432
433
434
435 public void setHintDate(String hintDate)
436 {
437 _facesBean.setProperty(_HINT_DATE_KEY, hintDate);
438 }
439
440
441
442
443
444
445 public String getHintDate()
446 {
447 Object obj = _facesBean.getProperty(_HINT_DATE_KEY);
448 return ComponentUtils.resolveString(obj);
449 }
450
451
452
453
454
455
456 public void setHintTime(String hintTime)
457 {
458 _facesBean.setProperty(_HINT_TIME_KEY, hintTime);
459 }
460
461
462
463
464
465
466 public String getHintTime()
467 {
468 Object obj = _facesBean.getProperty(_HINT_TIME_KEY);
469 return ComponentUtils.resolveString(obj);
470 }
471
472
473
474
475
476
477 public void setHintBoth(String hintBoth)
478 {
479 _facesBean.setProperty(_HINT_BOTH_KEY, hintBoth);
480 }
481
482
483
484
485
486
487 public String getHintBoth()
488 {
489 Object obj = _facesBean.getProperty(_HINT_BOTH_KEY);
490 return ComponentUtils.resolveString(obj);
491 }
492
493
494
495
496
497
498
499
500
501
502
503
504 protected Date getDate(FacesContext context, UIComponent component)
505 {
506 if (component instanceof ValueHolder)
507 {
508 Object value = ((ValueHolder)component).getValue();
509 if(value instanceof Date)
510 {
511 return (Date)value;
512 }
513 }
514 return null;
515 }
516
517 private Locale _extractConverterLocale(
518 FacesContext context)
519 {
520 Locale locale = getLocale();
521 if (null == locale)
522 {
523 RequestContext reqContext = RequestContext.getCurrentInstance();
524 if (reqContext != null)
525 {
526 locale = reqContext.getFormattingLocale();
527 }
528 if (locale == null)
529 {
530 locale = context.getViewRoot().getLocale();
531 }
532 }
533 return locale;
534 }
535
536 private Date _getParsedDate(FacesContext context,
537 UIComponent component,
538 String value)
539 {
540 if (context == null || component == null)
541 throw new NullPointerException(_LOG.getMessage(
542 "NULL_FACESCONTEXT_OR_UICOMPONENT"));
543
544 if (null == value)
545 return null;
546
547 value = value.trim();
548
549 if ( 1 > value.length() )
550 return null;
551
552 try
553 {
554 String pattern = getPattern();
555 if (pattern == null)
556 {
557
558 DateFormat format = getDateFormat(context, null, true, null);
559 if (format instanceof SimpleDateFormat)
560 {
561 pattern = ((SimpleDateFormat)format).toPattern();
562 }
563 }
564
565 if (pattern != null)
566 {
567 return _doLenientParse(context, component, value, pattern);
568 }
569 else
570 {
571
572 return _parse(context, component, value, null);
573 }
574 }
575 catch (ConverterException ce)
576 {
577 try
578 {
579
580
581 String secPattern = getSecondaryPattern();
582 if ( secPattern != null)
583 {
584 return _doLenientParse(context, component, value, secPattern);
585 }
586 }
587 catch(ConverterException secondaryCe)
588 {
589
590 ;
591 }
592 throw ce;
593 }
594 }
595
596
597
598
599
600
601
602
603 private void _fillTimePortion(
604 FacesContext context,
605 UIComponent component,
606 Date newDate)
607 {
608
609 Date prevDate = getDate(context, component);
610
611
612 if (prevDate == null)
613 {
614 return;
615 }
616
617
618 String pattern = getPattern();
619 if (pattern == null && !"date".equals(getType()))
620 {
621 return;
622 }
623
624
625 boolean fillMilliSeconds = true;
626 boolean fillSeconds = true;
627 boolean fillMinutes = true;
628 boolean fillHour = true;
629
630 if (pattern != null)
631 {
632 int patternLen = pattern.length();
633 for (int currCharIndex = 0; currCharIndex < patternLen; currCharIndex++)
634 {
635 switch (pattern.charAt(currCharIndex))
636 {
637 case 'S':
638 fillMilliSeconds = false;
639 break;
640 case 's':
641 fillSeconds = false;
642 break;
643 case 'm':
644 fillMinutes = false;
645 break;
646 case 'h':
647 case 'H':
648 case 'k':
649 case 'K':
650 fillHour = false;
651 break;
652 }
653 }
654 }
655
656
657 if ( fillMilliSeconds || fillSeconds || fillMinutes || fillHour )
658 {
659 TimeZone timeZone = _getTimeZone();
660
661
662 Calendar prevCal = Calendar.getInstance(timeZone);
663 prevCal.setTime(prevDate);
664
665 Calendar newCal = Calendar.getInstance(timeZone);
666 newCal.setTime(newDate);
667
668
669
670 if (fillMilliSeconds)
671 {
672 newCal.set(Calendar.MILLISECOND, prevCal.get(Calendar.MILLISECOND));
673 }
674
675 if (fillSeconds)
676 {
677 newCal.set(Calendar.SECOND, prevCal.get(Calendar.SECOND));
678 }
679
680 if(fillMinutes)
681 {
682 newCal.set(Calendar.MINUTE, prevCal.get(Calendar.MINUTE));
683 }
684
685 if(fillHour)
686 {
687 newCal.set(Calendar.HOUR_OF_DAY, prevCal.get(Calendar.HOUR_OF_DAY));
688 }
689
690
691 newDate.setTime(newCal.getTimeInMillis());
692 }
693 }
694
695 private Date _parse(
696 FacesContext context,
697 UIComponent component,
698 String value,
699 String pattern
700 )
701 {
702 DateFormat fmt = getDateFormat(context, pattern, true, null);
703 try
704 {
705 return fmt.parse(value);
706
707 } catch (ConverterException ce)
708 {
709 throw ce;
710 }
711 catch (ParseException pe)
712 {
713 Object[] params = _getPlaceHolderParameters(context, component, value);
714 throw new ConverterException(getParseErrorMessage(context, component,
715 pattern, params),
716 pe);
717 }
718 }
719
720
721
722
723 private Date _doLenientParse(
724 FacesContext context,
725 UIComponent component,
726 String value,
727 String pattern
728 )
729 {
730
731
732
733
734
735 if(pattern.endsWith(" '"))
736 {
737 value += " ";
738 }
739
740
741
742
743
744
745
746
747 ConverterException ce;
748 try
749 {
750 return _parse(context, component, value, pattern);
751 }
752 catch (ConverterException convException)
753 {
754
755
756 ce = convException;
757
758 List<String> patterns = new ArrayList<String>();
759 patterns.add(pattern);
760
761 Locale locale = _extractConverterLocale(context);
762
763 if (_CONVENIENCE_PATTERNS.containsKey(locale))
764 {
765 patterns.addAll(_CONVENIENCE_PATTERNS.get(locale));
766 }
767 List<String> lenientPatterns = new ArrayList<String>();
768 for (String tmpPattern : patterns)
769 {
770 lenientPatterns.addAll(_getLenientPatterns(tmpPattern));
771 }
772
773 for (String lenientPattern : lenientPatterns)
774 {
775 try
776 {
777 return _parse(context, component, value, lenientPattern);
778 }
779 catch (ConverterException e)
780 {
781
782
783
784 continue;
785 }
786 }
787 throw ce;
788 }
789 }
790
791
792
793
794
795
796
797
798
799
800
801 @Override
802 public void setLocale(Locale locale)
803 {
804 _facesBean.setProperty(_LOCALE_KEY, locale);
805 }
806
807
808
809
810
811
812
813
814 @JSFProperty
815 @Override
816 public Locale getLocale()
817 {
818 Object locale = _facesBean.getProperty(_LOCALE_KEY);
819 return ComponentUtils.resolveLocale(locale);
820 }
821
822
823
824
825
826
827
828
829
830
831 @Override
832 public void setPattern(String pattern)
833 {
834 _facesBean.setProperty(_PATTERN_KEY, pattern);
835 }
836
837
838
839
840
841 @JSFProperty
842 @Override
843 public String getPattern()
844 {
845 Object patternObj = _facesBean.getProperty(_PATTERN_KEY);
846 String pattern = ComponentUtils.resolveString(patternObj);
847
848 if (pattern != null && pattern.trim().isEmpty())
849 {
850 return null;
851 }
852
853 return pattern;
854 }
855
856
857
858
859
860
861 @Override
862 public void setTimeZone(TimeZone timeZone)
863 {
864 _facesBean.setProperty(_TIME_ZONE_KEY, timeZone);
865 }
866
867
868
869
870
871
872
873
874 @JSFProperty
875 @Override
876 public TimeZone getTimeZone()
877 {
878 Object timeZone = _facesBean.getProperty(_TIME_ZONE_KEY);
879 return ComponentUtils.resolveTimeZone(timeZone);
880 }
881
882
883
884
885
886
887
888
889
890
891 @Override
892 public void setType(String type)
893 {
894 _facesBean.setProperty(_TYPE_KEY, type);
895 }
896
897
898
899
900
901
902 @JSFProperty(defaultValue="date")
903 @Override
904 public String getType()
905 {
906 Object type = _facesBean.getProperty(_TYPE_KEY);
907 return ComponentUtils.resolveString(type, "date");
908 }
909
910
911
912
913
914
915
916
917
918
919
920 @Override
921 public void setDateStyle(String dateStyle)
922 {
923 _facesBean.setProperty(_DATE_STYLE_KEY, dateStyle);
924 }
925
926
927
928
929
930
931
932 @JSFProperty(defaultValue="shortish")
933 @Override
934 public String getDateStyle()
935 {
936 Object dateStyle = _facesBean.getProperty(_DATE_STYLE_KEY);
937 return ComponentUtils.resolveString(dateStyle, "shortish");
938 }
939
940
941
942
943
944
945
946
947
948
949 @Override
950 public void setTimeStyle(String timeStyle)
951 {
952 _facesBean.setProperty(_TIME_STYLE_KEY, timeStyle);
953 }
954
955
956
957
958
959 @JSFProperty(defaultValue="short")
960 @Override
961 public String getTimeStyle()
962 {
963 Object timeStyle = _facesBean.getProperty(_TIME_STYLE_KEY);
964 return ComponentUtils.resolveString(timeStyle, "short");
965 }
966
967
968
969
970
971
972
973
974
975 public void setSecondaryPattern(String secondaryPattern)
976 {
977 _facesBean.setProperty(_SECONDARY_PATTERN_KEY, secondaryPattern);
978 }
979
980
981
982
983
984 @JSFProperty
985 public String getSecondaryPattern()
986 {
987 Object secPattern = _facesBean.getProperty(_SECONDARY_PATTERN_KEY);
988 return ComponentUtils.resolveString(secPattern);
989 }
990
991 @Override
992 public boolean isTransient()
993 {
994 return _isTransient;
995 }
996
997 @Override
998 public void setTransient(boolean isTransient)
999 {
1000 _isTransient = isTransient;
1001 }
1002
1003 @Override
1004 public Object saveState(FacesContext context)
1005 {
1006 return _facesBean.saveState(context);
1007 }
1008
1009 @Override
1010 public void restoreState(FacesContext context, Object state)
1011 {
1012 _facesBean.restoreState(context, state);
1013 }
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028 public void setValueExpression(String name, ValueExpression expression)
1029 {
1030 ConverterUtils.setValueExpression(_facesBean, name, expression) ;
1031 }
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046 public ValueExpression getValueExpression(String name)
1047 {
1048 return ConverterUtils.getValueExpression(_facesBean, name);
1049 }
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065 public void setValueBinding(String name, ValueBinding binding)
1066 {
1067 ConverterUtils.setValueBinding(_facesBean, name, binding) ;
1068 }
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084 public ValueBinding getValueBinding(String name)
1085 {
1086 return ConverterUtils.getValueBinding(_facesBean, name);
1087 }
1088
1089
1090
1091
1092
1093
1094
1095
1096 @Override
1097 public boolean equals(Object object)
1098 {
1099 if (this == object)
1100 return true;
1101
1102 if(object instanceof DateTimeConverter)
1103 {
1104 DateTimeConverter other = (DateTimeConverter)object;
1105
1106 if ( (isDisabled() == other.isDisabled())
1107 && (isTransient() == other.isTransient())
1108 && ConverterUtils.equals(getDateStyle(), other.getDateStyle())
1109 && ConverterUtils.equals(getLocale(), other.getLocale())
1110 && ConverterUtils.equals(getPattern(), other.getPattern())
1111 && ConverterUtils.equals(getTimeStyle(), other.getTimeStyle())
1112 && ConverterUtils.equals(getTimeZone(), other.getTimeZone())
1113 && ConverterUtils.equals(getType(), other.getType())
1114 && ConverterUtils.equals(getSecondaryPattern(), other.getSecondaryPattern())
1115 && ConverterUtils.equals(getMessageDetailConvertDate(),
1116 other.getMessageDetailConvertDate())
1117 && ConverterUtils.equals(getMessageDetailConvertTime(),
1118 other.getMessageDetailConvertTime())
1119 && ConverterUtils.equals(getMessageDetailConvertBoth(),
1120 other.getMessageDetailConvertBoth())
1121 )
1122 {
1123 return true;
1124 }
1125 }
1126 return false;
1127 }
1128
1129
1130
1131
1132
1133 @Override
1134 public int hashCode()
1135 {
1136 int result = 17;
1137 result = result * 37 + (isDisabled() ? 1 : 0);
1138 result = result * 37 + (isTransient()? 1 : 0);
1139 result = result * 37 + _getHashValue(getDateStyle());
1140 result = result * 37 + _getHashValue(getLocale());
1141 result = result * 37 + _getHashValue(getPattern());
1142 result = result * 37 + _getHashValue(getTimeStyle());
1143 result = result * 37 + _getHashValue(getTimeZone());
1144 result = result * 37 + _getHashValue(getType());
1145 result = result * 37 + _getHashValue(getSecondaryPattern());
1146 result = result * 37 + _getHashValue(getMessageDetailConvertDate());
1147 result = result * 37 + _getHashValue(getMessageDetailConvertTime());
1148 result = result * 37 + _getHashValue(getMessageDetailConvertBoth());
1149 return result;
1150 }
1151
1152
1153
1154
1155
1156 public void setDisabled(boolean isDisabled)
1157 {
1158 _facesBean.setProperty(_DISABLED_KEY, Boolean.valueOf(isDisabled));
1159 }
1160
1161
1162
1163
1164
1165 public boolean isDisabled()
1166 {
1167 Boolean disabled = (Boolean) _facesBean.getProperty(_DISABLED_KEY);
1168
1169 return (disabled != null) ? disabled.booleanValue() : false;
1170 }
1171
1172 protected final DateFormat getDateFormat(
1173 FacesContext context,
1174 String pattern,
1175 boolean forParsing,
1176 Date targetDate
1177 ) throws ConverterException
1178 {
1179 ConverterException exception = null;
1180 try
1181 {
1182 DateFormat format = _getDateFormat(context, pattern, forParsing, targetDate);
1183 return format;
1184 }
1185 catch (ConverterException ce)
1186 {
1187 exception = ce;
1188 }
1189 catch (Exception e)
1190 {
1191 exception = new ConverterException(e);
1192 }
1193 throw exception;
1194 }
1195
1196
1197
1198
1199
1200
1201
1202 protected TimeZone getFormattingTimeZone(TimeZone tZone)
1203 {
1204 return getFormattingTimeZone (tZone, null);
1205 }
1206
1207
1208
1209
1210
1211
1212 protected TimeZone getFormattingTimeZone(TimeZone tZone, Date targetDate)
1213 {
1214 return tZone;
1215 }
1216
1217
1218
1219 private String[] _getExpectedPatterns(FacesContext context)
1220 {
1221 String pattern = getPattern();
1222
1223 if ( pattern != null )
1224 {
1225 return _getAllowedPatterns(context, pattern, getSecondaryPattern());
1226 }
1227 else
1228 {
1229 String datePattern = null;
1230
1231 try
1232 {
1233 DateFormat format = getDateFormat(context, null,false, null);
1234 if ((format != null) && (format instanceof SimpleDateFormat))
1235 {
1236 datePattern = ((SimpleDateFormat)format).toPattern();
1237 }
1238 }
1239 catch (ConverterException ce)
1240 {
1241
1242 ;
1243 }
1244 return _getAllowedPatterns(context, datePattern, getSecondaryPattern());
1245 }
1246 }
1247
1248 protected final FacesMessage getParseErrorMessage(
1249 FacesContext context,
1250 UIComponent component,
1251 String pattern,
1252 Object[] params
1253 )
1254 {
1255
1256
1257 String key = getViolationMessageKey(pattern);
1258 return _getConvertErrorFacesMessage(context, key, params, component);
1259
1260 }
1261
1262 protected final String getExample(FacesContext context)
1263 {
1264 String[] expectedPatterns = _getExpectedPatterns(context);
1265
1266 assert((expectedPatterns != null) && (expectedPatterns.length >= 1));
1267 String example = expectedPatterns[0];
1268 return example;
1269 }
1270
1271 private String[] _getAllowedPatterns(
1272 FacesContext context,
1273 String mainPattern,
1274 String secondaryPattern
1275 )
1276 {
1277 String[] patterns;
1278
1279 if (mainPattern != null)
1280 {
1281 if (secondaryPattern != null)
1282 {
1283 patterns = new String[]{mainPattern, secondaryPattern};
1284 }
1285 else
1286 {
1287 patterns = new String[]{mainPattern};
1288 }
1289 }
1290 else
1291 {
1292 patterns = new String[]{secondaryPattern};
1293 }
1294
1295
1296 for (int i = 0; i < patterns.length; i++)
1297 {
1298 patterns[i] = _getExample(context, patterns[i]);
1299 }
1300
1301 return patterns;
1302 }
1303
1304
1305
1306
1307
1308
1309
1310
1311 private static final int _getDateStyle(String dateStyle)
1312 {
1313 if (dateStyle.equals("shortish"))
1314 {
1315 return _SHORTISH;
1316 }
1317 else if (dateStyle.equals("default"))
1318 {
1319 return (DateFormat.DEFAULT);
1320 }
1321 else if (dateStyle.equals("short"))
1322 {
1323 return (DateFormat.SHORT);
1324 }
1325 else if (dateStyle.equals("medium"))
1326 {
1327 return (DateFormat.MEDIUM);
1328 }
1329 else if (dateStyle.equals("long"))
1330 {
1331 return (DateFormat.LONG);
1332 }
1333 else if (dateStyle.equals("full"))
1334 {
1335 return (DateFormat.FULL);
1336 }
1337 else
1338 throw new IllegalStateException(_LOG.getMessage(
1339 "INVALID_DATE_STYLE", dateStyle));
1340 }
1341
1342 private static final int _getTimeStyle(String timeStyle)
1343 {
1344 if ("default".equals(timeStyle))
1345 {
1346 return (DateFormat.DEFAULT);
1347 }
1348 else if ("short".equals(timeStyle))
1349 {
1350 return (DateFormat.SHORT);
1351 }
1352 else if ("medium".equals(timeStyle))
1353 {
1354 return (DateFormat.MEDIUM);
1355 }
1356 else if ("long".equals(timeStyle))
1357 {
1358 return (DateFormat.LONG);
1359 }
1360 else if ("full".equals(timeStyle))
1361 {
1362 return (DateFormat.FULL);
1363 }
1364 else
1365 throw new IllegalStateException(_LOG.getMessage(
1366 "INVALID_TIME_STYLE", timeStyle));
1367 }
1368
1369
1370
1371
1372
1373
1374 private static int _getType(String type)
1375 {
1376 if ("date".equals(type))
1377 return _TYPE_DATE;
1378 else if ("time".equals(type))
1379 return _TYPE_TIME;
1380 else if ("both".equals(type))
1381 return _TYPE_BOTH;
1382 else
1383 throw new IllegalStateException(_LOG.getMessage(
1384 "INVALID_TYPE", type));
1385 }
1386
1387
1388
1389 private static int _getHashValue(Object obj)
1390 {
1391 return obj == null? 0 : obj.hashCode();
1392 }
1393
1394 private static List<String> _getLenientPatterns(String pattern)
1395 {
1396
1397
1398
1399
1400
1401
1402
1403
1404 List<String> patterns = new ArrayList<String>();
1405
1406 patterns.add(pattern);
1407
1408 String[] leniencyApplicablePatterns = new String[1];
1409 leniencyApplicablePatterns[0] = pattern;
1410
1411 if (pattern.indexOf("MMM") != -1)
1412 {
1413 leniencyApplicablePatterns = new String[3];
1414 leniencyApplicablePatterns[0] = pattern;
1415
1416 String str1 = pattern.replaceAll("MMM", "MM");
1417 patterns.add(str1);
1418 leniencyApplicablePatterns[1] = str1;
1419
1420 String str2 = pattern.replaceAll("MMM", "M");
1421 leniencyApplicablePatterns[2] = str2;
1422 patterns.add(str2);
1423 }
1424
1425
1426
1427 int len = leniencyApplicablePatterns.length;
1428 if (pattern.indexOf('/') != -1)
1429 {
1430 for (int i = 0; i < len; i++)
1431 patterns.add(leniencyApplicablePatterns[i].replaceAll("/", "-"));
1432
1433 for (int i = 0; i < len; i++)
1434 patterns.add(leniencyApplicablePatterns[i].replaceAll("/", "."));
1435 }
1436 else if (pattern.indexOf('-') != -1)
1437 {
1438 for (int i = 0; i < len; i++)
1439 patterns.add(leniencyApplicablePatterns[i].replaceAll("-", "/"));
1440
1441 for (int i = 0; i < len; i++)
1442 patterns.add(leniencyApplicablePatterns[i].replaceAll("-", "."));
1443 }
1444 else if (pattern.indexOf('.') != -1)
1445 {
1446 for (int i = 0; i < len; i++)
1447 patterns.add(leniencyApplicablePatterns[i].replaceAll("\\.", "/"));
1448
1449 for (int i = 0; i < len; i++)
1450 patterns.add(leniencyApplicablePatterns[i].replaceAll("\\.", "-"));
1451 }
1452
1453 return patterns;
1454 }
1455
1456 private Object[] _getPlaceHolderParameters(
1457 FacesContext context,
1458 UIComponent component,
1459 String value)
1460 {
1461 Object label = ConverterUtils.getComponentLabel(component);
1462 String example = getExample(context);
1463 Object[] params = {label, value, example};
1464 return params;
1465 }
1466
1467 private Object _getRawConvertBothMessageDetail()
1468 {
1469 return _facesBean.getRawProperty(_CONVERT_BOTH_MESSAGE_DETAIL_KEY);
1470 }
1471
1472 private Object _getRawConvertDateMessageDetail()
1473 {
1474 return _facesBean.getRawProperty(_CONVERT_DATE_MESSAGE_DETAIL_KEY);
1475 }
1476
1477 private Object _getRawConvertTimeMessageDetail()
1478 {
1479 return _facesBean.getRawProperty(_CONVERT_TIME_MESSAGE_DETAIL_KEY);
1480 }
1481
1482 private FacesMessage _getConvertErrorFacesMessage(
1483 FacesContext context,
1484 String key,
1485 Object[] params,
1486 UIComponent component
1487 )
1488 {
1489 Object msgPattern = getMessagePattern(context, key, params, component);
1490 return MessageFactory.getMessage(context, key, msgPattern,
1491 params, component);
1492 }
1493
1494 private String _getExample(FacesContext context, String pattern)
1495 {
1496 DateFormat format = _getDateFormat(context, pattern, false, _EXAMPLE_DATE);
1497 return format.format(_EXAMPLE_DATE);
1498 }
1499
1500
1501 protected Object getMessagePattern(
1502 FacesContext context,
1503 String key,
1504 Object[] params,
1505 UIComponent component
1506 )
1507 {
1508 Object msgPattern;
1509 if (CONVERT_DATE_MESSAGE_ID.equals(key))
1510 {
1511 msgPattern = _getRawConvertDateMessageDetail();
1512 }
1513 else if (CONVERT_TIME_MESSAGE_ID.equals(key))
1514 {
1515 msgPattern = _getRawConvertTimeMessageDetail();
1516 }
1517 else if (CONVERT_BOTH_MESSAGE_ID.equals(key))
1518 {
1519 msgPattern = _getRawConvertBothMessageDetail();
1520 }
1521 else
1522 {
1523
1524 throw new IllegalArgumentException(_LOG.getMessage(
1525 "ILLEGAL_MESSAGE_ID", key));
1526 }
1527
1528 return msgPattern;
1529 }
1530
1531 protected String getViolationMessageKey(String pattern)
1532 {
1533 String key = null;
1534
1535 if (getPattern() == null || pattern == null)
1536 {
1537 String type = getType();
1538 if("date".equals(type))
1539 {
1540 key = CONVERT_DATE_MESSAGE_ID;
1541 }
1542 else if ("time".equals(type))
1543 {
1544 key = CONVERT_TIME_MESSAGE_ID;
1545 }
1546 else if ("both".equals(type))
1547 {
1548 key = CONVERT_BOTH_MESSAGE_ID;
1549 }
1550 else if (pattern == null)
1551 {
1552
1553
1554 throw new IllegalArgumentException(_LOG.getMessage(
1555 "ILLEGAL_ATTRIBUTE_TYPE_VALUE", type));
1556 }
1557 }
1558
1559 if (key == null)
1560 {
1561
1562 key = CONVERT_DATE_MESSAGE_ID;
1563 }
1564
1565 return key;
1566 }
1567
1568 private SimpleDateFormat _getSimpleDateFormat(String pattern, Locale locale)
1569 {
1570 String variant = locale.getVariant();
1571 SimpleDateFormat sdf = null;
1572
1573 if ((variant != null) && (variant.toUpperCase().startsWith("ORACLE")))
1574 {
1575
1576
1577 try
1578 {
1579 ResourceBundle oraElementsData =
1580 ResourceBundle.getBundle(_ORA_LOCALE_ELEMENTS_BASE, locale);
1581
1582 DateFormatSymbols syms = new DateFormatSymbols(locale);
1583
1584 String[] res = oraElementsData.getStringArray("AmPmMarkers");
1585 if (res != null)
1586 syms.setAmPmStrings(res);
1587 res = oraElementsData.getStringArray("Eras");
1588 if (res != null)
1589 syms.setEras(res);
1590 res = oraElementsData.getStringArray("MonthNames");
1591 if (res != null)
1592 syms.setMonths(res);
1593 res = oraElementsData.getStringArray("MonthAbbreviations");
1594 if (res != null)
1595 syms.setShortMonths(res);
1596 res = oraElementsData.getStringArray("DayAbbreviations");
1597 if (res != null)
1598 syms.setShortWeekdays(res);
1599 res = oraElementsData.getStringArray("DayNames");
1600 if (res != null)
1601 syms.setWeekdays(res);
1602 sdf = new SimpleDateFormat(pattern, syms);
1603 }
1604 catch (MissingResourceException e)
1605 {
1606
1607 sdf = new SimpleDateFormat(pattern, locale);
1608 }
1609 }
1610 else
1611 sdf = new SimpleDateFormat(pattern, locale);
1612
1613 return sdf;
1614 }
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624 private SimpleDateFormat _get4YearFormat(
1625 SimpleDateFormat format,
1626 Locale loc
1627 )
1628 {
1629 String formatPattern = format.toPattern();
1630
1631
1632
1633
1634 int patternLen = formatPattern.length();
1635
1636 int firstYIndex = -1;
1637 int yCount = 0;
1638 boolean inQuotes = false;
1639
1640 int currCharIndex = 0;
1641
1642 for (; currCharIndex < patternLen; currCharIndex++)
1643 {
1644 char currChar = formatPattern.charAt(currCharIndex);
1645
1646 switch (currChar)
1647 {
1648 case 'y':
1649 if (!inQuotes)
1650 {
1651
1652 if (firstYIndex < 0)
1653 firstYIndex = currCharIndex;
1654
1655 yCount++;
1656 }
1657 break;
1658
1659 case '\'':
1660 if (inQuotes)
1661 {
1662 int nextCharIndex = currCharIndex + 1;
1663
1664 if ((nextCharIndex < patternLen) &&
1665 ('\'' == formatPattern.charAt(nextCharIndex)))
1666 {
1667
1668 currCharIndex++;
1669 }
1670 else
1671 {
1672
1673 inQuotes = false;
1674 }
1675 }
1676 else
1677 {
1678
1679 inQuotes = true;
1680 }
1681
1682
1683 default:
1684 {
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694 }
1695 }
1696 }
1697
1698
1699
1700
1701
1702
1703 if ((yCount > 0) && (yCount < 4))
1704 {
1705 StringBuffer newFormatPattern = new StringBuffer(patternLen + 4 - yCount);
1706
1707
1708 if (firstYIndex > 0)
1709 {
1710 newFormatPattern.append(formatPattern.substring(0, firstYIndex));
1711 }
1712
1713
1714 for (; yCount < 4; yCount++)
1715 {
1716 newFormatPattern.append('y');
1717 }
1718
1719
1720 if (firstYIndex < patternLen)
1721 {
1722 newFormatPattern.append(formatPattern.substring(firstYIndex,
1723 patternLen));
1724 }
1725
1726
1727
1728 format = _getSimpleDateFormat(newFormatPattern.toString(), loc);
1729 }
1730
1731 return format;
1732 }
1733
1734 private DateFormat _getDateFormat(
1735 FacesContext context,
1736 String pattern,
1737 boolean forParsing,
1738 Date targetDate
1739 )
1740 {
1741 Locale locale = _extractConverterLocale(context);
1742 TimeZone tZone = _getTimeZone();
1743
1744 DateFormat format = _getCachedFormat(locale, tZone, pattern);
1745
1746 if (format != null)
1747 {
1748 format.setTimeZone(tZone);
1749 }
1750 else
1751 {
1752
1753
1754
1755
1756 if ( null == pattern || "".equals(pattern))
1757 {
1758 int type = _getType(getType());
1759
1760 if (type == _TYPE_DATE || type == _TYPE_BOTH)
1761 {
1762 int actualDateStyle = _getDateStyle(getDateStyle());
1763 int dateStyle = _changeShortishAsShortIfNeeded(actualDateStyle);
1764
1765 if (type == _TYPE_DATE)
1766 {
1767 format = DateFormat.getDateInstance(dateStyle, locale);
1768 }
1769 else
1770 {
1771 int timeStyle = _getTimeStyle(getTimeStyle());
1772 format = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
1773 }
1774 }
1775 if (type == _TYPE_TIME)
1776 {
1777 int timeStyle = _getTimeStyle(getTimeStyle());
1778 format = DateFormat.getTimeInstance(timeStyle, locale);
1779 }
1780 }
1781 else
1782 {
1783
1784 format = _getSimpleDateFormat(pattern, locale);
1785 }
1786
1787 if (format instanceof SimpleDateFormat)
1788 {
1789 SimpleDateFormat simpleFormat = (SimpleDateFormat)format;
1790
1791 if (!forParsing)
1792 {
1793
1794
1795
1796
1797
1798
1799 if (null == pattern && "shortish".equals(getDateStyle()) )
1800 {
1801 int type = _getType(getType());
1802
1803 if (type == _TYPE_DATE || type == _TYPE_BOTH )
1804 {
1805 simpleFormat = _get4YearFormat(simpleFormat, locale);
1806 format = simpleFormat;
1807 }
1808 }
1809 }
1810 else
1811 {
1812 Calendar cal;
1813 RequestContext reqContext = RequestContext.getCurrentInstance();
1814
1815 if (reqContext == null)
1816 {
1817 cal = null;
1818
1819 if(_LOG.isWarning())
1820 {
1821 _LOG.warning("NO_REQUESTCONTEXT_TWO_DIGIT_YEAR_START_DEFAULT");
1822 }
1823 }
1824 else
1825 {
1826 cal = new GregorianCalendar(reqContext.getTwoDigitYearStart(), 0, 0);
1827 }
1828
1829 if (cal != null)
1830 simpleFormat.set2DigitYearStart(cal.getTime());
1831 }
1832 }
1833
1834
1835 format.setLenient(false);
1836
1837
1838
1839 if (tZone != null)
1840 {
1841 TimeZone formatTZone = getFormattingTimeZone(tZone, targetDate);
1842 format.setTimeZone(formatTZone);
1843 }
1844
1845
1846 _cacheFormat(format, locale, tZone, pattern);
1847 }
1848
1849 return format;
1850 }
1851
1852 private int _changeShortishAsShortIfNeeded(int dateStyle)
1853 {
1854 if (dateStyle == _SHORTISH)
1855 dateStyle = DateFormat.SHORT;
1856 return dateStyle;
1857 }
1858
1859
1860
1861
1862
1863 private DateFormat _getCachedFormat(
1864 Locale locale,
1865 TimeZone tZone,
1866 String pattern
1867 )
1868 {
1869
1870 return null;
1871 }
1872
1873
1874 private void _cacheFormat(
1875 DateFormat format,
1876 Locale locale,
1877 TimeZone tZone,
1878 String pattern
1879 )
1880 {
1881
1882
1883
1884
1885 }
1886
1887 private TimeZone _getTimeZone()
1888 {
1889 TimeZone tZone = getTimeZone();
1890
1891 if (tZone == null)
1892 {
1893 RequestContext context = RequestContext.getCurrentInstance();
1894 if (context == null)
1895 {
1896 _LOG.warning("NO_REQUESTCONTEXT_TIMEZONE_DEFAULT");
1897 }
1898 else
1899 {
1900 tZone = context.getTimeZone();
1901 }
1902
1903
1904
1905 if (tZone == null)
1906 {
1907 tZone = _DEFAULT_TIME_ZONE;
1908 }
1909 }
1910
1911 return tZone;
1912 }
1913
1914 private static final FacesBean.Type _TYPE = new FacesBean.Type();
1915
1916 private static final PropertyKey _DATE_STYLE_KEY
1917 = _TYPE.registerKey("dateStyle", String.class, "shortish");
1918
1919 private static final PropertyKey _LOCALE_KEY
1920 = _TYPE.registerKey("locale", Locale.class);
1921
1922 private static final PropertyKey _PATTERN_KEY
1923 = _TYPE.registerKey("pattern", String.class);
1924
1925 private static final PropertyKey _SECONDARY_PATTERN_KEY
1926 = _TYPE.registerKey("secondaryPattern", String.class);
1927
1928 private static final PropertyKey _TIME_STYLE_KEY
1929 = _TYPE.registerKey("timeStyle", String.class, "short");
1930
1931 private static final PropertyKey _TIME_ZONE_KEY
1932 = _TYPE.registerKey("timeZone", TimeZone.class);
1933
1934 private static final PropertyKey _TYPE_KEY
1935 = _TYPE.registerKey("type", String.class, "date");
1936
1937 private static final PropertyKey _CONVERT_DATE_MESSAGE_DETAIL_KEY
1938 = _TYPE.registerKey("messageDetailConvertDate", String.class);
1939
1940 private static final PropertyKey _CONVERT_TIME_MESSAGE_DETAIL_KEY
1941 = _TYPE.registerKey("messageDetailConvertTime", String.class);
1942
1943 private static final PropertyKey _CONVERT_BOTH_MESSAGE_DETAIL_KEY
1944 = _TYPE.registerKey("messageDetailConvertBoth", String.class);
1945
1946 private static final PropertyKey _HINT_DATE_KEY =
1947 _TYPE.registerKey("hintDate", String.class);
1948
1949 private static final PropertyKey _HINT_TIME_KEY =
1950 _TYPE.registerKey("hintTime", String.class);
1951
1952 private static final PropertyKey _HINT_BOTH_KEY =
1953 _TYPE.registerKey("hintBoth", String.class);
1954
1955
1956 private static final PropertyKey _DISABLED_KEY =
1957 _TYPE.registerKey("disabled", Boolean.class, Boolean.FALSE);
1958
1959 private FacesBean _facesBean = ConverterUtils.getFacesBean(_TYPE);
1960
1961 private boolean _isTransient;
1962
1963 private static final TimeZone _DEFAULT_TIME_ZONE = TimeZone.getTimeZone("GMT");
1964
1965 private static final int _SHORTISH = -2;
1966
1967 private static final int _TYPE_DATE = 0;
1968
1969 private static final int _TYPE_TIME = 2;
1970
1971 private static final int _TYPE_BOTH = 4;
1972
1973 private static final String _ORA_LOCALE_ELEMENTS_BASE =
1974 "org.apache.myfaces.trinidad.resource.LocaleElements";
1975
1976 private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(DateTimeConverter.class);
1977 private static final Date _EXAMPLE_DATE;
1978
1979
1980
1981
1982
1983 private static final Map<Locale, List<String>> _CONVENIENCE_PATTERNS =
1984 new HashMap<Locale, List<String>>();
1985 private static final List<String> _US_CONVENIENCE_PATTERNS =
1986 Arrays.asList("MMMM dd, yy", "MMMM/dd/yy", "dd-MMMM-yy");
1987
1988 static
1989 {
1990 Calendar dateFactory = Calendar.getInstance(Locale.US);
1991 dateFactory.set(1998, 10, 29, 15, 45);
1992 _EXAMPLE_DATE = dateFactory.getTime();
1993
1994
1995
1996
1997 _CONVENIENCE_PATTERNS.put(Locale.US, _US_CONVENIENCE_PATTERNS);
1998 }
1999 }