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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [classpath/] [java/] [util/] [ResourceBundle.java] - Blame information for rev 14

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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