WW-5516 Fix TemplateDir and Theme fallback to Request/Session/Application attributes

This commit is contained in:
Kusal Kithul-Godage
2025-01-20 12:57:18 +11:00
parent 4e80f2661e
commit 2def24c7db
3 changed files with 121 additions and 9 deletions
@@ -26,7 +26,6 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsConstants;
@@ -35,6 +34,7 @@ import org.apache.struts2.components.template.Template;
import org.apache.struts2.components.template.TemplateEngine;
import org.apache.struts2.components.template.TemplateEngineManager;
import org.apache.struts2.components.template.TemplateRenderingContext;
import org.apache.struts2.dispatcher.AttributeMap;
import org.apache.struts2.dispatcher.StaticContentLoader;
import org.apache.struts2.util.ComponentUtils;
import org.apache.struts2.util.TextProviderHelper;
@@ -48,6 +48,10 @@ import java.util.List;
import java.util.Map;
import java.util.function.Function;
import static java.util.Collections.emptyMap;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.struts2.dispatcher.DispatcherConstants.ATTRIBUTES;
/**
* <p>
* UIBean is the standard superclass of all Struts UI components.
@@ -440,6 +444,9 @@ public abstract class UIBean extends Component {
private static final Logger LOG = LogManager.getLogger(UIBean.class);
static final String TEMPLATE_DIR = "templateDir";
static final String THEME = "theme";
protected static final String ATTR_FIELD_VALUE = "fieldValue";
protected static final String ATTR_NAME_VALUE = "nameValue";
protected static final String ATTR_VALUE = "value";
@@ -602,13 +609,18 @@ public abstract class UIBean extends Component {
result = findString(this.templateDir);
}
// Check Request, Session, Application scopes
if (isBlank(result)) {
result = (String) getAttrMap().get(TEMPLATE_DIR);
}
// Default template set
if (StringUtils.isBlank(result)) {
if (isBlank(result)) {
result = defaultTemplateDir;
}
// Defaults to 'template'
if (StringUtils.isBlank(result)) {
if (isBlank(result)) {
result = "template";
}
@@ -622,26 +634,36 @@ public abstract class UIBean extends Component {
result = findString(this.theme);
}
if (StringUtils.isBlank(result)) {
if (isBlank(result)) {
Form form = (Form) findAncestor(Form.class);
if (form != null) {
result = form.getTheme();
}
}
// Check Request, Session, Application scopes
if (isBlank(result)) {
result = (String) getAttrMap().get(THEME);
}
// Default theme set
if (StringUtils.isBlank(result)) {
if (isBlank(result)) {
result = defaultUITheme;
}
return result;
}
private Map<String, Object> getAttrMap() {
AttributeMap attrMap = (AttributeMap) getStack().getContext().get(ATTRIBUTES);
return attrMap != null ? attrMap : emptyMap();
}
public void evaluateParams() {
String gotTheme = getTheme();
addParameter("templateDir", getTemplateDir());
addParameter("theme", gotTheme);
addParameter(TEMPLATE_DIR, getTemplateDir());
addParameter(THEME, gotTheme);
addParameter("template", template != null ? findString(template) : getDefaultTemplate());
addParameter("dynamicAttributes", dynamicAttributes);
addParameter("themeExpansionToken", uiThemeExpansionToken);
@@ -29,6 +29,8 @@ import org.apache.struts2.dispatcher.AttributeMap;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.jsp.PageContext;
import static org.apache.struts2.dispatcher.DispatcherConstants.ATTRIBUTES;
public class TagUtils {
private static final Logger LOG = LogManager.getLogger(TagUtils.class);
@@ -46,8 +48,8 @@ public class TagUtils {
} else {
LOG.trace("Adds the current PageContext to ActionContext");
stack.getActionContext()
.withPageContext(pageContext)
.with("attr", new AttributeMap(stack.getContext()));
.withPageContext(pageContext)
.with(ATTRIBUTES, new AttributeMap(stack.getContext()));
}
return stack;
@@ -0,0 +1,88 @@
/*
* 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.components;
import org.apache.struts2.ActionContext;
import org.apache.struts2.dispatcher.DispatcherConstants;
import org.apache.struts2.views.jsp.AbstractTagTest;
import java.util.Map;
import static org.apache.struts2.components.UIBean.TEMPLATE_DIR;
import static org.apache.struts2.components.UIBean.THEME;
public class UIBeanTagTest extends AbstractTagTest {
private UIBean bean;
@Override
public void setUp() throws Exception {
super.setUp();
bean = new UIBean(stack, request, response) {
@Override
protected String getDefaultTemplate() {
return null;
}
};
}
public void testTemplateDir_ognlExpression() {
bean.setTemplateDir("%{testDir}");
stack.push(new Object() {
public String getTestDir() {
return "testValue";
}
});
assertEquals("testValue", bean.getTemplateDir());
}
public void testTemplateDir_attrMapFallback() {
ActionContext.of(context).getApplication().put(TEMPLATE_DIR, "applicationValue");
assertEquals("applicationValue", bean.getTemplateDir());
ActionContext.of(context).getSession().put(TEMPLATE_DIR, "sessionValue");
assertEquals("sessionValue", bean.getTemplateDir());
((Map<String, Object>) context.get(DispatcherConstants.REQUEST)).put(TEMPLATE_DIR, "requestValue");
assertEquals("requestValue", bean.getTemplateDir());
}
public void testTheme_ognlExpression() {
bean.setTheme("%{testTheme}");
stack.push(new Object() {
public String getTestTheme() {
return "testValue";
}
});
assertEquals("testValue", bean.getTheme());
}
public void testTheme_attrMapFallback() {
ActionContext.of(context).getApplication().put(THEME, "applicationValue");
assertEquals("applicationValue", bean.getTheme());
ActionContext.of(context).getSession().put(THEME, "sessionValue");
assertEquals("sessionValue", bean.getTheme());
((Map<String, Object>) context.get(DispatcherConstants.REQUEST)).put(THEME, "requestValue");
assertEquals("requestValue", bean.getTheme());
}
}