]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_2_1-src/src/com/ibm/icu/util/UResourceBundle.java
icu4jsrc
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / icu / util / UResourceBundle.java
1 //##header\r
2 /*\r
3  *******************************************************************************\r
4  * Copyright (C) 2004-2009, International Business Machines Corporation and    *\r
5  * others. All Rights Reserved.                                                *\r
6  *******************************************************************************\r
7  */\r
8 \r
9 package com.ibm.icu.util;\r
10 \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
19 \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
26 \r
27 //#if defined(FOUNDATION10) || defined(J2SE13) || defined(ECLIPSE_FRAGMENT)\r
28 //##import com.ibm.icu.impl.ByteBuffer;\r
29 //#else\r
30 import java.nio.ByteBuffer;\r
31 //#endif\r
32 \r
33 /**\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
38  * <P>\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
42  *\r
43  * <P>\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
48  * <P>\r
49  *\r
50  * The packaging of ICU *.res files can be of two types\r
51  * ICU4C:\r
52  * <pre>\r
53  *       root.res\r
54  *         |\r
55  *      --------\r
56  *     |        |\r
57  *   fr.res  en.res\r
58  *     |\r
59  *   --------\r
60  *  |        |\r
61  * fr_CA.res fr_FR.res\r
62  * </pre>\r
63  * JAVA/JDK:\r
64  * <pre>\r
65  *    LocaleElements.res\r
66  *         |\r
67  *      -------------------\r
68  *     |                   |\r
69  * LocaleElements_fr.res  LocaleElements_en.res\r
70  *     |\r
71  *   ---------------------------\r
72  *  |                            |\r
73  * LocaleElements_fr_CA.res   LocaleElements_fr_FR.res\r
74  * </pre>\r
75  * Depending on the organization of your resources, the syntax to getBundleInstance will change.\r
76  * To open ICU style organization use:\r
77  * <pre>\r
78  *      UResourceBundle bundle = UResourceBundle.getBundleInstance("com/mycompany/resources", "en_US", myClassLoader);\r
79  * </pre>\r
80  * To open Java/JDK style organization use:\r
81  * <pre>\r
82  *      UResourceBundle bundle = UResourceBundle.getBundleInstance("com.mycompany.resources.LocaleElements", "en_US", myClassLoader);\r
83  * </pre>\r
84  * <note>\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
88  * </note>\r
89  * @stable ICU 3.0\r
90  * @author ram\r
91  */\r
92 public abstract class UResourceBundle extends ResourceBundle{\r
93 \r
94 \r
95     /**\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
103      * @stable ICU 3.0\r
104      */\r
105     public static UResourceBundle getBundleInstance(String baseName, String localeName){\r
106         return getBundleInstance(baseName, localeName, ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);\r
107     }\r
108 \r
109     /**\r
110      * Creates a resource bundle using the specified base name, locale, and class root.\r
111      *\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
118      * @stable ICU 3.0\r
119      */\r
120     public static UResourceBundle getBundleInstance(String baseName, String localeName, ClassLoader root){\r
121         return getBundleInstance(baseName, localeName, root, false);\r
122     }\r
123 \r
124     /**\r
125      * Creates a resource bundle using the specified base name, locale, and class root.\r
126      *\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
135      * @stable ICU 3.0\r
136      *\r
137      */\r
138     protected static UResourceBundle getBundleInstance(String baseName, String localeName, ClassLoader root, boolean disableFallback) {\r
139         return instantiateBundle(baseName, localeName, root, disableFallback);\r
140     }\r
141 \r
142     /**\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
146      * @stable ICU 3.0\r
147      */\r
148     public UResourceBundle() {\r
149     }\r
150 \r
151     /**\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
157      * @stable ICU 3.0\r
158      */\r
159     public static UResourceBundle getBundleInstance(ULocale locale) {\r
160         if (locale==null) {\r
161             locale = ULocale.getDefault();\r
162         }\r
163         return getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale.toString(), ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);\r
164     }\r
165 \r
166     /**\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
172      * @stable ICU 3.0\r
173      */\r
174     public static UResourceBundle getBundleInstance(String baseName) {\r
175         if (baseName == null) {\r
176             baseName = ICUResourceBundle.ICU_BASE_NAME;\r
177         }\r
178         ULocale uloc = ULocale.getDefault();\r
179         return getBundleInstance(baseName, uloc.toString(), ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);\r
180     }\r
181 \r
182     /**\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
190      * @stable ICU 3.0\r
191      */\r
192 \r
193     public static UResourceBundle getBundleInstance(String baseName, Locale locale) {\r
194         if (baseName == null) {\r
195             baseName = ICUResourceBundle.ICU_BASE_NAME;\r
196         }\r
197         ULocale uloc = locale == null ? ULocale.getDefault() : ULocale.forLocale(locale);\r
198 \r
199         return getBundleInstance(baseName, uloc.toString(), ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);\r
200     }\r
201 \r
202     /**\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
210      * @stable ICU 3.0\r
211      */\r
212     public static UResourceBundle getBundleInstance(String baseName, ULocale locale) {\r
213         if (baseName == null) {\r
214             baseName = ICUResourceBundle.ICU_BASE_NAME;\r
215         }\r
216         if (locale == null) {\r
217             locale = ULocale.getDefault();\r
218         }\r
219         return getBundleInstance(baseName, locale.toString(), ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);\r
220     }\r
221 \r
222     /**\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
231      * @stable ICU 3.8\r
232      */\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
236         }\r
237         ULocale uloc = locale == null ? ULocale.getDefault() : ULocale.forLocale(locale);\r
238         return getBundleInstance(baseName, uloc.toString(), loader, false);\r
239     }\r
240 \r
241     /**\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
253      * @stable ICU 3.8\r
254      */\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
258         }\r
259         if (locale == null) {\r
260             locale = ULocale.getDefault();\r
261         }\r
262         return getBundleInstance(baseName, locale.toString(), loader, false);\r
263     }\r
264 \r
265     /**\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
270      *\r
271      * @return the locale of this resource bundle\r
272      * @stable ICU 3.0\r
273      */\r
274     public abstract ULocale getULocale();\r
275 \r
276     /**\r
277      * Gets the localeID\r
278      * @return The string representation of the localeID\r
279      * @stable ICU 3.0\r
280      */\r
281     protected abstract String getLocaleID();\r
282     /**\r
283      * Gets the base name of the resource bundle\r
284      * @return The string representation of the base name\r
285      * @stable ICU 3.0\r
286      */\r
287     protected abstract String getBaseName();\r
288 \r
289     /**\r
290      * Gets the parent bundle\r
291      * @return The parent bundle\r
292      * @stable ICU 3.0\r
293      */\r
294     protected abstract UResourceBundle getParent();\r
295 \r
296 \r
297     /**\r
298      * Get the locale of this bundle\r
299      * @return the locale of this resource bundle\r
300      * @stable ICU 3.0\r
301      */\r
302     public Locale getLocale(){\r
303         return getULocale().toLocale();\r
304     }\r
305 \r
306     // Cache for ResourceBundle instantiation\r
307     private static ICUCache BUNDLE_CACHE = new SimpleCache();\r
308 \r
309     /**\r
310      * @internal\r
311      */\r
312     public static void resetBundleCache()\r
313     {\r
314         /*\r
315          * A HACK!!!!!\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
322          *\r
323          */\r
324         //TODO figure a way around this method(see method comment)\r
325         BUNDLE_CACHE = new SimpleCache();\r
326     }\r
327     \r
328     private static void addToCache(ResourceCacheKey key, UResourceBundle b) {\r
329         BUNDLE_CACHE.put(key, b);\r
330     }\r
331 \r
332     /**\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
336      */\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
341         }\r
342     }\r
343     /**\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
347      */\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
352         }\r
353     }\r
354     private static UResourceBundle loadFromCache(ResourceCacheKey key) {\r
355         return (UResourceBundle)BUNDLE_CACHE.get(key);\r
356     }\r
357 \r
358     /**\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
367      */\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
373         ///CLOVER:OFF\r
374         public boolean equals(Object other) {\r
375             if (this == other) {\r
376                 return true;\r
377             }\r
378             try {\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
382                     return false;\r
383                 }\r
384                 //are the names the same?\r
385                 if (!searchName.equals(otherEntry.searchName)) {\r
386                     return false;\r
387                 }\r
388                 // are the default locales the same?\r
389                 if (defaultLocale == null) {\r
390                     if (otherEntry.defaultLocale != null) {\r
391                         return false;\r
392                     }\r
393                 } else {\r
394                     if (!defaultLocale.equals(otherEntry.defaultLocale)) {\r
395                         return false;\r
396                     }\r
397                 }\r
398                 //are refs (both non-null) or (both null)?\r
399                 if (loaderRef == null) {\r
400                     return otherEntry.loaderRef == null;\r
401                 } else {\r
402                     return (otherEntry.loaderRef != null)\r
403                             && (loaderRef.get() == otherEntry.loaderRef.get());\r
404                 }\r
405             } catch (NullPointerException e) {\r
406                 return false;\r
407             } catch (ClassCastException e) {\r
408                 return false;\r
409             }\r
410         }\r
411         public int hashCode() {\r
412             return hashCodeCache;\r
413         }\r
414         public Object clone() {\r
415             try {\r
416                 return super.clone();\r
417             } catch (CloneNotSupportedException e) {\r
418                 //this should never happen\r
419                 throw new IllegalStateException();\r
420             }\r
421         }\r
422         ///CLOVER:ON\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
429             }\r
430             if (root == null) {\r
431                 this.loaderRef = null;\r
432             } else {\r
433                 loaderRef = new SoftReference(root);\r
434                 hashCodeCache ^= root.hashCode();\r
435             }\r
436         }\r
437         /*private void clear() {\r
438             setKeyValues(null, "", null);\r
439         }*/\r
440     }\r
441 \r
442     private static final ResourceCacheKey cacheKey = new ResourceCacheKey();\r
443 \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
447 \r
448     private static SoftReference ROOT_CACHE;\r
449 \r
450     private static int getRootType(String baseName, ClassLoader root)\r
451     {\r
452         Map m = null;\r
453         Integer rootType;\r
454 \r
455         if (ROOT_CACHE != null) {\r
456             m = (Map) ROOT_CACHE.get();\r
457         }\r
458 \r
459         if (m == null) {\r
460             m = new HashMap();\r
461             ROOT_CACHE = new SoftReference(m);\r
462         }\r
463 \r
464         rootType = (Integer) m.get(baseName);\r
465 \r
466         if (rootType == null) {\r
467             String rootLocale = (baseName.indexOf('.')==-1) ? "root" : "";\r
468             int rt = ROOT_MISSING; // value set on success\r
469             try{\r
470                 ICUResourceBundle.getBundleInstance(baseName, rootLocale, root, true);\r
471                 rt = ROOT_ICU;\r
472             }catch(MissingResourceException ex){\r
473                 try{\r
474                     ResourceBundleWrapper.getBundleInstance(baseName, rootLocale, root, true);\r
475                     rt = ROOT_JAVA;\r
476                 }catch(MissingResourceException e){\r
477                     //throw away the exception\r
478                 }\r
479             }\r
480 \r
481             rootType = new Integer(rt);\r
482             m.put(baseName, rootType);\r
483         }\r
484 \r
485         return rootType.intValue();\r
486     }\r
487 \r
488     private static void setRootType(String baseName, int rootType)\r
489     {\r
490         Integer rt = new Integer(rootType);\r
491         Map m = null;\r
492 \r
493         if (ROOT_CACHE != null) {\r
494             m = (Map) ROOT_CACHE.get();\r
495         } else {\r
496             m = new HashMap();\r
497             ROOT_CACHE = new SoftReference(m);\r
498         }\r
499 \r
500         m.put(baseName, rt);\r
501     }\r
502 \r
503     /**\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
513      * @stable ICU 3.0\r
514      */\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
519 \r
520         ULocale defaultLocale = ULocale.getDefault();\r
521 \r
522         switch (rootType)\r
523         {\r
524         case ROOT_ICU:\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
530                 }\r
531 \r
532                 if (b == null) {\r
533                     b = ICUResourceBundle.getBundleInstance(baseName, localeName, root, disableFallback);\r
534                     //cacheKey.setKeyValues(root, fullName, defaultLocale);\r
535                     addToCache(cacheKey, b);\r
536                 }\r
537             } else {\r
538                 b = ICUResourceBundle.getBundleInstance(baseName, localeName, root, disableFallback);\r
539             }\r
540 \r
541             return b;\r
542 \r
543         case ROOT_JAVA:\r
544             return ResourceBundleWrapper.getBundleInstance(baseName, localeName, root, disableFallback);\r
545 \r
546         default:\r
547             try{\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
553             }\r
554             return b;\r
555         }\r
556     }\r
557 \r
558 \r
559     /**\r
560      * Returns a binary data from a binary resource.\r
561      *\r
562      * @return a pointer to a chuck of unsigned bytes which live in a memory mapped/DLL file.\r
563      * @see #getIntVector\r
564      * @see #getInt\r
565      * @throws MissingResourceException\r
566      * @throws UResourceTypeMismatchException\r
567      * @stable ICU 3.8\r
568      */\r
569     public ByteBuffer getBinary() {\r
570         throw new UResourceTypeMismatchException("");\r
571     }\r
572 \r
573     /**\r
574      * Returns a string from a string resource type\r
575      *\r
576      * @return a string\r
577      * @see #getBinary()\r
578      * @see #getIntVector\r
579      * @see #getInt\r
580      * @throws MissingResourceException\r
581      * @throws UResourceTypeMismatchException\r
582      * @stable ICU 3.8\r
583      */\r
584     public String getString() {\r
585         throw new UResourceTypeMismatchException("");\r
586     }\r
587 \r
588     /**\r
589      * Returns a string array from a array resource type\r
590      *\r
591      * @return a string\r
592      * @see #getString()\r
593      * @see #getIntVector\r
594      * @throws MissingResourceException\r
595      * @throws UResourceTypeMismatchException\r
596      * @stable ICU 3.8\r
597      */\r
598     public String[] getStringArray() {\r
599         throw new UResourceTypeMismatchException("");\r
600     }\r
601 \r
602     /**\r
603      * Returns a binary data from a binary resource.\r
604      *\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
608      * @see #getInt\r
609      * @throws MissingResourceException\r
610      * @throws UResourceTypeMismatchException\r
611      * @stable ICU 3.8\r
612      */\r
613     public byte[] getBinary(byte[] ba) {\r
614         throw new UResourceTypeMismatchException("");\r
615     }\r
616 \r
617     /**\r
618      * Returns a 32 bit integer array from a resource.\r
619      *\r
620      * @return a pointer to a chunk of unsigned bytes which live in a memory mapped/DLL file.\r
621      * @see #getBinary()\r
622      * @see #getInt\r
623      * @throws MissingResourceException\r
624      * @throws UResourceTypeMismatchException\r
625      * @stable ICU 3.8\r
626      */\r
627     public int[] getIntVector() {\r
628         throw new UResourceTypeMismatchException("");\r
629     }\r
630 \r
631     /**\r
632      * Returns a signed integer from a resource.\r
633      *\r
634      * @return an integer value\r
635      * @see #getIntVector\r
636      * @see #getBinary()\r
637      * @throws MissingResourceException\r
638      * @throws UResourceTypeMismatchException\r
639      * @stable ICU 3.8\r
640      */\r
641     public int getInt() {\r
642         throw new UResourceTypeMismatchException("");\r
643     }\r
644 \r
645     /**\r
646      * Returns a unsigned integer from a resource.\r
647      * This integer is originally 28 bit and the sign gets propagated.\r
648      *\r
649      * @return an integer value\r
650      * @see #getIntVector\r
651      * @see #getBinary()\r
652      * @throws MissingResourceException\r
653      * @throws UResourceTypeMismatchException\r
654      * @stable ICU 3.8\r
655      */\r
656     public int getUInt() {\r
657         throw new UResourceTypeMismatchException("");\r
658     }\r
659 \r
660     /**\r
661      * Returns a resource in a given resource that has a given key.\r
662      *\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
666      * @stable ICU 3.8\r
667      */\r
668     public UResourceBundle get(String aKey) {\r
669         UResourceBundle obj = handleGet(aKey, null, this);\r
670         if (obj == null) {\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
675             }\r
676             if (obj == null) {\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
682             }\r
683         }\r
684         ((ICUResourceBundle)obj).setLoadingStatus(getLocaleID());\r
685         return obj;\r
686     }\r
687 \r
688     /**\r
689      * Returns the string in a given resource at the specified index.\r
690      *\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
695      * @stable ICU 3.8\r
696      */\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
701         }\r
702         throw new UResourceTypeMismatchException("");\r
703     }\r
704 \r
705     /**\r
706      * Returns the resource in a given resource at the specified index.\r
707      *\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
712      * @stable ICU 3.8\r
713      */\r
714     public UResourceBundle get(int index) {\r
715         UResourceBundle obj = handleGet(index, null, this);\r
716         if (obj == null) {\r
717             obj = (ICUResourceBundle) getParent();\r
718             if (obj != null) {\r
719                 obj = obj.get(index);\r
720             }\r
721             if (obj == null)\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
726         }\r
727         ((ICUResourceBundle)obj).setLoadingStatus(getLocaleID());\r
728         return obj;\r
729     }\r
730     /**\r
731      * Returns the keys in this bundle as an enumeration\r
732      * @return an enumeration containing key strings\r
733      * @stable ICU 3.8\r
734      */\r
735     public Enumeration getKeys() {\r
736         initKeysVector();\r
737         return keys.elements();\r
738     }\r
739 \r
740     private Vector keys = null;\r
741     private synchronized void initKeysVector(){\r
742         if(keys!=null){\r
743             return;\r
744         }\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
751                 keys.add(elem);\r
752             }\r
753         }\r
754     }\r
755 \r
756     /**\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
763      * @stable ICU 3.8\r
764      */\r
765     public int getSize() {\r
766         return size;\r
767     }\r
768 \r
769     /**\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
774      *\r
775      * @return type of the given resource.\r
776      * @stable ICU 3.8\r
777      */\r
778     public int getType() {\r
779         int type = ICUResourceBundle.RES_GET_TYPE(resource);\r
780         if(type==TABLE32){\r
781             return TABLE; //Mask the table32's real type\r
782         }\r
783         return type;\r
784     }\r
785 \r
786     /**\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
790      * @stable ICU 3.8\r
791      */\r
792     public VersionInfo getVersion() {\r
793         return null;\r
794     }\r
795 \r
796     /**\r
797      * Returns the iterator which iterates over this\r
798      * resource bundle\r
799      * @return UResourceBundleIterator that iterates over the resources in the bundle\r
800      * @stable ICU 3.8\r
801      */\r
802     public UResourceBundleIterator getIterator() {\r
803         return new UResourceBundleIterator(this);\r
804     }\r
805     /**\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
809      * @stable ICU 3.8\r
810      */\r
811     public String getKey() {\r
812         return key;\r
813     }\r
814     /**\r
815      * Resource type constant for "no resource".\r
816      * @stable ICU 3.8\r
817      */\r
818     public static final int NONE = -1;\r
819 \r
820     /**\r
821      * Resource type constant for strings.\r
822      * @stable ICU 3.8\r
823      */\r
824     public static final int STRING = 0;\r
825 \r
826     /**\r
827      * Resource type constant for binary data.\r
828      * @stable ICU 3.8\r
829      */\r
830     public static final int BINARY = 1;\r
831 \r
832     /**\r
833      * Resource type constant for tables of key-value pairs.\r
834      * @stable ICU 3.8\r
835      */\r
836     public static final int TABLE = 2;\r
837 \r
838     /**\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
845      */\r
846     protected static final int ALIAS = 3;\r
847 \r
848     /**\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
854      */\r
855     protected static final int TABLE32 = 4;\r
856 \r
857     /**\r
858      * Resource type constant for a single 28-bit integer, interpreted as\r
859      * signed or unsigned by the getInt() function.\r
860      * @see #getInt\r
861      * @stable ICU 3.8\r
862      */\r
863     public static final int INT = 7;\r
864 \r
865     /**\r
866      * Resource type constant for arrays of resources.\r
867      * @stable ICU 3.8\r
868      */\r
869     public static final int ARRAY = 8;\r
870 \r
871     /**\r
872      * Resource type constant for vectors of 32-bit integers.\r
873      * @see #getIntVector\r
874      * @stable ICU 3.8\r
875      */\r
876     public static final int INT_VECTOR = 14;\r
877 \r
878     //====== protected members ==============\r
879     /**\r
880      * Data member where the subclasses store the key\r
881      * @internal\r
882      * @deprecated This API is ICU internal only.\r
883      */\r
884     protected String key;\r
885     /**\r
886      * Data member where the subclasses store the size of resources\r
887      * @internal\r
888      * @deprecated This API is ICU internal only.\r
889      */\r
890     protected int size = 1;\r
891     /**\r
892      * Data member where the subclasses store the offset within resource data\r
893      * @internal\r
894      * @deprecated This API is ICU internal only.\r
895      */\r
896     protected long resource = RES_BOGUS;\r
897     /**\r
898      * Data member where the subclasses store whether the resource is top level\r
899      * @internal\r
900      * @deprecated This API is ICU internal only.\r
901      */\r
902     protected boolean isTopLevel = false;\r
903 \r
904     private static final long RES_BOGUS = 0xffffffff;\r
905 \r
906     /**\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
915      * @stable ICU 3.8\r
916      */\r
917     protected UResourceBundle handleGet(String aKey, HashMap table, UResourceBundle requested) {\r
918         return null;\r
919     }\r
920 \r
921     /**\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
930      * @stable ICU 3.8\r
931      */\r
932     protected UResourceBundle handleGet(int index, HashMap table, UResourceBundle requested) {\r
933         return null;\r
934     }\r
935 \r
936     /**\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
940      * @stable ICU 3.8\r
941      */\r
942     protected String[] handleGetStringArray() {\r
943         return null;\r
944     }\r
945 \r
946     /**\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
949      *\r
950      * @return Enumeration An enumeration of all the keys in this resource.\r
951      * @stable ICU 3.8\r
952      */\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
957             item = get(i);\r
958             resKeys.add(item.getKey());\r
959         }\r
960         return resKeys.elements();\r
961     }\r
962 \r
963     /**\r
964      * {@inheritDoc}\r
965      * @stable ICU 3.8\r
966      */\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
972     }\r
973 \r
974     /**\r
975      * Override the superclass method\r
976      */\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
985         if (obj == null) {\r
986             UResourceBundle parentBundle = getParent();\r
987             if (parentBundle != null) {\r
988                 obj = parentBundle.handleGetObjectImpl(aKey, requested);\r
989             }\r
990             if (obj == null)\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
995         }\r
996         return obj;\r
997     }\r
998 \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
1004         }\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
1009             }\r
1010             try {\r
1011                 if (obj.getType() == ARRAY) {\r
1012                     return obj.handleGetStringArray();\r
1013                 }\r
1014             } catch (UResourceTypeMismatchException ex) {\r
1015                 return obj;\r
1016             }\r
1017         }\r
1018         return obj;\r
1019     }\r
1020 \r
1021     /**\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
1026      */\r
1027     protected abstract void setLoadingStatus(int newStatus);\r
1028 }\r