All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eigenbase.resgen.ShadowResourceBundle Maven / Gradle / Ivy

The newest version!
/*
// Licensed to Julian Hyde under one or more contributor license
// agreements. See the NOTICE file distributed with this work for
// additional information regarding copyright ownership.
//
// Julian Hyde licenses this file to you under the Apache License,
// Version 2.0 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/
package org.eigenbase.resgen;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * ShadowResourceBundle is an abstract base class for
 * {@link ResourceBundle} classes which are backed by a properties file. When
 * the class is created, it loads a properties file with the same name as the
 * class.
 *
 * 

In the standard scheme (see {@link ResourceBundle}), * if you call {@link ResourceBundle#getBundle}("foo.MyResource"), * it first looks for a class called foo.MyResource, then * looks for a file called foo/MyResource.properties. If it finds * the file, it creates a {@link PropertyResourceBundle} and loads the class. * The problem is if you want to load the .properties file * into a dedicated class; ShadowResourceBundle helps with this * case. * *

You should create a class as follows:

* *
package foo;
 *class MyResource extends org.eigenbase.resgen.ShadowResourceBundle {
 *    public MyResource() throws java.io.IOException {
 *    }
 *}
* *
Then when you call * {@link ResourceBundle#getBundle ResourceBundle.getBundle("foo.MyResource")}, * it will find the class before the properties file, but still automatically * load the properties file based upon the name of the class. */ public abstract class ShadowResourceBundle extends ResourceBundle { private PropertyResourceBundle bundle; private static final ThreadLocal mapThreadToLocale = new ThreadLocal(); protected static final Object[] emptyObjectArray = new Object[0]; /** * Creates a ShadowResourceBundle, and reads resources from * a .properties file with the same name as the current class. * For example, if the class is called foo.MyResource_en_US, * reads from foo/MyResource_en_US.properties, then * foo/MyResource_en.properties, then * foo/MyResource.properties. * * @throws IOException on error */ protected ShadowResourceBundle() throws IOException { super(); Class clazz = getClass(); InputStream stream = openPropertiesFile(clazz); if (stream == null) { throw new IOException("could not open properties file for " + getClass()); } MyPropertyResourceBundle previousBundle = new MyPropertyResourceBundle(stream); bundle = previousBundle; stream.close(); // Now load properties files for parent locales, which we deduce from // the names of our super-class, and its super-class. while (true) { clazz = clazz.getSuperclass(); if (clazz == null || clazz == ShadowResourceBundle.class || !ResourceBundle.class.isAssignableFrom(clazz)) { break; } stream = openPropertiesFile(clazz); if (stream == null) { continue; } MyPropertyResourceBundle newBundle = new MyPropertyResourceBundle(stream); stream.close(); if (previousBundle != null) { previousBundle.setParentTrojan(newBundle); } else { bundle = newBundle; } previousBundle = newBundle; } } static class MyPropertyResourceBundle extends PropertyResourceBundle { public MyPropertyResourceBundle(InputStream stream) throws IOException { super(stream); } void setParentTrojan(ResourceBundle parent) { super.setParent(parent); } } /** * Opens the properties file corresponding to a given class. The code is * copied from {@link ResourceBundle}. */ private static InputStream openPropertiesFile(Class clazz) { final ClassLoader loader = clazz.getClassLoader(); final String resName = clazz.getName().replace('.', '/') + ".properties"; return (InputStream)java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Object run() { if (loader != null) { return loader.getResourceAsStream(resName); } else { return ClassLoader.getSystemResourceAsStream(resName); } } }); } public Enumeration getKeys() { return bundle.getKeys(); } protected Object handleGetObject(String key) throws MissingResourceException { return bundle.getObject(key); } /** * Returns the instance of the baseName resource bundle for * the current thread's locale. For example, if called with * "mondrian.olap.MondrianResource", from a thread which has called * {@link #setThreadLocale}({@link Locale#FRENCH}), * will get an instance of * "mondrian.olap.MondrianResource_FR" from the cache. * *

This method should be called from a derived class, with the proper * casting:

* *
class MyResource extends ShadowResourceBundle {
     *    ...
     *    /**
     *      * Retrieves the instance of {@link MyResource} appropriate
     *      * to the current locale. If this thread has specified a locale
     *      * by calling {@link #setThreadLocale}, this locale is used,
     *      * otherwise the default locale is used.
     *      **/
     *    public static MyResource instance() {
     *       return (MyResource) instance(MyResource.class.getName());
     *    }
     *    ...
     * }
* * @deprecated This method does not work correctly in dynamically * loaded jars. * * @param baseName Base name * * @return Resource bundle */ protected static ResourceBundle instance(String baseName) { return instance(baseName, getThreadLocale()); } /** * Returns the instance of the baseName resource bundle * for the given locale. * *

This method should be called from a derived class, with the proper * casting:

* *
class MyResource extends ShadowResourceBundle {
     *    ...
     *
     *    /**
     *      * Retrieves the instance of {@link MyResource} appropriate
     *      * to the given locale.
     *      **/
     *    public static MyResource instance(Locale locale) {
     *       return (MyResource) instance(MyResource.class.getName(), locale);
     *    }
     *    ...
     * }
* * @param baseName Base name * @param locale Locale * @return Resource bundle * * @deprecated This method does not work correctly in dynamically * loaded jars. */ protected static ShadowResourceBundle instance( String baseName, Locale locale) { if (locale == null) { locale = Locale.getDefault(); } ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale); return instance(baseName, locale, bundle); } /** * Returns the instance of the baseName resource bundle * for the given locale. * *

This method should be called from a derived class, with the proper * casting:

* *
class MyResource extends ShadowResourceBundle {
     *    ...
     *
     *    /**
     *      * Retrieves the instance of {@link MyResource} appropriate
     *      * to the given locale.
     *      **/
     *    public static MyResource instance(Locale locale) {
     *       return (MyResource) instance(
     *           MyResource.class.getName(), locale,
     *           ResourceBundle.getBundle(MyResource.class.getName(), locale));
     *    }
     *    ...
     * }
* * @param baseName Base name * @param locale Locale * @param bundle Resource bundle * @return Resource bundle */ protected static ShadowResourceBundle instance( String baseName, Locale locale, ResourceBundle bundle) { if (bundle instanceof PropertyResourceBundle) { throw new ClassCastException( "ShadowResourceBundle.instance('" + baseName + "','" + locale + "') found " + baseName + "_" + locale + ".properties but not " + baseName + "_" + locale + ".class"); } return (ShadowResourceBundle) bundle; } /** Returns the preferred locale of the current thread, or * the default locale if the current thread has not called * {@link #setThreadLocale}. * * @return Locale */ protected static Locale getThreadOrDefaultLocale() { Locale locale = getThreadLocale(); if (locale == null) { return Locale.getDefault(); } else { return locale; } } /** Sets the locale for the current thread. * Used by {@link #instance(String,Locale)}. * * @param locale Locale */ public static void setThreadLocale(Locale locale) { mapThreadToLocale.set(locale); } /** Returns the preferred locale of the current thread, or null if the * thread has not called {@link #setThreadLocale}. * * @return Locale */ public static Locale getThreadLocale() { return (Locale) mapThreadToLocale.get(); } } // End ShadowResourceBundle.java




© 2015 - 2025 Weber Informatics LLC | Privacy Policy