Merge pull request #912 from atlassian-forks/issue/WW-5408-add-option-to-not-fallback-to-empty-namespace-when-unresolved

WW-5408 add option to not fallback to empty namespace when unresolved
This commit is contained in:
Kusal Kithul-Godage
2024-04-12 17:58:06 +10:00
committed by GitHub
7 changed files with 99 additions and 27 deletions
@@ -36,6 +36,8 @@ import org.apache.commons.lang3.ClassUtils;
import java.util.Locale;
import java.util.Map;
import static java.util.Collections.singletonMap;
/**
* Base JUnit TestCase to extend for XWork specific JUnit tests. Uses
* the generic test setup for logic.
@@ -56,9 +58,7 @@ public abstract class XWorkTestCase extends TestCase {
@Override
protected void setUp() throws Exception {
configurationManager = XWorkTestCaseHelper.setUp();
configuration = configurationManager.getConfiguration();
container = configuration.getContainer();
actionProxyFactory = container.getInstance(ActionProxyFactory.class);
reloadConfiguration(configurationManager);
}
@Override
@@ -66,13 +66,17 @@ public abstract class XWorkTestCase extends TestCase {
XWorkTestCaseHelper.tearDown(configurationManager);
}
protected void loadConfigurationProviders(ConfigurationProvider... providers) {
configurationManager = XWorkTestCaseHelper.loadConfigurationProviders(configurationManager, providers);
private void reloadConfiguration(ConfigurationManager configurationManager) {
configuration = configurationManager.getConfiguration();
container = configuration.getContainer();
actionProxyFactory = container.getInstance(ActionProxyFactory.class);
}
protected void loadConfigurationProviders(ConfigurationProvider... providers) {
configurationManager = XWorkTestCaseHelper.loadConfigurationProviders(configurationManager, providers);
reloadConfiguration(configurationManager);
}
protected void loadButSet(Map<String, ?> properties) {
loadConfigurationProviders(new StubConfigurationProvider() {
@Override
@@ -115,4 +119,25 @@ public abstract class XWorkTestCase extends TestCase {
.getContextMap();
}
protected void setStrutsConstant(String constant, String value) {
setStrutsConstant(singletonMap(constant, value));
}
protected void setStrutsConstant(final Map<String, String> overwritePropeties) {
configurationManager.addContainerProvider(new StubConfigurationProvider() {
@Override
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
for (Map.Entry<String, String> stringStringEntry : overwritePropeties.entrySet()) {
props.setProperty(stringStringEntry.getKey(), stringStringEntry.getValue(), null);
}
}
@Override
public void destroy() {
}
});
configurationManager.reload();
reloadConfiguration(configurationManager);
}
}
@@ -120,6 +120,7 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
@@ -459,9 +460,12 @@ public class DefaultConfiguration implements Configuration {
boolean appendNamedParameters = Boolean.parseBoolean(
container.getInstance(String.class, StrutsConstants.STRUTS_MATCHER_APPEND_NAMED_PARAMETERS)
);
boolean fallbackToEmptyNamespace = Boolean.parseBoolean(
Optional.ofNullable(container.getInstance(String.class, StrutsConstants.STRUTS_ACTION_CONFIG_FALLBACK_TO_EMPTY_NAMESPACE)).orElse("true")
);
return new RuntimeConfigurationImpl(Collections.unmodifiableMap(namespaceActionConfigs),
Collections.unmodifiableMap(namespaceConfigs), matcher, appendNamedParameters);
Collections.unmodifiableMap(namespaceConfigs), matcher, appendNamedParameters, fallbackToEmptyNamespace);
}
private void setDefaultResults(Map<String, ResultConfig> results, PackageConfig packageContext) {
@@ -536,14 +540,17 @@ public class DefaultConfiguration implements Configuration {
private final Map<String, ActionConfigMatcher> namespaceActionConfigMatchers;
private final NamespaceMatcher namespaceMatcher;
private final Map<String, String> namespaceConfigs;
private final boolean fallbackToEmptyNamespace;
public RuntimeConfigurationImpl(Map<String, Map<String, ActionConfig>> namespaceActionConfigs,
Map<String, String> namespaceConfigs,
PatternMatcher<int[]> matcher,
boolean appendNamedParameters)
boolean appendNamedParameters,
boolean fallbackToEmptyNamespace)
{
this.namespaceActionConfigs = namespaceActionConfigs;
this.namespaceConfigs = namespaceConfigs;
this.fallbackToEmptyNamespace = fallbackToEmptyNamespace;
this.namespaceActionConfigMatchers = new LinkedHashMap<>();
this.namespaceMatcher = new NamespaceMatcher(matcher, namespaceActionConfigs.keySet(), appendNamedParameters);
@@ -583,14 +590,17 @@ public class DefaultConfiguration implements Configuration {
}
// fail over to empty namespace
if (config == null && StringUtils.isNotBlank(namespace)) {
if (config == null && shouldFallbackToEmptyNamespace(namespace)) {
config = findActionConfigInNamespace("", name);
}
return config;
}
private boolean shouldFallbackToEmptyNamespace(String namespace) {
return StringUtils.isNotBlank(namespace) && ("/".equals(namespace) || fallbackToEmptyNamespace);
}
private ActionConfig findActionConfigInNamespace(String namespace, String name) {
ActionConfig config = null;
if (namespace == null) {
@@ -230,6 +230,8 @@ public final class StrutsConstants {
public static final String STRUTS_XWORKCONVERTER = "struts.xworkConverter";
public static final String STRUTS_ALWAYS_SELECT_FULL_NAMESPACE = "struts.mapper.alwaysSelectFullNamespace";
/** Fallback to empty namespace when request namespace didn't match any in action configuration */
public static final String STRUTS_ACTION_CONFIG_FALLBACK_TO_EMPTY_NAMESPACE = "struts.actionConfig.fallbackToEmptyNamespace";
/** The {@link com.opensymphony.xwork2.LocaleProviderFactory} implementation class */
public static final String STRUTS_LOCALE_PROVIDER_FACTORY = "struts.localeProviderFactory";
@@ -90,6 +90,7 @@ public class ConstantConfig {
private Boolean freemarkerWrapperAltMap;
private BeanConfig xworkConverter;
private Boolean mapperAlwaysSelectFullNamespace;
private Boolean actionConfigFallbackToEmptyNamespace;
private BeanConfig localeProviderFactory;
private String mapperIdParameterName;
private Boolean ognlAllowStaticFieldAccess;
@@ -226,6 +227,7 @@ public class ConstantConfig {
map.put(StrutsConstants.STRUTS_FREEMARKER_WRAPPER_ALT_MAP, Objects.toString(freemarkerWrapperAltMap, null));
map.put(StrutsConstants.STRUTS_XWORKCONVERTER, beanConfToString(xworkConverter));
map.put(StrutsConstants.STRUTS_ALWAYS_SELECT_FULL_NAMESPACE, Objects.toString(mapperAlwaysSelectFullNamespace, null));
map.put(StrutsConstants.STRUTS_ACTION_CONFIG_FALLBACK_TO_EMPTY_NAMESPACE, Objects.toString(actionConfigFallbackToEmptyNamespace, null));
map.put(StrutsConstants.STRUTS_LOCALE_PROVIDER_FACTORY, beanConfToString(localeProviderFactory));
map.put(StrutsConstants.STRUTS_ID_PARAMETER_NAME, mapperIdParameterName);
map.put(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, Objects.toString(ognlAllowStaticFieldAccess, null));
@@ -814,6 +816,14 @@ public class ConstantConfig {
this.mapperAlwaysSelectFullNamespace = mapperAlwaysSelectFullNamespace;
}
public Boolean getActionConfigFallbackToEmptyNamespace() {
return actionConfigFallbackToEmptyNamespace;
}
public void setActionConfigFallbackToEmptyNamespace(Boolean actionConfigFallbackToEmptyNamespace) {
this.actionConfigFallbackToEmptyNamespace = actionConfigFallbackToEmptyNamespace;
}
public BeanConfig getLocaleProviderFactory() {
return localeProviderFactory;
}
@@ -215,6 +215,9 @@ struts.xslt.nocache=false
### Whether to always select the namespace to be everything before the last slash or not
struts.mapper.alwaysSelectFullNamespace=false
### Whether to fallback to empty namespace when request namespace does not match any in configuration
struts.actionConfig.fallbackToEmptyNamespace=true
### Whether to allow static field access in OGNL expressions or not
struts.ognl.allowStaticFieldAccess=true
@@ -31,6 +31,7 @@ import com.opensymphony.xwork2.inject.ContainerBuilder;
import com.opensymphony.xwork2.mock.MockInterceptor;
import com.opensymphony.xwork2.test.StubConfigurationProvider;
import com.opensymphony.xwork2.util.location.LocatableProperties;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.config.StrutsXmlConfigurationProvider;
import org.apache.struts2.dispatcher.HttpParameters;
@@ -239,6 +240,41 @@ public class ConfigurationTest extends XWorkTestCase {
mockContainerProvider.verify();
}
public void testGetActionConfigFallbackToEmptyNamespaceWhenNamespaceDontMatchAndEmptyNamespaceFallbackIsEnabled() {
// struts.actionConfig.fallbackToEmptyNamespace default to true, so it is enabled
RuntimeConfiguration configuration = configurationManager.getConfiguration().getRuntimeConfiguration();
// check namespace that doesn't match fallback to empty namespace
ActionConfig actionConfig = configuration.getActionConfig("/something/that/is/not/in/the/namespace/config", "LazyFoo");
assertEquals("default", actionConfig.getPackageName()); // fallback to empty namespace (package name is default)
assertEquals("LazyFoo", actionConfig.getName());
// check non-empty namespace and name in config still matches
assertNotNull(configuration.getActionConfig("includeTest", "Foo"));
// check root namespace and name in config still matches
actionConfig = configuration.getActionConfig("/", "LazyFoo");
assertEquals("default", actionConfig.getPackageName());
assertEquals("LazyFoo", actionConfig.getName());
}
public void testGetActionConfigReturnNullWhenNamespaceDontMatchAndEmptyNamespaceFallbackIsDisabled() {
// set the struts.actionConfig.fallbackToEmptyNamespace to false and reload the configuration
setStrutsConstant(StrutsConstants.STRUTS_ACTION_CONFIG_FALLBACK_TO_EMPTY_NAMESPACE, "false");
RuntimeConfiguration configuration = configurationManager.getConfiguration().getRuntimeConfiguration();
// check namespace that doesn't match NOT fallback to empty namespace and return null
assertNull(configuration.getActionConfig("/something/that/is/not/in/the/namespace/config", "LazyFoo"));
// check non-empty namespace and name in config still matches
assertNotNull(configuration.getActionConfig("includeTest", "Foo"));
// check root namespace and name in config still matches
ActionConfig actionConfig = configuration.getActionConfig("/", "LazyFoo");
assertEquals("default", actionConfig.getPackageName());
assertEquals("LazyFoo", actionConfig.getName());
}
public void testInitForPackageProviders() {
loadConfigurationProviders(new StubConfigurationProvider() {
@@ -217,23 +217,9 @@ public class DebugTagTest extends AbstractUITagTest {
/**
* Overwrite the Struts Constant and reload container
*/
private void setStrutsConstant(final Map<String, String> overwritePropeties) {
configurationManager.addContainerProvider(new StubConfigurationProvider() {
@Override
public boolean needsReload() {
return true;
}
@Override
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
for (Map.Entry<String, String> stringStringEntry : overwritePropeties.entrySet()) {
props.setProperty(stringStringEntry.getKey(), stringStringEntry.getValue(), null);
}
}
});
configurationManager.reload();
container = configurationManager.getConfiguration().getContainer();
@Override
protected void setStrutsConstant(final Map<String, String> overwritePropeties) {
super.setStrutsConstant(overwritePropeties);
stack.getActionContext().withContainer(container);
}
}
}