| 1 | /* java.util.ResourceBundle
|
|---|
| 2 | Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
|
|---|
| 3 |
|
|---|
| 4 | This file is part of GNU Classpath.
|
|---|
| 5 |
|
|---|
| 6 | GNU Classpath is free software; you can redistribute it and/or modify
|
|---|
| 7 | it under the terms of the GNU General Public License as published by
|
|---|
| 8 | the Free Software Foundation; either version 2, or (at your option)
|
|---|
| 9 | any later version.
|
|---|
| 10 |
|
|---|
| 11 | GNU Classpath is distributed in the hope that it will be useful, but
|
|---|
| 12 | WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|---|
| 14 | General Public License for more details.
|
|---|
| 15 |
|
|---|
| 16 | You should have received a copy of the GNU General Public License
|
|---|
| 17 | along with GNU Classpath; see the file COPYING. If not, write to the
|
|---|
| 18 | Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|---|
| 19 | 02111-1307 USA.
|
|---|
| 20 |
|
|---|
| 21 | Linking this library statically or dynamically with other modules is
|
|---|
| 22 | making a combined work based on this library. Thus, the terms and
|
|---|
| 23 | conditions of the GNU General Public License cover the whole
|
|---|
| 24 | combination.
|
|---|
| 25 |
|
|---|
| 26 | As a special exception, the copyright holders of this library give you
|
|---|
| 27 | permission to link this library with independent modules to produce an
|
|---|
| 28 | executable, regardless of the license terms of these independent
|
|---|
| 29 | modules, and to copy and distribute the resulting executable under
|
|---|
| 30 | terms of your choice, provided that you also meet, for each linked
|
|---|
| 31 | independent module, the terms and conditions of the license of that
|
|---|
| 32 | module. An independent module is a module which is not derived from
|
|---|
| 33 | or based on this library. If you modify this library, you may extend
|
|---|
| 34 | this exception to your version of the library, but you are not
|
|---|
| 35 | obligated to do so. If you do not wish to do so, delete this
|
|---|
| 36 | exception statement from your version. */
|
|---|
| 37 |
|
|---|
| 38 |
|
|---|
| 39 | package java.util;
|
|---|
| 40 | import java.lang.ref.Reference;
|
|---|
| 41 | import java.lang.ref.SoftReference;
|
|---|
| 42 | import java.security.AccessController;
|
|---|
| 43 | import java.security.PrivilegedAction;
|
|---|
| 44 | import gnu.classpath.Configuration;
|
|---|
| 45 |
|
|---|
| 46 | /**
|
|---|
| 47 | * A resource bundle contains locale-specific data. If you need
|
|---|
| 48 | * localized data, you can load a resource bundle that matches the
|
|---|
| 49 | * locale with <code>getBundle</code>. Now you can get your object by
|
|---|
| 50 | * calling <code>getObject</code> or <code>getString</code> on that
|
|---|
| 51 | * bundle.
|
|---|
| 52 | * <br>
|
|---|
| 53 | * When a bundle is demanded for a specific locale, the ResourceBundle
|
|---|
| 54 | * is searched in following order (<i>def. language code<i> stands for
|
|---|
| 55 | * the two letter ISO language code of the default locale (see
|
|---|
| 56 | * <code>Locale.getDefault()</code>).
|
|---|
| 57 | * <pre>
|
|---|
| 58 | * 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 code</i>_<i>def. country code</i>_<i>def. variant</i>
|
|---|
| 62 | * baseName_<i>def. language code</i>_<i>def. country code</i>
|
|---|
| 63 | * baseName_<i>def. language code</i>
|
|---|
| 64 | * baseName
|
|---|
| 65 | * </pre>
|
|---|
| 66 | *
|
|---|
| 67 | * A bundle is backed up, by less specific bundle (omiting variant,
|
|---|
| 68 | * country or language). But it is not backed up by the default
|
|---|
| 69 | * language locale.
|
|---|
| 70 | * <br>
|
|---|
| 71 | * 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 | * <br>
|
|---|
| 76 | * When a bundle is searched, we look first for a class with
|
|---|
| 77 | * the given name and if that is not found for a file with
|
|---|
| 78 | * <code>.properties</code> extension in the classpath. The name
|
|---|
| 79 | * must be a fully qualified classname (with dots as path separators).
|
|---|
| 80 | * <br>
|
|---|
| 81 | * (Note: This implementation always backs up the class with a
|
|---|
| 82 | * properties file if that is existing, but you shouldn't rely on
|
|---|
| 83 | * this, if you want to be compatible to the standard JDK.)
|
|---|
| 84 | *
|
|---|
| 85 | * @see Locale
|
|---|
| 86 | * @see PropertyResourceBundle
|
|---|
| 87 | * @author Jochen Hoenicke */
|
|---|
| 88 | public abstract class ResourceBundle
|
|---|
| 89 | {
|
|---|
| 90 | /**
|
|---|
| 91 | * The parent bundle. This is consulted when you call getObject
|
|---|
| 92 | * and there is no such resource in the current bundle. This
|
|---|
| 93 | * field may be null.
|
|---|
| 94 | */
|
|---|
| 95 | protected ResourceBundle parent;
|
|---|
| 96 |
|
|---|
| 97 | /**
|
|---|
| 98 | * The locale of this resource bundle. You can read this with
|
|---|
| 99 | * <code>getLocale</code> and it is automatically set in
|
|---|
| 100 | * <code>getBundle</code>.
|
|---|
| 101 | */
|
|---|
| 102 | private Locale locale;
|
|---|
| 103 |
|
|---|
| 104 | /**
|
|---|
| 105 | * We override SecurityManager in order to access getClassContext().
|
|---|
| 106 | */
|
|---|
| 107 | static class Security extends SecurityManager
|
|---|
| 108 | {
|
|---|
| 109 | /** Return the ClassLoader of the class which called into this
|
|---|
| 110 | ResourceBundle, or null if it cannot be determined. */
|
|---|
| 111 | ClassLoader getCallingClassLoader()
|
|---|
| 112 | {
|
|---|
| 113 | Class[] stack = super.getClassContext();
|
|---|
| 114 | for (int i = 0; i < stack.length; i++)
|
|---|
| 115 | if (stack[i] != Security.class && stack[i] != ResourceBundle.class)
|
|---|
| 116 | return stack[i].getClassLoader();
|
|---|
| 117 | return null;
|
|---|
| 118 | }
|
|---|
| 119 | }
|
|---|
| 120 |
|
|---|
| 121 | // This will always work since java.util classes have (all) system
|
|---|
| 122 | // permissions.
|
|---|
| 123 | static Security security = (Security) AccessController.doPrivileged
|
|---|
| 124 | (
|
|---|
| 125 | new PrivilegedAction()
|
|---|
| 126 | {
|
|---|
| 127 | public Object run()
|
|---|
| 128 | {
|
|---|
| 129 | return new Security();
|
|---|
| 130 | }
|
|---|
| 131 | }
|
|---|
| 132 | );
|
|---|
| 133 |
|
|---|
| 134 | /**
|
|---|
| 135 | * The constructor. It does nothing special.
|
|---|
| 136 | */
|
|---|
| 137 | public ResourceBundle()
|
|---|
| 138 | {
|
|---|
| 139 | }
|
|---|
| 140 |
|
|---|
| 141 | /**
|
|---|
| 142 | * Get a String from this resource bundle. Since most localized
|
|---|
| 143 | * Objects are Strings, this method provides a convenient way to get
|
|---|
| 144 | * them without casting.
|
|---|
| 145 | * @param key the name of the resource.
|
|---|
| 146 | * @exception MissingResourceException
|
|---|
| 147 | * if that particular object could not be found in this bundle nor
|
|---|
| 148 | * the parent bundle.
|
|---|
| 149 | */
|
|---|
| 150 | public final String getString(String key) throws MissingResourceException
|
|---|
| 151 | {
|
|---|
| 152 | return (String) getObject(key);
|
|---|
| 153 | }
|
|---|
| 154 |
|
|---|
| 155 | /**
|
|---|
| 156 | * Get an array of Strings from this resource bundle. This method
|
|---|
| 157 | * provides a convenient way to get it without casting.
|
|---|
| 158 | * @param key the name of the resource.
|
|---|
| 159 | * @exception MissingResourceException
|
|---|
| 160 | * if that particular object could not be found in this bundle nor
|
|---|
| 161 | * the parent bundle.
|
|---|
| 162 | */
|
|---|
| 163 | public final String[] getStringArray(String key)
|
|---|
| 164 | throws MissingResourceException
|
|---|
| 165 | {
|
|---|
| 166 | return (String[]) getObject(key);
|
|---|
| 167 | }
|
|---|
| 168 |
|
|---|
| 169 | /**
|
|---|
| 170 | * Get an object from this resource bundle.
|
|---|
| 171 | * @param key the name of the resource.
|
|---|
| 172 | * @exception MissingResourceException
|
|---|
| 173 | * if that particular object could not be found in this bundle nor
|
|---|
| 174 | * the parent bundle.
|
|---|
| 175 | */
|
|---|
| 176 | public final Object getObject(String key) throws MissingResourceException
|
|---|
| 177 | {
|
|---|
| 178 | for (ResourceBundle bundle = this; bundle != null; bundle = bundle.parent)
|
|---|
| 179 | {
|
|---|
| 180 | try
|
|---|
| 181 | {
|
|---|
| 182 | Object o = bundle.handleGetObject(key);
|
|---|
| 183 | if (o != null)
|
|---|
| 184 | return o;
|
|---|
| 185 | }
|
|---|
| 186 | catch (MissingResourceException ex)
|
|---|
| 187 | {
|
|---|
| 188 | }
|
|---|
| 189 | }
|
|---|
| 190 | throw new MissingResourceException
|
|---|
| 191 | ("Key not found", getClass().getName(), key);
|
|---|
| 192 | }
|
|---|
| 193 |
|
|---|
| 194 | /**
|
|---|
| 195 | * Get the appropriate ResourceBundle for the default locale.
|
|---|
| 196 | * @param baseName the name of the ResourceBundle. This should be
|
|---|
| 197 | * a name of a Class or a properties-File. See the class
|
|---|
| 198 | * description for details.
|
|---|
| 199 | * @return the desired resource bundle
|
|---|
| 200 | * @exception MissingResourceException
|
|---|
| 201 | * if the resource bundle couldn't be found.
|
|---|
| 202 | */
|
|---|
| 203 | public static final ResourceBundle getBundle(String baseName)
|
|---|
| 204 | throws MissingResourceException
|
|---|
| 205 | {
|
|---|
| 206 | return getBundle(baseName, Locale.getDefault(),
|
|---|
| 207 | security.getCallingClassLoader());
|
|---|
| 208 | }
|
|---|
| 209 |
|
|---|
| 210 | /**
|
|---|
| 211 | * Get the appropriate ResourceBundle for the given locale.
|
|---|
| 212 | * @param baseName the name of the ResourceBundle. This should be
|
|---|
| 213 | * a name of a Class or a properties-File. See the class
|
|---|
| 214 | * description for details.
|
|---|
| 215 | * @param locale A locale.
|
|---|
| 216 | * @return the desired resource bundle
|
|---|
| 217 | * @exception MissingResourceException
|
|---|
| 218 | * if the resource bundle couldn't be found.
|
|---|
| 219 | */
|
|---|
| 220 | public static final ResourceBundle getBundle(String baseName,
|
|---|
| 221 | Locale locale)
|
|---|
| 222 | throws MissingResourceException
|
|---|
| 223 | {
|
|---|
| 224 | return getBundle(baseName, locale, security.getCallingClassLoader());
|
|---|
| 225 | }
|
|---|
| 226 |
|
|---|
| 227 | /**
|
|---|
| 228 | * The resource bundle cache. This is a two-level hash map: The key
|
|---|
| 229 | * is the class loader, the value is a new HashMap. The key of this
|
|---|
| 230 | * second hash map is the localized name, the value is a soft
|
|---|
| 231 | * references to the resource bundle. */
|
|---|
| 232 | private static Map resourceBundleCache = new HashMap();
|
|---|
| 233 |
|
|---|
| 234 | /**
|
|---|
| 235 | * The `empty' locale is created once in order to optimize
|
|---|
| 236 | * tryBundle().
|
|---|
| 237 | */
|
|---|
| 238 | private static final Locale emptyLocale = new Locale ("", "");
|
|---|
| 239 |
|
|---|
| 240 | /**
|
|---|
| 241 | * Tries to load a class or a property file with the specified name.
|
|---|
| 242 | * @param localizedName the name.
|
|---|
| 243 | * @param locale the locale, that must be used exactly.
|
|---|
| 244 | * @param classloader the classloader.
|
|---|
| 245 | * @param bundle the back up (parent) bundle
|
|---|
| 246 | * @return the resource bundle if that could be loaded, otherwise
|
|---|
| 247 | * <code>bundle</code>.
|
|---|
| 248 | */
|
|---|
| 249 | private static final ResourceBundle tryBundle(String localizedName,
|
|---|
| 250 | Locale locale,
|
|---|
| 251 | ClassLoader classloader,
|
|---|
| 252 | ResourceBundle bundle,
|
|---|
| 253 | HashMap cache)
|
|---|
| 254 | {
|
|---|
| 255 | {
|
|---|
| 256 | // First look into the cache.
|
|---|
| 257 | // XXX We should remove cleared references from the cache.
|
|---|
| 258 | Reference ref = (Reference) cache.get(localizedName);
|
|---|
| 259 | if (ref != null)
|
|---|
| 260 | {
|
|---|
| 261 | ResourceBundle rb = (ResourceBundle) ref.get();
|
|---|
| 262 | if (rb != null)
|
|---|
| 263 | // rb should already have the right parent, except if
|
|---|
| 264 | // something very strange happened.
|
|---|
| 265 | return rb;
|
|---|
| 266 | }
|
|---|
| 267 | }
|
|---|
| 268 |
|
|---|
| 269 | // foundBundle holds exact matches for the localizedName resource
|
|---|
| 270 | // bundle, which may later be cached.
|
|---|
| 271 | ResourceBundle foundBundle = null;
|
|---|
| 272 |
|
|---|
| 273 | try
|
|---|
| 274 | {
|
|---|
| 275 | java.io.InputStream is;
|
|---|
| 276 | final String resourceName =
|
|---|
| 277 | localizedName.replace('.', '/') + ".properties";
|
|---|
| 278 | if (classloader == null)
|
|---|
| 279 | is = ClassLoader.getSystemResourceAsStream (resourceName);
|
|---|
| 280 | else
|
|---|
| 281 | is = classloader.getResourceAsStream (resourceName);
|
|---|
| 282 | if (is != null)
|
|---|
| 283 | {
|
|---|
| 284 | foundBundle = new PropertyResourceBundle(is);
|
|---|
| 285 | foundBundle.parent = bundle;
|
|---|
| 286 | foundBundle.locale = locale;
|
|---|
| 287 | }
|
|---|
| 288 | }
|
|---|
| 289 | catch (java.io.IOException ex)
|
|---|
| 290 | {
|
|---|
| 291 | }
|
|---|
| 292 |
|
|---|
| 293 | try
|
|---|
| 294 | {
|
|---|
| 295 | Class rbClass;
|
|---|
| 296 | if (classloader == null)
|
|---|
| 297 | rbClass = Class.forName(localizedName);
|
|---|
| 298 | else
|
|---|
| 299 | rbClass = classloader.loadClass(localizedName);
|
|---|
| 300 | foundBundle = (ResourceBundle) rbClass.newInstance();
|
|---|
| 301 | foundBundle.parent = bundle;
|
|---|
| 302 | foundBundle.locale = locale;
|
|---|
| 303 | }
|
|---|
| 304 | catch (ClassNotFoundException ex)
|
|---|
| 305 | {
|
|---|
| 306 | }
|
|---|
| 307 | catch (IllegalAccessException ex)
|
|---|
| 308 | {
|
|---|
| 309 | }
|
|---|
| 310 | catch (InstantiationException ex)
|
|---|
| 311 | {
|
|---|
| 312 | // ignore them all
|
|---|
| 313 | // XXX should we also ignore ClassCastException?
|
|---|
| 314 | }
|
|---|
| 315 |
|
|---|
| 316 | if (foundBundle != null)
|
|---|
| 317 | cache.put(localizedName, new SoftReference(foundBundle));
|
|---|
| 318 |
|
|---|
| 319 | return foundBundle != null ? foundBundle : bundle;
|
|---|
| 320 | }
|
|---|
| 321 |
|
|---|
| 322 | /**
|
|---|
| 323 | * Tries to load a the bundle for a given locale, also loads the backup
|
|---|
| 324 | * locales with the same language.
|
|---|
| 325 | *
|
|---|
| 326 | * @param name the name.
|
|---|
| 327 | * @param locale the locale, that must be used exactly.
|
|---|
| 328 | * @param classloader the classloader.
|
|---|
| 329 | * @param bundle the back up (parent) bundle
|
|---|
| 330 | * @return the resource bundle if that could be loaded, otherwise
|
|---|
| 331 | * <code>bundle</code>.
|
|---|
| 332 | */
|
|---|
| 333 | private static final ResourceBundle tryLocalBundle(String baseName,
|
|---|
| 334 | Locale locale,
|
|---|
| 335 | ClassLoader classloader,
|
|---|
| 336 | ResourceBundle bundle,
|
|---|
| 337 | HashMap cache)
|
|---|
| 338 | {
|
|---|
| 339 | final String language = locale.getLanguage();
|
|---|
| 340 |
|
|---|
| 341 | if (language.length() > 0)
|
|---|
| 342 | {
|
|---|
| 343 | final String country = locale.getCountry();
|
|---|
| 344 | String name = baseName + "_" + language;
|
|---|
| 345 |
|
|---|
| 346 | if (country.length() != 0)
|
|---|
| 347 | {
|
|---|
| 348 | bundle = tryBundle(name,
|
|---|
| 349 | new Locale(language, ""),
|
|---|
| 350 | classloader, bundle, cache);
|
|---|
| 351 |
|
|---|
| 352 | name += "_" + country;
|
|---|
| 353 |
|
|---|
| 354 | final String variant = locale.getVariant();
|
|---|
| 355 |
|
|---|
| 356 | if (variant.length() != 0)
|
|---|
| 357 | {
|
|---|
| 358 | bundle = tryBundle(name,
|
|---|
| 359 | new Locale(language,
|
|---|
| 360 | country),
|
|---|
| 361 | classloader, bundle, cache);
|
|---|
| 362 |
|
|---|
| 363 | name += "_" + variant;
|
|---|
| 364 | }
|
|---|
| 365 | }
|
|---|
| 366 | bundle = tryBundle(name, locale, classloader, bundle, cache);
|
|---|
| 367 | }
|
|---|
| 368 | return bundle;
|
|---|
| 369 | }
|
|---|
| 370 |
|
|---|
| 371 | /**
|
|---|
| 372 | * Get the appropriate ResourceBundle for the given locale.
|
|---|
| 373 | * @param baseName the name of the ResourceBundle. This should be
|
|---|
| 374 | * a name of a Class or a properties file. See the class
|
|---|
| 375 | * description for details.
|
|---|
| 376 | * @param locale A locale.
|
|---|
| 377 | * @param classloader a ClassLoader.
|
|---|
| 378 | * @return the desired resource bundle
|
|---|
| 379 | * @exception MissingResourceException
|
|---|
| 380 | * if the resource bundle couldn't be found.
|
|---|
| 381 | */
|
|---|
| 382 | // This method is synchronized so that the cache is properly
|
|---|
| 383 | // handled.
|
|---|
| 384 | public static final synchronized ResourceBundle getBundle(String baseName,
|
|---|
| 385 | Locale locale,
|
|---|
| 386 | ClassLoader classLoader)
|
|---|
| 387 | throws MissingResourceException
|
|---|
| 388 | {
|
|---|
| 389 | // This implementation searches the bundle in the reverse direction
|
|---|
| 390 | // and builds the parent chain on the fly.
|
|---|
| 391 |
|
|---|
| 392 | HashMap cache = (HashMap) resourceBundleCache.get(classLoader);
|
|---|
| 393 | if (cache == null)
|
|---|
| 394 | {
|
|---|
| 395 | cache = new HashMap();
|
|---|
| 396 | resourceBundleCache.put(classLoader, cache);
|
|---|
| 397 | }
|
|---|
| 398 | else
|
|---|
| 399 | {
|
|---|
| 400 | // Fast path: If baseName + "_" + locale is in cache use it.
|
|---|
| 401 | String name = baseName + "_" + locale.toString();
|
|---|
| 402 | Reference ref = (Reference) cache.get(name);
|
|---|
| 403 | if (ref != null)
|
|---|
| 404 | {
|
|---|
| 405 | ResourceBundle rb = (ResourceBundle) ref.get();
|
|---|
| 406 | if (rb != null)
|
|---|
| 407 | // rb should already have the right parent, except if
|
|---|
| 408 | // something very strange happened.
|
|---|
| 409 | return rb;
|
|---|
| 410 | }
|
|---|
| 411 | }
|
|---|
| 412 |
|
|---|
| 413 | ResourceBundle baseBundle = tryBundle(baseName, emptyLocale,
|
|---|
| 414 | classLoader, null, cache);
|
|---|
| 415 | if (baseBundle == null)
|
|---|
| 416 | // JDK says, that if one provides a bundle base_en_UK, one
|
|---|
| 417 | // must also provide the bundles base_en and base.
|
|---|
| 418 | // This implies that if there is no bundle for base, there
|
|---|
| 419 | // is no bundle at all.
|
|---|
| 420 | throw new MissingResourceException("Bundle " + baseName + " not found", baseName, "");
|
|---|
| 421 |
|
|---|
| 422 | // Now use the default locale.
|
|---|
| 423 | ResourceBundle bundle = tryLocalBundle(baseName, locale,
|
|---|
| 424 | classLoader, baseBundle, cache);
|
|---|
| 425 | if (bundle == baseBundle && !locale.equals(Locale.getDefault()))
|
|---|
| 426 | {
|
|---|
| 427 | bundle = tryLocalBundle(baseName, Locale.getDefault(),
|
|---|
| 428 | classLoader, baseBundle, cache);
|
|---|
| 429 | }
|
|---|
| 430 | return bundle;
|
|---|
| 431 | }
|
|---|
| 432 |
|
|---|
| 433 | /**
|
|---|
| 434 | * Return the actual locale of this bundle. You can use it after
|
|---|
| 435 | * calling getBundle, to know if the bundle for the desired locale
|
|---|
| 436 | * was loaded or if the fall back was used.
|
|---|
| 437 | */
|
|---|
| 438 | public Locale getLocale()
|
|---|
| 439 | {
|
|---|
| 440 | return locale;
|
|---|
| 441 | }
|
|---|
| 442 |
|
|---|
| 443 | /**
|
|---|
| 444 | * Set the parent of this bundle. This is consulted when you call
|
|---|
| 445 | * getObject and there is no such resource in the current bundle.
|
|---|
| 446 | * @param parent the parent of this bundle.
|
|---|
| 447 | */
|
|---|
| 448 | protected void setParent(ResourceBundle parent)
|
|---|
| 449 | {
|
|---|
| 450 | // Shall we ignore the old parent?
|
|---|
| 451 | this.parent = parent;
|
|---|
| 452 | }
|
|---|
| 453 |
|
|---|
| 454 | /**
|
|---|
| 455 | * Override this method to provide the resource for a keys. This gets
|
|---|
| 456 | * called by <code>getObject</code>. If you don't have a resource
|
|---|
| 457 | * for the given key, you should return null instead throwing a
|
|---|
| 458 | * MissingResourceException. You don't have to ask the parent,
|
|---|
| 459 | * getObject() already does this.
|
|---|
| 460 | *
|
|---|
| 461 | * @param key The key of the resource.
|
|---|
| 462 | * @return The resource for the key, or null if not in bundle.
|
|---|
| 463 | * @exception MissingResourceException
|
|---|
| 464 | * you shouldn't throw this.
|
|---|
| 465 | */
|
|---|
| 466 | protected abstract Object handleGetObject(String key)
|
|---|
| 467 | throws MissingResourceException;
|
|---|
| 468 |
|
|---|
| 469 | /**
|
|---|
| 470 | * This method should return all keys for which a resource exists.
|
|---|
| 471 | * @return An enumeration of the keys.
|
|---|
| 472 | */
|
|---|
| 473 | public abstract Enumeration getKeys();
|
|---|
| 474 | }
|
|---|