1 /* GENERATED SOURCE. DO NOT MODIFY. */
2 // © 2016 and later: Unicode, Inc. and others.
3 // License & terms of use: http://www.unicode.org/copyright.html#License
4 /*
5  *******************************************************************************
6  * Copyright (C) 2004-2016, International Business Machines Corporation and
7  * others. All Rights Reserved.
8  *******************************************************************************
9  */
10 
11 package android.icu.util;
12 
13 import java.nio.ByteBuffer;
14 import java.util.Collections;
15 import java.util.Enumeration;
16 import java.util.HashMap;
17 import java.util.Locale;
18 import java.util.Map;
19 import java.util.MissingResourceException;
20 import java.util.ResourceBundle;
21 import java.util.Set;
22 import java.util.TreeSet;
23 import java.util.concurrent.ConcurrentHashMap;
24 
25 import android.icu.impl.ICUData;
26 import android.icu.impl.ICUResourceBundle;
27 import android.icu.impl.ICUResourceBundleReader;
28 import android.icu.impl.ResourceBundleWrapper;
29 
30 /**
31  * <strong>[icu enhancement]</strong> ICU's replacement for {@link java.util.ResourceBundle}.&nbsp;Methods, fields, and other functionality specific to ICU are labeled '<strong>[icu]</strong>'.
32  *
33  * <p>A class representing a collection of resource information pertaining to a given
34  * locale. A resource bundle provides a way of accessing locale- specific information in a
35  * data file. You create a resource bundle that manages the resources for a given locale
36  * and then ask it for individual resources.
37  *
38  * <p>In ResourceBundle, an object is created and the sub-items are fetched using the
39  * getString and getObject methods.  In UResourceBundle, each individual element of a
40  * resource is a resource by itself.
41  *
42  * <p>Resource bundles in ICU are currently defined using text files that conform to the
43  * following <a
44  * href="http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt">BNF
45  * definition</a>.  More on resource bundle concepts and syntax can be found in the <a
46  * href="http://www.icu-project.org/userguide/ResourceManagement.html">Users Guide</a>.
47  *
48  * <p>The packaging of ICU *.res files can be of two types
49  * ICU4C:
50  * <pre>
51  *       root.res
52  *         |
53  *      --------
54  *     |        |
55  *   fr.res  en.res
56  *     |
57  *   --------
58  *  |        |
59  * fr_CA.res fr_FR.res
60  * </pre>
61  * JAVA/JDK:
62  * <pre>
63  *    LocaleElements.res
64  *         |
65  *      -------------------
66  *     |                   |
67  * LocaleElements_fr.res  LocaleElements_en.res
68  *     |
69  *   ---------------------------
70  *  |                            |
71  * LocaleElements_fr_CA.res   LocaleElements_fr_FR.res
72  * </pre>
73  *
74  * Depending on the organization of your resources, the syntax to getBundleInstance will
75  * change.  To open ICU style organization use:
76  *
77  * <pre>
78  *      UResourceBundle bundle =
79  *          UResourceBundle.getBundleInstance("com/mycompany/resources",
80  *                                            "en_US", myClassLoader);
81  * </pre>
82  * To open Java/JDK style organization use:
83  * <pre>
84  *      UResourceBundle bundle =
85  *          UResourceBundle.getBundleInstance("com.mycompany.resources.LocaleElements",
86  *                                            "en_US", myClassLoader);
87  * </pre>
88  *
89  * <p>Note: Please use pass a class loader for loading non-ICU resources. Java security does not
90  * allow loading of resources across jar files. You must provide your class loader
91  * to load the resources
92 
93  * @author ram
94  * @hide Only a subset of ICU is exposed in Android
95  */
96 public abstract class UResourceBundle extends ResourceBundle {
97 
98 
99     /**
100      * <strong>[icu]</strong> Creates a resource bundle using the specified base name and locale.
101      * ICU_DATA_CLASS is used as the default root.
102      * @param baseName string containing the name of the data package.
103      *                    If null the default ICU package name is used.
104      * @param localeName the locale for which a resource bundle is desired
105      * @throws MissingResourceException If no resource bundle for the specified base name
106      * can be found
107      * @return a resource bundle for the given base name and locale
108      */
getBundleInstance(String baseName, String localeName)109     public static UResourceBundle getBundleInstance(String baseName, String localeName){
110         return getBundleInstance(baseName, localeName, ICUResourceBundle.ICU_DATA_CLASS_LOADER,
111                                  false);
112     }
113 
114     /**
115      * <strong>[icu]</strong> Creates a resource bundle using the specified base name, locale, and class root.
116      *
117      * @param baseName string containing the name of the data package.
118      *                    If null the default ICU package name is used.
119      * @param localeName the locale for which a resource bundle is desired
120      * @param root the class object from which to load the resource bundle
121      * @throws MissingResourceException If no resource bundle for the specified base name
122      * can be found
123      * @return a resource bundle for the given base name and locale
124      */
getBundleInstance(String baseName, String localeName, ClassLoader root)125     public static UResourceBundle getBundleInstance(String baseName, String localeName,
126                                                     ClassLoader root){
127         return getBundleInstance(baseName, localeName, root, false);
128     }
129 
130     /**
131      * <strong>[icu]</strong> Creates a resource bundle using the specified base name, locale, and class
132      * root.
133      *
134      * @param baseName string containing the name of the data package.
135      *                    If null the default ICU package name is used.
136      * @param localeName the locale for which a resource bundle is desired
137      * @param root the class object from which to load the resource bundle
138      * @param disableFallback Option to disable locale inheritence.
139      *                          If true the fallback chain will not be built.
140      * @throws MissingResourceException
141      *     if no resource bundle for the specified base name can be found
142      * @return a resource bundle for the given base name and locale
143      *
144      */
getBundleInstance(String baseName, String localeName, ClassLoader root, boolean disableFallback)145     protected static UResourceBundle getBundleInstance(String baseName, String localeName,
146                                                        ClassLoader root, boolean disableFallback) {
147         return instantiateBundle(baseName, localeName, root, disableFallback);
148     }
149 
150     /**
151      * <strong>[icu]</strong> Sole constructor.  (For invocation by subclass constructors, typically
152      * implicit.)  This is public for compatibility with Java, whose compiler
153      * will generate public default constructors for an abstract class.
154      */
UResourceBundle()155     public UResourceBundle() {
156     }
157 
158     /**
159      * <strong>[icu]</strong> Creates a UResourceBundle for the locale specified, from which users can extract
160      * resources by using their corresponding keys.
161      * @param locale  specifies the locale for which we want to open the resource.
162      *                If null the bundle for default locale is opened.
163      * @return a resource bundle for the given locale
164      */
getBundleInstance(ULocale locale)165     public static UResourceBundle getBundleInstance(ULocale locale) {
166         if (locale==null) {
167             locale = ULocale.getDefault();
168         }
169         return getBundleInstance(ICUData.ICU_BASE_NAME, locale.getBaseName(),
170                                  ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);
171     }
172 
173     /**
174      * <strong>[icu]</strong> Creates a UResourceBundle for the default locale and specified base name,
175      * from which users can extract resources by using their corresponding keys.
176      * @param baseName string containing the name of the data package.
177      *                    If null the default ICU package name is used.
178      * @return a resource bundle for the given base name and default locale
179      */
getBundleInstance(String baseName)180     public static UResourceBundle getBundleInstance(String baseName) {
181         if (baseName == null) {
182             baseName = ICUData.ICU_BASE_NAME;
183         }
184         ULocale uloc = ULocale.getDefault();
185         return getBundleInstance(baseName, uloc.getBaseName(), ICUResourceBundle.ICU_DATA_CLASS_LOADER,
186                                  false);
187     }
188 
189     /**
190      * <strong>[icu]</strong> Creates a UResourceBundle for the specified locale and specified base name,
191      * from which users can extract resources by using their corresponding keys.
192      * @param baseName string containing the name of the data package.
193      *                    If null the default ICU package name is used.
194      * @param locale  specifies the locale for which we want to open the resource.
195      *                If null the bundle for default locale is opened.
196      * @return a resource bundle for the given base name and locale
197      */
198 
getBundleInstance(String baseName, Locale locale)199     public static UResourceBundle getBundleInstance(String baseName, Locale locale) {
200         if (baseName == null) {
201             baseName = ICUData.ICU_BASE_NAME;
202         }
203         ULocale uloc = locale == null ? ULocale.getDefault() : ULocale.forLocale(locale);
204 
205         return getBundleInstance(baseName, uloc.getBaseName(),
206                                  ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);
207     }
208 
209     /**
210      * <strong>[icu]</strong> Creates a UResourceBundle, from which users can extract resources by using
211      * their corresponding keys.
212      * @param baseName string containing the name of the data package.
213      *                    If null the default ICU package name is used.
214      * @param locale  specifies the locale for which we want to open the resource.
215      *                If null the bundle for default locale is opened.
216      * @return a resource bundle for the given base name and locale
217      */
getBundleInstance(String baseName, ULocale locale)218     public static UResourceBundle getBundleInstance(String baseName, ULocale locale) {
219         if (baseName == null) {
220             baseName = ICUData.ICU_BASE_NAME;
221         }
222         if (locale == null) {
223             locale = ULocale.getDefault();
224         }
225         return getBundleInstance(baseName, locale.getBaseName(),
226                                  ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);
227     }
228 
229     /**
230      * <strong>[icu]</strong> Creates a UResourceBundle for the specified locale and specified base name,
231      * from which users can extract resources by using their corresponding keys.
232      * @param baseName string containing the name of the data package.
233      *                    If null the default ICU package name is used.
234      * @param locale  specifies the locale for which we want to open the resource.
235      *                If null the bundle for default locale is opened.
236      * @param loader  the loader to use
237      * @return a resource bundle for the given base name and locale
238      */
getBundleInstance(String baseName, Locale locale, ClassLoader loader)239     public static UResourceBundle getBundleInstance(String baseName, Locale locale,
240                                                     ClassLoader loader) {
241         if (baseName == null) {
242             baseName = ICUData.ICU_BASE_NAME;
243         }
244         ULocale uloc = locale == null ? ULocale.getDefault() : ULocale.forLocale(locale);
245         return getBundleInstance(baseName, uloc.getBaseName(), loader, false);
246     }
247 
248     /**
249      * <strong>[icu]</strong> Creates a UResourceBundle, from which users can extract resources by using
250      * their corresponding keys.<br><br>
251      * Note: Please use this API for loading non-ICU resources. Java security does not
252      * allow loading of resources across jar files. You must provide your class loader
253      * to load the resources
254      * @param baseName string containing the name of the data package.
255      *                    If null the default ICU package name is used.
256      * @param locale  specifies the locale for which we want to open the resource.
257      *                If null the bundle for default locale is opened.
258      * @param loader  the loader to use
259      * @return a resource bundle for the given base name and locale
260      */
getBundleInstance(String baseName, ULocale locale, ClassLoader loader)261     public static UResourceBundle getBundleInstance(String baseName, ULocale locale,
262                                                     ClassLoader loader) {
263         if (baseName == null) {
264             baseName = ICUData.ICU_BASE_NAME;
265         }
266         if (locale == null) {
267             locale = ULocale.getDefault();
268         }
269         return getBundleInstance(baseName, locale.getBaseName(), loader, false);
270     }
271 
272     /**
273      * <strong>[icu]</strong> Returns the RFC 3066 conformant locale id of this resource bundle.
274      * This method can be used after a call to getBundleInstance() to
275      * determine whether the resource bundle returned really
276      * corresponds to the requested locale or is a fallback.
277      *
278      * @return the locale of this resource bundle
279      */
getULocale()280     public abstract ULocale getULocale();
281 
282     /**
283      * <strong>[icu]</strong> Returns the localeID
284      * @return The string representation of the localeID
285      */
getLocaleID()286     protected abstract String getLocaleID();
287 
288     /**
289      * <strong>[icu]</strong> Returns the base name of the resource bundle
290      * @return The string representation of the base name
291      */
getBaseName()292     protected abstract String getBaseName();
293 
294     /**
295      * <strong>[icu]</strong> Returns the parent bundle
296      * @return The parent bundle
297      */
getParent()298     protected abstract UResourceBundle getParent();
299 
300 
301     /**
302      * Returns the locale of this bundle
303      * @return the locale of this resource bundle
304      */
305     @Override
getLocale()306     public Locale getLocale(){
307         return getULocale().toLocale();
308     }
309 
310     private enum RootType { MISSING, ICU, JAVA }
311 
312     private static Map<String, RootType> ROOT_CACHE = new ConcurrentHashMap<String, RootType>();
313 
getRootType(String baseName, ClassLoader root)314     private static RootType getRootType(String baseName, ClassLoader root) {
315         RootType rootType = ROOT_CACHE.get(baseName);
316 
317         if (rootType == null) {
318             String rootLocale = (baseName.indexOf('.')==-1) ? "root" : "";
319             try{
320                 ICUResourceBundle.getBundleInstance(baseName, rootLocale, root, true);
321                 rootType = RootType.ICU;
322             }catch(MissingResourceException ex){
323                 try{
324                     ResourceBundleWrapper.getBundleInstance(baseName, rootLocale, root, true);
325                     rootType = RootType.JAVA;
326                 }catch(MissingResourceException e){
327                     //throw away the exception
328                     rootType = RootType.MISSING;
329                 }
330             }
331 
332             ROOT_CACHE.put(baseName, rootType);
333         }
334 
335         return rootType;
336     }
337 
setRootType(String baseName, RootType rootType)338     private static void setRootType(String baseName, RootType rootType) {
339         ROOT_CACHE.put(baseName, rootType);
340     }
341 
342     /**
343      * <strong>[icu]</strong> Loads a new resource bundle for the given base name, locale and class loader.
344      * Optionally will disable loading of fallback bundles.
345      * @param baseName string containing the name of the data package.
346      *                    If null the default ICU package name is used.
347      * @param localeName the locale for which a resource bundle is desired
348      * @param root the class object from which to load the resource bundle
349      * @param disableFallback disables loading of fallback lookup chain
350      * @throws MissingResourceException If no resource bundle for the specified base name
351      * can be found
352      * @return a resource bundle for the given base name and locale
353      */
instantiateBundle(String baseName, String localeName, ClassLoader root, boolean disableFallback)354     protected static UResourceBundle instantiateBundle(String baseName, String localeName,
355                                                        ClassLoader root, boolean disableFallback) {
356         RootType rootType = getRootType(baseName, root);
357 
358         switch (rootType) {
359         case ICU:
360             return ICUResourceBundle.getBundleInstance(baseName, localeName, root, disableFallback);
361 
362         case JAVA:
363             return ResourceBundleWrapper.getBundleInstance(baseName, localeName, root,
364                                                            disableFallback);
365 
366         case MISSING:
367         default:
368             UResourceBundle b;
369             try{
370                 b = ICUResourceBundle.getBundleInstance(baseName, localeName, root,
371                                                         disableFallback);
372                 setRootType(baseName, RootType.ICU);
373             }catch(MissingResourceException ex){
374                 b = ResourceBundleWrapper.getBundleInstance(baseName, localeName, root,
375                                                             disableFallback);
376                 setRootType(baseName, RootType.JAVA);
377             }
378             return b;
379         }
380     }
381 
382     /**
383      * <strong>[icu]</strong> Returns a binary data item from a binary resource, as a read-only ByteBuffer.
384      *
385      * @return a pointer to a chunk of unsigned bytes which live in a memory mapped/DLL
386      * file.
387      * @see #getIntVector
388      * @see #getInt
389      * @throws MissingResourceException If no resource bundle can be found.
390      * @throws UResourceTypeMismatchException If the resource has a type mismatch.
391      */
getBinary()392     public ByteBuffer getBinary() {
393         throw new UResourceTypeMismatchException("");
394     }
395 
396     /**
397      * Returns a string from a string resource type
398      *
399      * @return a string
400      * @see #getBinary()
401      * @see #getIntVector
402      * @see #getInt
403      * @throws MissingResourceException If resource bundle is missing.
404      * @throws UResourceTypeMismatchException If resource bundle has a type mismatch.
405      */
getString()406     public String getString() {
407         throw new UResourceTypeMismatchException("");
408     }
409 
410     /**
411      * Returns a string array from a array resource type
412      *
413      * @return a string
414      * @see #getString()
415      * @see #getIntVector
416      * @throws MissingResourceException If resource bundle is missing.
417      * @throws UResourceTypeMismatchException If resource bundle has a type mismatch.
418      */
getStringArray()419     public String[] getStringArray() {
420         throw new UResourceTypeMismatchException("");
421     }
422 
423     /**
424      * <strong>[icu]</strong> Returns a binary data from a binary resource, as a byte array with a copy
425      * of the bytes from the resource bundle.
426      *
427      * @param ba  The byte array to write the bytes to. A null variable is OK.
428      * @return an array of bytes containing the binary data from the resource.
429      * @see #getIntVector
430      * @see #getInt
431      * @throws MissingResourceException If resource bundle is missing.
432      * @throws UResourceTypeMismatchException If resource bundle has a type mismatch.
433      */
getBinary(byte[] ba)434     public byte[] getBinary(byte[] ba) {
435         throw new UResourceTypeMismatchException("");
436     }
437 
438     /**
439      * <strong>[icu]</strong> Returns a 32 bit integer array from a resource.
440      *
441      * @return a pointer to a chunk of unsigned bytes which live in a memory mapped/DLL file.
442      * @see #getBinary()
443      * @see #getInt
444      * @throws MissingResourceException If resource bundle is missing.
445      * @throws UResourceTypeMismatchException If resource bundle has a type mismatch.
446      */
getIntVector()447     public int[] getIntVector() {
448         throw new UResourceTypeMismatchException("");
449     }
450 
451     /**
452      * <strong>[icu]</strong> Returns a signed integer from a resource.
453      *
454      * @return an integer value
455      * @see #getIntVector
456      * @see #getBinary()
457      * @throws MissingResourceException If resource bundle is missing.
458      * @throws UResourceTypeMismatchException If resource bundle type mismatch.
459      */
getInt()460     public int getInt() {
461         throw new UResourceTypeMismatchException("");
462     }
463 
464     /**
465      * <strong>[icu]</strong> Returns a unsigned integer from a resource.
466      * This integer is originally 28 bit and the sign gets propagated.
467      *
468      * @return an integer value
469      * @see #getIntVector
470      * @see #getBinary()
471      * @throws MissingResourceException If resource bundle is missing.
472      * @throws UResourceTypeMismatchException If resource bundle type mismatch.
473      */
getUInt()474     public int getUInt() {
475         throw new UResourceTypeMismatchException("");
476     }
477 
478     /**
479      * <strong>[icu]</strong> Returns a resource in a given resource that has a given key.
480      *
481      * @param aKey               a key associated with the wanted resource
482      * @return                  a resource bundle object representing the resource
483      * @throws MissingResourceException If resource bundle is missing.
484      */
get(String aKey)485     public UResourceBundle get(String aKey) {
486         UResourceBundle obj = findTopLevel(aKey);
487         if (obj == null) {
488             String fullName = ICUResourceBundleReader.getFullName(getBaseName(), getLocaleID());
489             throw new MissingResourceException(
490                     "Can't find resource for bundle " + fullName + ", key "
491                     + aKey, this.getClass().getName(), aKey);
492         }
493         return obj;
494     }
495 
496     /**
497      * Returns a resource in a given resource that has a given key, or null if the
498      * resource is not found.
499      *
500      * @param aKey the key associated with the wanted resource
501      * @return the resource, or null
502      * @see #get(String)
503      * @deprecated This API is ICU internal only.
504      * @hide draft / provisional / internal are hidden on Android
505      */
506     @Deprecated
findTopLevel(String aKey)507     protected UResourceBundle findTopLevel(String aKey) {
508         // NOTE: this only works for top-level resources.  For resources at lower
509         // levels, it fails when you fall back to the parent, since you're now
510         // looking at root resources, not at the corresponding nested resource.
511         for (UResourceBundle res = this; res != null; res = res.getParent()) {
512             UResourceBundle obj = res.handleGet(aKey, null, this);
513             if (obj != null) {
514                 return obj;
515             }
516         }
517         return null;
518     }
519 
520     /**
521      * Returns the string in a given resource at the specified index.
522      *
523      * @param index an index to the wanted string.
524      * @return a string which lives in the resource.
525      * @throws IndexOutOfBoundsException If the index value is out of bounds of accepted values.
526      * @throws UResourceTypeMismatchException If resource bundle type mismatch.
527      */
getString(int index)528     public String getString(int index) {
529         ICUResourceBundle temp = (ICUResourceBundle)get(index);
530         if (temp.getType() == STRING) {
531             return temp.getString();
532         }
533         throw new UResourceTypeMismatchException("");
534     }
535 
536     /**
537      * <strong>[icu]</strong> Returns the resource in a given resource at the specified index.
538      *
539      * @param index an index to the wanted resource.
540      * @return the sub resource UResourceBundle object
541      * @throws IndexOutOfBoundsException If the index value is out of bounds of accepted values.
542      * @throws MissingResourceException If the resource bundle is missing.
543      */
get(int index)544     public UResourceBundle get(int index) {
545         UResourceBundle obj = handleGet(index, null, this);
546         if (obj == null) {
547             obj = getParent();
548             if (obj != null) {
549                 obj = obj.get(index);
550             }
551             if (obj == null)
552                 throw new MissingResourceException(
553                         "Can't find resource for bundle "
554                                 + this.getClass().getName() + ", key "
555                                 + getKey(), this.getClass().getName(), getKey());
556         }
557         return obj;
558     }
559 
560     /**
561      * Returns a resource in a given resource that has a given index, or null if the
562      * resource is not found.
563      *
564      * @param index the index of the resource
565      * @return the resource, or null
566      * @see #get(int)
567      * @deprecated This API is ICU internal only.
568      * @hide draft / provisional / internal are hidden on Android
569      */
570     @Deprecated
findTopLevel(int index)571     protected UResourceBundle findTopLevel(int index) {
572         // NOTE: this _barely_ works for top-level resources.  For resources at lower
573         // levels, it fails when you fall back to the parent, since you're now
574         // looking at root resources, not at the corresponding nested resource.
575         // Not only that, but unless the indices correspond 1-to-1, the index will
576         // lose meaning.  Essentially this only works if the child resource arrays
577         // are prefixes of their parent arrays.
578         for (UResourceBundle res = this; res != null; res = res.getParent()) {
579             UResourceBundle obj = res.handleGet(index, null, this);
580             if (obj != null) {
581                 return obj;
582             }
583         }
584         return null;
585     }
586 
587     /**
588      * Returns the keys in this bundle as an enumeration
589      * @return an enumeration containing key strings,
590      *         which is empty if this is not a bundle or a table resource
591      */
592     @Override
getKeys()593     public Enumeration<String> getKeys() {
594         return Collections.enumeration(keySet());
595     }
596 
597     /**
598      * Returns a Set of all keys contained in this ResourceBundle and its parent bundles.
599      * @return a Set of all keys contained in this ResourceBundle and its parent bundles,
600      *         which is empty if this is not a bundle or a table resource
601      * @deprecated This API is ICU internal only.
602      * @hide draft / provisional / internal are hidden on Android
603      */
604     @Override
605     @Deprecated
keySet()606     public Set<String> keySet() {
607         // TODO: Java 6 ResourceBundle has keySet() which calls handleKeySet()
608         // and caches the results.
609         // When we upgrade to Java 6, we still need to check for isTopLevelResource().
610         // Keep the else branch as is. The if body should just return super.keySet().
611         // Remove then-redundant caching of the keys.
612         Set<String> keys = null;
613         ICUResourceBundle icurb = null;
614         if(isTopLevelResource() && this instanceof ICUResourceBundle) {
615             // We do not cache the top-level keys in this base class so that
616             // not every string/int/binary... resource has to have a keys cache field.
617             icurb = (ICUResourceBundle)this;
618             keys = icurb.getTopLevelKeySet();
619         }
620         if(keys == null) {
621             if(isTopLevelResource()) {
622                 TreeSet<String> newKeySet;
623                 if(parent == null) {
624                     newKeySet = new TreeSet<String>();
625                 } else if(parent instanceof UResourceBundle) {
626                     newKeySet = new TreeSet<String>(((UResourceBundle)parent).keySet());
627                 } else {
628                     // TODO: Java 6 ResourceBundle has keySet(); use it when we upgrade to Java 6
629                     // and remove this else branch.
630                     newKeySet = new TreeSet<String>();
631                     Enumeration<String> parentKeys = parent.getKeys();
632                     while(parentKeys.hasMoreElements()) {
633                         newKeySet.add(parentKeys.nextElement());
634                     }
635                 }
636                 newKeySet.addAll(handleKeySet());
637                 keys = Collections.unmodifiableSet(newKeySet);
638                 if(icurb != null) {
639                     icurb.setTopLevelKeySet(keys);
640                 }
641             } else {
642                 return handleKeySet();
643             }
644         }
645         return keys;
646     }
647 
648     /**
649      * Returns a Set of the keys contained <i>only</i> in this ResourceBundle.
650      * This does not include further keys from parent bundles.
651      * @return a Set of the keys contained only in this ResourceBundle,
652      *         which is empty if this is not a bundle or a table resource
653      * @deprecated This API is ICU internal only.
654      * @hide draft / provisional / internal are hidden on Android
655      */
656     @Override
657     @Deprecated
handleKeySet()658     protected Set<String> handleKeySet() {
659         return Collections.emptySet();
660     }
661 
662     /**
663      * <strong>[icu]</strong> Returns the size of a resource. Size for scalar types is always 1, and for
664      * vector/table types is the number of child resources.
665      *
666      * <br><b>Note:</b> Integer array is treated as a scalar type. There are no APIs to
667      * access individual members of an integer array. It is always returned as a whole.
668      * @return number of resources in a given resource.
669      */
getSize()670     public int getSize() {
671         return 1;
672     }
673 
674     /**
675      * <strong>[icu]</strong> Returns the type of a resource.
676      * Available types are {@link #INT INT}, {@link #ARRAY ARRAY},
677      * {@link #BINARY BINARY}, {@link #INT_VECTOR INT_VECTOR},
678      * {@link #STRING STRING}, {@link #TABLE TABLE}.
679      *
680      * @return type of the given resource.
681      */
getType()682     public int getType() {
683         return NONE;
684     }
685 
686     /**
687      * <strong>[icu]</strong> Return the version number associated with this UResourceBundle as an
688      * VersionInfo object.
689      * @return VersionInfo object containing the version of the bundle
690      */
getVersion()691     public VersionInfo getVersion() {
692         return null;
693     }
694 
695     /**
696      * <strong>[icu]</strong> Returns the iterator which iterates over this
697      * resource bundle
698      * @return UResourceBundleIterator that iterates over the resources in the bundle
699      */
getIterator()700     public UResourceBundleIterator getIterator() {
701         return new UResourceBundleIterator(this);
702     }
703 
704     /**
705      * <strong>[icu]</strong> Returns the key associated with a given resource. Not all the resources have
706      * a key - only those that are members of a table.
707      * @return a key associated to this resource, or null if it doesn't have a key
708      */
getKey()709     public String getKey() {
710         return null;
711     }
712 
713     /**
714      * <strong>[icu]</strong> Resource type constant for "no resource".
715      */
716     public static final int NONE = -1;
717 
718     /**
719      * <strong>[icu]</strong> Resource type constant for strings.
720      */
721     public static final int STRING = 0;
722 
723     /**
724      * <strong>[icu]</strong> Resource type constant for binary data.
725      */
726     public static final int BINARY = 1;
727 
728     /**
729      * <strong>[icu]</strong> Resource type constant for tables of key-value pairs.
730      */
731     public static final int TABLE = 2;
732 
733     /**
734      * <strong>[icu]</strong> Resource type constant for a single 28-bit integer, interpreted as
735      * signed or unsigned by the getInt() function.
736      * @see #getInt
737      */
738     public static final int INT = 7;
739 
740     /**
741      * <strong>[icu]</strong> Resource type constant for arrays of resources.
742      */
743     public static final int ARRAY = 8;
744 
745     /**
746      * Resource type constant for vectors of 32-bit integers.
747      * @see #getIntVector
748      */
749     public static final int INT_VECTOR = 14;
750 
751     //====== protected members ==============
752 
753     /**
754      * <strong>[icu]</strong> Actual worker method for fetching a resource based on the given key.
755      * Sub classes must override this method if they support resources with keys.
756      * @param aKey the key string of the resource to be fetched
757      * @param aliasesVisited hashtable object to hold references of resources already seen
758      * @param requested the original resource bundle object on which the get method was invoked.
759      *                  The requested bundle and the bundle on which this method is invoked
760      *                  are the same, except in the cases where aliases are involved.
761      * @return UResourceBundle a resource associated with the key
762      */
handleGet(String aKey, HashMap<String, String> aliasesVisited, UResourceBundle requested)763     protected UResourceBundle handleGet(String aKey, HashMap<String, String> aliasesVisited,
764                                         UResourceBundle requested) {
765         return null;
766     }
767 
768     /**
769      * <strong>[icu]</strong> Actual worker method for fetching a resource based on the given index.
770      * Sub classes must override this method if they support arrays of resources.
771      * @param index the index of the resource to be fetched
772      * @param aliasesVisited hashtable object to hold references of resources already seen
773      * @param requested the original resource bundle object on which the get method was invoked.
774      *                  The requested bundle and the bundle on which this method is invoked
775      *                  are the same, except in the cases where aliases are involved.
776      * @return UResourceBundle a resource associated with the index
777      */
handleGet(int index, HashMap<String, String> aliasesVisited, UResourceBundle requested)778     protected UResourceBundle handleGet(int index, HashMap<String, String> aliasesVisited,
779                                         UResourceBundle requested) {
780         return null;
781     }
782 
783     /**
784      * <strong>[icu]</strong> Actual worker method for fetching the array of strings in a resource.
785      * Sub classes must override this method if they support arrays of strings.
786      * @return String[] An array of strings containing strings
787      */
handleGetStringArray()788     protected String[] handleGetStringArray() {
789         return null;
790     }
791 
792     /**
793      * <strong>[icu]</strong> Actual worker method for fetching the keys of resources contained in the resource.
794      * Sub classes must override this method if they support keys and associated resources.
795      *
796      * @return Enumeration An enumeration of all the keys in this resource.
797      */
handleGetKeys()798     protected Enumeration<String> handleGetKeys(){
799         return null;
800     }
801 
802     /**
803      * {@inheritDoc}
804      */
805     // this method is declared in ResourceBundle class
806     // so cannot change the signature
807     // Override this method
808     @Override
handleGetObject(String aKey)809     protected Object handleGetObject(String aKey) {
810         return handleGetObjectImpl(aKey, this);
811     }
812 
813     /**
814      * Override the superclass method
815      */
816     // To facilitate XPath style aliases we need a way to pass the reference
817     // to requested locale. The only way I could figure out is to implement
818     // the look up logic here. This has a disadvantage that if the client
819     // loads an ICUResourceBundle, calls ResourceBundle.getObject method
820     // with a key that does not exist in the bundle then the lookup is
821     // done twice before throwing a MissingResourceExpection.
handleGetObjectImpl(String aKey, UResourceBundle requested)822     private Object handleGetObjectImpl(String aKey, UResourceBundle requested) {
823         Object obj = resolveObject(aKey, requested);
824         if (obj == null) {
825             UResourceBundle parentBundle = getParent();
826             if (parentBundle != null) {
827                 obj = parentBundle.handleGetObjectImpl(aKey, requested);
828             }
829             if (obj == null)
830                 throw new MissingResourceException(
831                     "Can't find resource for bundle "
832                     + this.getClass().getName() + ", key " + aKey,
833                     this.getClass().getName(), aKey);
834         }
835         return obj;
836     }
837 
838     // Routine for figuring out the type of object to be returned
839     // string or string array
resolveObject(String aKey, UResourceBundle requested)840     private Object resolveObject(String aKey, UResourceBundle requested) {
841         if (getType() == STRING) {
842             return getString();
843         }
844         UResourceBundle obj = handleGet(aKey, null, requested);
845         if (obj != null) {
846             if (obj.getType() == STRING) {
847                 return obj.getString();
848             }
849             try {
850                 if (obj.getType() == ARRAY) {
851                     return obj.handleGetStringArray();
852                 }
853             } catch (UResourceTypeMismatchException ex) {
854                 return obj;
855             }
856         }
857         return obj;
858     }
859 
860     /**
861      * Is this a top-level resource, that is, a whole bundle?
862      * @return true if this is a top-level resource
863      * @deprecated This API is ICU internal only.
864      * @hide draft / provisional / internal are hidden on Android
865      */
866     @Deprecated
isTopLevelResource()867     protected boolean isTopLevelResource() {
868         return true;
869     }
870 }
871