ListResourceBundle.java revision 12745:f068a4ffddd2
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
41package java.util;
42
43import 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 */
118public 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}
211