You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2017/05/18 08:09:47 UTC

[05/10] struts git commit: WW-4762 Extracts base abstract class

WW-4762 Extracts base abstract class


Project: http://git-wip-us.apache.org/repos/asf/struts/repo
Commit: http://git-wip-us.apache.org/repos/asf/struts/commit/2e23d7a0
Tree: http://git-wip-us.apache.org/repos/asf/struts/tree/2e23d7a0
Diff: http://git-wip-us.apache.org/repos/asf/struts/diff/2e23d7a0

Branch: refs/heads/master
Commit: 2e23d7a07ea4313136dc38b8de2451b04c882064
Parents: 8bf77a1
Author: Lukasz Lenart <lu...@apache.org>
Authored: Wed Apr 26 12:24:57 2017 +0200
Committer: Lukasz Lenart <lu...@apache.org>
Committed: Wed Apr 26 12:24:57 2017 +0200

----------------------------------------------------------------------
 .../util/AbstractLocalizedTextProvider.java     | 355 ++++++++++++++++++
 .../util/StrutsLocalizedTextProvider.java       | 368 +------------------
 2 files changed, 363 insertions(+), 360 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/struts/blob/2e23d7a0/core/src/main/java/com/opensymphony/xwork2/util/AbstractLocalizedTextProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/AbstractLocalizedTextProvider.java b/core/src/main/java/com/opensymphony/xwork2/util/AbstractLocalizedTextProvider.java
new file mode 100644
index 0000000..a2578bc
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/AbstractLocalizedTextProvider.java
@@ -0,0 +1,355 @@
+package com.opensymphony.xwork2.util;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.LocalizedTextProvider;
+import com.opensymphony.xwork2.inject.Inject;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.struts2.StrutsConstants;
+
+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.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+public abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
+
+    private static final Logger LOG = LogManager.getLogger(AbstractLocalizedTextProvider.class);
+
+    public static final String XWORK_MESSAGES_BUNDLE = "com/opensymphony/xwork2/xwork-messages";
+    public static final String STRUTS_MESSAGES_BUNDLE = "org/apache/struts2/struts-messages";
+
+    private static final String TOMCAT_RESOURCE_ENTRIES_FIELD = "resourceEntries";
+    private final String RELOADED = "com.opensymphony.xwork2.util.LocalizedTextProvider.reloaded";
+
+    protected final ConcurrentMap<String, ResourceBundle> bundlesMap = new ConcurrentHashMap<>();
+    protected boolean devMode = false;
+    protected boolean reloadBundles = false;
+
+    private final ConcurrentMap<MessageFormatKey, MessageFormat> messageFormats = new ConcurrentHashMap<>();
+    private final ConcurrentMap<Integer, List<String>> classLoaderMap = new ConcurrentHashMap<>();
+    private final Set<String> missingBundles = Collections.synchronizedSet(new HashSet<String>());
+    private final ConcurrentMap<Integer, ClassLoader> delegatedClassLoaderMap = new ConcurrentHashMap<>();
+
+    /**
+     * Add's the bundle to the internal list of default bundles.
+     * If the bundle already exists in the list it will be re-added.
+     *
+     * @param resourceBundleName the name of the bundle to add.
+     */
+    @Override
+    public void addDefaultResourceBundle(String resourceBundleName) {
+        //make sure this doesn't get added more than once
+        final ClassLoader ccl = getCurrentThreadContextClassLoader();
+        synchronized (XWORK_MESSAGES_BUNDLE) {
+            List<String> bundles = classLoaderMap.get(ccl.hashCode());
+            if (bundles == null) {
+                bundles = new CopyOnWriteArrayList<>();
+                classLoaderMap.put(ccl.hashCode(), bundles);
+            }
+            bundles.remove(resourceBundleName);
+            bundles.add(0, resourceBundleName);
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Added default resource bundle '{}' to default resource bundles for the following classloader '{}'", resourceBundleName, ccl.toString());
+        }
+    }
+
+    protected List<String> getCurrentBundleNames() {
+        return classLoaderMap.get(getCurrentThreadContextClassLoader().hashCode());
+    }
+
+    protected ClassLoader getCurrentThreadContextClassLoader() {
+        return Thread.currentThread().getContextClassLoader();
+    }
+
+    /**
+     * Returns a localized message for the specified key, aTextName.  Neither the key nor the
+     * message is evaluated.
+     *
+     * @param aTextName the message key
+     * @param locale    the locale the message should be for
+     * @return a localized message based on the specified key, or null if no localized message can be found for it
+     */
+    @Override
+    public String findDefaultText(String aTextName, Locale locale) {
+        List<String> localList = getCurrentBundleNames();
+
+        for (String bundleName : localList) {
+            ResourceBundle bundle = findResourceBundle(bundleName, locale);
+            if (bundle != null) {
+                reloadBundles();
+                try {
+                    return bundle.getString(aTextName);
+                } catch (MissingResourceException e) {
+                    // will be logged when not found in any bundle
+                }
+            }
+        }
+
+        if (devMode) {
+            LOG.warn("Missing key [{}] in bundles [{}]!", aTextName, localList);
+        } else {
+            LOG.debug("Missing key [{}] in bundles [{}]!", aTextName, localList);
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns a localized message for the specified key, aTextName, substituting variables from the
+     * array of params into the message.  Neither the key nor the message is evaluated.
+     *
+     * @param aTextName the message key
+     * @param locale    the locale the message should be for
+     * @param params    an array of objects to be substituted into the message text
+     * @return A formatted message based on the specified key, or null if no localized message can be found for it
+     */
+    @Override
+    public String findDefaultText(String aTextName, Locale locale, Object[] params) {
+        String defaultText = findDefaultText(aTextName, locale);
+        if (defaultText != null) {
+            MessageFormat mf = buildMessageFormat(defaultText, locale);
+            return formatWithNullDetection(mf, params);
+        }
+        return null;
+    }
+
+    /**
+     * @param classLoader a {@link ClassLoader} to look up the bundle from if none can be found on the current thread's classloader
+     */
+    public void setDelegatedClassLoader(final ClassLoader classLoader) {
+        synchronized (bundlesMap) {
+            delegatedClassLoaderMap.put(getCurrentThreadContextClassLoader().hashCode(), classLoader);
+        }
+    }
+
+    /**
+     * @param bundleName Removes the bundle from any cached "misses"
+     */
+    public void clearBundle(final String bundleName) {
+        bundlesMap.remove(getCurrentThreadContextClassLoader().hashCode() + bundleName);
+    }
+
+    protected void reloadBundles() {
+        reloadBundles(ActionContext.getContext() != null ? ActionContext.getContext().getContextMap() : null);
+    }
+
+    protected void reloadBundles(Map<String, Object> context) {
+        if (reloadBundles) {
+            try {
+                Boolean reloaded;
+                if (context != null) {
+                    reloaded = (Boolean) ObjectUtils.defaultIfNull(context.get(RELOADED), Boolean.FALSE);
+                } else {
+                    reloaded = Boolean.FALSE;
+                }
+                if (!reloaded) {
+                    bundlesMap.clear();
+                    try {
+                        clearMap(ResourceBundle.class, null, "cacheList");
+                    } catch (NoSuchFieldException e) {
+                        // happens in IBM JVM, that has a different ResourceBundle impl
+                        // it has a 'cache' member
+                        clearMap(ResourceBundle.class, null, "cache");
+                    }
+
+                    // now, for the true and utter hack, if we're running in tomcat, clear
+                    // it's class loader resource cache as well.
+                    clearTomcatCache();
+                    if (context != null) {
+                        context.put(RELOADED, true);
+                    }
+                    LOG.debug("Resource bundles reloaded");
+                }
+            } catch (Exception e) {
+                LOG.error("Could not reload resource bundles", e);
+            }
+        }
+    }
+
+    private void clearTomcatCache() {
+        ClassLoader loader = getCurrentThreadContextClassLoader();
+        // no need for compilation here.
+        Class cl = loader.getClass();
+
+        try {
+            if ("org.apache.catalina.loader.WebappClassLoader".equals(cl.getName())) {
+                clearMap(cl, loader, TOMCAT_RESOURCE_ENTRIES_FIELD);
+            } else {
+                LOG.debug("Class loader {} is not tomcat loader.", cl.getName());
+            }
+        } catch (NoSuchFieldException nsfe) {
+            if ("org.apache.catalina.loader.WebappClassLoaderBase".equals(cl.getSuperclass().getName())) {
+                LOG.debug("Base class {} doesn't contain '{}' field, trying with parent!", cl.getName(), TOMCAT_RESOURCE_ENTRIES_FIELD, nsfe);
+                try {
+                    clearMap(cl.getSuperclass(), loader, TOMCAT_RESOURCE_ENTRIES_FIELD);
+                } catch (Exception e) {
+                    LOG.warn("Couldn't clear tomcat cache using {}", cl.getSuperclass().getName(), e);
+                }
+            }
+        } catch (Exception e) {
+            LOG.warn("Couldn't clear tomcat cache", cl.getName(), e);
+        }
+    }
+
+    private 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);
+        }
+    }
+
+    protected MessageFormat buildMessageFormat(String pattern, Locale locale) {
+        MessageFormatKey key = new MessageFormatKey(pattern, locale);
+        MessageFormat format = messageFormats.get(key);
+        if (format == null) {
+            format = new MessageFormat(pattern);
+            format.setLocale(locale);
+            format.applyPattern(pattern);
+            messageFormats.put(key, format);
+        }
+
+        return format;
+    }
+
+    protected String formatWithNullDetection(MessageFormat mf, Object[] args) {
+        String message = mf.format(args);
+        if ("null".equals(message)) {
+            return null;
+        } else {
+            return message;
+        }
+    }
+
+    @Inject(value = StrutsConstants.STRUTS_I18N_RELOAD, required = false)
+    public void setReloadBundles(String reloadBundles) {
+        this.reloadBundles = Boolean.parseBoolean(reloadBundles);
+    }
+
+    @Inject(value = StrutsConstants.STRUTS_DEVMODE, required = false)
+    public void setDevMode(String devMode) {
+        this.devMode = Boolean.parseBoolean(devMode);
+    }
+
+    /**
+     * Finds the given resource bundle by it's name.
+     * <p>
+     * Will use <code>Thread.currentThread().getContextClassLoader()</code> as the classloader.
+     * </p>
+     *
+     * @param aBundleName the name of the bundle (usually it's FQN classname).
+     * @param locale      the locale.
+     * @return the bundle, <tt>null</tt> if not found.
+     */
+    @Override
+    public ResourceBundle findResourceBundle(String aBundleName, Locale locale) {
+        ClassLoader classLoader = getCurrentThreadContextClassLoader();
+        String key = createMissesKey(String.valueOf(classLoader.hashCode()), aBundleName, locale);
+
+        if (missingBundles.contains(key)) {
+            return null;
+        }
+
+        ResourceBundle bundle = null;
+        try {
+            if (bundlesMap.containsKey(key)) {
+                bundle = bundlesMap.get(key);
+            } else {
+                bundle = ResourceBundle.getBundle(aBundleName, locale, classLoader);
+                bundlesMap.putIfAbsent(key, bundle);
+            }
+        } catch (MissingResourceException ex) {
+            if (delegatedClassLoaderMap.containsKey(classLoader.hashCode())) {
+                try {
+                    if (bundlesMap.containsKey(key)) {
+                        bundle = bundlesMap.get(key);
+                    } else {
+                        bundle = ResourceBundle.getBundle(aBundleName, locale, delegatedClassLoaderMap.get(classLoader.hashCode()));
+                        bundlesMap.putIfAbsent(key, bundle);
+                    }
+                } catch (MissingResourceException e) {
+                    LOG.debug("Missing resource bundle [{}]!", aBundleName, e);
+                    missingBundles.add(key);
+                }
+            } else {
+                LOG.debug("Missing resource bundle [{}]!", aBundleName);
+                missingBundles.add(key);
+            }
+        }
+        return bundle;
+    }
+
+    /**
+     * Creates a key to used for lookup/storing in the bundle misses cache.
+     *
+     * @param prefix      the prefix for the returning String - it is supposed to be the ClassLoader hash code.
+     * @param aBundleName the name of the bundle (usually it's FQN classname).
+     * @param locale      the locale.
+     * @return the key to use for lookup/storing in the bundle misses cache.
+     */
+    private String createMissesKey(String prefix, String aBundleName, Locale locale) {
+        return prefix + aBundleName + "_" + locale.toString();
+    }
+
+    static class MessageFormatKey {
+        String pattern;
+        Locale locale;
+
+        MessageFormatKey(String pattern, Locale locale) {
+            this.pattern = pattern;
+            this.locale = locale;
+        }
+
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            MessageFormatKey that = (MessageFormatKey) o;
+
+            if (pattern != null ? !pattern.equals(that.pattern) : that.pattern != null) return false;
+            return locale != null ? locale.equals(that.locale) : that.locale == null;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = pattern != null ? pattern.hashCode() : 0;
+            result = 31 * result + (locale != null ? locale.hashCode() : 0);
+            return result;
+        }
+    }
+
+    static class GetDefaultMessageReturnArg {
+        String message;
+        boolean foundInBundle;
+
+        public GetDefaultMessageReturnArg(String message, boolean foundInBundle) {
+            this.message = message;
+            this.foundInBundle = foundInBundle;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/2e23d7a0/core/src/main/java/com/opensymphony/xwork2/util/StrutsLocalizedTextProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/StrutsLocalizedTextProvider.java b/core/src/main/java/com/opensymphony/xwork2/util/StrutsLocalizedTextProvider.java
index 78bf08d..3d03f9a 100644
--- a/core/src/main/java/com/opensymphony/xwork2/util/StrutsLocalizedTextProvider.java
+++ b/core/src/main/java/com/opensymphony/xwork2/util/StrutsLocalizedTextProvider.java
@@ -23,52 +23,32 @@ package com.opensymphony.xwork2.util;
 
 import com.opensymphony.xwork2.ActionContext;
 import com.opensymphony.xwork2.ActionInvocation;
-import com.opensymphony.xwork2.LocalizedTextProvider;
 import com.opensymphony.xwork2.ModelDriven;
 import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
 import com.opensymphony.xwork2.inject.Inject;
 import com.opensymphony.xwork2.util.reflection.ReflectionProviderFactory;
-import org.apache.commons.lang3.ObjectUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.message.ParameterizedMessage;
 import org.apache.struts2.StrutsConstants;
 
 import java.beans.PropertyDescriptor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.text.MessageFormat;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
 
 /**
  * Provides support for localization in the framework, it can be used to read only default bundles,
  * or it can search the class hierarchy to find proper bundles.
  */
-public class StrutsLocalizedTextProvider implements LocalizedTextProvider {
+public class StrutsLocalizedTextProvider extends AbstractLocalizedTextProvider {
 
     private static final Logger LOG = LogManager.getLogger(StrutsLocalizedTextProvider.class);
 
-    public static final String XWORK_MESSAGES_BUNDLE = "com/opensymphony/xwork2/xwork-messages";
-    public static final String STRUTS_MESSAGES_BUNDLE = "org/apache/struts2/struts-messages";
-
-    private static final String TOMCAT_RESOURCE_ENTRIES_FIELD = "resourceEntries";
-
-    private final ConcurrentMap<Integer, List<String>> classLoaderMap = new ConcurrentHashMap<>();
-
-    private boolean reloadBundles = false;
-    private boolean devMode = false;
-
-    private final ConcurrentMap<String, ResourceBundle> bundlesMap = new ConcurrentHashMap<>();
-    private final ConcurrentMap<MessageFormatKey, MessageFormat> messageFormats = new ConcurrentHashMap<>();
-    private final ConcurrentMap<Integer, ClassLoader> delegatedClassLoaderMap = new ConcurrentHashMap<>();
-    private final Set<String> missingBundles = Collections.synchronizedSet(new HashSet<String>());
-
-    private final String RELOADED = "com.opensymphony.xwork2.util.LocalizedTextUtil.reloaded";
-
     /**
      * Clears the internal list of resource bundles.
      *
@@ -80,26 +60,10 @@ public class StrutsLocalizedTextProvider implements LocalizedTextProvider {
     }
 
     public StrutsLocalizedTextProvider() {
-
         addDefaultResourceBundle(XWORK_MESSAGES_BUNDLE);
         addDefaultResourceBundle(STRUTS_MESSAGES_BUNDLE);
     }
 
-    /**
-     * Should resorce bundles be reloaded.
-     *
-     * @param reloadBundles reload bundles?
-     */
-    @Inject(value = StrutsConstants.STRUTS_I18N_RELOAD, required = false)
-    public void setReloadBundles(String reloadBundles) {
-        this.reloadBundles = Boolean.parseBoolean(reloadBundles);
-    }
-
-    @Inject(value = StrutsConstants.STRUTS_DEVMODE, required = false)
-    public void setDevMode(String devMode) {
-        this.devMode = Boolean.parseBoolean(devMode);
-    }
-
     @Inject(value = StrutsConstants.STRUTS_CUSTOM_I18N_RESOURCES, required = false)
     public void setCustomI18NResources(String bundles) {
         if (bundles != null && bundles.length() > 0) {
@@ -118,33 +82,6 @@ public class StrutsLocalizedTextProvider implements LocalizedTextProvider {
     }
 
     /**
-     * Add's the bundle to the internal list of default bundles.
-     * <p>
-     * If the bundle already exists in the list it will be readded.
-     * </p>
-     *
-     * @param resourceBundleName the name of the bundle to add.
-     */
-    @Override
-    public void addDefaultResourceBundle(String resourceBundleName) {
-        //make sure this doesn't get added more than once
-        final ClassLoader ccl = getCurrentThreadContextClassLoader();
-        synchronized (XWORK_MESSAGES_BUNDLE) {
-            List<String> bundles = classLoaderMap.get(ccl.hashCode());
-            if (bundles == null) {
-                bundles = new CopyOnWriteArrayList<>();
-                classLoaderMap.put(ccl.hashCode(), bundles);
-            }
-            bundles.remove(resourceBundleName);
-            bundles.add(0, resourceBundleName);
-        }
-
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("Added default resource bundle '{}' to default resource bundles for the following classloader '{}'", resourceBundleName, ccl.toString());
-        }
-    }
-
-    /**
      * Builds a {@link java.util.Locale} from a String of the form en_US_foo into a Locale
      * with language "en", country "US" and variant "foo". This will parse the output of
      * {@link java.util.Locale#toString()}.
@@ -190,135 +127,6 @@ public class StrutsLocalizedTextProvider implements LocalizedTextProvider {
     }
 
     /**
-     * Returns a localized message for the specified key, aTextName.  Neither the key nor the
-     * message is evaluated.
-     *
-     * @param aTextName the message key
-     * @param locale    the locale the message should be for
-     * @return a localized message based on the specified key, or null if no localized message can be found for it
-     */
-    @Override
-    public String findDefaultText(String aTextName, Locale locale) {
-        List<String> localList = classLoaderMap.get(Thread.currentThread().getContextClassLoader().hashCode());
-
-        for (String bundleName : localList) {
-            ResourceBundle bundle = findResourceBundle(bundleName, locale);
-            if (bundle != null) {
-                reloadBundles();
-                try {
-                    return bundle.getString(aTextName);
-                } catch (MissingResourceException e) {
-                	// will be logged when not found in any bundle
-                }
-            }
-        }
-
-        if (devMode) {
-            LOG.warn("Missing key [{}] in bundles [{}]!", aTextName, localList);
-        } else {
-            LOG.debug("Missing key [{}] in bundles [{}]!", aTextName, localList);
-        }
-
-        return null;
-    }
-
-    /**
-     * Returns a localized message for the specified key, aTextName, substituting variables from the
-     * array of params into the message.  Neither the key nor the message is evaluated.
-     *
-     * @param aTextName the message key
-     * @param locale    the locale the message should be for
-     * @param params    an array of objects to be substituted into the message text
-     * @return A formatted message based on the specified key, or null if no localized message can be found for it
-     */
-    @Override
-    public String findDefaultText(String aTextName, Locale locale, Object[] params) {
-        String defaultText = findDefaultText(aTextName, locale);
-        if (defaultText != null) {
-            MessageFormat mf = buildMessageFormat(defaultText, locale);
-            return formatWithNullDetection(mf, params);
-        }
-        return null;
-    }
-
-    /**
-     * Finds the given resource bundle by it's name.
-     * <p>
-     * Will use <code>Thread.currentThread().getContextClassLoader()</code> as the classloader.
-     * </p>
-     *
-     * @param aBundleName the name of the bundle (usually it's FQN classname).
-     * @param locale      the locale.
-     * @return the bundle, <tt>null</tt> if not found.
-     */
-    @Override
-    public ResourceBundle findResourceBundle(String aBundleName, Locale locale) {
-        ClassLoader classLoader = getCurrentThreadContextClassLoader();
-        String key = createMissesKey(String.valueOf(classLoader.hashCode()), aBundleName, locale);
-
-        if (missingBundles.contains(key)) {
-            return null;
-        }
-
-        ResourceBundle bundle = null;
-        try {
-            if (bundlesMap.containsKey(key)) {
-                bundle = bundlesMap.get(key);
-            } else {
-                bundle = ResourceBundle.getBundle(aBundleName, locale, classLoader);
-                bundlesMap.putIfAbsent(key, bundle);
-            }
-        } catch (MissingResourceException ex) {
-            if (delegatedClassLoaderMap.containsKey(classLoader.hashCode())) {
-                try {
-                    if (bundlesMap.containsKey(key)) {
-                        bundle = bundlesMap.get(key);
-                    } else {
-                        bundle = ResourceBundle.getBundle(aBundleName, locale, delegatedClassLoaderMap.get(classLoader.hashCode()));
-                        bundlesMap.putIfAbsent(key, bundle);
-                    }
-                } catch (MissingResourceException e) {
-                    LOG.debug("Missing resource bundle [{}]!", aBundleName, e);
-                    missingBundles.add(key);
-                }
-            } else {
-                LOG.debug("Missing resource bundle [{}]!", aBundleName);
-                missingBundles.add(key);
-            }
-        }
-        return bundle;
-    }
-
-    /**
-     * @param classLoader a {@link ClassLoader} to look up the bundle from if none can be found on the current thread's classloader
-     */
-    public void setDelegatedClassLoader(final ClassLoader classLoader) {
-        synchronized (bundlesMap) {
-            delegatedClassLoaderMap.put(getCurrentThreadContextClassLoader().hashCode(), classLoader);
-        }
-    }
-
-    /**
-     * @param bundleName Removes the bundle from any cached "misses"
-     */
-    public void clearBundle(final String bundleName) {
-        bundlesMap.remove(getCurrentThreadContextClassLoader().hashCode() + bundleName);
-    }
-
-
-    /**
-     * Creates a key to used for lookup/storing in the bundle misses cache.
-     *
-     * @param prefix      the prefix for the returning String - it is supposed to be the ClassLoader hash code.
-     * @param aBundleName the name of the bundle (usually it's FQN classname).
-     * @param locale      the locale.
-     * @return the key to use for lookup/storing in the bundle misses cache.
-     */
-    private String createMissesKey(String prefix, String aBundleName, Locale locale) {
-        return prefix + aBundleName + "_" + locale.toString();
-    }
-
-    /**
      * Calls {@link #findText(Class aClass, String aTextName, Locale locale, String defaultMessage, Object[] args)}
      * with aTextName as the default message.
      *
@@ -759,28 +567,6 @@ public class StrutsLocalizedTextProvider implements LocalizedTextProvider {
         }
     }
 
-    private String formatWithNullDetection(MessageFormat mf, Object[] args) {
-        String message = mf.format(args);
-        if ("null".equals(message)) {
-            return null;
-        } else {
-            return message;
-        }
-    }
-
-    private MessageFormat buildMessageFormat(String pattern, Locale locale) {
-        MessageFormatKey key = new MessageFormatKey(pattern, locale);
-        MessageFormat format = messageFormats.get(key);
-        if (format == null) {
-            format = new MessageFormat(pattern);
-            format.setLocale(locale);
-            format.applyPattern(pattern);
-            messageFormats.put(key, format);
-        }
-
-        return format;
-    }
-
     /**
      * Traverse up class hierarchy looking for message.  Looks at class, then implemented interface,
      * before going up hierarchy.
@@ -790,7 +576,7 @@ public class StrutsLocalizedTextProvider implements LocalizedTextProvider {
     private String findMessage(Class clazz, String key, String indexedKey, Locale locale, Object[] args, Set<String> checked,
                                       ValueStack valueStack) {
         if (checked == null) {
-            checked = new TreeSet<String>();
+            checked = new TreeSet<>();
         } else if (checked.contains(clazz.getName())) {
             return null;
         }
@@ -849,85 +635,6 @@ public class StrutsLocalizedTextProvider implements LocalizedTextProvider {
         return null;
     }
 
-    private void reloadBundles() {
-        reloadBundles(ActionContext.getContext() != null ? ActionContext.getContext().getContextMap() : null);
-    }
-
-    private void reloadBundles(Map<String, Object> context) {
-        if (reloadBundles) {
-            try {
-                Boolean reloaded;
-                if (context != null) {
-                    reloaded = (Boolean) ObjectUtils.defaultIfNull(context.get(RELOADED), Boolean.FALSE);
-                }else {
-                    reloaded = Boolean.FALSE;
-                }
-                if (!reloaded) {
-                    bundlesMap.clear();
-                    try {
-                        clearMap(ResourceBundle.class, null, "cacheList");
-                    } catch (NoSuchFieldException e) {
-                        // happens in IBM JVM, that has a different ResourceBundle impl
-                        // it has a 'cache' member
-                        clearMap(ResourceBundle.class, null, "cache");
-                    }
-
-                    // now, for the true and utter hack, if we're running in tomcat, clear
-                    // it's class loader resource cache as well.
-                    clearTomcatCache();
-                    if(context!=null) {
-                        context.put(RELOADED, true);
-                    }
-                    LOG.debug("Resource bundles reloaded");
-                }
-            } catch (Exception e) {
-                LOG.error("Could not reload resource bundles", e);
-            }
-        }
-    }
-
-
-    private void clearTomcatCache() {
-        ClassLoader loader = getCurrentThreadContextClassLoader();
-        // no need for compilation here.
-        Class cl = loader.getClass();
-
-        try {
-            if ("org.apache.catalina.loader.WebappClassLoader".equals(cl.getName())) {
-                clearMap(cl, loader, TOMCAT_RESOURCE_ENTRIES_FIELD);
-            } else {
-                LOG.debug("Class loader {} is not tomcat loader.", cl.getName());
-            }
-        } catch (NoSuchFieldException nsfe) {
-            if ("org.apache.catalina.loader.WebappClassLoaderBase".equals(cl.getSuperclass().getName())) {
-                LOG.debug("Base class {} doesn't contain '{}' field, trying with parent!", cl.getName(), TOMCAT_RESOURCE_ENTRIES_FIELD, nsfe);
-                try {
-                    clearMap(cl.getSuperclass(), loader, TOMCAT_RESOURCE_ENTRIES_FIELD);
-                } catch (Exception e) {
-                    LOG.warn("Couldn't clear tomcat cache using {}", cl.getSuperclass().getName(), e);
-                }
-            }
-        } catch (Exception e) {
-      	    LOG.warn("Couldn't clear tomcat cache", cl.getName(), e);
-        }
-    }
-
-
-    private 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);
-        }
-    }
-
     /**
      * Clears all the internal lists.
      *
@@ -938,63 +645,4 @@ public class StrutsLocalizedTextProvider implements LocalizedTextProvider {
         // no-op
     }
 
-    static class MessageFormatKey {
-        String pattern;
-        Locale locale;
-
-        MessageFormatKey(String pattern, Locale locale) {
-            this.pattern = pattern;
-            this.locale = locale;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) return true;
-            if (!(o instanceof MessageFormatKey)) return false;
-
-            final MessageFormatKey messageFormatKey = (MessageFormatKey) o;
-
-            if (locale != null ? !locale.equals(messageFormatKey.locale) : messageFormatKey.locale != null)
-                return false;
-            if (pattern != null ? !pattern.equals(messageFormatKey.pattern) : messageFormatKey.pattern != null)
-                return false;
-
-            return true;
-        }
-
-        @Override
-        public int hashCode() {
-            int result;
-            result = (pattern != null ? pattern.hashCode() : 0);
-            result = 29 * result + (locale != null ? locale.hashCode() : 0);
-            return result;
-        }
-    }
-
-    private static ClassLoader getCurrentThreadContextClassLoader() {
-        return Thread.currentThread().getContextClassLoader();
-    }
-
-    static class GetDefaultMessageReturnArg {
-        String message;
-        boolean foundInBundle;
-
-        public GetDefaultMessageReturnArg(String message, boolean foundInBundle) {
-            this.message = message;
-            this.foundInBundle = foundInBundle;
-        }
-    }
-
-    private static class EmptyResourceBundle extends ResourceBundle {
-        @Override
-        public Enumeration<String> getKeys() {
-            return null; // dummy
-        }
-
-        @Override
-        protected Object handleGetObject(String key) {
-            return null; // dummy
-        }
-    }
-
 }