1
2
3
4 package org.rcfaces.core.internal.tools;
5
6 import java.text.DateFormat;
7 import java.text.DecimalFormat;
8 import java.text.Format;
9 import java.text.NumberFormat;
10 import java.text.SimpleDateFormat;
11 import java.util.HashMap;
12 import java.util.Locale;
13 import java.util.Map;
14 import java.util.TimeZone;
15
16 import javax.faces.FacesException;
17 import javax.faces.component.UIComponent;
18
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 import org.rcfaces.core.component.capability.IComponentLocaleCapability;
22 import org.rcfaces.core.internal.Constants;
23 import org.rcfaces.core.internal.converter.LocaleConverter;
24 import org.rcfaces.core.internal.renderkit.IComponentRenderContext;
25
26
27
28
29
30
31 public class LocaleTools {
32 private static final String REVISION = "$Revision: 1.7 $";
33
34 private static final Log LOG = LogFactory.getLog(LocaleTools.class);
35
36 public static final boolean NORMALIZE_LOCALE_PARAMETER_SUPPORT = false;
37
38 public static final int DATE_TYPE = 0;
39
40 public static final int TIME_TYPE = 1;
41
42 public static final int DATE_TIME_TYPE = 2;
43
44 public static final int NUMBER_TYPE = 3;
45
46 public static final int INTEGER_TYPE = 4;
47
48 public static final int PERCENT_TYPE = 5;
49
50 public static final int CURRENCY_TYPE = 6;
51
52 public static final int MAX_TYPE = 6;
53
54 private static final Map dateFormatByLocale;
55 static {
56 if (Constants.CACHED_LOCALE_FORMATS) {
57 dateFormatByLocale = new HashMap(32);
58 }
59 }
60
61 private static final int DEFAULT_STYLE_BY_TYPE[] = new int[MAX_TYPE + 1];
62 static {
63 DEFAULT_STYLE_BY_TYPE[0] = DateFormat.SHORT;
64 DEFAULT_STYLE_BY_TYPE[1] = DateFormat.MEDIUM;
65 DEFAULT_STYLE_BY_TYPE[2] = DateFormat.MEDIUM;
66 }
67
68
69
70
71
72
73 protected static interface IFormatNormalizer {
74 String normalizeFormat(IComponentRenderContext componentRenderContext,
75 int type, String format, String param);
76 }
77
78
79
80
81
82
83 protected static class LocaleDateTimeFormatNormalizer implements
84 LocaleTools.IFormatNormalizer {
85 private static final String REVISION = "$Revision: 1.7 $";
86
87 private final int style;
88
89 private final Map dateFormatByLocale = new HashMap();
90
91 LocaleDateTimeFormatNormalizer(int style) {
92 this.style = style;
93 }
94
95 public String normalizeFormat(
96 IComponentRenderContext componentRenderContext, int type,
97 String format, String param) {
98
99 Locale locale = getLocale(componentRenderContext, param);
100
101 return getFormatPattern(locale, style, type);
102 }
103
104 protected Locale getLocale(
105 IComponentRenderContext componentRenderContext, String param) {
106 Locale locale = null;
107
108 if (param != null) {
109 locale = (Locale) LocaleConverter.SINGLETON.getAsObject(null,
110 null, param);
111 if (locale == null) {
112 throw new FacesException("Invalid locale name '" + param
113 + "'.");
114 }
115 }
116
117 if (locale == null) {
118 locale = componentRenderContext.getRenderContext()
119 .getProcessContext().getUserLocale();
120 }
121
122 return locale;
123 }
124
125 public DateFormat getDateFormat(Locale locale) {
126 DateFormat dateFormat;
127 synchronized (dateFormatByLocale) {
128 dateFormat = (DateFormat) dateFormatByLocale.get(locale);
129 if (dateFormat == null) {
130 dateFormat = DateFormat.getDateInstance(style, locale);
131 dateFormatByLocale.put(locale, dateFormat);
132 }
133 }
134 return dateFormat;
135 }
136
137 }
138
139 public static String normalizeFormat(
140 IComponentRenderContext componentRenderContext, String format,
141 int type, Map normalizers) {
142 if (format == null || format.length() < 1) {
143 return format;
144 }
145
146 String param = null;
147 if (LocaleTools.NORMALIZE_LOCALE_PARAMETER_SUPPORT) {
148 if (format.charAt(0) != '$') {
149 return format;
150 }
151
152 format = format.substring(1);
153
154 int idx = format.indexOf('(');
155 if (idx >= 0) {
156 param = format.substring(idx + 1);
157 format = format.substring(0, idx);
158
159 idx = param.lastIndexOf(')');
160 if (idx < 0 || idx != param.length() - 1) {
161 throw new FacesException("Invalid date format '" + format
162 + "' parentheses are not correctly balanced.");
163 }
164
165 param = param.substring(0, idx);
166 }
167 }
168
169 LocaleTools.IFormatNormalizer normalizer = (LocaleTools.IFormatNormalizer) normalizers
170 .get(format.toUpperCase());
171 if (normalizer == null) {
172 return format;
173 }
174
175 return normalizer.normalizeFormat(componentRenderContext, type, format,
176 param);
177 }
178
179 private static final CachedLocale getCachedLocale(Locale locale) {
180 synchronized (dateFormatByLocale) {
181 CachedLocale cachedLocale = (CachedLocale) dateFormatByLocale
182 .get(locale);
183 if (cachedLocale != null) {
184 return cachedLocale;
185 }
186
187 cachedLocale = new CachedLocale(locale);
188 dateFormatByLocale.put(locale, cachedLocale);
189
190 return cachedLocale;
191 }
192 }
193
194 private static Format getFormatByType(Locale locale, TimeZone timeZone,
195 int type, int style) {
196 if (style < 0) {
197 style = DEFAULT_STYLE_BY_TYPE[type];
198 }
199
200 Format format;
201 switch (type) {
202 case DATE_TYPE:
203 format = DateFormat.getDateInstance(style, locale);
204 break;
205
206 case TIME_TYPE:
207 format = DateFormat.getTimeInstance(style, locale);
208 break;
209
210 case DATE_TIME_TYPE:
211 format = DateFormat.getDateTimeInstance(style, style, locale);
212 break;
213
214 case NUMBER_TYPE:
215 return NumberFormat.getNumberInstance(locale);
216
217 case INTEGER_TYPE:
218 return NumberFormat.getIntegerInstance(locale);
219
220 case PERCENT_TYPE:
221 return NumberFormat.getPercentInstance(locale);
222
223 case CURRENCY_TYPE:
224 return NumberFormat.getCurrencyInstance(locale);
225
226 default:
227 LOG.error("Invalid format type=" + type);
228 return null;
229 }
230
231 if (timeZone != null && (format instanceof DateFormat)) {
232 DateFormat dateFormat = (DateFormat) format;
233
234 if (dateFormat.getCalendar().getTimeZone().equals(timeZone) == false) {
235 dateFormat.setTimeZone(timeZone);
236 }
237 }
238
239 return format;
240 }
241
242 private static String getPattern(Format format) {
243 if (format instanceof SimpleDateFormat) {
244 return ((SimpleDateFormat) format).toPattern();
245 }
246
247 if (format instanceof DecimalFormat) {
248 return ((DecimalFormat) format).toPattern();
249 }
250
251 throw new FacesException("Can not get format pattern from format: "
252 + format);
253
254 }
255
256
257
258
259
260
261 private static final class CachedLocale {
262 private final Locale locale;
263
264 private final Format defaultFormats[];
265
266 private String patternsByType[][];
267
268 public CachedLocale(Locale locale) {
269 this.locale = locale;
270
271 this.defaultFormats = new Format[MAX_TYPE + 1];
272 }
273
274 public Locale getLocale() {
275 return locale;
276 }
277
278 public Format getDefaultFormat(int type) {
279 Format format;
280
281 synchronized (defaultFormats) {
282 format = defaultFormats[type];
283 if (format == null) {
284 format = getFormatByType(locale, null, type, -1);
285 defaultFormats[type] = format;
286 }
287 }
288
289 return format;
290 }
291
292 public String getDefaultPattern(int type) {
293 return getPattern(type, DEFAULT_STYLE_BY_TYPE[type]);
294 }
295
296 public String getPattern(int type, int style) {
297
298 synchronized (this) {
299 if (patternsByType == null) {
300 patternsByType = new String[MAX_TYPE + 1][];
301 }
302
303 String patterns[] = patternsByType[type];
304 if (patterns != null) {
305 String pattern = patterns[style];
306 if (pattern != null) {
307 return pattern;
308 }
309 } else {
310 patterns = new String[DateFormat.SHORT + 1];
311 patternsByType[type] = patterns;
312 }
313
314 boolean dateFormat = (type == DATE_TYPE);
315 if (dateFormat && style == DateFormat.MEDIUM) {
316
317
318
319 style = DateFormat.SHORT;
320 }
321
322 Format format;
323 if (style == DEFAULT_STYLE_BY_TYPE[type]) {
324 format = getDefaultFormat(type);
325
326 } else {
327 format = getFormatByType(locale, null, type, style);
328 }
329
330 String pattern;
331 synchronized (format) {
332 pattern = LocaleTools.getPattern(format);
333 }
334
335 if (dateFormat) {
336
337 if (pattern.indexOf("yyy") < 0) {
338 int idx = pattern.indexOf("yy");
339 if (idx >= 0) {
340 pattern = pattern.substring(0, idx) + "yy"
341 + pattern.substring(idx);
342 }
343 }
344 }
345
346 patterns[style] = pattern;
347
348 return pattern;
349 }
350 }
351 }
352
353 public static String getFormatPattern(Locale locale, int style, int type) {
354
355 if (Constants.CACHED_LOCALE_FORMATS == false) {
356 Format format = getFormatByType(locale, null, type, style);
357
358 return getPattern(format);
359 }
360
361 return LocaleTools.getCachedLocale(locale).getPattern(type, style);
362 }
363
364 public static Locale getLocale(UIComponent component, boolean literalValue) {
365 if (literalValue) {
366 return PageConfiguration.getLiteralLocale(null, component);
367 }
368
369 if (component instanceof IComponentLocaleCapability) {
370 Locale locale = ((IComponentLocaleCapability) component)
371 .getComponentLocale();
372
373 if (locale != null) {
374 return locale;
375 }
376 }
377
378 return ContextTools.getUserLocale(null);
379 }
380
381 public static Format getDefaultFormat(UIComponent component, int type,
382 boolean literalValue) {
383
384 Locale locale = getLocale(component, literalValue);
385
386 if (Constants.CACHED_LOCALE_FORMATS == false) {
387 return getFormatByType(locale, null, type, -1);
388 }
389
390 return LocaleTools.getCachedLocale(locale).getDefaultFormat(type);
391 }
392
393 public static String getDefaultPattern(Locale locale, int type) {
394
395 if (Constants.CACHED_LOCALE_FORMATS == false) {
396 Format format = getFormatByType(locale, null, type, -1);
397
398 return getPattern(format);
399 }
400
401 return LocaleTools.getCachedLocale(locale).getDefaultPattern(type);
402 }
403
404 }