Merge pull request #1113 from apache/feature/WW-5481-text

WW-5481 Extract text related classes into org.apache.struts2.text
This commit is contained in:
Lukasz Lenart
2024-11-03 12:16:15 +01:00
committed by GitHub
86 changed files with 722 additions and 932 deletions
@@ -25,6 +25,8 @@ import org.apache.struts2.conversion.impl.ConversionData;
import org.apache.struts2.inject.Container;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.interceptor.ValidationAware;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.util.ValueStack;
import java.io.Serializable;
@@ -26,6 +26,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.text.LocalizedTextProvider;
import java.io.Serial;
import java.io.Serializable;
@@ -23,15 +23,14 @@ import org.apache.commons.lang3.StringUtils;
import java.util.Locale;
/**
* Indicates that the implementing class can provide its own {@link Locale}.
*
* <p>
* This is useful for when an action may wish override the default locale. All that is
* needed is to implement this interface and return your own custom locale.
* The {@link TextProvider} interface uses this interface heavily for retrieving
* internationalized messages from resource bundles.
* The {@link org.apache.struts2.text.TextProvider} interface uses this interface
* heavily for retrieving internationalized messages from resource bundles.
* </p>
*
* @author Jason Carreira
@@ -1,49 +0,0 @@
/*
* 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 org.apache.struts2;
import org.apache.struts2.util.ValueStack;
import java.io.Serializable;
import java.util.Locale;
import java.util.ResourceBundle;
public interface LocalizedTextProvider extends Serializable {
String findDefaultText(String aTextName, Locale locale);
String findDefaultText(String aTextName, Locale locale, Object[] params);
ResourceBundle findResourceBundle(String aBundleName, Locale locale);
String findText(Class aClass, String aTextName, Locale locale);
String findText(Class aClass, String aTextName, Locale locale, String defaultMessage, Object[] args);
String findText(Class aClass, String aTextName, Locale locale, String defaultMessage, Object[] args, ValueStack valueStack);
String findText(ResourceBundle bundle, String aTextName, Locale locale);
String findText(ResourceBundle bundle, String aTextName, Locale locale, String defaultMessage, Object[] args);
String findText(ResourceBundle bundle, String aTextName, Locale locale, String defaultMessage, Object[] args, ValueStack valueStack);
void addDefaultResourceBundle(String resourceBundleName);
}
@@ -18,7 +18,7 @@
*/
package org.apache.struts2.components;
import org.apache.struts2.TextProvider;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.util.ValueStack;
import org.apache.logging.log4j.LogManager;
@@ -22,14 +22,14 @@ import java.io.Writer;
import java.util.ResourceBundle;
import org.apache.struts2.LocaleProviderFactory;
import org.apache.struts2.LocalizedTextProvider;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.LocalizedTextProvider;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.views.annotations.StrutsTag;
import org.apache.struts2.views.annotations.StrutsTagAttribute;
import org.apache.struts2.StrutsException;
import org.apache.struts2.LocaleProvider;
import org.apache.struts2.TextProvider;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.util.ValueStack;
import org.apache.logging.log4j.LogManager;
@@ -23,11 +23,11 @@ import org.apache.struts2.ActionProxyFactory;
import org.apache.struts2.FileManager;
import org.apache.struts2.FileManagerFactory;
import org.apache.struts2.LocaleProviderFactory;
import org.apache.struts2.LocalizedTextProvider;
import org.apache.struts2.text.LocalizedTextProvider;
import org.apache.struts2.ObjectFactory;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.TextProvider;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.UnknownHandlerManager;
import org.apache.struts2.components.UrlRenderer;
import org.apache.struts2.components.date.DateFormatter;
@@ -20,15 +20,15 @@ package org.apache.struts2.config.impl;
import org.apache.struts2.ActionContext;
import org.apache.struts2.DefaultLocaleProviderFactory;
import org.apache.struts2.DefaultTextProvider;
import org.apache.struts2.text.DefaultTextProvider;
import org.apache.struts2.FileManager;
import org.apache.struts2.FileManagerFactory;
import org.apache.struts2.LocaleProviderFactory;
import org.apache.struts2.LocalizedTextProvider;
import org.apache.struts2.text.LocalizedTextProvider;
import org.apache.struts2.ObjectFactory;
import org.apache.struts2.StrutsTextProviderFactory;
import org.apache.struts2.TextProvider;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.StrutsTextProviderFactory;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.config.Configuration;
import org.apache.struts2.config.ConfigurationException;
import org.apache.struts2.config.ContainerProvider;
@@ -92,7 +92,7 @@ import org.apache.struts2.ognl.accessor.RootAccessor;
import org.apache.struts2.ognl.accessor.XWorkMethodAccessor;
import org.apache.struts2.util.OgnlTextParser;
import org.apache.struts2.util.PatternMatcher;
import org.apache.struts2.util.StrutsLocalizedTextProvider;
import org.apache.struts2.text.StrutsLocalizedTextProvider;
import org.apache.struts2.util.TextParser;
import org.apache.struts2.util.ValueStack;
import org.apache.struts2.util.ValueStackFactory;
@@ -19,7 +19,7 @@
package org.apache.struts2.conversion.impl;
import org.apache.struts2.ActionContext;
import org.apache.struts2.TextProvider;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.util.ValueStack;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -21,7 +21,7 @@ package org.apache.struts2.conversion.impl;
import org.apache.struts2.ActionContext;
import org.apache.struts2.FileManager;
import org.apache.struts2.FileManagerFactory;
import org.apache.struts2.LocalizedTextProvider;
import org.apache.struts2.text.LocalizedTextProvider;
import org.apache.struts2.conversion.ConversionAnnotationProcessor;
import org.apache.struts2.conversion.ConversionFileProcessor;
import org.apache.struts2.conversion.TypeConverter;
@@ -20,12 +20,10 @@ package org.apache.struts2.interceptor;
import org.apache.struts2.LocaleProvider;
import org.apache.struts2.LocaleProviderFactory;
import org.apache.struts2.TextProvider;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.inject.Container;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.interceptor.AbstractInterceptor;
import org.apache.struts2.interceptor.ValidationAware;
import org.apache.struts2.util.TextParseUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -22,7 +22,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.ActionContext;
import org.apache.struts2.ActionInvocation;
import org.apache.struts2.LocalizedTextProvider;
import org.apache.struts2.text.LocalizedTextProvider;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.config.entities.ActionConfig;
import org.apache.struts2.dispatcher.HttpParameters;
@@ -23,7 +23,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.ActionContext;
import org.apache.struts2.ActionInvocation;
import org.apache.struts2.LocalizedTextProvider;
import org.apache.struts2.text.LocalizedTextProvider;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.config.entities.ActionConfig;
import org.apache.struts2.config.entities.Parameterizable;
@@ -19,11 +19,9 @@
package org.apache.struts2.interceptor;
import org.apache.struts2.ActionInvocation;
import org.apache.struts2.TextProvider;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.interceptor.ValidationAware;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.interceptor.MethodFilterInterceptor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.ServletActionContext;
@@ -19,7 +19,7 @@
package org.apache.struts2.ognl;
import org.apache.struts2.ActionContext;
import org.apache.struts2.TextProvider;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.conversion.impl.XWorkConverter;
import org.apache.struts2.inject.Container;
import org.apache.struts2.inject.Inject;
@@ -18,7 +18,7 @@
*/
package org.apache.struts2.ognl;
import org.apache.struts2.TextProvider;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.conversion.NullHandler;
import org.apache.struts2.conversion.impl.XWorkConverter;
import org.apache.struts2.inject.Container;
@@ -16,15 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.util;
package org.apache.struts2.text;
import org.apache.struts2.ActionContext;
import org.apache.struts2.LocalizedTextProvider;
import org.apache.struts2.inject.Inject;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.ActionContext;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.util.TextParseUtil;
import org.apache.struts2.util.ValueStack;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -66,24 +67,18 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
private final Set<String> missingBundles = ConcurrentHashMap.newKeySet();
private final ConcurrentMap<Integer, ClassLoader> delegatedClassLoaderMap = new ConcurrentHashMap<>();
/**
* Adds 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) {
public void addDefaultResourceBundle(String bundleName) {
//make sure this doesn't get added more than once
final ClassLoader ccl = getCurrentThreadContextClassLoader();
synchronized (XWORK_MESSAGES_BUNDLE) {
List<String> bundles = classLoaderMap.computeIfAbsent(ccl.hashCode(), k -> new CopyOnWriteArrayList<>());
bundles.remove(resourceBundleName);
bundles.add(0, resourceBundleName);
bundles.remove(bundleName);
bundles.add(0, bundleName);
}
if (LOG.isDebugEnabled()) {
LOG.debug("Added default resource bundle '{}' to default resource bundles for the following classloader '{}'", resourceBundleName, ccl.toString());
LOG.debug("Added default resource bundle '{}' to default resource bundles for the following classloader '{}'", bundleName, ccl.toString());
}
}
@@ -112,16 +107,8 @@ abstract class AbstractLocalizedTextProvider 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) {
public String findDefaultText(String textKey, Locale locale) {
List<String> localList = getCurrentBundleNames();
for (String bundleName : localList) {
@@ -129,7 +116,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
if (bundle != null) {
reloadBundles();
try {
return bundle.getString(aTextName);
return bundle.getString(textKey);
} catch (MissingResourceException e) {
// will be logged when not found in any bundle
}
@@ -137,26 +124,17 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
}
if (devMode) {
LOG.warn("Missing key [{}] in bundles [{}]!", aTextName, localList);
LOG.warn("Missing key [{}] in bundles [{}]!", textKey, localList);
} else {
LOG.debug("Missing key [{}] in bundles [{}]!", aTextName, localList);
LOG.debug("Missing key [{}] in bundles [{}]!", textKey, 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);
public String findDefaultText(String textKey, Locale locale, Object[] params) {
String defaultText = findDefaultText(textKey, locale);
if (defaultText != null) {
MessageFormat mf = buildMessageFormat(defaultText, locale);
return formatWithNullDetection(mf, params);
@@ -164,51 +142,27 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
return null;
}
/**
* <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,
public String findText(ResourceBundle bundle, String textKey, Locale locale, String defaultMessage, Object[] args,
ValueStack valueStack) {
try {
reloadBundles(valueStack.getContext());
String message = TextParseUtil.translateVariables(bundle.getString(aTextName), valueStack);
String message = TextParseUtil.translateVariables(bundle.getString(textKey), valueStack);
MessageFormat mf = buildMessageFormat(message, locale);
return formatWithNullDetection(mf, args);
} catch (MissingResourceException ex) {
if (devMode) {
LOG.warn("Missing key [{}] in bundle [{}]!", aTextName, bundle);
LOG.warn("Missing key [{}] in bundle [{}]!", textKey, bundle);
} else {
LOG.debug("Missing key [{}] in bundle [{}]!", aTextName, bundle);
LOG.debug("Missing key [{}] in bundle [{}]!", textKey, bundle);
}
}
GetDefaultMessageReturnArg result = getDefaultMessage(aTextName, locale, valueStack, args, defaultMessage);
GetDefaultMessageReturnArg result = getDefaultMessage(textKey, locale, valueStack, args, defaultMessage);
if (unableToFindTextForKey(result)) {
LOG.warn("Unable to find text for key '{}' in ResourceBundles for locale '{}'", aTextName, locale);
LOG.warn("Unable to find text for key '{}' in ResourceBundles for locale '{}'", textKey, locale);
}
return result != null ? result.message : null;
}
@@ -224,11 +178,10 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
/**
* Clear a specific bundle + locale combination from the <code>bundlesMap</code>.
* Intended for descendants to use clear a bundle + locale combination.
* Intended for descendants to use clear a bundle + locale combination.
*
* @param bundleName The bundle (combined with locale) to remove from the bundle map
* @param locale Provides the locale to combine with the bundle to get the key
*
* @since 6.0.0
*/
protected void clearBundle(final String bundleName, Locale locale) {
@@ -239,13 +192,13 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
/**
* Clears the <code>missingBundles</code> contents. This allows descendants to
* clear the <b>"missing bundles cache"</b> when desired (or needed).
*
* clear the <b>"missing bundles cache"</b> when desired (or needed).
* <p>
* Note: This method may be used when the <code>bundlesMap</code> state has changed
* in such a way that bundles that were previously "missing" may now be available
* (e.g. after calling {@link #addDefaultResourceBundle(java.lang.String)} when the
* {@link AbstractLocalizedTextProvider} has already been used for failed bundle
* lookups of a given key, or some transitory state made a bundle lookup fail.
* in such a way that bundles that were previously "missing" may now be available
* (e.g. after calling {@link #addDefaultResourceBundle(java.lang.String)} when the
* {@link AbstractLocalizedTextProvider} has already been used for failed bundle
* lookups of a given key, or some transitory state made a bundle lookup fail.
*
* @since 6.0.0
*/
@@ -287,10 +240,10 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
/**
* A helper method for {@link ResourceBundle} bundle reload logic.
*
* <p>
* Uses standard {@link ResourceBundle} methods to clear the bundle caches for the
* {@link ClassLoader} instances that this class is aware of at the time of the call.
*
* <p>
* The <code>clearCache()</code> methods have been available since Java 1.6, so
* it is anticipated the logic will work on any subsequent JVM versions.
*
@@ -301,27 +254,29 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
ResourceBundle.clearCache(); // Bundles loaded by the caller's classloader.
ResourceBundle.clearCache(ccl); // Bundles loaded by the context classloader (may be the same).
// Clear the bundle cache for any non-null delegated classloaders.
delegatedClassLoaderMap.forEach( (key, value) -> { if (value != null) ResourceBundle.clearCache(value) ;} );
delegatedClassLoaderMap.forEach((key, value) -> {
if (value != null) ResourceBundle.clearCache(value);
});
}
/**
* "Hacky" helper method that attempts to clear the Tomcat <code>ResourceEntry</code>
* {@link Map} using knowledge of the Tomcat source code.
*
* <p>
* It relies on the {@link #TOMCAT_RESOURCE_ENTRIES_FIELD} field name, base class name
* {@link #TOMCAT_WEBAPP_CLASSLOADER_BASE}. and descendant class names {@link #TOMCAT_WEBAPP_CLASSLOADER},
* {@link #TOMCAT_PARALLEL_WEBAPP_CLASSLOADER}, to keep the values identified in the constants.
* It appears to be valid for Tomcat versions 7-10 so far, but could become invalid at any time in the future
* when the resource handling logic in Tomcat changes.
*
* <p>
* Note: With Java 9+, calling this method may result in "Illegal reflective access" warnings. Be aware
* its logic may fail in a future version of Java that blocks the reflection calls needed for this method.
* its logic may fail in a future version of Java that blocks the reflection calls needed for this method.
*/
private void clearTomcatCache() {
ClassLoader loader = getCurrentThreadContextClassLoader();
// no need for compilation here.
Class cl = loader.getClass();
Class superCl = cl.getSuperclass();
Class<?> cl = loader.getClass();
Class<?> superCl = cl.getSuperclass();
try {
if ((TOMCAT_WEBAPP_CLASSLOADER.equals(cl.getName()) || TOMCAT_PARALLEL_WEBAPP_CLASSLOADER.equals(cl.getName())) &&
@@ -348,19 +303,19 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
/**
* Helper method that is intended to clear a {@link Map} instance by name.
*
* <p>
* This method relies on reflection to perform its operations, and may be blocked in Java 9 and later,
* depending on the accessibility of the field.
*
* @param cl The {@link Class} of the obj parameter.
* @param obj The {@link Object} from which the named field is to be extracted (may be <code>null</code> for a static field).
* @param cl The {@link Class} of the obj parameter.
* @param obj The {@link Object} from which the named field is to be extracted (may be <code>null</code> for a static field).
* @param name The name of the field containing a {@link Map} reference.
* @throws NoSuchFieldException if a field accessed by this call does not exist.
* @throws IllegalAccessException if a field, method or or class accessed by this call cannot be accessed.
* @throws NoSuchMethodException if a method accessed by this call does not exist.
* @throws NoSuchFieldException if a field accessed by this call does not exist.
* @throws IllegalAccessException if a field, method or or class accessed by this call cannot be accessed.
* @throws NoSuchMethodException if a method accessed by this call does not exist.
* @throws InvocationTargetException if a method accessed by this call fails invocation.
*/
private void clearMap(Class cl, Object obj, String name)
private void clearMap(Class<?> cl, Object obj, String name)
throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Field field = cl.getDeclaredField(name);
@@ -372,7 +327,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
Object cache = field.get(obj);
synchronized (cache) {
Class ccl = cache.getClass();
Class<?> ccl = cache.getClass();
Method clearMethod = ccl.getMethod("clear");
clearMethod.invoke(cache);
}
@@ -416,7 +371,6 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
* flow of the {@link LocalizedTextProvider} implementation the descendant provides).
*
* @param searchDefaultBundlesFirst provide {@link String} "true" or "false" to set the flag state accordingly.
*
* @since 6.0.0
*/
@Inject(value = StrutsConstants.STRUTS_I18N_SEARCH_DEFAULTBUNDLES_FIRST, required = false)
@@ -424,20 +378,10 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
this.searchDefaultBundlesFirst = Boolean.parseBoolean(searchDefaultBundlesFirst);
}
/**
* 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) {
public ResourceBundle findResourceBundle(String bundleName, Locale locale) {
ClassLoader classLoader = getCurrentThreadContextClassLoader();
String key = createMissesKey(String.valueOf(classLoader.hashCode()), aBundleName, locale);
String key = createMissesKey(String.valueOf(classLoader.hashCode()), bundleName, locale);
if (missingBundles.contains(key)) {
return null;
@@ -448,7 +392,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
if (bundlesMap.containsKey(key)) {
bundle = bundlesMap.get(key);
} else {
bundle = ResourceBundle.getBundle(aBundleName, locale, classLoader);
bundle = ResourceBundle.getBundle(bundleName, locale, classLoader);
bundlesMap.putIfAbsent(key, bundle);
}
} catch (MissingResourceException ex) {
@@ -457,15 +401,15 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
if (bundlesMap.containsKey(key)) {
bundle = bundlesMap.get(key);
} else {
bundle = ResourceBundle.getBundle(aBundleName, locale, delegatedClassLoaderMap.get(classLoader.hashCode()));
bundle = ResourceBundle.getBundle(bundleName, locale, delegatedClassLoaderMap.get(classLoader.hashCode()));
bundlesMap.putIfAbsent(key, bundle);
}
} catch (MissingResourceException e) {
LOG.debug("Missing resource bundle [{}]!", aBundleName, e);
LOG.debug("Missing resource bundle [{}]!", bundleName, e);
missingBundles.add(key);
}
} else {
LOG.debug("Missing resource bundle [{}]!", aBundleName);
LOG.debug("Missing resource bundle [{}]!", bundleName);
missingBundles.add(key);
}
}
@@ -503,7 +447,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
* @return the default message.
*/
protected GetDefaultMessageReturnArg getDefaultMessage(String key, Locale locale, ValueStack valueStack, Object[] args,
String defaultMessage) {
String defaultMessage) {
GetDefaultMessageReturnArg result = null;
boolean found = true;
@@ -539,18 +483,18 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
* general key would be passed in the alternateKey parameter.
* </p>
*
* @param key the initial key to search for a value within the default resource bundles.
* @param alternateKey the alternate (fall-back) key to search for a value within the default resource bundles, if the initial key lookup fails.
* @param locale the {@link Locale} to be used for the default resource bundle lookup.
* @param valueStack the {@link ValueStack} associated with the operation.
* @param args the argument array for parameterized messages (may be <code>null</code>).
* @param defaultMessage the default message {@link String} to use if both key lookup operations fail.
* @param key the initial key to search for a value within the default resource bundles.
* @param alternateKey the alternate (fall-back) key to search for a value within the default resource bundles, if the initial key lookup fails.
* @param locale the {@link Locale} to be used for the default resource bundle lookup.
* @param valueStack the {@link ValueStack} associated with the operation.
* @param args the argument array for parameterized messages (may be <code>null</code>).
* @param defaultMessage the default message {@link String} to use if both key lookup operations fail.
* @return the {@link GetDefaultMessageReturnArg} result containing the processed message lookup (by key first, then alternateKey if key's lookup fails).
* If both key lookup operations fail, defaultMessage is used for processing.
* If defaultMessage is <code>null</code> then the return result may be <code>null</code>.
* If both key lookup operations fail, defaultMessage is used for processing.
* If defaultMessage is <code>null</code> then the return result may be <code>null</code>.
*/
protected GetDefaultMessageReturnArg getDefaultMessageWithAlternateKey(String key, String alternateKey, Locale locale, ValueStack valueStack,
Object[] args, String defaultMessage) {
Object[] args, String defaultMessage) {
GetDefaultMessageReturnArg result;
if (alternateKey == null || alternateKey.isEmpty()) {
result = getDefaultMessage(key, locale, valueStack, args, defaultMessage);
@@ -593,8 +537,8 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
*
* @return the message
*/
protected String findMessage(Class clazz, String key, String indexedKey, Locale locale, Object[] args, Set<String> checked,
ValueStack valueStack) {
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())) {
@@ -617,9 +561,9 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
}
// look in properties of implemented interfaces
Class[] interfaces = clazz.getInterfaces();
Class<?>[] interfaces = clazz.getInterfaces();
for (Class anInterface : interfaces) {
for (Class<?> anInterface : interfaces) {
msg = getMessage(anInterface.getName(), locale, key, valueStack, args);
if (msg != null) {
@@ -639,7 +583,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
if (clazz.isInterface()) {
interfaces = clazz.getInterfaces();
for (Class anInterface : interfaces) {
for (Class<?> anInterface : interfaces) {
msg = findMessage(anInterface, key, indexedKey, locale, args, checked, valueStack);
if (msg != null) {
@@ -655,6 +599,36 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
return null;
}
protected String extractIndexedName(String textKey) {
String indexedTextName = null;
// calculate indexedTextName (collection[*]) if applicable
if (textKey.contains("[")) {
int i = -1;
indexedTextName = textKey;
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;
}
}
return indexedTextName;
}
protected void logMissingText(Class<?> startClazz, String textKey, Locale locale, GetDefaultMessageReturnArg result, String indexedTextName) {
// could we find the text, if not log a WARN
if (unableToFindTextForKey(result) && LOG.isDebugEnabled()) {
String warn = "Unable to find text for key '" + textKey + "' ";
if (indexedTextName != null) {
warn += " or indexed key '" + indexedTextName + "' ";
}
warn += "in class '" + startClazz.getName() + "' and locale '" + locale + "'";
LOG.debug(warn);
}
}
static class MessageFormatKey {
String pattern;
Locale locale;
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2;
package org.apache.struts2.text;
import org.apache.struts2.util.ValueStack;
import org.apache.logging.log4j.LogManager;
@@ -16,8 +16,10 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2;
package org.apache.struts2.text;
import org.apache.struts2.ActionContext;
import org.apache.struts2.Unchainable;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.util.ValueStack;
@@ -0,0 +1,82 @@
/*
* 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 org.apache.struts2.text;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.ActionContext;
import org.apache.struts2.util.ValueStack;
import java.util.Locale;
import java.util.ResourceBundle;
/**
* Provides support for localization in the framework, it can be used to read only default bundles.
* <p>
* Note that unlike {@link StrutsLocalizedTextProvider}, this class {@link GlobalLocalizedTextProvider} will
* <em>only</em> search the default bundles for localized text.
*/
public class GlobalLocalizedTextProvider extends AbstractLocalizedTextProvider {
private static final Logger LOG = LogManager.getLogger(GlobalLocalizedTextProvider.class);
public GlobalLocalizedTextProvider() {
addDefaultResourceBundle(XWORK_MESSAGES_BUNDLE);
addDefaultResourceBundle(STRUTS_MESSAGES_BUNDLE);
}
@Override
public String findText(Class<?> startClazz, String textKey, Locale locale) {
return findText(startClazz, textKey, locale, textKey, new Object[0]);
}
@Override
public String findText(Class<?> startClazz, String textKey, Locale locale, String defaultMessage, Object[] args) {
ValueStack valueStack = ActionContext.getContext().getValueStack();
return findText(startClazz, textKey, locale, defaultMessage, args, valueStack);
}
@Override
public String findText(Class<?> startClazz, String textKey, Locale locale, String defaultMessage, Object[] args, ValueStack valueStack) {
if (textKey == null) {
LOG.debug("Key is null, short-circuit to default message");
return defaultMessage;
}
String indexedTextName = extractIndexedName(textKey);
// get default
GetDefaultMessageReturnArg result = getDefaultMessageWithAlternateKey(textKey, indexedTextName, locale, valueStack, args, defaultMessage);
logMissingText(startClazz, textKey, locale, result, indexedTextName);
return result != null ? result.message : null;
}
@Override
public String findText(ResourceBundle bundle, String textKey, Locale locale) {
return findText(bundle, textKey, locale, textKey, new Object[0]);
}
@Override
public String findText(ResourceBundle bundle, String textKey, Locale locale, String defaultMessage, Object[] args) {
ValueStack valueStack = ActionContext.getContext().getValueStack();
return findText(bundle, textKey, locale, defaultMessage, args, valueStack);
}
}
@@ -16,70 +16,80 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.util;
package org.apache.struts2.text;
import org.apache.struts2.ActionContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.util.ValueStack;
import java.io.Serializable;
import java.util.Locale;
import java.util.ResourceBundle;
/**
* Provides support for localization in the framework, it can be used to read only default bundles.
*
* Note that unlike {@link StrutsLocalizedTextProvider}, this class {@link GlobalLocalizedTextProvider} will
* <em>only</em> search the default bundles for localized text.
*/
public class GlobalLocalizedTextProvider extends AbstractLocalizedTextProvider {
private static final Logger LOG = LogManager.getLogger(GlobalLocalizedTextProvider.class);
public GlobalLocalizedTextProvider() {
addDefaultResourceBundle(XWORK_MESSAGES_BUNDLE);
addDefaultResourceBundle(STRUTS_MESSAGES_BUNDLE);
}
public interface LocalizedTextProvider extends Serializable {
/**
* Calls {@link #findText(Class aClass, String aTextName, Locale locale, String defaultMessage, Object[] args)}
* with aTextName as the default message.
* Returns a localized message for the specified key, aTextName. Neither the key nor the
* message is evaluated.
*
* @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)
* @param textKey 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 findText(Class aClass, String aTextName, Locale locale) {
return findText(aClass, aTextName, locale, aTextName, new Object[0]);
}
String findDefaultText(String textKey, Locale locale);
/**
* 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 textKey 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
*/
String findDefaultText(String textKey, Locale locale, Object[] params);
/**
* Finds the given resource bundle by it's name.
* <p>
* Finds a localized text message for the given key, aTextName. Both the key and the message
* Will use <code>Thread.currentThread().getContextClassLoader()</code> as the classloader.
* </p>
*
* @param bundleName the name of the bundle (usually it's FQN classname).
* @param locale the locale.
* @return the bundle, <tt>null</tt> if not found.
*/
ResourceBundle findResourceBundle(String bundleName, Locale locale);
/**
* Calls {@link #findText(Class startClazz, String textKey, Locale locale, String defaultMessage, Object[] args)}
* with textKey as the default message.
*
* @param startClazz class name
* @param textKey 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 startClazz, String textKey, Locale locale, String defaultMessage, Object[] args)
*/
String findText(Class<?> startClazz, String textKey, Locale locale);
/**
* Finds a localized text message for the given key, textKey. 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 the message in the default resource bundles.</li>
* <li>If not found, 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 startClazz the class whose name to use as the start point for the search
* @param textKey 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
@@ -87,42 +97,29 @@ public class GlobalLocalizedTextProvider extends AbstractLocalizedTextProvider {
* 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);
}
String findText(Class<?> startClazz, String textKey, Locale locale, String defaultMessage, Object[] args);
/**
* <p>
* Finds a localized text message for the given key, aTextName. Both the key and the message
* Finds a localized text message for the given key, textKey. 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 the message in the default resource bundles.</li>
* <li>If not found, 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 DEBUG level log warning 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 startClazz the class whose name to use as the start point for the search
* @param textKey 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
@@ -131,91 +128,66 @@ public class GlobalLocalizedTextProvider extends AbstractLocalizedTextProvider {
* 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 = getDefaultMessageWithAlternateKey(aTextName, 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;
}
String findText(Class<?> startClazz, String textKey, Locale locale, String defaultMessage, Object[] args, ValueStack valueStack);
/**
* <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
* @param bundle a resource bundle name
* @param textKey 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]);
}
String findText(ResourceBundle bundle, String textKey, Locale locale);
/**
* <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 textKey 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);
}
String findText(ResourceBundle bundle, String textKey, Locale locale, String defaultMessage, Object[] args);
/**
* Finds a localized text message for the given key, aTextName, in the specified resource
* bundle.
* <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>
* If a message is <b>not</b> found a WARN log will be logged.
*
* @param bundle the bundle
* @param textKey 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
*/
String findText(ResourceBundle bundle, String textKey, Locale locale, String defaultMessage, Object[] args, ValueStack valueStack);
/**
* Adds the bundle to the internal list of default bundles.
* If the bundle already exists in the list it will be re-added.
*
* @param bundleName the name of the bundle to add.
*/
void addDefaultResourceBundle(String bundleName);
}
@@ -16,7 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2;
package org.apache.struts2.text;
import org.apache.struts2.LocaleProvider;
import java.util.ResourceBundle;
@@ -39,7 +41,7 @@ public interface ResourceBundleTextProvider extends TextProvider {
*
* @param clazz the class to use for loading.
*/
void setClazz(Class clazz);
void setClazz(Class<?> clazz);
/**
* Set the LocaleProvider to use.
@@ -0,0 +1,213 @@
/*
* 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 org.apache.struts2.text;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.ActionContext;
import org.apache.struts2.ActionInvocation;
import org.apache.struts2.ModelDriven;
import org.apache.struts2.conversion.impl.XWorkConverter;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.util.ValueStack;
import org.apache.struts2.util.reflection.ReflectionProvider;
import java.beans.PropertyDescriptor;
import java.util.Locale;
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 StrutsLocalizedTextProvider extends AbstractLocalizedTextProvider {
private static final Logger LOG = LogManager.getLogger(StrutsLocalizedTextProvider.class);
private transient ReflectionProvider reflectionProvider;
public StrutsLocalizedTextProvider() {
addDefaultResourceBundle(XWORK_MESSAGES_BUNDLE);
addDefaultResourceBundle(STRUTS_MESSAGES_BUNDLE);
}
@Override
public String findText(Class<?> startClazz, String textKey, Locale locale) {
return findText(startClazz, textKey, locale, textKey, new Object[0]);
}
@Override
public String findText(Class<?> startClazz, String textKey, Locale locale, String defaultMessage, Object[] args) {
ValueStack valueStack = ActionContext.getContext().getValueStack();
return findText(startClazz, textKey, locale, defaultMessage, args, valueStack);
}
@Override
public String findText(Class<?> startClazz, String textKey, Locale locale, String defaultMessage, Object[] args,
ValueStack valueStack) {
if (textKey == null) {
LOG.debug("Key is null, short-circuit to default message");
return defaultMessage;
}
String indexedTextName = extractIndexedName(textKey);
// Allow for and track an early lookup for the message in the default resource bundles first, before searching the class hierarchy.
// The early lookup is only performed when the text provider has been configured to do so, otherwise follow the standard processing order.
boolean performedInitialDefaultBundlesMessageLookup = false;
GetDefaultMessageReturnArg result = null;
// If search default bundles first is set true, call alternative logic first.
if (searchDefaultBundlesFirst) {
result = getDefaultMessageWithAlternateKey(textKey, indexedTextName, locale, valueStack, args, defaultMessage);
performedInitialDefaultBundlesMessageLookup = true;
if (!unableToFindTextForKey(result)) {
return result.message; // Found a message in the default resource bundles for textKey or indexedTextName.
}
}
// search up class hierarchy
String msg = findMessage(startClazz, textKey, indexedTextName, locale, args, null, valueStack);
if (msg != null) {
return msg;
}
if (ModelDriven.class.isAssignableFrom(startClazz)) {
ActionContext context = ActionContext.getContext();
// search up model's class hierarchy
ActionInvocation actionInvocation = context.getActionInvocation();
// ActionInvocation may be null if we're being run from a Sitemesh filter, so we won't get model texts if this is null
if (actionInvocation != null) {
Object action = actionInvocation.getAction();
if (action instanceof ModelDriven) {
Object model = ((ModelDriven<?>) action).getModel();
if (model != null) {
msg = findMessage(model.getClass(), textKey, indexedTextName, locale, args, null, valueStack);
if (msg != null) {
return msg;
}
}
}
}
}
// nothing still? alright, search the package hierarchy now
for (Class<?> clazz = startClazz;
(clazz != null) && !clazz.equals(Object.class);
clazz = clazz.getSuperclass()) {
String basePackageName = clazz.getName();
while (basePackageName.lastIndexOf('.') != -1) {
basePackageName = basePackageName.substring(0, basePackageName.lastIndexOf('.'));
String packageName = basePackageName + ".package";
msg = getMessage(packageName, locale, textKey, valueStack, args);
if (msg != null) {
return msg;
}
if (indexedTextName != null) {
msg = getMessage(packageName, locale, indexedTextName, valueStack, args);
if (msg != null) {
return msg;
}
}
}
}
// see if it's a child property
int idx = textKey.indexOf('.');
if (idx != -1) {
String newKey = null;
String prop = null;
if (textKey.startsWith(XWorkConverter.CONVERSION_ERROR_PROPERTY_PREFIX)) {
idx = textKey.indexOf('.', XWorkConverter.CONVERSION_ERROR_PROPERTY_PREFIX.length());
if (idx != -1) {
prop = textKey.substring(XWorkConverter.CONVERSION_ERROR_PROPERTY_PREFIX.length(), idx);
newKey = XWorkConverter.CONVERSION_ERROR_PROPERTY_PREFIX + textKey.substring(idx + 1);
}
} else {
prop = textKey.substring(0, idx);
newKey = textKey.substring(idx + 1);
}
if (prop != null) {
Object obj = valueStack.findValue(prop);
try {
Object actionObj = reflectionProvider.getRealTarget(prop, valueStack.getContext(), valueStack.getRoot());
if (actionObj != null) {
PropertyDescriptor propertyDescriptor = reflectionProvider.getPropertyDescriptor(actionObj.getClass(), prop);
if (propertyDescriptor != null) {
Class<?> clazz = propertyDescriptor.getPropertyType();
if (clazz != null) {
if (obj != null) {
valueStack.push(obj);
}
msg = findText(clazz, newKey, locale, null, args);
if (obj != null) {
valueStack.pop();
}
if (msg != null) {
return msg;
}
}
}
}
} catch (Exception e) {
LOG.debug("unable to find property {}", prop, e);
}
}
}
// get default
// Note: The default bundles lookup may already have been performed (via alternate early lookup),
// so we check first to avoid repeating the same operation twice.
if (!performedInitialDefaultBundlesMessageLookup) {
result = getDefaultMessageWithAlternateKey(textKey, indexedTextName, locale, valueStack, args, defaultMessage);
}
logMissingText(startClazz, textKey, locale, result, indexedTextName);
return result != null ? result.message : null;
}
@Override
public String findText(ResourceBundle bundle, String textKey, Locale locale) {
return findText(bundle, textKey, locale, textKey, new Object[0]);
}
@Override
public String findText(ResourceBundle bundle, String textKey, Locale locale, String defaultMessage, Object[] args) {
ValueStack valueStack = ActionContext.getContext().getValueStack();
return findText(bundle, textKey, locale, defaultMessage, args, valueStack);
}
@Inject
public void setReflectionProvider(ReflectionProvider reflectionProvider) {
this.reflectionProvider = reflectionProvider;
}
}
@@ -16,8 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2;
package org.apache.struts2.text;
import org.apache.struts2.LocaleProviderFactory;
import org.apache.struts2.inject.Inject;
import java.util.ResourceBundle;
@@ -49,7 +50,7 @@ public class StrutsTextProviderFactory implements TextProviderFactory {
}
@Override
public TextProvider createInstance(Class clazz) {
public TextProvider createInstance(Class<?> clazz) {
TextProvider instance = getTextProvider(clazz);
if (instance instanceof ResourceBundleTextProvider) {
((ResourceBundleTextProvider) instance).setClazz(clazz);
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2;
package org.apache.struts2.text;
import org.apache.struts2.util.ValueStack;
@@ -33,9 +33,9 @@ import java.util.ResourceBundle;
* global texts to be defined for an application base class.
*
* <p>
* You can override {@link LocaleProvider#getLocale()} to change the behaviour of how
* You can override {@link org.apache.struts2.LocaleProvider#getLocale()} to change the behaviour of how
* to choose locale for the bundles that are returned. Typically you would
* use the {@link LocaleProvider} interface to get the users configured locale.
* use the {@link org.apache.struts2.LocaleProvider} interface to get the users configured locale.
* </p>
*
* <p>
@@ -56,7 +56,7 @@ import java.util.ResourceBundle;
* </p>
* @author Jason Carreira
* @author Rainer Hermanns
* @see LocaleProvider
* @see org.apache.struts2.LocaleProvider
* @see TextProviderSupport
*/
public interface TextProvider {
@@ -16,13 +16,13 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2;
package org.apache.struts2.text;
import java.util.ResourceBundle;
public interface TextProviderFactory {
TextProvider createInstance(Class clazz);
TextProvider createInstance(Class<?> clazz);
TextProvider createInstance(ResourceBundle bundle);
@@ -16,12 +16,19 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2;
package org.apache.struts2.text;
import org.apache.struts2.LocaleProvider;
import org.apache.struts2.LocaleProviderFactory;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.util.ValueStack;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
/**
* Default TextProvider implementation.
@@ -31,7 +38,7 @@ import java.util.*;
*/
public class TextProviderSupport implements ResourceBundleTextProvider {
protected Class clazz;
protected Class<?> clazz;
protected LocaleProvider localeProvider;
protected ResourceBundle bundle;
protected LocalizedTextProvider localizedTextProvider;
@@ -42,7 +49,7 @@ public class TextProviderSupport implements ResourceBundleTextProvider {
* @param clazz a clazz to use for reading the resource bundle.
* @param provider a locale provider.
*/
public TextProviderSupport(Class clazz, LocaleProvider provider, LocalizedTextProvider localizedTextProvider) {
public TextProviderSupport(Class<?> clazz, LocaleProvider provider, LocalizedTextProvider localizedTextProvider) {
this.clazz = clazz;
this.localeProvider = provider;
this.localizedTextProvider = localizedTextProvider;
@@ -72,7 +79,7 @@ public class TextProviderSupport implements ResourceBundleTextProvider {
* @param clazz a clazz to use for reading the resource bundle.
*/
@Override
public void setClazz(Class clazz) {
public void setClazz(Class<?> clazz) {
this.clazz = clazz;
}
@@ -103,13 +110,13 @@ public class TextProviderSupport implements ResourceBundleTextProvider {
* class.
*/
public boolean hasKey(String key) {
String message;
if (clazz != null) {
message = localizedTextProvider.findText(clazz, key, getLocale(), null, new Object[0] );
String message;
if (clazz != null) {
message = localizedTextProvider.findText(clazz, key, getLocale(), null, new Object[0]);
} else {
message = localizedTextProvider.findText(bundle, key, getLocale(), null, new Object[0]);
}
return message != null;
return message != null;
}
/**
@@ -135,7 +142,7 @@ public class TextProviderSupport implements ResourceBundleTextProvider {
* a cascading style that allow global texts to be defined for an application base
* class. If no text is found for this text name, the default value is returned.
*
* @param key name of text to be found
* @param key name of text to be found
* @param defaultValue the default value which will be returned if no text is found
* @return value of named text or the provided defaultValue if no value is found
*/
@@ -151,7 +158,7 @@ public class TextProviderSupport implements ResourceBundleTextProvider {
* a cascading style that allow global texts to be defined for an application base
* class. If no text is found for this text name, the default value is returned.
*
* @param key name of text to be found
* @param key name of text to be found
* @param defaultValue the default value which will be returned if no text is found
* @return value of named text or the provided defaultValue if no value is found
*/
@@ -169,8 +176,8 @@ public class TextProviderSupport implements ResourceBundleTextProvider {
* a cascading style that allow global texts to be defined for an application base
* class. If no text is found for this text name, the default value is returned.
*
* @param key name of text to be found
* @param args a List of args to be used in a MessageFormat message
* @param key name of text to be found
* @param args a List of args to be used in a MessageFormat message
* @return value of named text or the provided key if no value is found
*/
public String getText(String key, List<?> args) {
@@ -185,8 +192,8 @@ public class TextProviderSupport implements ResourceBundleTextProvider {
* a cascading style that allow global texts to be defined for an application base
* class. If no text is found for this text name, the default value is returned.
*
* @param key name of text to be found
* @param args an array of args to be used in a MessageFormat message
* @param key name of text to be found
* @param args an array of args to be used in a MessageFormat message
* @return value of named text or the provided key if no value is found
*/
public String getText(String key, String[] args) {
@@ -201,7 +208,7 @@ public class TextProviderSupport implements ResourceBundleTextProvider {
* a cascading style that allow global texts to be defined for an application base
* class. If no text is found for this text name, the default value is returned.
*
* @param key name of text to be found
* @param key name of text to be found
* @param defaultValue the default value which will be returned if no text is found
* @param args a List of args to be used in a MessageFormat message
* @return value of named text or the provided defaultValue if no value is found
@@ -242,7 +249,7 @@ public class TextProviderSupport implements ResourceBundleTextProvider {
* default value is returned. Instead of using the value stack in the ActionContext
* this version of the getText() method uses the provided value stack.
*
* @param key the resource bundle key that is to be searched for
* @param key the resource bundle key that is to be searched for
* @param defaultValue the default value which will be returned if no message is found
* @param args a list args to be used in a {@link java.text.MessageFormat} message
* @param stack the value stack to use for finding the text
@@ -251,10 +258,10 @@ public class TextProviderSupport implements ResourceBundleTextProvider {
public String getText(String key, String defaultValue, List<?> args, ValueStack stack) {
Object[] argsArray = ((args != null) ? args.toArray() : null);
Locale locale;
if (stack == null){
locale = getLocale();
}else{
locale = stack.getActionContext().getLocale();
if (stack == null) {
locale = getLocale();
} else {
locale = stack.getActionContext().getLocale();
}
if (locale == null) {
locale = getLocale();
@@ -266,7 +273,6 @@ public class TextProviderSupport implements ResourceBundleTextProvider {
}
}
/**
* Gets a message based on a key using the supplied args, as defined in
* {@link java.text.MessageFormat}, or, if the message is not found, a supplied
@@ -280,21 +286,7 @@ public class TextProviderSupport implements ResourceBundleTextProvider {
* @return the message as found in the resource bundle, or defaultValue if none is found
*/
public String getText(String key, String defaultValue, String[] args, ValueStack stack) {
Locale locale;
if (stack == null){
locale = getLocale();
}else{
locale = stack.getActionContext().getLocale();
}
if (locale == null) {
locale = getLocale();
}
if (clazz != null) {
return localizedTextProvider.findText(clazz, key, locale, defaultValue, args, stack);
} else {
return localizedTextProvider.findText(bundle, key, locale, defaultValue, args, stack);
}
return getText(key, defaultValue, args != null ? Arrays.stream(args).toList() : List.of(), stack);
}
/**
@@ -18,7 +18,7 @@
*/
package org.apache.struts2.util;
import org.apache.struts2.TextProvider;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.interceptor.ValidationAware;
import org.apache.logging.log4j.Logger;
@@ -1,382 +0,0 @@
/*
* 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 org.apache.struts2.util;
import org.apache.struts2.ActionContext;
import org.apache.struts2.ActionInvocation;
import org.apache.struts2.ModelDriven;
import org.apache.struts2.conversion.impl.XWorkConverter;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.util.reflection.ReflectionProvider;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.beans.PropertyDescriptor;
import java.util.Locale;
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 StrutsLocalizedTextProvider extends AbstractLocalizedTextProvider {
private static final Logger LOG = LogManager.getLogger(StrutsLocalizedTextProvider.class);
private transient ReflectionProvider reflectionProvider;
public StrutsLocalizedTextProvider() {
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>If {@link #searchDefaultBundlesFirst} is <code>true</code>, look for the message in the default resource bundles first.</li>
* <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 from the 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
* (Note: the lookup is not repeated again if {@link #searchDefaultBundlesFirst} was <code>true</code>).</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>If {@link #searchDefaultBundlesFirst} is <code>true</code>, look for the message in the default resource bundles first.</li>
* <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 from the 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
* (Note: the lookup is not repeated again if {@link #searchDefaultBundlesFirst} was <code>true</code>).</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 DEBUG level log warning 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;
}
}
// Allow for and track an early lookup for the message in the default resource bundles first, before searching the class hierarchy.
// The early lookup is only performed when the text provider has been configured to do so, otherwise follow the standard processing order.
boolean performedInitialDefaultBundlesMessageLookup = false;
GetDefaultMessageReturnArg result = null;
// If search default bundles first is set true, call alternative logic first.
if (searchDefaultBundlesFirst) {
result = getDefaultMessageWithAlternateKey(aTextName, indexedTextName, locale, valueStack, args, defaultMessage);
performedInitialDefaultBundlesMessageLookup = true;
if (!unableToFindTextForKey(result)) {
return result.message; // Found a message in the default resource bundles for aTextName or indexedTextName.
}
}
// search up class hierarchy
String msg = findMessage(aClass, aTextName, indexedTextName, locale, args, null, valueStack);
if (msg != null) {
return msg;
}
if (ModelDriven.class.isAssignableFrom(aClass)) {
ActionContext context = ActionContext.getContext();
// search up model's class hierarchy
ActionInvocation actionInvocation = context.getActionInvocation();
// ActionInvocation may be null if we're being run from a Sitemesh filter, so we won't get model texts if this is null
if (actionInvocation != null) {
Object action = actionInvocation.getAction();
if (action instanceof ModelDriven) {
Object model = ((ModelDriven) action).getModel();
if (model != null) {
msg = findMessage(model.getClass(), aTextName, indexedTextName, locale, args, null, valueStack);
if (msg != null) {
return msg;
}
}
}
}
}
// nothing still? alright, search the package hierarchy now
for (Class clazz = aClass;
(clazz != null) && !clazz.equals(Object.class);
clazz = clazz.getSuperclass()) {
String basePackageName = clazz.getName();
while (basePackageName.lastIndexOf('.') != -1) {
basePackageName = basePackageName.substring(0, basePackageName.lastIndexOf('.'));
String packageName = basePackageName + ".package";
msg = getMessage(packageName, locale, aTextName, valueStack, args);
if (msg != null) {
return msg;
}
if (indexedTextName != null) {
msg = getMessage(packageName, locale, indexedTextName, valueStack, args);
if (msg != null) {
return msg;
}
}
}
}
// see if it's a child property
int idx = aTextName.indexOf('.');
if (idx != -1) {
String newKey = null;
String prop = null;
if (aTextName.startsWith(XWorkConverter.CONVERSION_ERROR_PROPERTY_PREFIX)) {
idx = aTextName.indexOf('.', XWorkConverter.CONVERSION_ERROR_PROPERTY_PREFIX.length());
if (idx != -1) {
prop = aTextName.substring(XWorkConverter.CONVERSION_ERROR_PROPERTY_PREFIX.length(), idx);
newKey = XWorkConverter.CONVERSION_ERROR_PROPERTY_PREFIX + aTextName.substring(idx + 1);
}
} else {
prop = aTextName.substring(0, idx);
newKey = aTextName.substring(idx + 1);
}
if (prop != null) {
Object obj = valueStack.findValue(prop);
try {
Object actionObj = reflectionProvider.getRealTarget(prop, valueStack.getContext(), valueStack.getRoot());
if (actionObj != null) {
PropertyDescriptor propertyDescriptor = reflectionProvider.getPropertyDescriptor(actionObj.getClass(), prop);
if (propertyDescriptor != null) {
Class clazz = propertyDescriptor.getPropertyType();
if (clazz != null) {
if (obj != null) {
valueStack.push(obj);
}
msg = findText(clazz, newKey, locale, null, args);
if (obj != null) {
valueStack.pop();
}
if (msg != null) {
return msg;
}
}
}
}
} catch (Exception e) {
LOG.debug("unable to find property {}", prop, e);
}
}
}
// get default
// Note: The default bundles lookup may already have been performed (via alternate early lookup),
// so we check first to avoid repeating the same operation twice.
if (!performedInitialDefaultBundlesMessageLookup) {
result = getDefaultMessageWithAlternateKey(aTextName, 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(java.util.ResourceBundle, String, java.util.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);
}
@Inject
public void setReflectionProvider(ReflectionProvider reflectionProvider) {
this.reflectionProvider = reflectionProvider;
}
}
@@ -18,8 +18,7 @@
*/
package org.apache.struts2.util;
import org.apache.struts2.TextProvider;
import org.apache.struts2.util.ValueStack;
import org.apache.struts2.text.TextProvider;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -19,7 +19,7 @@
package org.apache.struts2.util;
import org.apache.struts2.ActionContext;
import org.apache.struts2.LocalizedTextProvider;
import org.apache.struts2.text.LocalizedTextProvider;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.dispatcher.Parameter;
@@ -21,7 +21,7 @@ package org.apache.struts2.validator;
import org.apache.struts2.ActionContext;
import org.apache.struts2.FileManager;
import org.apache.struts2.FileManagerFactory;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.util.ClassLoaderUtil;
import org.apache.struts2.util.ValueStack;
@@ -21,11 +21,11 @@ package org.apache.struts2.validator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.ActionContext;
import org.apache.struts2.CompositeTextProvider;
import org.apache.struts2.text.CompositeTextProvider;
import org.apache.struts2.LocaleProvider;
import org.apache.struts2.LocaleProviderFactory;
import org.apache.struts2.TextProvider;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.interceptor.ValidationAware;
import org.apache.struts2.util.ValueStack;
@@ -19,7 +19,7 @@
package org.apache.struts2.validator;
import org.apache.struts2.LocaleProvider;
import org.apache.struts2.TextProvider;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.interceptor.ValidationAware;
/**
@@ -18,7 +18,7 @@
*/
package org.apache.struts2.validator.validators;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.util.TextParseUtil;
import org.apache.struts2.util.ValueStack;
@@ -19,8 +19,8 @@
package org.apache.struts2.validator.validators;
import org.apache.struts2.ActionContext;
import org.apache.struts2.CompositeTextProvider;
import org.apache.struts2.TextProvider;
import org.apache.struts2.text.CompositeTextProvider;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.util.ValueStack;
import org.apache.struts2.validator.ActionValidatorManager;
+7 -7
View File
@@ -128,15 +128,15 @@
<bean type="org.apache.struts2.conversion.impl.StringConverter" name="struts"
class="org.apache.struts2.conversion.impl.StringConverter" scope="singleton"/>
<bean type="org.apache.struts2.LocalizedTextProvider" name="global-only"
class="org.apache.struts2.util.GlobalLocalizedTextProvider" scope="singleton"/>
<bean type="org.apache.struts2.LocalizedTextProvider" name="struts"
class="org.apache.struts2.util.StrutsLocalizedTextProvider" scope="singleton"/>
<bean type="org.apache.struts2.text.LocalizedTextProvider" name="global-only"
class="org.apache.struts2.text.GlobalLocalizedTextProvider" scope="singleton"/>
<bean type="org.apache.struts2.text.LocalizedTextProvider" name="struts"
class="org.apache.struts2.text.StrutsLocalizedTextProvider" scope="singleton"/>
<bean type="org.apache.struts2.TextProvider" name="system" class="org.apache.struts2.DefaultTextProvider"
<bean type="org.apache.struts2.text.TextProvider" name="system" class="org.apache.struts2.text.DefaultTextProvider"
scope="singleton"/>
<bean type="org.apache.struts2.TextProviderFactory" name="struts"
class="org.apache.struts2.StrutsTextProviderFactory" scope="singleton"/>
<bean type="org.apache.struts2.text.TextProviderFactory" name="struts"
class="org.apache.struts2.text.StrutsTextProviderFactory" scope="singleton"/>
<bean type="org.apache.struts2.LocaleProviderFactory" name="struts"
class="org.apache.struts2.DefaultLocaleProviderFactory" scope="singleton"/>
@@ -20,6 +20,7 @@ package org.apache.struts2;
import org.apache.struts2.action.Action;
import org.apache.struts2.conversion.impl.ConversionData;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.util.ValueStack;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
@@ -20,6 +20,7 @@ package org.apache.struts2;
import org.apache.struts2.config.providers.MockConfigurationProvider;
import org.apache.struts2.config.providers.XmlConfigurationProvider;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.util.ValueStack;
import org.apache.struts2.util.ValueStackFactory;
import org.apache.struts2.config.StrutsXmlConfigurationProvider;
@@ -27,7 +27,7 @@ import org.apache.struts2.interceptor.parameter.StrutsParameter;
* @author Jason Carreira
* Created Apr 8, 2003 6:27:29 PM
*/
public class ModelDrivenAction extends ActionSupport implements ModelDriven {
public class ModelDrivenAction extends ActionSupport implements ModelDriven<TestBean> {
private String foo;
private final TestBean model = new TestBean();
@@ -20,6 +20,7 @@ package org.apache.struts2;
import org.apache.struts2.mock.DummyTextProvider;
import org.apache.struts2.mock.InjectableAction;
import org.apache.struts2.text.TextProvider;
import java.util.HashMap;
@@ -18,7 +18,7 @@
*/
package org.apache.struts2.components;
import org.apache.struts2.LocalizedTextProvider;
import org.apache.struts2.text.LocalizedTextProvider;
import org.apache.struts2.StrutsException;
import org.apache.struts2.TestConfigurationProvider;
import org.apache.struts2.views.jsp.AbstractTagTest;
@@ -18,7 +18,7 @@
*/
package org.apache.struts2.config;
import org.apache.struts2.LocalizedTextProvider;
import org.apache.struts2.text.LocalizedTextProvider;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.StrutsInternalTestCase;
@@ -21,8 +21,7 @@ package org.apache.struts2.config;
import java.util.Locale;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.LocalizedTextProvider;
import org.apache.struts2.config.ConfigurationException;
import org.apache.struts2.text.LocalizedTextProvider;
import org.apache.struts2.test.StubConfigurationProvider;
import org.apache.struts2.StrutsConstants;
@@ -52,7 +52,7 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase
Class.forName("org.apache.struts2.interceptor.ConditionalInterceptor"),
Class.forName("org.apache.struts2.ActionSupport"),
Class.forName("org.apache.struts2.result.ActionChainResult"),
Class.forName("org.apache.struts2.TextProvider"),
Class.forName("org.apache.struts2.text.TextProvider"),
Class.forName("org.apache.struts2.interceptor.NoOpInterceptor"),
Class.forName("org.apache.struts2.interceptor.Interceptor"),
Class.forName("java.lang.Object"),
@@ -77,7 +77,7 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase
Class.forName("org.apache.struts2.mock.MockResult"),
Class.forName("org.apache.struts2.interceptor.ConditionalInterceptor"),
Class.forName("org.apache.struts2.ActionSupport"),
Class.forName("org.apache.struts2.TextProvider"),
Class.forName("org.apache.struts2.text.TextProvider"),
Class.forName("org.apache.struts2.interceptor.Interceptor"),
Class.forName("java.lang.Object"),
Class.forName("org.apache.struts2.Validateable"),
@@ -101,7 +101,7 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase
Class.forName("org.apache.struts2.interceptor.ConditionalInterceptor"),
Class.forName("org.apache.struts2.ActionSupport"),
Class.forName("org.apache.struts2.result.ActionChainResult"),
Class.forName("org.apache.struts2.TextProvider"),
Class.forName("org.apache.struts2.text.TextProvider"),
Class.forName("org.apache.struts2.interceptor.NoOpInterceptor"),
Class.forName("org.apache.struts2.interceptor.Interceptor"),
Class.forName("java.lang.Object"),
@@ -19,7 +19,7 @@
package org.apache.struts2.conversion.impl;
import org.apache.struts2.ActionContext;
import org.apache.struts2.StubTextProvider;
import org.apache.struts2.text.StubTextProvider;
import org.apache.struts2.StubValueStack;
import org.apache.struts2.util.ValueStack;
import org.apache.struts2.StrutsInternalTestCase;
@@ -19,7 +19,7 @@
package org.apache.struts2.conversion.impl;
import org.apache.struts2.ActionContext;
import org.apache.struts2.StubTextProvider;
import org.apache.struts2.text.StubTextProvider;
import org.apache.struts2.StubValueStack;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.util.ValueStack;
@@ -21,10 +21,10 @@ package org.apache.struts2.conversion.impl;
import org.apache.struts2.ActionContext;
import org.apache.struts2.ModelDrivenAction;
import org.apache.struts2.SimpleAction;
import org.apache.struts2.StubTextProvider;
import org.apache.struts2.text.StubTextProvider;
import org.apache.struts2.StubValueStack;
import org.apache.struts2.TestBean;
import org.apache.struts2.TextProvider;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.ognl.OgnlValueStack;
import org.apache.struts2.test.ModelDrivenAction2;
@@ -19,7 +19,7 @@
package org.apache.struts2.dispatcher;
import org.apache.struts2.ActionContext;
import org.apache.struts2.LocalizedTextProvider;
import org.apache.struts2.text.LocalizedTextProvider;
import org.apache.struts2.ObjectFactory;
import org.apache.struts2.StubValueStack;
import org.apache.struts2.config.ConfigurationException;
@@ -25,7 +25,7 @@ import org.apache.struts2.ActionSupport;
import org.apache.struts2.ModelDrivenAction;
import org.apache.struts2.SimpleAction;
import org.apache.struts2.TestBean;
import org.apache.struts2.TextProvider;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.config.entities.ActionConfig;
import org.apache.struts2.config.providers.MockConfigurationProvider;
@@ -18,7 +18,7 @@
*/
package org.apache.struts2.mock;
import org.apache.struts2.TextProvider;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.util.ValueStack;
import java.util.List;
@@ -18,7 +18,7 @@
*/
package org.apache.struts2.mock;
import org.apache.struts2.TextProvider;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.inject.Inject;
public class InjectableAction {
@@ -19,7 +19,7 @@
package org.apache.struts2.ognl;
import org.apache.struts2.ActionContext;
import org.apache.struts2.StubTextProvider;
import org.apache.struts2.text.StubTextProvider;
import org.apache.struts2.StubValueStack;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.config.ConfigurationException;
@@ -20,7 +20,7 @@ package org.apache.struts2.ognl;
import org.apache.struts2.SimpleAction;
import org.apache.struts2.TestBean;
import org.apache.struts2.TextProvider;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.config.ConfigurationException;
import org.apache.struts2.conversion.impl.ConversionData;
@@ -30,7 +30,6 @@ public class ModelDrivenAction2 extends ModelDrivenAction {
private final TestBean2 model = new TestBean2();
/**
* @return the model to be pushed onto the ValueStack after the Action itself
*/
@@ -16,25 +16,20 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2;
package org.apache.struts2.text;
import org.apache.struts2.ActionContext;
import org.apache.struts2.XWorkTestCase;
import java.util.ArrayList;
import java.util.Locale;
import java.util.ResourceBundle;
/**
* <code>CompositeTextProviderTest</code>
*
* @author <a href="mailto:hermanns@aixcept.de">Rainer Hermanns</a>
* @version $Id$
*/
public class CompositeTextProviderTest extends XWorkTestCase {
private CompositeTextProvider textProvider = null;
public void testGetText() throws Exception {
public void testGetText() {
// we should get the text from the 1st text provider
assertEquals(textProvider.getText("name"), "1 name");
assertEquals(textProvider.getText("age"), "1 age");
@@ -45,8 +40,7 @@ public class CompositeTextProviderTest extends XWorkTestCase {
assertEquals(textProvider.getText("someNonExistingKey"), "someNonExistingKey");
}
public void testGetTextWithDefaultValues() throws Exception {
public void testGetTextWithDefaultValues() {
assertEquals(textProvider.getText("name", "some default name"), "1 name");
assertEquals(textProvider.getText("age", "some default age"), "1 age");
assertEquals(textProvider.getText("no_such_key", "default value"), "default value");
@@ -56,16 +50,24 @@ public class CompositeTextProviderTest extends XWorkTestCase {
assertEquals(textProvider.getText("bike", "some default bike"), "This is a bike");
}
public void testGetTextWithDefaultValuesAndArgs() throws Exception {
public void testGetTextWithDefaultValuesAndArgs() {
assertEquals(textProvider.getText("goodnight", "say good night", "Adam"), "1 good night Adam");
assertEquals(textProvider.getText("goodnight", "say good night", new String[] { "Adam" }), "1 good night Adam");
assertEquals(textProvider.getText("goodnight", "say good night", new ArrayList<Object>() { {add("Adam");} }), "1 good night Adam");
assertEquals(textProvider.getText("goodmorning", "say good morning", new String[] { "Jack", "Jim" }), "1 good morning Jack and Jim");
assertEquals(textProvider.getText("goodmorning", "say good morning", new ArrayList<Object>() { { add("Jack"); add("Jim"); }}), "1 good morning Jack and Jim");
assertEquals(textProvider.getText("goodnight", "say good night", new String[]{"Adam"}), "1 good night Adam");
assertEquals(textProvider.getText("goodnight", "say good night", new ArrayList<>() {
{
add("Adam");
}
}), "1 good night Adam");
assertEquals(textProvider.getText("goodmorning", "say good morning", new String[]{"Jack", "Jim"}), "1 good morning Jack and Jim");
assertEquals(textProvider.getText("goodmorning", "say good morning", new ArrayList<>() {
{
add("Jack");
add("Jim");
}
}), "1 good morning Jack and Jim");
}
public void testHasKey() throws Exception {
public void testHasKey() {
assertTrue(textProvider.hasKey("name"));
assertTrue(textProvider.hasKey("age"));
assertTrue(textProvider.hasKey("cat"));
@@ -77,15 +79,15 @@ public class CompositeTextProviderTest extends XWorkTestCase {
assertFalse(textProvider.hasKey("nosuchkey"));
}
public void testGetResourceBundleByName() throws Exception {
public void testGetResourceBundleByName() {
assertNotNull(textProvider.getTexts("org.apache.struts2.validator.CompositeTextProviderTestResourceBundle1"));
assertNotNull(textProvider.getTexts("org.apache.struts2.validator.CompositeTextProviderTestResourceBundle2"));
assertNull(textProvider.getTexts("org.apache.struts2.validator.CompositeTextProviderTestResourceBundle3"));
}
public void testGetResourceBundle() throws Exception {
public void testGetResourceBundle() {
assertNotNull(textProvider.getTexts());
// we should get the first resource bundle where 'car' and 'bike' has a i18n msg
// we should get the first resource bundle where 'car' and 'bike' has an i18n msg
assertNotNull(textProvider.getTexts().getString("car"));
assertNotNull(textProvider.getTexts().getString("bike"));
}
@@ -16,22 +16,20 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2;
package org.apache.struts2.text;
import org.apache.struts2.ActionContext;
import org.apache.struts2.XWorkTestCase;
import java.util.*;
/**
* Unit test for {@link DefaultTextProvider}.
*
* @author Claus Ibsen
*/
public class DefaultTextProviderTest extends XWorkTestCase {
private DefaultTextProvider tp;
public void testSimpleGetTexts() throws Exception {
public void testSimpleGetTexts() {
assertEquals("Hello World", tp.getText("hello"));
assertEquals(null, tp.getText("not.in.bundle"));
assertNull(tp.getText("not.in.bundle"));
assertEquals("Hello World", tp.getText("hello", "this is default"));
assertEquals("this is default", tp.getText("not.in.bundle", "this is default"));
@@ -43,16 +41,16 @@ public class DefaultTextProviderTest extends XWorkTestCase {
assertEquals("Hello World", tp.getText("hello", nullStrings));
}
public void testGetTextsWithArgs() throws Exception {
public void testGetTextsWithArgs() {
assertEquals("Hello World", tp.getText("hello", "this is default", "from me")); // no args in bundle
assertEquals("Hello World from me", tp.getText("hello.0", "this is default", "from me"));
assertEquals("this is default", tp.getText("not.in.bundle", "this is default", "from me"));
assertEquals("this is default from me", tp.getText("not.in.bundle", "this is default {0}", "from me"));
assertEquals(null, tp.getText("not.in.bundle"));
assertNull(tp.getText("not.in.bundle"));
}
public void testGetTextsWithListArgs() throws Exception {
public void testGetTextsWithListArgs() {
List<Object> args = new ArrayList<>();
args.add("Santa");
args.add("loud");
@@ -68,13 +66,13 @@ public class DefaultTextProviderTest extends XWorkTestCase {
assertEquals("Hello World Santa", tp.getText("hello.0", args)); // only 1 arg in bundle
assertEquals("Hello World. This is Santa speaking loud", tp.getText("hello.1", args));
assertEquals(null, tp.getText("not.in.bundle", args));
assertNull(tp.getText("not.in.bundle", args));
assertEquals("Hello World", tp.getText("hello", "this is default", (List) null));
assertEquals("this is default", tp.getText("not.in.bundle", "this is default", (List) null));
}
public void testGetTextsWithArrayArgs() throws Exception {
public void testGetTextsWithArrayArgs() {
String[] args = { "Santa", "loud" };
assertEquals("Hello World", tp.getText("hello", "this is default", args)); // no args in bundle
assertEquals("Hello World Santa", tp.getText("hello.0", "this is default", args)); // only 1 arg in bundle
@@ -88,13 +86,13 @@ public class DefaultTextProviderTest extends XWorkTestCase {
assertEquals("Hello World Santa", tp.getText("hello.0", args)); // only 1 arg in bundle
assertEquals("Hello World. This is Santa speaking loud", tp.getText("hello.1", args));
assertEquals(null, tp.getText("not.in.bundle", args));
assertNull(tp.getText("not.in.bundle", args));
assertEquals("Hello World", tp.getText("hello", "this is default", (String[]) null));
assertEquals("this is default", tp.getText("not.in.bundle", "this is default", (String[]) null));
}
public void testGetTextsWithListAndStack() throws Exception {
public void testGetTextsWithListAndStack() {
List<Object> args = new ArrayList<>();
args.add("Santa");
args.add("loud");
@@ -107,7 +105,7 @@ public class DefaultTextProviderTest extends XWorkTestCase {
assertEquals("this is default Santa speaking loud", tp.getText("not.in.bundle", "this is default {0} speaking {1}", args, null));
}
public void testGetTextsWithArrayAndStack() throws Exception {
public void testGetTextsWithArrayAndStack() {
String[] args = { "Santa", "loud" };
assertEquals("Hello World", tp.getText("hello", "this is default", args, null)); // no args in bundle
assertEquals("Hello World Santa", tp.getText("hello.0", "this is default", args, null)); // only 1 arg in bundle
@@ -118,7 +116,7 @@ public class DefaultTextProviderTest extends XWorkTestCase {
assertEquals("this is default Santa speaking loud", tp.getText("not.in.bundle", "this is default {0} speaking {1}", args, null));
}
public void testGetBundle() throws Exception {
public void testGetBundle() {
assertNull(tp.getTexts()); // always returns null
ResourceBundle rb = ResourceBundle.getBundle(TextProviderSupportTest.class.getName(), Locale.CANADA);
@@ -16,23 +16,24 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.util;
package org.apache.struts2.text;
import com.mockobjects.dynamic.Mock;
import org.apache.struts2.action.Action;
import org.apache.struts2.ActionContext;
import org.apache.struts2.ActionInvocation;
import org.apache.struts2.ActionProxy;
import org.apache.struts2.ActionSupport;
import org.apache.struts2.LocalizedTextProvider;
import org.apache.struts2.ModelDriven;
import org.apache.struts2.SimpleAction;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.action.Action;
import org.apache.struts2.config.StrutsXmlConfigurationProvider;
import org.apache.struts2.config.providers.XmlConfigurationProvider;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
import org.apache.struts2.test.ModelDrivenAction2;
import org.apache.struts2.test.TestBean2;
import org.apache.struts2.config.StrutsXmlConfigurationProvider;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
import org.apache.struts2.util.Bar;
import org.apache.struts2.util.ValueStack;
import java.text.DateFormat;
import java.text.ParseException;
@@ -41,19 +42,11 @@ import java.util.HashMap;
import java.util.Locale;
import java.util.ResourceBundle;
/**
* Unit test for {@link StrutsLocalizedTextProvider}.
*
* @author jcarreira
* @author tm_jee
* @version $Date$ $Id$
*/
public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
private LocalizedTextProvider localizedTextProvider;
public void testNpeWhenClassIsPrimitive() throws Exception {
public void testNpeWhenClassIsPrimitive() {
ValueStack stack = ActionContext.getContext().getValueStack();
stack.push(new MyObject());
String result = localizedTextProvider.findText(MyObject.class, "someObj.someI18nKey", Locale.ENGLISH, "default message", null, stack);
@@ -66,15 +59,15 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
}
}
public void testActionGetTextWithNullObject() throws Exception {
public void testActionGetTextWithNullObject() {
MyAction action = new MyAction();
container.inject(action);
Mock mockActionInvocation = new Mock(ActionInvocation.class);
mockActionInvocation.expectAndReturn("getAction", action);
ActionContext.getContext()
.withActionInvocation((ActionInvocation) mockActionInvocation.proxy())
.getValueStack().push(action);
.withActionInvocation((ActionInvocation) mockActionInvocation.proxy())
.getValueStack().push(action);
String message = action.getText("barObj.title");
assertEquals("Title:", message);
@@ -94,11 +87,11 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
}
}
public void testActionGetText() throws Exception {
public void testActionGetText() {
ModelDrivenAction2 action = new ModelDrivenAction2();
container.inject(action);
TestBean2 bean = (TestBean2) action.getModel();
TestBean2 bean = action.getModel();
Bar bar = new Bar();
bean.setBarObj(bar);
@@ -116,7 +109,7 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
localizedTextProvider.findText(this.getClass(), null, Locale.getDefault());
}
public void testActionGetTextXXX() throws Exception {
public void testActionGetTextXXX() {
localizedTextProvider.addDefaultResourceBundle("org/apache/struts2/util/FindMe");
SimpleAction action = new SimpleAction();
@@ -125,8 +118,8 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
Mock mockActionInvocation = new Mock(ActionInvocation.class);
mockActionInvocation.expectAndReturn("getAction", action);
ActionContext.getContext()
.withActionInvocation((ActionInvocation) mockActionInvocation.proxy())
.getValueStack().push(action);
.withActionInvocation((ActionInvocation) mockActionInvocation.proxy())
.getValueStack().push(action);
String message = action.getText("bean.name");
String foundBean2 = action.getText("bean2.name");
@@ -148,16 +141,16 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
public void testAddDefaultResourceBundle2() throws Exception {
localizedTextProvider.addDefaultResourceBundle("org/apache/struts2/SimpleAction");
ActionProxy proxy = actionProxyFactory.createActionProxy("/", "packagelessAction", null, new HashMap<String, Object>(), false, true);
ActionProxy proxy = actionProxyFactory.createActionProxy("/", "packagelessAction", null, new HashMap<>(), false, true);
proxy.execute();
}
public void testDefaultMessage() throws Exception {
public void testDefaultMessage() {
String message = localizedTextProvider.findDefaultText("xwork.error.action.execution", Locale.getDefault());
assertEquals("Error during Action invocation", message);
}
public void testDefaultMessageOverride() throws Exception {
public void testDefaultMessageOverride() {
String message = localizedTextProvider.findDefaultText("xwork.error.action.execution", Locale.getDefault());
assertEquals("Error during Action invocation", message);
@@ -167,8 +160,8 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
assertEquals("Testing resource bundle override", message);
}
public void testFindTextInChildProperty() throws Exception {
ModelDriven action = new ModelDrivenAction2();
public void testFindTextInChildProperty() {
ModelDriven<?> action = new ModelDrivenAction2();
TestBean2 bean = (TestBean2) action.getModel();
Bar bar = new Bar();
bean.setBarObj(bar);
@@ -184,7 +177,7 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
assertEquals("Title is invalid!", message);
}
public void testFindTextInInterface() throws Exception {
public void testFindTextInInterface() {
Action action = new ModelDrivenAction2();
Mock mockActionInvocation = new Mock(ActionInvocation.class);
mockActionInvocation.expectAndReturn("getAction", action);
@@ -194,8 +187,8 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
assertEquals("Foo!", message);
}
public void testFindTextInPackage() throws Exception {
ModelDriven action = new ModelDrivenAction2();
public void testFindTextInPackage() {
ModelDriven<?> action = new ModelDrivenAction2();
Mock mockActionInvocation = new Mock(ActionInvocation.class);
mockActionInvocation.expectAndReturn("getAction", action);
@@ -205,12 +198,12 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
assertEquals("It works!", message);
}
public void testParameterizedDefaultMessage() throws Exception {
public void testParameterizedDefaultMessage() {
String message = localizedTextProvider.findDefaultText("xwork.exception.missing-action", Locale.getDefault(), new String[]{"AddUser"});
assertEquals("There is no Action mapped for action name AddUser.", message);
}
public void testParameterizedDefaultMessageWithPackage() throws Exception {
public void testParameterizedDefaultMessageWithPackage() {
String message = localizedTextProvider.findDefaultText("xwork.exception.missing-package-action", Locale.getDefault(), new String[]{"blah", "AddUser"});
assertEquals("There is no Action mapped for namespace blah and action name AddUser.", message);
}
@@ -270,20 +263,18 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
*/
public void testLocalizedTextProviderClearingMethods() {
TestStrutsLocalizedTextProvider testStrutsLocalizedTextProvider = new TestStrutsLocalizedTextProvider();
assertTrue("testStrutsLocalizedTextProvider not instance of AbstractLocalizedTextProvider ?",
testStrutsLocalizedTextProvider instanceof AbstractLocalizedTextProvider);
assertEquals("testStrutsLocalizedTextProvider starting default bundle map size not 0 before any retrievals ?",
0, testStrutsLocalizedTextProvider.currentBundlesMapSize());
0, testStrutsLocalizedTextProvider.currentBundlesMapSize());
// Access the two default bundles to populate their cache entries and test bundle map size.
ResourceBundle tempBundle = testStrutsLocalizedTextProvider.findResourceBundle(
TestStrutsLocalizedTextProvider.XWORK_MESSAGES_BUNDLE, Locale.ENGLISH);
TestStrutsLocalizedTextProvider.XWORK_MESSAGES_BUNDLE, Locale.ENGLISH);
assertNotNull("XWORK_MESSAGES_BUNDLE retrieval null ?", tempBundle);
tempBundle = testStrutsLocalizedTextProvider.findResourceBundle(
TestStrutsLocalizedTextProvider.STRUTS_MESSAGES_BUNDLE, Locale.ENGLISH);
TestStrutsLocalizedTextProvider.STRUTS_MESSAGES_BUNDLE, Locale.ENGLISH);
assertNotNull("STRUTS_MESSAGES_BUNDLE retrieval null ?", tempBundle);
assertEquals("testStrutsLocalizedTextProvider bundle map size not 2 after retrievals ?",
2, testStrutsLocalizedTextProvider.currentBundlesMapSize());
2, testStrutsLocalizedTextProvider.currentBundlesMapSize());
// Add and then access four test bundles to populate their cache entries and test bundle map size.
testStrutsLocalizedTextProvider.addDefaultResourceBundle("org/apache/struts2/util/LocalizedTextUtilTest");
@@ -291,34 +282,34 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
testStrutsLocalizedTextProvider.addDefaultResourceBundle("org/apache/struts2/SimpleAction");
testStrutsLocalizedTextProvider.addDefaultResourceBundle("org/apache/struts2/test");
tempBundle = testStrutsLocalizedTextProvider.findResourceBundle(
"org/apache/struts2/util/LocalizedTextUtilTest", Locale.ENGLISH);
"org/apache/struts2/util/LocalizedTextUtilTest", Locale.ENGLISH);
assertNotNull("org/apache/struts2/util/LocalizedTextUtilTest retrieval null ?", tempBundle);
tempBundle = testStrutsLocalizedTextProvider.findResourceBundle(
"org/apache/struts2/util/FindMe", Locale.ENGLISH);
"org/apache/struts2/util/FindMe", Locale.ENGLISH);
assertNotNull("org/apache/struts2/util/FindMe retrieval null ?", tempBundle);
tempBundle = testStrutsLocalizedTextProvider.findResourceBundle(
"org/apache/struts2/SimpleAction", Locale.ENGLISH);
"org/apache/struts2/SimpleAction", Locale.ENGLISH);
assertNotNull("org/apache/struts2/SimpleAction retrieval null ?", tempBundle);
tempBundle = testStrutsLocalizedTextProvider.findResourceBundle(
"org/apache/struts2/test", Locale.ENGLISH);
"org/apache/struts2/test", Locale.ENGLISH);
assertNotNull("org/apache/struts2/test retrieval null ?", tempBundle);
assertEquals("testStrutsLocalizedTextProvider bundle map size not 6 after retrievals ?",
6, testStrutsLocalizedTextProvider.currentBundlesMapSize());
6, testStrutsLocalizedTextProvider.currentBundlesMapSize());
// Expect the call to function with bundle name + locale. Remove all four of the non-default
// bundles and confirm the bundle map size changes.
testStrutsLocalizedTextProvider.callClearBundleWithLocale("org/apache/struts2/test", Locale.ENGLISH);
assertEquals("testStrutsLocalizedTextProvider bundle map size not 5 after locale clear call ?",
5, testStrutsLocalizedTextProvider.currentBundlesMapSize());
5, testStrutsLocalizedTextProvider.currentBundlesMapSize());
testStrutsLocalizedTextProvider.callClearBundleWithLocale("org/apache/struts2/SimpleAction", Locale.ENGLISH);
assertEquals("testStrutsLocalizedTextProvider bundle map size not 4 after locale clear call ?",
4, testStrutsLocalizedTextProvider.currentBundlesMapSize());
4, testStrutsLocalizedTextProvider.currentBundlesMapSize());
testStrutsLocalizedTextProvider.callClearBundleWithLocale("org/apache/struts2/util/FindMe", Locale.ENGLISH);
assertEquals("testStrutsLocalizedTextProvider bundle map size not 3 after locale clear call ?",
3, testStrutsLocalizedTextProvider.currentBundlesMapSize());
3, testStrutsLocalizedTextProvider.currentBundlesMapSize());
testStrutsLocalizedTextProvider.callClearBundleWithLocale("org/apache/struts2/util/LocalizedTextUtilTest", Locale.ENGLISH);
assertEquals("testStrutsLocalizedTextProvider bundle map size not 2 after locale clear call ?",
2, testStrutsLocalizedTextProvider.currentBundlesMapSize());
2, testStrutsLocalizedTextProvider.currentBundlesMapSize());
// Confirm the missing bundles cache clearing method does not produce any Exceptions or failures.
testStrutsLocalizedTextProvider.callClearMissingBundlesCache();
@@ -332,20 +323,18 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
*/
public void testLocalizedTextProviderReloadMethods() {
TestStrutsLocalizedTextProvider testStrutsLocalizedTextProvider = new TestStrutsLocalizedTextProvider();
assertTrue("testStrutsLocalizedTextProvider not instance of AbstractLocalizedTextProvider ?",
testStrutsLocalizedTextProvider instanceof AbstractLocalizedTextProvider);
assertEquals("testStrutsLocalizedTextProvider starting default bundle map size not 0 before any retrievals ?",
0, testStrutsLocalizedTextProvider.currentBundlesMapSize());
0, testStrutsLocalizedTextProvider.currentBundlesMapSize());
// Access the two default bundles to populate their cache entries and test bundle map size.
ResourceBundle tempBundle = testStrutsLocalizedTextProvider.findResourceBundle(
TestStrutsLocalizedTextProvider.XWORK_MESSAGES_BUNDLE, Locale.ENGLISH);
TestStrutsLocalizedTextProvider.XWORK_MESSAGES_BUNDLE, Locale.ENGLISH);
assertNotNull("XWORK_MESSAGES_BUNDLE retrieval null ?", tempBundle);
tempBundle = testStrutsLocalizedTextProvider.findResourceBundle(
TestStrutsLocalizedTextProvider.STRUTS_MESSAGES_BUNDLE, Locale.ENGLISH);
TestStrutsLocalizedTextProvider.STRUTS_MESSAGES_BUNDLE, Locale.ENGLISH);
assertNotNull("STRUTS_MESSAGES_BUNDLE retrieval null ?", tempBundle);
assertEquals("testStrutsLocalizedTextProvider bundle map size not 2 after retrievals ?",
2, testStrutsLocalizedTextProvider.currentBundlesMapSize());
2, testStrutsLocalizedTextProvider.currentBundlesMapSize());
// Force a bundle reload call for code coverage and to confirm it causes the bundle map to be emptied.
assertNotNull("ActionContext is somehow null ?", ActionContext.getContext());
@@ -355,17 +344,17 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
boolean bundlesReloadedAfterCall = testStrutsLocalizedTextProvider.getBundlesReloadedIndicatorValue();
assertTrue("Bundles reload value false after forced reload ?", bundlesReloadedAfterCall);
assertEquals("testStrutsLocalizedTextProvider bundle map size not 0 after reload (which should clear it) ?",
0, testStrutsLocalizedTextProvider.currentBundlesMapSize());
0, testStrutsLocalizedTextProvider.currentBundlesMapSize());
// Access the two default bundles again (after reload) to populate their cache entries and test bundle map size.
tempBundle = testStrutsLocalizedTextProvider.findResourceBundle(
TestStrutsLocalizedTextProvider.XWORK_MESSAGES_BUNDLE, Locale.ENGLISH);
TestStrutsLocalizedTextProvider.XWORK_MESSAGES_BUNDLE, Locale.ENGLISH);
assertNotNull("XWORK_MESSAGES_BUNDLE retrieval null ?", tempBundle);
tempBundle = testStrutsLocalizedTextProvider.findResourceBundle(
TestStrutsLocalizedTextProvider.STRUTS_MESSAGES_BUNDLE, Locale.ENGLISH);
TestStrutsLocalizedTextProvider.STRUTS_MESSAGES_BUNDLE, Locale.ENGLISH);
assertNotNull("STRUTS_MESSAGES_BUNDLE retrieval null ?", tempBundle);
assertEquals("testStrutsLocalizedTextProvider bundle map size not 2 after retrievals ?",
2, testStrutsLocalizedTextProvider.currentBundlesMapSize());
2, testStrutsLocalizedTextProvider.currentBundlesMapSize());
}
/**
@@ -391,7 +380,7 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
final String DEFAULT_MESSAGE_WITH_PARAMS = DEFAULT_MESSAGE + " We provide a couple of parameter placeholders: -{0}- and -{1}- for fun.";
final String param1 = "param1_String";
final String param2 = "param2_String";
final String[] paramArray = { param1, param2 };
final String[] paramArray = {param1, param2};
TestStrutsLocalizedTextProvider testStrutsLocalizedTextProvider = new TestStrutsLocalizedTextProvider();
// Load some specific default bundles already provided and used by other tests within this module.
@@ -457,7 +446,7 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
/**
* Test the {@link StrutsLocalizedTextProvider#findText(java.lang.Class, java.lang.String, java.util.Locale, java.lang.String, java.lang.Object[], org.apache.struts2.util.ValueStack) }
* method for basic correctness.
*
* <p>
* It is the version of the method that will search the class hierarchy resource bundles first, unless {@link StrutsLocalizedTextProvider#searchDefaultBundlesFirst}
* is true (in which case it will search the default resource bundles first). No matter the flag setting, it should search until it finds a match, or fails to find
* a match and returns the default message parameter that was passed.
@@ -469,7 +458,7 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
final String DEFAULT_MESSAGE_WITH_PARAMS = DEFAULT_MESSAGE + " We provide a couple of parameter placeholders: -{0}- and -{1}- for fun.";
final String param1 = "param1_String";
final String param2 = "param2_String";
final String[] paramArray = { param1, param2 };
final String[] paramArray = {param1, param2};
TestStrutsLocalizedTextProvider testStrutsLocalizedTextProvider = new TestStrutsLocalizedTextProvider();
// Load some specific default bundles already provided and used by other tests within this module.
@@ -585,7 +574,7 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
/**
* Some test correctness depends on this {@link #RELOADED} value matching that of the private ancestor
* field {@link AbstractLocalizedTextProvider#RELOADED}. If the ancestor field value changes, ensure this
* field {@link AbstractLocalizedTextProvider#RELOADED}. If the ancestor field value changes, ensure this
* field's value is updated to match it exactly.
*/
private static final String RELOADED = "org.apache.struts2.util.LocalizedTextProvider.reloaded";
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2;
package org.apache.struts2.text;
import org.apache.struts2.util.ValueStack;
@@ -16,29 +16,27 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2;
package org.apache.struts2.text;
import org.apache.struts2.LocaleProvider;
import org.apache.struts2.XWorkTestCase;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
/**
* Unit test for {@link TextProviderSupport}.
*
* @author Claus Ibsen
*/
public class TextProviderSupportTest extends XWorkTestCase {
private TextProviderSupport tp;
private java.util.ResourceBundle rb;
public void testHasKey() throws Exception {
assertTrue(tp.hasKey("hello"));
assertFalse(tp.hasKey("not.in.bundle"));
public void testHasKey() {
assertTrue(tp.hasKey("hello"));
assertFalse(tp.hasKey("not.in.bundle"));
}
public void testSimpleGetTexts() throws Exception {
public void testSimpleGetTexts() {
assertEquals("Hello World", tp.getText("hello"));
assertEquals("not.in.bundle", tp.getText("not.in.bundle"));
@@ -46,7 +44,7 @@ public class TextProviderSupportTest extends XWorkTestCase {
assertEquals("this is default", tp.getText("not.in.bundle", "this is default"));
}
public void testGetTextsWithArgs() throws Exception {
public void testGetTextsWithArgs() {
assertEquals("Hello World", tp.getText("hello", "this is default", "from me")); // no args in bundle
assertEquals("Hello World from me", tp.getText("hello.0", "this is default", "from me"));
assertEquals("this is default", tp.getText("not.in.bundle", "this is default", "from me"));
@@ -55,7 +53,7 @@ public class TextProviderSupportTest extends XWorkTestCase {
assertEquals("not.in.bundle", tp.getText("not.in.bundle"));
}
public void testGetTextsWithListArgs() throws Exception {
public void testGetTextsWithListArgs() {
List<Object> args = new ArrayList<>();
args.add("Santa");
args.add("loud");
@@ -74,8 +72,8 @@ public class TextProviderSupportTest extends XWorkTestCase {
assertEquals("not.in.bundle", tp.getText("not.in.bundle", args));
}
public void testGetTextsWithArrayArgs() throws Exception {
String[] args = { "Santa", "loud" };
public void testGetTextsWithArrayArgs() {
String[] args = {"Santa", "loud"};
assertEquals("Hello World", tp.getText("hello", "this is default", args)); // no args in bundle
assertEquals("Hello World Santa", tp.getText("hello.0", "this is default", args)); // only 1 arg in bundle
assertEquals("Hello World. This is Santa speaking loud", tp.getText("hello.1", "this is default", args));
@@ -91,18 +89,18 @@ public class TextProviderSupportTest extends XWorkTestCase {
assertEquals("not.in.bundle", tp.getText("not.in.bundle", args));
}
public void testGetBundle() throws Exception {
public void testGetBundle() {
assertEquals(rb, tp.getTexts());
assertEquals(rb, tp.getTexts(TextProviderSupportTest.class.getName()));
}
public void testDifficultSymbols1() {
String val= tp.getText("symbols1");
String val = tp.getText("symbols1");
assertEquals("\"=!@#$%^&*(){qwe}<>?:|}{[]\\';/.,<>`~'", val);
}
public void testDifficultSymbols2() {
String val= tp.getText("symbols2");
String val = tp.getText("symbols2");
assertEquals("\"=!@#$%^&*()<>?:|[]\\';/.,<>`~'", val);
}
@@ -132,6 +130,7 @@ public class TextProviderSupportTest extends XWorkTestCase {
@Override
protected void tearDown() throws Exception {
super.tearDown();
rb = null;
tp = null;
}
@@ -27,7 +27,7 @@ import org.apache.struts2.FileManager;
import org.apache.struts2.FileManagerFactory;
import org.apache.struts2.SimpleAction;
import org.apache.struts2.SimpleAnnotationAction;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.config.entities.ActionConfig;
import org.apache.struts2.test.AnnotationDataAware2;
@@ -19,7 +19,7 @@
package org.apache.struts2.validator;
import org.apache.struts2.ActionContext;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.interceptor.ValidationAware;
import org.apache.struts2.ValidationAwareSupport;
import org.apache.struts2.XWorkTestCase;
@@ -21,7 +21,7 @@ package org.apache.struts2.validator;
import org.apache.struts2.ActionContext;
import org.apache.struts2.ActionProxy;
import org.apache.struts2.ActionSupport;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.ValidationAwareSupport;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.config.providers.MockConfigurationProvider;
@@ -18,7 +18,7 @@
*/
package org.apache.struts2.validator;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import java.util.*;
@@ -20,7 +20,7 @@ package org.apache.struts2.validator;
import org.apache.struts2.ActionContext;
import org.apache.struts2.ActionSupport;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.util.ValueStack;
import org.apache.struts2.validator.validators.EmailValidator;
@@ -25,7 +25,7 @@ import org.apache.struts2.ActionContext;
import org.apache.struts2.ActionInvocation;
import org.apache.struts2.ActionProxy;
import org.apache.struts2.TestBean;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.ValidationAwareSupport;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.config.entities.ActionConfig;
@@ -19,9 +19,8 @@
package org.apache.struts2.validator;
import org.apache.struts2.ActionContext;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.util.ValueStack;
import org.apache.struts2.validator.validators.RegexFieldValidator;
import java.util.Arrays;
@@ -20,7 +20,7 @@ package org.apache.struts2.validator;
import org.apache.struts2.ActionContext;
import org.apache.struts2.ActionSupport;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.conversion.impl.ConversionData;
import org.apache.struts2.mock.MockActionInvocation;
@@ -21,9 +21,7 @@ package org.apache.struts2.validator;
import org.apache.struts2.ActionContext;
import org.apache.struts2.ActionProxy;
import org.apache.struts2.SimpleAction;
import org.apache.struts2.StubTextProvider;
import org.apache.struts2.StubValueStack;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.config.providers.MockConfigurationProvider;
import org.apache.struts2.config.providers.XmlConfigurationProvider;
@@ -20,7 +20,7 @@ package org.apache.struts2.validator;
import org.apache.struts2.ActionContext;
import org.apache.struts2.ActionSupport;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.util.ValueStack;
import org.apache.struts2.validator.validators.StringLengthFieldValidator;
@@ -22,7 +22,7 @@ import org.apache.struts2.action.Action;
import org.apache.struts2.ActionContext;
import org.apache.struts2.ActionInvocation;
import org.apache.struts2.ActionProxy;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.ValidationAwareSupport;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.config.entities.ActionConfig;
@@ -19,7 +19,7 @@
package org.apache.struts2.validator;
import org.apache.struts2.ActionContext;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.util.ValueStack;
import org.apache.struts2.validator.validators.URLValidator;
@@ -22,9 +22,9 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.struts2.CompositeTextProvider;
import org.apache.struts2.TextProvider;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.CompositeTextProvider;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.validator.DelegatingValidatorContext;
import org.apache.struts2.validator.ValidatorContext;
@@ -18,7 +18,7 @@
*/
package org.apache.struts2.validator.validators;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.util.ValueStack;
import org.apache.struts2.util.ValueStackFactory;
import org.apache.struts2.validator.DummyValidatorContext;
@@ -19,7 +19,7 @@
package org.apache.struts2.validator.validators;
import org.apache.struts2.ActionContext;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.util.ValueStack;
import org.apache.struts2.util.ValueStackFactory;
@@ -18,7 +18,7 @@
*/
package org.apache.struts2.validator.validators;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.util.ValueStack;
import org.apache.struts2.util.ValueStackFactory;
@@ -18,7 +18,7 @@
*/
package org.apache.struts2.validator.validators;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.util.ValueStack;
import org.apache.struts2.util.ValueStackFactory;
@@ -19,7 +19,7 @@
package org.apache.struts2.validator.validators;
import org.apache.struts2.ActionContext;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.validator.DummyValidatorContext;
import org.apache.struts2.StrutsInternalTestCase;
import org.junit.Test;
@@ -20,7 +20,7 @@ package org.apache.struts2.validator.validators;
import org.apache.struts2.ActionContext;
import org.apache.struts2.ActionSupport;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.util.ValueStack;
import org.apache.struts2.validator.DummyValidatorContext;
@@ -18,7 +18,7 @@
*/
package org.apache.struts2.validator.validators;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.util.ValueStack;
import org.apache.struts2.util.ValueStackFactory;
@@ -21,7 +21,7 @@ package org.apache.struts.beanvalidation.validation.interceptor;
import org.apache.struts2.ActionInvocation;
import org.apache.struts2.ActionProxy;
import org.apache.struts2.ModelDriven;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.interceptor.MethodFilterInterceptor;
import org.apache.struts2.validator.DelegatingValidatorContext;
@@ -18,7 +18,7 @@
*/
package org.apache.struts2.mock;
import org.apache.struts2.TextProvider;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.util.ValueStack;
import java.util.List;
@@ -25,7 +25,7 @@ import org.apache.struts2.ModelDrivenAction;
import org.apache.struts2.ObjectFactory;
import org.apache.struts2.SimpleAction;
import org.apache.struts2.TestBean;
import org.apache.struts2.TextProvider;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.XWorkTestCase;
import org.apache.struts2.config.ConfigurationException;
import org.apache.struts2.config.entities.ActionConfig;
@@ -19,8 +19,8 @@
package org.apache.struts2.tiles;
import org.apache.struts2.ActionContext;
import org.apache.struts2.TextProvider;
import org.apache.struts2.TextProviderFactory;
import org.apache.struts2.text.TextProvider;
import org.apache.struts2.text.TextProviderFactory;
import org.apache.struts2.config.ConfigurationException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;