blob: 074a7223cca15686fb1549b1b37e349fe4691c60 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package org.apache.roller.weblogger.util;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A utility class for handling i18n messaging.
*/
public final class I18nMessages {
private static final Log LOG = LogFactory.getLog(I18nMessages.class);
// locale and bundle we are using for messaging
private final Locale locale;
private final ResourceBundle bundle;
// a map of cached messages instances, keyed by locale
private static Map<Locale, I18nMessages> messagesMap =
Collections.synchronizedMap(new HashMap());
private I18nMessages(String locale) {
Locale loc = I18nUtils.toLocale(locale);
this.locale = loc;
this.bundle = ResourceBundle.getBundle("ApplicationResources", loc);
}
private I18nMessages(Locale locale) {
this.locale = locale;
this.bundle = ResourceBundle.getBundle("ApplicationResources", locale);
}
/**
* Get an instance for a given locale.
*/
public static I18nMessages getMessages(String locale) {
LOG.debug("request for messages in locale = " + locale);
// check if we already have a message utils created for that locale
I18nMessages messages = messagesMap.get(I18nUtils.toLocale(locale));
// if no utils for that language yet then construct
if(messages == null) {
messages = new I18nMessages(locale);
// keep a reference to it
messagesMap.put(messages.getLocale(), messages);
}
return messages;
}
/**
* Get an instance for a given locale.
*/
public static I18nMessages getMessages(Locale locale) {
LOG.debug("request for messages in locale = " + locale.toString());
// check if we already have a message utils created for that locale
I18nMessages messages = messagesMap.get(locale);
// if no utils for that language yet then construct
if(messages == null) {
messages = new I18nMessages(locale);
// keep a reference to it
messagesMap.put(messages.getLocale(), messages);
}
return messages;
}
/**
* The locale representing this message utils.
*/
public Locale getLocale() {
return this.locale;
}
/**
* Get a message from the bundle.
*/
public String getString(String key) {
try {
return bundle.getString(key);
} catch (Exception e) {
// send a warning in the logs
LOG.warn("Error getting key " + key);
return key;
}
}
/**
* Get a message from the bundle and substitute the given args into
* the message contents.
*/
public String getString(String key, List args) {
try {
String msg = bundle.getString(key);
return MessageFormat.format(msg, args.toArray());
} catch (Exception e) {
// send a warning in the logs
LOG.warn("Error getting key " + key, e);
return key;
}
}
/**
* Get a message from the bundle and substitute the given args into
* the message contents.
*/
public String getString(String key, Object[] args) {
try {
String msg = bundle.getString(key);
return MessageFormat.format(msg, args);
} catch (Exception e) {
// send a warning in the logs
LOG.warn("Error getting key " + key, e);
return key;
}
}
/**
* Reload bundle.
*
* @param key
* the key
*/
public static void reloadBundle(Locale key) {
try {
Class type = ResourceBundle.class;
Field cacheList = type.getDeclaredField("cacheList");
synchronized (cacheList) {
cacheList.setAccessible(true);
((Map) cacheList.get(ResourceBundle.class)).clear();
}
clearTomcatCache();
// Remove cached bundle
messagesMap.remove(key);
} catch (Exception e) {
LOG.error("Error clearing message resource bundles", e);
}
}
/**
* Clear tomcat cache.
*
* @see com.opensymphony.xwork2.util.LocalizedTextUtil
*/
private static void clearTomcatCache() {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
// no need for compilation here.
Class cl = loader.getClass();
try {
if ("org.apache.catalina.loader.WebappClassLoader".equals(cl
.getName())) {
clearMap(cl, loader, "resourceEntries");
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("class loader " + cl.getName()
+ " is not tomcat loader.");
}
}
} catch (Exception e) {
LOG.warn("couldn't clear tomcat cache", e);
}
}
private static void clearMap(Class cl, Object obj, String name)
throws NoSuchFieldException, IllegalAccessException,
NoSuchMethodException, InvocationTargetException {
Field field = cl.getDeclaredField(name);
field.setAccessible(true);
Object cache = field.get(obj);
synchronized (cache) {
Class ccl = cache.getClass();
Method clearMethod = ccl.getMethod("clear");
clearMethod.invoke(cache);
}
}
}