1. /*
  2. * @(#)ListResourceBundle.java 1.16 00/01/19
  3. *
  4. * Copyright 1996-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. /*
  11. * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  12. * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  13. *
  14. * The original version of this source code and documentation
  15. * is copyrighted and owned by Taligent, Inc., a wholly-owned
  16. * subsidiary of IBM. These materials are provided under terms
  17. * of a License Agreement between Taligent and Sun. This technology
  18. * is protected by multiple US and International patents.
  19. *
  20. * This notice and attribution to Taligent may not be removed.
  21. * Taligent is a registered trademark of Taligent, Inc.
  22. *
  23. */
  24. package java.util;
  25. import java.util.Hashtable;
  26. /**
  27. * <code>ListResourceBundle</code> is a abstract subclass of
  28. * <code>ResourceBundle</code> that manages resources for a locale
  29. * in a convenient and easy to use list. See <code>ResourceBundle</code> for
  30. * more information about resource bundles in general.
  31. *
  32. * <P>
  33. * Subclasses must override <code>getContents</code> and provide an array,
  34. * where each item in the array is a pair of objects.
  35. * The first element of each pair is a <code>String</code> key, and the second
  36. * is the value associated with that key. [Right now, there's no error-checking
  37. * code to enforce this, so you could specify key-value pairs that have
  38. * something other than a String as a key. But since the interfaces are defined
  39. * in terms of String, any value with a key that isn't a String will be
  40. * inaccessible.]
  41. *
  42. * <p>
  43. * In the following example, the keys are of the form "s1"... The actual
  44. * keys are entirely up to your choice, so long as they are the same as
  45. * the keys you use in your program to retrieve the objects from the bundle.
  46. * Keys are case-sensitive. <code>MyResource</code> is the default version
  47. * of the bundle family, and <code>MyResource_fr</code> is the french version:
  48. * <blockquote>
  49. * <pre>
  50. * //====================
  51. * class MyResource extends ListResourceBundle {
  52. * public Object[][] getContents() {
  53. * return contents;
  54. * }
  55. * static final Object[][] contents = {
  56. * // LOCALIZE THIS
  57. * {"s1", "3"}, // starting value in choice field
  58. * {"s2", "MyDisk"}, // starting value in string field
  59. * {"s3", "3 Mar 96"}, // starting value in date field
  60. * {"s4", "The disk '{1}' contained {0} on {2}."}, // initial pattern
  61. * {"s5", "0"}, // first choice number
  62. * {"s6", "no files"}, // first choice value
  63. * {"s7", "1"}, // second choice number
  64. * {"s8", "one file"}, // second choice value
  65. * {"s9", "2"}, // third choice number
  66. * {"s10", "{0}|3 files"}, // third choice value
  67. * {"s11", "format threw an exception: {0}"}, // generic exception message
  68. * {"s12", "ERROR"}, // what to show in field in case of error
  69. * {"s14", "Result"}, // label for formatted stuff
  70. * {"s13", "Dialog"}, // standard font
  71. * {"s15", "Pattern"}, // label for standard pattern
  72. * {"s16", new Dimension(1,5)} // real object, not just string
  73. * // END OF MATERIAL TO LOCALIZE
  74. * };
  75. * }
  76. * //====================
  77. * class MyResource_fr extends ListResourceBundle {
  78. * public Object[][] getContents() {
  79. * return contents;
  80. }
  81. * static final Object[][] contents = {
  82. * // LOCALIZE THIS
  83. * {"s1", "3"}, // starting value in choice field
  84. * {"s2", "MonDisk"}, // starting value in string field
  85. * {"s3", "3 Mar 96"}, // starting value in date field
  86. * {"s4", "Le disk '{1}' a {0} a {2}."}, // initial pattern
  87. * {"s5", "0"}, // first choice number
  88. * {"s6", "pas de files"}, // first choice value
  89. * {"s7", "1"}, // second choice number
  90. * {"s8", "une file"}, // second choice value
  91. * {"s9", "2"}, // third choice number
  92. * {"s10", "{0}|3 files"}, // third choice value
  93. * {"s11", "Le format a jete une exception: {0}"}, // generic exception message
  94. * {"s12", "ERROR"}, // what to show in field in case of error
  95. * {"s14", "Resulte"}, // label for formatted stuff
  96. * {"s13", "Dialogue"}, // standard font
  97. * {"s15", "Pattern"}, // label for standard pattern
  98. * {"s16", new Dimension(1,3)} // real object, not just string
  99. * // END OF MATERIAL TO LOCALIZE
  100. * };
  101. * }
  102. * </pre>
  103. * </blockquote>
  104. * @see ResourceBundle
  105. * @see PropertyResourceBundle
  106. * @since JDK1.1
  107. */
  108. public abstract class ListResourceBundle extends ResourceBundle {
  109. /**
  110. * Sole constructor. (For invocation by subclass constructors, typically
  111. * implicit.)
  112. */
  113. public ListResourceBundle() {
  114. }
  115. /**
  116. * Override of ResourceBundle, same semantics
  117. */
  118. public final Object handleGetObject(String key) {
  119. // lazily load the lookup hashtable.
  120. if (lookup == null) {
  121. loadLookup();
  122. }
  123. return lookup.get(key); // this class ignores locales
  124. }
  125. /**
  126. * Implementation of ResourceBundle.getKeys.
  127. */
  128. public Enumeration getKeys() {
  129. // lazily load the lookup hashtable.
  130. if (lookup == null) {
  131. loadLookup();
  132. }
  133. Enumeration result = null;
  134. if (parent != null) {
  135. final Enumeration myKeys = lookup.keys();
  136. final Enumeration parentKeys = parent.getKeys();
  137. result = new Enumeration() {
  138. public boolean hasMoreElements() {
  139. if (temp == null)
  140. nextElement();
  141. return temp != null;
  142. }
  143. public Object nextElement() {
  144. Object returnVal = temp;
  145. if (myKeys.hasMoreElements())
  146. temp = myKeys.nextElement();
  147. else {
  148. temp = null;
  149. while (temp == null && parentKeys.hasMoreElements()) {
  150. temp = parentKeys.nextElement();
  151. if (lookup.containsKey(temp))
  152. temp = null;
  153. }
  154. }
  155. return returnVal;
  156. }
  157. Object temp = null;
  158. };
  159. } else {
  160. result = lookup.keys();
  161. }
  162. return result;
  163. }
  164. /**
  165. * See class description.
  166. */
  167. abstract protected Object[][] getContents();
  168. // ==================privates====================
  169. /**
  170. * We lazily load the lookup hashtable. This function does the
  171. * loading.
  172. */
  173. private synchronized void loadLookup() {
  174. if (lookup != null)
  175. return;
  176. Object[][] contents = getContents();
  177. Hashtable temp = new Hashtable(contents.length);
  178. for (int i = 0; i < contents.length; ++i) {
  179. temp.put(contents[i][0],contents[i][1]);
  180. }
  181. lookup = temp;
  182. }
  183. private Hashtable lookup = null;
  184. }