ResourceBundle.java revision f5597e626ecf7949d249dea08c1a2964d890ec11
1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.util;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.AccessController;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.PrivilegedAction;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project// BEGIN android-changed
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project// import org.apache.harmony.kernel.vm.VM;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport com.ibm.icu4jni.util.Resources;
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport dalvik.system.VMStack;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project// END android-changed
30f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonimport org.apache.harmony.luni.util.Msg;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code ResourceBundle} is an abstract class which is the superclass of classes which
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * provide {@code Locale}-specific resources. A bundle contains a number of named
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * resources, where the names are {@code Strings}. A bundle may have a parent bundle,
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * and when a resource is not found in a bundle, the parent bundle is searched for
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the resource. If the fallback mechanism reaches the base bundle and still
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * can't find the resource it throws a {@code MissingResourceException}.
39f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson *
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <ul>
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>All bundles for the same group of resources share a common base bundle.
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * This base bundle acts as the root and is the last fallback in case none of
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * its children was able to respond to a request.</li>
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>The first level contains changes between different languages. Only the
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * differences between a language and the language of the base bundle need to be
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * handled by a language-specific {@code ResourceBundle}.</li>
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>The second level contains changes between different countries that use
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the same language. Only the differences between a country and the country of
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the language bundle need to be handled by a country-specific {@code ResourceBundle}.
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * </li>
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>The third level contains changes that don't have a geographic reason
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (e.g. changes that where made at some point in time like {@code PREEURO} where the
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * currency of come countries changed. The country bundle would return the
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * current currency (Euro) and the {@code PREEURO} variant bundle would return the old
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * currency (e.g. DM for Germany).</li>
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * </ul>
57f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson *
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <strong>Examples</strong>
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <ul>
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName (base bundle)
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName_de (german language bundle)
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName_fr (french language bundle)
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName_de_DE (bundle with Germany specific resources in german)
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName_de_CH (bundle with Switzerland specific resources in german)
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName_fr_CH (bundle with Switzerland specific resources in french)
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName_de_DE_PREEURO (bundle with Germany specific resources in german of
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the time before the Euro)
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName_fr_FR_PREEURO (bundle with France specific resources in french of
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the time before the Euro)
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * </ul>
71f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson *
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * It's also possible to create variants for languages or countries. This can be
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * done by just skipping the country or language abbreviation:
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * BaseName_us__POSIX or BaseName__DE_PREEURO. But it's not allowed to
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * circumvent both language and country: BaseName___VARIANT is illegal.
76f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson *
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see Properties
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see PropertyResourceBundle
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see ListResourceBundle
80f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * @since 1.1
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic abstract class ResourceBundle {
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The parent of this {@code ResourceBundle} that is used if this bundle doesn't
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * include the requested resource.
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected ResourceBundle parent;
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Locale locale;
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    static class MissingBundle extends ResourceBundle {
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public Enumeration<String> getKeys() {
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public Object handleGetObject(String name) {
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final ResourceBundle MISSING = new MissingBundle();
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final ResourceBundle MISSINGBASE = new MissingBundle();
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final WeakHashMap<Object, Hashtable<String, ResourceBundle>> cache = new WeakHashMap<Object, Hashtable<String, ResourceBundle>>();
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // BEGIN android-added
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static Locale defaultLocale = Locale.getDefault();
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // END android-added
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new instance of this class.
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public ResourceBundle() {
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /* empty */
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Finds the named resource bundle for the default {@code Locale} and the caller's
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code ClassLoader}.
124f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param bundleName
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the {@code ResourceBundle}.
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the requested {@code ResourceBundle}.
128f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws MissingResourceException
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                if the {@code ResourceBundle} cannot be found.
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static final ResourceBundle getBundle(String bundleName)
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws MissingResourceException {
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // BEGIN android-changed
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return getBundleImpl(bundleName, Locale.getDefault(), VMStack
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                .getCallingClassLoader());
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // END android-changed
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Finds the named {@code ResourceBundle} for the specified {@code Locale} and the caller
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code ClassLoader}.
142f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param bundleName
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the {@code ResourceBundle}.
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param locale
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the {@code Locale}.
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the requested resource bundle.
148f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws MissingResourceException
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                if the resource bundle cannot be found.
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static final ResourceBundle getBundle(String bundleName,
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Locale locale) {
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // BEGIN android-changed
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return getBundleImpl(bundleName, locale,
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                VMStack.getCallingClassLoader());
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // END android-changed
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Finds the named resource bundle for the specified {@code Locale} and {@code ClassLoader}.
161f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The passed base name and {@code Locale} are used to create resource bundle names.
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The first name is created by concatenating the base name with the result
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * of {@link Locale#toString()}. From this name all parent bundle names are
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * derived. Then the same thing is done for the default {@code Locale}. This results
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * in a list of possible bundle names.
167f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <strong>Example</strong> For the basename "BaseName", the {@code Locale} of the
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * German part of Switzerland (de_CH) and the default {@code Locale} en_US the list
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * would look something like this:
171f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <ol>
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>BaseName_de_CH</li>
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>BaseName_de</li>
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>Basename_en_US</li>
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>Basename_en</li>
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>BaseName</li>
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * </ol>
179f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This list also shows the order in which the bundles will be searched for a requested
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * resource in the German part of Switzerland (de_CH).
182f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
183f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * As a first step, this method tries to instantiate
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * a {@code ResourceBundle} with the names provided.
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * If such a class can be instantiated and initialized, it is returned and
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * all the parent bundles are instantiated too. If no such class can be
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * found this method tries to load a {@code .properties} file with the names by
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * replacing dots in the base name with a slash and by appending
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * "{@code .properties}" at the end of the string. If such a resource can be found
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * by calling {@link ClassLoader#getResource(String)} it is used to
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * initialize a {@link PropertyResourceBundle}. If this succeeds, it will
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * also load the parents of this {@code ResourceBundle}.
193f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * For compatibility with older code, the bundle name isn't required to be
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * a fully qualified class name. It's also possible to directly pass
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the path to a properties file (without a file extension).
197f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param bundleName
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the {@code ResourceBundle}.
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param locale
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the {@code Locale}.
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param loader
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the {@code ClassLoader} to use.
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the requested {@code ResourceBundle}.
205f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws MissingResourceException
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                if the {@code ResourceBundle} cannot be found.
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static ResourceBundle getBundle(String bundleName, Locale locale,
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ClassLoader loader) throws MissingResourceException {
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (loader == null) {
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NullPointerException();
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // BEGIN android-changed
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return getBundleImpl(bundleName, locale, loader);
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // END android-changed
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static ResourceBundle getBundleImpl(String bundleName,
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Locale locale, ClassLoader loader) throws MissingResourceException {
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (bundleName != null) {
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ResourceBundle bundle;
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // BEGIN android-added
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!defaultLocale.equals(Locale.getDefault())) {
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                cache.clear();
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                defaultLocale = Locale.getDefault();
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // END android-added
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!locale.equals(Locale.getDefault())) {
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                String localeName = locale.toString();
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (localeName.length() > 0) {
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    localeName = "_" + localeName; //$NON-NLS-1$
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if ((bundle = handleGetBundle(bundleName, localeName, false,
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        loader)) != null) {
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return bundle;
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String localeName = Locale.getDefault().toString();
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (localeName.length() > 0) {
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                localeName = "_" + localeName; //$NON-NLS-1$
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if ((bundle = handleGetBundle(bundleName, localeName, true, loader)) != null) {
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return bundle;
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
245f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            throw new MissingResourceException(Msg.getString("KA029", bundleName, locale), bundleName + '_' + locale, //$NON-NLS-1$
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    ""); //$NON-NLS-1$
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        throw new NullPointerException();
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the names of the resources contained in this {@code ResourceBundle}.
253f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return an {@code Enumeration} of the resource names.
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public abstract Enumeration<String> getKeys();
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the {@code Locale} of this {@code ResourceBundle}. In case a bundle was not
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * found for the requested {@code Locale}, this will return the actual {@code Locale} of
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * this resource bundle that was found after doing a fallback.
262f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the {@code Locale} of this {@code ResourceBundle}.
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Locale getLocale() {
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return locale;
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the named resource from this {@code ResourceBundle}. If the resource
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * cannot be found in this bundle, it falls back to the parent bundle (if
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * it's not null) by calling the {@link #handleGetObject} method. If the resource still
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * can't be found it throws a {@code MissingResourceException}.
274f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param key
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the resource.
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the resource object.
278f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws MissingResourceException
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                if the resource is not found.
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final Object getObject(String key) {
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ResourceBundle last, theParent = this;
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        do {
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Object result = theParent.handleGetObject(key);
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (result != null) {
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return result;
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            last = theParent;
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            theParent = theParent.parent;
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } while (theParent != null);
291f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        throw new MissingResourceException(Msg.getString("KA029", last.getClass().getName(), key), last.getClass().getName(), key); //$NON-NLS-1$
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the named string resource from this {@code ResourceBundle}.
296f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param key
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the resource.
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the resource string.
300f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws MissingResourceException
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                if the resource is not found.
302f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws ClassCastException
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                if the resource found is not a string.
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @see #getObject(String)
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final String getString(String key) {
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return (String) getObject(key);
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the named resource from this {@code ResourceBundle}.
312f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param key
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the resource.
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the resource string array.
316f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws MissingResourceException
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                if the resource is not found.
318f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws ClassCastException
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                if the resource found is not an array of strings.
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @see #getObject(String)
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final String[] getStringArray(String key) {
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return (String[]) getObject(key);
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static ResourceBundle handleGetBundle(String base, String locale,
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            boolean loadBase, final ClassLoader loader) {
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ResourceBundle bundle = null;
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String bundleName = base + locale;
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Object cacheKey = loader != null ? (Object) loader : (Object) "null"; //$NON-NLS-1$
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Hashtable<String, ResourceBundle> loaderCache;
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (cache) {
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            loaderCache = cache.get(cacheKey);
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (loaderCache == null) {
335f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                loaderCache = new Hashtable<String, ResourceBundle>();
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                cache.put(cacheKey, loaderCache);
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ResourceBundle result = loaderCache.get(bundleName);
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (result != null) {
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (result == MISSINGBASE) {
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return null;
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (result == MISSING) {
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (!loadBase) {
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return null;
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                String extension = strip(locale);
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (extension == null) {
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return null;
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return handleGetBundle(base, extension, loadBase, loader);
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return result;
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // BEGIN android-changed
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            /*
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * Intercept loading of ResourceBundles that contain Harmony
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * I18N data. Deliver our special, ICU-based bundles in this case.
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * All other ResourceBundles use the ordinary mechanism, so user
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * code behaves as it should.
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if(bundleName.startsWith("org.apache.harmony.luni.internal.locale.")) {
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                String icuBundleName = bundleName.substring(40);
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                String icuLocale = (locale.length() > 0 ? locale.substring(1) : locale);
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // we know that Resources will deliver an assignable class
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                bundle = Resources.getInstance(icuBundleName, icuLocale);
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Class<?> bundleClass = Class.forName(bundleName, true, loader);
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (ResourceBundle.class.isAssignableFrom(bundleClass)) {
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    bundle = (ResourceBundle) bundleClass.newInstance();
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // END android-changed
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (LinkageError e) {
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (Exception e) {
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (bundle != null) {
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            bundle.setLocale(locale);
383f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        } else {
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            final String fileName = bundleName.replace('.', '/');
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            InputStream stream = AccessController
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .doPrivileged(new PrivilegedAction<InputStream>() {
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        public InputStream run() {
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            return loader == null ? ClassLoader
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                    .getSystemResourceAsStream(fileName
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                            + ".properties") : loader //$NON-NLS-1$
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                    .getResourceAsStream(fileName
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                            + ".properties"); //$NON-NLS-1$
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    });
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (stream != null) {
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                try {
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    try {
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        bundle = new PropertyResourceBundle(stream);
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    } finally {
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        stream.close();
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    bundle.setLocale(locale);
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } catch (IOException e) {
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String extension = strip(locale);
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (bundle != null) {
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (extension != null) {
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                ResourceBundle parent = handleGetBundle(base, extension, true,
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        loader);
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (parent != null) {
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    bundle.setParent(parent);
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            loaderCache.put(bundleName, bundle);
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return bundle;
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (extension != null && (loadBase || extension.length() > 0)) {
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            bundle = handleGetBundle(base, extension, loadBase, loader);
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (bundle != null) {
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                loaderCache.put(bundleName, bundle);
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return bundle;
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        loaderCache.put(bundleName, loadBase ? MISSINGBASE : MISSING);
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the named resource from this {@code ResourceBundle}, or null if the
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * resource is not found.
435f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param key
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the resource.
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the resource object.
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected abstract Object handleGetObject(String key);
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets the parent resource bundle of this {@code ResourceBundle}. The parent is
444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * searched for resources which are not found in this {@code ResourceBundle}.
445f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param bundle
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the parent {@code ResourceBundle}.
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void setParent(ResourceBundle bundle) {
450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        parent = bundle;
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static String strip(String name) {
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int index = name.lastIndexOf('_');
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (index != -1) {
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return name.substring(0, index);
457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void setLocale(String name) {
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String language = "", country = "", variant = ""; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (name.length() > 1) {
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int nextIndex = name.indexOf('_', 1);
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (nextIndex == -1) {
466adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                nextIndex = name.length();
467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            language = name.substring(1, nextIndex);
469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (nextIndex + 1 < name.length()) {
470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int index = nextIndex;
471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                nextIndex = name.indexOf('_', nextIndex + 1);
472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (nextIndex == -1) {
473adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    nextIndex = name.length();
474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                country = name.substring(index + 1, nextIndex);
476adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (nextIndex + 1 < name.length()) {
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    variant = name.substring(nextIndex + 1, name.length());
478adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
479adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
480adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
481adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        locale = new Locale(language, country, variant);
482adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
484