WW-4762 Introduces default provider which only uses default bundles

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

Branch: refs/heads/default-provider
Commit: bb19a6209886795b76385e48fd86424c144ee029
Parents: 2e23d7a
Author: Lukasz Lenart <lukaszlen...@apache.org>
Authored: Wed Apr 26 20:28:11 2017 +0200
Committer: Lukasz Lenart <lukaszlen...@apache.org>
Committed: Wed Apr 26 20:28:11 2017 +0200

----------------------------------------------------------------------
 .../util/AbstractLocalizedTextProvider.java     | 145 ++++++++-
 .../util/DefaultLocalizedTextProvider.java      | 310 +++++++++++++++++++
 .../util/StrutsLocalizedTextProvider.java       | 161 +---------
 3 files changed, 461 insertions(+), 155 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/struts/blob/bb19a620/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
index a2578bc..8c377c1 100644
--- 
a/core/src/main/java/com/opensymphony/xwork2/util/AbstractLocalizedTextProvider.java
+++ 
b/core/src/main/java/com/opensymphony/xwork2/util/AbstractLocalizedTextProvider.java
@@ -20,11 +20,12 @@ import java.util.Map;
 import java.util.MissingResourceException;
 import java.util.ResourceBundle;
 import java.util.Set;
+import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 
-public abstract class AbstractLocalizedTextProvider implements 
LocalizedTextProvider {
+abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
 
     private static final Logger LOG = 
LogManager.getLogger(AbstractLocalizedTextProvider.class);
 
@@ -302,6 +303,26 @@ public abstract class AbstractLocalizedTextProvider 
implements LocalizedTextProv
     }
 
     /**
+     * Determines if we found the text in the bundles.
+     *
+     * @param result the result so far
+     * @return <tt>true</tt> if we could <b>not</b> find the text, 
<tt>false</tt> if the text was found (=success).
+     */
+    protected boolean unableToFindTextForKey(GetDefaultMessageReturnArg 
result) {
+        if (result == null || result.message == null) {
+            return true;
+        }
+
+        // did we find it in the bundle, then no problem?
+        if (result.foundInBundle) {
+            return false;
+        }
+
+        // not found in bundle
+        return true;
+    }
+
+    /**
      * 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.
@@ -313,6 +334,128 @@ public abstract class AbstractLocalizedTextProvider 
implements LocalizedTextProv
         return prefix + aBundleName + "_" + locale.toString();
     }
 
+    /**
+     * @return the default message.
+     */
+    protected GetDefaultMessageReturnArg getDefaultMessage(String key, Locale 
locale, ValueStack valueStack, Object[] args,
+                                                                String 
defaultMessage) {
+        GetDefaultMessageReturnArg result = null;
+        boolean found = true;
+
+        if (key != null) {
+            String message = findDefaultText(key, locale);
+
+            if (message == null) {
+                message = defaultMessage;
+                found = false; // not found in bundles
+            }
+
+            // defaultMessage may be null
+            if (message != null) {
+                MessageFormat mf = 
buildMessageFormat(TextParseUtil.translateVariables(message, valueStack), 
locale);
+
+                String msg = formatWithNullDetection(mf, args);
+                result = new GetDefaultMessageReturnArg(msg, found);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * @return the message from the named resource bundle.
+     */
+    protected String getMessage(String bundleName, Locale locale, String key, 
ValueStack valueStack, Object[] args) {
+        ResourceBundle bundle = findResourceBundle(bundleName, locale);
+        if (bundle == null) {
+            return null;
+        }
+        if (valueStack != null)
+            reloadBundles(valueStack.getContext());
+        try {
+               String message = bundle.getString(key);
+               if (valueStack != null)
+                       message = 
TextParseUtil.translateVariables(bundle.getString(key), valueStack);
+            MessageFormat mf = buildMessageFormat(message, locale);
+            return formatWithNullDetection(mf, args);
+        } catch (MissingResourceException e) {
+            if (devMode) {
+                LOG.warn("Missing key [{}] in bundle [{}]!", key, bundleName);
+            } else {
+                LOG.debug("Missing key [{}] in bundle [{}]!", key, bundleName);
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Traverse up class hierarchy looking for message.  Looks at class, then 
implemented interface,
+     * before going up hierarchy.
+     *
+     * @return the message
+     */
+    protected String findMessage(Class clazz, String key, String indexedKey, 
Locale locale, Object[] args, Set<String> checked,
+                                      ValueStack valueStack) {
+        if (checked == null) {
+            checked = new TreeSet<>();
+        } else if (checked.contains(clazz.getName())) {
+            return null;
+        }
+
+        // look in properties of this class
+        String msg = getMessage(clazz.getName(), locale, key, valueStack, 
args);
+
+        if (msg != null) {
+            return msg;
+        }
+
+        if (indexedKey != null) {
+            msg = getMessage(clazz.getName(), locale, indexedKey, valueStack, 
args);
+
+            if (msg != null) {
+                return msg;
+            }
+        }
+
+        // look in properties of implemented interfaces
+        Class[] interfaces = clazz.getInterfaces();
+
+        for (Class anInterface : interfaces) {
+            msg = getMessage(anInterface.getName(), locale, key, valueStack, 
args);
+
+            if (msg != null) {
+                return msg;
+            }
+
+            if (indexedKey != null) {
+                msg = getMessage(anInterface.getName(), locale, indexedKey, 
valueStack, args);
+
+                if (msg != null) {
+                    return msg;
+                }
+            }
+        }
+
+        // traverse up hierarchy
+        if (clazz.isInterface()) {
+            interfaces = clazz.getInterfaces();
+
+            for (Class anInterface : interfaces) {
+                msg = findMessage(anInterface, key, indexedKey, locale, args, 
checked, valueStack);
+
+                if (msg != null) {
+                    return msg;
+                }
+            }
+        } else {
+            if (!clazz.equals(Object.class) && !clazz.isPrimitive()) {
+                return findMessage(clazz.getSuperclass(), key, indexedKey, 
locale, args, checked, valueStack);
+            }
+        }
+
+        return null;
+    }
+
     static class MessageFormatKey {
         String pattern;
         Locale locale;

http://git-wip-us.apache.org/repos/asf/struts/blob/bb19a620/core/src/main/java/com/opensymphony/xwork2/util/DefaultLocalizedTextProvider.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/com/opensymphony/xwork2/util/DefaultLocalizedTextProvider.java
 
b/core/src/main/java/com/opensymphony/xwork2/util/DefaultLocalizedTextProvider.java
new file mode 100644
index 0000000..acd3943
--- /dev/null
+++ 
b/core/src/main/java/com/opensymphony/xwork2/util/DefaultLocalizedTextProvider.java
@@ -0,0 +1,310 @@
+/*
+ * $Id$
+ *
+ * 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 com.opensymphony.xwork2.util;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ModelDriven;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * 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 DefaultLocalizedTextProvider extends 
AbstractLocalizedTextProvider {
+
+    private static final Logger LOG = 
LogManager.getLogger(DefaultLocalizedTextProvider.class);
+
+    public DefaultLocalizedTextProvider() {
+        addDefaultResourceBundle(XWORK_MESSAGES_BUNDLE);
+        addDefaultResourceBundle(STRUTS_MESSAGES_BUNDLE);
+    }
+
+    /**
+     * Calls {@link #findText(Class aClass, String aTextName, Locale locale, 
String defaultMessage, Object[] args)}
+     * with aTextName as the default message.
+     *
+     * @param aClass    class name
+     * @param aTextName text name
+     * @param locale    the locale
+     * @return the localized text, or null if none can be found and no 
defaultMessage is provided
+     * @see #findText(Class aClass, String aTextName, Locale locale, String 
defaultMessage, Object[] args)
+     */
+    @Override
+    public String findText(Class aClass, String aTextName, Locale locale) {
+        return findText(aClass, aTextName, locale, aTextName, new Object[0]);
+    }
+
+    /**
+     * <p>
+     * Finds a localized text message for the given key, aTextName. Both the 
key and the message
+     * itself is evaluated as required.  The following algorithm is used to 
find the requested
+     * message:
+     * </p>
+     *
+     * <ol>
+     * <li>Look for message in aClass' class hierarchy.
+     * <ol>
+     * <li>Look for the message in a resource bundle for aClass</li>
+     * <li>If not found, look for the message in a resource bundle for any 
implemented interface</li>
+     * <li>If not found, traverse up the Class' hierarchy and repeat from the 
first sub-step</li>
+     * </ol></li>
+     * <li>If not found and aClass is a {@link ModelDriven} Action, then look 
for message in
+     * the model's class hierarchy (repeat sub-steps listed above).</li>
+     * <li>If not found, look for message in child property.  This is 
determined by evaluating
+     * the message key as an OGNL expression.  For example, if the key is
+     * <i>user.address.state</i>, then it will attempt to see if "user" can be 
resolved into an
+     * object.  If so, repeat the entire process fromthe beginning with the 
object's class as
+     * aClass and "address.state" as the message key.</li>
+     * <li>If not found, look for the message in aClass' package 
hierarchy.</li>
+     * <li>If still not found, look for the message in the default resource 
bundles.</li>
+     * <li>Return defaultMessage</li>
+     * </ol>
+     *
+     * <p>
+     * When looking for the message, if the key indexes a collection (e.g. 
user.phone[0]) and a
+     * message for that specific key cannot be found, the general form will 
also be looked up
+     * (i.e. user.phone[*]).
+     * </p>
+     *
+     * <p>
+     * If a message is found, it will also be interpolated.  Anything within 
<code>${...}</code>
+     * will be treated as an OGNL expression and evaluated as such.
+     * </p>
+     *
+     * @param aClass         the class whose name to use as the start point 
for the search
+     * @param aTextName      the key to find the text message for
+     * @param locale         the locale the message should be for
+     * @param defaultMessage the message to be returned if no text message can 
be found in any
+     *                       resource bundle
+     * @param args           arguments
+     *                       resource bundle
+     * @return the localized text, or null if none can be found and no 
defaultMessage is provided
+     */
+    @Override
+    public String findText(Class aClass, String aTextName, Locale locale, 
String defaultMessage, Object[] args) {
+        ValueStack valueStack = ActionContext.getContext().getValueStack();
+        return findText(aClass, aTextName, locale, defaultMessage, args, 
valueStack);
+
+    }
+
+    /**
+     * <p>
+     * Finds a localized text message for the given key, aTextName. Both the 
key and the message
+     * itself is evaluated as required.  The following algorithm is used to 
find the requested
+     * message:
+     * </p>
+     *
+     * <ol>
+     * <li>Look for message in aClass' class hierarchy.
+     * <ol>
+     * <li>Look for the message in a resource bundle for aClass</li>
+     * <li>If not found, look for the message in a resource bundle for any 
implemented interface</li>
+     * <li>If not found, traverse up the Class' hierarchy and repeat from the 
first sub-step</li>
+     * </ol></li>
+     * <li>If not found and aClass is a {@link ModelDriven} Action, then look 
for message in
+     * the model's class hierarchy (repeat sub-steps listed above).</li>
+     * <li>If not found, look for message in child property.  This is 
determined by evaluating
+     * the message key as an OGNL expression.  For example, if the key is
+     * <i>user.address.state</i>, then it will attempt to see if "user" can be 
resolved into an
+     * object.  If so, repeat the entire process fromthe beginning with the 
object's class as
+     * aClass and "address.state" as the message key.</li>
+     * <li>If not found, look for the message in aClass' package 
hierarchy.</li>
+     * <li>If still not found, look for the message in the default resource 
bundles.</li>
+     * <li>Return defaultMessage</li>
+     * </ol>
+     *
+     * <p>
+     * When looking for the message, if the key indexes a collection (e.g. 
user.phone[0]) and a
+     * message for that specific key cannot be found, the general form will 
also be looked up
+     * (i.e. user.phone[*]).
+     * </p>
+     *
+     * <p>
+     * If a message is found, it will also be interpolated.  Anything within 
<code>${...}</code>
+     * will be treated as an OGNL expression and evaluated as such.
+     * </p>
+     *
+     * <p>
+     * If a message is <b>not</b> found a WARN log will be logged.
+     * </p>
+     *
+     * @param aClass         the class whose name to use as the start point 
for the search
+     * @param aTextName      the key to find the text message for
+     * @param locale         the locale the message should be for
+     * @param defaultMessage the message to be returned if no text message can 
be found in any
+     *                       resource bundle
+     * @param args           arguments
+     * @param valueStack     the value stack to use to evaluate expressions 
instead of the
+     *                       one in the ActionContext ThreadLocal
+     * @return the localized text, or null if none can be found and no 
defaultMessage is provided
+     */
+    @Override
+    public String findText(Class aClass, String aTextName, Locale locale, 
String defaultMessage, Object[] args, ValueStack valueStack) {
+        String indexedTextName = null;
+        if (aTextName == null) {
+            LOG.warn("Trying to find text with null key!");
+            aTextName = "";
+        }
+        // calculate indexedTextName (collection[*]) if applicable
+        if (aTextName.contains("[")) {
+            int i = -1;
+
+            indexedTextName = aTextName;
+
+            while ((i = indexedTextName.indexOf("[", i + 1)) != -1) {
+                int j = indexedTextName.indexOf("]", i);
+                String a = indexedTextName.substring(0, i);
+                String b = indexedTextName.substring(j);
+                indexedTextName = a + "[*" + b;
+            }
+        }
+
+        // get default
+        GetDefaultMessageReturnArg result;
+        if (indexedTextName == null) {
+            result = getDefaultMessage(aTextName, locale, valueStack, args, 
defaultMessage);
+        } else {
+            result = getDefaultMessage(aTextName, locale, valueStack, args, 
null);
+            if (result != null && result.message != null) {
+                return result.message;
+            }
+            result = getDefaultMessage(indexedTextName, locale, valueStack, 
args, defaultMessage);
+        }
+
+        // could we find the text, if not log a warn
+        if (unableToFindTextForKey(result) && LOG.isDebugEnabled()) {
+            String warn = "Unable to find text for key '" + aTextName + "' ";
+            if (indexedTextName != null) {
+                warn += " or indexed key '" + indexedTextName + "' ";
+            }
+            warn += "in class '" + aClass.getName() + "' and locale '" + 
locale + "'";
+            LOG.debug(warn);
+        }
+
+        return result != null ? result.message : null;
+    }
+
+    /**
+     * <p>
+     * Finds a localized text message for the given key, aTextName, in the 
specified resource bundle
+     * with aTextName as the default message.
+     * </p>
+     *
+     * <p>
+     * If a message is found, it will also be interpolated.  Anything within 
<code>${...}</code>
+     * will be treated as an OGNL expression and evaluated as such.
+     * </p>
+     *
+     * @param bundle    a resource bundle name
+     * @param aTextName text name
+     * @param locale    the locale
+     * @return the localized text, or null if none can be found and no 
defaultMessage is provided
+     * @see #findText(ResourceBundle, String, Locale, String, Object[])
+     */
+    @Override
+    public String findText(ResourceBundle bundle, String aTextName, Locale 
locale) {
+        return findText(bundle, aTextName, locale, aTextName, new Object[0]);
+    }
+
+    /**
+     * <p>
+     * Finds a localized text message for the given key, aTextName, in the 
specified resource
+     * bundle.
+     * </p>
+     *
+     * <p>
+     * If a message is found, it will also be interpolated.  Anything within 
<code>${...}</code>
+     * will be treated as an OGNL expression and evaluated as such.
+     * </p>
+     *
+     * <p>
+     * If a message is <b>not</b> found a WARN log will be logged.
+     * </p>
+     *
+     * @param bundle         the bundle
+     * @param aTextName      the key
+     * @param locale         the locale
+     * @param defaultMessage the default message to use if no message was 
found in the bundle
+     * @param args           arguments for the message formatter.
+     * @return the localized text, or null if none can be found and no 
defaultMessage is provided
+     */
+    @Override
+    public String findText(ResourceBundle bundle, String aTextName, Locale 
locale, String defaultMessage, Object[] args) {
+        ValueStack valueStack = ActionContext.getContext().getValueStack();
+        return findText(bundle, aTextName, locale, defaultMessage, args, 
valueStack);
+    }
+
+    /**
+     * <p>
+     * Finds a localized text message for the given key, aTextName, in the 
specified resource
+     * bundle.
+     * </p>
+     *
+     * <p>
+     * If a message is found, it will also be interpolated.  Anything within 
<code>${...}</code>
+     * will be treated as an OGNL expression and evaluated as such.
+     * </p>
+     *
+     * <p>
+     * If a message is <b>not</b> found a WARN log will be logged.
+     * </p>
+     *
+     * @param bundle         the bundle
+     * @param aTextName      the key
+     * @param locale         the locale
+     * @param defaultMessage the default message to use if no message was 
found in the bundle
+     * @param args           arguments for the message formatter.
+     * @param valueStack     the OGNL value stack.
+     * @return the localized text, or null if none can be found and no 
defaultMessage is provided
+     */
+    @Override
+    public String findText(ResourceBundle bundle, String aTextName, Locale 
locale, String defaultMessage, Object[] args,
+                           ValueStack valueStack) {
+        try {
+            reloadBundles(valueStack.getContext());
+
+            String message = 
TextParseUtil.translateVariables(bundle.getString(aTextName), valueStack);
+            MessageFormat mf = buildMessageFormat(message, locale);
+
+            return formatWithNullDetection(mf, args);
+        } catch (MissingResourceException ex) {
+            if (devMode) {
+                LOG.warn("Missing key [{}] in bundle [{}]!", aTextName, 
bundle);
+            } else {
+                LOG.debug("Missing key [{}] in bundle [{}]!", aTextName, 
bundle);
+            }
+        }
+
+        GetDefaultMessageReturnArg result = getDefaultMessage(aTextName, 
locale, valueStack, args, defaultMessage);
+        if (unableToFindTextForKey(result)) {
+            LOG.warn("Unable to find text for key '{}' in ResourceBundles for 
locale '{}'", aTextName, locale);
+        }
+        return result != null ? result.message : null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/bb19a620/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 3d03f9a..9552869 100644
--- 
a/core/src/main/java/com/opensymphony/xwork2/util/StrutsLocalizedTextProvider.java
+++ 
b/core/src/main/java/com/opensymphony/xwork2/util/StrutsLocalizedTextProvider.java
@@ -37,9 +37,7 @@ import java.text.MessageFormat;
 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,
@@ -89,7 +87,6 @@ public class StrutsLocalizedTextProvider extends 
AbstractLocalizedTextProvider {
      * @param localeStr     The locale String to parse.
      * @param defaultLocale The locale to use if localeStr is <tt>null</tt>.
      * @return requested Locale
-     *
      * @deprecated please use {@link 
org.apache.commons.lang3.LocaleUtils#toLocale(String)}
      */
     @Deprecated
@@ -130,10 +127,9 @@ public class StrutsLocalizedTextProvider extends 
AbstractLocalizedTextProvider {
      * Calls {@link #findText(Class aClass, String aTextName, Locale locale, 
String defaultMessage, Object[] args)}
      * with aTextName as the default message.
      *
-     * @param aClass class name
-     * @param aTextName  text name
-     * @param locale the locale
-     *
+     * @param aClass    class name
+     * @param aTextName text name
+     * @param locale    the locale
      * @return the localized text, or null if none can be found and no 
defaultMessage is provided
      * @see #findText(Class aClass, String aTextName, Locale locale, String 
defaultMessage, Object[] args)
      */
@@ -251,7 +247,7 @@ public class StrutsLocalizedTextProvider extends 
AbstractLocalizedTextProvider {
                            ValueStack valueStack) {
         String indexedTextName = null;
         if (aTextName == null) {
-               LOG.warn("Trying to find text with null key!");
+            LOG.warn("Trying to find text with null key!");
             aTextName = "";
         }
         // calculate indexedTextName (collection[*]) if applicable
@@ -395,26 +391,6 @@ public class StrutsLocalizedTextProvider extends 
AbstractLocalizedTextProvider {
     }
 
     /**
-     * Determines if we found the text in the bundles.
-     *
-     * @param result the result so far
-     * @return <tt>true</tt> if we could <b>not</b> find the text, 
<tt>false</tt> if the text was found (=success).
-     */
-    private boolean unableToFindTextForKey(GetDefaultMessageReturnArg result) {
-        if (result == null || result.message == null) {
-            return true;
-        }
-
-        // did we find it in the bundle, then no problem?
-        if (result.foundInBundle) {
-            return false;
-        }
-
-        // not found in bundle
-        return true;
-    }
-
-    /**
      * <p>
      * Finds a localized text message for the given key, aTextName, in the 
specified resource bundle
      * with aTextName as the default message.
@@ -425,10 +401,9 @@ public class StrutsLocalizedTextProvider extends 
AbstractLocalizedTextProvider {
      * will be treated as an OGNL expression and evaluated as such.
      * </p>
      *
-     * @param bundle a resource bundle name
-     * @param aTextName  text name
-     * @param locale the locale
-     *
+     * @param bundle    a resource bundle name
+     * @param aTextName text name
+     * @param locale    the locale
      * @return the localized text, or null if none can be found and no 
defaultMessage is provided
      * @see #findText(java.util.ResourceBundle, String, java.util.Locale, 
String, Object[])
      */
@@ -514,128 +489,6 @@ public class StrutsLocalizedTextProvider extends 
AbstractLocalizedTextProvider {
     }
 
     /**
-     * @return the default message.
-     */
-    private GetDefaultMessageReturnArg getDefaultMessage(String key, Locale 
locale, ValueStack valueStack, Object[] args,
-                                                                String 
defaultMessage) {
-        GetDefaultMessageReturnArg result = null;
-        boolean found = true;
-
-        if (key != null) {
-            String message = findDefaultText(key, locale);
-
-            if (message == null) {
-                message = defaultMessage;
-                found = false; // not found in bundles
-            }
-
-            // defaultMessage may be null
-            if (message != null) {
-                MessageFormat mf = 
buildMessageFormat(TextParseUtil.translateVariables(message, valueStack), 
locale);
-
-                String msg = formatWithNullDetection(mf, args);
-                result = new GetDefaultMessageReturnArg(msg, found);
-            }
-        }
-
-        return result;
-    }
-
-    /**
-     * @return the message from the named resource bundle.
-     */
-    private String getMessage(String bundleName, Locale locale, String key, 
ValueStack valueStack, Object[] args) {
-        ResourceBundle bundle = findResourceBundle(bundleName, locale);
-        if (bundle == null) {
-            return null;
-        }
-        if (valueStack != null) 
-            reloadBundles(valueStack.getContext());
-        try {
-               String message = bundle.getString(key);
-               if (valueStack != null) 
-                       message = 
TextParseUtil.translateVariables(bundle.getString(key), valueStack);
-            MessageFormat mf = buildMessageFormat(message, locale);
-            return formatWithNullDetection(mf, args);
-        } catch (MissingResourceException e) {
-            if (devMode) {
-                LOG.warn("Missing key [{}] in bundle [{}]!", key, bundleName);
-            } else {
-                LOG.debug("Missing key [{}] in bundle [{}]!", key, bundleName);
-            }
-            return null;
-        }
-    }
-
-    /**
-     * Traverse up class hierarchy looking for message.  Looks at class, then 
implemented interface,
-     * before going up hierarchy.
-     *
-     * @return the message
-     */
-    private String findMessage(Class clazz, String key, String indexedKey, 
Locale locale, Object[] args, Set<String> checked,
-                                      ValueStack valueStack) {
-        if (checked == null) {
-            checked = new TreeSet<>();
-        } else if (checked.contains(clazz.getName())) {
-            return null;
-        }
-
-        // look in properties of this class
-        String msg = getMessage(clazz.getName(), locale, key, valueStack, 
args);
-
-        if (msg != null) {
-            return msg;
-        }
-
-        if (indexedKey != null) {
-            msg = getMessage(clazz.getName(), locale, indexedKey, valueStack, 
args);
-
-            if (msg != null) {
-                return msg;
-            }
-        }
-
-        // look in properties of implemented interfaces
-        Class[] interfaces = clazz.getInterfaces();
-
-        for (Class anInterface : interfaces) {
-            msg = getMessage(anInterface.getName(), locale, key, valueStack, 
args);
-
-            if (msg != null) {
-                return msg;
-            }
-
-            if (indexedKey != null) {
-                msg = getMessage(anInterface.getName(), locale, indexedKey, 
valueStack, args);
-
-                if (msg != null) {
-                    return msg;
-                }
-            }
-        }
-
-        // traverse up hierarchy
-        if (clazz.isInterface()) {
-            interfaces = clazz.getInterfaces();
-
-            for (Class anInterface : interfaces) {
-                msg = findMessage(anInterface, key, indexedKey, locale, args, 
checked, valueStack);
-
-                if (msg != null) {
-                    return msg;
-                }
-            }
-        } else {
-            if (!clazz.equals(Object.class) && !clazz.isPrimitive()) {
-                return findMessage(clazz.getSuperclass(), key, indexedKey, 
locale, args, checked, valueStack);
-            }
-        }
-
-        return null;
-    }
-
-    /**
      * Clears all the internal lists.
      *
      * @deprecated used only in tests

Reply via email to