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
diff --git a/core/src/main/java/com/opensymphony/xwork2/XWorkTestCase.java b/core/src/main/java/com/opensymphony/xwork2/XWorkTestCase.java
index 88790fc..8a4695e 100644
--- a/core/src/main/java/com/opensymphony/xwork2/XWorkTestCase.java
+++ b/core/src/main/java/com/opensymphony/xwork2/XWorkTestCase.java
@@ -36,6 +36,8 @@
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 @@
@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 @@
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 @@
.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);
+ }
}
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java b/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java
index 7bf0e7c..7c725e1 100644
--- a/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java
+++ b/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java
@@ -120,6 +120,7 @@
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 @@
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 @@
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 @@
}
// 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) {
diff --git a/core/src/main/java/org/apache/struts2/StrutsConstants.java b/core/src/main/java/org/apache/struts2/StrutsConstants.java
index 10d9fa5..91b8eb2 100644
--- a/core/src/main/java/org/apache/struts2/StrutsConstants.java
+++ b/core/src/main/java/org/apache/struts2/StrutsConstants.java
@@ -230,6 +230,8 @@
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";
diff --git a/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java b/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java
index 6106aad..11b30c2 100644
--- a/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java
+++ b/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java
@@ -90,6 +90,7 @@
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 @@
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 @@
this.mapperAlwaysSelectFullNamespace = mapperAlwaysSelectFullNamespace;
}
+ public Boolean getActionConfigFallbackToEmptyNamespace() {
+ return actionConfigFallbackToEmptyNamespace;
+ }
+
+ public void setActionConfigFallbackToEmptyNamespace(Boolean actionConfigFallbackToEmptyNamespace) {
+ this.actionConfigFallbackToEmptyNamespace = actionConfigFallbackToEmptyNamespace;
+ }
+
public BeanConfig getLocaleProviderFactory() {
return localeProviderFactory;
}
diff --git a/core/src/main/resources/org/apache/struts2/default.properties b/core/src/main/resources/org/apache/struts2/default.properties
index 96c5459..8b7226a 100644
--- a/core/src/main/resources/org/apache/struts2/default.properties
+++ b/core/src/main/resources/org/apache/struts2/default.properties
@@ -215,6 +215,9 @@
### 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
diff --git a/core/src/test/java/com/opensymphony/xwork2/config/ConfigurationTest.java b/core/src/test/java/com/opensymphony/xwork2/config/ConfigurationTest.java
index b52b9d4..520f8c2 100644
--- a/core/src/test/java/com/opensymphony/xwork2/config/ConfigurationTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/config/ConfigurationTest.java
@@ -31,6 +31,7 @@
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 @@
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() {
diff --git a/core/src/test/java/org/apache/struts2/views/jsp/ui/DebugTagTest.java b/core/src/test/java/org/apache/struts2/views/jsp/ui/DebugTagTest.java
index 7f4b545..b7db515 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/ui/DebugTagTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/ui/DebugTagTest.java
@@ -217,23 +217,9 @@
/**
* 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);
}
-}
\ No newline at end of file
+}