001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-present, by David Gilbert 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-present, by Jess Thrysoee and Contributors.
031 *
032 * Original Author:  Jess Thrysoee;
033 * Contributor(s):   David Gilbert;
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 */
064public class ResourceBundleWrapper {
065
066    /**
067     * A special class loader with no code base lookup.  This field may be
068     * {@code null} (the field is only initialised if removeCodeBase() is
069     * called from an applet).
070     */
071    private static URLClassLoader noCodeBaseClassLoader;
072
073    /**
074     * Private constructor.
075     */
076    private ResourceBundleWrapper() {
077        // all methods are static, no need to instantiate
078    }
079
080    /**
081     * Instantiate a {@link URLClassLoader} for resource lookups where the
082     * codeBase URL is removed.  This method is typically called from an
083     * applet's init() method.  If this method is never called, the
084     * {@code getBundle()} methods map to the standard
085     * {@link ResourceBundle} lookup methods.
086     *
087     * @param codeBase  the codeBase URL.
088     * @param urlClassLoader  the class loader.
089     */
090    public static void removeCodeBase(URL codeBase,
091            URLClassLoader urlClassLoader) {
092        List urlsNoBase = new ArrayList();
093
094        URL[] urls = urlClassLoader.getURLs();
095        for (int i = 0; i < urls.length; i++) {
096            if (!urls[i].sameFile(codeBase)) {
097                urlsNoBase.add(urls[i]);
098            }
099        }
100        // substitute the filtered URL list
101        URL[] urlsNoBaseArray = (URL[]) urlsNoBase.toArray(new URL[0]);
102        noCodeBaseClassLoader = URLClassLoader.newInstance(urlsNoBaseArray);
103    }
104
105    /**
106     * Finds and returns the specified resource bundle.
107     *
108     * @param baseName  the base name.
109     *
110     * @return The resource bundle.
111     */
112    public static ResourceBundle getBundle(String baseName) {
113        // the noCodeBaseClassLoader is configured by a call to the
114        // removeCodeBase() method, typically in the init() method of an
115        // applet...
116        if (noCodeBaseClassLoader != null) {
117            return ResourceBundle.getBundle(baseName, Locale.getDefault(),
118                    noCodeBaseClassLoader);
119        }
120        else {
121            // standard ResourceBundle behaviour
122            return ResourceBundle.getBundle(baseName);
123        }
124    }
125
126    /**
127     * Finds and returns the specified resource bundle.
128     *
129     * @param baseName  the base name.
130     * @param locale  the locale.
131     *
132     * @return The resource bundle.
133     */
134    public static ResourceBundle getBundle(String baseName, Locale locale) {
135
136        // the noCodeBaseClassLoader is configured by a call to the
137        // removeCodeBase() method, typically in the init() method of an
138        // applet...
139        if (noCodeBaseClassLoader != null) {
140            return ResourceBundle.getBundle(baseName, locale,
141                    noCodeBaseClassLoader);
142        }
143        else {
144            // standard ResourceBundle behaviour
145            return ResourceBundle.getBundle(baseName, locale);
146        }
147    }
148
149    /**
150     * Maps directly to {@code ResourceBundle.getBundle(baseName, locale,
151     * loader)}.
152     *
153     * @param baseName  the base name.
154     * @param locale  the locale.
155     * @param loader  the class loader.
156     *
157     * @return The resource bundle.
158     */
159    public static ResourceBundle getBundle(String baseName, Locale locale,
160            ClassLoader loader) {
161        return ResourceBundle.getBundle(baseName, locale, loader);
162    }
163
164}