OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [java/] [util/] [ResourceBundle.java] - Blame information for rev 771

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 771 jeremybenn
/* ResourceBundle -- aids in loading resource bundles
2
   Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004, 2005, 2006
3
   Free Software Foundation, Inc.
4
 
5
This file is part of GNU Classpath.
6
 
7
GNU Classpath is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2, or (at your option)
10
any later version.
11
 
12
GNU Classpath is distributed in the hope that it will be useful, but
13
WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
General Public License for more details.
16
 
17
You should have received a copy of the GNU General Public License
18
along with GNU Classpath; see the file COPYING.  If not, write to the
19
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20
02110-1301 USA.
21
 
22
Linking this library statically or dynamically with other modules is
23
making a combined work based on this library.  Thus, the terms and
24
conditions of the GNU General Public License cover the whole
25
combination.
26
 
27
As a special exception, the copyright holders of this library give you
28
permission to link this library with independent modules to produce an
29
executable, regardless of the license terms of these independent
30
modules, and to copy and distribute the resulting executable under
31
terms of your choice, provided that you also meet, for each linked
32
independent module, the terms and conditions of the license of that
33
module.  An independent module is a module which is not derived from
34
or based on this library.  If you modify this library, you may extend
35
this exception to your version of the library, but you are not
36
obligated to do so.  If you do not wish to do so, delete this
37
exception statement from your version. */
38
 
39
 
40
package java.util;
41
 
42
import gnu.classpath.VMStackWalker;
43
 
44
import gnu.java.lang.CPStringBuilder;
45
 
46
import java.io.IOException;
47
import java.io.InputStream;
48
 
49
/**
50
 * A resource bundle contains locale-specific data. If you need localized
51
 * data, you can load a resource bundle that matches the locale with
52
 * <code>getBundle</code>. Now you can get your object by calling
53
 * <code>getObject</code> or <code>getString</code> on that bundle.
54
 *
55
 * <p>When a bundle is demanded for a specific locale, the ResourceBundle
56
 * is searched in following order (<i>def. language</i> stands for the
57
 * two letter ISO language code of the default locale (see
58
 * <code>Locale.getDefault()</code>).
59
 *
60
<pre>baseName_<i>language code</i>_<i>country code</i>_<i>variant</i>
61
baseName_<i>language code</i>_<i>country code</i>
62
baseName_<i>language code</i>
63
baseName_<i>def. language</i>_<i>def. country</i>_<i>def. variant</i>
64
baseName_<i>def. language</i>_<i>def. country</i>
65
baseName_<i>def. language</i>
66
baseName</pre>
67
 *
68
 * <p>A bundle is backed up by less specific bundles (omitting variant, country
69
 * or language). But it is not backed up by the default language locale.
70
 *
71
 * <p>If you provide a bundle for a given locale, say
72
 * <code>Bundle_en_UK_POSIX</code>, you must also provide a bundle for
73
 * all sub locales, ie. <code>Bundle_en_UK</code>, <code>Bundle_en</code>, and
74
 * <code>Bundle</code>.
75
 *
76
 * <p>When a bundle is searched, we look first for a class with the given
77
 * name, then for a file with <code>.properties</code> extension in the
78
 * classpath. The name must be a fully qualified classname (with dots as
79
 * path separators).
80
 *
81
 * <p>(Note: This implementation always backs up the class with a properties
82
 * file if that is existing, but you shouldn't rely on this, if you want to
83
 * be compatible to the standard JDK.)
84
 *
85
 * @author Jochen Hoenicke
86
 * @author Eric Blake (ebb9@email.byu.edu)
87
 * @see Locale
88
 * @see ListResourceBundle
89
 * @see PropertyResourceBundle
90
 * @since 1.1
91
 * @status updated to 1.4
92
 */
93
public abstract class ResourceBundle
94
{
95
  /**
96
   * Maximum size of our cache of <code>ResourceBundle</code>s keyed by
97
   * {@link BundleKey} instances.
98
   *
99
   * @see BundleKey
100
   */
101
  private static final int CACHE_SIZE = 100;
102
 
103
  /**
104
   * The parent bundle. This is consulted when you call getObject and there
105
   * is no such resource in the current bundle. This field may be null.
106
   */
107
  protected ResourceBundle parent;
108
 
109
  /**
110
   * The locale of this resource bundle. You can read this with
111
   * <code>getLocale</code> and it is automatically set in
112
   * <code>getBundle</code>.
113
   */
114
  private Locale locale;
115
 
116
  /**
117
   * A VM-wide cache of resource bundles already fetched.
118
   * <p>
119
   * This {@link Map} is a Least Recently Used (LRU) cache, of the last
120
   * {@link #CACHE_SIZE} accessed <code>ResourceBundle</code>s keyed by the
121
   * tuple: default locale, resource-bundle name, resource-bundle locale, and
122
   * classloader.
123
   *
124
   * @see BundleKey
125
   */
126
  private static Map<BundleKey,Object> bundleCache =
127
    new LinkedHashMap<BundleKey,Object>(CACHE_SIZE + 1, 0.75F, true)
128
  {
129
    public boolean removeEldestEntry(Map.Entry<BundleKey,Object> entry)
130
    {
131
      return size() > CACHE_SIZE;
132
    }
133
  };
134
 
135
  /**
136
   * The constructor. It does nothing special.
137
   */
138
  public ResourceBundle()
139
  {
140
  }
141
 
142
  /**
143
   * Get a String from this resource bundle. Since most localized Objects
144
   * are Strings, this method provides a convenient way to get them without
145
   * casting.
146
   *
147
   * @param key the name of the resource
148
   * @throws MissingResourceException if the resource can't be found
149
   * @throws NullPointerException if key is null
150
   * @throws ClassCastException if resource is not a string
151
   */
152
  public final String getString(String key)
153
  {
154
    return (String) getObject(key);
155
  }
156
 
157
  /**
158
   * Get an array of Strings from this resource bundle. This method
159
   * provides a convenient way to get it without casting.
160
   *
161
   * @param key the name of the resource
162
   * @throws MissingResourceException if the resource can't be found
163
   * @throws NullPointerException if key is null
164
   * @throws ClassCastException if resource is not a string
165
   */
166
  public final String[] getStringArray(String key)
167
  {
168
    return (String[]) getObject(key);
169
  }
170
 
171
  /**
172
   * Get an object from this resource bundle. This will call
173
   * <code>handleGetObject</code> for this resource and all of its parents,
174
   * until it finds a non-null resource.
175
   *
176
   * @param key the name of the resource
177
   * @throws MissingResourceException if the resource can't be found
178
   * @throws NullPointerException if key is null
179
   */
180
  public final Object getObject(String key)
181
  {
182
    for (ResourceBundle bundle = this; bundle != null; bundle = bundle.parent)
183
      {
184
        Object o = bundle.handleGetObject(key);
185
        if (o != null)
186
          return o;
187
      }
188
 
189
    String className = getClass().getName();
190
    throw new MissingResourceException("Key '" + key
191
                                       + "'not found in Bundle: "
192
                                       + className, className, key);
193
  }
194
 
195
  /**
196
   * Return the actual locale of this bundle. You can use it after calling
197
   * getBundle, to know if the bundle for the desired locale was loaded or
198
   * if the fall back was used.
199
   *
200
   * @return the bundle's locale
201
   */
202
  public Locale getLocale()
203
  {
204
    return locale;
205
  }
206
 
207
  /**
208
   * Set the parent of this bundle. The parent is consulted when you call
209
   * getObject and there is no such resource in the current bundle.
210
   *
211
   * @param parent the parent of this bundle
212
   */
213
  protected void setParent(ResourceBundle parent)
214
  {
215
    this.parent = parent;
216
  }
217
 
218
  /**
219
   * Get the appropriate ResourceBundle for the default locale. This is like
220
   * calling <code>getBundle(baseName, Locale.getDefault(),
221
   * getClass().getClassLoader()</code>, except that any security check of
222
   * getClassLoader won't fail.
223
   *
224
   * @param baseName the name of the ResourceBundle
225
   * @return the desired resource bundle
226
   * @throws MissingResourceException if the resource bundle can't be found
227
   * @throws NullPointerException if baseName is null
228
   */
229
  public static ResourceBundle getBundle(String baseName)
230
  {
231
    ClassLoader cl = VMStackWalker.getCallingClassLoader();
232
    if (cl == null)
233
      cl = ClassLoader.getSystemClassLoader();
234
    return getBundle(baseName, Locale.getDefault(), cl);
235
  }
236
 
237
  /**
238
   * Get the appropriate ResourceBundle for the given locale. This is like
239
   * calling <code>getBundle(baseName, locale,
240
   * getClass().getClassLoader()</code>, except that any security check of
241
   * getClassLoader won't fail.
242
   *
243
   * @param baseName the name of the ResourceBundle
244
   * @param locale A locale
245
   * @return the desired resource bundle
246
   * @throws MissingResourceException if the resource bundle can't be found
247
   * @throws NullPointerException if baseName or locale is null
248
   */
249
  public static ResourceBundle getBundle(String baseName, Locale locale)
250
  {
251
    ClassLoader cl = VMStackWalker.getCallingClassLoader();
252
    if (cl == null)
253
      cl = ClassLoader.getSystemClassLoader();
254
    return getBundle(baseName, locale, cl);
255
  }
256
 
257
  /** Cache key for the ResourceBundle cache.  Resource bundles are keyed
258
      by the combination of bundle name, locale, and class loader. */
259
  private static class BundleKey
260
  {
261
    Locale defaultLocale;
262
    String baseName;
263
    Locale locale;
264
    ClassLoader classLoader;
265
    int hashcode;
266
 
267
    BundleKey() {}
268
 
269
    BundleKey(Locale dl, String s, Locale l, ClassLoader cl)
270
    {
271
      set(dl, s, l, cl);
272
    }
273
 
274
    void set(Locale dl, String s, Locale l, ClassLoader cl)
275
    {
276
      defaultLocale = dl;
277
      baseName = s;
278
      locale = l;
279
      classLoader = cl;
280
      hashcode = defaultLocale.hashCode() ^ baseName.hashCode()
281
          ^ locale.hashCode() ^ classLoader.hashCode();
282
    }
283
 
284
    public int hashCode()
285
    {
286
      return hashcode;
287
    }
288
 
289
    public boolean equals(Object o)
290
    {
291
      if (! (o instanceof BundleKey))
292
        return false;
293
      BundleKey key = (BundleKey) o;
294
      return hashcode == key.hashcode
295
          && defaultLocale.equals(key.defaultLocale)
296
          && baseName.equals(key.baseName)
297
          && locale.equals(key.locale)
298
          && classLoader.equals(key.classLoader);
299
    }
300
 
301
    public String toString()
302
    {
303
      CPStringBuilder builder = new CPStringBuilder(getClass().getName());
304
      builder.append("[defaultLocale=");
305
      builder.append(defaultLocale);
306
      builder.append(",baseName=");
307
      builder.append(baseName);
308
      builder.append(",locale=");
309
      builder.append(locale);
310
      builder.append(",classLoader=");
311
      builder.append(classLoader);
312
      builder.append("]");
313
      return builder.toString();
314
    }
315
  }
316
 
317
  /** A cache lookup key. This avoids having to a new one for every
318
   *  getBundle() call. */
319
  private static final BundleKey lookupKey = new BundleKey();
320
 
321
  /** Singleton cache entry to represent previous failed lookups. */
322
  private static final Object nullEntry = new Object();
323
 
324
  /**
325
   * Get the appropriate ResourceBundle for the given locale. The following
326
   * strategy is used:
327
   *
328
   * <p>A sequence of candidate bundle names are generated, and tested in
329
   * this order, where the suffix 1 means the string from the specified
330
   * locale, and the suffix 2 means the string from the default locale:</p>
331
   *
332
   * <ul>
333
   * <li>baseName + "_" + language1 + "_" + country1 + "_" + variant1</li>
334
   * <li>baseName + "_" + language1 + "_" + country1</li>
335
   * <li>baseName + "_" + language1</li>
336
   * <li>baseName + "_" + language2 + "_" + country2 + "_" + variant2</li>
337
   * <li>baseName + "_" + language2 + "_" + country2</li>
338
   * <li>baseName + "_" + language2</li>
339
   * <li>baseName</li>
340
   * </ul>
341
   *
342
   * <p>In the sequence, entries with an empty string are ignored. Next,
343
   * <code>getBundle</code> tries to instantiate the resource bundle:</p>
344
   *
345
   * <ul>
346
   * <li>First, an attempt is made to load a class in the specified classloader
347
   * which is a subclass of ResourceBundle, and which has a public constructor
348
   * with no arguments, via reflection.</li>
349
   * <li>Next, a search is made for a property resource file, by replacing
350
   * '.' with '/' and appending ".properties", and using
351
   * ClassLoader.getResource(). If a file is found, then a
352
   * PropertyResourceBundle is created from the file's contents.</li>
353
   * </ul>
354
   * If no resource bundle was found, a MissingResourceException is thrown.
355
   *
356
   * <p>Next, the parent chain is implemented. The remaining candidate names
357
   * in the above sequence are tested in a similar manner, and if any results
358
   * in a resource bundle, it is assigned as the parent of the first bundle
359
   * using the <code>setParent</code> method (unless the first bundle already
360
   * has a parent).</p>
361
   *
362
   * <p>For example, suppose the following class and property files are
363
   * provided: MyResources.class, MyResources_fr_CH.properties,
364
   * MyResources_fr_CH.class, MyResources_fr.properties,
365
   * MyResources_en.properties, and MyResources_es_ES.class. The contents of
366
   * all files are valid (that is, public non-abstract subclasses of
367
   * ResourceBundle with public nullary constructors for the ".class" files,
368
   * syntactically correct ".properties" files). The default locale is
369
   * Locale("en", "UK").</p>
370
   *
371
   * <p>Calling getBundle with the shown locale argument values instantiates
372
   * resource bundles from the following sources:</p>
373
   *
374
   * <ul>
375
   * <li>Locale("fr", "CH"): result MyResources_fr_CH.class, parent
376
   *   MyResources_fr.properties, parent MyResources.class</li>
377
   * <li>Locale("fr", "FR"): result MyResources_fr.properties, parent
378
   *   MyResources.class</li>
379
   * <li>Locale("de", "DE"): result MyResources_en.properties, parent
380
   *   MyResources.class</li>
381
   * <li>Locale("en", "US"): result MyResources_en.properties, parent
382
   *   MyResources.class</li>
383
   * <li>Locale("es", "ES"): result MyResources_es_ES.class, parent
384
   *   MyResources.class</li>
385
   * </ul>
386
   *
387
   * <p>The file MyResources_fr_CH.properties is never used because it is hidden
388
   * by MyResources_fr_CH.class.</p>
389
   *
390
   * @param baseName the name of the ResourceBundle
391
   * @param locale A locale
392
   * @param classLoader a ClassLoader
393
   * @return the desired resource bundle
394
   * @throws MissingResourceException if the resource bundle can't be found
395
   * @throws NullPointerException if any argument is null
396
   * @since 1.2
397
   */
398
  // This method is synchronized so that the cache is properly
399
  // handled.
400
  public static synchronized ResourceBundle getBundle
401
    (String baseName, Locale locale, ClassLoader classLoader)
402
  {
403
    Locale defaultLocale = Locale.getDefault();
404
    // This will throw NullPointerException if any arguments are null.
405
    lookupKey.set(defaultLocale, baseName, locale, classLoader);
406
    Object obj = bundleCache.get(lookupKey);
407
    if (obj instanceof ResourceBundle)
408
      return (ResourceBundle) obj;
409
 
410
    if (obj == nullEntry)
411
      throw new MissingResourceException("Bundle " + baseName
412
                                         + " not found for locale " + locale
413
                                         + " by classloader " + classLoader,
414
                                         baseName, "");
415
    // First, look for a bundle for the specified locale. We don't want
416
    // the base bundle this time.
417
    boolean wantBase = locale.equals(defaultLocale);
418
    ResourceBundle bundle = tryBundle(baseName, locale, classLoader, wantBase);
419
    // Try the default locale if neccessary.
420
    if (bundle == null && ! wantBase)
421
      bundle = tryBundle(baseName, defaultLocale, classLoader, true);
422
 
423
    BundleKey key = new BundleKey(defaultLocale, baseName, locale, classLoader);
424
    if (bundle == null)
425
      {
426
        // Cache the fact that this lookup has previously failed.
427
        bundleCache.put(key, nullEntry);
428
        throw new MissingResourceException("Bundle " + baseName
429
                                           + " not found for locale " + locale
430
                                           + " by classloader " + classLoader,
431
                                           baseName, "");
432
      }
433
    // Cache the result and return it.
434
    bundleCache.put(key, bundle);
435
    return bundle;
436
  }
437
 
438
  /**
439
   * Override this method to provide the resource for a keys. This gets
440
   * called by <code>getObject</code>. If you don't have a resource
441
   * for the given key, you should return null instead throwing a
442
   * MissingResourceException. You don't have to ask the parent, getObject()
443
   * already does this; nor should you throw a MissingResourceException.
444
   *
445
   * @param key the key of the resource
446
   * @return the resource for the key, or null if not in bundle
447
   * @throws NullPointerException if key is null
448
   */
449
  protected abstract Object handleGetObject(String key);
450
 
451
  /**
452
   * This method should return all keys for which a resource exists; you
453
   * should include the enumeration of any parent's keys, after filtering out
454
   * duplicates.
455
   *
456
   * @return an enumeration of the keys
457
   */
458
  public abstract Enumeration<String> getKeys();
459
 
460
  /**
461
   * Tries to load a class or a property file with the specified name.
462
   *
463
   * @param localizedName the name
464
   * @param classloader the classloader
465
   * @return the resource bundle if it was loaded, otherwise the backup
466
   */
467
  private static ResourceBundle tryBundle(String localizedName,
468
                                          ClassLoader classloader)
469
  {
470
    ResourceBundle bundle = null;
471
    try
472
      {
473
        Class<?> rbClass;
474
        if (classloader == null)
475
          rbClass = Class.forName(localizedName);
476
        else
477
          rbClass = classloader.loadClass(localizedName);
478
        // Note that we do the check up front instead of catching
479
        // ClassCastException.  The reason for this is that some crazy
480
        // programs (Eclipse) have classes that do not extend
481
        // ResourceBundle but that have the same name as a property
482
        // bundle; in fact Eclipse relies on ResourceBundle not
483
        // instantiating these classes.
484
        if (ResourceBundle.class.isAssignableFrom(rbClass))
485
          bundle = (ResourceBundle) rbClass.newInstance();
486
      }
487
    catch (Exception ex) {}
488
 
489
    if (bundle == null)
490
      {
491
        try
492
          {
493
            InputStream is;
494
            String resourceName
495
              = localizedName.replace('.', '/') + ".properties";
496
            if (classloader == null)
497
              is = ClassLoader.getSystemResourceAsStream(resourceName);
498
            else
499
              is = classloader.getResourceAsStream(resourceName);
500
            if (is != null)
501
              bundle = new PropertyResourceBundle(is);
502
          }
503
        catch (IOException ex)
504
          {
505
            MissingResourceException mre = new MissingResourceException
506
              ("Failed to load bundle: " + localizedName, localizedName, "");
507
            mre.initCause(ex);
508
            throw mre;
509
          }
510
      }
511
 
512
    return bundle;
513
  }
514
 
515
  /**
516
   * Tries to load the bundle for a given locale, also loads the backup
517
   * locales with the same language.
518
   *
519
   * @param baseName the raw bundle name, without locale qualifiers
520
   * @param locale the locale
521
   * @param classLoader the classloader
522
   * @param wantBase whether a resource bundle made only from the base name
523
   *        (with no locale information attached) should be returned.
524
   * @return the resource bundle if it was loaded, otherwise the backup
525
   */
526
  private static ResourceBundle tryBundle(String baseName, Locale locale,
527
                                          ClassLoader classLoader,
528
                                          boolean wantBase)
529
  {
530
    String language = locale.getLanguage();
531
    String country = locale.getCountry();
532
    String variant = locale.getVariant();
533
 
534
    int baseLen = baseName.length();
535
 
536
    // Build up a CPStringBuilder containing the complete bundle name, fully
537
    // qualified by locale.
538
    CPStringBuilder sb = new CPStringBuilder(baseLen + variant.length() + 7);
539
 
540
    sb.append(baseName);
541
 
542
    if (language.length() > 0)
543
      {
544
        sb.append('_');
545
        sb.append(language);
546
 
547
        if (country.length() > 0)
548
          {
549
            sb.append('_');
550
            sb.append(country);
551
 
552
            if (variant.length() > 0)
553
              {
554
                sb.append('_');
555
                sb.append(variant);
556
              }
557
          }
558
      }
559
 
560
    // Now try to load bundles, starting with the most specialized name.
561
    // Build up the parent chain as we go.
562
    String bundleName = sb.toString();
563
    ResourceBundle first = null; // The most specialized bundle.
564
    ResourceBundle last = null; // The least specialized bundle.
565
 
566
    while (true)
567
      {
568
        ResourceBundle foundBundle = tryBundle(bundleName, classLoader);
569
        if (foundBundle != null)
570
          {
571
            if (first == null)
572
              first = foundBundle;
573
            if (last != null)
574
              last.parent = foundBundle;
575
            foundBundle.locale = locale;
576
            last = foundBundle;
577
          }
578
        int idx = bundleName.lastIndexOf('_');
579
        // Try the non-localized base name only if we already have a
580
        // localized child bundle, or wantBase is true.
581
        if (idx > baseLen || (idx == baseLen && (first != null || wantBase)))
582
          bundleName = bundleName.substring(0, idx);
583
        else
584
          break;
585
      }
586
 
587
    return first;
588
  }
589
 
590
  /**
591
   * Remove all resources from the cache that were loaded
592
   * using the class loader of the calling class.
593
   *
594
   * @since 1.6
595
   */
596
  public static final void clearCache()
597
  {
598
    clearCache(VMStackWalker.getCallingClassLoader());
599
  }
600
 
601
  /**
602
   * Remove all resources from the cache that were loaded
603
   * using the specified class loader.
604
   *
605
   * @param loader the loader used for the bundles that will be removed.
606
   * @throws NullPointerException if {@code loader} is {@code null}.
607
   * @since 1.6
608
   */
609
  public static final void clearCache(ClassLoader loader)
610
  {
611
    if (loader == null)
612
      throw new NullPointerException("The loader can not be null.");
613
    synchronized (ResourceBundle.class)
614
      {
615
        Iterator<BundleKey> iter = bundleCache.keySet().iterator();
616
        while (iter.hasNext())
617
          {
618
            BundleKey key = iter.next();
619
            if (key.classLoader == loader)
620
              iter.remove();
621
          }
622
      }
623
  }
624
 
625
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.