3 *******************************************************************************
\r
4 * Copyright (C) 2004-2009, International Business Machines Corporation and *
\r
5 * others. All Rights Reserved. *
\r
6 *******************************************************************************
\r
9 package com.ibm.icu.util;
\r
11 import java.lang.ref.SoftReference;
\r
12 import java.util.Enumeration;
\r
13 import java.util.HashMap;
\r
14 import java.util.Locale;
\r
15 import java.util.Map;
\r
16 import java.util.MissingResourceException;
\r
17 import java.util.ResourceBundle;
\r
18 import java.util.Vector;
\r
20 import com.ibm.icu.impl.ICUCache;
\r
21 import com.ibm.icu.impl.ICUResourceBundle;
\r
22 import com.ibm.icu.impl.ICUResourceBundleReader;
\r
23 import com.ibm.icu.impl.ResourceBundleWrapper;
\r
24 import com.ibm.icu.impl.SimpleCache;
\r
25 import com.ibm.icu.util.ULocale;
\r
27 //#if defined(FOUNDATION10) || defined(J2SE13) || defined(ECLIPSE_FRAGMENT)
\r
28 //##import com.ibm.icu.impl.ByteBuffer;
\r
30 import java.nio.ByteBuffer;
\r
34 * A class representing a collection of resource information pertaining to a given
\r
35 * locale. A resource bundle provides a way of accessing locale- specific information in
\r
36 * a data file. You create a resource bundle that manages the resources for a given
\r
37 * locale and then ask it for individual resources.
\r
39 * In ResourceBundle class, an object is created
\r
40 * and the sub items are fetched using getString, getObject methods.
\r
41 * In UResourceBundle,each individual element of a resource is a resource by itself.
\r
44 * Resource bundles in ICU are currently defined using text files which conform to the following
\r
45 * <a href="http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt">BNF definition</a>.
\r
46 * More on resource bundle concepts and syntax can be found in the
\r
47 * <a href="http://www.icu-project.org/userguide/ResourceManagement.html">Users Guide</a>.
\r
50 * The packaging of ICU *.res files can be of two types
\r
61 * fr_CA.res fr_FR.res
\r
65 * LocaleElements.res
\r
67 * -------------------
\r
69 * LocaleElements_fr.res LocaleElements_en.res
\r
71 * ---------------------------
\r
73 * LocaleElements_fr_CA.res LocaleElements_fr_FR.res
\r
75 * Depending on the organization of your resources, the syntax to getBundleInstance will change.
\r
76 * To open ICU style organization use:
\r
78 * UResourceBundle bundle = UResourceBundle.getBundleInstance("com/mycompany/resources", "en_US", myClassLoader);
\r
80 * To open Java/JDK style organization use:
\r
82 * UResourceBundle bundle = UResourceBundle.getBundleInstance("com.mycompany.resources.LocaleElements", "en_US", myClassLoader);
\r
85 * Please use pass a class loader for loading non-ICU resources. Java security does not
\r
86 * allow loading of resources across jar files. You must provide your class loader
\r
87 * to load the resources
\r
92 public abstract class UResourceBundle extends ResourceBundle{
\r
96 * Creates a resource bundle using the specified base name and locale.
\r
97 * ICU_DATA_CLASS is used as the default root.
\r
98 * @param baseName the base name of the resource bundle, a fully qualified class name
\r
99 * @param localeName the locale for which a resource bundle is desired
\r
100 * @exception MissingResourceException
\r
101 * if no resource bundle for the specified base name can be found
\r
102 * @return a resource bundle for the given base name and locale
\r
105 public static UResourceBundle getBundleInstance(String baseName, String localeName){
\r
106 return getBundleInstance(baseName, localeName, ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);
\r
110 * Creates a resource bundle using the specified base name, locale, and class root.
\r
112 * @param baseName the base name of the resource bundle, a fully qualified class name
\r
113 * @param localeName the locale for which a resource bundle is desired
\r
114 * @param root the class object from which to load the resource bundle
\r
115 * @exception MissingResourceException
\r
116 * if no resource bundle for the specified base name can be found
\r
117 * @return a resource bundle for the given base name and locale
\r
120 public static UResourceBundle getBundleInstance(String baseName, String localeName, ClassLoader root){
\r
121 return getBundleInstance(baseName, localeName, root, false);
\r
125 * Creates a resource bundle using the specified base name, locale, and class root.
\r
127 * @param baseName the base name of the resource bundle, a fully qualified class name
\r
128 * @param localeName the locale for which a resource bundle is desired
\r
129 * @param root the class object from which to load the resource bundle
\r
130 * @param disableFallback Option to disable locale inheritence.
\r
131 * If true the fallback chain will not be built.
\r
132 * @exception MissingResourceException
\r
133 * if no resource bundle for the specified base name can be found
\r
134 * @return a resource bundle for the given base name and locale
\r
138 protected static UResourceBundle getBundleInstance(String baseName, String localeName, ClassLoader root, boolean disableFallback) {
\r
139 return instantiateBundle(baseName, localeName, root, disableFallback);
\r
143 * Sole constructor. (For invocation by subclass constructors, typically
\r
144 * implicit.) This is public for compatibility with Java, whose compiler
\r
145 * will generate public default constructors for an abstract class.
\r
148 public UResourceBundle() {
\r
152 * Creates a UResourceBundle for the locale specified, from which users can extract resources by using
\r
153 * their corresponding keys.
\r
154 * @param locale specifies the locale for which we want to open the resource.
\r
155 * If null the bundle for default locale is opened.
\r
156 * @return a resource bundle for the given locale
\r
159 public static UResourceBundle getBundleInstance(ULocale locale) {
\r
160 if (locale==null) {
\r
161 locale = ULocale.getDefault();
\r
163 return getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale.toString(), ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);
\r
167 * Creates a UResourceBundle for the default locale and specified base name,
\r
168 * from which users can extract resources by using their corresponding keys.
\r
169 * @param baseName specifies the locale for which we want to open the resource.
\r
170 * If null the bundle for default locale is opened.
\r
171 * @return a resource bundle for the given base name and default locale
\r
174 public static UResourceBundle getBundleInstance(String baseName) {
\r
175 if (baseName == null) {
\r
176 baseName = ICUResourceBundle.ICU_BASE_NAME;
\r
178 ULocale uloc = ULocale.getDefault();
\r
179 return getBundleInstance(baseName, uloc.toString(), ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);
\r
183 * Creates a UResourceBundle for the specified locale and specified base name,
\r
184 * from which users can extract resources by using their corresponding keys.
\r
185 * @param baseName specifies the locale for which we want to open the resource.
\r
186 * If null the bundle for default locale is opened.
\r
187 * @param locale specifies the locale for which we want to open the resource.
\r
188 * If null the bundle for default locale is opened.
\r
189 * @return a resource bundle for the given base name and locale
\r
193 public static UResourceBundle getBundleInstance(String baseName, Locale locale) {
\r
194 if (baseName == null) {
\r
195 baseName = ICUResourceBundle.ICU_BASE_NAME;
\r
197 ULocale uloc = locale == null ? ULocale.getDefault() : ULocale.forLocale(locale);
\r
199 return getBundleInstance(baseName, uloc.toString(), ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);
\r
203 * Creates a UResourceBundle, from which users can extract resources by using
\r
204 * their corresponding keys.
\r
205 * @param baseName string containing the name of the data package.
\r
206 * If null the default ICU package name is used.
\r
207 * @param locale specifies the locale for which we want to open the resource.
\r
208 * If null the bundle for default locale is opened.
\r
209 * @return a resource bundle for the given base name and locale
\r
212 public static UResourceBundle getBundleInstance(String baseName, ULocale locale) {
\r
213 if (baseName == null) {
\r
214 baseName = ICUResourceBundle.ICU_BASE_NAME;
\r
216 if (locale == null) {
\r
217 locale = ULocale.getDefault();
\r
219 return getBundleInstance(baseName, locale.toString(), ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);
\r
223 * Creates a UResourceBundle for the specified locale and specified base name,
\r
224 * from which users can extract resources by using their corresponding keys.
\r
225 * @param baseName specifies the locale for which we want to open the resource.
\r
226 * If null the bundle for default locale is opened.
\r
227 * @param locale specifies the locale for which we want to open the resource.
\r
228 * If null the bundle for default locale is opened.
\r
229 * @param loader the loader to use
\r
230 * @return a resource bundle for the given base name and locale
\r
233 public static UResourceBundle getBundleInstance(String baseName, Locale locale, ClassLoader loader) {
\r
234 if (baseName == null) {
\r
235 baseName = ICUResourceBundle.ICU_BASE_NAME;
\r
237 ULocale uloc = locale == null ? ULocale.getDefault() : ULocale.forLocale(locale);
\r
238 return getBundleInstance(baseName, uloc.toString(), loader, false);
\r
242 * Creates a UResourceBundle, from which users can extract resources by using
\r
243 * their corresponding keys.<br><br>
\r
244 * Note: Please use this API for loading non-ICU resources. Java security does not
\r
245 * allow loading of resources across jar files. You must provide your class loader
\r
246 * to load the resources
\r
247 * @param baseName string containing the name of the data package.
\r
248 * If null the default ICU package name is used.
\r
249 * @param locale specifies the locale for which we want to open the resource.
\r
250 * If null the bundle for default locale is opened.
\r
251 * @param loader the loader to use
\r
252 * @return a resource bundle for the given base name and locale
\r
255 public static UResourceBundle getBundleInstance(String baseName, ULocale locale, ClassLoader loader) {
\r
256 if (baseName == null) {
\r
257 baseName = ICUResourceBundle.ICU_BASE_NAME;
\r
259 if (locale == null) {
\r
260 locale = ULocale.getDefault();
\r
262 return getBundleInstance(baseName, locale.toString(), loader, false);
\r
266 * Returns the RFC 3066 conformant locale id of this resource bundle.
\r
267 * This method can be used after a call to getBundleInstance() to
\r
268 * determine whether the resource bundle returned really
\r
269 * corresponds to the requested locale or is a fallback.
\r
271 * @return the locale of this resource bundle
\r
274 public abstract ULocale getULocale();
\r
277 * Gets the localeID
\r
278 * @return The string representation of the localeID
\r
281 protected abstract String getLocaleID();
\r
283 * Gets the base name of the resource bundle
\r
284 * @return The string representation of the base name
\r
287 protected abstract String getBaseName();
\r
290 * Gets the parent bundle
\r
291 * @return The parent bundle
\r
294 protected abstract UResourceBundle getParent();
\r
298 * Get the locale of this bundle
\r
299 * @return the locale of this resource bundle
\r
302 public Locale getLocale(){
\r
303 return getULocale().toLocale();
\r
306 // Cache for ResourceBundle instantiation
\r
307 private static ICUCache BUNDLE_CACHE = new SimpleCache();
\r
312 public static void resetBundleCache()
\r
316 * Currently if a resourcebundle with fallback turned ON is added to the cache
\r
317 * and then a getBundleInstance() is called for a bundle with fallback turned OFF
\r
318 * it will actually search the cache for any bundle of the same locale
\r
319 * regaurdless of fallback status. This method has been created so that if
\r
320 * The calling method KNOWS that instances of the other fallback state may be in the
\r
321 * cache, the calling method may call this method to clear out the cache.
\r
324 //TODO figure a way around this method(see method comment)
\r
325 BUNDLE_CACHE = new SimpleCache();
\r
328 private static void addToCache(ResourceCacheKey key, UResourceBundle b) {
\r
329 BUNDLE_CACHE.put(key, b);
\r
333 * Method used by subclasses to add the a particular resource bundle object to the managed cache
\r
334 * @internal revisit for ICU 3.6
\r
335 * @deprecated This API is ICU internal only.
\r
337 protected static void addToCache(ClassLoader cl, String fullName, ULocale defaultLocale, UResourceBundle b){
\r
338 synchronized(cacheKey){
\r
339 cacheKey.setKeyValues(cl, fullName, defaultLocale);
\r
340 addToCache((ResourceCacheKey)cacheKey.clone(), b);
\r
344 * Method used by sub classes to load a resource bundle object from the managed cache
\r
345 * @internal revisit for ICU 3.6
\r
346 * @deprecated This API is ICU internal only.
\r
348 protected static UResourceBundle loadFromCache(ClassLoader cl, String fullName, ULocale defaultLocale){
\r
349 synchronized(cacheKey){
\r
350 cacheKey.setKeyValues(cl, fullName, defaultLocale);
\r
351 return loadFromCache(cacheKey);
\r
354 private static UResourceBundle loadFromCache(ResourceCacheKey key) {
\r
355 return (UResourceBundle)BUNDLE_CACHE.get(key);
\r
359 * Key used for cached resource bundles. The key checks
\r
360 * the resource name, the class root, and the default
\r
361 * locale to determine if the resource is a match to the
\r
362 * requested one. The root may be null, but the
\r
363 * searchName and the default locale must have a non-null value.
\r
364 * Note that the default locale may change over time, and
\r
365 * lookup should always be based on the current default
\r
366 * locale (if at all).
\r
368 private static final class ResourceCacheKey implements Cloneable {
\r
369 private SoftReference loaderRef;
\r
370 private String searchName;
\r
371 private ULocale defaultLocale;
\r
372 private int hashCodeCache;
\r
374 public boolean equals(Object other) {
\r
375 if (this == other) {
\r
379 final ResourceCacheKey otherEntry = (ResourceCacheKey) other;
\r
380 //quick check to see if they are not equal
\r
381 if (hashCodeCache != otherEntry.hashCodeCache) {
\r
384 //are the names the same?
\r
385 if (!searchName.equals(otherEntry.searchName)) {
\r
388 // are the default locales the same?
\r
389 if (defaultLocale == null) {
\r
390 if (otherEntry.defaultLocale != null) {
\r
394 if (!defaultLocale.equals(otherEntry.defaultLocale)) {
\r
398 //are refs (both non-null) or (both null)?
\r
399 if (loaderRef == null) {
\r
400 return otherEntry.loaderRef == null;
\r
402 return (otherEntry.loaderRef != null)
\r
403 && (loaderRef.get() == otherEntry.loaderRef.get());
\r
405 } catch (NullPointerException e) {
\r
407 } catch (ClassCastException e) {
\r
411 public int hashCode() {
\r
412 return hashCodeCache;
\r
414 public Object clone() {
\r
416 return super.clone();
\r
417 } catch (CloneNotSupportedException e) {
\r
418 //this should never happen
\r
419 throw new IllegalStateException();
\r
423 private synchronized void setKeyValues(ClassLoader root, String searchName, ULocale defaultLocale) {
\r
424 this.searchName = searchName;
\r
425 hashCodeCache = searchName.hashCode();
\r
426 this.defaultLocale = defaultLocale;
\r
427 if (defaultLocale != null) {
\r
428 hashCodeCache ^= defaultLocale.hashCode();
\r
430 if (root == null) {
\r
431 this.loaderRef = null;
\r
433 loaderRef = new SoftReference(root);
\r
434 hashCodeCache ^= root.hashCode();
\r
437 /*private void clear() {
\r
438 setKeyValues(null, "", null);
\r
442 private static final ResourceCacheKey cacheKey = new ResourceCacheKey();
\r
444 private static final int ROOT_MISSING = 0;
\r
445 private static final int ROOT_ICU = 1;
\r
446 private static final int ROOT_JAVA = 2;
\r
448 private static SoftReference ROOT_CACHE;
\r
450 private static int getRootType(String baseName, ClassLoader root)
\r
455 if (ROOT_CACHE != null) {
\r
456 m = (Map) ROOT_CACHE.get();
\r
461 ROOT_CACHE = new SoftReference(m);
\r
464 rootType = (Integer) m.get(baseName);
\r
466 if (rootType == null) {
\r
467 String rootLocale = (baseName.indexOf('.')==-1) ? "root" : "";
\r
468 int rt = ROOT_MISSING; // value set on success
\r
470 ICUResourceBundle.getBundleInstance(baseName, rootLocale, root, true);
\r
472 }catch(MissingResourceException ex){
\r
474 ResourceBundleWrapper.getBundleInstance(baseName, rootLocale, root, true);
\r
476 }catch(MissingResourceException e){
\r
477 //throw away the exception
\r
481 rootType = new Integer(rt);
\r
482 m.put(baseName, rootType);
\r
485 return rootType.intValue();
\r
488 private static void setRootType(String baseName, int rootType)
\r
490 Integer rt = new Integer(rootType);
\r
493 if (ROOT_CACHE != null) {
\r
494 m = (Map) ROOT_CACHE.get();
\r
497 ROOT_CACHE = new SoftReference(m);
\r
500 m.put(baseName, rt);
\r
504 * Loads a new resource bundle for the give base name, locale and class loader.
\r
505 * Optionally will disable loading of fallback bundles.
\r
506 * @param baseName the base name of the resource bundle, a fully qualified class name
\r
507 * @param localeName the locale for which a resource bundle is desired
\r
508 * @param root the class object from which to load the resource bundle
\r
509 * @param disableFallback disables loading of fallback lookup chain
\r
510 * @exception MissingResourceException
\r
511 * if no resource bundle for the specified base name can be found
\r
512 * @return a resource bundle for the given base name and locale
\r
515 protected static UResourceBundle instantiateBundle(String baseName, String localeName,
\r
516 ClassLoader root, boolean disableFallback){
\r
517 UResourceBundle b = null;
\r
518 int rootType = getRootType(baseName, root);
\r
520 ULocale defaultLocale = ULocale.getDefault();
\r
525 if(disableFallback) {
\r
526 String fullName = ICUResourceBundleReader.getFullName(baseName, localeName);
\r
527 synchronized(cacheKey){
\r
528 cacheKey.setKeyValues(root, fullName, defaultLocale);
\r
529 b = loadFromCache(cacheKey);
\r
533 b = ICUResourceBundle.getBundleInstance(baseName, localeName, root, disableFallback);
\r
534 //cacheKey.setKeyValues(root, fullName, defaultLocale);
\r
535 addToCache(cacheKey, b);
\r
538 b = ICUResourceBundle.getBundleInstance(baseName, localeName, root, disableFallback);
\r
544 return ResourceBundleWrapper.getBundleInstance(baseName, localeName, root, disableFallback);
\r
548 b = ICUResourceBundle.getBundleInstance(baseName, localeName, root, disableFallback);
\r
549 setRootType(baseName, ROOT_ICU);
\r
550 }catch(MissingResourceException ex){
\r
551 b = ResourceBundleWrapper.getBundleInstance(baseName, localeName, root, disableFallback);
\r
552 setRootType(baseName, ROOT_JAVA);
\r
560 * Returns a binary data from a binary resource.
\r
562 * @return a pointer to a chuck of unsigned bytes which live in a memory mapped/DLL file.
\r
563 * @see #getIntVector
\r
565 * @throws MissingResourceException
\r
566 * @throws UResourceTypeMismatchException
\r
569 public ByteBuffer getBinary() {
\r
570 throw new UResourceTypeMismatchException("");
\r
574 * Returns a string from a string resource type
\r
577 * @see #getBinary()
\r
578 * @see #getIntVector
\r
580 * @throws MissingResourceException
\r
581 * @throws UResourceTypeMismatchException
\r
584 public String getString() {
\r
585 throw new UResourceTypeMismatchException("");
\r
589 * Returns a string array from a array resource type
\r
592 * @see #getString()
\r
593 * @see #getIntVector
\r
594 * @throws MissingResourceException
\r
595 * @throws UResourceTypeMismatchException
\r
598 public String[] getStringArray() {
\r
599 throw new UResourceTypeMismatchException("");
\r
603 * Returns a binary data from a binary resource.
\r
605 * @param ba The byte array to write the bytes to. A null variable is OK.
\r
606 * @return an array bytes containing the binary data from the resource.
\r
607 * @see #getIntVector
\r
609 * @throws MissingResourceException
\r
610 * @throws UResourceTypeMismatchException
\r
613 public byte[] getBinary(byte[] ba) {
\r
614 throw new UResourceTypeMismatchException("");
\r
618 * Returns a 32 bit integer array from a resource.
\r
620 * @return a pointer to a chunk of unsigned bytes which live in a memory mapped/DLL file.
\r
621 * @see #getBinary()
\r
623 * @throws MissingResourceException
\r
624 * @throws UResourceTypeMismatchException
\r
627 public int[] getIntVector() {
\r
628 throw new UResourceTypeMismatchException("");
\r
632 * Returns a signed integer from a resource.
\r
634 * @return an integer value
\r
635 * @see #getIntVector
\r
636 * @see #getBinary()
\r
637 * @throws MissingResourceException
\r
638 * @throws UResourceTypeMismatchException
\r
641 public int getInt() {
\r
642 throw new UResourceTypeMismatchException("");
\r
646 * Returns a unsigned integer from a resource.
\r
647 * This integer is originally 28 bit and the sign gets propagated.
\r
649 * @return an integer value
\r
650 * @see #getIntVector
\r
651 * @see #getBinary()
\r
652 * @throws MissingResourceException
\r
653 * @throws UResourceTypeMismatchException
\r
656 public int getUInt() {
\r
657 throw new UResourceTypeMismatchException("");
\r
661 * Returns a resource in a given resource that has a given key.
\r
663 * @param aKey a key associated with the wanted resource
\r
664 * @return a resource bundle object representing the resource
\r
665 * @throws MissingResourceException
\r
668 public UResourceBundle get(String aKey) {
\r
669 UResourceBundle obj = handleGet(aKey, null, this);
\r
671 UResourceBundle res = this;
\r
672 while ((res = res.getParent()) != null && obj == null) {
\r
673 //call the get method to recursively fetch the resource
\r
674 obj = res.handleGet(aKey, null, this);
\r
677 String fullName = ICUResourceBundleReader.getFullName(
\r
678 getBaseName(), getLocaleID());
\r
679 throw new MissingResourceException(
\r
680 "Can't find resource for bundle " + fullName + ", key "
\r
681 + aKey, this.getClass().getName(), aKey);
\r
684 ((ICUResourceBundle)obj).setLoadingStatus(getLocaleID());
\r
689 * Returns the string in a given resource at the specified index.
\r
691 * @param index an index to the wanted string.
\r
692 * @return a string which lives in the resource.
\r
693 * @throws IndexOutOfBoundsException
\r
694 * @throws UResourceTypeMismatchException
\r
697 public String getString(int index) {
\r
698 ICUResourceBundle temp = (ICUResourceBundle)get(index);
\r
699 if (temp.getType() == STRING) {
\r
700 return temp.getString();
\r
702 throw new UResourceTypeMismatchException("");
\r
706 * Returns the resource in a given resource at the specified index.
\r
708 * @param index an index to the wanted resource.
\r
709 * @return the sub resource UResourceBundle object
\r
710 * @throws IndexOutOfBoundsException
\r
711 * @throws MissingResourceException
\r
714 public UResourceBundle get(int index) {
\r
715 UResourceBundle obj = handleGet(index, null, this);
\r
717 obj = (ICUResourceBundle) getParent();
\r
719 obj = obj.get(index);
\r
722 throw new MissingResourceException(
\r
723 "Can't find resource for bundle "
\r
724 + this.getClass().getName() + ", key "
\r
725 + getKey(), this.getClass().getName(), getKey());
\r
727 ((ICUResourceBundle)obj).setLoadingStatus(getLocaleID());
\r
731 * Returns the keys in this bundle as an enumeration
\r
732 * @return an enumeration containing key strings
\r
735 public Enumeration getKeys() {
\r
737 return keys.elements();
\r
740 private Vector keys = null;
\r
741 private synchronized void initKeysVector(){
\r
745 //ICUResourceBundle current = this;
\r
746 keys = new Vector();
\r
747 Enumeration e = this.handleGetKeys();
\r
748 while(e.hasMoreElements()){
\r
749 String elem = (String)e.nextElement();
\r
750 if(!keys.contains(elem)){
\r
757 * Returns the size of a resource. Size for scalar types is always 1,
\r
758 * and for vector/table types is the number of child resources.
\r
759 * <br><b><font color='red'>Warning: </font></b> Integer array is treated as a scalar type. There are no
\r
760 * APIs to access individual members of an integer array. It
\r
761 * is always returned as a whole.
\r
762 * @return number of resources in a given resource.
\r
765 public int getSize() {
\r
770 * Returns the type of a resource.
\r
771 * Available types are {@link #INT INT}, {@link #ARRAY ARRAY},
\r
772 * {@link #BINARY BINARY}, {@link #INT_VECTOR INT_VECTOR},
\r
773 * {@link #STRING STRING}, {@link #TABLE TABLE}.
\r
775 * @return type of the given resource.
\r
778 public int getType() {
\r
779 int type = ICUResourceBundle.RES_GET_TYPE(resource);
\r
781 return TABLE; //Mask the table32's real type
\r
787 * Return the version number associated with this UResourceBundle as an
\r
788 * VersionInfo object.
\r
789 * @return VersionInfo object containing the version of the bundle
\r
792 public VersionInfo getVersion() {
\r
797 * Returns the iterator which iterates over this
\r
799 * @return UResourceBundleIterator that iterates over the resources in the bundle
\r
802 public UResourceBundleIterator getIterator() {
\r
803 return new UResourceBundleIterator(this);
\r
806 * Returns the key associated with a given resource. Not all the resources have a key - only
\r
807 * those that are members of a table.
\r
808 * @return a key associated to this resource, or null if it doesn't have a key
\r
811 public String getKey() {
\r
815 * Resource type constant for "no resource".
\r
818 public static final int NONE = -1;
\r
821 * Resource type constant for strings.
\r
824 public static final int STRING = 0;
\r
827 * Resource type constant for binary data.
\r
830 public static final int BINARY = 1;
\r
833 * Resource type constant for tables of key-value pairs.
\r
836 public static final int TABLE = 2;
\r
839 * Resource type constant for aliases;
\r
840 * internally stores a string which identifies the actual resource
\r
841 * storing the data (can be in a different resource bundle).
\r
842 * Resolved internally before delivering the actual resource through the API.
\r
843 * @internal ICU 3.8
\r
844 * @deprecated This API is ICU internal only.
\r
846 protected static final int ALIAS = 3;
\r
849 * Internal use only.
\r
850 * Alternative resource type constant for tables of key-value pairs.
\r
851 * Never returned by getType().
\r
852 * @internal ICU 3.8
\r
853 * @deprecated This API is ICU internal only.
\r
855 protected static final int TABLE32 = 4;
\r
858 * Resource type constant for a single 28-bit integer, interpreted as
\r
859 * signed or unsigned by the getInt() function.
\r
863 public static final int INT = 7;
\r
866 * Resource type constant for arrays of resources.
\r
869 public static final int ARRAY = 8;
\r
872 * Resource type constant for vectors of 32-bit integers.
\r
873 * @see #getIntVector
\r
876 public static final int INT_VECTOR = 14;
\r
878 //====== protected members ==============
\r
880 * Data member where the subclasses store the key
\r
882 * @deprecated This API is ICU internal only.
\r
884 protected String key;
\r
886 * Data member where the subclasses store the size of resources
\r
888 * @deprecated This API is ICU internal only.
\r
890 protected int size = 1;
\r
892 * Data member where the subclasses store the offset within resource data
\r
894 * @deprecated This API is ICU internal only.
\r
896 protected long resource = RES_BOGUS;
\r
898 * Data member where the subclasses store whether the resource is top level
\r
900 * @deprecated This API is ICU internal only.
\r
902 protected boolean isTopLevel = false;
\r
904 private static final long RES_BOGUS = 0xffffffff;
\r
907 * Actual worker method for fetching a resource based on the given key.
\r
908 * Sub classes must override this method if they support resources with keys.
\r
909 * @param aKey the key string of the resource to be fetched
\r
910 * @param table hashtable object to hold references of resources already seen
\r
911 * @param requested the original resource bundle object on which the get method was invoked.
\r
912 * The requested bundle and the bundle on which this method is invoked
\r
913 * are the same, except in the cases where aliases are involved.
\r
914 * @return UResourceBundle a resource associated with the key
\r
917 protected UResourceBundle handleGet(String aKey, HashMap table, UResourceBundle requested) {
\r
922 * Actual worker method for fetching a resource based on the given index.
\r
923 * Sub classes must override this method if they support arrays of resources.
\r
924 * @param index the index of the resource to be fetched
\r
925 * @param table hashtable object to hold references of resources already seen
\r
926 * @param requested the original resource bundle object on which the get method was invoked.
\r
927 * The requested bundle and the bundle on which this method is invoked
\r
928 * are the same, except in the cases where aliases are involved.
\r
929 * @return UResourceBundle a resource associated with the index
\r
932 protected UResourceBundle handleGet(int index, HashMap table, UResourceBundle requested) {
\r
937 * Actual worker method for fetching the array of strings in a resource.
\r
938 * Sub classes must override this method if they support arrays of strings.
\r
939 * @return String[] An array of strings containing strings
\r
942 protected String[] handleGetStringArray() {
\r
947 * Actual worker method for fetching the keys of resources contained in the resource.
\r
948 * Sub classes must override this method if they support keys and associated resources.
\r
950 * @return Enumeration An enumeration of all the keys in this resource.
\r
953 protected Enumeration handleGetKeys(){
\r
954 Vector resKeys = new Vector();
\r
955 UResourceBundle item = null;
\r
956 for (int i = 0; i < size; i++) {
\r
958 resKeys.add(item.getKey());
\r
960 return resKeys.elements();
\r
967 // this method is declared in ResourceBundle class
\r
968 // so cannot change the signature
\r
969 // Override this method
\r
970 protected Object handleGetObject(String aKey) {
\r
971 return handleGetObjectImpl(aKey, this);
\r
975 * Override the superclass method
\r
977 // To facilitate XPath style aliases we need a way to pass the reference
\r
978 // to requested locale. The only way I could figure out is to implement
\r
979 // the look up logic here. This has a disadvantage that if the client
\r
980 // loads an ICUResourceBundle, calls ResourceBundle.getObject method
\r
981 // with a key that does not exist in the bundle then the lookup is
\r
982 // done twice before throwing a MissingResourceExpection.
\r
983 private Object handleGetObjectImpl(String aKey, UResourceBundle requested) {
\r
984 Object obj = resolveObject(aKey, requested);
\r
986 UResourceBundle parentBundle = getParent();
\r
987 if (parentBundle != null) {
\r
988 obj = parentBundle.handleGetObjectImpl(aKey, requested);
\r
991 throw new MissingResourceException(
\r
992 "Can't find resource for bundle "
\r
993 + this.getClass().getName() + ", key " + aKey,
\r
994 this.getClass().getName(), aKey);
\r
999 // Routine for figuring out the type of object to be returned
\r
1000 // string or string array
\r
1001 private Object resolveObject(String aKey, UResourceBundle requested) {
\r
1002 if (getType() == STRING) {
\r
1003 return getString();
\r
1005 UResourceBundle obj = handleGet(aKey, null, requested);
\r
1006 if (obj != null) {
\r
1007 if (obj.getType() == STRING) {
\r
1008 return obj.getString();
\r
1011 if (obj.getType() == ARRAY) {
\r
1012 return obj.handleGetStringArray();
\r
1014 } catch (UResourceTypeMismatchException ex) {
\r
1022 * This method is for setting the loading status of the resource.
\r
1023 * The status is analogous to the warning status in ICU4C.
\r
1024 * @internal ICU 3.8
\r
1025 * @deprecated This API is ICU internal only.
\r
1027 protected abstract void setLoadingStatus(int newStatus);
\r