/[classpath]/classpath/java/util/ResourceBundle.java
ViewVC logotype

Diff of /classpath/java/util/ResourceBundle.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.15 by ericb, Fri Mar 22 21:25:19 2002 UTC revision 1.16 by ericb, Sun Mar 24 23:42:38 2002 UTC
# Line 47  import java.security.PrivilegedAction; Line 47  import java.security.PrivilegedAction;
47  import gnu.classpath.Configuration;  import gnu.classpath.Configuration;
48    
49  /**  /**
50   * A resource bundle contains locale-specific data.  If you need   * A resource bundle contains locale-specific data. If you need localized
51   * localized data, you can load a resource bundle that matches the   * data, you can load a resource bundle that matches the locale with
52   * locale with <code>getBundle</code>.  Now you can get your object by   * <code>getBundle</code>. Now you can get your object by calling
53   * calling <code>getObject</code> or <code>getString</code> on that   * <code>getObject</code> or <code>getString</code> on that bundle.
54   * bundle.   *
55   * <br>   * <p>When a bundle is demanded for a specific locale, the ResourceBundle
56   * When a bundle is demanded for a specific locale, the ResourceBundle   * is searched in following order (<i>def. language<i> stands for the
57   * is searched in following order (<i>def. language code<i> stands for   * two letter ISO language code of the default locale (see
  * the two letter ISO language code of the default locale (see  
58   * <code>Locale.getDefault()</code>).   * <code>Locale.getDefault()</code>).
59   * <pre>   * <pre>
60   * baseName_<i>language code</i>_<i>country code</i>_<i>variant</i>   * baseName_<i>language code</i>_<i>country code</i>_<i>variant</i>
61   * baseName_<i>language code</i>_<i>country code</i>   * baseName_<i>language code</i>_<i>country code</i>
62   * baseName_<i>language code</i>   * baseName_<i>language code</i>
63   * baseName_<i>def. language code</i>_<i>def. country code</i>_<i>def. variant</i>   * baseName_<i>def. language</i>_<i>def. country</i>_<i>def. variant</i>
64   * baseName_<i>def. language code</i>_<i>def. country code</i>   * baseName_<i>def. language</i>_<i>def. country</i>
65   * baseName_<i>def. language code</i>   * baseName_<i>def. language</i>
66   * baseName   * baseName
67   * </pre>   * </pre>
68   *   *
69   * A bundle is backed up, by less specific bundle (omiting variant,   * A bundle is backed up by less specific bundles (omiting variant, country
70   * country or language). But it is not backed up by the default   * or language). But it is not backed up by the default language locale.
71   * language locale.   *
72   * <br>   * <p>If you provide a bundle for a given locale, say
  * If you provide a bundle for a given locale, say  
73   * <code>Bundle_en_UK_POSIX</code>, you must also provide a bundle for   * <code>Bundle_en_UK_POSIX</code>, you must also provide a bundle for
74   * all sub locales, ie. <code>Bundle_en_UK</code>, <code>Bundle_en</code>, and   * all sub locales, ie. <code>Bundle_en_UK</code>, <code>Bundle_en</code>, and
75   * <code>Bundle</code>.   * <code>Bundle</code>.
  * <br>  
  * When a bundle is searched, we look first for a class with  
  * the given name and if that is not found for a file with  
  * <code>.properties</code> extension in the classpath.  The name  
  * must be a fully qualified classname (with dots as path separators).  
  * <br>  
  * (Note: This implementation always backs up the class with a  
  * properties file if that is existing, but you shouldn't rely on  
  * this, if you want to be compatible to the standard JDK.)  
76   *   *
77     * <p>When a bundle is searched, we look first for a class with the given
78     * name, then for a file with <code>.properties</code> extension in the
79     * classpath. The name must be a fully qualified classname (with dots as
80     * path separators).
81     *
82     * <p>(Note: This implementation always backs up the class with a properties
83     * file if that is existing, but you shouldn't rely on this, if you want to
84     * be compatible to the standard JDK.)
85     *
86     * @author Jochen Hoenicke
87     * @author Eric Blake <ebb9@email.byu.edu>
88   * @see Locale   * @see Locale
89     * @see ListResourceBundle
90   * @see PropertyResourceBundle   * @see PropertyResourceBundle
91   * @author Jochen Hoenicke */   * @since 1.1
92     * @status updated to 1.4
93     */
94  public abstract class ResourceBundle  public abstract class ResourceBundle
95  {  {
96    /**    /**
97     * The parent bundle.  This is consulted when you call getObject     * The parent bundle. This is consulted when you call getObject and there
98     * and there is no such resource in the current bundle.  This     * is no such resource in the current bundle. This field may be null.
    * field may be null.  
99     */     */
100    protected ResourceBundle parent;    protected ResourceBundle parent;
101    
102    /**    /**
103     * The locale of this resource bundle.  You can read this with     * The locale of this resource bundle. You can read this with
104     * <code>getLocale</code> and it is automatically set in     * <code>getLocale</code> and it is automatically set in
105     * <code>getBundle</code>.     * <code>getBundle</code>.
106     */     */
# Line 107  public abstract class ResourceBundle Line 109  public abstract class ResourceBundle
109    /**    /**
110     * We override SecurityManager in order to access getClassContext().     * We override SecurityManager in order to access getClassContext().
111     */     */
112    static class Security extends SecurityManager    private static final class Security extends SecurityManager
113    {    {
114      /** Return the ClassLoader of the class which called into this      /**
115          ResourceBundle, or null if it cannot be determined. */       * Avoid accessor method of private constructor.
116         */
117        Security()
118        {
119        }
120    
121        /**
122         * Return the ClassLoader of the class which called into this
123         * ResourceBundle, or null if it cannot be determined.
124         */
125      ClassLoader getCallingClassLoader()      ClassLoader getCallingClassLoader()
126      {      {
127        Class[] stack = super.getClassContext();        Class[] stack = getClassContext();
128        for (int i = 0; i < stack.length; i++)        for (int i = 0; i < stack.length; i++)
129          if (stack[i] != Security.class && stack[i] != ResourceBundle.class)          if (stack[i] != Security.class && stack[i] != ResourceBundle.class)
130            return stack[i].getClassLoader();            return stack[i].getClassLoader();
131        return null;        return null;
132      }      }
133    }    }
134    
135    // This will always work since java.util classes have (all) system    /** A security context for grabbing the correct class loader. */
136    // permissions.    private static final Security security
137    static Security security = (Security) AccessController.doPrivileged      = (Security) AccessController.doPrivileged(new PrivilegedAction()
     (  
       new PrivilegedAction()  
138        {        {
139            // This will always work since java.util classes have (all) system
140            // permissions.
141          public Object run()          public Object run()
142          {          {
143            return new Security();            return new Security();
# Line 135  public abstract class ResourceBundle Line 146  public abstract class ResourceBundle
146      );      );
147    
148    /**    /**
149     * The constructor.  It does nothing special.     * The resource bundle cache. This is a two-level hash map: The key
150       * is the class loader, the value is a new HashMap. The key of this
151       * second hash map is the localized name, the value is a soft
152       * references to the resource bundle.
153       */
154      private static final Map resourceBundleCache = new HashMap();
155    
156      /**
157       * The `empty' locale is created once in order to optimize
158       * tryBundle().
159       */
160      private static final Locale emptyLocale = new Locale("");
161    
162      /**
163       * The constructor. It does nothing special.
164     */     */
165    public ResourceBundle()    public ResourceBundle()
166    {    {
167    }    }
168    
169    /**    /**
170     * Get a String from this resource bundle.  Since most localized     * Get a String from this resource bundle. Since most localized Objects
171     * Objects are Strings, this method provides a convenient way to get     * are Strings, this method provides a convenient way to get them without
172     * them without casting.     * casting.
173     * @param key the name of the resource.     *
174     * @throws MissingResourceException     * @param key the name of the resource
175     *   if that particular object could not be found in this bundle nor     * @throws MissingResourceException if the resource can't be found
176     *   the parent bundle.     * @throws NullPointerException if key is null
177       * @throws ClassCastException if resource is not a string
178     */     */
179    public final String getString(String key) throws MissingResourceException    public final String getString(String key)
180    {    {
181      return (String) getObject(key);      return (String) getObject(key);
182    }    }
183    
184    /**    /**
185     * Get an array of Strings from this resource bundle.  This method     * Get an array of Strings from this resource bundle. This method
186     * provides a convenient way to get it without casting.     * provides a convenient way to get it without casting.
187     * @param key the name of the resource.     *
188     * @throws MissingResourceException     * @param key the name of the resource
189     *   if that particular object could not be found in this bundle nor     * @throws MissingResourceException if the resource can't be found
190     *   the parent bundle.     * @throws NullPointerException if key is null
191       * @throws ClassCastException if resource is not a string
192     */     */
193    public final String[] getStringArray(String key)    public final String[] getStringArray(String key)
     throws MissingResourceException  
194    {    {
195      return (String[]) getObject(key);      return (String[]) getObject(key);
196    }    }
197    
198    /**    /**
199     * Get an object from this resource bundle.     * Get an object from this resource bundle. This will call
200     * @param key the name of the resource.     * <code>handleGetObject</code> for this resource and all of its parents,
201     * @throws MissingResourceException     * until it finds a non-null resource.
202     *   if that particular object could not be found in this bundle nor     *
203     *   the parent bundle.     * @param key the name of the resource
204       * @throws MissingResourceException if the resource can't be found
205       * @throws NullPointerException if key is null
206     */     */
207    public final Object getObject(String key) throws MissingResourceException    public final Object getObject(String key)
208    {    {
209      for (ResourceBundle bundle = this; bundle != null; bundle = bundle.parent)      for (ResourceBundle bundle = this; bundle != null; bundle = bundle.parent)
210        {        try
211          try          {
212            {            Object o = bundle.handleGetObject(key);
213              Object o = bundle.handleGetObject(key);            if (o != null)
214              if (o != null)              return o;
215                return o;          }
216            }        catch (MissingResourceException ex)
217          catch (MissingResourceException ex)          {
218            {          }
219            }      throw new MissingResourceException("Key not found",
220        }                                         getClass().getName(), key);
221      throw new MissingResourceException    }
222        ("Key not found", getClass().getName(), key);  
223      /**
224       * Return the actual locale of this bundle. You can use it after calling
225       * getBundle, to know if the bundle for the desired locale was loaded or
226       * if the fall back was used.
227       *
228       * @return the bundle's locale
229       */
230      public Locale getLocale()
231      {
232        return locale;
233    }    }
234    
235    /**    /**
236     * Get the appropriate ResourceBundle for the default locale.     * Set the parent of this bundle. The parent is consulted when you call
237     * @param baseName the name of the ResourceBundle.  This should be     * getObject and there is no such resource in the current bundle.
238     * a name of a Class or a properties-File.  See the class     *
239     * description for details.     * @param parent the parent of this bundle
240       */
241      protected void setParent(ResourceBundle parent)
242      {
243        // Shall we ignore the old parent?
244        this.parent = parent;
245      }
246    
247      /**
248       * Get the appropriate ResourceBundle for the default locale. This is like
249       * calling <code>getBundle(baseName, Locale.getDefault(),
250       * getClass().getClassLoader()</code>, except that any security check of
251       * getClassLoader won't fail.
252       *
253       * @param baseName the name of the ResourceBundle
254     * @return the desired resource bundle     * @return the desired resource bundle
255     * @throws MissingResourceException if the resource bundle can't be found     * @throws MissingResourceException if the resource bundle can't be found
256       * @throws NullPointerException if baseName is null
257     */     */
258    public static final ResourceBundle getBundle(String baseName)    public static final ResourceBundle getBundle(String baseName)
     throws MissingResourceException  
259    {    {
260      return getBundle(baseName, Locale.getDefault(),      return getBundle(baseName, Locale.getDefault(),
261                       security.getCallingClassLoader());                       security.getCallingClassLoader());
262    }    }
263    
264    /**    /**
265     * Get the appropriate ResourceBundle for the given locale.     * Get the appropriate ResourceBundle for the given locale. This is like
266     * @param baseName the name of the ResourceBundle.  This should be     * calling <code>getBundle(baseName, locale,
267     * a name of a Class or a properties-File.  See the class     * getClass().getClassLoader()</code>, except that any security check of
268     * description for details.     * getClassLoader won't fail.
269     * @param locale A locale.     *
270       * @param baseName the name of the ResourceBundle
271       * @param locale A locale
272     * @return the desired resource bundle     * @return the desired resource bundle
273     * @throws MissingResourceException if the resource bundle can't be found     * @throws MissingResourceException if the resource bundle can't be found
274       * @throws NullPointerException if baseName or locale is null
275     */     */
276    public static final ResourceBundle getBundle(String baseName,    public static final ResourceBundle getBundle(String baseName,
277                                                 Locale locale)                                                 Locale locale)
     throws MissingResourceException  
278    {    {
279      return getBundle(baseName, locale, security.getCallingClassLoader());      return getBundle(baseName, locale, security.getCallingClassLoader());
280    }    }
281    
282    /**    /**
283     * The resource bundle cache.  This is a two-level hash map: The key     * Get the appropriate ResourceBundle for the given locale. The following
284     * is the class loader, the value is a new HashMap.  The key of this     * strategy is used:
285     * second hash map is the localized name, the value is a soft     *
286     * references to the resource bundle.  */     * <p>A sequence of candidate bundle names are generated, and tested in
287    private static Map resourceBundleCache = new HashMap();     * this order, where the suffix 1 means the string from the specified
288       * locale, and the suffix 2 means the string from the default locale:<ul>
289       * <li>baseName + "_" + language1 + "_" + country1 + "_" + variant1</li>
290       * <li>baseName + "_" + language1 + "_" + country1</li>
291       * <li>baseName + "_" + language1</li>
292       * <li>baseName + "_" + language2 + "_" + country2 + "_" + variant2</li>
293       * <li>baseName + "_" + language2 + "_" + country2</li>
294       * <li>baseName + "_" + language2<li>
295       * <li>baseName</li>
296       * </ul>
297       *
298       * <p>In the sequence, entries with an empty string are ignored. Next,
299       * <code>getBundle</code> tries to instantiate the resource bundle:<ul>
300       * <li>First, an attempt is made to load a class in the specified classloader
301       * which is a subclass of ResourceBundle, and which has a public constructor
302       * with no arguments, via reflection.</li>
303       * <li>Next, a search is made for a property resource file, by replacing
304       * '.' with '/' and appending ".properties", and using
305       * ClassLoader.getResource(). If a file is found, then a
306       * PropertyResourceBundle is created from the file's contents.</li>
307       * </ul>
308       * If no resource bundle was found, a MissingResourceException is thrown.
309       *
310       * <p>Next, the parent chain is implemented. The remaining candidate names
311       * in the above sequence are tested in a similar manner, and if any results
312       * in a resource bundle, it is assigned as the parent of the first bundle
313       * using the <code>setParent</code> method (unless the first bundle already
314       * has a parent).
315       *
316       * <p>For example, suppose the following class and property files are
317       * provided: MyResources.class, MyResources_fr_CH.properties,
318       * MyResources_fr_CH.class, MyResources_fr.properties,
319       * MyResources_en.properties, and MyResources_es_ES.class. The contents of
320       * all files are valid (that is, public non-abstract subclasses of
321       * ResourceBundle with public nullary constructors for the ".class" files,
322       * syntactically correct ".properties" files). The default locale is
323       * Locale("en", "UK").
324       *
325       * <p>Calling getBundle with the shown locale argument values instantiates
326       * resource bundles from the following sources:<ul>
327       * <li>Locale("fr", "CH"): result MyResources_fr_CH.class, parent
328       *   MyResources_fr.properties, parent MyResources.class</li>
329       * <li>Locale("fr", "FR"): result MyResources_fr.properties, parent
330       *   MyResources.class</li>
331       * <li>Locale("de", "DE"): result MyResources_en.properties, parent
332       *   MyResources.class</li>
333       * <li>Locale("en", "US"): result MyResources_en.properties, parent
334       *   MyResources.class</li>
335       * <li>Locale("es", "ES"): result MyResources_es_ES.class, parent
336       *   MyResources.class</li>
337       * </ul>
338       * The file MyResources_fr_CH.properties is never used because it is hidden
339       * by MyResources_fr_CH.class.
340       *
341       * @param baseName the name of the ResourceBundle
342       * @param locale A locale
343       * @param classloader a ClassLoader
344       * @return the desired resource bundle
345       * @throws MissingResourceException if the resource bundle can't be found
346       * @throws NullPointerException if any argument is null
347       * @since 1.2
348       */
349      // This method is synchronized so that the cache is properly
350      // handled.
351      public static final synchronized ResourceBundle getBundle
352        (String baseName, Locale locale, ClassLoader classLoader)
353      {
354        // This implementation searches the bundle in the reverse direction
355        // and builds the parent chain on the fly.
356        HashMap cache = (HashMap) resourceBundleCache.get(classLoader);
357        StringBuffer sb = new StringBuffer(60);
358        sb.append(baseName).append('_').append(locale);
359        String name = sb.toString();
360    
361        if (cache == null)
362          {
363            cache = new HashMap();
364            resourceBundleCache.put(classLoader, cache);
365          }
366        else
367          {
368            Reference ref = (Reference) cache.get(name);
369            if (ref != null)
370              {
371                ResourceBundle rb = (ResourceBundle) ref.get();
372                if (rb != null)
373                  // rb should already have the right parent, except if
374                  // something very strange happened.
375                  return rb;
376              }
377          }
378    
379        ResourceBundle baseBundle = tryBundle(baseName, emptyLocale,
380                                              classLoader, null, cache);
381        if (baseBundle == null)
382          // JDK says, that if one provides a bundle base_en_UK, one
383          // must also provide the bundles base_en and base.
384          // This implies that if there is no bundle for base, there
385          // is no bundle at all.
386          throw new MissingResourceException("Bundle " + baseName + " not found",
387                                             baseName, "");
388    
389        // Now use the default locale.
390        ResourceBundle bundle = tryLocalBundle(baseName, locale,
391                                               classLoader, baseBundle, cache);
392        if (bundle == baseBundle && !locale.equals(Locale.getDefault()))
393          bundle = tryLocalBundle(baseName, Locale.getDefault(),
394                                  classLoader, baseBundle, cache);
395    
396        // Check whether baseName_locale has been loaded; if not, map the
397        // "baseName" bundle to "baseName_locale" to avoid retrying to load
398        // baseName_locale.
399        Reference ref = (Reference) cache.get(name);
400        if (ref == null)
401          cache.put(name, new SoftReference(bundle));
402    
403        return bundle;
404      }
405    
406    /**    /**
407     * The `empty' locale is created once in order to optimize     * Override this method to provide the resource for a keys. This gets
408     * tryBundle().     * called by <code>getObject</code>. If you don't have a resource
409       * for the given key, you should return null instead throwing a
410       * MissingResourceException. You don't have to ask the parent, getObject()
411       * already does this; nor should you throw a MissingResourceException.
412       *
413       * @param key the key of the resource
414       * @return the resource for the key, or null if not in bundle
415       * @throws NullPointerException if key is null
416     */     */
417    private static final Locale emptyLocale = new Locale ("", "");    protected abstract Object handleGetObject(String key);
418    
419      /**
420       * This method should return all keys for which a resource exists; you
421       * should include the enumeration of any parent's keys, after filtering out
422       * duplicates.
423       *
424       * @return an enumeration of the keys
425       */
426      public abstract Enumeration getKeys();
427    
428    /**    /**
429     * Tries to load a class or a property file with the specified name.     * Tries to load a class or a property file with the specified name.
430     * @param localizedName the name.     *
431     * @param locale the locale, that must be used exactly.     * @param localizedName the name
432     * @param classloader the classloader.     * @param locale the locale, that must be used exactly
433     * @param bundle the back up (parent) bundle     * @param classloader the classloader
434     * @return the resource bundle if that could be loaded, otherwise     * @param bundle the backup (parent) bundle
435     * <code>bundle</code>.     * @return the resource bundle if it was loaded, otherwise the backup
436     */     */
437    private static final ResourceBundle tryBundle(String localizedName,    private static final ResourceBundle tryBundle(String localizedName,
438                                                  Locale locale,                                                  Locale locale,
439                                                  ClassLoader classloader,                                                  ClassLoader classloader,
440                                                  ResourceBundle bundle,                                                  ResourceBundle bundle,
441                                                  HashMap cache)                                                  HashMap cache)
442    {    {
443      {      // First look into the cache.
444        // First look into the cache.      // XXX We should remove cleared references from the cache.
445        // XXX We should remove cleared references from the cache.      Reference ref = (Reference) cache.get(localizedName);
446        Reference ref = (Reference) cache.get(localizedName);      if (ref != null)
447        if (ref != null)        {
448          {          ResourceBundle rb = (ResourceBundle) ref.get();
449            ResourceBundle rb = (ResourceBundle) ref.get();          if (rb != null)
450            if (rb != null)            // rb should already have the right parent, except if
451              // rb should already have the right parent, except if            // something very strange happened.
452              // something very strange happened.            return rb;
453              return rb;        }
         }  
     }  
454    
455      // foundBundle holds exact matches for the localizedName resource      // foundBundle holds exact matches for the localizedName resource
456      // bundle, which may later be cached.      // bundle, which may later be cached.
457      ResourceBundle foundBundle = null;      ResourceBundle foundBundle = null;
458      try      try
459        {        {
460          Class rbClass;          Class rbClass;
461          if (classloader == null)          if (classloader == null)
462            rbClass = Class.forName(localizedName);            rbClass = Class.forName(localizedName);
463          else          else
464            rbClass = classloader.loadClass(localizedName);            rbClass = classloader.loadClass(localizedName);
465          foundBundle = (ResourceBundle) rbClass.newInstance();          foundBundle = (ResourceBundle) rbClass.newInstance();
466          foundBundle.parent = bundle;          foundBundle.parent = bundle;
467          foundBundle.locale = locale;          foundBundle.locale = locale;
468        }        }
469      catch (ClassNotFoundException ex)      catch (Exception ex)
470        {        {
471        }          // ignore them all
     catch (IllegalAccessException ex)  
       {  
       }  
     catch (InstantiationException ex)  
       {  
         // ignore them all  
         // XXX should we also ignore ClassCastException?  
472        }        }
473      if (foundBundle == null)      if (foundBundle == null)
474        try        try
# Line 299  public abstract class ResourceBundle Line 477  public abstract class ResourceBundle
477            final String resourceName            final String resourceName
478              = localizedName.replace('.', '/') + ".properties";              = localizedName.replace('.', '/') + ".properties";
479            if (classloader == null)            if (classloader == null)
480              is = ClassLoader.getSystemResourceAsStream (resourceName);              is = ClassLoader.getSystemResourceAsStream(resourceName);
481            else            else
482              is = classloader.getResourceAsStream (resourceName);              is = classloader.getResourceAsStream(resourceName);
483            if (is != null)            if (is != null)
484              {              {
485                foundBundle = new PropertyResourceBundle(is);                foundBundle = new PropertyResourceBundle(is);
486                foundBundle.parent = bundle;                foundBundle.parent = bundle;
487                foundBundle.locale = locale;                foundBundle.locale = locale;
# Line 323  public abstract class ResourceBundle Line 501  public abstract class ResourceBundle
501     * Tries to load a the bundle for a given locale, also loads the backup     * Tries to load a the bundle for a given locale, also loads the backup
502     * locales with the same language.     * locales with the same language.
503     *     *
504     * @param name the name.     * @param name the name
505     * @param locale the locale, that must be used exactly.     * @param locale the locale, that must be used exactly
506     * @param classloader the classloader.     * @param classloader the classloader
507     * @param bundle the back up (parent) bundle     * @param bundle the backup (parent) bundle
508     * @return the resource bundle if that could be loaded, otherwise     * @return the resource bundle if it was loaded, otherwise the backup
    * <code>bundle</code>.  
509     */     */
510    private static final ResourceBundle tryLocalBundle(String baseName,    private static final ResourceBundle tryLocalBundle(String baseName,
511                                                       Locale locale,                                                       Locale locale,
512                                                       ClassLoader classloader,                                                       ClassLoader classloader,
513                                                       ResourceBundle bundle,                                                       ResourceBundle bundle,
514                                                       HashMap cache)                                                       HashMap cache)
515    {    {
516      final String language = locale.getLanguage();      final String language = locale.getLanguage();
517      StringBuffer sb = new StringBuffer(60);      StringBuffer sb = new StringBuffer(60);
518    
519      if (language.length() > 0)      if (language.length() > 0)
520        {        {
521          final String country = locale.getCountry();          final String country = locale.getCountry();
522          sb.append(baseName).append('_').append(language);          sb.append(baseName).append('_').append(language);
523          String name = sb.toString();          String name = sb.toString();
524    
525          if (country.length() != 0)          if (country.length() != 0)
526            {            {
527              bundle = tryBundle(name,              bundle = tryBundle(name, new Locale(language),
528                                 new Locale(language, ""),                                 classloader, bundle, cache);
                                classloader, bundle, cache);  
529              sb.append('_').append(country);              sb.append('_').append(country);
530              name = sb.toString();              name = sb.toString();
531    
532              final String variant = locale.getVariant();              final String variant = locale.getVariant();
533    
534              if (variant.length() != 0)              if (variant.length() != 0)
535                {                {
536                  bundle = tryBundle(name,                  bundle = tryBundle(name, new Locale(language, country),
537                                     new Locale(language,                                     classloader, bundle, cache);
                                               country),  
                                    classloader, bundle, cache);  
538                  sb.append('_').append(variant);                  sb.append('_').append(variant);
539                  name = sb.toString();                  name = sb.toString();
540                }                }
541            }            }
542          bundle = tryBundle(name, locale, classloader, bundle, cache);          bundle = tryBundle(name, locale, classloader, bundle, cache);
543        }        }
544      return bundle;      return bundle;
545    }    }
546    } // class ResourceBundle
   /**  
    * Get the appropriate ResourceBundle for the given locale.  
    * @param baseName the name of the ResourceBundle.  This should be  
    * a name of a Class or a properties file.  See the class  
    * description for details.  
    * @param locale A locale.  
    * @param classloader a ClassLoader.  
    * @return the desired resource bundle  
    * @throws MissingResourceException if the resource bundle can't be found  
    */  
   // This method is synchronized so that the cache is properly  
   // handled.  
   public static final synchronized ResourceBundle getBundle(String baseName,  
                                                             Locale locale,  
                                                             ClassLoader classLoader)  
     throws MissingResourceException  
   {  
     // This implementation searches the bundle in the reverse direction  
     // and builds the parent chain on the fly.  
   
     HashMap cache = (HashMap) resourceBundleCache.get(classLoader);  
     StringBuffer sb = new StringBuffer(60);  
     sb.append(baseName).append('_').append(locale);  
     String name = sb.toString();  
   
     if (cache == null)  
       {  
         cache = new HashMap();  
         resourceBundleCache.put(classLoader, cache);  
       }  
     else  
       {  
         Reference ref = (Reference) cache.get(name);  
         if (ref != null)  
           {  
             ResourceBundle rb = (ResourceBundle) ref.get();  
             if (rb != null)  
               // rb should already have the right parent, except if  
               // something very strange happened.  
               return rb;  
           }  
       }  
   
     ResourceBundle baseBundle = tryBundle(baseName, emptyLocale,  
                                           classLoader, null, cache);  
     if (baseBundle == null)  
       // JDK says, that if one provides a bundle base_en_UK, one  
       // must also provide the bundles base_en and base.  
       // This implies that if there is no bundle for base, there  
       // is no bundle at all.  
       throw new MissingResourceException("Bundle " + baseName + " not found", baseName, "");  
   
     // Now use the default locale.  
     ResourceBundle bundle = tryLocalBundle(baseName, locale,  
                                            classLoader, baseBundle, cache);  
     if (bundle == baseBundle && !locale.equals(Locale.getDefault()))  
       {  
         bundle = tryLocalBundle(baseName, Locale.getDefault(),  
                                 classLoader, baseBundle, cache);  
       }  
   
     // Check whether baseName_locale has been loaded; if not, map the  
     // "baseName" bundle to "baseName_locale" to avoid retrying to load  
     // baseName_locale.  
     Reference ref = (Reference) cache.get(name);  
     if (ref == null)  
       cache.put(name, new SoftReference(bundle));  
   
     return bundle;  
   }  
   
   /**  
    * Return the actual locale of this bundle.  You can use it after  
    * calling getBundle, to know if the bundle for the desired locale  
    * was loaded or if the fall back was used.  
    */  
   public Locale getLocale()  
   {  
     return locale;  
   }  
   
   /**  
    * Set the parent of this bundle. This is consulted when you call  
    * getObject and there is no such resource in the current bundle.  
    * @param parent the parent of this bundle.  
    */  
   protected void setParent(ResourceBundle parent)  
   {  
     // Shall we ignore the old parent?  
     this.parent = parent;  
   }  
   
   /**  
    * Override this method to provide the resource for a keys.  This gets  
    * called by <code>getObject</code>.  If you don't have a resource  
    * for the given key, you should return null instead throwing a  
    * MissingResourceException.   You don't have to ask the parent,  
    * getObject() already does this.  
    *  
    * @param key The key of the resource.  
    * @return The resource for the key, or null if not in bundle.  
    * @throws MissingResourceException you shouldn't throw this  
    */  
   protected abstract Object handleGetObject(String key)  
     throws MissingResourceException;  
   
   /**  
    * This method should return all keys for which a resource exists.  
    * @return An enumeration of the keys.  
    */  
   public abstract Enumeration getKeys();  
 }  

Legend:
Removed from v.1.15  
changed lines
  Added in v.1.16

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26