2 *******************************************************************************
3 * Copyright (C) 2004-2013, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
8 package com.ibm.icu.util;
10 import java.lang.ref.SoftReference;
11 import java.nio.ByteBuffer;
12 import java.util.Collections;
13 import java.util.Enumeration;
14 import java.util.HashMap;
15 import java.util.Locale;
16 import java.util.MissingResourceException;
17 import java.util.ResourceBundle;
19 import java.util.TreeSet;
20 import java.util.concurrent.ConcurrentHashMap;
22 import com.ibm.icu.impl.ICUCache;
23 import com.ibm.icu.impl.ICUResourceBundle;
24 import com.ibm.icu.impl.ICUResourceBundleReader;
25 import com.ibm.icu.impl.ResourceBundleWrapper;
26 import com.ibm.icu.impl.SimpleCache;
29 * {@icuenhanced java.util.ResourceBundle}.{@icu _usage_}
31 * <p>A class representing a collection of resource information pertaining to a given
32 * locale. A resource bundle provides a way of accessing locale- specific information in a
33 * data file. You create a resource bundle that manages the resources for a given locale
34 * and then ask it for individual resources.
36 * <p>In ResourceBundle, an object is created and the sub-items are fetched using the
37 * getString and getObject methods. In UResourceBundle, each individual element of a
38 * resource is a resource by itself.
40 * <p>Resource bundles in ICU are currently defined using text files that conform to the
42 * href="http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt">BNF
43 * definition</a>. More on resource bundle concepts and syntax can be found in the <a
44 * href="http://www.icu-project.org/userguide/ResourceManagement.html">Users Guide</a>.
46 * <p>The packaging of ICU *.res files can be of two types
65 * LocaleElements_fr.res LocaleElements_en.res
67 * ---------------------------
69 * LocaleElements_fr_CA.res LocaleElements_fr_FR.res
72 * Depending on the organization of your resources, the syntax to getBundleInstance will
73 * change. To open ICU style organization use:
76 * UResourceBundle bundle =
77 * UResourceBundle.getBundleInstance("com/mycompany/resources",
78 * "en_US", myClassLoader);
80 * To open Java/JDK style organization use:
82 * UResourceBundle bundle =
83 * UResourceBundle.getBundleInstance("com.mycompany.resources.LocaleElements",
84 * "en_US", myClassLoader);
87 * Please use pass a class loader for loading non-ICU resources. Java security does not
88 * allow loading of resources across jar files. You must provide your class loader
89 * to load the resources
94 public abstract class UResourceBundle extends ResourceBundle {
98 * {@icu} Creates a resource bundle using the specified base name and locale.
99 * ICU_DATA_CLASS is used as the default root.
100 * @param baseName the base name of the resource bundle, a fully qualified class name
101 * @param localeName the locale for which a resource bundle is desired
102 * @throws MissingResourceException If no resource bundle for the specified base name
104 * @return a resource bundle for the given base name and locale
107 public static UResourceBundle getBundleInstance(String baseName, String localeName){
108 return getBundleInstance(baseName, localeName, ICUResourceBundle.ICU_DATA_CLASS_LOADER,
113 * {@icu} Creates a resource bundle using the specified base name, locale, and class root.
115 * @param baseName the base name of the resource bundle, a fully qualified class name
116 * @param localeName the locale for which a resource bundle is desired
117 * @param root the class object from which to load the resource bundle
118 * @throws MissingResourceException If no resource bundle for the specified base name
120 * @return a resource bundle for the given base name and locale
123 public static UResourceBundle getBundleInstance(String baseName, String localeName,
125 return getBundleInstance(baseName, localeName, root, false);
129 * {@icu} Creates a resource bundle using the specified base name, locale, and class
132 * @param baseName the base name of the resource bundle, a fully qualified class name
133 * @param localeName the locale for which a resource bundle is desired
134 * @param root the class object from which to load the resource bundle
135 * @param disableFallback Option to disable locale inheritence.
136 * If true the fallback chain will not be built.
137 * @throws MissingResourceException
138 * if no resource bundle for the specified base name can be found
139 * @return a resource bundle for the given base name and locale
143 protected static UResourceBundle getBundleInstance(String baseName, String localeName,
144 ClassLoader root, boolean disableFallback) {
145 return instantiateBundle(baseName, localeName, root, disableFallback);
149 * {@icu} Sole constructor. (For invocation by subclass constructors, typically
150 * implicit.) This is public for compatibility with Java, whose compiler
151 * will generate public default constructors for an abstract class.
154 public UResourceBundle() {
158 * {@icu} Creates a UResourceBundle for the locale specified, from which users can extract
159 * resources by using their corresponding keys.
160 * @param locale specifies the locale for which we want to open the resource.
161 * If null the bundle for default locale is opened.
162 * @return a resource bundle for the given locale
165 public static UResourceBundle getBundleInstance(ULocale locale) {
167 locale = ULocale.getDefault();
169 return getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale.toString(),
170 ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);
174 * {@icu} 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 specifies the locale for which we want to open the resource.
177 * If null the bundle for default locale is opened.
178 * @return a resource bundle for the given base name and default locale
181 public static UResourceBundle getBundleInstance(String baseName) {
182 if (baseName == null) {
183 baseName = ICUResourceBundle.ICU_BASE_NAME;
185 ULocale uloc = ULocale.getDefault();
186 return getBundleInstance(baseName, uloc.toString(), ICUResourceBundle.ICU_DATA_CLASS_LOADER,
191 * {@icu} Creates a UResourceBundle for the specified locale and specified base name,
192 * from which users can extract resources by using their corresponding keys.
193 * @param baseName specifies the locale for which we want to open the resource.
194 * If null the bundle for default locale is opened.
195 * @param locale specifies the locale for which we want to open the resource.
196 * If null the bundle for default locale is opened.
197 * @return a resource bundle for the given base name and locale
201 public static UResourceBundle getBundleInstance(String baseName, Locale locale) {
202 if (baseName == null) {
203 baseName = ICUResourceBundle.ICU_BASE_NAME;
205 ULocale uloc = locale == null ? ULocale.getDefault() : ULocale.forLocale(locale);
207 return getBundleInstance(baseName, uloc.toString(), ICUResourceBundle.ICU_DATA_CLASS_LOADER,
212 * {@icu} Creates a UResourceBundle, from which users can extract resources by using
213 * their corresponding keys.
214 * @param baseName string containing the name of the data package.
215 * If null the default ICU package name is used.
216 * @param locale specifies the locale for which we want to open the resource.
217 * If null the bundle for default locale is opened.
218 * @return a resource bundle for the given base name and locale
221 public static UResourceBundle getBundleInstance(String baseName, ULocale locale) {
222 if (baseName == null) {
223 baseName = ICUResourceBundle.ICU_BASE_NAME;
225 if (locale == null) {
226 locale = ULocale.getDefault();
228 return getBundleInstance(baseName, locale.toString(),
229 ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);
233 * {@icu} Creates a UResourceBundle for the specified locale and specified base name,
234 * from which users can extract resources by using their corresponding keys.
235 * @param baseName specifies the locale for which we want to open the resource.
236 * If null the bundle for default locale is opened.
237 * @param locale specifies the locale for which we want to open the resource.
238 * If null the bundle for default locale is opened.
239 * @param loader the loader to use
240 * @return a resource bundle for the given base name and locale
243 public static UResourceBundle getBundleInstance(String baseName, Locale locale,
244 ClassLoader loader) {
245 if (baseName == null) {
246 baseName = ICUResourceBundle.ICU_BASE_NAME;
248 ULocale uloc = locale == null ? ULocale.getDefault() : ULocale.forLocale(locale);
249 return getBundleInstance(baseName, uloc.toString(), loader, false);
253 * {@icu} Creates a UResourceBundle, from which users can extract resources by using
254 * their corresponding keys.<br><br>
255 * Note: Please use this API for loading non-ICU resources. Java security does not
256 * allow loading of resources across jar files. You must provide your class loader
257 * to load the resources
258 * @param baseName string containing the name of the data package.
259 * If null the default ICU package name is used.
260 * @param locale specifies the locale for which we want to open the resource.
261 * If null the bundle for default locale is opened.
262 * @param loader the loader to use
263 * @return a resource bundle for the given base name and locale
266 public static UResourceBundle getBundleInstance(String baseName, ULocale locale,
267 ClassLoader loader) {
268 if (baseName == null) {
269 baseName = ICUResourceBundle.ICU_BASE_NAME;
271 if (locale == null) {
272 locale = ULocale.getDefault();
274 return getBundleInstance(baseName, locale.toString(), loader, false);
278 * {@icu} Returns the RFC 3066 conformant locale id of this resource bundle.
279 * This method can be used after a call to getBundleInstance() to
280 * determine whether the resource bundle returned really
281 * corresponds to the requested locale or is a fallback.
283 * @return the locale of this resource bundle
286 public abstract ULocale getULocale();
289 * {@icu} Returns the localeID
290 * @return The string representation of the localeID
293 protected abstract String getLocaleID();
296 * {@icu} Returns the base name of the resource bundle
297 * @return The string representation of the base name
300 protected abstract String getBaseName();
303 * {@icu} Returns the parent bundle
304 * @return The parent bundle
307 protected abstract UResourceBundle getParent();
311 * Returns the locale of this bundle
312 * @return the locale of this resource bundle
315 public Locale getLocale(){
316 return getULocale().toLocale();
319 // Cache for ResourceBundle instantiation
320 private static ICUCache<ResourceCacheKey, UResourceBundle> BUNDLE_CACHE =
321 new SimpleCache<ResourceCacheKey, UResourceBundle>();
325 * @deprecated This API is ICU internal only.
327 public static void resetBundleCache() {
330 * Currently if a resourcebundle with fallback turned ON is added to the cache
331 * and then a getBundleInstance() is called for a bundle with fallback turned OFF
332 * it will actually search the cache for any bundle of the same locale
333 * regaurdless of fallback status. This method has been created so that if
334 * The calling method KNOWS that instances of the other fallback state may be in the
335 * cache, the calling method may call this method to clear out the cache.
338 //TODO figure a way around this method(see method comment)
339 BUNDLE_CACHE = new SimpleCache<ResourceCacheKey, UResourceBundle>();
343 * Method used by subclasses to add a resource bundle object to the managed
344 * cache. Works like a putIfAbsent(): If the cache already contains a matching
345 * bundle, that one will be retained and returned.
347 * @deprecated This API is ICU internal only.
349 protected static UResourceBundle addToCache(ClassLoader cl, String fullName,
350 ULocale defaultLocale, UResourceBundle b) {
351 synchronized(cacheKey){
352 cacheKey.setKeyValues(cl, fullName, defaultLocale);
353 UResourceBundle cachedBundle = BUNDLE_CACHE.get(cacheKey);
354 if (cachedBundle != null) {
357 BUNDLE_CACHE.put((ResourceCacheKey)cacheKey.clone(), b);
363 * Method used by sub classes to load a resource bundle object from the managed cache
365 * @deprecated This API is ICU internal only.
367 protected static UResourceBundle loadFromCache(ClassLoader cl, String fullName,
368 ULocale defaultLocale){
369 synchronized(cacheKey){
370 cacheKey.setKeyValues(cl, fullName, defaultLocale);
371 return BUNDLE_CACHE.get(cacheKey);
376 * Key used for cached resource bundles. The key checks
377 * the resource name, the class root, and the default
378 * locale to determine if the resource is a match to the
379 * requested one. The root may be null, but the
380 * searchName and the default locale must have a non-null value.
381 * Note that the default locale may change over time, and
382 * lookup should always be based on the current default
383 * locale (if at all).
385 private static final class ResourceCacheKey implements Cloneable {
386 private SoftReference<ClassLoader> loaderRef;
387 private String searchName;
388 private ULocale defaultLocale;
389 private int hashCodeCache;
391 public boolean equals(Object other) {
399 final ResourceCacheKey otherEntry = (ResourceCacheKey) other;
400 //quick check to see if they are not equal
401 if (hashCodeCache != otherEntry.hashCodeCache) {
404 //are the names the same?
405 if (!searchName.equals(otherEntry.searchName)) {
408 // are the default locales the same?
409 if (defaultLocale == null) {
410 if (otherEntry.defaultLocale != null) {
414 if (!defaultLocale.equals(otherEntry.defaultLocale)) {
418 //are refs (both non-null) or (both null)?
419 if (loaderRef == null) {
420 return otherEntry.loaderRef == null;
422 return (otherEntry.loaderRef != null)
423 && (loaderRef.get() == otherEntry.loaderRef.get());
425 } catch (NullPointerException e) {
427 } catch (ClassCastException e) {
432 public int hashCode() {
433 return hashCodeCache;
436 public Object clone() {
438 return super.clone();
439 } catch (CloneNotSupportedException e) {
440 //this should never happen
441 throw new IllegalStateException();
446 private synchronized void setKeyValues(ClassLoader root, String searchName,
447 ULocale defaultLocale) {
448 this.searchName = searchName;
449 hashCodeCache = searchName.hashCode();
450 this.defaultLocale = defaultLocale;
451 if (defaultLocale != null) {
452 hashCodeCache ^= defaultLocale.hashCode();
455 this.loaderRef = null;
457 loaderRef = new SoftReference<ClassLoader>(root);
458 hashCodeCache ^= root.hashCode();
461 /*private void clear() {
462 setKeyValues(null, "", null);
466 private static final ResourceCacheKey cacheKey = new ResourceCacheKey();
468 private static final int ROOT_MISSING = 0;
469 private static final int ROOT_ICU = 1;
470 private static final int ROOT_JAVA = 2;
472 private static SoftReference<ConcurrentHashMap<String, Integer>> ROOT_CACHE =
473 new SoftReference<ConcurrentHashMap<String, Integer>>(new ConcurrentHashMap<String, Integer>());
475 private static int getRootType(String baseName, ClassLoader root) {
476 ConcurrentHashMap<String, Integer> m = null;
479 m = ROOT_CACHE.get();
481 synchronized(UResourceBundle.class) {
482 m = ROOT_CACHE.get();
484 m = new ConcurrentHashMap<String, Integer>();
485 ROOT_CACHE = new SoftReference<ConcurrentHashMap<String, Integer>>(m);
490 rootType = m.get(baseName);
492 if (rootType == null) {
493 String rootLocale = (baseName.indexOf('.')==-1) ? "root" : "";
494 int rt = ROOT_MISSING; // value set on success
496 ICUResourceBundle.getBundleInstance(baseName, rootLocale, root, true);
498 }catch(MissingResourceException ex){
500 ResourceBundleWrapper.getBundleInstance(baseName, rootLocale, root, true);
502 }catch(MissingResourceException e){
503 //throw away the exception
507 rootType = Integer.valueOf(rt);
508 m.putIfAbsent(baseName, rootType);
511 return rootType.intValue();
514 private static void setRootType(String baseName, int rootType) {
515 Integer rt = Integer.valueOf(rootType);
516 ConcurrentHashMap<String, Integer> m = null;
518 m = ROOT_CACHE.get();
520 synchronized(UResourceBundle.class) {
521 m = ROOT_CACHE.get();
523 m = new ConcurrentHashMap<String, Integer>();
524 ROOT_CACHE = new SoftReference<ConcurrentHashMap<String, Integer>>(m);
533 * {@icu} Loads a new resource bundle for the given base name, locale and class loader.
534 * Optionally will disable loading of fallback bundles.
535 * @param baseName the base name of the resource bundle, a fully qualified class name
536 * @param localeName the locale for which a resource bundle is desired
537 * @param root the class object from which to load the resource bundle
538 * @param disableFallback disables loading of fallback lookup chain
539 * @throws MissingResourceException If no resource bundle for the specified base name
541 * @return a resource bundle for the given base name and locale
544 protected static UResourceBundle instantiateBundle(String baseName, String localeName,
545 ClassLoader root, boolean disableFallback) {
546 UResourceBundle b = null;
547 int rootType = getRootType(baseName, root);
549 ULocale defaultLocale = ULocale.getDefault();
554 if(disableFallback) {
555 String fullName = ICUResourceBundleReader.getFullName(baseName, localeName);
556 b = loadFromCache(root, fullName, defaultLocale);
558 b = ICUResourceBundle.getBundleInstance(baseName, localeName, root,
562 b = ICUResourceBundle.getBundleInstance(baseName, localeName, root,
569 return ResourceBundleWrapper.getBundleInstance(baseName, localeName, root,
574 b = ICUResourceBundle.getBundleInstance(baseName, localeName, root,
576 setRootType(baseName, ROOT_ICU);
577 }catch(MissingResourceException ex){
578 b = ResourceBundleWrapper.getBundleInstance(baseName, localeName, root,
580 setRootType(baseName, ROOT_JAVA);
587 * {@icu} Returns a binary data item from a binary resource, as a read-only ByteBuffer.
589 * @return a pointer to a chunk of unsigned bytes which live in a memory mapped/DLL
593 * @throws MissingResourceException If no resource bundle can be found.
594 * @throws UResourceTypeMismatchException If the resource has a type mismatch.
597 public ByteBuffer getBinary() {
598 throw new UResourceTypeMismatchException("");
602 * Returns a string from a string resource type
608 * @throws MissingResourceException If resource bundle is missing.
609 * @throws UResourceTypeMismatchException If resource bundle has a type mismatch.
612 public String getString() {
613 throw new UResourceTypeMismatchException("");
617 * Returns a string array from a array resource type
622 * @throws MissingResourceException If resource bundle is missing.
623 * @throws UResourceTypeMismatchException If resource bundle has a type mismatch.
626 public String[] getStringArray() {
627 throw new UResourceTypeMismatchException("");
631 * {@icu} Returns a binary data from a binary resource, as a byte array with a copy
632 * of the bytes from the resource bundle.
634 * @param ba The byte array to write the bytes to. A null variable is OK.
635 * @return an array of bytes containing the binary data from the resource.
638 * @throws MissingResourceException If resource bundle is missing.
639 * @throws UResourceTypeMismatchException If resource bundle has a type mismatch.
642 public byte[] getBinary(byte[] ba) {
643 throw new UResourceTypeMismatchException("");
647 * {@icu} Returns a 32 bit integer array from a resource.
649 * @return a pointer to a chunk of unsigned bytes which live in a memory mapped/DLL file.
652 * @throws MissingResourceException If resource bundle is missing.
653 * @throws UResourceTypeMismatchException If resource bundle has a type mismatch.
656 public int[] getIntVector() {
657 throw new UResourceTypeMismatchException("");
661 * {@icu} Returns a signed integer from a resource.
663 * @return an integer value
666 * @throws MissingResourceException If resource bundle is missing.
667 * @throws UResourceTypeMismatchException If resource bundle type mismatch.
670 public int getInt() {
671 throw new UResourceTypeMismatchException("");
675 * {@icu} Returns a unsigned integer from a resource.
676 * This integer is originally 28 bit and the sign gets propagated.
678 * @return an integer value
681 * @throws MissingResourceException If resource bundle is missing.
682 * @throws UResourceTypeMismatchException If resource bundle type mismatch.
685 public int getUInt() {
686 throw new UResourceTypeMismatchException("");
690 * {@icu} Returns a resource in a given resource that has a given key.
692 * @param aKey a key associated with the wanted resource
693 * @return a resource bundle object representing the resource
694 * @throws MissingResourceException If resource bundle is missing.
697 public UResourceBundle get(String aKey) {
698 UResourceBundle obj = findTopLevel(aKey);
700 String fullName = ICUResourceBundleReader.getFullName(getBaseName(), getLocaleID());
701 throw new MissingResourceException(
702 "Can't find resource for bundle " + fullName + ", key "
703 + aKey, this.getClass().getName(), aKey);
709 * Returns a resource in a given resource that has a given key, or null if the
710 * resource is not found.
712 * @param aKey the key associated with the wanted resource
713 * @return the resource, or null
716 * @deprecated This API is ICU internal only.
718 protected UResourceBundle findTopLevel(String aKey) {
719 // NOTE: this only works for top-level resources. For resources at lower
720 // levels, it fails when you fall back to the parent, since you're now
721 // looking at root resources, not at the corresponding nested resource.
722 for (UResourceBundle res = this; res != null; res = res.getParent()) {
723 UResourceBundle obj = res.handleGet(aKey, null, this);
725 ((ICUResourceBundle) obj).setLoadingStatus(getLocaleID());
733 * Returns the string in a given resource at the specified index.
735 * @param index an index to the wanted string.
736 * @return a string which lives in the resource.
737 * @throws IndexOutOfBoundsException If the index value is out of bounds of accepted values.
738 * @throws UResourceTypeMismatchException If resource bundle type mismatch.
741 public String getString(int index) {
742 ICUResourceBundle temp = (ICUResourceBundle)get(index);
743 if (temp.getType() == STRING) {
744 return temp.getString();
746 throw new UResourceTypeMismatchException("");
750 * {@icu} Returns the resource in a given resource at the specified index.
752 * @param index an index to the wanted resource.
753 * @return the sub resource UResourceBundle object
754 * @throws IndexOutOfBoundsException If the index value is out of bounds of accepted values.
755 * @throws MissingResourceException If the resource bundle is missing.
758 public UResourceBundle get(int index) {
759 UResourceBundle obj = handleGet(index, null, this);
761 obj = (ICUResourceBundle) getParent();
763 obj = obj.get(index);
766 throw new MissingResourceException(
767 "Can't find resource for bundle "
768 + this.getClass().getName() + ", key "
769 + getKey(), this.getClass().getName(), getKey());
771 ((ICUResourceBundle)obj).setLoadingStatus(getLocaleID());
776 * Returns a resource in a given resource that has a given index, or null if the
777 * resource is not found.
779 * @param index the index of the resource
780 * @return the resource, or null
783 * @deprecated This API is ICU internal only.
785 protected UResourceBundle findTopLevel(int index) {
786 // NOTE: this _barely_ works for top-level resources. For resources at lower
787 // levels, it fails when you fall back to the parent, since you're now
788 // looking at root resources, not at the corresponding nested resource.
789 // Not only that, but unless the indices correspond 1-to-1, the index will
790 // lose meaning. Essentially this only works if the child resource arrays
791 // are prefixes of their parent arrays.
792 for (UResourceBundle res = this; res != null; res = res.getParent()) {
793 UResourceBundle obj = res.handleGet(index, null, this);
795 ((ICUResourceBundle) obj).setLoadingStatus(getLocaleID());
803 * Returns the keys in this bundle as an enumeration
804 * @return an enumeration containing key strings,
805 * which is empty if this is not a bundle or a table resource
808 public Enumeration<String> getKeys() {
809 return Collections.enumeration(keySet());
813 * Returns a Set of all keys contained in this ResourceBundle and its parent bundles.
814 * @return a Set of all keys contained in this ResourceBundle and its parent bundles,
815 * which is empty if this is not a bundle or a table resource
817 * @deprecated This API is ICU internal only.
819 public Set<String> keySet() {
821 if(isTopLevelResource()) {
822 TreeSet<String> newKeySet;
824 newKeySet = new TreeSet<String>();
825 } else if(parent instanceof UResourceBundle) {
826 newKeySet = new TreeSet<String>(((UResourceBundle)parent).keySet());
828 // TODO: Java 6 ResourceBundle has keySet(); use it when we upgrade to Java 6
829 // and remove this else branch.
830 newKeySet = new TreeSet<String>();
831 Enumeration<String> parentKeys = parent.getKeys();
832 while(parentKeys.hasMoreElements()) {
833 newKeySet.add(parentKeys.nextElement());
836 newKeySet.addAll(handleKeySet());
837 keys = Collections.unmodifiableSet(newKeySet);
839 return handleKeySet();
845 private Set<String> keys = null;
847 * Returns a Set of the keys contained <i>only</i> in this ResourceBundle.
848 * This does not include further keys from parent bundles.
849 * @return a Set of the keys contained only in this ResourceBundle,
850 * which is empty if this is not a bundle or a table resource
852 * @deprecated This API is ICU internal only.
854 protected Set<String> handleKeySet() {
855 return Collections.emptySet();
859 * {@icu} Returns the size of a resource. Size for scalar types is always 1, and for
860 * vector/table types is the number of child resources.
862 * <br><b>Note:</b> Integer array is treated as a scalar type. There are no APIs to
863 * access individual members of an integer array. It is always returned as a whole.
864 * @return number of resources in a given resource.
867 public int getSize() {
872 * {@icu} Returns the type of a resource.
873 * Available types are {@link #INT INT}, {@link #ARRAY ARRAY},
874 * {@link #BINARY BINARY}, {@link #INT_VECTOR INT_VECTOR},
875 * {@link #STRING STRING}, {@link #TABLE TABLE}.
877 * @return type of the given resource.
880 public int getType() {
885 * {@icu} Return the version number associated with this UResourceBundle as an
886 * VersionInfo object.
887 * @return VersionInfo object containing the version of the bundle
890 public VersionInfo getVersion() {
895 * {@icu} Returns the iterator which iterates over this
897 * @return UResourceBundleIterator that iterates over the resources in the bundle
900 public UResourceBundleIterator getIterator() {
901 return new UResourceBundleIterator(this);
905 * {@icu} Returns the key associated with a given resource. Not all the resources have
906 * a key - only those that are members of a table.
907 * @return a key associated to this resource, or null if it doesn't have a key
910 public String getKey() {
915 * {@icu} Resource type constant for "no resource".
918 public static final int NONE = -1;
921 * {@icu} Resource type constant for strings.
924 public static final int STRING = 0;
927 * {@icu} Resource type constant for binary data.
930 public static final int BINARY = 1;
933 * {@icu} Resource type constant for tables of key-value pairs.
936 public static final int TABLE = 2;
939 * {@icu} Resource type constant for a single 28-bit integer, interpreted as
940 * signed or unsigned by the getInt() function.
944 public static final int INT = 7;
947 * {@icu} Resource type constant for arrays of resources.
950 public static final int ARRAY = 8;
953 * Resource type constant for vectors of 32-bit integers.
957 public static final int INT_VECTOR = 14;
959 //====== protected members ==============
962 * {@icu} Actual worker method for fetching a resource based on the given key.
963 * Sub classes must override this method if they support resources with keys.
964 * @param aKey the key string of the resource to be fetched
965 * @param table hashtable object to hold references of resources already seen
966 * @param requested the original resource bundle object on which the get method was invoked.
967 * The requested bundle and the bundle on which this method is invoked
968 * are the same, except in the cases where aliases are involved.
969 * @return UResourceBundle a resource associated with the key
972 protected UResourceBundle handleGet(String aKey, HashMap<String, String> table,
973 UResourceBundle requested) {
978 * {@icu} Actual worker method for fetching a resource based on the given index.
979 * Sub classes must override this method if they support arrays of resources.
980 * @param index the index of the resource to be fetched
981 * @param table hashtable object to hold references of resources already seen
982 * @param requested the original resource bundle object on which the get method was invoked.
983 * The requested bundle and the bundle on which this method is invoked
984 * are the same, except in the cases where aliases are involved.
985 * @return UResourceBundle a resource associated with the index
988 protected UResourceBundle handleGet(int index, HashMap<String, String> table,
989 UResourceBundle requested) {
994 * {@icu} Actual worker method for fetching the array of strings in a resource.
995 * Sub classes must override this method if they support arrays of strings.
996 * @return String[] An array of strings containing strings
999 protected String[] handleGetStringArray() {
1004 * {@icu} Actual worker method for fetching the keys of resources contained in the resource.
1005 * Sub classes must override this method if they support keys and associated resources.
1007 * @return Enumeration An enumeration of all the keys in this resource.
1010 protected Enumeration<String> handleGetKeys(){
1018 // this method is declared in ResourceBundle class
1019 // so cannot change the signature
1020 // Override this method
1021 protected Object handleGetObject(String aKey) {
1022 return handleGetObjectImpl(aKey, this);
1026 * Override the superclass method
1028 // To facilitate XPath style aliases we need a way to pass the reference
1029 // to requested locale. The only way I could figure out is to implement
1030 // the look up logic here. This has a disadvantage that if the client
1031 // loads an ICUResourceBundle, calls ResourceBundle.getObject method
1032 // with a key that does not exist in the bundle then the lookup is
1033 // done twice before throwing a MissingResourceExpection.
1034 private Object handleGetObjectImpl(String aKey, UResourceBundle requested) {
1035 Object obj = resolveObject(aKey, requested);
1037 UResourceBundle parentBundle = getParent();
1038 if (parentBundle != null) {
1039 obj = parentBundle.handleGetObjectImpl(aKey, requested);
1042 throw new MissingResourceException(
1043 "Can't find resource for bundle "
1044 + this.getClass().getName() + ", key " + aKey,
1045 this.getClass().getName(), aKey);
1050 // Routine for figuring out the type of object to be returned
1051 // string or string array
1052 private Object resolveObject(String aKey, UResourceBundle requested) {
1053 if (getType() == STRING) {
1056 UResourceBundle obj = handleGet(aKey, null, requested);
1058 if (obj.getType() == STRING) {
1059 return obj.getString();
1062 if (obj.getType() == ARRAY) {
1063 return obj.handleGetStringArray();
1065 } catch (UResourceTypeMismatchException ex) {
1073 * This method is for setting the loading status of the resource.
1074 * The status is analogous to the warning status in ICU4C.
1076 * @deprecated This API is ICU internal only.
1078 protected abstract void setLoadingStatus(int newStatus);
1081 * Is this a top-level resource, that is, a whole bundle?
1082 * @return true if this is a top-level resource
1084 * @deprecated This API is ICU internal only.
1086 protected boolean isTopLevelResource() {