001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2020, by Object Refinery Limited and Contributors.
006 *
007 * Project Info:  http://www.jfree.org/jfreechart/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
022 * USA.
023 *
024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates.
025 * Other names may be trademarks of their respective owners.]
026 *
027 * --------------------------
028 * ResourceBundleWrapper.java
029 * --------------------------
030 * (C)opyright 2008-2020, by Jess Thrysoee and Contributors.
031 *
032 * Original Author:  Jess Thrysoee;
033 * Contributor(s):   David Gilbert (for Object Refinery Limited);
034 *
035 */
036
037package org.jfree.chart.util;
038
039import java.net.URL;
040import java.net.URLClassLoader;
041import java.util.ArrayList;
042import java.util.List;
043import java.util.Locale;
044import java.util.ResourceBundle;
045
046/**
047 * Wrapper of ResourceBundle.getBundle() methods. This wrapper is introduced to
048 * avoid a dramatic performance penalty by superfluous resource (and classes
049 * loaded by Class.forName) lookups on web server in applets.
050 *
051 * <pre>
052 * public class AppletC extends javax.swing.JApplet {
053 *    public void init() {
054 *       ResourceBundleWrapper.removeCodeBase(getCodeBase(),
055 *               (URLClassLoader) getClass().getClassLoader());
056 *    ...
057 * </pre>
058 *
059 * @see <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4243379">
060 *               Bug ID: 4243379</a>
061 * @see <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4668479">
062 *               Bug ID: 4668479</a>
063 *
064 * @since 1.0.12
065 */
066public class ResourceBundleWrapper {
067
068    /**
069     * A special class loader with no code base lookup.  This field may be
070     * {@code null} (the field is only initialised if removeCodeBase() is
071     * called from an applet).
072     */
073    private static URLClassLoader noCodeBaseClassLoader;
074
075    /**
076     * Private constructor.
077     */
078    private ResourceBundleWrapper() {
079        // all methods are static, no need to instantiate
080    }
081
082    /**
083     * Instantiate a {@link URLClassLoader} for resource lookups where the
084     * codeBase URL is removed.  This method is typically called from an
085     * applet's init() method.  If this method is never called, the
086     * {@code getBundle()} methods map to the standard
087     * {@link ResourceBundle} lookup methods.
088     *
089     * @param codeBase  the codeBase URL.
090     * @param urlClassLoader  the class loader.
091     */
092    public static void removeCodeBase(URL codeBase,
093            URLClassLoader urlClassLoader) {
094        List urlsNoBase = new ArrayList();
095
096        URL[] urls = urlClassLoader.getURLs();
097        for (int i = 0; i < urls.length; i++) {
098            if (!urls[i].sameFile(codeBase)) {
099                urlsNoBase.add(urls[i]);
100            }
101        }
102        // substitute the filtered URL list
103        URL[] urlsNoBaseArray = (URL[]) urlsNoBase.toArray(new URL[0]);
104        noCodeBaseClassLoader = URLClassLoader.newInstance(urlsNoBaseArray);
105    }
106
107    /**
108     * Finds and returns the specified resource bundle.
109     *
110     * @param baseName  the base name.
111     *
112     * @return The resource bundle.
113     */
114    public static ResourceBundle getBundle(String baseName) {
115        // the noCodeBaseClassLoader is configured by a call to the
116        // removeCodeBase() method, typically in the init() method of an
117        // applet...
118        if (noCodeBaseClassLoader != null) {
119            return ResourceBundle.getBundle(baseName, Locale.getDefault(),
120                    noCodeBaseClassLoader);
121        }
122        else {
123            // standard ResourceBundle behaviour
124            return ResourceBundle.getBundle(baseName);
125        }
126    }
127
128    /**
129     * Finds and returns the specified resource bundle.
130     *
131     * @param baseName  the base name.
132     * @param locale  the locale.
133     *
134     * @return The resource bundle.
135     */
136    public static ResourceBundle getBundle(String baseName, Locale locale) {
137
138        // the noCodeBaseClassLoader is configured by a call to the
139        // removeCodeBase() method, typically in the init() method of an
140        // applet...
141        if (noCodeBaseClassLoader != null) {
142            return ResourceBundle.getBundle(baseName, locale,
143                    noCodeBaseClassLoader);
144        }
145        else {
146            // standard ResourceBundle behaviour
147            return ResourceBundle.getBundle(baseName, locale);
148        }
149    }
150
151    /**
152     * Maps directly to {@code ResourceBundle.getBundle(baseName, locale,
153     * loader)}.
154     *
155     * @param baseName  the base name.
156     * @param locale  the locale.
157     * @param loader  the class loader.
158     *
159     * @return The resource bundle.
160     */
161    public static ResourceBundle getBundle(String baseName, Locale locale,
162            ClassLoader loader) {
163        return ResourceBundle.getBundle(baseName, locale, loader);
164    }
165
166}