1 |
/* java.util.ResourceBundle |
/* ResourceBundle -- aids in loading resource bundles |
2 |
Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc. |
Copyright (C) 1998, 1999, 2001, 2002 Free Software Foundation, Inc. |
3 |
|
|
4 |
This file is part of GNU Classpath. |
This file is part of GNU Classpath. |
5 |
|
|
37 |
|
|
38 |
|
|
39 |
package java.util; |
package java.util; |
40 |
|
|
41 |
import java.lang.ref.Reference; |
import java.lang.ref.Reference; |
42 |
import java.lang.ref.SoftReference; |
import java.lang.ref.SoftReference; |
43 |
|
import java.io.InputStream; |
44 |
|
import java.io.IOException; |
45 |
import java.security.AccessController; |
import java.security.AccessController; |
46 |
import java.security.PrivilegedAction; |
import java.security.PrivilegedAction; |
47 |
import gnu.classpath.Configuration; |
import gnu.classpath.Configuration; |
79 |
* When a bundle is searched, we look first for a class with |
* When a bundle is searched, we look first for a class with |
80 |
* the given name and if that is not found for a file with |
* the given name and if that is not found for a file with |
81 |
* <code>.properties</code> extension in the classpath. The name |
* <code>.properties</code> extension in the classpath. The name |
82 |
* must be a fully qualified classname (with dots as path separators). |
* must be a fully qualified classname (with dots as path separators). |
83 |
* <br> |
* <br> |
84 |
* (Note: This implementation always backs up the class with a |
* (Note: This implementation always backs up the class with a |
85 |
* properties file if that is existing, but you shouldn't rely on |
* properties file if that is existing, but you shouldn't rely on |
93 |
/** |
/** |
94 |
* The parent bundle. This is consulted when you call getObject |
* The parent bundle. This is consulted when you call getObject |
95 |
* and there is no such resource in the current bundle. This |
* and there is no such resource in the current bundle. This |
96 |
* field may be null. |
* field may be null. |
97 |
*/ |
*/ |
98 |
protected ResourceBundle parent; |
protected ResourceBundle parent; |
99 |
|
|
100 |
/** |
/** |
101 |
* The locale of this resource bundle. You can read this with |
* The locale of this resource bundle. You can read this with |
102 |
* <code>getLocale</code> and it is automatically set in |
* <code>getLocale</code> and it is automatically set in |
103 |
* <code>getBundle</code>. |
* <code>getBundle</code>. |
104 |
*/ |
*/ |
105 |
private Locale locale; |
private Locale locale; |
106 |
|
|
107 |
/** |
/** |
108 |
* We override SecurityManager in order to access getClassContext(). |
* We override SecurityManager in order to access getClassContext(). |
109 |
*/ |
*/ |
110 |
static class Security extends SecurityManager |
static class Security extends SecurityManager |
111 |
{ |
{ |
120 |
return null; |
return null; |
121 |
} |
} |
122 |
} |
} |
123 |
|
|
124 |
// This will always work since java.util classes have (all) system |
// This will always work since java.util classes have (all) system |
125 |
// permissions. |
// permissions. |
126 |
static Security security = (Security) AccessController.doPrivileged |
static Security security = (Security) AccessController.doPrivileged |
146 |
* Objects are Strings, this method provides a convenient way to get |
* Objects are Strings, this method provides a convenient way to get |
147 |
* them without casting. |
* them without casting. |
148 |
* @param key the name of the resource. |
* @param key the name of the resource. |
149 |
* @exception MissingResourceException |
* @throws MissingResourceException |
150 |
* if that particular object could not be found in this bundle nor |
* if that particular object could not be found in this bundle nor |
151 |
* the parent bundle. |
* the parent bundle. |
152 |
*/ |
*/ |
159 |
* Get an array of Strings from this resource bundle. This method |
* Get an array of Strings from this resource bundle. This method |
160 |
* provides a convenient way to get it without casting. |
* provides a convenient way to get it without casting. |
161 |
* @param key the name of the resource. |
* @param key the name of the resource. |
162 |
* @exception MissingResourceException |
* @throws MissingResourceException |
163 |
* if that particular object could not be found in this bundle nor |
* if that particular object could not be found in this bundle nor |
164 |
* the parent bundle. |
* the parent bundle. |
165 |
*/ |
*/ |
172 |
/** |
/** |
173 |
* Get an object from this resource bundle. |
* Get an object from this resource bundle. |
174 |
* @param key the name of the resource. |
* @param key the name of the resource. |
175 |
* @exception MissingResourceException |
* @throws MissingResourceException |
176 |
* if that particular object could not be found in this bundle nor |
* if that particular object could not be found in this bundle nor |
177 |
* the parent bundle. |
* the parent bundle. |
178 |
*/ |
*/ |
195 |
} |
} |
196 |
|
|
197 |
/** |
/** |
198 |
* Get the appropriate ResourceBundle for the default locale. |
* Get the appropriate ResourceBundle for the default locale. |
199 |
* @param baseName the name of the ResourceBundle. This should be |
* @param baseName the name of the ResourceBundle. This should be |
200 |
* a name of a Class or a properties-File. See the class |
* a name of a Class or a properties-File. See the class |
201 |
* description for details. |
* description for details. |
202 |
* @return the desired resource bundle |
* @return the desired resource bundle |
203 |
* @exception MissingResourceException |
* @throws MissingResourceException if the resource bundle can't be found |
|
* if the resource bundle couldn't be found. |
|
204 |
*/ |
*/ |
205 |
public static final ResourceBundle getBundle(String baseName) |
public static final ResourceBundle getBundle(String baseName) |
206 |
throws MissingResourceException |
throws MissingResourceException |
210 |
} |
} |
211 |
|
|
212 |
/** |
/** |
213 |
* Get the appropriate ResourceBundle for the given locale. |
* Get the appropriate ResourceBundle for the given locale. |
214 |
* @param baseName the name of the ResourceBundle. This should be |
* @param baseName the name of the ResourceBundle. This should be |
215 |
* a name of a Class or a properties-File. See the class |
* a name of a Class or a properties-File. See the class |
216 |
* description for details. |
* description for details. |
217 |
* @param locale A locale. |
* @param locale A locale. |
218 |
* @return the desired resource bundle |
* @return the desired resource bundle |
219 |
* @exception MissingResourceException |
* @throws MissingResourceException if the resource bundle can't be found |
|
* if the resource bundle couldn't be found. |
|
220 |
*/ |
*/ |
221 |
public static final ResourceBundle getBundle(String baseName, |
public static final ResourceBundle getBundle(String baseName, |
222 |
Locale locale) |
Locale locale) |
234 |
|
|
235 |
/** |
/** |
236 |
* The `empty' locale is created once in order to optimize |
* The `empty' locale is created once in order to optimize |
237 |
* tryBundle(). |
* tryBundle(). |
238 |
*/ |
*/ |
239 |
private static final Locale emptyLocale = new Locale ("", ""); |
private static final Locale emptyLocale = new Locale ("", ""); |
240 |
|
|
244 |
* @param locale the locale, that must be used exactly. |
* @param locale the locale, that must be used exactly. |
245 |
* @param classloader the classloader. |
* @param classloader the classloader. |
246 |
* @param bundle the back up (parent) bundle |
* @param bundle the back up (parent) bundle |
247 |
* @return the resource bundle if that could be loaded, otherwise |
* @return the resource bundle if that could be loaded, otherwise |
248 |
* <code>bundle</code>. |
* <code>bundle</code>. |
249 |
*/ |
*/ |
250 |
private static final ResourceBundle tryBundle(String localizedName, |
private static final ResourceBundle tryBundle(String localizedName, |
270 |
// foundBundle holds exact matches for the localizedName resource |
// foundBundle holds exact matches for the localizedName resource |
271 |
// bundle, which may later be cached. |
// bundle, which may later be cached. |
272 |
ResourceBundle foundBundle = null; |
ResourceBundle foundBundle = null; |
|
|
|
|
try |
|
|
{ |
|
|
java.io.InputStream is; |
|
|
final String resourceName = |
|
|
localizedName.replace('.', '/') + ".properties"; |
|
|
if (classloader == null) |
|
|
is = ClassLoader.getSystemResourceAsStream (resourceName); |
|
|
else |
|
|
is = classloader.getResourceAsStream (resourceName); |
|
|
if (is != null) |
|
|
{ |
|
|
foundBundle = new PropertyResourceBundle(is); |
|
|
foundBundle.parent = bundle; |
|
|
foundBundle.locale = locale; |
|
|
} |
|
|
} |
|
|
catch (java.io.IOException ex) |
|
|
{ |
|
|
} |
|
|
|
|
273 |
try |
try |
274 |
{ |
{ |
275 |
Class rbClass; |
Class rbClass; |
292 |
// ignore them all |
// ignore them all |
293 |
// XXX should we also ignore ClassCastException? |
// XXX should we also ignore ClassCastException? |
294 |
} |
} |
295 |
|
if (foundBundle == null) |
296 |
|
try |
297 |
|
{ |
298 |
|
InputStream is; |
299 |
|
final String resourceName |
300 |
|
= localizedName.replace('.', '/') + ".properties"; |
301 |
|
if (classloader == null) |
302 |
|
is = ClassLoader.getSystemResourceAsStream (resourceName); |
303 |
|
else |
304 |
|
is = classloader.getResourceAsStream (resourceName); |
305 |
|
if (is != null) |
306 |
|
{ |
307 |
|
foundBundle = new PropertyResourceBundle(is); |
308 |
|
foundBundle.parent = bundle; |
309 |
|
foundBundle.locale = locale; |
310 |
|
} |
311 |
|
} |
312 |
|
catch (IOException ex) |
313 |
|
{ |
314 |
|
} |
315 |
|
|
316 |
if (foundBundle != null) |
if (foundBundle != null) |
317 |
cache.put(localizedName, new SoftReference(foundBundle)); |
cache.put(localizedName, new SoftReference(foundBundle)); |
327 |
* @param locale the locale, that must be used exactly. |
* @param locale the locale, that must be used exactly. |
328 |
* @param classloader the classloader. |
* @param classloader the classloader. |
329 |
* @param bundle the back up (parent) bundle |
* @param bundle the back up (parent) bundle |
330 |
* @return the resource bundle if that could be loaded, otherwise |
* @return the resource bundle if that could be loaded, otherwise |
331 |
* <code>bundle</code>. |
* <code>bundle</code>. |
332 |
*/ |
*/ |
333 |
private static final ResourceBundle tryLocalBundle(String baseName, |
private static final ResourceBundle tryLocalBundle(String baseName, |
337 |
HashMap cache) |
HashMap cache) |
338 |
{ |
{ |
339 |
final String language = locale.getLanguage(); |
final String language = locale.getLanguage(); |
340 |
|
StringBuffer sb = new StringBuffer(60); |
341 |
|
|
342 |
if (language.length() > 0) |
if (language.length() > 0) |
343 |
{ |
{ |
344 |
final String country = locale.getCountry(); |
final String country = locale.getCountry(); |
345 |
String name = baseName + "_" + language; |
sb.append(baseName).append('_').append(language); |
346 |
|
String name = sb.toString(); |
347 |
|
|
348 |
if (country.length() != 0) |
if (country.length() != 0) |
349 |
{ |
{ |
350 |
bundle = tryBundle(name, |
bundle = tryBundle(name, |
351 |
new Locale(language, ""), |
new Locale(language, ""), |
352 |
classloader, bundle, cache); |
classloader, bundle, cache); |
353 |
|
sb.append('_').append(country); |
354 |
name += "_" + country; |
name = sb.toString(); |
355 |
|
|
356 |
final String variant = locale.getVariant(); |
final String variant = locale.getVariant(); |
357 |
|
|
361 |
new Locale(language, |
new Locale(language, |
362 |
country), |
country), |
363 |
classloader, bundle, cache); |
classloader, bundle, cache); |
364 |
|
sb.append('_').append(variant); |
365 |
name += "_" + variant; |
name = sb.toString(); |
366 |
} |
} |
367 |
} |
} |
368 |
bundle = tryBundle(name, locale, classloader, bundle, cache); |
bundle = tryBundle(name, locale, classloader, bundle, cache); |
371 |
} |
} |
372 |
|
|
373 |
/** |
/** |
374 |
* Get the appropriate ResourceBundle for the given locale. |
* Get the appropriate ResourceBundle for the given locale. |
375 |
* @param baseName the name of the ResourceBundle. This should be |
* @param baseName the name of the ResourceBundle. This should be |
376 |
* a name of a Class or a properties file. See the class |
* a name of a Class or a properties file. See the class |
377 |
* description for details. |
* description for details. |
378 |
* @param locale A locale. |
* @param locale A locale. |
379 |
* @param classloader a ClassLoader. |
* @param classloader a ClassLoader. |
380 |
* @return the desired resource bundle |
* @return the desired resource bundle |
381 |
* @exception MissingResourceException |
* @throws MissingResourceException if the resource bundle can't be found |
|
* if the resource bundle couldn't be found. |
|
382 |
*/ |
*/ |
383 |
// This method is synchronized so that the cache is properly |
// This method is synchronized so that the cache is properly |
384 |
// handled. |
// handled. |
391 |
// and builds the parent chain on the fly. |
// and builds the parent chain on the fly. |
392 |
|
|
393 |
HashMap cache = (HashMap) resourceBundleCache.get(classLoader); |
HashMap cache = (HashMap) resourceBundleCache.get(classLoader); |
394 |
|
StringBuffer sb = new StringBuffer(60); |
395 |
|
sb.append(baseName).append('_').append(locale); |
396 |
|
String name = sb.toString(); |
397 |
|
|
398 |
if (cache == null) |
if (cache == null) |
399 |
{ |
{ |
400 |
cache = new HashMap(); |
cache = new HashMap(); |
402 |
} |
} |
403 |
else |
else |
404 |
{ |
{ |
|
// Fast path: If baseName + "_" + locale is in cache use it. |
|
|
String name = baseName + "_" + locale.toString(); |
|
405 |
Reference ref = (Reference) cache.get(name); |
Reference ref = (Reference) cache.get(name); |
406 |
if (ref != null) |
if (ref != null) |
407 |
{ |
{ |
430 |
bundle = tryLocalBundle(baseName, Locale.getDefault(), |
bundle = tryLocalBundle(baseName, Locale.getDefault(), |
431 |
classLoader, baseBundle, cache); |
classLoader, baseBundle, cache); |
432 |
} |
} |
433 |
|
|
434 |
|
// Check whether baseName_locale has been loaded; if not, map the |
435 |
|
// "baseName" bundle to "baseName_locale" to avoid retrying to load |
436 |
|
// baseName_locale. |
437 |
|
Reference ref = (Reference) cache.get(name); |
438 |
|
if (ref == null) |
439 |
|
cache.put(name, new SoftReference(bundle)); |
440 |
|
|
441 |
return bundle; |
return bundle; |
442 |
} |
} |
443 |
|
|
466 |
* Override this method to provide the resource for a keys. This gets |
* Override this method to provide the resource for a keys. This gets |
467 |
* called by <code>getObject</code>. If you don't have a resource |
* called by <code>getObject</code>. If you don't have a resource |
468 |
* for the given key, you should return null instead throwing a |
* for the given key, you should return null instead throwing a |
469 |
* MissingResourceException. You don't have to ask the parent, |
* MissingResourceException. You don't have to ask the parent, |
470 |
* getObject() already does this. |
* getObject() already does this. |
471 |
* |
* |
472 |
* @param key The key of the resource. |
* @param key The key of the resource. |
473 |
* @return The resource for the key, or null if not in bundle. |
* @return The resource for the key, or null if not in bundle. |
474 |
* @exception MissingResourceException |
* @throws MissingResourceException you shouldn't throw this |
|
* you shouldn't throw this. |
|
475 |
*/ |
*/ |
476 |
protected abstract Object handleGetObject(String key) |
protected abstract Object handleGetObject(String key) |
477 |
throws MissingResourceException; |
throws MissingResourceException; |