001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2013, 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, 2009, by Jess Thrysoee and Contributors.
031 *
032 * Original Author:  Jess Thrysoee;
033 * Contributor(s):   David Gilbert (for Object Refinery Limited);
034 *
035 * Changes
036 * -------
037 * 18-Dec-2008 : Version 1 (JT);
038 *
039 */
040
041package org.jfree.chart.util;
042
043import java.net.URL;
044import java.net.URLClassLoader;
045import java.util.ArrayList;
046import java.util.List;
047import java.util.Locale;
048import java.util.ResourceBundle;
049
050/**
051 * Wrapper of ResourceBundle.getBundle() methods. This wrapper is introduced to
052 * avoid a dramatic performance penalty by superfluous resource (and classes
053 * loaded by Class.forName) lookups on web server in applets.
054 *
055 * <pre>
056 * public class AppletC extends javax.swing.JApplet {
057 *    public void init() {
058 *       ResourceBundleWrapper.removeCodeBase(getCodeBase(),
059 *               (URLClassLoader) getClass().getClassLoader());
060 *    ...
061 * </pre>
062 *
063 * @see <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4243379">
064 *               Bug ID: 4243379</a>
065 * @see <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4668479">
066 *               Bug ID: 4668479</a>
067 *
068 * @since 1.0.12
069 */
070public class ResourceBundleWrapper {
071
072    /**
073     * A special class loader with no code base lookup.  This field may be
074     * <code>null</code> (the field is only initialised if removeCodeBase() is
075     * called from an applet).
076     */
077    private static URLClassLoader noCodeBaseClassLoader;
078
079    /**
080     * Private constructor.
081     */
082    private ResourceBundleWrapper() {
083        // all methods are static, no need to instantiate
084    }
085
086    /**
087     * Instantiate a {@link URLClassLoader} for resource lookups where the
088     * codeBase URL is removed.  This method is typically called from an
089     * applet's init() method.  If this method is never called, the
090     * <code>getBundle()</code> methods map to the standard
091     * {@link ResourceBundle} lookup methods.
092     *
093     * @param codeBase  the codeBase URL.
094     * @param urlClassLoader  the class loader.
095     */
096    public static void removeCodeBase(URL codeBase,
097            URLClassLoader urlClassLoader) {
098        List urlsNoBase = new ArrayList();
099
100        URL[] urls = urlClassLoader.getURLs();
101        for (int i = 0; i < urls.length; i++) {
102            if (!urls[i].sameFile(codeBase)) {
103                urlsNoBase.add(urls[i]);
104            }
105        }
106        // substitute the filtered URL list
107        URL[] urlsNoBaseArray = (URL[]) urlsNoBase.toArray(new URL[0]);
108        noCodeBaseClassLoader = URLClassLoader.newInstance(urlsNoBaseArray);
109    }
110
111    /**
112     * Finds and returns the specified resource bundle.
113     *
114     * @param baseName  the base name.
115     *
116     * @return The resource bundle.
117     */
118    public static ResourceBundle getBundle(String baseName) {
119        // the noCodeBaseClassLoader is configured by a call to the
120        // removeCodeBase() method, typically in the init() method of an
121        // applet...
122        if (noCodeBaseClassLoader != null) {
123            return ResourceBundle.getBundle(baseName, Locale.getDefault(),
124                    noCodeBaseClassLoader);
125        }
126        else {
127            // standard ResourceBundle behaviour
128            return ResourceBundle.getBundle(baseName);
129        }
130    }
131
132    /**
133     * Finds and returns the specified resource bundle.
134     *
135     * @param baseName  the base name.
136     * @param locale  the locale.
137     *
138     * @return The resource bundle.
139     */
140    public static ResourceBundle getBundle(String baseName, Locale locale) {
141
142        // the noCodeBaseClassLoader is configured by a call to the
143        // removeCodeBase() method, typically in the init() method of an
144        // applet...
145        if (noCodeBaseClassLoader != null) {
146            return ResourceBundle.getBundle(baseName, locale,
147                    noCodeBaseClassLoader);
148        }
149        else {
150            // standard ResourceBundle behaviour
151            return ResourceBundle.getBundle(baseName, locale);
152        }
153    }
154
155    /**
156     * Maps directly to <code>ResourceBundle.getBundle(baseName, locale,
157     * loader)</code>.
158     *
159     * @param baseName  the base name.
160     * @param locale  the locale.
161     * @param loader  the class loader.
162     *
163     * @return The resource bundle.
164     */
165    public static ResourceBundle getBundle(String baseName, Locale locale,
166            ClassLoader loader) {
167        return ResourceBundle.getBundle(baseName, locale, loader);
168    }
169
170}