001: /*
002: * (C) Copyright IBM Corp. 2002-2005 - All Rights Reserved
003: */
004:
005: package com.ibm.icu.impl;
006:
007: import java.lang.ref.SoftReference;
008: import java.util.Locale;
009: import java.util.MissingResourceException;
010: import java.util.ResourceBundle;
011: import java.util.Arrays;
012: import java.util.Collections;
013: import java.util.HashMap;
014: import java.util.HashSet;
015: import java.util.Map;
016: import java.util.Set;
017:
018: import com.ibm.icu.util.ULocale;
019:
020: /**
021: * Provides information about and access to resource bundles in the
022: * com.ibm.text.resources package. Unlike the java version, this does
023: * not include resources from any other location. In particular, it
024: * does not look in the boot or system class path.
025: */
026: public class ICULocaleData {
027:
028: /**
029: * The package for ICU locale data.
030: */
031: private static final String ICU_PACKAGE = "com.ibm.icu.impl.data";
032:
033: /**
034: * The base name (bundle name) for ICU locale data.
035: */
036: static final String LOCALE_ELEMENTS = "LocaleElements";
037:
038: /**
039: * Creates a LocaleElements resource bundle for the given locale
040: * in the default ICU package.
041: * @param locale the locale of the bundle to retrieve, or
042: * null to use the default locale
043: * @return a ResourceBundle for the LocaleElements of the given
044: * locale, or null on failure
045: */
046: public static ResourceBundle getLocaleElements(ULocale locale) {
047: if (locale == null) {
048: locale = ULocale.getDefault();
049: }
050: return getResourceBundle(ICU_PACKAGE, LOCALE_ELEMENTS, locale
051: .getBaseName());
052: }
053:
054: /**
055: * Creates a LocaleElements resource bundle for the given locale
056: * in the default ICU package.
057: * @param localeName the string name of the locale of the bundle
058: * to retrieve, e.g., "en_US".
059: * @return a ResourceBundle for the LocaleElements of the given
060: * locale, or null on failure
061: */
062: public static ResourceBundle getLocaleElements(String localeName) {
063: return getResourceBundle(ICU_PACKAGE, LOCALE_ELEMENTS,
064: localeName);
065: }
066:
067: /**
068: * Creates a resource bundle for the given base name and locale
069: * in the default ICU package.
070: * @param bundleName the base name of the bundle to retrieve,
071: * e.g. "LocaleElements".
072: * @param localeName the string name of the locale of the bundle
073: * to retrieve, e.g. "en_US".
074: * @return a ResourceBundle with the given base name for the given
075: * locale, or null on failure
076: */
077: public static ResourceBundle getResourceBundle(String bundleName,
078: String localeName) {
079: return getResourceBundle(ICU_PACKAGE, bundleName, localeName);
080: }
081:
082: /**
083: * Creates a resource bundle for the given base name and locale
084: * in the default ICU package.
085: * @param bundleName the base name of the bundle to retrieve,
086: * e.g. "LocaleElements".
087: * @param locale the locale of the bundle to retrieve, or
088: * null to use the default locale
089: * @return a ResourceBundle with the given base name for the given
090: * locale, or null on failure
091: */
092: public static ResourceBundle getResourceBundle(String bundleName,
093: ULocale locale) {
094: if (locale == null) {
095: locale = ULocale.getDefault();
096: }
097: return getResourceBundle(ICU_PACKAGE, bundleName, locale
098: .getBaseName());
099: }
100:
101: /**
102: * Creates a resource bundle for the given package, base name, and
103: * locale.
104: * @param packageName a package name, e.g., "com.ibm.icu.impl.data".
105: * @param bundleName the base name of the bundle to retrieve,
106: * e.g. "LocaleElements".
107: * @param localeName the string name of the locale of the bundle
108: * to retrieve, e.g. "en_US".
109: * @return the first ResourceBundle with the given base name for
110: * the given locale found in each of the packages, or null on
111: * failure
112: */
113: public static ResourceBundle getResourceBundle(String packageName,
114: String bundleName, String localeName) {
115: try {
116: String path = packageName + "." + bundleName;
117: if (DEBUG)
118: System.out.println("calling instantiate: " + path + "_"
119: + localeName);
120: return instantiate(path, localeName);
121: } catch (MissingResourceException e) {
122: if (DEBUG)
123: System.out.println(bundleName + "_" + localeName
124: + " not found in " + packageName);
125: throw e;
126: }
127: }
128:
129: /**
130: * Creates a resource bundle for the given base name and locale in
131: * one of the given packages, trying each package in order.
132: * @param packages a list of one or more package names
133: * @param bundleName the base name of the bundle to retrieve,
134: * e.g. "LocaleElements".
135: * @param localeName the string name of the locale of the bundle
136: * to retrieve, e.g. "en_US".
137: * @return the first ResourceBundle with the given base name for
138: * the given locale found in each of the packages, or null on
139: * failure
140: */
141: public static ResourceBundle getResourceBundle(String[] packages,
142: String bundleName, String localeName) {
143: ResourceBundle r = null;
144: for (int i = 0; r == null && i < packages.length; ++i) {
145: r = getResourceBundle(packages[i], bundleName, localeName);
146: }
147: return r;
148: }
149:
150: /**
151: * Get a resource bundle from the resource bundle path. Unlike getResourceBundle, this
152: * returns an 'unparented' bundle that exactly matches the bundle name and locale name.
153: */
154: public static ResourceBundle loadResourceBundle(String bundleName,
155: ULocale locale) {
156: if (locale == null) {
157: locale = ULocale.getDefault();
158: }
159: return loadResourceBundle(bundleName, locale.getBaseName());
160: }
161:
162: /**
163: * Get a resource bundle from the resource bundle path. Unlike getResourceBundle, this
164: * returns an 'unparented' bundle that exactly matches the bundle name and locale name.
165: */
166: public static ResourceBundle loadResourceBundle(String bundleName,
167: String localeName) {
168: if (localeName != null && localeName.length() > 0) {
169: bundleName = bundleName + "_" + localeName;
170: }
171: String name = ICU_PACKAGE + "." + bundleName;
172: try {
173: if (name.indexOf("_zh_") == -1) { // DLF temporary hack
174: Class rbclass = Class.forName(name);
175: ResourceBundle rb = (ResourceBundle) rbclass
176: .newInstance();
177: return rb;
178: }
179: } catch (ClassNotFoundException e) {
180: if (DEBUG) {
181: System.out.println(name + " not found");
182: }
183: // ignore, keep looking
184: } catch (Exception e) {
185: if (DEBUG) {
186: e.printStackTrace();
187: System.out.println(e.getMessage());
188: }
189: }
190: if (DEBUG) {
191: System.out.println(bundleName + " not found.");
192: }
193:
194: return null;
195: }
196:
197: // ========== privates ==========
198:
199: // Flag for enabling/disabling debugging code
200: private static final boolean DEBUG = ICUDebug.enabled("localedata");
201:
202: // Cache for getAvailableLocales
203: private static SoftReference GET_AVAILABLE_CACHE;
204:
205: // Cache for ResourceBundle instantiation
206: private static SoftReference BUNDLE_CACHE;
207:
208: private static ResourceBundle loadFromCache(String key) {
209: if (BUNDLE_CACHE != null) {
210: Map m = (Map) BUNDLE_CACHE.get();
211: if (m != null) {
212: return (ResourceBundle) m.get(key);
213: }
214: }
215: return null;
216: }
217:
218: private static void addToCache(String key, ResourceBundle b) {
219: Map m = null;
220: if (BUNDLE_CACHE != null) {
221: m = (Map) BUNDLE_CACHE.get();
222: }
223: if (m == null) {
224: m = new HashMap();
225: BUNDLE_CACHE = new SoftReference(m);
226: }
227: m.put(key, b);
228: }
229:
230: // recursively build bundle
231: private static ResourceBundle instantiate(String name) {
232: ResourceBundle b = loadFromCache(name);
233: if (b == null) {
234: ResourceBundle parent = null;
235: int i = name.lastIndexOf('_');
236:
237: // TODO: convert this to use ULocale
238: final Locale rootLocale = new Locale("", "", "");
239:
240: if (i != -1) {
241: parent = instantiate(name.substring(0, i));
242: }
243: try {
244: Locale locale = rootLocale;
245: i = name.indexOf('_');
246: if (i != -1) {
247: locale = LocaleUtility.getLocaleFromName(name
248: .substring(i + 1));
249: } else {
250: i = name.length();
251: }
252:
253: ClassLoader cl = ICULocaleData.class.getClassLoader();
254: if (cl == null) {
255: // we're on the bootstrap
256: cl = ClassLoader.getSystemClassLoader();
257: }
258: Class cls = cl.loadClass(name);
259: if (ICUListResourceBundle.class.isAssignableFrom(cls)) {
260: ICUListResourceBundle bx = (ICUListResourceBundle) cls
261: .newInstance();
262:
263: if (parent != null) {
264: bx.setParentX(parent);
265: }
266: bx.icuLocale = locale;
267: b = bx;
268: // System.out.println("iculistresourcebundle: " + name + " is " + b);
269: } else {
270: b = ResourceBundle.getBundle(name.substring(0, i),
271: locale);
272: // System.out.println("resourcebundle: " + name + " is " + b);
273: }
274: addToCache(name, b);
275: } catch (ClassNotFoundException e) {
276:
277: int j = name.indexOf('_');
278: int k = name.lastIndexOf('_');
279: // if a bogus locale is passed then the parent should be
280: // the default locale not the root locale!
281: if (k == j && j != -1) {
282:
283: String locName = name.substring(j + 1, name
284: .length());
285: String defaultName = ULocale.getDefault()
286: .toString();
287:
288: if (!locName.equals(rootLocale.toString())
289: && defaultName.indexOf(locName) == -1) {
290: String bundle = name.substring(0, j);
291: parent = instantiate(bundle + "_" + defaultName);
292: }
293: }
294: b = parent;
295: } catch (Exception e) {
296: System.out.println("failure");
297: System.out.println(e);
298: }
299: }
300: //if(b==null){
301: // throw new MissingResourceException("Could not load data "+name,"","");
302: //}
303: return b;
304: }
305:
306: /**
307: * Still need permissions to use our own class loader, is there no way
308: * to load class resources from new locations that aren't already on the
309: * class path?
310: */
311: private synchronized static ResourceBundle instantiate(String name,
312: String localeName) {
313: if (localeName.length() != 0) {
314: name = name + "_" + localeName;
315: }
316: ResourceBundle b = instantiate(name);
317: if (b == null) {
318: throw new MissingResourceException("Could not load data "
319: + name, "", "");
320: }
321: return b;
322: }
323:
324: private static Set createLocaleNameSet(String bundleName) {
325: try {
326: ResourceBundle index = getResourceBundle(bundleName,
327: "index");
328: Object[][] localeStrings = (Object[][]) index
329: .getObject("InstalledLocales");
330: String[] localeNames = new String[localeStrings.length];
331:
332: // barf gag choke spit hack...
333: // since java's Locale 'fixes' the locale string for some locales,
334: // we have to fix our names to match, otherwise the Locale[] list
335: // won't match the locale name set. What were they thinking?!?
336: for (int i = 0; i < localeNames.length; ++i) {
337: localeNames[i] = LocaleUtility.getLocaleFromName(
338: (String) localeStrings[i][0]).toString();
339: }
340:
341: HashSet set = new HashSet();
342: set.addAll(Arrays.asList(localeNames));
343: return Collections.unmodifiableSet(set);
344: } catch (MissingResourceException e) {
345: if (DEBUG)
346: System.out
347: .println("couldn't find index for bundleName: "
348: + bundleName);
349: Thread.dumpStack();
350: }
351: return Collections.EMPTY_SET;
352: }
353:
354: /*
355: private static Locale[] createLocaleList(String bundleName) {
356: try {
357: ResourceBundle index = getResourceBundle(bundleName, "index");
358: Object[][] localeStrings = (Object[][]) index.getObject("InstalledLocales");
359: Locale[] locales = new Locale[localeStrings.length];
360: for (int i = 0; i < localeStrings.length; ++i) {
361: locales[i] = LocaleUtility.getLocaleFromName((String)localeStrings[i][0]);
362: }
363: return locales;
364: }
365: catch (MissingResourceException e) {
366: if (DEBUG) System.out.println("couldn't find index for bundleName: " + bundleName);
367: Thread.dumpStack();
368: }
369: return new Locale[0];
370: }
371: */
372: }
|