blob: e85e27e8a2ffd657756ab84daa143cdc271e9191 [file] [log] [blame]
/* $Id: Messages.java 1001023 2011-12-12 18:41:28Z hozawa $ */
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.apache.manifoldcf.core.i18n;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.HashSet;
import java.util.Vector;
import java.util.Properties;
import java.io.InputStream;
import org.apache.manifoldcf.core.system.Logging;
import org.apache.manifoldcf.core.interfaces.ManifoldCFException;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.util.ExtProperties;
public class Messages
{
// Keep track of messages and bundles we've already complained about.
protected static Set<BundleKey> bundleSet = new HashSet<BundleKey>();
protected static Set<MessageKey> messageSet = new HashSet<MessageKey>();
protected static Set<ResourceKey> resourceSet = new HashSet<ResourceKey>();
/** Constructor - do no instantiate
*/
protected Messages()
{
}
/** Create and initialize a velocity engine instance, given a class.
*/
public static VelocityEngine createVelocityEngine(Class classInstance)
throws ManifoldCFException
{
VelocityEngine engine = new VelocityEngine();
Properties configuration = new Properties();
// This is the property that describes the id's of the resource loaders.
configuration.setProperty(VelocityEngine.RESOURCE_LOADER,"mcf");
// This is the property which describes the resource loader itself
// Used to be ".instance" and accept an instance. No longer allowed.
configuration.setProperty("mcf."+VelocityEngine.RESOURCE_LOADER+".class",MCFVelocityResourceLoader.class.getName() /*new MCFVelocityResourceLoader(classInstance)*/);
configuration.setProperty("mcf."+VelocityEngine.RESOURCE_LOADER+".classinstance",classInstance.getName());
engine.setProperties(configuration);
//engine.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
// "org.apache.velocity.runtime.log.Log4JLogChute" );
//engine.setProperty("runtime.log.logsystem.log4j.logger",
// "velocity");
//"runtime.log.instance"
return engine;
}
/** Read a resource as an input stream, given a class, path, locale, and resource key.
*/
public static InputStream getResourceAsStream(Class classInstance, String pathName,
Locale originalLocale, String resourceKey)
throws ManifoldCFException
{
Locale locale = originalLocale;
InputStream is = classInstance.getResourceAsStream(localizeResourceName(pathName,resourceKey,locale));
if (is == null)
{
complainMissingResource("No resource in path '"+pathName+"' named '"+resourceKey+"' found for locale '"+locale.toString()+"'",
new Exception("Resource not found"),pathName,locale,resourceKey);
locale = new Locale(locale.getLanguage());
is = classInstance.getResourceAsStream(localizeResourceName(pathName,resourceKey,locale));
if (is == null)
{
complainMissingResource("No resource in path '"+pathName+"' named '"+resourceKey+"' found for locale '"+locale.toString()+"'",
new Exception("Resource not found"),pathName,locale,resourceKey);
locale = Locale.US;
is = classInstance.getResourceAsStream(localizeResourceName(pathName,resourceKey,locale));
if (is == null)
{
complainMissingResource("No resource in path '"+pathName+"' named '"+resourceKey+"' found for locale '"+locale.toString()+"'",
new Exception("Resource not found"),pathName,locale,resourceKey);
locale = new Locale(locale.getLanguage());
is = classInstance.getResourceAsStream(localizeResourceName(pathName,resourceKey,locale));
if (is == null)
{
complainMissingResource("No resource in path '"+pathName+"' named '"+resourceKey+"' found for locale '"+locale.toString()+"'",
new Exception("Resource not found"),pathName,locale,resourceKey);
is = classInstance.getResourceAsStream(localizeResourceName(pathName,resourceKey,null));
if (is == null)
throw new ManifoldCFException("No matching language resource in path '"+pathName+"' named '"+resourceKey+"' found for locale '"+originalLocale.toString()+"'");
}
}
}
}
return is;
}
private static String localizeResourceName(String pathName, String resourceName, Locale locale)
{
// Path names temporarily disabled, since they don't work.
// MHL
if (locale == null)
return /*pathName + "." + */resourceName;
int dotIndex = resourceName.lastIndexOf(".");
if (dotIndex == -1)
return /*pathName + "." + */resourceName + "_" + locale.toString();
return /*pathName + "." + */resourceName.substring(0,dotIndex) + "_" + locale.toString() + resourceName.substring(dotIndex);
}
/** Obtain a resource bundle given a class, bundle name, and locale.
*@return null if the resource bundle could not be found.
*/
public static ResourceBundle getResourceBundle(Class clazz, String bundleName, Locale locale)
{
ResourceBundle resources;
ClassLoader classLoader = clazz.getClassLoader();
try
{
resources = ResourceBundle.getBundle(bundleName, locale, classLoader);
}
catch (MissingResourceException e)
{
complainMissingBundle("Missing resource bundle '" + bundleName + "' for locale '"+locale.toString()+"': "+e.getMessage()+"; trying "+locale.getLanguage(),
e,bundleName,locale);
// Try plain language next
locale = new Locale(locale.getLanguage());
try
{
resources = ResourceBundle.getBundle(bundleName, locale, classLoader);
}
catch (MissingResourceException e2)
{
// Use English if we don't have a bundle for the current locale
complainMissingBundle("Missing resource bundle '" + bundleName + "' for locale '"+locale.toString()+"': "+e2.getMessage()+"; trying en_US",
e2,bundleName,locale);
locale = Locale.US;
try
{
resources = ResourceBundle.getBundle(bundleName, locale, classLoader);
}
catch (MissingResourceException e3)
{
complainMissingBundle("No backup en_US bundle found! "+e3.getMessage(),e3,bundleName,locale);
locale = new Locale(locale.getLanguage());
try
{
resources = ResourceBundle.getBundle(bundleName, locale, classLoader);
}
catch (MissingResourceException e4)
{
complainMissingBundle("No backup en bundle found! "+e4.getMessage(),e4,bundleName,locale);
return null;
}
}
}
}
return resources;
}
/** Obtain a message given a resource bundle and message key.
*@return null if the message could not be found.
*/
public static String getMessage(Class clazz, String bundleName, Locale locale, String messageKey)
{
ResourceBundle resources = getResourceBundle(clazz,bundleName,locale);
if (resources == null)
return null;
return getMessage(resources,bundleName,locale,messageKey);
}
/** Obtain a message given a resource bundle and message key.
*@return null if the message could not be found.
*/
public static String getMessage(ResourceBundle resources, String bundleName, Locale locale, String messageKey)
{
String message;
try
{
return resources.getString(messageKey);
}
catch (MissingResourceException e)
{
complainMissingMessage("Missing resource '" + messageKey + "' in bundle '" + bundleName + "' for locale '"+locale.toString()+"'",
e,bundleName,locale,messageKey);
return null;
}
}
/** Obtain a string given a resource bundle and message key.
*/
public static String getString(ResourceBundle resourceBundle, String bundleName,
Locale locale, String messageKey)
{
return getString(resourceBundle, bundleName, locale, messageKey, null);
}
/** Obtain a string given a class, bundle, locale, message key, and arguments.
*/
public static String getString(Class clazz, String bundleName, Locale locale,
String messageKey, Object[] args)
{
String message = getMessage(clazz,bundleName,locale,messageKey);
if (message == null)
return messageKey;
// Format the message
String formatMessage;
if (args != null)
{
MessageFormat fm = new MessageFormat(message, Locale.ROOT);
fm.setLocale(locale);
formatMessage = fm.format(args);
}
else
{
formatMessage = message;
}
return formatMessage;
}
/** Obtain a string given a resource bundle, message key, and arguments.
*/
public static String getString(ResourceBundle resourceBundle, String bundleName,
Locale locale, String messageKey, Object[] args)
{
String message = getMessage(resourceBundle,bundleName,locale,messageKey);
if (message == null)
return messageKey;
// Format the message
String formatMessage;
if (args != null)
{
if (locale == null) {
locale = Locale.ROOT;
}
MessageFormat fm = new MessageFormat(message, locale);
formatMessage = fm.format(args);
}
else
{
formatMessage = message;
}
return formatMessage;
}
protected static void complainMissingBundle(String errorMessage, Throwable exception, String bundleName, Locale locale)
{
String localeName = locale.toString();
BundleKey bk = new BundleKey(bundleName,localeName);
synchronized (bundleSet)
{
if (bundleSet.contains(bk))
return;
bundleSet.add(bk);
}
logError(errorMessage,exception);
}
protected static void complainMissingMessage(String errorMessage, Throwable exception, String bundleName, Locale locale, String messageKey)
{
String localeName = locale.toString();
MessageKey bk = new MessageKey(bundleName,localeName,messageKey);
synchronized (messageSet)
{
if (messageSet.contains(bk))
return;
messageSet.add(bk);
}
logError(errorMessage,exception);
}
protected static void complainMissingResource(String errorMessage, Throwable exception, String pathName, Locale locale, String resourceKey)
{
String localeName = locale.toString();
ResourceKey bk = new ResourceKey(pathName,localeName,resourceKey);
synchronized (resourceSet)
{
if (resourceSet.contains(bk))
return;
resourceSet.add(bk);
}
logError(errorMessage,exception);
}
protected static void logError(String errorMessage, Throwable exception)
{
if (Logging.misc == null)
{
System.err.println(errorMessage);
exception.printStackTrace(System.err);
}
else
Logging.misc.error(errorMessage,exception);
}
/** Class to help keep track of the missing resource bundles we've already complained about,
* so we don't fill up the standard out log with repetitive stuff. */
protected static class BundleKey
{
protected String bundleName;
protected String localeName;
public BundleKey(String bundleName, String localeName)
{
this.bundleName = bundleName;
this.localeName = localeName;
}
public int hashCode()
{
return bundleName.hashCode() + localeName.hashCode();
}
public boolean equals(Object o)
{
if (!(o instanceof BundleKey))
return false;
BundleKey b = (BundleKey)o;
return b.bundleName.equals(bundleName) && b.localeName.equals(localeName);
}
}
/** Class to help keep track of the missing messages we've already complained about,
* so we don't fill up the standard out log with repetitive stuff. */
protected static class MessageKey
{
protected String bundleName;
protected String localeName;
protected String messageKey;
public MessageKey(String bundleName, String localeName, String messageKey)
{
this.bundleName = bundleName;
this.localeName = localeName;
this.messageKey = messageKey;
}
public int hashCode()
{
return bundleName.hashCode() + localeName.hashCode() + messageKey.hashCode();
}
public boolean equals(Object o)
{
if (!(o instanceof MessageKey))
return false;
MessageKey b = (MessageKey)o;
return b.bundleName.equals(bundleName) && b.localeName.equals(localeName) && b.messageKey.equals(messageKey);
}
}
/** Class to help keep track of the missing resources we've already complained about,
* so we don't fill up the standard out log with repetitive stuff. */
protected static class ResourceKey
{
protected String pathName;
protected String localeName;
protected String resourceKey;
public ResourceKey(String pathName, String localeName, String resourceKey)
{
this.pathName = pathName;
this.localeName = localeName;
this.resourceKey = resourceKey;
}
public int hashCode()
{
return pathName.hashCode() + localeName.hashCode() + resourceKey.hashCode();
}
public boolean equals(Object o)
{
if (!(o instanceof ResourceKey))
return false;
ResourceKey b = (ResourceKey)o;
return b.pathName.equals(pathName) && b.localeName.equals(localeName) && b.resourceKey.equals(resourceKey);
}
}
}