/*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the "License"). You may not use this file except
* in compliance with the License.
*
* You can obtain a copy of the license at
* glassfish/bootstrap/legal/CDDLv1.0.txt or
* https://glassfish.dev.java.net/public/CDDLv1.0.html.
* See the License for the specific language governing
* permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* HEADER in each file and include the License file at
* glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
* add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your
* own identifying information: Portions Copyright [yyyy]
* [name of copyright owner]
*/
/*
* Copyright 2005 The Apache Software Foundation.
*
* Licensed 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.
*/
import java.util.*;
import java.text.MessageFormat;
import java.security.AccessController;
import java.security.PrivilegedAction;
/** Helper class for constructing messages from bundles. The intended usage
* of this class is to construct a new instance bound to a bundle, as in
*
* I18NHelper msg = I18NHelper.getInstance("com.sun.org.apache.jdo.util.jdo.Bundle");
*
* This call uses the class loader that loaded the I18NHelper class to find
* the specified Bundle. The class provides two overloaded getInstance
* methods allowing to specify a different class loader:
* {@link #getInstance(Class cls)} looks for a bundle
* called "Bundle.properties" located in the package of the specified class
* object and {@link #getInstance(String bundleName,ClassLoader loader)}
* uses the specified class loader to find the bundle.
*
* Subsequently, instance methods can be used to format message strings
* using the text from the bundle, as in
*
* throw new JDOFatalInternalException (msg.msg("ERR_NoMetadata", cls.getName()));
* @since 1.0.1
* @version 1.1
*/
public class I18NHelper {
/** Bundles that have already been loaded
*/
private static Hashtable bundles = new Hashtable();
/** Helper instances that have already been created
*/
private static Hashtable helpers = new Hashtable();
/** The default locale for this VM.
*/
private static Locale locale = Locale.getDefault();
/** The name of the bundle used by this instance of the helper.
*/
private final String bundleName;
/** The bundle used by this instance of the helper.
*/
private ResourceBundle bundle = null;
/** Throwable if ResourceBundle couldn't be loaded
*/
private Throwable failure = null;
/** The unqualified standard name of a bundle. */
private static final String bundleSuffix = ".Bundle"; // NOI18N
/** Constructor */
private I18NHelper() {
this.bundleName = null;
}
/** Constructor for an instance bound to a bundle.
* @param bundleName the name of the resource bundle
* @param loader the class loader from which to load the resource
* bundle
*/
private I18NHelper (String bundleName, ClassLoader loader) {
this.bundleName = bundleName;
try {
bundle = loadBundle (bundleName, loader);
}
catch (Throwable e) {
failure = e;
}
}
/** An instance bound to a bundle. This method uses the current class
* loader to find the bundle.
* @param bundleName the name of the bundle
* @return the helper instance bound to the bundle
*/
public static I18NHelper getInstance (String bundleName) {
return getInstance (bundleName, I18NHelper.class.getClassLoader());
}
/** An instance bound to a bundle. This method figures out the bundle name
* for the class object's package and uses the class' class loader to
* find the bundle. Note, the specified class object must not be
* null
.
* @param cls the class object from which to load the resource bundle
* @return the helper instance bound to the bundle
*/
public static I18NHelper getInstance (final Class cls) {
ClassLoader classLoader = (ClassLoader) AccessController.doPrivileged (
new PrivilegedAction () {
public Object run () {
return cls.getClassLoader();
}
}
);
String bundle = getPackageName (cls.getName()) + bundleSuffix;
return getInstance (bundle, classLoader);
}
/** An instance bound to a bundle. This method uses the specified class
* loader to find the bundle. Note, the specified class loader must not
* be null
.
* @param bundleName the name of the bundle
* @param loader the class loader from which to load the resource
* bundle
* @return the helper instance bound to the bundle
*/
public static I18NHelper getInstance (String bundleName,
ClassLoader loader) {
I18NHelper helper = (I18NHelper) helpers.get (bundleName);
if (helper != null) {
return helper;
}
helper = new I18NHelper(bundleName, loader);
helpers.put (bundleName, helper);
// if two threads simultaneously create the same helper, return the first
// one to be put into the Hashtable. The other will be garbage collected.
return (I18NHelper) helpers.get (bundleName);
}
/** Message formatter
* @param messageKey the message key
* @return the resolved message text
*/
public String msg (String messageKey) {
assertBundle (messageKey);
return getMessage (bundle, messageKey);
}
/** Message formatter
* @param messageKey the message key
* @param arg1 the first argument
* @return the resolved message text
*/
public String msg (String messageKey, Object arg1) {
assertBundle (messageKey);
return getMessage (bundle, messageKey, arg1);
}
/** Message formatter
* @param messageKey the message key
* @param arg1 the first argument
* @param arg2 the second argument
* @return the resolved message text
*/
public String msg (String messageKey, Object arg1, Object arg2) {
assertBundle (messageKey);
return getMessage (bundle, messageKey, arg1, arg2);
}
/** Message formatter
* @param messageKey the message key
* @param arg1 the first argument
* @param arg2 the second argument
* @param arg3 the third argument
* @return the resolved message text
*/
public String msg (String messageKey, Object arg1, Object arg2, Object arg3) {
assertBundle (messageKey);
return getMessage (bundle, messageKey, arg1, arg2, arg3);
}
/** Message formatter
* @param messageKey the message key
* @param args the array of arguments
* @return the resolved message text
*/
public String msg (String messageKey, Object[] args) {
assertBundle (messageKey);
return getMessage (bundle, messageKey, args);
}
/** Message formatter
* @param messageKey the message key
* @param arg the argument
* @return the resolved message text
*/
public String msg (String messageKey, int arg) {
assertBundle (messageKey);
return getMessage(bundle, messageKey, arg);
}
/** Message formatter
* @param messageKey the message key
* @param arg the argument
* @return the resolved message text
*/
public String msg (String messageKey, boolean arg) {
assertBundle (messageKey);
return getMessage(bundle, messageKey, arg);
}
/** Returns the resource bundle used by this I18NHelper.
* @return the associated resource bundle
* @since 1.1
*/
public ResourceBundle getResourceBundle () {
assertBundle ();
return bundle;
}
// Internal helper methods
/**
* Load ResourceBundle by bundle name
* @param bundleName the name of the bundle
* @param loader the class loader from which to load the resource bundle
* @return the ResourceBundle
*/
final private static ResourceBundle loadBundle(
String bundleName, ClassLoader loader) {
ResourceBundle messages = (ResourceBundle)bundles.get(bundleName);
if (messages == null) //not found as loaded - add
{
messages = ResourceBundle.getBundle(bundleName, locale, loader);
bundles.put(bundleName, messages);
}
return messages;
}
/** Assert resources available
* @since 1.1
* @throws RuntimeException if the resource bundle could not
* be loaded during construction.
*/
private void assertBundle () {
if (failure != null)
throw new RuntimeException (
"No resources could be found for bundle:\"" + //NOI18N
bundle + "\" " + failure); //NOI18N
}
/** Assert resources available
* @param key the message key
* @since 1.0.2
* @throws RuntimeException if the resource bundle could not
* be loaded during construction.
*/
private void assertBundle (String key) {
if (failure != null)
throw new RuntimeException (
"No resources could be found to annotate error message key:\"" + //NOI18N
key + "\" " + failure); //NOI18N
}
/**
* Returns message as String
* @param messages the resource bundle
* @param messageKey the message key
* @return the resolved message text
*/
final private static String getMessage(ResourceBundle messages, String messageKey)
{
return messages.getString(messageKey);
}
/**
* Formats message by adding array of arguments
* @param messages the resource bundle
* @param messageKey the message key
* @param msgArgs an array of arguments to substitute into the message
* @return the resolved message text
*/
final private static String getMessage(ResourceBundle messages, String messageKey, Object msgArgs[])
{
for (int i=0; i if (msgArgs[i] == null) msgArgs[i] = ""; // NOI18N
}
MessageFormat formatter = new MessageFormat(messages.getString(messageKey));
return formatter.format(msgArgs);
}
/**
* Formats message by adding an Object
argument.
* @param messages the resource bundle
* @param messageKey the message key
* @param arg the argument
* @return the resolved message text
*/
final private static String getMessage(ResourceBundle messages, String messageKey, Object arg)
{
Object []args = {arg};
return getMessage(messages, messageKey, args);
}
/**
* Formats message by adding two Object
arguments.
* @param messages the resource bundle
* @param messageKey the message key
* @param arg1 the first argument
* @param arg2 the second argument
* @return the resolved message text
*/
final private static String getMessage(ResourceBundle messages, String messageKey, Object arg1,
Object arg2)
{
Object []args = {arg1, arg2};
return getMessage(messages, messageKey, args);
}
/**
* Formats message by adding three Object
arguments.
* @param messages the resource bundle
* @param messageKey the message key
* @param arg1 the first argument
* @param arg2 the second argument
* @param arg3 the third argument
* @return the resolved message text
*/
final private static String getMessage(ResourceBundle messages, String messageKey, Object arg1,
Object arg2, Object arg3)
{
Object []args = {arg1, arg2, arg3};
return getMessage(messages, messageKey, args);
}
/**
* Formats message by adding an int
as an argument.
* @param messages the resource bundle
* @param messageKey the message key
* @param arg the argument
* @return the resolved message text
*/
final private static String getMessage(ResourceBundle messages, String messageKey, int arg)
{
Object []args = {new Integer(arg)};
return getMessage(messages, messageKey, args);
}
/**
* Formats message by adding a boolean
as an argument.
* @param messages the resource bundle
* @param messageKey the message key
* @param arg the argument
* @return the resolved message text
*/
final private static String getMessage(ResourceBundle messages, String messageKey, boolean arg)
{
Object []args = {String.valueOf(arg)};
return getMessage(messages, messageKey, args);
}
/**
* Returns the package portion of the specified class.
* @param className the name of the class from which to extract the
* package
* @return package portion of the specified class
*/
final private static String getPackageName(final String className)
{
final int index = className.lastIndexOf('.');
return ((index != -1) ? className.substring(0, index) : ""); // NOI18N
}
}