1 /* 2 * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved 28 * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved 29 * 30 * The original version of this source code and documentation 31 * is copyrighted and owned by Taligent, Inc., a wholly-owned 32 * subsidiary of IBM. These materials are provided under terms 33 * of a License Agreement between Taligent and Sun. This technology 34 * is protected by multiple US and International patents. 35 * 36 * This notice and attribution to Taligent may not be removed. 37 * Taligent is a registered trademark of Taligent, Inc. 38 * 39 */ 40 41 package java.util; 42 43 import sun.util.ResourceBundleEnumeration; 44 45 /** 46 * {@code ListResourceBundle} is an abstract subclass of 47 * {@code ResourceBundle} that manages resources for a locale 48 * in a convenient and easy to use list. See {@code ResourceBundle} for 49 * more information about resource bundles in general. 50 * 51 * <P> 52 * Subclasses must override {@code getContents} and provide an array, 53 * where each item in the array is a pair of objects. 54 * The first element of each pair is the key, which must be a 55 * {@code String}, and the second element is the value associated with 56 * that key. 57 * 58 * <p> 59 * The following <a id="sample">example</a> shows two members of a resource 60 * bundle family with the base name "MyResources". 61 * "MyResources" is the default member of the bundle family, and 62 * "MyResources_fr" is the French member. 63 * These members are based on {@code ListResourceBundle} 64 * (a related <a href="PropertyResourceBundle.html#sample">example</a> shows 65 * how you can add a bundle to this family that's based on a properties file). 66 * The keys in this example are of the form "s1" etc. The actual 67 * keys are entirely up to your choice, so long as they are the same as 68 * the keys you use in your program to retrieve the objects from the bundle. 69 * Keys are case-sensitive. 70 * <blockquote> 71 * <pre> 72 * 73 * public class MyResources extends ListResourceBundle { 74 * protected Object[][] getContents() { 75 * return new Object[][] { 76 * // LOCALIZE THIS 77 * {"s1", "The disk \"{1}\" contains {0}."}, // MessageFormat pattern 78 * {"s2", "1"}, // location of {0} in pattern 79 * {"s3", "My Disk"}, // sample disk name 80 * {"s4", "no files"}, // first ChoiceFormat choice 81 * {"s5", "one file"}, // second ChoiceFormat choice 82 * {"s6", "{0,number} files"}, // third ChoiceFormat choice 83 * {"s7", "3 Mar 96"}, // sample date 84 * {"s8", new Dimension(1,5)} // real object, not just string 85 * // END OF MATERIAL TO LOCALIZE 86 * }; 87 * } 88 * } 89 * 90 * public class MyResources_fr extends ListResourceBundle { 91 * protected Object[][] getContents() { 92 * return new Object[][] { 93 * // LOCALIZE THIS 94 * {"s1", "Le disque \"{1}\" {0}."}, // MessageFormat pattern 95 * {"s2", "1"}, // location of {0} in pattern 96 * {"s3", "Mon disque"}, // sample disk name 97 * {"s4", "ne contient pas de fichiers"}, // first ChoiceFormat choice 98 * {"s5", "contient un fichier"}, // second ChoiceFormat choice 99 * {"s6", "contient {0,number} fichiers"}, // third ChoiceFormat choice 100 * {"s7", "3 mars 1996"}, // sample date 101 * {"s8", new Dimension(1,3)} // real object, not just string 102 * // END OF MATERIAL TO LOCALIZE 103 * }; 104 * } 105 * } 106 * </pre> 107 * </blockquote> 108 * 109 * <p> 110 * The implementation of a {@code ListResourceBundle} subclass must be thread-safe 111 * if it's simultaneously used by multiple threads. The default implementations 112 * of the methods in this class are thread-safe. 113 * 114 * @see ResourceBundle 115 * @see PropertyResourceBundle 116 * @since 1.1 117 */ 118 public abstract class ListResourceBundle extends ResourceBundle { 119 /** 120 * Sole constructor. (For invocation by subclass constructors, typically 121 * implicit.) 122 */ ListResourceBundle()123 public ListResourceBundle() { 124 } 125 126 // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification. handleGetObject(String key)127 public final Object handleGetObject(String key) { 128 // lazily load the lookup hashtable. 129 if (lookup == null) { 130 loadLookup(); 131 } 132 if (key == null) { 133 throw new NullPointerException(); 134 } 135 return lookup.get(key); // this class ignores locales 136 } 137 138 /** 139 * Returns an {@code Enumeration} of the keys contained in 140 * this {@code ResourceBundle} and its parent bundles. 141 * 142 * @return an {@code Enumeration} of the keys contained in 143 * this {@code ResourceBundle} and its parent bundles. 144 * @see #keySet() 145 */ getKeys()146 public Enumeration<String> getKeys() { 147 // lazily load the lookup hashtable. 148 if (lookup == null) { 149 loadLookup(); 150 } 151 152 ResourceBundle parent = this.parent; 153 return new ResourceBundleEnumeration(lookup.keySet(), 154 (parent != null) ? parent.getKeys() : null); 155 } 156 157 /** 158 * Returns a {@code Set} of the keys contained 159 * <em>only</em> in this {@code ResourceBundle}. 160 * 161 * @return a {@code Set} of the keys contained only in this 162 * {@code ResourceBundle} 163 * @since 1.6 164 * @see #keySet() 165 */ handleKeySet()166 protected Set<String> handleKeySet() { 167 if (lookup == null) { 168 loadLookup(); 169 } 170 return lookup.keySet(); 171 } 172 173 /** 174 * Returns an array in which each item is a pair of objects in an 175 * {@code Object} array. The first element of each pair is 176 * the key, which must be a {@code String}, and the second 177 * element is the value associated with that key. See the class 178 * description for details. 179 * 180 * @return an array of an {@code Object} array representing a 181 * key-value pair. 182 */ getContents()183 protected abstract Object[][] getContents(); 184 185 // ==================privates==================== 186 187 /** 188 * We lazily load the lookup hashtable. This function does the 189 * loading. 190 */ loadLookup()191 private synchronized void loadLookup() { 192 if (lookup != null) 193 return; 194 195 Object[][] contents = getContents(); 196 HashMap<String,Object> temp = new HashMap<>(contents.length); 197 for (Object[] content : contents) { 198 // key must be non-null String, value must be non-null 199 String key = (String) content[0]; 200 Object value = content[1]; 201 if (key == null || value == null) { 202 throw new NullPointerException(); 203 } 204 temp.put(key, value); 205 } 206 lookup = temp; 207 } 208 209 private volatile Map<String,Object> lookup; 210 } 211