001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2008, 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     * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025     * in the United States and other countries.]
026     *
027     * --------------------------
028     * ResourceBundleWrapper.java
029     * --------------------------
030     * (C)opyright 2008, 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    
041    package org.jfree.chart.util;
042    
043    import java.net.URL;
044    import java.net.URLClassLoader;
045    import java.util.ArrayList;
046    import java.util.List;
047    import java.util.Locale;
048    import 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     */
070    public 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 final 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 final ResourceBundle getBundle(String baseName,
141                Locale locale) {
142    
143            // the noCodeBaseClassLoader is configured by a call to the
144            // removeCodeBase() method, typically in the init() method of an
145            // applet...
146            if (noCodeBaseClassLoader != null) {
147                return ResourceBundle.getBundle(baseName, locale,
148                        noCodeBaseClassLoader);
149            }
150            else {
151                // standard ResourceBundle behaviour
152                return ResourceBundle.getBundle(baseName, locale);
153            }
154        }
155    
156        /**
157         * Maps directly to <code>ResourceBundle.getBundle(baseName, locale,
158         * loader)</code>.
159         *
160         * @param baseName  the base name.
161         * @param locale  the locale.
162         * @param loader  the class loader.
163         *
164         * @return The resource bundle.
165         */
166        public static ResourceBundle getBundle(String baseName, Locale locale,
167                ClassLoader loader) {
168            return ResourceBundle.getBundle(baseName, locale, loader);
169        }
170    
171    }