| /* $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); |
| } |
| } |
| |
| } |
| |