1 /*
   2  * Copyright (c) 1996, 2005, 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</code> is an abstract subclass of
  47  * <code>ResourceBundle</code> that manages resources for a locale
  48  * in a convenient and easy to use list. See <code>ResourceBundle</code> for
  49  * more information about resource bundles in general.
  50  *
  51  * <P>
  52  * Subclasses must override <code>getContents</code> 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</code>, and the second element is the value associated with
  56  * that key.
  57  *
  58  * <p>
  59  * The following <a name="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</code>
  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  * @see ResourceBundle
 109  * @see PropertyResourceBundle
 110  * @since JDK1.1
 111  */
 112 public abstract class ListResourceBundle extends ResourceBundle {
 113     /**
 114      * Sole constructor.  (For invocation by subclass constructors, typically
 115      * implicit.)
 116      */
 117     public ListResourceBundle() {
 118     }
 119 
 120     // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
 121     public final Object handleGetObject(String key) {
 122         // lazily load the lookup hashtable.
 123         if (lookup == null) {
 124             loadLookup();
 125         }
 126         if (key == null) {
 127             throw new NullPointerException();
 128         }
 129         return lookup.get(key); // this class ignores locales
 130     }
 131 
 132     /**
 133      * Returns an <code>Enumeration</code> of the keys contained in
 134      * this <code>ResourceBundle</code> and its parent bundles.
 135      *
 136      * @return an <code>Enumeration</code> of the keys contained in
 137      *         this <code>ResourceBundle</code> and its parent bundles.
 138      * @see #keySet()
 139      */
 140     public Enumeration<String> getKeys() {
 141         // lazily load the lookup hashtable.
 142         if (lookup == null) {
 143             loadLookup();
 144         }
 145 
 146         ResourceBundle parent = this.parent;
 147         return new ResourceBundleEnumeration(lookup.keySet(),
 148                 (parent != null) ? parent.getKeys() : null);
 149     }
 150 
 151     /**
 152      * Returns a <code>Set</code> of the keys contained
 153      * <em>only</em> in this <code>ResourceBundle</code>.
 154      *
 155      * @return a <code>Set</code> of the keys contained only in this
 156      *         <code>ResourceBundle</code>
 157      * @since 1.6
 158      * @see #keySet()
 159      */
 160     protected Set<String> handleKeySet() {
 161         if (lookup == null) {
 162             loadLookup();
 163         }
 164         return lookup.keySet();
 165     }
 166 
 167     /**
 168      * Returns an array in which each item is a pair of objects in an
 169      * <code>Object</code> array. The first element of each pair is
 170      * the key, which must be a <code>String</code>, and the second
 171      * element is the value associated with that key.  See the class
 172      * description for details.
 173      *
 174      * @return an array of an <code>Object</code> array representing a
 175      * key-value pair.
 176      */
 177     abstract protected Object[][] getContents();
 178 
 179     // ==================privates====================
 180 
 181     /**
 182      * We lazily load the lookup hashtable.  This function does the
 183      * loading.
 184      */
 185     private synchronized void loadLookup() {
 186         if (lookup != null)
 187             return;
 188 
 189         Object[][] contents = getContents();
 190         HashMap<String,Object> temp = new HashMap<>(contents.length);
 191         for (int i = 0; i < contents.length; ++i) {
 192             // key must be non-null String, value must be non-null
 193             String key = (String) contents[i][0];
 194             Object value = contents[i][1];
 195             if (key == null || value == null) {
 196                 throw new NullPointerException();
 197             }
 198             temp.put(key, value);
 199         }
 200         lookup = temp;
 201     }
 202 
 203     private Map<String,Object> lookup = null;
 204 }