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