1 | /* |
2 | |
3 | Derby - Class org.apache.derby.iapi.tools.i18n.LocalizedResource |
4 | |
5 | Copyright 2004 The Apache Software Foundation or its licensors, as applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | You may obtain a copy of the License at |
10 | |
11 | http://www.apache.org/licenses/LICENSE-2.0 |
12 | |
13 | Unless required by applicable law or agreed to in writing, software |
14 | distributed under the License is distributed on an "AS IS" BASIS, |
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | See the License for the specific language governing permissions and |
17 | limitations under the License. |
18 | |
19 | */ |
20 | package org.apache.derby.iapi.tools.i18n; |
21 | |
22 | import java.io.InputStream; |
23 | import java.io.OutputStream; |
24 | import java.io.UnsupportedEncodingException; |
25 | |
26 | import java.util.ResourceBundle; |
27 | import java.util.Date; |
28 | import java.util.Locale; |
29 | import java.util.StringTokenizer; |
30 | |
31 | import java.text.MessageFormat; |
32 | import java.text.NumberFormat; |
33 | import java.text.DecimalFormat; |
34 | import java.text.DateFormat; |
35 | import java.text.ParseException; |
36 | import java.text.FieldPosition; |
37 | |
38 | import java.sql.Timestamp; |
39 | import java.sql.ResultSet; |
40 | import java.sql.ResultSetMetaData; |
41 | import java.sql.SQLException; |
42 | import java.sql.Types; |
43 | |
44 | |
45 | public final class LocalizedResource implements java.security.PrivilegedAction { |
46 | |
47 | private static boolean HAVE_BIG_DECIMAL; |
48 | |
49 | { |
50 | boolean haveBigDecimal; |
51 | try { |
52 | Class.forName("java.math.BigDecimal"); |
53 | haveBigDecimal = true; |
54 | } catch (Throwable t) { |
55 | haveBigDecimal = false; |
56 | } |
57 | HAVE_BIG_DECIMAL = haveBigDecimal; |
58 | } |
59 | |
60 | private ResourceBundle res; |
61 | private Locale locale; |
62 | private String encode; |
63 | private final static String MESSAGE_FILE = "org.apache.derby.loc.toolsmessages"; |
64 | private final static String ENV_CODESET = "derby.ui.codeset"; |
65 | private final static String ENV_LOCALE = "derby.ui.locale"; |
66 | private String messageFileName; |
67 | private String resourceKey; |
68 | private LocalizedOutput out; |
69 | private LocalizedInput in; |
70 | private boolean enableLocalized; |
71 | private boolean unicodeEscape; |
72 | private static LocalizedResource local; |
73 | private int dateSize; |
74 | private int timeSize; |
75 | private int timestampSize; |
76 | private DateFormat formatDate; |
77 | private DateFormat formatTime; |
78 | private DateFormat formatTimestamp; |
79 | private NumberFormat formatNumber; |
80 | private DecimalFormat formatDecimal; |
81 | public LocalizedResource(){ |
82 | init(); |
83 | } |
84 | public LocalizedResource(String encStr, String locStr, String msgF){ |
85 | init(encStr,locStr,msgF); |
86 | } |
87 | public static LocalizedResource getInstance(){ |
88 | if (local == null){ |
89 | local = new LocalizedResource(); |
90 | } |
91 | return local; |
92 | } |
93 | public void init(){ |
94 | init(null,null,null); |
95 | } |
96 | public void init (String encStr, String locStr, String msgF){ |
97 | if (encStr != null){ |
98 | encode = encStr; |
99 | } |
100 | //then get encoding string from environment |
101 | if (encode == null) { |
102 | String eEncode = getEnvProperty(ENV_CODESET); |
103 | if ( eEncode != null ){ |
104 | encode = eEncode; |
105 | } |
106 | } |
107 | |
108 | // If null at this point then the default encoding |
109 | // will be always used. |
110 | |
111 | //get locale string from the caller first |
112 | locale = getNewLocale(locStr); |
113 | |
114 | //if null, get locale again from the environment variable |
115 | if (locale==null) { |
116 | String s = getEnvProperty(ENV_LOCALE); |
117 | locale = getNewLocale(s); |
118 | } |
119 | //get the default locale if forced |
120 | if (locale==null){ |
121 | locale = Locale.getDefault(); |
122 | } |
123 | if (msgF != null) { |
124 | messageFileName = msgF; |
125 | } |
126 | else { |
127 | messageFileName = MESSAGE_FILE; |
128 | } |
129 | //create default in/out |
130 | out = getNewOutput(System.out); |
131 | in = getNewInput(System.in); |
132 | |
133 | //for faster code: get the format objs |
134 | if (enableLocalized && locale != null){ |
135 | formatDecimal = (DecimalFormat)DecimalFormat.getInstance(locale); |
136 | formatNumber = NumberFormat.getInstance(locale); |
137 | formatDate = DateFormat.getDateInstance(DateFormat.LONG,locale); |
138 | formatTime = DateFormat.getTimeInstance(DateFormat.LONG,locale); |
139 | formatTimestamp = DateFormat.getDateTimeInstance(DateFormat.LONG, |
140 | DateFormat.LONG, locale); |
141 | } |
142 | else { |
143 | formatDecimal = (DecimalFormat)DecimalFormat.getInstance(); |
144 | formatNumber = NumberFormat.getInstance(); |
145 | formatDate = DateFormat.getDateInstance(DateFormat.LONG); |
146 | formatTime = DateFormat.getTimeInstance(DateFormat.LONG); |
147 | formatTimestamp = DateFormat.getDateTimeInstance(DateFormat.LONG, |
148 | DateFormat.LONG); |
149 | } |
150 | //initialize display sizes for columns |
151 | initMaxSizes2(); |
152 | } |
153 | //get the message file resource according to the locale |
154 | //fall back to English message file if locale message file is not found |
155 | private void setResource(){ |
156 | if (res != null){ |
157 | return; |
158 | } |
159 | if ( locale == null || locale.toString().equals("none") ){ |
160 | res = ResourceBundle.getBundle(MESSAGE_FILE); |
161 | } |
162 | else |
163 | try { |
164 | res = ResourceBundle.getBundle(messageFileName,locale); |
165 | } |
166 | catch(java.util.MissingResourceException e){ |
167 | res = ResourceBundle.getBundle(messageFileName,Locale.ENGLISH); |
168 | } |
169 | } |
170 | private void initMaxSizes2(){ |
171 | dateSize = 0; |
172 | timeSize = 0; |
173 | timestampSize = 0; |
174 | |
175 | int len; |
176 | |
177 | // check the date & timestamp max length |
178 | // 3900/01/28 !! original devloper thought they were getting 2000/01/28 |
179 | Date d = new Date(60907276800000L); |
180 | Timestamp t = new Timestamp(d.getTime()); |
181 | for(int month = 0 ; month <=11 ; month++, d.setTime(d.getTime() + (30L * 24L * 60L * 60L * 1000L))) { |
182 | len=getDateAsString(d).length(); |
183 | |
184 | if(len > dateSize ) { |
185 | dateSize=len; |
186 | } |
187 | |
188 | t.setTime(d.getTime() + ((((21L * 60L) + 59L) * 60L) + 59L)); |
189 | len=getTimestampAsString(t).length(); |
190 | |
191 | if(len > timestampSize) { |
192 | timestampSize=len; |
193 | } |
194 | } |
195 | |
196 | // set the time max length |
197 | // minimum of 18 because the old buggy code always used 18 |
198 | len = 18; |
199 | for (int hour = 0 ; hour < 24; hour++) { |
200 | |
201 | long secs = (hour * 3600L) + (59 * 60L) + 59L; |
202 | |
203 | long ms = secs * 1000L; |
204 | |
205 | Date td = new Date(ms); |
206 | |
207 | String fd = formatTime.format(td); |
208 | |
209 | if (fd.length() > len) |
210 | len = fd.length(); |
211 | } |
212 | timeSize=len; |
213 | |
214 | } |
215 | |
216 | public LocalizedInput getNewInput(InputStream i) { |
217 | try { |
218 | if (encode != null) |
219 | return new LocalizedInput(i,encode); |
220 | } |
221 | catch (UnsupportedEncodingException e){ |
222 | |
223 | } |
224 | return new LocalizedInput(i); |
225 | } |
226 | |
227 | public LocalizedInput getNewEncodedInput(InputStream i, String encoding) { |
228 | try { |
229 | return new LocalizedInput(i,encoding); |
230 | } |
231 | catch (UnsupportedEncodingException e){ |
232 | |
233 | } |
234 | return new LocalizedInput(i); |
235 | } |
236 | |
237 | public LocalizedOutput getNewOutput(OutputStream o){ |
238 | try { |
239 | if (encode != null) |
240 | return new LocalizedOutput(o,encode); |
241 | } |
242 | catch(UnsupportedEncodingException e){ |
243 | } |
244 | return new LocalizedOutput(o); |
245 | } |
246 | public String getTextMessage(String key ) { |
247 | if ( res == null){ |
248 | setResource(); |
249 | } |
250 | String s = key; |
251 | try{ |
252 | s = res.getString(key); |
253 | } catch (Exception e) { |
254 | s = key; |
255 | } |
256 | //System.out.println(local.toString()); |
257 | //System.out.println("GetKey:"+key+"="+s); |
258 | return s; |
259 | } |
260 | public String getTextMessage(String key, Object o){ |
261 | Object [] att=new Object[] {o}; |
262 | return getTextMessage(key,att); |
263 | } |
264 | public String getTextMessage(String key, Object o1, Object o2){ |
265 | Object [] att=new Object[] {o1,o2}; |
266 | return getTextMessage(key,att); |
267 | } |
268 | public String getTextMessage(String key, Object o1, Object o2, Object o3){ |
269 | Object [] att=new Object[] {o1,o2,o3}; |
270 | return getTextMessage(key,att); |
271 | } |
272 | public String getTextMessage(String key, Object o1, Object o2, Object o3, Object o4){ |
273 | Object [] att=new Object[] {o1,o2,o3,o4}; |
274 | return getTextMessage(key,att); |
275 | } |
276 | private Locale getNewLocale(String locStr){ |
277 | String l="", r="", v=""; |
278 | StringTokenizer st; |
279 | if (locStr==null) { |
280 | return null; |
281 | } |
282 | st=new StringTokenizer(locStr, "_"); |
283 | try { |
284 | l=st.nextToken(); |
285 | if(st.hasMoreTokens()==true) |
286 | r=st.nextToken(); |
287 | if(st.hasMoreTokens()==true) |
288 | v=st.nextToken(); |
289 | return new Locale(l,r,v); |
290 | } catch (Exception e) { |
291 | return null; |
292 | } |
293 | } |
294 | public String getTextMessage(String key, Object [] objectArr) { |
295 | if (res == null){ |
296 | setResource(); |
297 | } |
298 | try{ |
299 | return MessageFormat.format(res.getString(key), objectArr); |
300 | } catch (Exception e) { |
301 | String tmpFormat = key; |
302 | for (int i=0; i<objectArr.length; i++) |
303 | tmpFormat = tmpFormat + ", <{" + (i) + "}>"; |
304 | return MessageFormat.format(tmpFormat, objectArr); |
305 | } |
306 | } |
307 | public String getLocalizedString(ResultSet rs, |
308 | ResultSetMetaData rsm, |
309 | int columnNumber) throws SQLException{ |
310 | if (!enableLocalized){ |
311 | return rs.getString(columnNumber); |
312 | } |
313 | int type = rsm.getColumnType(columnNumber); |
314 | if ( type == Types.DATE ) { |
315 | return getDateAsString(rs.getDate(columnNumber)); |
316 | } |
317 | else if ( type == Types.INTEGER || type == Types.SMALLINT || |
318 | type == Types.BIGINT || type == Types.TINYINT ) { |
319 | return getNumberAsString(rs.getLong(columnNumber)); |
320 | } |
321 | else if (type == Types.REAL || type == Types.FLOAT || |
322 | type == Types.DOUBLE ) { |
323 | return getNumberAsString(rs.getDouble(columnNumber)); |
324 | } |
325 | else if (HAVE_BIG_DECIMAL && (type == Types.NUMERIC || type == Types.DECIMAL)) { |
326 | return getNumberAsString(rs.getBigDecimal(columnNumber, |
327 | rsm.getScale(columnNumber))); |
328 | } |
329 | else if (type == Types.TIME ) { |
330 | return getTimeAsString(rs.getTime(columnNumber)); |
331 | } |
332 | else if (type == Types.TIMESTAMP ) { |
333 | return getTimestampAsString(rs.getTimestamp(columnNumber)); |
334 | } |
335 | return rs.getString(columnNumber); |
336 | } |
337 | |
338 | public String getDateAsString(Date d){ |
339 | if (!enableLocalized){ |
340 | return d.toString(); |
341 | } |
342 | return formatDate.format(d); |
343 | } |
344 | public String getTimeAsString(Date t){ |
345 | if (!enableLocalized){ |
346 | return t.toString(); |
347 | } |
348 | return formatTime.format(t, new StringBuffer(), |
349 | new java.text.FieldPosition(0)).toString(); |
350 | } |
351 | public String getNumberAsString(int o){ |
352 | if (enableLocalized){ |
353 | return formatNumber.format(o); |
354 | } |
355 | else { |
356 | return String.valueOf(o); |
357 | } |
358 | } |
359 | public String getNumberAsString(long o){ |
360 | if (enableLocalized){ |
361 | return formatNumber.format(o); |
362 | } |
363 | else{ |
364 | return String.valueOf(o); |
365 | } |
366 | } |
367 | public String getNumberAsString(Object o){ |
368 | if (enableLocalized){ |
369 | return formatNumber.format(o, new StringBuffer(), |
370 | new FieldPosition(0)).toString(); |
371 | } |
372 | else { |
373 | return o.toString(); |
374 | } |
375 | } |
376 | public String getNumberAsString(double o){ |
377 | if (!enableLocalized) { |
378 | return String.valueOf(o); |
379 | } |
380 | return formatDecimal.format(o); |
381 | } |
382 | public String getTimestampAsString(Timestamp t){ |
383 | if (!enableLocalized){ |
384 | return t.toString(); |
385 | } |
386 | return formatTime.format(t, new StringBuffer(), |
387 | new java.text.FieldPosition(0)).toString(); |
388 | } |
389 | public int getColumnDisplaySize(ResultSetMetaData rsm, |
390 | int columnNumber) throws SQLException{ |
391 | if (!enableLocalized){ |
392 | return rsm.getColumnDisplaySize(columnNumber); |
393 | } |
394 | int type = rsm.getColumnType(columnNumber); |
395 | if (type == Types.DATE) |
396 | return dateSize; |
397 | if (type == Types.TIME) |
398 | return timeSize; |
399 | if (type == Types.TIMESTAMP) |
400 | return timestampSize; |
401 | return rsm.getColumnDisplaySize(columnNumber); |
402 | } |
403 | public String getStringFromDate(String dateStr) |
404 | throws ParseException{ |
405 | if (!enableLocalized){ |
406 | return dateStr; |
407 | } |
408 | Date d = formatDate.parse(dateStr); |
409 | return new java.sql.Date(d.getTime()).toString(); |
410 | } |
411 | public String getStringFromTime(String timeStr) |
412 | throws ParseException{ |
413 | if (!enableLocalized){ |
414 | return timeStr; |
415 | } |
416 | Date t = formatTime.parse(timeStr); |
417 | return new java.sql.Time(t.getTime()).toString(); |
418 | } |
419 | public String getStringFromValue(String val) |
420 | throws ParseException{ |
421 | if (!enableLocalized){ |
422 | return val; |
423 | } |
424 | return formatNumber.parse(val).toString(); |
425 | } |
426 | public String getStringFromTimestamp(String timestampStr) |
427 | throws ParseException{ |
428 | if (!enableLocalized){ |
429 | return timestampStr; |
430 | } |
431 | Date ts = formatTimestamp.parse(timestampStr); |
432 | return new java.sql.Timestamp(ts.getTime()).toString(); |
433 | } |
434 | public Locale getLocale(){ |
435 | return locale; |
436 | } |
437 | |
438 | private final synchronized String getEnvProperty(String key) { |
439 | String s; |
440 | try |
441 | { |
442 | resourceKey = key; |
443 | s = (String) java.security.AccessController.doPrivileged(this); |
444 | } |
445 | catch (SecurityException se) { |
446 | s = null; |
447 | } |
448 | //System.out.println("{"+resourceKey+"="+s+"}"); |
449 | return s; |
450 | } |
451 | public final Object run() { |
452 | String s = System.getProperty(resourceKey); |
453 | return s; |
454 | } |
455 | public static boolean enableLocalization(boolean mode) { |
456 | getInstance().enableLocalized = mode; |
457 | //re-initialized locale |
458 | getInstance().init(); |
459 | return mode; |
460 | } |
461 | public boolean isLocalized(){ |
462 | return getInstance().enableLocalized; |
463 | } |
464 | public static String getMessage(String key){ |
465 | return getInstance().getTextMessage(key); |
466 | } |
467 | public static String getMessage(String key, Object o1){ |
468 | return getInstance().getTextMessage(key,o1); |
469 | } |
470 | public static String getMessage(String key, Object o1, Object o2){ |
471 | return getInstance().getTextMessage(key,o1,o2); |
472 | } |
473 | public static String getMessage(String key, Object o1, Object o2, Object o3){ |
474 | return getInstance().getTextMessage(key,o1,o2,o3); |
475 | } |
476 | public static String getMessage(String key, Object o1, Object o2, Object o3, Object o4){ |
477 | return getInstance().getTextMessage(key,o1,o2,o3,o4); |
478 | } |
479 | public static LocalizedOutput OutputWriter(){ |
480 | return getInstance().out; |
481 | } |
482 | public static LocalizedInput InputReader(){ |
483 | return getInstance().in; |
484 | } |
485 | public static String getNumber(long o){ |
486 | return getInstance().getNumberAsString(o); |
487 | } |
488 | public static String getNumber(int o){ |
489 | return getInstance().getNumberAsString(o); |
490 | } |
491 | public static void setUnicodeEscape(boolean u){ |
492 | getInstance().unicodeEscape = u; |
493 | } |
494 | public static boolean getUnicodeEscape(){ |
495 | return getInstance().unicodeEscape; |
496 | } |
497 | public String toString(){ |
498 | String s = "toString(){\n" + |
499 | "locale=" + (locale==null?"null":locale.toString()) + "\n" + |
500 | "encode=" + encode + "\n" + |
501 | "messageFile=" + messageFileName + "\n" + |
502 | "resourceKey=" + resourceKey + "\n" + |
503 | "enableLocalized=" + enableLocalized + " \n" + |
504 | "unicodeEscape=" + unicodeEscape + "\n" + |
505 | "dateSize=" + dateSize + "\n" + |
506 | "timeSize=" + timeSize + "\n" + |
507 | "timestampSize="+timestampSize+ "\n}"; |
508 | return s; |
509 | } |
510 | } |