You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by gd...@apache.org on 2002/01/03 22:57:22 UTC
cvs commit: xml-axis/java/src/org/apache/axis/utils RB.java
gdaniels 02/01/03 13:57:22
Added: java/src/org/apache/axis/utils RB.java
Log:
Utility class for dealing with internationalized string resources.
This class deals with:
1) Locales
2) Automatically merging properties from "parent" files to "children" (see
comments)
3) Automatically searching the correct place in the classpath for messages,
which allows us to organize messages in a much nicer way
Originally written by Karl Moss at Macromedia, tweaked for Axis.
Revision Changes Path
1.1 xml-axis/java/src/org/apache/axis/utils/RB.java
Index: RB.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Axis" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.axis.utils;
import java.util.HashMap;
import java.util.ResourceBundle;
import java.util.MissingResourceException;
import java.util.Locale;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Date;
import java.util.Enumeration;
import java.text.MessageFormat;
import java.io.InputStream;
import java.io.IOException;
/**
* <p>Wrapper class for resource bundles. Property files are used to store
* resource strings, which are the only types of resources available.
* Property files can inherit properties from other files so that
* a base property file can be used and a small number of properties
* can be over-ridden by another property file. For example you may
* create an english version of a resource file named "resource.properties".
* You then decide that the British English version of all of the properties
* except one are the same, so there is no need to redefine all of the
* properties in "resource_en_GB", just the one that is different.</p>
* <p>The property file lookup searches for classes with various suffixes
* on the basis if the desired local and the current default local
* (as returned by Local.getDefault()). As property files are found the
* property values are merged so that inheritance is preserved.</p>
* <p>The order of searching is:</p>
* <dir>
* basename + "_" + langage + "_" + country + "_" + variant
* basename + "_" + langage + "_" + country
* basename + "_" + langage
* basename + "_" + defaultLanguage + "_" + defaultCountry + "_" + defaultVariant
* basename + "_" + defaultLanguage + "_" + defaultCountry
* basename + "_" + defaultLanguage
* basename
* </dir>
* <p>The basename is the name of the property file without the ".properties"
* extension.</p>
* <p>Properties will be cached for performance.<p>
* <p>Property values stored in the property files can also contain dynamic
* variables. Any dynamic variable defined in PropertiesUtil.getVariableValue()
* can be used (such as {date}), as well as arguments in the form {0}, {1}, etc.
* Argument values are specified in the various overloaded getString() methods.</p>
*
* @author Karl Moss (kmoss@macromedia.com)
* @author Glen Daniels (gdaniels@macromedia.com)
*/
public class RB {
// The static cache of properties. The key is the basename + the local +
// the default local and the element is the Properties object containing
// the resources
static Hashtable propertyCache = new Hashtable();
// The default base name
public static final String BASE_NAME = "resource";
// The property file extension
public static final String PROPERTY_EXT = ".properties";
// The name of the current base property file (with extension)
protected String basePropertyFileName;
// The properties for the current resource bundle
protected Properties resourceProperties;
/**
* Construct a new RB
* @param name The name of the property file without the ".properties" extension
*/
public RB(String name) throws MissingResourceException
{
this(null, name, null);
}
/**
* Construct a new RB
* @param caller The calling object. This is used to get the package name
* to further construct the basename as well as to get the proper ClassLoader
* @param name The name of the property file without the ".properties" extension
*/
public RB(Object caller, String name) throws MissingResourceException
{
this(caller, name, null);
}
/**
* Construct a new RB
* @param caller The calling object. This is used to get the package name
* to further construct the basename as well as to get the proper ClassLoader
* @param name The name of the property file without the ".properties" extension
* @param local The local
*/
public RB(Object caller, String name, Locale locale) throws MissingResourceException
{
ClassLoader cl = null;
if (caller != null) {
Class c;
if (caller instanceof Class) {
c = (Class) caller;
}
else {
c = caller.getClass();
}
// Get the appropriate class loader
cl = c.getClassLoader();
if (name.indexOf("/") == -1) {
// Create the full basename only if not given
String fullName = c.getName();
int pos = fullName.lastIndexOf(".");
if (pos > 0) {
name = fullName.substring(0, pos + 1).replace('.', '/') + name;
}
}
}
Locale defaultLocale = Locale.getDefault();
// If the locale given is the same as the default locale, ignore it
if (locale != null) {
if (locale.equals(defaultLocale)) {
locale = null;
}
}
// Load the properties. If no property files exist then a
// MissingResourceException will be thrown
loadProperties(name, cl, locale, defaultLocale);
}
/**
* Gets a string message from the resource bundle for the given key
* @param key The resource key
* @return The message
*/
public String getString(String key) throws MissingResourceException
{
return getString(key, (Object[]) null);
}
/**
* <p>Gets a string message from the resource bundle for the given key. The
* message may contain variables that will be substituted with the given
* arguments. Variables have the format:</p>
* <dir>
* This message has two variables: {0} and {1}
* </dir>
* @param key The resource key
* @param arg0 The argument to place in variable {0}
* @return The message
*/
public String getString(String key, Object arg0) throws MissingResourceException
{
Object[] o = new Object[1];
o[0] = arg0;
return getString(key, o);
}
/**
* <p>Gets a string message from the resource bundle for the given key. The
* message may contain variables that will be substituted with the given
* arguments. Variables have the format:</p>
* <dir>
* This message has two variables: {0} and {1}
* </dir>
* @param key The resource key
* @param arg0 The argument to place in variable {0}
* @param arg1 The argument to place in variable {1}
* @return The message
*/
public String getString(String key, Object arg0, Object arg1) throws MissingResourceException
{
Object[] o = new Object[2];
o[0] = arg0;
o[1] = arg1;
return getString(key, o);
}
/**
* <p>Gets a string message from the resource bundle for the given key. The
* message may contain variables that will be substituted with the given
* arguments. Variables have the format:</p>
* <dir>
* This message has two variables: {0} and {1}
* </dir>
* @param key The resource key
* @param arg0 The argument to place in variable {0}
* @param arg1 The argument to place in variable {1}
* @param arg2 The argument to place in variable {1}
* @return The message
*/
public String getString(String key, Object arg0, Object arg1, Object arg2) throws MissingResourceException
{
Object[] o = new Object[3];
o[0] = arg0;
o[1] = arg1;
o[2] = arg2;
return getString(key, o);
}
/**
* <p>Gets a string message from the resource bundle for the given key. The
* message may contain variables that will be substituted with the given
* arguments. Variables have the format:</p>
* <dir>
* This message has two variables: {0} and {1}
* </dir>
* @param key The resource key
* @param array An array of objects to place in corresponding variables
* @return The message
*/
public String getString(String key, Object[] array) throws MissingResourceException
{
String msg = null;
if (resourceProperties != null) {
msg = resourceProperties.getProperty(key);
}
if (msg == null) {
throw new MissingResourceException("Can't find resource key \"" + key +
"\" in base name " + basePropertyFileName,
basePropertyFileName, key);
}
msg = MessageFormat.format(msg, array);
return msg;
}
protected void loadProperties(String basename, ClassLoader loader, Locale locale,
Locale defaultLocale)
throws MissingResourceException
{
// Check the cache first
String loaderName = "";
if (loader != null) {
loaderName = ":" + loader.hashCode();
}
String cacheKey = basename + ":" + locale + ":" + defaultLocale + loaderName;
Properties p = (Properties) propertyCache.get(cacheKey);
basePropertyFileName = basename + PROPERTY_EXT;
if (p == null) {
// The properties were not found in the cache. Search the given locale
// first
if (locale != null) {
p = loadProperties(basename, loader, locale, p);
}
// Search the default locale
if (defaultLocale != null) {
p = loadProperties(basename, loader, defaultLocale, p);
}
// Search for the basename
p = merge(p, loadProperties(basePropertyFileName, loader));
if (p == null) {
throw new MissingResourceException("Can't find resource for base name " +
basePropertyFileName, basePropertyFileName, "");
}
// Cache the properties
propertyCache.put(cacheKey, p);
}
resourceProperties = p;
}
protected Properties loadProperties(String basename, ClassLoader loader, Locale locale,
Properties props)
{
String language = locale.getLanguage();
String country = locale.getCountry();
String variant = locale.getVariant();
if (variant != null) {
if (variant.trim().length() == 0) {
variant = null;
}
}
if (language != null) {
if (country != null) {
if (variant != null) {
props = merge(props, loadProperties(basename + "_" + language +"_" + country + "_" + variant +
PROPERTY_EXT, loader));
}
props = merge(props, loadProperties(basename + "_" + language +"_" + country +
PROPERTY_EXT, loader));
}
props = merge(props, loadProperties(basename + "_" + language + PROPERTY_EXT, loader));
}
return props;
}
protected Properties loadProperties(String resname, ClassLoader loader)
{
Properties props = null;
// Attempt to open and load the properties
InputStream in = null;
try {
if (loader != null) {
in = loader.getResourceAsStream(resname);
}
// Either we're using the system class loader or we didn't find the
// resource using the given class loader
if (in == null) {
in = ClassLoader.getSystemResourceAsStream(resname);
}
if (in != null) {
props = new Properties();
try {
props.load(in);
}
catch (IOException ex) {
// On error, clear the props
props = null;
}
}
}
finally {
if (in != null) {
try {
in.close();
}
catch (Exception ex) {
// Ignore error on close
}
}
}
return props;
}
/**
* Merge two Properties objects
*/
protected Properties merge(Properties p1, Properties p2)
{
if ((p1 == null) &&
(p2 == null)) {
return null;
}
else if (p1 == null) {
return p2;
}
else if (p2 == null) {
return p1;
}
// Now merge. p1 takes precedence
Enumeration enum = p2.keys();
while (enum.hasMoreElements()) {
String key = (String) enum.nextElement();
if (p1.getProperty(key) == null) {
p1.put(key, p2.getProperty(key));
}
}
return p1;
}
/**
* Get the underlying properties
*/
public Properties getProperties()
{
return resourceProperties;
}
// STATIC ACCESSORS
/**
* Get a message from resource.properties from the package of the given object.
* @param caller The calling object, used to get the package name and class loader
* @param key The resource key
* @return The formatted message
*/
public static String getString(Object caller, String key)
throws MissingResourceException
{
return getMessage(caller, BASE_NAME, null, key, null);
}
/**
* Get a message from resource.properties from the package of the given object.
* @param caller The calling object, used to get the package name and class loader
* @param key The resource key
* @param arg0 The argument to place in variable {0}
* @return The formatted message
*/
public static String getString(Object caller, String key, Object arg0)
throws MissingResourceException
{
Object[] o = new Object[1];
o[0] = arg0;
return getMessage(caller, BASE_NAME, null, key, o);
}
/**
* Get a message from resource.properties from the package of the given object.
* @param caller The calling object, used to get the package name and class loader
* @param key The resource key
* @param arg0 The argument to place in variable {0}
* @param arg1 The argument to place in variable {1}
* @return The formatted message
*/
public static String getString(Object caller, String key, Object arg0, Object arg1)
throws MissingResourceException
{
Object[] o = new Object[2];
o[0] = arg0;
o[1] = arg1;
return getMessage(caller, BASE_NAME, null, key, o);
}
/**
* Get a message from resource.properties from the package of the given object.
* @param caller The calling object, used to get the package name and class loader
* @param key The resource key
* @param arg0 The argument to place in variable {0}
* @param arg1 The argument to place in variable {1}
* @param arg2 The argument to place in variable {2}
* @return The formatted message
*/
public static String getString(Object caller, String key, Object arg0, Object arg1, Object arg2)
throws MissingResourceException
{
Object[] o = new Object[3];
o[0] = arg0;
o[1] = arg1;
o[2] = arg2;
return getMessage(caller, BASE_NAME, null, key, o);
}
/**
* Get a message from resource.properties from the package of the given object.
* @param caller The calling object, used to get the package name and class loader
* @param key The resource key
* @param arg0 The argument to place in variable {0}
* @param arg1 The argument to place in variable {1}
* @param arg2 The argument to place in variable {2}
* @param arg3 The argument to place in variable {3}
* @return The formatted message
*/
public static String getString(Object caller, String key, Object arg0, Object arg1, Object arg2, Object arg3)
throws MissingResourceException
{
Object[] o = new Object[4];
o[0] = arg0;
o[1] = arg1;
o[2] = arg2;
o[3] = arg3;
return getMessage(caller, BASE_NAME, null, key, o);
}
/**
* Get a message from resource.properties from the package of the given object.
* @param caller The calling object, used to get the package name and class loader
* @param key The resource key
* @param arg0 The argument to place in variable {0}
* @param arg1 The argument to place in variable {1}
* @param arg2 The argument to place in variable {2}
* @param arg3 The argument to place in variable {3}
* @param arg4 The argument to place in variable {4}
* @return The formatted message
*/
public static String getString(Object caller, String key, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4)
throws MissingResourceException
{
Object[] o = new Object[5];
o[0] = arg0;
o[1] = arg1;
o[2] = arg2;
o[3] = arg3;
o[4] = arg4;
return getMessage(caller, BASE_NAME, null, key, o);
}
/**
* Get a message from resource.properties from the package of the given object.
* @param caller The calling object, used to get the package name and class loader
* @param key The resource key
* @param array An array of objects to place in corresponding variables
* @return The formatted message
*/
public static String getString(Object caller, String key, Object[] args)
throws MissingResourceException
{
return getMessage(caller, BASE_NAME, null, key, args);
}
/**
* Get a message from resource.properties from the package of the given object.
* @param caller The calling object, used to get the package name and class loader
* @param locale The locale
* @param key The resource key
* @return The formatted message
*/
public static String getString(Object caller, Locale locale, String key)
throws MissingResourceException
{
return getMessage(caller, BASE_NAME, locale, key, null);
}
/**
* Get a message from resource.properties from the package of the given object.
* @param caller The calling object, used to get the package name and class loader
* @param locale The locale
* @param key The resource key
* @param arg0 The argument to place in variable {0}
* @return The formatted message
*/
public static String getString(Object caller, Locale locale, String key, Object arg0)
throws MissingResourceException
{
Object[] o = new Object[1];
o[0] = arg0;
return getMessage(caller, BASE_NAME, locale, key, o);
}
/**
* Get a message from resource.properties from the package of the given object.
* @param caller The calling object, used to get the package name and class loader
* @param locale The locale
* @param key The resource key
* @param arg0 The argument to place in variable {0}
* @param arg1 The argument to place in variable {1}
* @return The formatted message
*/
public static String getString(Object caller, Locale locale, String key, Object arg0, Object arg1)
throws MissingResourceException
{
Object[] o = new Object[2];
o[0] = arg0;
o[1] = arg1;
return getMessage(caller, BASE_NAME, locale, key, o);
}
/**
* Get a message from resource.properties from the package of the given object.
* @param caller The calling object, used to get the package name and class loader
* @param locale The locale
* @param key The resource key
* @param arg0 The argument to place in variable {0}
* @param arg1 The argument to place in variable {1}
* @param arg2 The argument to place in variable {2}
* @return The formatted message
*/
public static String getString(Object caller, Locale locale, String key, Object arg0, Object arg1, Object arg2)
throws MissingResourceException
{
Object[] o = new Object[3];
o[0] = arg0;
o[1] = arg1;
o[2] = arg2;
return getMessage(caller, BASE_NAME, locale, key, o);
}
/**
* Get a message from resource.properties from the package of the given object.
* @param caller The calling object, used to get the package name and class loader
* @param locale The locale
* @param key The resource key
* @param arg0 The argument to place in variable {0}
* @param arg1 The argument to place in variable {1}
* @param arg2 The argument to place in variable {2}
* @param arg3 The argument to place in variable {3}
* @return The formatted message
*/
public static String getString(Object caller, Locale locale, String key, Object arg0, Object arg1, Object arg2, Object arg3)
throws MissingResourceException
{
Object[] o = new Object[4];
o[0] = arg0;
o[1] = arg1;
o[2] = arg2;
o[3] = arg3;
return getMessage(caller, BASE_NAME, locale, key, o);
}
/**
* Get a message from resource.properties from the package of the given object.
* @param caller The calling object, used to get the package name and class loader
* @param locale The locale
* @param key The resource key
* @param arg0 The argument to place in variable {0}
* @param arg1 The argument to place in variable {1}
* @param arg2 The argument to place in variable {2}
* @param arg3 The argument to place in variable {3}
* @return The formatted message
*/
public static String getString(Object caller, Locale locale, String key, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4)
throws MissingResourceException
{
Object[] o = new Object[5];
o[0] = arg0;
o[1] = arg1;
o[2] = arg2;
o[3] = arg3;
o[4] = arg4;
return getMessage(caller, BASE_NAME, locale, key, o);
}
/**
* Get a message from resource.properties from the package of the given object.
* @param caller The calling object, used to get the package name and class loader
* @param locale The locale
* @param key The resource key
* @param array An array of objects to place in corresponding variables
* @return The formatted message
*/
public static String getString(Object caller, Locale locale, String key, Object[] args)
throws MissingResourceException
{
return getMessage(caller, BASE_NAME, locale, key, args);
}
// Workhorse that does the resource loading and key lookup
public static String getMessage(Object caller, String basename, Locale locale, String key,
Object[] args)
throws MissingResourceException
{
String msg = null;
MissingResourceException firstEx = null;
String fullName = null;
Class curClass = null;
if (caller != null) {
if(caller instanceof Class)
curClass = (Class) caller;
else
curClass = caller.getClass();
}
while (msg == null) {
// Get the full name of the resource
if (curClass != null) {
// Create the full basename
String pkgName = curClass.getName();
int pos = pkgName.lastIndexOf(".");
if (pos > 0) {
fullName = pkgName.substring(0, pos + 1).replace('.', '/') + basename;
}
else {
fullName = basename;
}
}
else {
fullName = basename;
}
try {
RB rb = new RB(caller, fullName, locale);
msg = rb.getString(key, args);
}
catch (MissingResourceException ex) {
if (curClass == null) {
throw ex;
}
// Save the first exception
if (firstEx == null) {
firstEx = ex;
}
// Get the superclass
Class sc = curClass.getSuperclass();
if (sc == null) {
throw firstEx;
}
String cname = sc.getName();
if (cname.startsWith("java.") ||
cname.startsWith("javax.")) {
throw firstEx;
}
// Try the superclass package
curClass = sc;
}
}
return msg;
}
/**
* Clears the internal cache
*/
public static void clearCache()
{
propertyCache.clear();
}
}