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
11package android.icu.util;
12
13import java.nio.ByteBuffer;
14import java.util.Collections;
15import java.util.Enumeration;
16import java.util.HashMap;
17import java.util.Locale;
18import java.util.Map;
19import java.util.MissingResourceException;
20import java.util.ResourceBundle;
21import java.util.Set;
22import java.util.TreeSet;
23import java.util.concurrent.ConcurrentHashMap;
24
25import android.icu.impl.ICUData;
26import android.icu.impl.ICUResourceBundle;
27import android.icu.impl.ICUResourceBundleReader;
28import 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 */
96public 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     */
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     */
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     */
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     */
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     */
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     */
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
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     */
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     */
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     */
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     */
280    public abstract ULocale getULocale();
281
282    /**
283     * <strong>[icu]</strong> Returns the localeID
284     * @return The string representation of the localeID
285     */
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     */
292    protected abstract String getBaseName();
293
294    /**
295     * <strong>[icu]</strong> Returns the parent bundle
296     * @return The parent bundle
297     */
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
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
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
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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
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     */
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     */
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
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
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
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
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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
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.
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
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
867    protected boolean isTopLevelResource() {
868        return true;
869    }
870}
871