1 /*
   2  * Copyright (c) 1996, 2013, 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  *
 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      */
 123     public ListResourceBundle() {
 124     }
 125 
 126     // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
 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</code> of the keys contained in
 140      * this <code>ResourceBundle</code> and its parent bundles.
 141      *
 142      * @return an <code>Enumeration</code> of the keys contained in
 143      *         this <code>ResourceBundle</code> and its parent bundles.
 144      * @see #keySet()
 145      */
 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</code> of the keys contained
 159      * <em>only</em> in this <code>ResourceBundle</code>.
 160      *
 161      * @return a <code>Set</code> of the keys contained only in this
 162      *         <code>ResourceBundle</code>
 163      * @since 1.6
 164      * @see #keySet()
 165      */
 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</code> array. The first element of each pair is
 176      * the key, which must be a <code>String</code>, 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</code> array representing a
 181      * key-value pair.
 182      */
 183     protected abstract Object[][] getContents();
 184 
 185     // ==================privates====================
 186 
 187     /**
 188      * We lazily load the lookup hashtable.  This function does the
 189      * loading.
 190      */
 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 Map<String,Object> lookup = null;
 210 }