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 20565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughesimport dalvik.system.VMStack; 21565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughesimport java.io.File; 22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException; 23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream; 24565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughesimport java.io.InputStreamReader; 25565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughesimport java.net.URL; 26565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughesimport java.net.URLConnection; 272a6f23ff8690ac2f025588a360547ce96cde0943Elliott Hughesimport java.nio.charset.StandardCharsets; 282c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilsonimport libcore.io.IoUtils; 29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code ResourceBundle} is an abstract class which is the superclass of classes which 32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * provide {@code Locale}-specific resources. A bundle contains a number of named 33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * resources, where the names are {@code Strings}. A bundle may have a parent bundle, 34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * and when a resource is not found in a bundle, the parent bundle is searched for 35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the resource. If the fallback mechanism reaches the base bundle and still 36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * can't find the resource it throws a {@code MissingResourceException}. 37f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <ul> 39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>All bundles for the same group of resources share a common base bundle. 40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * This base bundle acts as the root and is the last fallback in case none of 41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * its children was able to respond to a request.</li> 42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>The first level contains changes between different languages. Only the 43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * differences between a language and the language of the base bundle need to be 44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * handled by a language-specific {@code ResourceBundle}.</li> 45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>The second level contains changes between different countries that use 46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the same language. Only the differences between a country and the country of 47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the language bundle need to be handled by a country-specific {@code ResourceBundle}. 48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * </li> 49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>The third level contains changes that don't have a geographic reason 50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (e.g. changes that where made at some point in time like {@code PREEURO} where the 51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * currency of come countries changed. The country bundle would return the 52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * current currency (Euro) and the {@code PREEURO} variant bundle would return the old 53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * currency (e.g. DM for Germany).</li> 54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * </ul> 55f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <strong>Examples</strong> 57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <ul> 58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName (base bundle) 59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName_de (german language bundle) 60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName_fr (french language bundle) 61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName_de_DE (bundle with Germany specific resources in german) 62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName_de_CH (bundle with Switzerland specific resources in german) 63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName_fr_CH (bundle with Switzerland specific resources in french) 64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName_de_DE_PREEURO (bundle with Germany specific resources in german of 65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the time before the Euro) 66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName_fr_FR_PREEURO (bundle with France specific resources in french of 67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the time before the Euro) 68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * </ul> 69f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * It's also possible to create variants for languages or countries. This can be 71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * done by just skipping the country or language abbreviation: 72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * BaseName_us__POSIX or BaseName__DE_PREEURO. But it's not allowed to 73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * circumvent both language and country: BaseName___VARIANT is illegal. 74f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see Properties 76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see PropertyResourceBundle 77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see ListResourceBundle 78f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * @since 1.1 79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic abstract class ResourceBundle { 81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 82f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes private static final String UNDER_SCORE = "_"; 83565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 84f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes private static final String EMPTY_STRING = ""; 85565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The parent of this {@code ResourceBundle} that is used if this bundle doesn't 88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * include the requested resource. 89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected ResourceBundle parent; 91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private Locale locale; 93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 94565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes private long lastLoadTime = 0; 95565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project static class MissingBundle extends ResourceBundle { 97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Enumeration<String> getKeys() { 99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return null; 100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Object handleGetObject(String name) { 104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return null; 105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private static final ResourceBundle MISSING = new MissingBundle(); 109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private static final ResourceBundle MISSINGBASE = new MissingBundle(); 111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 1122c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson private static final WeakHashMap<Object, Hashtable<String, ResourceBundle>> cache 1132c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson = new WeakHashMap<Object, Hashtable<String, ResourceBundle>>(); 1142c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson 1152c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson private static Locale cacheLocale = Locale.getDefault(); 116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Constructs a new instance of this class. 119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public ResourceBundle() { 121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /* empty */ 122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Finds the named resource bundle for the default {@code Locale} and the caller's 126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code ClassLoader}. 127f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param bundleName 129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the {@code ResourceBundle}. 130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the requested {@code ResourceBundle}. 131f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * @throws MissingResourceException 132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if the {@code ResourceBundle} cannot be found. 133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 1342c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson public static ResourceBundle getBundle(String bundleName) throws MissingResourceException { 1359ef23e5d7f45cf120abb0e140d657bf7c79b3721Jesse Wilson ClassLoader classLoader = VMStack.getCallingClassLoader(); 1369ef23e5d7f45cf120abb0e140d657bf7c79b3721Jesse Wilson if (classLoader == null) { 1379ef23e5d7f45cf120abb0e140d657bf7c79b3721Jesse Wilson classLoader = getLoader(); 1389ef23e5d7f45cf120abb0e140d657bf7c79b3721Jesse Wilson } 1399ef23e5d7f45cf120abb0e140d657bf7c79b3721Jesse Wilson return getBundle(bundleName, Locale.getDefault(), classLoader); 140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Finds the named {@code ResourceBundle} for the specified {@code Locale} and the caller 144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code ClassLoader}. 145f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param bundleName 147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the {@code ResourceBundle}. 148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param locale 149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the {@code Locale}. 150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the requested resource bundle. 151f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * @throws MissingResourceException 152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if the resource bundle cannot be found. 153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 1542c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson public static ResourceBundle getBundle(String bundleName, Locale locale) { 1559ef23e5d7f45cf120abb0e140d657bf7c79b3721Jesse Wilson ClassLoader classLoader = VMStack.getCallingClassLoader(); 1569ef23e5d7f45cf120abb0e140d657bf7c79b3721Jesse Wilson if (classLoader == null) { 1579ef23e5d7f45cf120abb0e140d657bf7c79b3721Jesse Wilson classLoader = getLoader(); 1589ef23e5d7f45cf120abb0e140d657bf7c79b3721Jesse Wilson } 1599ef23e5d7f45cf120abb0e140d657bf7c79b3721Jesse Wilson return getBundle(bundleName, locale, classLoader); 160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Finds the named resource bundle for the specified {@code Locale} and {@code ClassLoader}. 164f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The passed base name and {@code Locale} are used to create resource bundle names. 166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The first name is created by concatenating the base name with the result 167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * of {@link Locale#toString()}. From this name all parent bundle names are 168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * derived. Then the same thing is done for the default {@code Locale}. This results 169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * in a list of possible bundle names. 170f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <strong>Example</strong> For the basename "BaseName", the {@code Locale} of the 172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * German part of Switzerland (de_CH) and the default {@code Locale} en_US the list 173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * would look something like this: 174f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <ol> 176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName_de_CH</li> 177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName_de</li> 178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>Basename_en_US</li> 179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>Basename_en</li> 180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>BaseName</li> 181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * </ol> 182f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * This list also shows the order in which the bundles will be searched for a requested 184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * resource in the German part of Switzerland (de_CH). 185f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 186f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * As a first step, this method tries to instantiate 187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * a {@code ResourceBundle} with the names provided. 188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * If such a class can be instantiated and initialized, it is returned and 189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * all the parent bundles are instantiated too. If no such class can be 190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * found this method tries to load a {@code .properties} file with the names by 191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * replacing dots in the base name with a slash and by appending 192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * "{@code .properties}" at the end of the string. If such a resource can be found 193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * by calling {@link ClassLoader#getResource(String)} it is used to 194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * initialize a {@link PropertyResourceBundle}. If this succeeds, it will 195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * also load the parents of this {@code ResourceBundle}. 196f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * For compatibility with older code, the bundle name isn't required to be 198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * a fully qualified class name. It's also possible to directly pass 199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the path to a properties file (without a file extension). 200f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param bundleName 202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the {@code ResourceBundle}. 203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param locale 204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the {@code Locale}. 205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param loader 206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the {@code ClassLoader} to use. 207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the requested {@code ResourceBundle}. 208f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * @throws MissingResourceException 209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if the {@code ResourceBundle} cannot be found. 210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public static ResourceBundle getBundle(String bundleName, Locale locale, 212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project ClassLoader loader) throws MissingResourceException { 21386acc043d3334651ee26c65467d78d6cefedd397Kenny Root if (loader == null) { 21486acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("loader == null"); 21586acc043d3334651ee26c65467d78d6cefedd397Kenny Root } else if (bundleName == null) { 21686acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("bundleName == null"); 217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 2182c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson Locale defaultLocale = Locale.getDefault(); 2192c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson if (!cacheLocale.equals(defaultLocale)) { 2202c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson cache.clear(); 2212c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson cacheLocale = defaultLocale; 2222c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson } 2232c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson ResourceBundle bundle = null; 2242c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson if (!locale.equals(defaultLocale)) { 2252c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson bundle = handleGetBundle(false, bundleName, locale, loader); 2262c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson } 2272c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson if (bundle == null) { 2282c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson bundle = handleGetBundle(true, bundleName, defaultLocale, loader); 2292c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson if (bundle == null) { 2302c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson throw missingResourceException(bundleName + '_' + locale, ""); 231565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 232565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 2332c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson return bundle; 234565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 235565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 236565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes private static MissingResourceException missingResourceException(String className, String key) { 237565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes String detail = "Can't find resource for bundle '" + className + "', key '" + key + "'"; 238565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes throw new MissingResourceException(detail, className, key); 239565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 240565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 241565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 242565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * Finds the named resource bundle for the specified base name and control. 243f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 244565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param baseName 245565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the base name of a resource bundle 246565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param control 247565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the control that control the access sequence 248565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @return the named resource bundle 249f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 250565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @since 1.6 251565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 2522c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson public static ResourceBundle getBundle(String baseName, ResourceBundle.Control control) { 253565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return getBundle(baseName, Locale.getDefault(), getLoader(), control); 254565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 255565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 256565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 257565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * Finds the named resource bundle for the specified base name and control. 258f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 259565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param baseName 260565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the base name of a resource bundle 261565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param targetLocale 262565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the target locale of the resource bundle 263565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param control 264565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the control that control the access sequence 265565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @return the named resource bundle 266f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 267565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @since 1.6 268565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 2692c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson public static ResourceBundle getBundle(String baseName, 270565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes Locale targetLocale, ResourceBundle.Control control) { 271565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return getBundle(baseName, targetLocale, getLoader(), control); 272565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 273565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 274565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes private static ClassLoader getLoader() { 275ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes ClassLoader cl = ResourceBundle.class.getClassLoader(); 276ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes if (cl == null) { 277ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes cl = ClassLoader.getSystemClassLoader(); 278ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes } 279ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes return cl; 280565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 281565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 282565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 283565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * Finds the named resource bundle for the specified base name and control. 284f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 285565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param baseName 286565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the base name of a resource bundle 287565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param targetLocale 288565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the target locale of the resource bundle 289565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param loader 290565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the class loader to load resource 291565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param control 292565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the control that control the access sequence 293565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @return the named resource bundle 294f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 295565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @since 1.6 296565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 297565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public static ResourceBundle getBundle(String baseName, 298565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes Locale targetLocale, ClassLoader loader, 299565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ResourceBundle.Control control) { 300565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes boolean expired = false; 301565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes String bundleName = control.toBundleName(baseName, targetLocale); 3022c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson Object cacheKey = loader != null ? loader : "null"; 3032c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson Hashtable<String, ResourceBundle> loaderCache = getLoaderCache(cacheKey); 304565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ResourceBundle result = loaderCache.get(bundleName); 305565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (result != null) { 306565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes long time = control.getTimeToLive(baseName, targetLocale); 307565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (time == 0 || time == Control.TTL_NO_EXPIRATION_CONTROL 308565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes || time + result.lastLoadTime < System.currentTimeMillis()) { 309565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (MISSING == result) { 310565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes throw new MissingResourceException(null, bundleName + '_' 311565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes + targetLocale, EMPTY_STRING); 312565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 313565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return result; 314565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 315565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes expired = true; 316565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 317565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes // try to load 318565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ResourceBundle ret = processGetBundle(baseName, targetLocale, loader, 319565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes control, expired, result); 320565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 321b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (ret != null) { 322565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes loaderCache.put(bundleName, ret); 323565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret.lastLoadTime = System.currentTimeMillis(); 324565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return ret; 325565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 326565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes loaderCache.put(bundleName, MISSING); 3272c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson throw new MissingResourceException(null, bundleName + '_' + targetLocale, EMPTY_STRING); 328565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 329565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 330565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes private static ResourceBundle processGetBundle(String baseName, 331565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes Locale targetLocale, ClassLoader loader, 332565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ResourceBundle.Control control, boolean expired, 333565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ResourceBundle result) { 334b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes List<Locale> locales = control.getCandidateLocales(baseName, targetLocale); 335b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (locales == null) { 336565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes throw new IllegalArgumentException(); 337565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 338565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes List<String> formats = control.getFormats(baseName); 339565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (Control.FORMAT_CLASS == formats 340565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes || Control.FORMAT_PROPERTIES == formats 341565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes || Control.FORMAT_DEFAULT == formats) { 342565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes throw new IllegalArgumentException(); 343565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 344565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ResourceBundle ret = null; 345565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ResourceBundle currentBundle = null; 346565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ResourceBundle bundle = null; 347565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes for (Locale locale : locales) { 348565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes for (String format : formats) { 349565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes try { 350565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (expired) { 351565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes bundle = control.newBundle(baseName, locale, format, 352565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes loader, control.needsReload(baseName, locale, 353565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes format, loader, result, System 354565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes .currentTimeMillis())); 355565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 356565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } else { 357565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes try { 358565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes bundle = control.newBundle(baseName, locale, 359565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes format, loader, false); 360565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } catch (IllegalArgumentException e) { 361565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes // do nothing 362565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 363565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 364565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } catch (IllegalAccessException e) { 365565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes // do nothing 366565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } catch (InstantiationException e) { 367565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes // do nothing 368565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } catch (IOException e) { 369565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes // do nothing 370565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 371b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (bundle != null) { 372b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (currentBundle != null) { 373565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes currentBundle.setParent(bundle); 374565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes currentBundle = bundle; 375565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } else { 376b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (ret == null) { 377565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret = bundle; 378565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes currentBundle = ret; 379565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 380565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 381565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 382b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (bundle != null) { 383565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes break; 384565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 385565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 386565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 387565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 388b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if ((ret == null) 389565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes || (Locale.ROOT.equals(ret.getLocale()) && (!(locales.size() == 1 && locales 390565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes .contains(Locale.ROOT))))) { 391b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes Locale nextLocale = control.getFallbackLocale(baseName, targetLocale); 392b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (nextLocale != null) { 393565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret = processGetBundle(baseName, nextLocale, loader, control, 394565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes expired, result); 395565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 396565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 397565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 398565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return ret; 399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the names of the resources contained in this {@code ResourceBundle}. 403f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return an {@code Enumeration} of the resource names. 405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public abstract Enumeration<String> getKeys(); 407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Gets the {@code Locale} of this {@code ResourceBundle}. In case a bundle was not 410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * found for the requested {@code Locale}, this will return the actual {@code Locale} of 411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * this resource bundle that was found after doing a fallback. 412f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the {@code Locale} of this {@code ResourceBundle}. 414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Locale getLocale() { 416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return locale; 417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the named resource from this {@code ResourceBundle}. If the resource 421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * cannot be found in this bundle, it falls back to the parent bundle (if 422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * it's not null) by calling the {@link #handleGetObject} method. If the resource still 423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * can't be found it throws a {@code MissingResourceException}. 424f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param key 426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the resource. 427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the resource object. 428f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * @throws MissingResourceException 429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if the resource is not found. 430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final Object getObject(String key) { 432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project ResourceBundle last, theParent = this; 433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project do { 434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Object result = theParent.handleGetObject(key); 435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (result != null) { 436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return result; 437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project last = theParent; 439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project theParent = theParent.parent; 440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } while (theParent != null); 441565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes throw missingResourceException(last.getClass().getName(), key); 442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the named string resource from this {@code ResourceBundle}. 446f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param key 448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the resource. 449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the resource string. 450f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * @throws MissingResourceException 451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if the resource is not found. 452f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * @throws ClassCastException 453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if the resource found is not a string. 454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see #getObject(String) 455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final String getString(String key) { 457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return (String) getObject(key); 458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the named resource from this {@code ResourceBundle}. 462f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param key 464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the resource. 465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the resource string array. 466f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * @throws MissingResourceException 467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if the resource is not found. 468f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * @throws ClassCastException 469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if the resource found is not an array of strings. 470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see #getObject(String) 471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final String[] getStringArray(String key) { 473adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return (String[]) getObject(key); 474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 4762c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson private static ResourceBundle handleGetBundle(boolean loadBase, String base, Locale locale, 4772c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson ClassLoader loader) { 4782c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson String localeName = locale.toString(); 4792c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson String bundleName = localeName.isEmpty() 4802c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson ? base 4812c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson : (base + "_" + localeName); 4822c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson Object cacheKey = loader != null ? loader : "null"; 4832c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson Hashtable<String, ResourceBundle> loaderCache = getLoaderCache(cacheKey); 4842c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson ResourceBundle cached = loaderCache.get(bundleName); 4852c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson if (cached != null) { 4862c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson if (cached == MISSINGBASE) { 487adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return null; 4882c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson } else if (cached == MISSING) { 489adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (!loadBase) { 490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return null; 491adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 4922c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson Locale newLocale = strip(locale); 4932c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson if (newLocale == null) { 494adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return null; 495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 4962c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson return handleGetBundle(loadBase, base, newLocale, loader); 497adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 4982c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson return cached; 499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 500adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 5012c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson ResourceBundle bundle = null; 502adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 503aba52f92911e0faa4ae1907becc5a66cdb3254deElliott Hughes Class<?> bundleClass = Class.forName(bundleName, true, loader); 504aba52f92911e0faa4ae1907becc5a66cdb3254deElliott Hughes if (ResourceBundle.class.isAssignableFrom(bundleClass)) { 505aba52f92911e0faa4ae1907becc5a66cdb3254deElliott Hughes bundle = (ResourceBundle) bundleClass.newInstance(); 506adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 5072c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson } catch (LinkageError ignored) { 5082c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson } catch (Exception ignored) { 509adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 510adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 511adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (bundle != null) { 512adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project bundle.setLocale(locale); 513f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 5142c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson String fileName = bundleName.replace('.', '/') + ".properties"; 5152c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson InputStream stream = loader != null 5162c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson ? loader.getResourceAsStream(fileName) 5172c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson : ClassLoader.getSystemResourceAsStream(fileName); 518adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (stream != null) { 519adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 5202a6f23ff8690ac2f025588a360547ce96cde0943Elliott Hughes bundle = new PropertyResourceBundle(new InputStreamReader(stream, StandardCharsets.UTF_8)); 521adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project bundle.setLocale(locale); 5222c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson } catch (IOException ignored) { 5232c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson } finally { 5242c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson IoUtils.closeQuietly(stream); 525adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 526adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 527adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 528adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 5292c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson Locale strippedLocale = strip(locale); 530adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (bundle != null) { 5312c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson if (strippedLocale != null) { 5322c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson ResourceBundle parent = handleGetBundle(loadBase, base, strippedLocale, loader); 533adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (parent != null) { 534adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project bundle.setParent(parent); 535adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 536adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 537adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project loaderCache.put(bundleName, bundle); 538adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return bundle; 539adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 540adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 5412c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson if (strippedLocale != null && (loadBase || !strippedLocale.toString().isEmpty())) { 5422c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson bundle = handleGetBundle(loadBase, base, strippedLocale, loader); 543adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (bundle != null) { 544adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project loaderCache.put(bundleName, bundle); 545adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return bundle; 546adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 547adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 548adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project loaderCache.put(bundleName, loadBase ? MISSINGBASE : MISSING); 549adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return null; 550adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 551adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 5522c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson private static Hashtable<String, ResourceBundle> getLoaderCache(Object cacheKey) { 5532c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson synchronized (cache) { 5542c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson Hashtable<String, ResourceBundle> loaderCache = cache.get(cacheKey); 5552c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson if (loaderCache == null) { 5562c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson loaderCache = new Hashtable<String, ResourceBundle>(); 5572c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson cache.put(cacheKey, loaderCache); 5582c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson } 5592c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson return loaderCache; 5602c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson } 5612c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson } 5622c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson 563adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 564adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the named resource from this {@code ResourceBundle}, or null if the 565adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * resource is not found. 566f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 567adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param key 568adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the resource. 569adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the resource object. 570adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 571adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected abstract Object handleGetObject(String key); 572adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 573adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 574adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Sets the parent resource bundle of this {@code ResourceBundle}. The parent is 575adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * searched for resources which are not found in this {@code ResourceBundle}. 576f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 577adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param bundle 578adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the parent {@code ResourceBundle}. 579adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 580adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected void setParent(ResourceBundle bundle) { 581adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project parent = bundle; 582adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 583adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 5842c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson /** 5852c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson * Returns a locale with the most-specific field removed, or null if this 5862c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson * locale had an empty language, country and variant. 5872c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson */ 5882c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson private static Locale strip(Locale locale) { 5892c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson String language = locale.getLanguage(); 5902c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson String country = locale.getCountry(); 5912c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson String variant = locale.getVariant(); 5922c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson if (!variant.isEmpty()) { 5932c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson variant = ""; 5942c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson } else if (!country.isEmpty()) { 5952c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson country = ""; 5962c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson } else if (!language.isEmpty()) { 5972c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson language = ""; 5982c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson } else { 5992c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson return null; 600adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 6012c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson return new Locale(language, country, variant); 602adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 603adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 604565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes private void setLocale(Locale locale) { 605565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes this.locale = locale; 606565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 607565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 6082c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson public static void clearCache() { 609565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes cache.remove(ClassLoader.getSystemClassLoader()); 610565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 611565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 6122c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson public static void clearCache(ClassLoader loader) { 613b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (loader == null) { 61486acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("loader == null"); 615565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 616565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes cache.remove(loader); 617565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 618565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 619565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public boolean containsKey(String key) { 620b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (key == null) { 62186acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("key == null"); 622565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 623565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return keySet().contains(key); 624565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 625565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 626565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public Set<String> keySet() { 627565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes Set<String> ret = new HashSet<String>(); 628565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes Enumeration<String> keys = getKeys(); 629565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes while (keys.hasMoreElements()) { 630565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret.add(keys.nextElement()); 631565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 632565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return ret; 633565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 634565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 635565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes protected Set<String> handleKeySet() { 636565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes Set<String> set = keySet(); 637565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes Set<String> ret = new HashSet<String>(); 638565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes for (String key : set) { 639b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (handleGetObject(key) != null) { 640565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret.add(key); 641565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 642565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 643565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return ret; 644565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 645565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 646565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes private static class NoFallbackControl extends Control { 647565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 648565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes static final Control NOFALLBACK_FORMAT_PROPERTIES_CONTROL = new NoFallbackControl( 649565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes JAVAPROPERTIES); 650565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 651565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes static final Control NOFALLBACK_FORMAT_CLASS_CONTROL = new NoFallbackControl( 652565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes JAVACLASS); 653565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 654565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes static final Control NOFALLBACK_FORMAT_DEFAULT_CONTROL = new NoFallbackControl( 655565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes listDefault); 656565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 657565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public NoFallbackControl(String format) { 658565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes listClass = new ArrayList<String>(); 659565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes listClass.add(format); 660565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes super.format = Collections.unmodifiableList(listClass); 661565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 662565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 663565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public NoFallbackControl(List<String> list) { 664565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes super.format = list; 665565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 666565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 667565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes @Override 668565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public Locale getFallbackLocale(String baseName, Locale locale) { 66986acc043d3334651ee26c65467d78d6cefedd397Kenny Root if (baseName == null) { 67086acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("baseName == null"); 67186acc043d3334651ee26c65467d78d6cefedd397Kenny Root } else if (locale == null) { 67286acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("locale == null"); 673565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 674565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return null; 675565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 676565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 677565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 678565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes private static class SimpleControl extends Control { 679565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public SimpleControl(String format) { 680565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes listClass = new ArrayList<String>(); 681565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes listClass.add(format); 682565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes super.format = Collections.unmodifiableList(listClass); 683565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 684565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 685565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 686565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 687565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * ResourceBundle.Control is a static utility class defines ResourceBundle 688565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * load access methods, its default access order is as the same as before. 689565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * However users can implement their own control. 690f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 691565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @since 1.6 692565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 693565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public static class Control { 694565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes static List<String> listDefault = new ArrayList<String>(); 695565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 696565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes static List<String> listClass = new ArrayList<String>(); 697565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 698565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes static List<String> listProperties = new ArrayList<String>(); 699565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 700565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes static String JAVACLASS = "java.class"; 701565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 702565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes static String JAVAPROPERTIES = "java.properties"; 703565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 704565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes static { 705565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes listDefault.add(JAVACLASS); 706565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes listDefault.add(JAVAPROPERTIES); 707565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes listClass.add(JAVACLASS); 708565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes listProperties.add(JAVAPROPERTIES); 709565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 710565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 711565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 712565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * a list defines default format 713565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 714565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public static final List<String> FORMAT_DEFAULT = Collections 715565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes .unmodifiableList(listDefault); 716565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 717565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 718565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * a list defines java class format 719565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 720565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public static final List<String> FORMAT_CLASS = Collections 721565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes .unmodifiableList(listClass); 722565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 723565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 724565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * a list defines property format 725565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 726565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public static final List<String> FORMAT_PROPERTIES = Collections 727565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes .unmodifiableList(listProperties); 728565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 729565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 730565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * a constant that indicates cache will not be used. 731565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 732565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public static final long TTL_DONT_CACHE = -1L; 733565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 734565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 735565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * a constant that indicates cache will not be expired. 736565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 737565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public static final long TTL_NO_EXPIRATION_CONTROL = -2L; 738565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 739565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes private static final Control FORMAT_PROPERTIES_CONTROL = new SimpleControl( 740565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes JAVAPROPERTIES); 741565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 742565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes private static final Control FORMAT_CLASS_CONTROL = new SimpleControl( 743565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes JAVACLASS); 744565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 745565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes private static final Control FORMAT_DEFAULT_CONTROL = new Control(); 746565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 747565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes List<String> format; 748565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 749565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 750565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * default constructor 751f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 752565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 753565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes protected Control() { 754565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes listClass = new ArrayList<String>(); 755565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes listClass.add(JAVACLASS); 756565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes listClass.add(JAVAPROPERTIES); 757565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes format = Collections.unmodifiableList(listClass); 758565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 759565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 760565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 761eeefcae2980c8db05ec08303b5b112afce232d26Elliott Hughes * Returns a control according to {@code formats}. 762565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 7632c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson public static Control getControl(List<String> formats) { 764565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes switch (formats.size()) { 765565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes case 1: 766565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (formats.contains(JAVACLASS)) { 767565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return FORMAT_CLASS_CONTROL; 768565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 769565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (formats.contains(JAVAPROPERTIES)) { 770565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return FORMAT_PROPERTIES_CONTROL; 771565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 772565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes break; 773565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes case 2: 774565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (formats.equals(FORMAT_DEFAULT)) { 775565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return FORMAT_DEFAULT_CONTROL; 776565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 777565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes break; 778565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 779565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes throw new IllegalArgumentException(); 780565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 781565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 782565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 783eeefcae2980c8db05ec08303b5b112afce232d26Elliott Hughes * Returns a control according to {@code formats} whose fallback 784eeefcae2980c8db05ec08303b5b112afce232d26Elliott Hughes * locale is null. 785565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 7862c98427a50610d4991e9b0ada6cbc7aceb194580Jesse Wilson public static Control getNoFallbackControl(List<String> formats) { 787565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes switch (formats.size()) { 788565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes case 1: 789565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (formats.contains(JAVACLASS)) { 790565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return NoFallbackControl.NOFALLBACK_FORMAT_CLASS_CONTROL; 791565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 792565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (formats.contains(JAVAPROPERTIES)) { 793565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return NoFallbackControl.NOFALLBACK_FORMAT_PROPERTIES_CONTROL; 794565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 795565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes break; 796565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes case 2: 797565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (formats.equals(FORMAT_DEFAULT)) { 798565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return NoFallbackControl.NOFALLBACK_FORMAT_DEFAULT_CONTROL; 799565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 800565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes break; 801565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 802565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes throw new IllegalArgumentException(); 803565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 804565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 805565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 806eeefcae2980c8db05ec08303b5b112afce232d26Elliott Hughes * Returns a list of candidate locales according to {@code baseName} in 807eeefcae2980c8db05ec08303b5b112afce232d26Elliott Hughes * {@code locale}. 808565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 809565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public List<Locale> getCandidateLocales(String baseName, Locale locale) { 81086acc043d3334651ee26c65467d78d6cefedd397Kenny Root if (baseName == null) { 81186acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("baseName == null"); 81286acc043d3334651ee26c65467d78d6cefedd397Kenny Root } else if (locale == null) { 81386acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("locale == null"); 814565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 815565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes List<Locale> retList = new ArrayList<Locale>(); 816565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes String language = locale.getLanguage(); 817565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes String country = locale.getCountry(); 818565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes String variant = locale.getVariant(); 819565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (!EMPTY_STRING.equals(variant)) { 820565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes retList.add(new Locale(language, country, variant)); 821565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 822565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (!EMPTY_STRING.equals(country)) { 823565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes retList.add(new Locale(language, country)); 824565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 825565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (!EMPTY_STRING.equals(language)) { 826565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes retList.add(new Locale(language)); 827565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 828565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes retList.add(Locale.ROOT); 829565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return retList; 830565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 831565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 832565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 833eeefcae2980c8db05ec08303b5b112afce232d26Elliott Hughes * Returns a list of strings of formats according to {@code baseName}. 834565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 835565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public List<String> getFormats(String baseName) { 836b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (baseName == null) { 83786acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("baseName == null"); 838565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 839565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return format; 840565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 841565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 842565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 843eeefcae2980c8db05ec08303b5b112afce232d26Elliott Hughes * Returns the fallback locale for {@code baseName} in {@code locale}. 844565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 845565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public Locale getFallbackLocale(String baseName, Locale locale) { 84686acc043d3334651ee26c65467d78d6cefedd397Kenny Root if (baseName == null) { 84786acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("baseName == null"); 84886acc043d3334651ee26c65467d78d6cefedd397Kenny Root } else if (locale == null) { 84986acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("locale == null"); 850565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 851565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (Locale.getDefault() != locale) { 852565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return Locale.getDefault(); 853565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 854565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return null; 855565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 856565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 857565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 858eeefcae2980c8db05ec08303b5b112afce232d26Elliott Hughes * Returns a new ResourceBundle. 859f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 860565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param baseName 861565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the base name to use 862565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param locale 863565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the given locale 864565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param format 865eeefcae2980c8db05ec08303b5b112afce232d26Elliott Hughes * the format, default is "java.class" or "java.properties" 866565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param loader 867565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the classloader to use 868565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param reload 869eeefcae2980c8db05ec08303b5b112afce232d26Elliott Hughes * whether to reload the resource 870565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @return a new ResourceBundle according to the give parameters 871565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @throws IllegalAccessException 872eeefcae2980c8db05ec08303b5b112afce232d26Elliott Hughes * if we can not access resources 873565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @throws InstantiationException 874eeefcae2980c8db05ec08303b5b112afce232d26Elliott Hughes * if we can not instantiate a resource class 875565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @throws IOException 876565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * if other I/O exception happens 877565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 878565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public ResourceBundle newBundle(String baseName, Locale locale, 879565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes String format, ClassLoader loader, boolean reload) 880565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes throws IllegalAccessException, InstantiationException, 881565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes IOException { 88286acc043d3334651ee26c65467d78d6cefedd397Kenny Root if (format == null) { 88386acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("format == null"); 88486acc043d3334651ee26c65467d78d6cefedd397Kenny Root } else if (loader == null) { 88586acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("loader == null"); 886565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 887565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes final String bundleName = toBundleName(baseName, locale); 888565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes final ClassLoader clsloader = loader; 889565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ResourceBundle ret; 890510dc6afb60f9099127c5bc9fb91d86b778d747fElliott Hughes if (format.equals(JAVACLASS)) { 891ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes Class<?> cls = null; 892ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes try { 893ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes cls = clsloader.loadClass(bundleName); 894ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes } catch (Exception e) { 895ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes } catch (NoClassDefFoundError e) { 896ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes } 897b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (cls == null) { 898565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return null; 899565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 900565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes try { 901565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ResourceBundle bundle = (ResourceBundle) cls.newInstance(); 902565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes bundle.setLocale(locale); 903565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return bundle; 904565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } catch (NullPointerException e) { 905565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return null; 906565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 907565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 908510dc6afb60f9099127c5bc9fb91d86b778d747fElliott Hughes if (format.equals(JAVAPROPERTIES)) { 909ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes InputStream streams = null; 910ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes final String resourceName = toResourceName(bundleName, "properties"); 911565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (reload) { 912565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes URL url = null; 913565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes try { 914565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes url = loader.getResource(resourceName); 915565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } catch (NullPointerException e) { 916565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes // do nothing 917565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 918b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (url != null) { 919565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes URLConnection con = url.openConnection(); 920565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes con.setUseCaches(false); 921565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes streams = con.getInputStream(); 922565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 923565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } else { 924565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes try { 925ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes streams = clsloader.getResourceAsStream(resourceName); 926565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } catch (NullPointerException e) { 927565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes // do nothing 928565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 929565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 930565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (streams != null) { 931565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes try { 932565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret = new PropertyResourceBundle(new InputStreamReader(streams)); 933565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret.setLocale(locale); 934565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes streams.close(); 935565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } catch (IOException e) { 936565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return null; 937565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 938565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return ret; 939565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 940565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return null; 941565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 942565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes throw new IllegalArgumentException(); 943565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 944565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 945565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 946eeefcae2980c8db05ec08303b5b112afce232d26Elliott Hughes * Returns the time to live of the ResourceBundle {@code baseName} in {@code locale}, 947eeefcae2980c8db05ec08303b5b112afce232d26Elliott Hughes * default is TTL_NO_EXPIRATION_CONTROL. 948565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 949565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public long getTimeToLive(String baseName, Locale locale) { 95086acc043d3334651ee26c65467d78d6cefedd397Kenny Root if (baseName == null) { 95186acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("baseName == null"); 95286acc043d3334651ee26c65467d78d6cefedd397Kenny Root } else if (locale == null) { 95386acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("locale == null"); 954565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 955565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return TTL_NO_EXPIRATION_CONTROL; 956565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 957565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 958565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 959eeefcae2980c8db05ec08303b5b112afce232d26Elliott Hughes * Returns true if the ResourceBundle needs to reload. 960f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 961565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param baseName 962565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the base name of the ResourceBundle 963565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param locale 964565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the locale of the ResourceBundle 965565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param format 966565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the format to load 967565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param loader 968565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the ClassLoader to load resource 969565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param bundle 970565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the ResourceBundle 971565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param loadTime 972565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the expired time 973565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @return if the ResourceBundle needs to reload 974565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 975565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public boolean needsReload(String baseName, Locale locale, 976565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes String format, ClassLoader loader, ResourceBundle bundle, 977565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes long loadTime) { 978b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (bundle == null) { 979565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes // FIXME what's the use of bundle? 98086acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("bundle == null"); 981565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 982565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes String bundleName = toBundleName(baseName, locale); 983565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes String suffix = format; 984510dc6afb60f9099127c5bc9fb91d86b778d747fElliott Hughes if (format.equals(JAVACLASS)) { 985565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes suffix = "class"; 986565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 987510dc6afb60f9099127c5bc9fb91d86b778d747fElliott Hughes if (format.equals(JAVAPROPERTIES)) { 988565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes suffix = "properties"; 989565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 990565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes String urlname = toResourceName(bundleName, suffix); 991565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes URL url = loader.getResource(urlname); 992b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (url != null) { 993565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes String fileName = url.getFile(); 994565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes long lastModified = new File(fileName).lastModified(); 995565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (lastModified > loadTime) { 996565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return true; 997565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 998565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 999565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return false; 1000565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 1001565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 1002565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 1003565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * a utility method to answer the name of a resource bundle according to 1004565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the given base name and locale 1005f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 1006565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param baseName 1007565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the given base name 1008565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param locale 1009565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the locale to use 1010565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @return the name of a resource bundle according to the given base 1011565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * name and locale 1012565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 1013565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public String toBundleName(String baseName, Locale locale) { 1014565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes final String emptyString = EMPTY_STRING; 1015565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes final String preString = UNDER_SCORE; 1016565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes final String underline = UNDER_SCORE; 1017b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (baseName == null) { 101886acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("baseName == null"); 1019565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 1020565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes StringBuilder ret = new StringBuilder(); 1021565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes StringBuilder prefix = new StringBuilder(); 1022565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret.append(baseName); 1023565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (!locale.getLanguage().equals(emptyString)) { 1024565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret.append(underline); 1025565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret.append(locale.getLanguage()); 1026565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } else { 1027565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes prefix.append(preString); 1028565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 1029565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (!locale.getCountry().equals(emptyString)) { 1030565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret.append((CharSequence) prefix); 1031565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret.append(underline); 1032565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret.append(locale.getCountry()); 1033565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes prefix = new StringBuilder(); 1034565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } else { 1035565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes prefix.append(preString); 1036565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 1037565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes if (!locale.getVariant().equals(emptyString)) { 1038565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret.append((CharSequence) prefix); 1039565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret.append(underline); 1040565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret.append(locale.getVariant()); 1041565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 1042565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return ret.toString(); 1043565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 1044565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes 1045565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes /** 1046565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * a utility method to answer the name of a resource according to the 1047565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * given bundleName and suffix 1048f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 1049565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param bundleName 1050565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the given bundle name 1051565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @param suffix 1052565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * the suffix 1053565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * @return the name of a resource according to the given bundleName and 1054565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes * suffix 1055565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes */ 1056565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes public final String toResourceName(String bundleName, String suffix) { 1057b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (suffix == null) { 105886acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("suffix == null"); 1059565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 1060565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes StringBuilder ret = new StringBuilder(bundleName.replace('.', '/')); 1061565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret.append('.'); 1062565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes ret.append(suffix); 1063565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes return ret.toString(); 1064565a85d06ab8bc321d39f12012468cdfb65f5cfeElliott Hughes } 1065adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1066adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 1067