001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019:
020: package org.apache.axis2.i18n;
021:
022: import java.io.IOException;
023: import java.io.InputStream;
024: import java.text.MessageFormat;
025: import java.util.Enumeration;
026: import java.util.Hashtable;
027: import java.util.Locale;
028: import java.util.MissingResourceException;
029: import java.util.Properties;
030:
031: /**
032: * CURRENTLY NOT USED
033: * KEEPING FOR REFERENCE 9/19/2002
034: * <p/>
035: * <p>Wrapper class for resource bundles. Property files are used to store
036: * resource strings, which are the only types of resources available.
037: * Property files can inherit properties from other files so that
038: * a base property file can be used and a small number of properties
039: * can be over-ridden by another property file. For example you may
040: * create an english version of a resource file named "resource.properties".
041: * You then decide that the British English version of all of the properties
042: * except one are the same, so there is no need to redefine all of the
043: * properties in "resource_en_GB", just the one that is different.</p>
044: * <p>The property file lookup searches for classes with various suffixes
045: * on the basis if the desired local and the current default local
046: * (as returned by Local.getDefault()). As property files are found the
047: * property values are merged so that inheritance is preserved.</p>
048: * <p>The order of searching is:</p>
049: * <dir>
050: * basename + "_" + langage + "_" + country + "_" + variant
051: * basename + "_" + langage + "_" + country
052: * basename + "_" + langage
053: * basename + "_" + defaultLanguage + "_" + defaultCountry + "_" + defaultVariant
054: * basename + "_" + defaultLanguage + "_" + defaultCountry
055: * basename + "_" + defaultLanguage
056: * basename
057: * </dir>
058: * <p>The basename is the name of the property file without the ".properties"
059: * extension.</p>
060: * <p>Properties will be cached for performance.<p>
061: * <p>Property values stored in the property files can also contain dynamic
062: * variables. Any dynamic variable defined in PropertiesUtil.getVariableValue()
063: * can be used (such as {date}), as well as arguments in the form {0}, {1}, etc.
064: * Argument values are specified in the various overloaded getString() methods.</p>
065: */
066: public class RB {
067: // The static cache of properties. The key is the basename + the local +
068: // the default local and the element is the Properties object containing
069: // the resources
070: static Hashtable propertyCache = new Hashtable();
071:
072: // The default base name
073: public static final String BASE_NAME = "resource";
074:
075: // The property file extension
076: public static final String PROPERTY_EXT = ".properties";
077:
078: // The name of the current base property file (with extension)
079: protected String basePropertyFileName;
080:
081: // The properties for the current resource bundle
082: protected Properties resourceProperties;
083:
084: /**
085: * Construct a new RB
086: *
087: * @param name The name of the property file without the ".properties" extension
088: */
089: public RB(String name) throws MissingResourceException {
090: this (null, name, null);
091: }
092:
093: /**
094: * Construct a new RB
095: *
096: * @param caller The calling object. This is used to get the package name
097: * to further construct the basename as well as to get the proper ClassLoader
098: * @param name The name of the property file without the ".properties" extension
099: */
100: public RB(Object caller, String name)
101: throws MissingResourceException {
102: this (caller, name, null);
103: }
104:
105: /**
106: * Construct a new RB
107: *
108: * @param caller The calling object. This is used to get the package name
109: * to further construct the basename as well as to get the proper ClassLoader
110: * @param name The name of the property file without the ".properties" extension
111: * @param locale The locale
112: */
113: public RB(Object caller, String name, Locale locale)
114: throws MissingResourceException {
115: ClassLoader cl = null;
116:
117: if (caller != null) {
118:
119: Class c;
120: if (caller instanceof Class) {
121: c = (Class) caller;
122: } else {
123: c = caller.getClass();
124: }
125:
126: // Get the appropriate class loader
127: cl = c.getClassLoader();
128:
129: if (name.indexOf("/") == -1) {
130:
131: // Create the full basename only if not given
132: String fullName = c.getName();
133:
134: int pos = fullName.lastIndexOf(".");
135: if (pos > 0) {
136: name = fullName.substring(0, pos + 1).replace('.',
137: '/')
138: + name;
139: }
140: }
141: } else {
142: // Try the shared default properties file...
143: if (name.indexOf("/") == -1) {
144: name = "org/apache/axis2/default-resource";
145: }
146: }
147:
148: Locale defaultLocale = Locale.getDefault();
149:
150: // If the locale given is the same as the default locale, ignore it
151: if (locale != null) {
152: if (locale.equals(defaultLocale)) {
153: locale = null;
154: }
155: }
156:
157: // Load the properties. If no property files exist then a
158: // MissingResourceException will be thrown
159: loadProperties(name, cl, locale, defaultLocale);
160: }
161:
162: /**
163: * Gets a string message from the resource bundle for the given key
164: *
165: * @param key The resource key
166: * @return The message
167: */
168: public String getString(String key) throws MissingResourceException {
169: return getString(key, (Object[]) null);
170: }
171:
172: /**
173: * <p>Gets a string message from the resource bundle for the given key. The
174: * message may contain variables that will be substituted with the given
175: * arguments. Variables have the format:</p>
176: * <dir>
177: * This message has two variables: {0} and {1}
178: * </dir>
179: *
180: * @param key The resource key
181: * @param arg0 The argument to place in variable {0}
182: * @return The message
183: */
184: public String getString(String key, Object arg0)
185: throws MissingResourceException {
186: Object[] o = new Object[1];
187: o[0] = arg0;
188: return getString(key, o);
189: }
190:
191: /**
192: * <p>Gets a string message from the resource bundle for the given key. The
193: * message may contain variables that will be substituted with the given
194: * arguments. Variables have the format:</p>
195: * <dir>
196: * This message has two variables: {0} and {1}
197: * </dir>
198: *
199: * @param key The resource key
200: * @param arg0 The argument to place in variable {0}
201: * @param arg1 The argument to place in variable {1}
202: * @return The message
203: */
204: public String getString(String key, Object arg0, Object arg1)
205: throws MissingResourceException {
206: Object[] o = new Object[2];
207: o[0] = arg0;
208: o[1] = arg1;
209: return getString(key, o);
210: }
211:
212: /**
213: * <p>Gets a string message from the resource bundle for the given key. The
214: * message may contain variables that will be substituted with the given
215: * arguments. Variables have the format:</p>
216: * <dir>
217: * This message has two variables: {0} and {1}
218: * </dir>
219: *
220: * @param key The resource key
221: * @param arg0 The argument to place in variable {0}
222: * @param arg1 The argument to place in variable {1}
223: * @param arg2 The argument to place in variable {1}
224: * @return The message
225: */
226: public String getString(String key, Object arg0, Object arg1,
227: Object arg2) throws MissingResourceException {
228: Object[] o = new Object[3];
229: o[0] = arg0;
230: o[1] = arg1;
231: o[2] = arg2;
232: return getString(key, o);
233: }
234:
235: /**
236: * <p>Gets a string message from the resource bundle for the given key. The
237: * message may contain variables that will be substituted with the given
238: * arguments. Variables have the format:</p>
239: * <dir>
240: * This message has two variables: {0} and {1}
241: * </dir>
242: *
243: * @param key The resource key
244: * @param array An array of objects to place in corresponding variables
245: * @return The message
246: */
247: public String getString(String key, Object[] array)
248: throws MissingResourceException {
249: String msg = null;
250: if (resourceProperties != null) {
251: msg = resourceProperties.getProperty(key);
252: }
253:
254: if (msg == null) {
255: throw new MissingResourceException(
256: "Cannot find resource key \"" + key
257: + "\" in base name " + basePropertyFileName,
258: basePropertyFileName, key);
259: }
260:
261: msg = MessageFormat.format(msg, array);
262: return msg;
263: }
264:
265: protected void loadProperties(String basename, ClassLoader loader,
266: Locale locale, Locale defaultLocale)
267: throws MissingResourceException {
268: // Check the cache first
269: String loaderName = "";
270: if (loader != null) {
271: loaderName = ":" + loader.hashCode();
272: }
273: String cacheKey = basename + ":" + locale + ":" + defaultLocale
274: + loaderName;
275: Properties p = (Properties) propertyCache.get(cacheKey);
276: basePropertyFileName = basename + PROPERTY_EXT;
277:
278: if (p == null) {
279: // The properties were not found in the cache. Search the given locale
280: // first
281: if (locale != null) {
282: p = loadProperties(basename, loader, locale, p);
283: }
284:
285: // Search the default locale
286: if (defaultLocale != null) {
287: p = loadProperties(basename, loader, defaultLocale, p);
288: }
289:
290: // Search for the basename
291: p = merge(p, loadProperties(basePropertyFileName, loader));
292:
293: if (p == null) {
294: throw new MissingResourceException(
295: "Cannot find resource for base name "
296: + basePropertyFileName,
297: basePropertyFileName, "");
298: }
299:
300: // Cache the properties
301: propertyCache.put(cacheKey, p);
302:
303: }
304:
305: resourceProperties = p;
306: }
307:
308: protected Properties loadProperties(String basename,
309: ClassLoader loader, Locale locale, Properties props) {
310:
311: String language = locale.getLanguage();
312: String country = locale.getCountry();
313: String variant = locale.getVariant();
314: if (variant != null) {
315: if (variant.trim().length() == 0) {
316: variant = null;
317: }
318: }
319:
320: if (language != null) {
321:
322: if (country != null) {
323:
324: if (variant != null) {
325: props = merge(props, loadProperties(basename + "_"
326: + language + "_" + country + "_" + variant
327: + PROPERTY_EXT, loader));
328: }
329: props = merge(props, loadProperties(basename + "_"
330: + language + "_" + country + PROPERTY_EXT,
331: loader));
332: }
333: props = merge(props, loadProperties(basename + "_"
334: + language + PROPERTY_EXT, loader));
335: }
336: return props;
337: }
338:
339: protected Properties loadProperties(String resname,
340: ClassLoader loader) {
341: Properties props = null;
342:
343: // Attempt to open and load the properties
344: InputStream in = null;
345: try {
346: if (loader != null) {
347: in = loader.getResourceAsStream(resname);
348: }
349:
350: // Either we're using the system class loader or we didn't find the
351: // resource using the given class loader
352: if (in == null) {
353: in = ClassLoader.getSystemResourceAsStream(resname);
354: }
355: if (in != null) {
356: props = new Properties();
357: try {
358: props.load(in);
359: } catch (IOException ex) {
360: // On error, clear the props
361: props = null;
362: }
363: }
364: } finally {
365: if (in != null) {
366: try {
367: in.close();
368: } catch (Exception ex) {
369: // Ignore error on close
370: }
371: }
372: }
373: return props;
374: }
375:
376: /**
377: * Merge two Properties objects
378: */
379: protected Properties merge(Properties p1, Properties p2) {
380: if ((p1 == null) && (p2 == null)) {
381: return null;
382: } else if (p1 == null) {
383: return p2;
384: } else if (p2 == null) {
385: return p1;
386: }
387:
388: // Now merge. p1 takes precedence
389: Enumeration enumeration = p2.keys();
390: while (enumeration.hasMoreElements()) {
391: String key = (String) enumeration.nextElement();
392: if (p1.getProperty(key) == null) {
393: p1.put(key, p2.getProperty(key));
394: }
395: }
396:
397: return p1;
398: }
399:
400: /**
401: * Get the underlying properties
402: */
403: public Properties getProperties() {
404: return resourceProperties;
405: }
406:
407: // STATIC ACCESSORS
408:
409: /**
410: * Get a message from resource.properties from the package of the given object.
411: *
412: * @param caller The calling object, used to get the package name and class loader
413: * @param key The resource key
414: * @return The formatted message
415: */
416: public static String getString(Object caller, String key)
417: throws MissingResourceException {
418: return getMessage(caller, BASE_NAME, null, key, null);
419: }
420:
421: /**
422: * Get a message from resource.properties from the package of the given object.
423: *
424: * @param caller The calling object, used to get the package name and class loader
425: * @param key The resource key
426: * @param arg0 The argument to place in variable {0}
427: * @return The formatted message
428: */
429: public static String getString(Object caller, String key,
430: Object arg0) throws MissingResourceException {
431: Object[] o = new Object[1];
432: o[0] = arg0;
433: return getMessage(caller, BASE_NAME, null, key, o);
434: }
435:
436: /**
437: * Get a message from resource.properties from the package of the given object.
438: *
439: * @param caller The calling object, used to get the package name and class loader
440: * @param key The resource key
441: * @param arg0 The argument to place in variable {0}
442: * @param arg1 The argument to place in variable {1}
443: * @return The formatted message
444: */
445: public static String getString(Object caller, String key,
446: Object arg0, Object arg1) throws MissingResourceException {
447: Object[] o = new Object[2];
448: o[0] = arg0;
449: o[1] = arg1;
450: return getMessage(caller, BASE_NAME, null, key, o);
451: }
452:
453: /**
454: * Get a message from resource.properties from the package of the given object.
455: *
456: * @param caller The calling object, used to get the package name and class loader
457: * @param key The resource key
458: * @param arg0 The argument to place in variable {0}
459: * @param arg1 The argument to place in variable {1}
460: * @param arg2 The argument to place in variable {2}
461: * @return The formatted message
462: */
463: public static String getString(Object caller, String key,
464: Object arg0, Object arg1, Object arg2)
465: throws MissingResourceException {
466: Object[] o = new Object[3];
467: o[0] = arg0;
468: o[1] = arg1;
469: o[2] = arg2;
470: return getMessage(caller, BASE_NAME, null, key, o);
471: }
472:
473: /**
474: * Get a message from resource.properties from the package of the given object.
475: *
476: * @param caller The calling object, used to get the package name and class loader
477: * @param key The resource key
478: * @param arg0 The argument to place in variable {0}
479: * @param arg1 The argument to place in variable {1}
480: * @param arg2 The argument to place in variable {2}
481: * @param arg3 The argument to place in variable {3}
482: * @return The formatted message
483: */
484: public static String getString(Object caller, String key,
485: Object arg0, Object arg1, Object arg2, Object arg3)
486: throws MissingResourceException {
487: Object[] o = new Object[4];
488: o[0] = arg0;
489: o[1] = arg1;
490: o[2] = arg2;
491: o[3] = arg3;
492: return getMessage(caller, BASE_NAME, null, key, o);
493: }
494:
495: /**
496: * Get a message from resource.properties from the package of the given object.
497: *
498: * @param caller The calling object, used to get the package name and class loader
499: * @param key The resource key
500: * @param arg0 The argument to place in variable {0}
501: * @param arg1 The argument to place in variable {1}
502: * @param arg2 The argument to place in variable {2}
503: * @param arg3 The argument to place in variable {3}
504: * @param arg4 The argument to place in variable {4}
505: * @return Returns the formatted message.
506: */
507: public static String getString(Object caller, String key,
508: Object arg0, Object arg1, Object arg2, Object arg3,
509: Object arg4) throws MissingResourceException {
510: Object[] o = new Object[5];
511: o[0] = arg0;
512: o[1] = arg1;
513: o[2] = arg2;
514: o[3] = arg3;
515: o[4] = arg4;
516: return getMessage(caller, BASE_NAME, null, key, o);
517: }
518:
519: /**
520: * Get a message from resource.properties from the package of the given object.
521: *
522: * @param caller The calling object, used to get the package name and class loader
523: * @param key The resource key
524: * @param args An array of objects to place in corresponding variables
525: * @return Returns the formatted message.
526: */
527: public static String getString(Object caller, String key,
528: Object[] args) throws MissingResourceException {
529: return getMessage(caller, BASE_NAME, null, key, args);
530: }
531:
532: /**
533: * Get a message from resource.properties from the package of the given object.
534: *
535: * @param caller The calling object, used to get the package name and class loader
536: * @param locale The locale
537: * @param key The resource key
538: * @return The formatted message
539: */
540: public static String getString(Object caller, Locale locale,
541: String key) throws MissingResourceException {
542: return getMessage(caller, BASE_NAME, locale, key, null);
543: }
544:
545: /**
546: * Get a message from resource.properties from the package of the given object.
547: *
548: * @param caller The calling object, used to get the package name and class loader
549: * @param locale The locale
550: * @param key The resource key
551: * @param arg0 The argument to place in variable {0}
552: * @return The formatted message
553: */
554: public static String getString(Object caller, Locale locale,
555: String key, Object arg0) throws MissingResourceException {
556: Object[] o = new Object[1];
557: o[0] = arg0;
558: return getMessage(caller, BASE_NAME, locale, key, o);
559: }
560:
561: /**
562: * Get a message from resource.properties from the package of the given object.
563: *
564: * @param caller The calling object, used to get the package name and class loader
565: * @param locale The locale
566: * @param key The resource key
567: * @param arg0 The argument to place in variable {0}
568: * @param arg1 The argument to place in variable {1}
569: * @return The formatted message
570: */
571: public static String getString(Object caller, Locale locale,
572: String key, Object arg0, Object arg1)
573: throws MissingResourceException {
574: Object[] o = new Object[2];
575: o[0] = arg0;
576: o[1] = arg1;
577: return getMessage(caller, BASE_NAME, locale, key, o);
578: }
579:
580: /**
581: * Get a message from resource.properties from the package of the given object.
582: *
583: * @param caller The calling object, used to get the package name and class loader
584: * @param locale The locale
585: * @param key The resource key
586: * @param arg0 The argument to place in variable {0}
587: * @param arg1 The argument to place in variable {1}
588: * @param arg2 The argument to place in variable {2}
589: * @return The formatted message
590: */
591: public static String getString(Object caller, Locale locale,
592: String key, Object arg0, Object arg1, Object arg2)
593: throws MissingResourceException {
594: Object[] o = new Object[3];
595: o[0] = arg0;
596: o[1] = arg1;
597: o[2] = arg2;
598: return getMessage(caller, BASE_NAME, locale, key, o);
599: }
600:
601: /**
602: * Get a message from resource.properties from the package of the given object.
603: *
604: * @param caller The calling object, used to get the package name and class loader
605: * @param locale The locale
606: * @param key The resource key
607: * @param arg0 The argument to place in variable {0}
608: * @param arg1 The argument to place in variable {1}
609: * @param arg2 The argument to place in variable {2}
610: * @param arg3 The argument to place in variable {3}
611: * @return The formatted message
612: */
613: public static String getString(Object caller, Locale locale,
614: String key, Object arg0, Object arg1, Object arg2,
615: Object arg3) throws MissingResourceException {
616: Object[] o = new Object[4];
617: o[0] = arg0;
618: o[1] = arg1;
619: o[2] = arg2;
620: o[3] = arg3;
621: return getMessage(caller, BASE_NAME, locale, key, o);
622: }
623:
624: /**
625: * Get a message from resource.properties from the package of the given object.
626: *
627: * @param caller The calling object, used to get the package name and class loader
628: * @param locale The locale
629: * @param key The resource key
630: * @param arg0 The argument to place in variable {0}
631: * @param arg1 The argument to place in variable {1}
632: * @param arg2 The argument to place in variable {2}
633: * @param arg3 The argument to place in variable {3}
634: * @return Returns the formatted message.
635: */
636: public static String getString(Object caller, Locale locale,
637: String key, Object arg0, Object arg1, Object arg2,
638: Object arg3, Object arg4) throws MissingResourceException {
639: Object[] o = new Object[5];
640: o[0] = arg0;
641: o[1] = arg1;
642: o[2] = arg2;
643: o[3] = arg3;
644: o[4] = arg4;
645: return getMessage(caller, BASE_NAME, locale, key, o);
646: }
647:
648: /**
649: * Get a message from resource.properties from the package of the given object.
650: *
651: * @param caller The calling object, used to get the package name and class loader
652: * @param locale The locale
653: * @param key The resource key
654: * @param args An array of objects to place in corresponding variables
655: * @return Returns the formatted message.
656: */
657: public static String getString(Object caller, Locale locale,
658: String key, Object[] args) throws MissingResourceException {
659: return getMessage(caller, BASE_NAME, locale, key, args);
660: }
661:
662: // Workhorse that does the resource loading and key lookup
663: public static String getMessage(Object caller, String basename,
664: Locale locale, String key, Object[] args)
665: throws MissingResourceException {
666: String msg = null;
667: MissingResourceException firstEx = null;
668: String fullName = null;
669: Class curClass = null;
670: boolean didNull = false;
671:
672: if (caller != null) {
673: if (caller instanceof Class) {
674: curClass = (Class) caller;
675: } else {
676: curClass = caller.getClass();
677: }
678: }
679:
680: while (msg == null) {
681:
682: // Get the full name of the resource
683: if (curClass != null) {
684:
685: // Create the full basename
686: String pkgName = curClass.getName();
687:
688: int pos = pkgName.lastIndexOf(".");
689: if (pos > 0) {
690: fullName = pkgName.substring(0, pos + 1).replace(
691: '.', '/')
692: + basename;
693: } else {
694: fullName = basename;
695: }
696: } else {
697: fullName = basename;
698: }
699:
700: try {
701: RB rb = new RB(caller, fullName, locale);
702: msg = rb.getString(key, args);
703: } catch (MissingResourceException ex) {
704: if (curClass == null) {
705: throw ex;
706: }
707:
708: // Save the first exception
709: if (firstEx == null) {
710: firstEx = ex;
711: }
712:
713: // Get the superclass
714: curClass = curClass.getSuperclass();
715: if (curClass == null) {
716: if (didNull) {
717: throw firstEx;
718: }
719: didNull = true;
720: caller = null;
721: } else {
722: String cname = curClass.getName();
723: if (cname.startsWith("java.")
724: || cname.startsWith("javax.")) {
725: if (didNull) {
726: throw firstEx;
727: }
728: didNull = true;
729: caller = null;
730: curClass = null;
731: }
732: }
733: }
734:
735: }
736: return msg;
737: }
738:
739: /**
740: * Clears the internal cache.
741: */
742: public static void clearCache() {
743: propertyCache.clear();
744: }
745: }
|