content: /*
   * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this
   * particular file as subject to the "Classpath" exception as provided
   * by Oracle in the LICENSE file that accompanied this code.
   *
   * This code is distributed in the hope that it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   * version 2 for more details (a copy is included in the LICENSE file that
   * accompanied this code).
   *
   * You should have received a copy of the GNU General Public License version
   * 2 along with this work; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  
  /*
   * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
   * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
   *
   * The original version of this source code and documentation
   * is copyrighted and owned by Taligent, Inc., a wholly-owned
   * subsidiary of IBM. These materials are provided under terms
   * of a License Agreement between Taligent and Sun. This technology
   * is protected by multiple US and International patents.
   *
   * This notice and attribution to Taligent may not be removed.
   * Taligent is a registered trademark of Taligent, Inc.
   *
   */
  
  package java.util;
  
  import sun.util.ResourceBundleEnumeration;
  
  /**
   * <code>ListResourceBundle</code> is an abstract subclass of
   * <code>ResourceBundle</code> that manages resources for a locale
   * in a convenient and easy to use list. See <code>ResourceBundle</code> for
   * more information about resource bundles in general.
   *
   * <P>
   * Subclasses must override <code>getContents</code> and provide an array,
   * where each item in the array is a pair of objects.
   * The first element of each pair is the key, which must be a
   * <code>String</code>, and the second element is the value associated with
   * that key.
   *
   * <p>
   * The following <a name="sample">example</a> shows two members of a resource
   * bundle family with the base name "MyResources".
   * "MyResources" is the default member of the bundle family, and
   * "MyResources_fr" is the French member.
   * These members are based on <code>ListResourceBundle</code>
   * (a related <a href="PropertyResourceBundle.html#sample">example</a> shows
   * how you can add a bundle to this family that's based on a properties file).
   * The keys in this example are of the form "s1" etc. The actual
   * keys are entirely up to your choice, so long as they are the same as
   * the keys you use in your program to retrieve the objects from the bundle.
   * Keys are case-sensitive.
   * <blockquote>
   * <pre>
   *
   * public class MyResources extends ListResourceBundle {
   *     protected Object[][] getContents() {
   *         return new Object[][] {
   *         // LOCALIZE THIS
   *             {"s1", "The disk \"{1}\" contains {0}."},  // MessageFormat pattern
   *             {"s2", "1"},                               // location of {0} in pattern
   *             {"s3", "My Disk"},                         // sample disk name
   *             {"s4", "no files"},                        // first ChoiceFormat choice
   *             {"s5", "one file"},                        // second ChoiceFormat choice
   *             {"s6", "{0,number} files"},                // third ChoiceFormat choice
   *             {"s7", "3 Mar 96"},                        // sample date
   *             {"s8", new Dimension(1,5)}                 // real object, not just string
   *         // END OF MATERIAL TO LOCALIZE
   *         };
   *     }
   * }
   *
   * public class MyResources_fr extends ListResourceBundle {
   *     protected Object[][] getContents() {
   *         return new Object[][] {
   *         // LOCALIZE THIS
   *             {"s1", "Le disque \"{1}\" {0}."},          // MessageFormat pattern
   *             {"s2", "1"},                               // location of {0} in pattern
   *             {"s3", "Mon disque"},                      // sample disk name
   *             {"s4", "ne contient pas de fichiers"},     // first ChoiceFormat choice
   *             {"s5", "contient un fichier"},             // second ChoiceFormat choice
   *             {"s6", "contient {0,number} fichiers"},    // third ChoiceFormat choice
   *             {"s7", "3 mars 1996"},                     // sample date
   *             {"s8", new Dimension(1,3)}                 // real object, not just string
   *         // END OF MATERIAL TO LOCALIZE
   *         };
   *     }
   * }
   * </pre>
   * </blockquote>
   *
   * <p>
   * The implementation of a {@code ListResourceBundle} subclass must be thread-safe
   * if it's simultaneously used by multiple threads. The default implementations
   * of the methods in this class are thread-safe.
   *
   * @see ResourceBundle
   * @see PropertyResourceBundle
   * @since JDK1.1
   */
  public abstract class ListResourceBundle extends ResourceBundle {
      /**
       * Sole constructor.  (For invocation by subclass constructors, typically
       * implicit.)
       */
      public ListResourceBundle() {
      }
  
      // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
      public final Object handleGetObject(String key) {
          // lazily load the lookup hashtable.
          if (lookup == null) {
              loadLookup();
          }
          if (key == null) {
              throw new NullPointerException();
          }
          return lookup.get(key); // this class ignores locales
      }
  
      /**
       * Returns an <code>Enumeration</code> of the keys contained in
       * this <code>ResourceBundle</code> and its parent bundles.
       *
       * @return an <code>Enumeration</code> of the keys contained in
       *         this <code>ResourceBundle</code> and its parent bundles.
       * @see #keySet()
       */
      public Enumeration<String> getKeys() {
          // lazily load the lookup hashtable.
          if (lookup == null) {
              loadLookup();
          }
  
          ResourceBundle parent = this.parent;
          return new ResourceBundleEnumeration(lookup.keySet(),
                  (parent != null) ? parent.getKeys() : null);
      }
  
      /**
       * Returns a <code>Set</code> of the keys contained
       * <em>only</em> in this <code>ResourceBundle</code>.
       *
       * @return a <code>Set</code> of the keys contained only in this
       *         <code>ResourceBundle</code>
       * @since 1.6
       * @see #keySet()
       */
      protected Set<String> handleKeySet() {
          if (lookup == null) {
              loadLookup();
          }
          return lookup.keySet();
      }
  
      /**
       * Returns an array in which each item is a pair of objects in an
       * <code>Object</code> array. The first element of each pair is
       * the key, which must be a <code>String</code>, and the second
       * element is the value associated with that key.  See the class
       * description for details.
       *
       * @return an array of an <code>Object</code> array representing a
       * key-value pair.
       */
      abstract protected Object[][] getContents();
  
      // ==================privates====================
  
      /**
       * We lazily load the lookup hashtable.  This function does the
       * loading.
       */
      private synchronized void loadLookup() {
          if (lookup != null)
              return;
  
          Object[][] contents = getContents();
          HashMap<String,Object> temp = new HashMap<>(contents.length);
          for (int i = 0; i < contents.length; ++i) {
              // key must be non-null String, value must be non-null
              String key = (String) contents[i][0];
              Object value = contents[i][1];
              if (key == null || value == null) {
                  throw new NullPointerException();
              }
              temp.put(key, value);
          }
          lookup = temp;
      }
  
      // Android-changed: Fix unsafe publication http://b/31467561
      // Fixed in OpenJDK 9: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/29ecac30ecae
      // was: private Map<String,Object> lookup = null;
      private volatile Map<String,Object> lookup = null;
  }
  