JavacMessages.java revision 2571:10fc81ac75b4
1197383Sdelphij/* 2197571Sdelphij * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. 3205297Sjkim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4197571Sdelphij * 5197571Sdelphij * This code is free software; you can redistribute it and/or modify it 6197571Sdelphij * under the terms of the GNU General Public License version 2 only, as 7197571Sdelphij * published by the Free Software Foundation. Oracle designates this 8197571Sdelphij * particular file as subject to the "Classpath" exception as provided 9197571Sdelphij * by Oracle in the LICENSE file that accompanied this code. 10197571Sdelphij * 11197571Sdelphij * This code is distributed in the hope that it will be useful, but WITHOUT 12197571Sdelphij * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13197571Sdelphij * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14197571Sdelphij * version 2 for more details (a copy is included in the LICENSE file that 15197571Sdelphij * accompanied this code). 16197571Sdelphij * 17197571Sdelphij * You should have received a copy of the GNU General Public License version 18197571Sdelphij * 2 along with this work; if not, write to the Free Software Foundation, 19197571Sdelphij * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20197571Sdelphij * 21197571Sdelphij * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22197571Sdelphij * or visit www.oracle.com if you need additional information or have any 23197571Sdelphij * questions. 24197571Sdelphij */ 25197571Sdelphij 26197383Sdelphijpackage com.sun.tools.javac.util; 27197383Sdelphij 28197383Sdelphijimport com.sun.tools.javac.api.Messages; 29197383Sdelphijimport java.lang.ref.SoftReference; 30197383Sdelphijimport java.util.ResourceBundle; 31197383Sdelphijimport java.util.MissingResourceException; 32197383Sdelphijimport java.text.MessageFormat; 33197383Sdelphijimport java.util.HashMap; 34198251Sjkimimport java.util.Locale; 35197383Sdelphijimport java.util.Map; 36197442Sjkim 37198251Sjkim/** 38197383Sdelphij * Support for formatted localized messages. 39197383Sdelphij * 40200591Sjkim * <p><b>This is NOT part of any supported API. 41197383Sdelphij * If you write code that depends on this, you do so at your own risk. 42198251Sjkim * This code and its internal interfaces are subject to change or 43198251Sjkim * deletion without notice.</b> 44198251Sjkim */ 45198251Sjkimpublic class JavacMessages implements Messages { 46198251Sjkim /** The context key for the JavacMessages object. */ 47198251Sjkim public static final Context.Key<JavacMessages> messagesKey = new Context.Key<>(); 48198251Sjkim 49197383Sdelphij /** Get the JavacMessages instance for this context. */ 50197383Sdelphij public static JavacMessages instance(Context context) { 51197383Sdelphij JavacMessages instance = context.get(messagesKey); 52210877Sjkim if (instance == null) 53207456Sjkim instance = new JavacMessages(context); 54207456Sjkim return instance; 55210877Sjkim } 56210877Sjkim 57210877Sjkim private Map<Locale, SoftReference<List<ResourceBundle>>> bundleCache; 58207456Sjkim 59210877Sjkim private List<String> bundleNames; 60210877Sjkim 61211120Sjkim private Locale currentLocale; 62211120Sjkim private List<ResourceBundle> currentBundles; 63211120Sjkim 64211120Sjkim public Locale getCurrentLocale() { 65211120Sjkim return currentLocale; 66211120Sjkim } 67211120Sjkim 68210877Sjkim public void setCurrentLocale(Locale locale) { 69210877Sjkim if (locale == null) { 70227309Sed locale = Locale.getDefault(); 71227309Sed } 72210877Sjkim this.currentBundles = getBundles(locale); 73267992Shselasky this.currentLocale = locale; 74210877Sjkim } 75210877Sjkim 76267992Shselasky /** Creates a JavacMessages object. 77210877Sjkim */ 78210877Sjkim public JavacMessages(Context context) { 79210877Sjkim this(defaultBundleName, context.get(Locale.class)); 80210877Sjkim context.put(messagesKey, this); 81210877Sjkim } 82210877Sjkim 83210877Sjkim /** Creates a JavacMessages object. 84210877Sjkim * @param bundleName the name to identify the resource bundle of localized messages. 85210877Sjkim */ 86210877Sjkim public JavacMessages(String bundleName) throws MissingResourceException { 87210877Sjkim this(bundleName, null); 88210877Sjkim } 89210877Sjkim 90210877Sjkim /** Creates a JavacMessages object. 91210877Sjkim * @param bundleName the name to identify the resource bundle of localized messages. 92210877Sjkim */ 93210877Sjkim public JavacMessages(String bundleName, Locale locale) throws MissingResourceException { 94210877Sjkim bundleNames = List.nil(); 95210877Sjkim bundleCache = new HashMap<>(); 96210877Sjkim add(bundleName); 97210877Sjkim setCurrentLocale(locale); 98210877Sjkim } 99210877Sjkim 100210877Sjkim public JavacMessages() throws MissingResourceException { 101210877Sjkim this(defaultBundleName); 102210877Sjkim } 103210877Sjkim 104210877Sjkim public void add(String bundleName) throws MissingResourceException { 105210877Sjkim bundleNames = bundleNames.prepend(bundleName); 106210877Sjkim if (!bundleCache.isEmpty()) 107210877Sjkim bundleCache.clear(); 108210887Sjkim currentBundles = null; 109210877Sjkim } 110210877Sjkim 111210877Sjkim public List<ResourceBundle> getBundles(Locale locale) { 112210877Sjkim if (locale == currentLocale && currentBundles != null) 113210877Sjkim return currentBundles; 114210877Sjkim SoftReference<List<ResourceBundle>> bundles = bundleCache.get(locale); 115210877Sjkim List<ResourceBundle> bundleList = bundles == null ? null : bundles.get(); 116210877Sjkim if (bundleList == null) { 117210877Sjkim bundleList = List.nil(); 118210877Sjkim for (String bundleName : bundleNames) { 119210877Sjkim try { 120210877Sjkim ResourceBundle rb = ResourceBundle.getBundle(bundleName, locale); 121211112Sjkim bundleList = bundleList.prepend(rb); 122298801Spfg } catch (MissingResourceException e) { 123210877Sjkim throw new InternalError("Cannot find javac resource bundle for locale " + locale); 124211112Sjkim } 125211112Sjkim } 126211112Sjkim bundleCache.put(locale, new SoftReference<>(bundleList)); 127211112Sjkim } 128211112Sjkim return bundleList; 129211112Sjkim } 130210877Sjkim 131210938Sjkim /** Gets the localized string corresponding to a key, formatted with a set of args. 132210934Sjkim */ 133211112Sjkim public String getLocalizedString(String key, Object... args) { 134210877Sjkim return getLocalizedString(currentLocale, key, args); 135210877Sjkim } 136210877Sjkim 137211112Sjkim public String getLocalizedString(Locale l, String key, Object... args) { 138210877Sjkim if (l == null) 139210877Sjkim l = getCurrentLocale(); 140210877Sjkim return getLocalizedString(getBundles(l), key, args); 141210877Sjkim } 142210877Sjkim 143211112Sjkim /* Static access: 144211112Sjkim * javac has a firmly entrenched notion of a default message bundle 145210877Sjkim * which it can access from any static context. This is used to get 146211112Sjkim * easy access to simple localized strings. 147211112Sjkim */ 148211112Sjkim 149211112Sjkim private static final String defaultBundleName = 150211112Sjkim "com.sun.tools.javac.resources.compiler"; 151210877Sjkim private static ResourceBundle defaultBundle; 152211112Sjkim private static JavacMessages defaultMessages; 153211112Sjkim 154211112Sjkim 155211112Sjkim /** 156210934Sjkim * Returns a localized string from the compiler's default bundle. 157210934Sjkim */ 158210934Sjkim // used to support legacy Log.getLocalizedString 159211114Sjkim static String getDefaultLocalizedString(String key, Object... args) { 160211112Sjkim return getLocalizedString(List.of(getDefaultBundle()), key, args); 161211112Sjkim } 162211112Sjkim 163211112Sjkim // used to support legacy static Diagnostic.fragment 164210877Sjkim @Deprecated 165210877Sjkim static JavacMessages getDefaultMessages() { 166210877Sjkim if (defaultMessages == null) 167210877Sjkim defaultMessages = new JavacMessages(defaultBundleName); 168210877Sjkim return defaultMessages; 169210877Sjkim } 170210877Sjkim 171210877Sjkim public static ResourceBundle getDefaultBundle() { 172210877Sjkim try { 173210877Sjkim if (defaultBundle == null) 174210877Sjkim defaultBundle = ResourceBundle.getBundle(defaultBundleName); 175210877Sjkim return defaultBundle; 176210877Sjkim } 177210877Sjkim catch (MissingResourceException e) { 178210877Sjkim throw new Error("Fatal: Resource for compiler is missing", e); 179210877Sjkim } 180210877Sjkim } 181210877Sjkim 182210877Sjkim private static String getLocalizedString(List<ResourceBundle> bundles, 183211120Sjkim String key, 184210877Sjkim Object... args) { 185210877Sjkim String msg = null; 186210877Sjkim for (List<ResourceBundle> l = bundles; l.nonEmpty() && msg == null; l = l.tail) { 187210877Sjkim ResourceBundle rb = l.head; 188210877Sjkim try { 189210877Sjkim msg = rb.getString(key); 190210877Sjkim } 191210877Sjkim catch (MissingResourceException e) { 192210877Sjkim // ignore, try other bundles in list 193210877Sjkim } 194210877Sjkim } 195211120Sjkim if (msg == null) { 196210877Sjkim msg = "compiler message file broken: key=" + key + 197210877Sjkim " arguments={0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}"; 198210877Sjkim } 199210877Sjkim return MessageFormat.format(msg, args); 200210877Sjkim } 201210877Sjkim} 202210992Sjkim