001: /*
002:
003: Derby - Class org.apache.derby.iapi.tools.i18n.LocalizedResource
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to You under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021: package org.apache.derby.iapi.tools.i18n;
022:
023: import java.io.InputStream;
024: import java.io.OutputStream;
025: import java.io.UnsupportedEncodingException;
026:
027: import java.util.ResourceBundle;
028: import java.util.Date;
029: import java.util.Locale;
030: import java.util.StringTokenizer;
031:
032: import java.text.MessageFormat;
033: import java.text.NumberFormat;
034: import java.text.DecimalFormat;
035: import java.text.DateFormat;
036: import java.text.ParseException;
037: import java.text.FieldPosition;
038:
039: import java.sql.Timestamp;
040: import java.sql.ResultSet;
041: import java.sql.ResultSetMetaData;
042: import java.sql.SQLException;
043: import java.sql.Types;
044:
045: public final class LocalizedResource implements
046: java.security.PrivilegedAction {
047:
048: private static final boolean HAVE_BIG_DECIMAL;
049:
050: static {
051: boolean haveBigDecimal;
052: try {
053: Class.forName("java.math.BigDecimal");
054: haveBigDecimal = true;
055: } catch (Throwable t) {
056: haveBigDecimal = false;
057: }
058: HAVE_BIG_DECIMAL = haveBigDecimal;
059: }
060:
061: private ResourceBundle res;
062: private Locale locale;
063: private String encode;
064: private final static String MESSAGE_FILE = "org.apache.derby.loc.toolsmessages";
065: private final static String ENV_CODESET = "derby.ui.codeset";
066: private final static String ENV_LOCALE = "derby.ui.locale";
067: private String messageFileName;
068: private String resourceKey;
069: private LocalizedOutput out;
070: private LocalizedInput in;
071: private boolean enableLocalized;
072: private boolean unicodeEscape;
073: private static LocalizedResource local;
074: private int dateSize;
075: private int timeSize;
076: private int timestampSize;
077: private DateFormat formatDate;
078: private DateFormat formatTime;
079: private DateFormat formatTimestamp;
080: private NumberFormat formatNumber;
081: private DecimalFormat formatDecimal;
082:
083: public LocalizedResource() {
084: init();
085: }
086:
087: public LocalizedResource(String encStr, String locStr, String msgF) {
088: init(encStr, locStr, msgF);
089: }
090:
091: public static LocalizedResource getInstance() {
092: if (local == null) {
093: local = new LocalizedResource();
094: }
095: return local;
096: }
097:
098: public void init() {
099: init(null, null, null);
100: }
101:
102: public void init(String encStr, String locStr, String msgF) {
103: if (encStr != null) {
104: encode = encStr;
105: }
106: //then get encoding string from environment
107: if (encode == null) {
108: String eEncode = getEnvProperty(ENV_CODESET);
109: if (eEncode != null) {
110: encode = eEncode;
111: }
112: }
113:
114: // If null at this point then the default encoding
115: // will be always used.
116:
117: //get locale string from the caller first
118: locale = getNewLocale(locStr);
119:
120: //if null, get locale again from the environment variable
121: if (locale == null) {
122: String s = getEnvProperty(ENV_LOCALE);
123: locale = getNewLocale(s);
124: }
125: //get the default locale if forced
126: if (locale == null) {
127: locale = Locale.getDefault();
128: }
129: if (msgF != null) {
130: messageFileName = msgF;
131: } else {
132: messageFileName = MESSAGE_FILE;
133: }
134: //create default in/out
135: out = getNewOutput(System.out);
136: in = getNewInput(System.in);
137:
138: //for faster code: get the format objs
139: if (enableLocalized && locale != null) {
140: formatDecimal = (DecimalFormat) DecimalFormat
141: .getInstance(locale);
142: formatNumber = NumberFormat.getInstance(locale);
143: formatDate = DateFormat.getDateInstance(DateFormat.LONG,
144: locale);
145: formatTime = DateFormat.getTimeInstance(DateFormat.LONG,
146: locale);
147: formatTimestamp = DateFormat.getDateTimeInstance(
148: DateFormat.LONG, DateFormat.LONG, locale);
149: } else {
150: formatDecimal = (DecimalFormat) DecimalFormat.getInstance();
151: formatNumber = NumberFormat.getInstance();
152: formatDate = DateFormat.getDateInstance(DateFormat.LONG);
153: formatTime = DateFormat.getTimeInstance(DateFormat.LONG);
154: formatTimestamp = DateFormat.getDateTimeInstance(
155: DateFormat.LONG, DateFormat.LONG);
156: }
157: //initialize display sizes for columns
158: initMaxSizes2();
159: }
160:
161: //get the message file resource according to the locale
162: //fall back to English message file if locale message file is not found
163: private void setResource() {
164: if (res != null) {
165: return;
166: }
167: if (locale == null || locale.toString().equals("none")) {
168: res = ResourceBundle.getBundle(MESSAGE_FILE);
169: } else
170: try {
171: res = ResourceBundle.getBundle(messageFileName, locale);
172: } catch (java.util.MissingResourceException e) {
173: res = ResourceBundle.getBundle(messageFileName,
174: Locale.ENGLISH);
175: }
176: }
177:
178: private void initMaxSizes2() {
179: dateSize = 0;
180: timeSize = 0;
181: timestampSize = 0;
182:
183: int len;
184:
185: // check the date & timestamp max length
186: // 3900/01/28 !! original devloper thought they were getting 2000/01/28
187: Date d = new Date(60907276800000L);
188: Timestamp t = new Timestamp(d.getTime());
189: for (int month = 0; month <= 11; month++, d.setTime(d.getTime()
190: + (30L * 24L * 60L * 60L * 1000L))) {
191: len = getDateAsString(d).length();
192:
193: if (len > dateSize) {
194: dateSize = len;
195: }
196:
197: t
198: .setTime(d.getTime()
199: + ((((21L * 60L) + 59L) * 60L) + 59L));
200: len = getTimestampAsString(t).length();
201:
202: if (len > timestampSize) {
203: timestampSize = len;
204: }
205: }
206:
207: // set the time max length
208: // minimum of 18 because the old buggy code always used 18
209: len = 18;
210: for (int hour = 0; hour < 24; hour++) {
211:
212: long secs = (hour * 3600L) + (59 * 60L) + 59L;
213:
214: long ms = secs * 1000L;
215:
216: Date td = new Date(ms);
217:
218: String fd = formatTime.format(td);
219:
220: if (fd.length() > len)
221: len = fd.length();
222: }
223: timeSize = len;
224:
225: }
226:
227: public LocalizedInput getNewInput(InputStream i) {
228: try {
229: if (encode != null)
230: return new LocalizedInput(i, encode);
231: } catch (UnsupportedEncodingException e) {
232:
233: }
234: return new LocalizedInput(i);
235: }
236:
237: public LocalizedInput getNewEncodedInput(InputStream i,
238: String encoding) {
239: try {
240: return new LocalizedInput(i, encoding);
241: } catch (UnsupportedEncodingException e) {
242:
243: }
244: return new LocalizedInput(i);
245: }
246:
247: public LocalizedOutput getNewOutput(OutputStream o) {
248: try {
249: if (encode != null)
250: return new LocalizedOutput(o, encode);
251: } catch (UnsupportedEncodingException e) {
252: }
253: return new LocalizedOutput(o);
254: }
255:
256: /**
257: * Get a new LocalizedOutput with the given encoding.
258: * @throws UnsupportedEncodingException
259: */
260: public LocalizedOutput getNewEncodedOutput(OutputStream o,
261: String encoding) throws UnsupportedEncodingException {
262: return new LocalizedOutput(o, encoding);
263: }
264:
265: public String getTextMessage(String key) {
266: if (res == null) {
267: setResource();
268: }
269: String s = key;
270: try {
271: s = res.getString(key);
272: } catch (Exception e) {
273: s = key;
274: }
275: //System.out.println(local.toString());
276: //System.out.println("GetKey:"+key+"="+s);
277: return s;
278: }
279:
280: public String getTextMessage(String key, Object o) {
281: Object[] att = new Object[] { o };
282: return getTextMessage(key, att);
283: }
284:
285: public String getTextMessage(String key, Object o1, Object o2) {
286: Object[] att = new Object[] { o1, o2 };
287: return getTextMessage(key, att);
288: }
289:
290: public String getTextMessage(String key, Object o1, Object o2,
291: Object o3) {
292: Object[] att = new Object[] { o1, o2, o3 };
293: return getTextMessage(key, att);
294: }
295:
296: public String getTextMessage(String key, Object o1, Object o2,
297: Object o3, Object o4) {
298: Object[] att = new Object[] { o1, o2, o3, o4 };
299: return getTextMessage(key, att);
300: }
301:
302: private Locale getNewLocale(String locStr) {
303: String l = "", r = "", v = "";
304: StringTokenizer st;
305: if (locStr == null) {
306: return null;
307: }
308: st = new StringTokenizer(locStr, "_");
309: try {
310: l = st.nextToken();
311: if (st.hasMoreTokens() == true)
312: r = st.nextToken();
313: if (st.hasMoreTokens() == true)
314: v = st.nextToken();
315: return new Locale(l, r, v);
316: } catch (Exception e) {
317: return null;
318: }
319: }
320:
321: public String getTextMessage(String key, Object[] objectArr) {
322: if (res == null) {
323: setResource();
324: }
325: try {
326: return MessageFormat.format(res.getString(key), objectArr);
327: } catch (Exception e) {
328: String tmpFormat = key;
329: for (int i = 0; i < objectArr.length; i++)
330: tmpFormat = tmpFormat + ", <{" + (i) + "}>";
331: return MessageFormat.format(tmpFormat, objectArr);
332: }
333: }
334:
335: public String getLocalizedString(ResultSet rs,
336: ResultSetMetaData rsm, int columnNumber)
337: throws SQLException {
338: if (!enableLocalized) {
339: return rs.getString(columnNumber);
340: }
341: int type = rsm.getColumnType(columnNumber);
342: if (type == Types.DATE) {
343: return getDateAsString(rs.getDate(columnNumber));
344: } else if (type == Types.INTEGER || type == Types.SMALLINT
345: || type == Types.BIGINT || type == Types.TINYINT) {
346: return getNumberAsString(rs.getLong(columnNumber));
347: } else if (type == Types.REAL || type == Types.FLOAT
348: || type == Types.DOUBLE) {
349: return getNumberAsString(rs.getDouble(columnNumber));
350: } else if (HAVE_BIG_DECIMAL
351: && (type == Types.NUMERIC || type == Types.DECIMAL)) {
352: return getNumberAsString(rs.getBigDecimal(columnNumber, rsm
353: .getScale(columnNumber)));
354: } else if (type == Types.TIME) {
355: return getTimeAsString(rs.getTime(columnNumber));
356: } else if (type == Types.TIMESTAMP) {
357: return getTimestampAsString(rs.getTimestamp(columnNumber));
358: }
359: return rs.getString(columnNumber);
360: }
361:
362: public String getDateAsString(Date d) {
363: if (!enableLocalized) {
364: return d.toString();
365: }
366: return formatDate.format(d);
367: }
368:
369: public String getTimeAsString(Date t) {
370: if (!enableLocalized) {
371: return t.toString();
372: }
373: return formatTime.format(t, new StringBuffer(),
374: new java.text.FieldPosition(0)).toString();
375: }
376:
377: public String getNumberAsString(int o) {
378: if (enableLocalized) {
379: return formatNumber.format(o);
380: } else {
381: return String.valueOf(o);
382: }
383: }
384:
385: public String getNumberAsString(long o) {
386: if (enableLocalized) {
387: return formatNumber.format(o);
388: } else {
389: return String.valueOf(o);
390: }
391: }
392:
393: public String getNumberAsString(Object o) {
394: if (enableLocalized) {
395: return formatNumber.format(o, new StringBuffer(),
396: new FieldPosition(0)).toString();
397: } else {
398: return o.toString();
399: }
400: }
401:
402: public String getNumberAsString(double o) {
403: if (!enableLocalized) {
404: return String.valueOf(o);
405: }
406: return formatDecimal.format(o);
407: }
408:
409: public String getTimestampAsString(Timestamp t) {
410: if (!enableLocalized) {
411: return t.toString();
412: }
413: return formatTime.format(t, new StringBuffer(),
414: new java.text.FieldPosition(0)).toString();
415: }
416:
417: public int getColumnDisplaySize(ResultSetMetaData rsm,
418: int columnNumber) throws SQLException {
419: if (!enableLocalized) {
420: return rsm.getColumnDisplaySize(columnNumber);
421: }
422: int type = rsm.getColumnType(columnNumber);
423: if (type == Types.DATE)
424: return dateSize;
425: if (type == Types.TIME)
426: return timeSize;
427: if (type == Types.TIMESTAMP)
428: return timestampSize;
429: return rsm.getColumnDisplaySize(columnNumber);
430: }
431:
432: public String getStringFromDate(String dateStr)
433: throws ParseException {
434: if (!enableLocalized) {
435: return dateStr;
436: }
437: Date d = formatDate.parse(dateStr);
438: return new java.sql.Date(d.getTime()).toString();
439: }
440:
441: public String getStringFromTime(String timeStr)
442: throws ParseException {
443: if (!enableLocalized) {
444: return timeStr;
445: }
446: Date t = formatTime.parse(timeStr);
447: return new java.sql.Time(t.getTime()).toString();
448: }
449:
450: public String getStringFromValue(String val) throws ParseException {
451: if (!enableLocalized) {
452: return val;
453: }
454: return formatNumber.parse(val).toString();
455: }
456:
457: public String getStringFromTimestamp(String timestampStr)
458: throws ParseException {
459: if (!enableLocalized) {
460: return timestampStr;
461: }
462: Date ts = formatTimestamp.parse(timestampStr);
463: return new java.sql.Timestamp(ts.getTime()).toString();
464: }
465:
466: public Locale getLocale() {
467: return locale;
468: }
469:
470: private final synchronized String getEnvProperty(String key) {
471: String s;
472: try {
473: resourceKey = key;
474: s = (String) java.security.AccessController
475: .doPrivileged(this );
476: } catch (SecurityException se) {
477: s = null;
478: }
479: //System.out.println("{"+resourceKey+"="+s+"}");
480: return s;
481: }
482:
483: public final Object run() {
484: String s = System.getProperty(resourceKey);
485: return s;
486: }
487:
488: public static boolean enableLocalization(boolean mode) {
489: getInstance().enableLocalized = mode;
490: //re-initialized locale
491: getInstance().init();
492: return mode;
493: }
494:
495: public boolean isLocalized() {
496: return getInstance().enableLocalized;
497: }
498:
499: public static String getMessage(String key) {
500: return getInstance().getTextMessage(key);
501: }
502:
503: public static String getMessage(String key, Object o1) {
504: return getInstance().getTextMessage(key, o1);
505: }
506:
507: public static String getMessage(String key, Object o1, Object o2) {
508: return getInstance().getTextMessage(key, o1, o2);
509: }
510:
511: public static String getMessage(String key, Object o1, Object o2,
512: Object o3) {
513: return getInstance().getTextMessage(key, o1, o2, o3);
514: }
515:
516: public static String getMessage(String key, Object o1, Object o2,
517: Object o3, Object o4) {
518: return getInstance().getTextMessage(key, o1, o2, o3, o4);
519: }
520:
521: public static LocalizedOutput OutputWriter() {
522: return getInstance().out;
523: }
524:
525: public static LocalizedInput InputReader() {
526: return getInstance().in;
527: }
528:
529: public static String getNumber(long o) {
530: return getInstance().getNumberAsString(o);
531: }
532:
533: public static String getNumber(int o) {
534: return getInstance().getNumberAsString(o);
535: }
536:
537: public static void setUnicodeEscape(boolean u) {
538: getInstance().unicodeEscape = u;
539: }
540:
541: public static boolean getUnicodeEscape() {
542: return getInstance().unicodeEscape;
543: }
544:
545: public String toString() {
546: String s = "toString(){\n" + "locale="
547: + (locale == null ? "null" : locale.toString()) + "\n"
548: + "encode=" + encode + "\n" + "messageFile="
549: + messageFileName + "\n" + "resourceKey=" + resourceKey
550: + "\n" + "enableLocalized=" + enableLocalized + " \n"
551: + "unicodeEscape=" + unicodeEscape + "\n" + "dateSize="
552: + dateSize + "\n" + "timeSize=" + timeSize + "\n"
553: + "timestampSize=" + timestampSize + "\n}";
554: return s;
555: }
556: }
|