]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/main/classes/core/src/com/ibm/icu/util/UResourceBundle.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / main / classes / core / src / com / ibm / icu / util / UResourceBundle.java
1 /*\r
2  *******************************************************************************\r
3  * Copyright (C) 2004-2010, International Business Machines Corporation and    *\r
4  * others. All Rights Reserved.                                                *\r
5  *******************************************************************************\r
6  */\r
7 \r
8 package com.ibm.icu.util;\r
9 \r
10 import java.lang.ref.SoftReference;\r
11 import java.nio.ByteBuffer;\r
12 import java.util.Collections;\r
13 import java.util.Enumeration;\r
14 import java.util.HashMap;\r
15 import java.util.Locale;\r
16 import java.util.Map;\r
17 import java.util.MissingResourceException;\r
18 import java.util.ResourceBundle;\r
19 import java.util.Set;\r
20 import java.util.TreeSet;\r
21 \r
22 import com.ibm.icu.impl.ICUCache;\r
23 import com.ibm.icu.impl.ICUResourceBundle;\r
24 import com.ibm.icu.impl.ResourceBundleWrapper;\r
25 import com.ibm.icu.impl.SimpleCache;\r
26 \r
27 /**\r
28  * {@icuenhanced java.util.ResourceBundle}.{@icu _usage_}\r
29  *\r
30  * <p>A class representing a collection of resource information pertaining to a given\r
31  * locale. A resource bundle provides a way of accessing locale- specific information in a\r
32  * data file. You create a resource bundle that manages the resources for a given locale\r
33  * and then ask it for individual resources.\r
34  *\r
35  * <p>In ResourceBundle, an object is created and the sub-items are fetched using the\r
36  * getString and getObject methods.  In UResourceBundle, each individual element of a\r
37  * resource is a resource by itself.\r
38  *\r
39  * <p>Resource bundles in ICU are currently defined using text files that conform to the\r
40  * following <a\r
41  * href="http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt">BNF\r
42  * definition</a>.  More on resource bundle concepts and syntax can be found in the <a\r
43  * href="http://www.icu-project.org/userguide/ResourceManagement.html">Users Guide</a>.\r
44  *\r
45  * <p>The packaging of ICU *.res files can be of two types\r
46  * ICU4C:\r
47  * <pre>\r
48  *       root.res\r
49  *         |\r
50  *      --------\r
51  *     |        |\r
52  *   fr.res  en.res\r
53  *     |\r
54  *   --------\r
55  *  |        |\r
56  * fr_CA.res fr_FR.res\r
57  * </pre>\r
58  * JAVA/JDK:\r
59  * <pre>\r
60  *    LocaleElements.res\r
61  *         |\r
62  *      -------------------\r
63  *     |                   |\r
64  * LocaleElements_fr.res  LocaleElements_en.res\r
65  *     |\r
66  *   ---------------------------\r
67  *  |                            |\r
68  * LocaleElements_fr_CA.res   LocaleElements_fr_FR.res\r
69  * </pre>\r
70  *\r
71  * Depending on the organization of your resources, the syntax to getBundleInstance will\r
72  * change.  To open ICU style organization use:\r
73  *\r
74  * <pre>\r
75  *      UResourceBundle bundle = \r
76  *          UResourceBundle.getBundleInstance("com/mycompany/resources", \r
77  *                                            "en_US", myClassLoader);\r
78  * </pre>\r
79  * To open Java/JDK style organization use:\r
80  * <pre>\r
81  *      UResourceBundle bundle = \r
82  *          UResourceBundle.getBundleInstance("com.mycompany.resources.LocaleElements", \r
83  *                                            "en_US", myClassLoader);\r
84  * </pre>\r
85  * <note>\r
86  * Please use pass a class loader for loading non-ICU resources. Java security does not\r
87  * allow loading of resources across jar files. You must provide your class loader\r
88  * to load the resources\r
89  * </note>\r
90  * @stable ICU 3.0\r
91  * @author ram\r
92  */\r
93 public abstract class UResourceBundle extends ResourceBundle {\r
94 \r
95 \r
96     /**\r
97      * {@icu} Creates a resource bundle using the specified base name and locale.\r
98      * ICU_DATA_CLASS is used as the default root.\r
99      * @param baseName the base name of the resource bundle, a fully qualified class name\r
100      * @param localeName the locale for which a resource bundle is desired\r
101      * @throws MissingResourceException If no resource bundle for the specified base name\r
102      * can be found\r
103      * @return a resource bundle for the given base name and locale\r
104      * @stable ICU 3.0\r
105      */\r
106     public static UResourceBundle getBundleInstance(String baseName, String localeName){\r
107         return getBundleInstance(baseName, localeName, ICUResourceBundle.ICU_DATA_CLASS_LOADER, \r
108                                  false);\r
109     }\r
110 \r
111     /**\r
112      * {@icu} Creates a resource bundle using the specified base name, locale, and class root.\r
113      *\r
114      * @param baseName the base name of the resource bundle, a fully qualified class name\r
115      * @param localeName the locale for which a resource bundle is desired\r
116      * @param root the class object from which to load the resource bundle\r
117      * @throws MissingResourceException If no resource bundle for the specified base name\r
118      * can be found\r
119      * @return a resource bundle for the given base name and locale\r
120      * @stable ICU 3.0\r
121      */\r
122     public static UResourceBundle getBundleInstance(String baseName, String localeName, \r
123                                                     ClassLoader root){\r
124         return getBundleInstance(baseName, localeName, root, false);\r
125     }\r
126 \r
127     /**\r
128      * {@icu} Creates a resource bundle using the specified base name, locale, and class\r
129      * root.\r
130      *\r
131      * @param baseName the base name of the resource bundle, a fully qualified class name\r
132      * @param localeName the locale for which a resource bundle is desired\r
133      * @param root the class object from which to load the resource bundle\r
134      * @param disableFallback Option to disable locale inheritence.\r
135      *                          If true the fallback chain will not be built.\r
136      * @throws MissingResourceException\r
137      *     if no resource bundle for the specified base name can be found\r
138      * @return a resource bundle for the given base name and locale\r
139      * @stable ICU 3.0\r
140      *\r
141      */\r
142     protected static UResourceBundle getBundleInstance(String baseName, String localeName, \r
143                                                        ClassLoader root, boolean disableFallback) {\r
144         return instantiateBundle(baseName, localeName, root, disableFallback);\r
145     }\r
146 \r
147     /**\r
148      * {@icu} Sole constructor.  (For invocation by subclass constructors, typically\r
149      * implicit.)  This is public for compatibility with Java, whose compiler\r
150      * will generate public default constructors for an abstract class.\r
151      * @stable ICU 3.0\r
152      */\r
153     public UResourceBundle() {\r
154     }\r
155 \r
156     /**\r
157      * {@icu} Creates a UResourceBundle for the locale specified, from which users can extract\r
158      * resources by using their corresponding keys.\r
159      * @param locale  specifies the locale for which we want to open the resource.\r
160      *                If null the bundle for default locale is opened.\r
161      * @return a resource bundle for the given locale\r
162      * @stable ICU 3.0\r
163      */\r
164     public static UResourceBundle getBundleInstance(ULocale locale) {\r
165         if (locale==null) {\r
166             locale = ULocale.getDefault();\r
167         }\r
168         return getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale.toString(), \r
169                                  ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);\r
170     }\r
171 \r
172     /**\r
173      * {@icu} Creates a UResourceBundle for the default locale and specified base name,\r
174      * from which users can extract resources by using their corresponding keys.\r
175      * @param baseName  specifies the locale for which we want to open the resource.\r
176      *                If null the bundle for default locale is opened.\r
177      * @return a resource bundle for the given base name and default locale\r
178      * @stable ICU 3.0\r
179      */\r
180     public static UResourceBundle getBundleInstance(String baseName) {\r
181         if (baseName == null) {\r
182             baseName = ICUResourceBundle.ICU_BASE_NAME;\r
183         }\r
184         ULocale uloc = ULocale.getDefault();\r
185         return getBundleInstance(baseName, uloc.toString(), ICUResourceBundle.ICU_DATA_CLASS_LOADER, \r
186                                  false);\r
187     }\r
188 \r
189     /**\r
190      * {@icu} Creates a UResourceBundle for the specified locale and specified base name,\r
191      * from which users can extract resources by using their corresponding keys.\r
192      * @param baseName  specifies the locale for which we want to open the resource.\r
193      *                If null the bundle for default locale is opened.\r
194      * @param locale  specifies the locale for which we want to open the resource.\r
195      *                If null the bundle for default locale is opened.\r
196      * @return a resource bundle for the given base name and locale\r
197      * @stable ICU 3.0\r
198      */\r
199 \r
200     public static UResourceBundle getBundleInstance(String baseName, Locale locale) {\r
201         if (baseName == null) {\r
202             baseName = ICUResourceBundle.ICU_BASE_NAME;\r
203         }\r
204         ULocale uloc = locale == null ? ULocale.getDefault() : ULocale.forLocale(locale);\r
205 \r
206         return getBundleInstance(baseName, uloc.toString(), ICUResourceBundle.ICU_DATA_CLASS_LOADER, \r
207                                  false);\r
208     }\r
209 \r
210     /**\r
211      * {@icu} Creates a UResourceBundle, from which users can extract resources by using\r
212      * their corresponding keys.\r
213      * @param baseName string containing the name of the data package.\r
214      *                    If null the default ICU package name is used.\r
215      * @param locale  specifies the locale for which we want to open the resource.\r
216      *                If null the bundle for default locale is opened.\r
217      * @return a resource bundle for the given base name and locale\r
218      * @stable ICU 3.0\r
219      */\r
220     public static UResourceBundle getBundleInstance(String baseName, ULocale locale) {\r
221         if (baseName == null) {\r
222             baseName = ICUResourceBundle.ICU_BASE_NAME;\r
223         }\r
224         if (locale == null) {\r
225             locale = ULocale.getDefault();\r
226         }\r
227         return getBundleInstance(baseName, locale.toString(), \r
228                                  ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);\r
229     }\r
230 \r
231     /**\r
232      * {@icu} Creates a UResourceBundle for the specified locale and specified base name,\r
233      * from which users can extract resources by using their corresponding keys.\r
234      * @param baseName  specifies the locale for which we want to open the resource.\r
235      *                If null the bundle for default locale is opened.\r
236      * @param locale  specifies the locale for which we want to open the resource.\r
237      *                If null the bundle for default locale is opened.\r
238      * @param loader  the loader to use\r
239      * @return a resource bundle for the given base name and locale\r
240      * @stable ICU 3.8\r
241      */\r
242     public static UResourceBundle getBundleInstance(String baseName, Locale locale, \r
243                                                     ClassLoader loader) {\r
244         if (baseName == null) {\r
245             baseName = ICUResourceBundle.ICU_BASE_NAME;\r
246         }\r
247         ULocale uloc = locale == null ? ULocale.getDefault() : ULocale.forLocale(locale);\r
248         return getBundleInstance(baseName, uloc.toString(), loader, false);\r
249     }\r
250 \r
251     /**\r
252      * {@icu} Creates a UResourceBundle, from which users can extract resources by using\r
253      * their corresponding keys.<br><br>\r
254      * Note: Please use this API for loading non-ICU resources. Java security does not\r
255      * allow loading of resources across jar files. You must provide your class loader\r
256      * to load the resources\r
257      * @param baseName string containing the name of the data package.\r
258      *                    If null the default ICU package name is used.\r
259      * @param locale  specifies the locale for which we want to open the resource.\r
260      *                If null the bundle for default locale is opened.\r
261      * @param loader  the loader to use\r
262      * @return a resource bundle for the given base name and locale\r
263      * @stable ICU 3.8\r
264      */\r
265     public static UResourceBundle getBundleInstance(String baseName, ULocale locale, \r
266                                                     ClassLoader loader) {\r
267         if (baseName == null) {\r
268             baseName = ICUResourceBundle.ICU_BASE_NAME;\r
269         }\r
270         if (locale == null) {\r
271             locale = ULocale.getDefault();\r
272         }\r
273         return getBundleInstance(baseName, locale.toString(), loader, false);\r
274     }\r
275 \r
276     /**\r
277      * {@icu} Returns the RFC 3066 conformant locale id of this resource bundle.\r
278      * This method can be used after a call to getBundleInstance() to\r
279      * determine whether the resource bundle returned really\r
280      * corresponds to the requested locale or is a fallback.\r
281      *\r
282      * @return the locale of this resource bundle\r
283      * @stable ICU 3.0\r
284      */\r
285     public abstract ULocale getULocale();\r
286 \r
287     /**\r
288      * {@icu} Returns the localeID\r
289      * @return The string representation of the localeID\r
290      * @stable ICU 3.0\r
291      */\r
292     protected abstract String getLocaleID();\r
293 \r
294     /**\r
295      * {@icu} Returns the base name of the resource bundle\r
296      * @return The string representation of the base name\r
297      * @stable ICU 3.0\r
298      */\r
299     protected abstract String getBaseName();\r
300 \r
301     /**\r
302      * {@icu} Returns the parent bundle\r
303      * @return The parent bundle\r
304      * @stable ICU 3.0\r
305      */\r
306     protected abstract UResourceBundle getParent();\r
307 \r
308 \r
309     /**\r
310      * Returns the locale of this bundle\r
311      * @return the locale of this resource bundle\r
312      * @stable ICU 3.0\r
313      */\r
314     public Locale getLocale(){\r
315         return getULocale().toLocale();\r
316     }\r
317 \r
318     // Cache for ResourceBundle instantiation\r
319     private static ICUCache<ResourceCacheKey, UResourceBundle> BUNDLE_CACHE =\r
320         new SimpleCache<ResourceCacheKey, UResourceBundle>();\r
321 \r
322     /**\r
323      * @internal\r
324      * @deprecated This API is ICU internal only.\r
325      */\r
326     public static void resetBundleCache() {\r
327         /*\r
328          * A HACK!!!!!\r
329          * Currently if a resourcebundle with fallback turned ON is added to the cache\r
330          * and then a getBundleInstance() is called for a bundle with fallback turned OFF\r
331          * it will actually search the cache for any bundle of the same locale\r
332          * regaurdless of fallback status. This method has been created so that if\r
333          * The calling method KNOWS that instances of the other fallback state may be in the\r
334          * cache, the calling method may call this method to clear out the cache.\r
335          *\r
336          */\r
337         //TODO figure a way around this method(see method comment)\r
338         BUNDLE_CACHE = new SimpleCache<ResourceCacheKey, UResourceBundle>();\r
339     }\r
340 \r
341     /**\r
342      * Method used by subclasses to add a resource bundle object to the managed\r
343      * cache.  Works like a putIfAbsent(): If the cache already contains a matching\r
344      * bundle, that one will be retained and returned.\r
345      * @internal\r
346      * @deprecated This API is ICU internal only.\r
347      */\r
348     protected static UResourceBundle addToCache(ClassLoader cl, String fullName,\r
349                                                 ULocale defaultLocale, UResourceBundle b) {\r
350         synchronized(cacheKey){\r
351             cacheKey.setKeyValues(cl, fullName, defaultLocale);\r
352             UResourceBundle cachedBundle = BUNDLE_CACHE.get(cacheKey);\r
353             if (cachedBundle != null) {\r
354                 return cachedBundle;\r
355             }\r
356             BUNDLE_CACHE.put((ResourceCacheKey)cacheKey.clone(), b);\r
357             return b;\r
358         }\r
359     }\r
360 \r
361     /**\r
362      * Method used by sub classes to load a resource bundle object from the managed cache\r
363      * @internal\r
364      * @deprecated This API is ICU internal only.\r
365      */\r
366     protected static UResourceBundle loadFromCache(ClassLoader cl, String fullName, \r
367                                                    ULocale defaultLocale){\r
368         synchronized(cacheKey){\r
369             cacheKey.setKeyValues(cl, fullName, defaultLocale);\r
370             return BUNDLE_CACHE.get(cacheKey);\r
371         }\r
372     }\r
373 \r
374     /**\r
375      * Key used for cached resource bundles.  The key checks\r
376      * the resource name, the class root, and the default\r
377      * locale to determine if the resource is a match to the\r
378      * requested one. The root may be null, but the\r
379      * searchName and the default locale must have a non-null value.\r
380      * Note that the default locale may change over time, and\r
381      * lookup should always be based on the current default\r
382      * locale (if at all).\r
383      */\r
384     private static final class ResourceCacheKey implements Cloneable {\r
385         private SoftReference<ClassLoader> loaderRef;\r
386         private String searchName;\r
387         private ULocale defaultLocale;\r
388         private int hashCodeCache;\r
389         ///CLOVER:OFF\r
390         public boolean equals(Object other) {\r
391             if (this == other) {\r
392                 return true;\r
393             }\r
394             try {\r
395                 final ResourceCacheKey otherEntry = (ResourceCacheKey) other;\r
396                 //quick check to see if they are not equal\r
397                 if (hashCodeCache != otherEntry.hashCodeCache) {\r
398                     return false;\r
399                 }\r
400                 //are the names the same?\r
401                 if (!searchName.equals(otherEntry.searchName)) {\r
402                     return false;\r
403                 }\r
404                 // are the default locales the same?\r
405                 if (defaultLocale == null) {\r
406                     if (otherEntry.defaultLocale != null) {\r
407                         return false;\r
408                     }\r
409                 } else {\r
410                     if (!defaultLocale.equals(otherEntry.defaultLocale)) {\r
411                         return false;\r
412                     }\r
413                 }\r
414                 //are refs (both non-null) or (both null)?\r
415                 if (loaderRef == null) {\r
416                     return otherEntry.loaderRef == null;\r
417                 } else {\r
418                     return (otherEntry.loaderRef != null)\r
419                             && (loaderRef.get() == otherEntry.loaderRef.get());\r
420                 }\r
421             } catch (NullPointerException e) {\r
422                 return false;\r
423             } catch (ClassCastException e) {\r
424                 return false;\r
425             }\r
426         }\r
427 \r
428         public int hashCode() {\r
429             return hashCodeCache;\r
430         }\r
431 \r
432         public Object clone() {\r
433             try {\r
434                 return super.clone();\r
435             } catch (CloneNotSupportedException e) {\r
436                 //this should never happen\r
437                 throw new IllegalStateException();\r
438             }\r
439         }\r
440 \r
441         ///CLOVER:ON\r
442         private synchronized void setKeyValues(ClassLoader root, String searchName, \r
443                                                ULocale defaultLocale) {\r
444             this.searchName = searchName;\r
445             hashCodeCache = searchName.hashCode();\r
446             this.defaultLocale = defaultLocale;\r
447             if (defaultLocale != null) {\r
448                 hashCodeCache ^= defaultLocale.hashCode();\r
449             }\r
450             if (root == null) {\r
451                 this.loaderRef = null;\r
452             } else {\r
453                 loaderRef = new SoftReference<ClassLoader>(root);\r
454                 hashCodeCache ^= root.hashCode();\r
455             }\r
456         }\r
457         /*private void clear() {\r
458             setKeyValues(null, "", null);\r
459         }*/\r
460     }\r
461 \r
462     private static final ResourceCacheKey cacheKey = new ResourceCacheKey();\r
463 \r
464     private static final int ROOT_MISSING = 0;\r
465     private static final int ROOT_ICU = 1;\r
466     private static final int ROOT_JAVA = 2;\r
467 \r
468     private static SoftReference<Map<String, Integer>> ROOT_CACHE;\r
469 \r
470     private static int getRootType(String baseName, ClassLoader root) {\r
471         Map<String, Integer> m = null;\r
472         Integer rootType;\r
473 \r
474         if (ROOT_CACHE != null) {\r
475             m = ROOT_CACHE.get();\r
476         }\r
477 \r
478         if (m == null) {\r
479             m = new HashMap<String, Integer>();\r
480             ROOT_CACHE = new SoftReference<Map<String, Integer>>(m);\r
481         }\r
482 \r
483         rootType = m.get(baseName);\r
484 \r
485         if (rootType == null) {\r
486             String rootLocale = (baseName.indexOf('.')==-1) ? "root" : "";\r
487             int rt = ROOT_MISSING; // value set on success\r
488             try{\r
489                 ICUResourceBundle.getBundleInstance(baseName, rootLocale, root, true);\r
490                 rt = ROOT_ICU;\r
491             }catch(MissingResourceException ex){\r
492                 try{\r
493                     ResourceBundleWrapper.getBundleInstance(baseName, rootLocale, root, true);\r
494                     rt = ROOT_JAVA;\r
495                 }catch(MissingResourceException e){\r
496                     //throw away the exception\r
497                 }\r
498             }\r
499 \r
500             rootType = Integer.valueOf(rt);\r
501             m.put(baseName, rootType);\r
502         }\r
503 \r
504         return rootType.intValue();\r
505     }\r
506 \r
507     private static void setRootType(String baseName, int rootType) {\r
508         Integer rt = Integer.valueOf(rootType);\r
509         Map<String, Integer> m = null;\r
510 \r
511         if (ROOT_CACHE != null) {\r
512             m = ROOT_CACHE.get();\r
513         } else {\r
514             m = new HashMap<String, Integer>();\r
515             ROOT_CACHE = new SoftReference<Map<String, Integer>>(m);\r
516         }\r
517 \r
518         m.put(baseName, rt);\r
519     }\r
520 \r
521     /**\r
522      * {@icu} Loads a new resource bundle for the given base name, locale and class loader.\r
523      * Optionally will disable loading of fallback bundles.\r
524      * @param baseName the base name of the resource bundle, a fully qualified class name\r
525      * @param localeName the locale for which a resource bundle is desired\r
526      * @param root the class object from which to load the resource bundle\r
527      * @param disableFallback disables loading of fallback lookup chain\r
528      * @throws MissingResourceException If no resource bundle for the specified base name\r
529      * can be found\r
530      * @return a resource bundle for the given base name and locale\r
531      * @stable ICU 3.0\r
532      */\r
533     protected static UResourceBundle instantiateBundle(String baseName, String localeName,\r
534                                                        ClassLoader root, boolean disableFallback) {\r
535         UResourceBundle b = null;\r
536         int rootType = getRootType(baseName, root);\r
537 \r
538         ULocale defaultLocale = ULocale.getDefault();\r
539 \r
540         switch (rootType)\r
541         {\r
542         case ROOT_ICU:\r
543             if(disableFallback) {\r
544                 String fullName = ICUResourceBundle.getFullName(baseName, localeName);\r
545                 b = loadFromCache(root, fullName, defaultLocale);\r
546                 if (b == null) {\r
547                     b = ICUResourceBundle.getBundleInstance(baseName, localeName, root, \r
548                                                             disableFallback);\r
549                 }\r
550             } else {\r
551                 b = ICUResourceBundle.getBundleInstance(baseName, localeName, root, \r
552                                                         disableFallback);\r
553             }\r
554 \r
555             return b;\r
556 \r
557         case ROOT_JAVA:\r
558             return ResourceBundleWrapper.getBundleInstance(baseName, localeName, root, \r
559                                                            disableFallback);\r
560 \r
561         default:\r
562             try{\r
563                 b = ICUResourceBundle.getBundleInstance(baseName, localeName, root, \r
564                                                         disableFallback);\r
565                 setRootType(baseName, ROOT_ICU);\r
566             }catch(MissingResourceException ex){\r
567                 b = ResourceBundleWrapper.getBundleInstance(baseName, localeName, root, \r
568                                                             disableFallback);\r
569                 setRootType(baseName, ROOT_JAVA);\r
570             }\r
571             return b;\r
572         }\r
573     }\r
574 \r
575     /**\r
576      * {@icu} Returns a binary data item from a binary resource, as a read-only ByteBuffer.\r
577      *\r
578      * @return a pointer to a chunk of unsigned bytes which live in a memory mapped/DLL\r
579      * file.\r
580      * @see #getIntVector\r
581      * @see #getInt\r
582      * @throws MissingResourceException If no resource bundle can be found.\r
583      * @throws UResourceTypeMismatchException If the resource has a type mismatch.\r
584      * @stable ICU 3.8\r
585      */\r
586     public ByteBuffer getBinary() {\r
587         throw new UResourceTypeMismatchException("");\r
588     }\r
589 \r
590     /**\r
591      * Returns a string from a string resource type\r
592      *\r
593      * @return a string\r
594      * @see #getBinary()\r
595      * @see #getIntVector\r
596      * @see #getInt\r
597      * @throws MissingResourceException If resource bundle is missing.\r
598      * @throws UResourceTypeMismatchException If resource bundle has a type mismatch.\r
599      * @stable ICU 3.8\r
600      */\r
601     public String getString() {\r
602         throw new UResourceTypeMismatchException("");\r
603     }\r
604 \r
605     /**\r
606      * Returns a string array from a array resource type\r
607      *\r
608      * @return a string\r
609      * @see #getString()\r
610      * @see #getIntVector\r
611      * @throws MissingResourceException If resource bundle is missing.\r
612      * @throws UResourceTypeMismatchException If resource bundle has a type mismatch.\r
613      * @stable ICU 3.8\r
614      */\r
615     public String[] getStringArray() {\r
616         throw new UResourceTypeMismatchException("");\r
617     }\r
618 \r
619     /**\r
620      * {@icu} Returns a binary data from a binary resource, as a byte array with a copy\r
621      * of the bytes from the resource bundle.\r
622      *\r
623      * @param ba  The byte array to write the bytes to. A null variable is OK.\r
624      * @return an array of bytes containing the binary data from the resource.\r
625      * @see #getIntVector\r
626      * @see #getInt\r
627      * @throws MissingResourceException If resource bundle is missing.\r
628      * @throws UResourceTypeMismatchException If resource bundle has a type mismatch.\r
629      * @stable ICU 3.8\r
630      */\r
631     public byte[] getBinary(byte[] ba) {\r
632         throw new UResourceTypeMismatchException("");\r
633     }\r
634 \r
635     /**\r
636      * {@icu} Returns a 32 bit integer array from a resource.\r
637      *\r
638      * @return a pointer to a chunk of unsigned bytes which live in a memory mapped/DLL file.\r
639      * @see #getBinary()\r
640      * @see #getInt\r
641      * @throws MissingResourceException If resource bundle is missing.\r
642      * @throws UResourceTypeMismatchException If resource bundle has a type mismatch.\r
643      * @stable ICU 3.8\r
644      */\r
645     public int[] getIntVector() {\r
646         throw new UResourceTypeMismatchException("");\r
647     }\r
648 \r
649     /**\r
650      * {@icu} Returns a signed integer from a resource.\r
651      *\r
652      * @return an integer value\r
653      * @see #getIntVector\r
654      * @see #getBinary()\r
655      * @throws MissingResourceException If resource bundle is missing.\r
656      * @throws UResourceTypeMismatchException If resource bundle type mismatch.\r
657      * @stable ICU 3.8\r
658      */\r
659     public int getInt() {\r
660         throw new UResourceTypeMismatchException("");\r
661     }\r
662 \r
663     /**\r
664      * {@icu} Returns a unsigned integer from a resource.\r
665      * This integer is originally 28 bit and the sign gets propagated.\r
666      *\r
667      * @return an integer value\r
668      * @see #getIntVector\r
669      * @see #getBinary()\r
670      * @throws MissingResourceException If resource bundle is missing.\r
671      * @throws UResourceTypeMismatchException If resource bundle type mismatch.\r
672      * @stable ICU 3.8\r
673      */\r
674     public int getUInt() {\r
675         throw new UResourceTypeMismatchException("");\r
676     }\r
677 \r
678     /**\r
679      * {@icu} Returns a resource in a given resource that has a given key.\r
680      *\r
681      * @param aKey               a key associated with the wanted resource\r
682      * @return                  a resource bundle object representing the resource\r
683      * @throws MissingResourceException If resource bundle is missing.\r
684      * @stable ICU 3.8\r
685      */\r
686     public UResourceBundle get(String aKey) {\r
687         UResourceBundle obj = findTopLevel(aKey);\r
688         if (obj == null) {\r
689             String fullName = ICUResourceBundle.getFullName(getBaseName(), getLocaleID());\r
690             throw new MissingResourceException(\r
691                     "Can't find resource for bundle " + fullName + ", key "\r
692                     + aKey, this.getClass().getName(), aKey);\r
693         }\r
694         return obj;\r
695     }\r
696 \r
697     /**\r
698      * Returns a resource in a given resource that has a given key, or null if the\r
699      * resource is not found.\r
700      *\r
701      * @param aKey the key associated with the wanted resource\r
702      * @return the resource, or null\r
703      * @see #get(String)\r
704      * @internal\r
705      * @deprecated This API is ICU internal only.\r
706      */\r
707     protected UResourceBundle findTopLevel(String aKey) {\r
708         // NOTE: this only works for top-level resources.  For resources at lower\r
709         // levels, it fails when you fall back to the parent, since you're now\r
710         // looking at root resources, not at the corresponding nested resource.\r
711         for (UResourceBundle res = this; res != null; res = res.getParent()) {\r
712             UResourceBundle obj = res.handleGet(aKey, null, this);\r
713             if (obj != null) {\r
714                 ((ICUResourceBundle) obj).setLoadingStatus(getLocaleID());\r
715                 return obj;\r
716             }\r
717         }\r
718         return null;\r
719     }\r
720 \r
721     /**\r
722      * Returns the string in a given resource at the specified index.\r
723      *\r
724      * @param index an index to the wanted string.\r
725      * @return a string which lives in the resource.\r
726      * @throws IndexOutOfBoundsException If the index value is out of bounds of accepted values.\r
727      * @throws UResourceTypeMismatchException If resource bundle type mismatch.\r
728      * @stable ICU 3.8\r
729      */\r
730     public String getString(int index) {\r
731         ICUResourceBundle temp = (ICUResourceBundle)get(index);\r
732         if (temp.getType() == STRING) {\r
733             return temp.getString();\r
734         }\r
735         throw new UResourceTypeMismatchException("");\r
736     }\r
737 \r
738     /**\r
739      * {@icu} Returns the resource in a given resource at the specified index.\r
740      *\r
741      * @param index an index to the wanted resource.\r
742      * @return the sub resource UResourceBundle object\r
743      * @throws IndexOutOfBoundsException If the index value is out of bounds of accepted values.\r
744      * @throws MissingResourceException If the resource bundle is missing.\r
745      * @stable ICU 3.8\r
746      */\r
747     public UResourceBundle get(int index) {\r
748         UResourceBundle obj = handleGet(index, null, this);\r
749         if (obj == null) {\r
750             obj = (ICUResourceBundle) getParent();\r
751             if (obj != null) {\r
752                 obj = obj.get(index);\r
753             }\r
754             if (obj == null)\r
755                 throw new MissingResourceException(\r
756                         "Can't find resource for bundle "\r
757                                 + this.getClass().getName() + ", key "\r
758                                 + getKey(), this.getClass().getName(), getKey());\r
759         }\r
760         ((ICUResourceBundle)obj).setLoadingStatus(getLocaleID());\r
761         return obj;\r
762     }\r
763 \r
764     /**\r
765      * Returns a resource in a given resource that has a given index, or null if the\r
766      * resource is not found.\r
767      *\r
768      * @param index the index of the resource\r
769      * @return the resource, or null\r
770      * @see #get(int)\r
771      * @internal\r
772      * @deprecated This API is ICU internal only.\r
773      */\r
774     protected UResourceBundle findTopLevel(int index) {\r
775         // NOTE: this _barely_ works for top-level resources.  For resources at lower\r
776         // levels, it fails when you fall back to the parent, since you're now\r
777         // looking at root resources, not at the corresponding nested resource.\r
778         // Not only that, but unless the indices correspond 1-to-1, the index will\r
779         // lose meaning.  Essentially this only works if the child resource arrays\r
780         // are prefixes of their parent arrays.\r
781         for (UResourceBundle res = this; res != null; res = res.getParent()) {\r
782             UResourceBundle obj = res.handleGet(index, null, this);\r
783             if (obj != null) {\r
784                 ((ICUResourceBundle) obj).setLoadingStatus(getLocaleID());\r
785                 return obj;\r
786             }\r
787         }\r
788         return null;\r
789     }\r
790 \r
791     /**\r
792      * Returns the keys in this bundle as an enumeration\r
793      * @return an enumeration containing key strings,\r
794      *         which is empty if this is not a bundle or a table resource\r
795      * @stable ICU 3.8\r
796      */\r
797     public Enumeration<String> getKeys() {\r
798         return Collections.enumeration(keySet());\r
799     }\r
800 \r
801     /**\r
802      * Returns a Set of all keys contained in this ResourceBundle and its parent bundles.\r
803      * @return a Set of all keys contained in this ResourceBundle and its parent bundles,\r
804      *         which is empty if this is not a bundle or a table resource\r
805      * @internal\r
806      * @deprecated This API is ICU internal only.\r
807      */\r
808     public Set<String> keySet() {\r
809         if(keys == null) {\r
810             if(isTopLevelResource()) {\r
811                 TreeSet<String> newKeySet;\r
812                 if(parent == null) {\r
813                     newKeySet = new TreeSet<String>();\r
814                 } else if(parent instanceof UResourceBundle) {\r
815                     newKeySet = new TreeSet<String>(((UResourceBundle)parent).keySet());\r
816                 } else {\r
817                     // TODO: Java 6 ResourceBundle has keySet(); use it when we upgrade to Java 6\r
818                     // and remove this else branch.\r
819                     newKeySet = new TreeSet<String>();\r
820                     Enumeration<String> parentKeys = parent.getKeys();\r
821                     while(parentKeys.hasMoreElements()) {\r
822                         newKeySet.add(parentKeys.nextElement());\r
823                     }\r
824                 }\r
825                 newKeySet.addAll(handleKeySet());\r
826                 keys = Collections.unmodifiableSet(newKeySet);\r
827             } else {\r
828                 return handleKeySet();\r
829             }\r
830         }\r
831         return keys;\r
832     }\r
833 \r
834     private Set<String> keys = null;\r
835     /**\r
836      * Returns a Set of the keys contained <i>only</i> in this ResourceBundle.\r
837      * This does not include further keys from parent bundles.\r
838      * @return a Set of the keys contained only in this ResourceBundle,\r
839      *         which is empty if this is not a bundle or a table resource\r
840      * @internal\r
841      * @deprecated This API is ICU internal only.\r
842      */\r
843     protected Set<String> handleKeySet() {\r
844         return Collections.emptySet();\r
845     }\r
846 \r
847     /**\r
848      * {@icu} Returns the size of a resource. Size for scalar types is always 1, and for\r
849      * vector/table types is the number of child resources.\r
850      * \r
851      * <br><b>Note:</b> Integer array is treated as a scalar type. There are no APIs to\r
852      * access individual members of an integer array. It is always returned as a whole.\r
853      * @return number of resources in a given resource.\r
854      * @stable ICU 3.8\r
855      */\r
856     public int getSize() {\r
857         return 1;\r
858     }\r
859 \r
860     /**\r
861      * {@icu} Returns the type of a resource.\r
862      * Available types are {@link #INT INT}, {@link #ARRAY ARRAY},\r
863      * {@link #BINARY BINARY}, {@link #INT_VECTOR INT_VECTOR},\r
864      * {@link #STRING STRING}, {@link #TABLE TABLE}.\r
865      *\r
866      * @return type of the given resource.\r
867      * @stable ICU 3.8\r
868      */\r
869     public int getType() {\r
870         return NONE;\r
871     }\r
872 \r
873     /**\r
874      * {@icu} Return the version number associated with this UResourceBundle as an\r
875      * VersionInfo object.\r
876      * @return VersionInfo object containing the version of the bundle\r
877      * @stable ICU 3.8\r
878      */\r
879     public VersionInfo getVersion() {\r
880         return null;\r
881     }\r
882 \r
883     /**\r
884      * {@icu} Returns the iterator which iterates over this\r
885      * resource bundle\r
886      * @return UResourceBundleIterator that iterates over the resources in the bundle\r
887      * @stable ICU 3.8\r
888      */\r
889     public UResourceBundleIterator getIterator() {\r
890         return new UResourceBundleIterator(this);\r
891     }\r
892 \r
893     /**\r
894      * {@icu} Returns the key associated with a given resource. Not all the resources have\r
895      * a key - only those that are members of a table.\r
896      * @return a key associated to this resource, or null if it doesn't have a key\r
897      * @stable ICU 3.8\r
898      */\r
899     public String getKey() {\r
900         return null;\r
901     }\r
902 \r
903     /**\r
904      * {@icu} Resource type constant for "no resource".\r
905      * @stable ICU 3.8\r
906      */\r
907     public static final int NONE = -1;\r
908 \r
909     /**\r
910      * {@icu} Resource type constant for strings.\r
911      * @stable ICU 3.8\r
912      */\r
913     public static final int STRING = 0;\r
914 \r
915     /**\r
916      * {@icu} Resource type constant for binary data.\r
917      * @stable ICU 3.8\r
918      */\r
919     public static final int BINARY = 1;\r
920 \r
921     /**\r
922      * {@icu} Resource type constant for tables of key-value pairs.\r
923      * @stable ICU 3.8\r
924      */\r
925     public static final int TABLE = 2;\r
926 \r
927     /**\r
928      * {@icu} Resource type constant for a single 28-bit integer, interpreted as\r
929      * signed or unsigned by the getInt() function.\r
930      * @see #getInt\r
931      * @stable ICU 3.8\r
932      */\r
933     public static final int INT = 7;\r
934 \r
935     /**\r
936      * {@icu} Resource type constant for arrays of resources.\r
937      * @stable ICU 3.8\r
938      */\r
939     public static final int ARRAY = 8;\r
940 \r
941     /**\r
942      * Resource type constant for vectors of 32-bit integers.\r
943      * @see #getIntVector\r
944      * @stable ICU 3.8\r
945      */\r
946     public static final int INT_VECTOR = 14;\r
947 \r
948     //====== protected members ==============\r
949 \r
950     /**\r
951      * {@icu} Actual worker method for fetching a resource based on the given key.\r
952      * Sub classes must override this method if they support resources with keys.\r
953      * @param aKey the key string of the resource to be fetched\r
954      * @param table hashtable object to hold references of resources already seen\r
955      * @param requested the original resource bundle object on which the get method was invoked.\r
956      *                  The requested bundle and the bundle on which this method is invoked\r
957      *                  are the same, except in the cases where aliases are involved.\r
958      * @return UResourceBundle a resource associated with the key\r
959      * @stable ICU 3.8\r
960      */\r
961     protected UResourceBundle handleGet(String aKey, HashMap<String, String> table, \r
962                                         UResourceBundle requested) {\r
963         return null;\r
964     }\r
965 \r
966     /**\r
967      * {@icu} Actual worker method for fetching a resource based on the given index.\r
968      * Sub classes must override this method if they support arrays of resources.\r
969      * @param index the index of the resource to be fetched\r
970      * @param table hashtable object to hold references of resources already seen\r
971      * @param requested the original resource bundle object on which the get method was invoked.\r
972      *                  The requested bundle and the bundle on which this method is invoked\r
973      *                  are the same, except in the cases where aliases are involved.\r
974      * @return UResourceBundle a resource associated with the index\r
975      * @stable ICU 3.8\r
976      */\r
977     protected UResourceBundle handleGet(int index, HashMap<String, String> table, \r
978                                         UResourceBundle requested) {\r
979         return null;\r
980     }\r
981 \r
982     /**\r
983      * {@icu} Actual worker method for fetching the array of strings in a resource.\r
984      * Sub classes must override this method if they support arrays of strings.\r
985      * @return String[] An array of strings containing strings\r
986      * @stable ICU 3.8\r
987      */\r
988     protected String[] handleGetStringArray() {\r
989         return null;\r
990     }\r
991 \r
992     /**\r
993      * {@icu} Actual worker method for fetching the keys of resources contained in the resource.\r
994      * Sub classes must override this method if they support keys and associated resources.\r
995      *\r
996      * @return Enumeration An enumeration of all the keys in this resource.\r
997      * @stable ICU 3.8\r
998      */\r
999     protected Enumeration<String> handleGetKeys(){\r
1000         return null;\r
1001     }\r
1002 \r
1003     /**\r
1004      * {@inheritDoc}\r
1005      * @stable ICU 3.8\r
1006      */\r
1007     // this method is declared in ResourceBundle class\r
1008     // so cannot change the signature\r
1009     // Override this method\r
1010     protected Object handleGetObject(String aKey) {\r
1011         return handleGetObjectImpl(aKey, this);\r
1012     }\r
1013 \r
1014     /**\r
1015      * Override the superclass method\r
1016      */\r
1017     // To facilitate XPath style aliases we need a way to pass the reference\r
1018     // to requested locale. The only way I could figure out is to implement\r
1019     // the look up logic here. This has a disadvantage that if the client\r
1020     // loads an ICUResourceBundle, calls ResourceBundle.getObject method\r
1021     // with a key that does not exist in the bundle then the lookup is\r
1022     // done twice before throwing a MissingResourceExpection.\r
1023     private Object handleGetObjectImpl(String aKey, UResourceBundle requested) {\r
1024         Object obj = resolveObject(aKey, requested);\r
1025         if (obj == null) {\r
1026             UResourceBundle parentBundle = getParent();\r
1027             if (parentBundle != null) {\r
1028                 obj = parentBundle.handleGetObjectImpl(aKey, requested);\r
1029             }\r
1030             if (obj == null)\r
1031                 throw new MissingResourceException(\r
1032                     "Can't find resource for bundle "\r
1033                     + this.getClass().getName() + ", key " + aKey,\r
1034                     this.getClass().getName(), aKey);\r
1035         }\r
1036         return obj;\r
1037     }\r
1038 \r
1039     // Routine for figuring out the type of object to be returned\r
1040     // string or string array\r
1041     private Object resolveObject(String aKey, UResourceBundle requested) {\r
1042         if (getType() == STRING) {\r
1043             return getString();\r
1044         }\r
1045         UResourceBundle obj = handleGet(aKey, null, requested);\r
1046         if (obj != null) {\r
1047             if (obj.getType() == STRING) {\r
1048                 return obj.getString();\r
1049             }\r
1050             try {\r
1051                 if (obj.getType() == ARRAY) {\r
1052                     return obj.handleGetStringArray();\r
1053                 }\r
1054             } catch (UResourceTypeMismatchException ex) {\r
1055                 return obj;\r
1056             }\r
1057         }\r
1058         return obj;\r
1059     }\r
1060 \r
1061     /**\r
1062      * This method is for setting the loading status of the resource.\r
1063      * The status is analogous to the warning status in ICU4C.\r
1064      * @internal\r
1065      * @deprecated This API is ICU internal only.\r
1066      */\r
1067     protected abstract void setLoadingStatus(int newStatus);\r
1068 \r
1069     /**\r
1070      * Is this a top-level resource, that is, a whole bundle?\r
1071      * @return true if this is a top-level resource\r
1072      * @internal\r
1073      * @deprecated This API is ICU internal only.\r
1074      */\r
1075     protected boolean isTopLevelResource() {\r
1076         return true;\r
1077     }\r
1078 }\r