Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions xwork-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

<groupId>org.apache.struts.xwork</groupId>
<artifactId>xwork-core</artifactId>
<version>2.3.16.4-SNAPSHOT</version>
<packaging>jar</packaging>
<name>XWork: Core</name>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;


/**
Expand Down Expand Up @@ -87,15 +86,15 @@
*/
public class LocalizedTextUtil {

private static final List<String> DEFAULT_RESOURCE_BUNDLES = new CopyOnWriteArrayList<String>();
private static final ConcurrentMap<Integer, List<String>> classLoaderMap = new ConcurrentHashMap<Integer, List<String>>();
private static final Logger LOG = LoggerFactory.getLogger(LocalizedTextUtil.class);
private static boolean reloadBundles = false;
private static final ResourceBundle EMPTY_BUNDLE = new EmptyResourceBundle();
private static final ConcurrentMap<String, ResourceBundle> bundlesMap = new ConcurrentHashMap<String, ResourceBundle>();
private static final ConcurrentMap<MessageFormatKey, MessageFormat> messageFormats = new ConcurrentHashMap<MessageFormatKey, MessageFormat>();
private static final ConcurrentMap<Integer, ClassLoader> delegatedClassLoaderMap = new ConcurrentHashMap<Integer, ClassLoader>();

private static ClassLoader delegatedClassLoader;
private static final String RELOADED = "com.opensymphony.xwork2.util.LocalizedTextUtil.reloaded";
private static final String XWORK_MESSAGES_BUNDLE = "com/opensymphony/xwork2/xwork-messages";

static {
clearDefaultResourceBundles();
Expand All @@ -106,16 +105,10 @@ public class LocalizedTextUtil {
* Clears the internal list of resource bundles.
*/
public static void clearDefaultResourceBundles() {
if (DEFAULT_RESOURCE_BUNDLES != null) {
synchronized (DEFAULT_RESOURCE_BUNDLES) {
DEFAULT_RESOURCE_BUNDLES.clear();
DEFAULT_RESOURCE_BUNDLES.add("com/opensymphony/xwork2/xwork-messages");
}
} else {
synchronized (DEFAULT_RESOURCE_BUNDLES) {
DEFAULT_RESOURCE_BUNDLES.add("com/opensymphony/xwork2/xwork-messages");
}
}
ClassLoader ccl = getThreadCurrentThreadGetContextClassLoader();
List<String> bundles = new ArrayList<String>();
classLoaderMap.put(ccl.hashCode(), bundles);
bundles.add(0, XWORK_MESSAGES_BUNDLE);
}

/**
Expand All @@ -136,13 +129,21 @@ public static void setReloadBundles(boolean reloadBundles) {
*/
public static void addDefaultResourceBundle(String resourceBundleName) {
//make sure this doesn't get added more than once
synchronized (DEFAULT_RESOURCE_BUNDLES) {
DEFAULT_RESOURCE_BUNDLES.remove(resourceBundleName);
DEFAULT_RESOURCE_BUNDLES.add(0, resourceBundleName);
ClassLoader ccl = null;
synchronized (classLoaderMap) {
ccl = getThreadCurrentThreadGetContextClassLoader();
List<String> bundles = classLoaderMap.get(ccl.hashCode());
if (bundles == null) {
bundles = new ArrayList<String>();
classLoaderMap.put(ccl.hashCode(), bundles);
bundles.add(XWORK_MESSAGES_BUNDLE);
}
bundles.remove(resourceBundleName);
bundles.add(0, resourceBundleName);
}

if (LOG.isDebugEnabled()) {
LOG.debug("Added default resource bundle '" + resourceBundleName + "' to default resource bundles = " + DEFAULT_RESOURCE_BUNDLES);
LOG.debug("Added default resource bundle '" + resourceBundleName + "' to default resource bundles for the following classloader " + ccl.toString());
}
}

Expand Down Expand Up @@ -197,7 +198,7 @@ public static Locale localeFromString(String localeStr, Locale defaultLocale) {
* @return a localized message based on the specified key, or null if no localized message can be found for it
*/
public static String findDefaultText(String aTextName, Locale locale) {
List<String> localList = DEFAULT_RESOURCE_BUNDLES;
List<String> localList = classLoaderMap.get(getThreadCurrentThreadGetContextClassLoader().hashCode());

for (String bundleName : localList) {
ResourceBundle bundle = findResourceBundle(bundleName, locale);
Expand Down Expand Up @@ -236,8 +237,6 @@ public static String findDefaultText(String aTextName, Locale locale, Object[] p
* Finds the given resorce bundle by it's name.
* <p/>
* Will use <code>Thread.currentThread().getContextClassLoader()</code> as the classloader.
* If {@link #delegatedClassLoader} is defined and the bundle cannot be found the current
* classloader it will delegate to that.
*
* @param aBundleName the name of the bundle (usually it's FQN classname).
* @param locale the locale.
Expand All @@ -246,35 +245,32 @@ public static String findDefaultText(String aTextName, Locale locale, Object[] p
public static ResourceBundle findResourceBundle(String aBundleName, Locale locale) {
String key = createMissesKey(aBundleName, locale);

ResourceBundle bundle;
ResourceBundle bundle = null;

ClassLoader classLoader = getThreadCurrentThreadGetContextClassLoader();
try {
key = classLoader.hashCode()+key;

if (!bundlesMap.containsKey(key)) {
bundle = ResourceBundle.getBundle(aBundleName, locale, Thread.currentThread().getContextClassLoader());
bundle = ResourceBundle.getBundle(aBundleName, locale, classLoader);
bundlesMap.putIfAbsent(key, bundle);
} else {
bundle = bundlesMap.get(key);
}

bundle = bundlesMap.get(key);
} catch (MissingResourceException ex) {
if (delegatedClassLoader != null) {
if (delegatedClassLoaderMap.containsKey(classLoader.hashCode())) {
try {
if (!bundlesMap.containsKey(key)) {
bundle = ResourceBundle.getBundle(aBundleName, locale, delegatedClassLoader);
bundle = ResourceBundle.getBundle(aBundleName, locale, delegatedClassLoaderMap.get(classLoader.hashCode()));
bundlesMap.putIfAbsent(key, bundle);
} else {
bundle = bundlesMap.get(key);
}

bundle = bundlesMap.get(key);

} catch (MissingResourceException e) {
bundle = EMPTY_BUNDLE;
bundlesMap.putIfAbsent(key, bundle);
}
} else {
bundle = EMPTY_BUNDLE;
bundlesMap.putIfAbsent(key, bundle);
}
}
return (bundle == EMPTY_BUNDLE) ? null : bundle;
return bundle;
}

/**
Expand All @@ -284,7 +280,7 @@ public static ResourceBundle findResourceBundle(String aBundleName, Locale local
*/
public static void setDelegatedClassLoader(final ClassLoader classLoader) {
synchronized (bundlesMap) {
delegatedClassLoader = classLoader;
delegatedClassLoaderMap.put(getThreadCurrentThreadGetContextClassLoader().hashCode(), classLoader);
}
}

Expand All @@ -294,7 +290,7 @@ public static void setDelegatedClassLoader(final ClassLoader classLoader) {
* @param bundleName
*/
public static void clearBundle(final String bundleName) {
bundlesMap.remove(bundleName);
bundlesMap.remove(getThreadCurrentThreadGetContextClassLoader().hashCode() + bundleName);
}


Expand Down Expand Up @@ -816,7 +812,7 @@ private static void reloadBundles(Map<String, Object> context) {


private static void clearTomcatCache() {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
ClassLoader loader = getThreadCurrentThreadGetContextClassLoader();
// no need for compilation here.
Class cl = loader.getClass();

Expand Down Expand Up @@ -893,6 +889,10 @@ public int hashCode() {
}
}

private static ClassLoader getThreadCurrentThreadGetContextClassLoader() {
return Thread.currentThread().getContextClassLoader();
}

static class GetDefaultMessageReturnArg {
String message;
boolean foundInBundle;
Expand Down