/*
* Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.visage.runtime.util;
import java.util.Collections;
import java.util.Map;
import java.util.Locale;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import org.visage.runtime.util.backport.ResourceBundle;
public class StringLocalization {
private static final Map<ThreadGroup, Map<String, String>> map =
Collections.synchronizedMap(
new WeakHashMap<ThreadGroup, Map<String, String>>());
public static String getLocalizedString(String scriptName, String explicitKey,
String literal, Object... embeddedExpr) {
String key = scriptName.replaceAll("/", "\\.");
int lastDot = key.lastIndexOf('.');
if (lastDot != -1) {
key = key.substring(0, lastDot) + "/" + key.substring(lastDot + 1);
} else {
key = "/" + key;
}
return getLocalizedString(
getPropertiesName(key), explicitKey, literal, Locale.getDefault(), embeddedExpr);
}
public static String getLocalizedString(String propertiesName, String explicitKey,
String literal, Locale locale, Object... embeddedExpr) {
String localization = literal;
ClassLoader cl = getCallerLoader();
if (cl == null) {
return literal;
}
ResourceBundle rb = ResourceBundle.getBundle(propertiesName,
locale, cl, VisagePropertyResourceBundle.VisagePropertiesControl.INSTANCE);
if (explicitKey != null) {
localization = rb.getString(explicitKey);
if (explicitKey.equals(localization) &&
!rb.keySet().contains(explicitKey)) {
localization = literal;
}
} else {
localization = rb.getString(literal.replaceAll("\r\n|\r|\n", "\n"));
}
if (embeddedExpr.length != 0) {
localization = VisageFormatter.sprintf(locale, localization, embeddedExpr);
}
return localization;
}
public static void associate(String source, String properties) {
getAssociation().put(source, properties);
}
public static void dissociate(String source) {
Map<String, String> assoc = getAssociation();
// remove itself first
assoc.remove(source);
// remove all associationis for source files in that package
if (source.indexOf('/') == -1) {
String toRemove = source + "/";
for (String key : assoc.keySet()) {
if (key.startsWith(toRemove)) {
assoc.remove(key);
}
}
}
}
/**
* Get the properties file name for the given key, which consists of
* 'packageName(/scriptFileName)'. E.g., 'Example.visage' in 'foo.bar' package would have
* a key as 'foo.bar/Example', while 'foo.bar' can represent the package itself.
* A script file in the unnamed package can be denoted as '/Example'.
*/
public static String getPropertiesName(String key) {
String propertiesName = key.replaceAll("^/", "").replaceAll("/", ".");
Map<String, String> assoc = getAssociation();
Pattern chopoff = Pattern.compile("[\\./][^\\./]*\\z");
while (true) {
if (assoc.containsKey(key)) {
propertiesName = assoc.get(key);
break;
} else {
if ("".equals(key)) {
break;
} else if (chopoff.matcher(key).find()) {
key = chopoff.matcher(key).replaceAll("");
} else {
key = "";
}
}
}
return propertiesName;
}
private static Map<String, String> getAssociation() {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
Map<String, String> assoc = map.get(tg);
if (assoc == null) {
assoc = new ConcurrentHashMap<String, String>();
map.put(tg, assoc);
}
return assoc;
}
private static ClassContext classContext = null;
private static final String PKGNAME = StringLocalization.class.getPackage().getName();
static {
try {
classContext = (ClassContext)AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Object run() {
return new ClassContext();
}
});
} catch (PrivilegedActionException pae) {
// classContext should remain null.
}
}
private static ClassLoader getCallerLoader() {
if (classContext != null) {
Class[] callers = classContext.getClassContext();
for (Class c : callers) {
if (!c.getName().startsWith(PKGNAME)) {
ClassLoader cl = c.getClassLoader();
if (cl == null) {
// bootstrap class loader. use the system class loader instead
return ClassLoader.getSystemClassLoader();
} else {
return cl;
}
}
}
}
return null;
}
}