From 2def24c7db1e327dee3aad1d7d4893ff078106e3 Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Mon, 20 Jan 2025 12:57:18 +1100 Subject: [PATCH] WW-5516 Fix TemplateDir and Theme fallback to Request/Session/Application attributes --- .../org/apache/struts2/components/UIBean.java | 36 ++++++-- .../apache/struts2/views/jsp/TagUtils.java | 6 +- .../struts2/components/UIBeanTagTest.java | 88 +++++++++++++++++++ 3 files changed, 121 insertions(+), 9 deletions(-) create mode 100644 core/src/test/java/org/apache/struts2/components/UIBeanTagTest.java diff --git a/core/src/main/java/org/apache/struts2/components/UIBean.java b/core/src/main/java/org/apache/struts2/components/UIBean.java index 17fb9eac6f..0d54290991 100644 --- a/core/src/main/java/org/apache/struts2/components/UIBean.java +++ b/core/src/main/java/org/apache/struts2/components/UIBean.java @@ -26,7 +26,6 @@ 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.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.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; + /** *

* 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 String getTemplateDir() { 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 String getTheme() { 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 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); diff --git a/core/src/main/java/org/apache/struts2/views/jsp/TagUtils.java b/core/src/main/java/org/apache/struts2/views/jsp/TagUtils.java index 68f6707620..e8dc60c811 100644 --- a/core/src/main/java/org/apache/struts2/views/jsp/TagUtils.java +++ b/core/src/main/java/org/apache/struts2/views/jsp/TagUtils.java @@ -29,6 +29,8 @@ 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 static ValueStack getStack(PageContext pageContext) { } 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; diff --git a/core/src/test/java/org/apache/struts2/components/UIBeanTagTest.java b/core/src/test/java/org/apache/struts2/components/UIBeanTagTest.java new file mode 100644 index 0000000000..7dccccb1e1 --- /dev/null +++ b/core/src/test/java/org/apache/struts2/components/UIBeanTagTest.java @@ -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) 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) context.get(DispatcherConstants.REQUEST)).put(THEME, "requestValue"); + assertEquals("requestValue", bean.getTheme()); + } +}