1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one or more 3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * contributor license agreements. See the NOTICE file distributed with 4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * this work for additional information regarding copyright ownership. 5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The ASF licenses this file to You under the Apache License, Version 2.0 6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (the "License"); you may not use this file except in compliance with 7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the License. You may obtain a copy of the License at 8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and 15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License. 16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage org.apache.harmony.luni.util; 19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.AccessController; 22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.PrivilegedAction; 23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Locale; 24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.MissingResourceException; 25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.ResourceBundle; 26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// BEGIN android-added 27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.lang.ref.SoftReference; 28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.HashMap; 29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.logging.Logger; 30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// END android-added 31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// BEGIN android-changed 33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport dalvik.system.VMStack; 34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// END android-changed 35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/** 37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This class contains helper methods for loading resource bundles and 38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * formatting external message strings. 39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic final class MsgHelp { 42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // BEGIN android-added 43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // A HashMap mapping a resource name to a SoftReference to a ResourceBundle 44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // holding the messages for that resource. 45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private static HashMap<String, SoftReference<ResourceBundle>> sRefMap = null; 46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public synchronized static ResourceBundle loadBundle(String resource) { 48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (sRefMap == null) { 49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project sRefMap = new HashMap<String, SoftReference<ResourceBundle>>(); 50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project SoftReference<ResourceBundle> bundleRef = sRefMap.get(resource); 52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (bundleRef == null || bundleRef.get() == null) { 53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Attempt to load the messages. 54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project try { 55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ResourceBundle bundle = setLocale(Locale.getDefault(), 56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project resource); 57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project bundleRef = new SoftReference<ResourceBundle>(bundle); 58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project sRefMap.put(resource, bundleRef); 59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return bundle; 60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } catch (Throwable e) { 61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Logger.global.warning("Got Throwable " + e + 62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project " loading messages"); 63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return null; 64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return bundleRef.get(); 67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public static String getString(String resource, String msg) { 71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ResourceBundle bundle = MsgHelp.loadBundle(resource); 72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (bundle == null) { 73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return msg; 74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project try { 76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return bundle.getString(msg); 77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } catch (MissingResourceException e) { 78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return "Missing message: " + msg; // $NON_NLS-1$ 79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project static public String getString(String resource, String msg, Object[] args) { 83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project String format = msg; 84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ResourceBundle bundle = MsgHelp.loadBundle(resource); 85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (bundle != null) { 86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project try { 87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project format = bundle.getString(msg); 88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } catch (MissingResourceException e) { 89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return format(format, args); 93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // END android-added 95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Generates a formatted text string given a source string containing 98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * "argument markers" of the form "{argNum}" where each argNum must be in 99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the range 0..9. The result is generated by inserting the toString of each 100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * argument into the position indicated in the string. 101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <p> 102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * To insert the "{" character into the output, use a single backslash 103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * character to escape it (i.e. "\{"). The "}" character does not need to be 104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * escaped. 105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param format 107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * String the format to use when printing. 108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param args 109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Object[] the arguments to use. 110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @return String the formatted message. 111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public static String format(String format, Object[] args) { 113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project StringBuilder answer = new StringBuilder(format.length() 114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project + (args.length * 20)); 115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project String[] argStrings = new String[args.length]; 116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (int i = 0; i < args.length; ++i) { 117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (args[i] == null) 118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project argStrings[i] = "<null>"; 119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project else 120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project argStrings[i] = args[i].toString(); 121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int lastI = 0; 123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (int i = format.indexOf('{', 0); i >= 0; i = format.indexOf('{', 124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lastI)) { 125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (i != 0 && format.charAt(i - 1) == '\\') { 126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // It's escaped, just print and loop. 127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (i != 1) 128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project answer.append(format.substring(lastI, i - 1)); 129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project answer.append('{'); 130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lastI = i + 1; 131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // It's a format character. 133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (i > format.length() - 3) { 134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Bad format, just print and loop. 135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project answer.append(format.substring(lastI, format.length())); 136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lastI = format.length(); 137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int argnum = (byte) Character.digit(format.charAt(i + 1), 139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 10); 140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (argnum < 0 || format.charAt(i + 2) != '}') { 141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Bad format, just print and loop. 142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project answer.append(format.substring(lastI, i + 1)); 143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lastI = i + 1; 144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Got a good one! 146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project answer.append(format.substring(lastI, i)); 147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (argnum >= argStrings.length) 148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project answer.append("<missing argument>"); 149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project else 150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project answer.append(argStrings[argnum]); 151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lastI = i + 3; 152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (lastI < format.length()) 157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project answer.append(format.substring(lastI, format.length())); 158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return answer.toString(); 159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Changes the locale of the messages. 163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param locale 165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Locale the locale to change to. 166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param resource 167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the name of the bundle resource 168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project static public ResourceBundle setLocale(final Locale locale, 170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project final String resource) { 171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project try { 172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // BEGIN android-removed 173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // final ClassLoader loader = VM.bootCallerClassLoader(); 174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // END android-removed 175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return (ResourceBundle) AccessController 176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project .doPrivileged(new PrivilegedAction<Object>() { 177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public Object run() { 178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // BEGIN android-changed 179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return ResourceBundle.getBundle(resource, locale, 180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ClassLoader.getSystemClassLoader()); 181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // END android-changed 182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project }); 184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } catch (MissingResourceException e) { 185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return null; 187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 189