From e299bba112e3e0e0ab9faf6052ef077046ae43ac Mon Sep 17 00:00:00 2001 From: Sebastian Peters Date: Fri, 26 Jan 2024 12:44:36 +0100 Subject: [PATCH 01/24] Update maven-war-plugin to 3.4.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 84f11fd73..5fe0e3cc4 100644 --- a/pom.xml +++ b/pom.xml @@ -281,7 +281,7 @@ org.apache.maven.plugins maven-war-plugin - 3.3.1 + 3.4.0 org.apache.felix From 8087ba97ee462309e82446ba0df4b306f40ae80b Mon Sep 17 00:00:00 2001 From: Sebastian Peters Date: Fri, 26 Jan 2024 12:45:01 +0100 Subject: [PATCH 02/24] Update maven-site-plugin to 3.12.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5fe0e3cc4..5e1aadba6 100644 --- a/pom.xml +++ b/pom.xml @@ -419,7 +419,7 @@ org.apache.maven.plugins maven-site-plugin - 3.9.0 + 3.12.1 false From 028fedd3067f21ebdccc80c0b95b7d7e91dcdea3 Mon Sep 17 00:00:00 2001 From: Sebastian Peters Date: Fri, 26 Jan 2024 12:45:17 +0100 Subject: [PATCH 03/24] Update assertj to 3.25.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5e1aadba6..8f18670c2 100644 --- a/pom.xml +++ b/pom.xml @@ -990,7 +990,7 @@ org.assertj assertj-core - 3.24.2 + 3.25.2 test From 77285186df1ba93ac49ad74b5d33054783a51d1e Mon Sep 17 00:00:00 2001 From: Sebastian Peters Date: Fri, 26 Jan 2024 12:48:45 +0100 Subject: [PATCH 04/24] Update slf4j to 2.0.11 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8f18670c2..1e440a8a9 100644 --- a/pom.xml +++ b/pom.xml @@ -113,7 +113,7 @@ 2.16.0 2.20.0 3.3.4 - 2.0.9 + 2.0.11 5.3.27 3.0.8 1.0.7 From 71d28ed90d71c280ceb04b7a5cacca88d3e56aa5 Mon Sep 17 00:00:00 2001 From: Sebastian Peters Date: Fri, 26 Jan 2024 12:49:09 +0100 Subject: [PATCH 05/24] Update jackson to 2.16.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1e440a8a9..4e1f8fe08 100644 --- a/pom.xml +++ b/pom.xml @@ -110,7 +110,7 @@ 9.6 - 2.16.0 + 2.16.1 2.20.0 3.3.4 2.0.11 From f8a8172a3e6f28d62796b5d3b17329923bfd026e Mon Sep 17 00:00:00 2001 From: Sebastian Peters Date: Fri, 26 Jan 2024 12:49:46 +0100 Subject: [PATCH 06/24] Update spring to 5.3.31 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4e1f8fe08..b03fb5eda 100644 --- a/pom.xml +++ b/pom.xml @@ -114,7 +114,7 @@ 2.20.0 3.3.4 2.0.11 - 5.3.27 + 5.3.31 3.0.8 1.0.7 3.0.0-M7 From fd2cf91601492a991048559190ae95b88e2c7ff6 Mon Sep 17 00:00:00 2001 From: Sebastian Peters Date: Fri, 26 Jan 2024 12:50:20 +0100 Subject: [PATCH 07/24] Update log4j2 to 2.21.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b03fb5eda..bf89cecc7 100644 --- a/pom.xml +++ b/pom.xml @@ -111,7 +111,7 @@ 9.6 2.16.1 - 2.20.0 + 2.21.1 3.3.4 2.0.11 5.3.31 From 8ef55db35f38ed0be4b0cd971c4a8bfd3f39595d Mon Sep 17 00:00:00 2001 From: Sebastian Peters Date: Sat, 27 Jan 2024 11:05:31 +0100 Subject: [PATCH 08/24] Update maven-dependency-plugin to 3.6.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bf89cecc7..b942f8a6e 100644 --- a/pom.xml +++ b/pom.xml @@ -291,7 +291,7 @@ org.apache.maven.plugins maven-dependency-plugin - 3.6.0 + 3.6.1 org.apache.maven.plugins From 27f0b569662620ad1c680c746317b0a964518336 Mon Sep 17 00:00:00 2001 From: Sebastian Peters Date: Sat, 27 Jan 2024 11:06:15 +0100 Subject: [PATCH 09/24] Update maven-enforcer-plugin to 3.4.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b942f8a6e..7db90a961 100644 --- a/pom.xml +++ b/pom.xml @@ -361,7 +361,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 3.1.0 + 3.4.1 enforce From fd7e74867cd279859566d080ab0cf2fe5b977fab Mon Sep 17 00:00:00 2001 From: Sebastian Peters Date: Sat, 27 Jan 2024 11:09:12 +0100 Subject: [PATCH 10/24] Update commons-lang3 to 3.14.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7db90a961..b510a7261 100644 --- a/pom.xml +++ b/pom.xml @@ -871,7 +871,7 @@ org.apache.commons commons-lang3 - 3.13.0 + 3.14.0 org.apache.commons From 218e634bf1c7a62843b97aede3a8bf15fb0d9d6b Mon Sep 17 00:00:00 2001 From: Sebastian Peters Date: Sat, 27 Jan 2024 11:09:42 +0100 Subject: [PATCH 11/24] Update commons-io to 2.15.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b510a7261..cb2173a8e 100644 --- a/pom.xml +++ b/pom.xml @@ -866,7 +866,7 @@ commons-io commons-io - 2.13.0 + 2.15.1 org.apache.commons From abd824fdd293aaa78ee4453596672d905928dd0f Mon Sep 17 00:00:00 2001 From: Sebastian Peters Date: Sat, 27 Jan 2024 11:10:16 +0100 Subject: [PATCH 12/24] Update commons-text to 1.11.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cb2173a8e..3fd6b92f7 100644 --- a/pom.xml +++ b/pom.xml @@ -876,7 +876,7 @@ org.apache.commons commons-text - 1.10.0 + 1.11.0 commons-el From 9328ae7ec10f23c5ad0fb2e8a4a1c555a2094a17 Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Fri, 2 Feb 2024 17:25:17 +1100 Subject: [PATCH 13/24] WW-5391 Add interface for VelocityManager extension point --- .../osgi/OsgiConfigurationProvider.java | 24 +- .../portlet/result/PortletVelocityResult.java | 564 +++++++++--------- .../VelocityBeanSelectionProvider.java | 2 +- .../views/velocity/VelocityManager.java | 5 +- .../velocity/VelocityManagerInterface.java | 39 ++ .../views/velocity/result/VelocityResult.java | 37 +- .../template/VelocityTemplateEngine.java | 17 +- 7 files changed, 399 insertions(+), 289 deletions(-) create mode 100644 plugins/velocity/src/main/java/org/apache/struts2/views/velocity/VelocityManagerInterface.java diff --git a/plugins/osgi/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java b/plugins/osgi/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java index 61b22c281..ba56b4e6d 100644 --- a/plugins/osgi/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java +++ b/plugins/osgi/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java @@ -24,15 +24,15 @@ import com.opensymphony.xwork2.ObjectFactory; import com.opensymphony.xwork2.config.Configuration; import com.opensymphony.xwork2.config.ConfigurationException; import com.opensymphony.xwork2.config.PackageProvider; -import com.opensymphony.xwork2.config.entities.PackageConfig; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.util.finder.ClassLoaderInterface; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.LogManager; import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.apache.struts2.osgi.host.OsgiHost; import org.apache.struts2.osgi.loaders.VelocityBundleResourceLoader; import org.apache.struts2.views.velocity.VelocityManager; +import org.apache.struts2.views.velocity.VelocityManagerInterface; import org.apache.velocity.app.Velocity; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; @@ -40,7 +40,6 @@ import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleListener; import javax.servlet.ServletContext; -import java.util.HashMap; import java.util.HashSet; import java.util.Properties; import java.util.Set; @@ -255,9 +254,12 @@ public class OsgiConfigurationProvider implements PackageProvider, BundleListene } @Inject - public void setVelocityManager(VelocityManager vm) { - LOG.trace("OSGi ConfigurationProvider - setVelocityManager() called - VelocityManager: [{}]", vm); - + public void setVelocityManager(VelocityManagerInterface vmi) { + LOG.trace("OSGi ConfigurationProvider - setVelocityManager() called - VelocityManager: [{}]", vmi); + if (!(vmi instanceof VelocityManager)) { + return; + } + VelocityManager vm = (VelocityManager) vmi; Properties props = new Properties(); props.setProperty("osgi.resource.loader.description", "OSGI bundle loader"); props.setProperty("osgi.resource.loader.class", VelocityBundleResourceLoader.class.getName()); @@ -265,6 +267,14 @@ public class OsgiConfigurationProvider implements PackageProvider, BundleListene vm.setVelocityProperties(props); } + /** + * @deprecated since 6.4.0 + */ + @Deprecated + public void setVelocityManager(VelocityManager mgr) { + setVelocityManager((VelocityManagerInterface) mgr); + } + @Inject public void setServletContext(ServletContext servletContext) { LOG.trace("OSGi ConfigurationProvider - setServletContext() called - ServletContext: [{}]", servletContext); diff --git a/plugins/portlet/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java index fcae67c45..d40ce9331 100644 --- a/plugins/portlet/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java +++ b/plugins/portlet/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java @@ -1,270 +1,294 @@ -/* - * 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.portlet.result; - -import com.opensymphony.xwork2.ActionContext; -import com.opensymphony.xwork2.ActionInvocation; -import com.opensymphony.xwork2.inject.Inject; -import com.opensymphony.xwork2.util.ValueStack; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.LogManager; -import org.apache.struts2.ServletActionContext; -import org.apache.struts2.StrutsConstants; -import org.apache.struts2.result.StrutsResultSupport; -import org.apache.struts2.portlet.PortletConstants; -import org.apache.struts2.portlet.PortletPhase; -import org.apache.struts2.portlet.context.PortletActionContext; -import org.apache.struts2.views.JspSupportServlet; -import org.apache.struts2.views.velocity.VelocityManager; -import org.apache.velocity.Template; -import org.apache.velocity.app.VelocityEngine; -import org.apache.velocity.context.Context; - -import javax.portlet.ActionResponse; -import javax.servlet.Servlet; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.jsp.JspFactory; -import javax.servlet.jsp.PageContext; -import java.io.OutputStreamWriter; -import java.io.Writer; - -/** - * - * - * Using the Servlet container's {@link JspFactory}, this result mocks a JSP - * execution environment and then displays a Velocity template that will be - * streamed directly to the servlet output. - * - * - *

This result type takes the following parameters:

- * - * - * - *
    - * - *
  • location (default) - the location of the template to process. - *
  • - * - *
  • parse - true by default. If set to false, the location param - * will not be parsed for Ognl expressions.
  • - * - *
- *

- * This result follows the same rules from {@link StrutsResultSupport}. - *

- * - * - * - *

Example:

- * - *
- * <!-- START SNIPPET: example -->
- *  <result name="success" type="velocity">
- *    <param name="location">foo.vm</param>
- *  </result>
- *  <!-- END SNIPPET: example -->
- * 
- * - */ -public class PortletVelocityResult extends StrutsResultSupport { - - private static final long serialVersionUID = -8241086555872212274L; - - private static final Logger LOG = LogManager.getLogger(PortletVelocityResult.class); - - private String defaultEncoding; - private VelocityManager velocityManager; - private JspFactory jspFactory = JspFactory.getDefaultFactory(); - - public PortletVelocityResult() { - super(); - } - - public PortletVelocityResult(String location) { - super(location); - } - - @Inject - public void setVelocityManager(VelocityManager mgr) { - this.velocityManager = mgr; - } - - @Inject(StrutsConstants.STRUTS_I18N_ENCODING) - public void setDefaultEncoding(String encoding) { - this.defaultEncoding = encoding; - } - - /* (non-Javadoc) - * @see org.apache.struts2.result.StrutsResultSupport#doExecute(java.lang.String, com.opensymphony.xwork2.ActionInvocation) - */ - public void doExecute(String location, ActionInvocation invocation) throws Exception { - PortletPhase phase = PortletActionContext.getPhase(); - if (phase.isAction()) { - executeActionResult(location, invocation); - } else if (phase.isRender()) { - executeRenderResult(location, invocation); - } - } - - /** - * Executes the result - * - * @param location The location string - * @param invocation The action invocation - */ - private void executeActionResult(String location, ActionInvocation invocation) { - ActionResponse res = PortletActionContext.getActionResponse(); - // View is rendered outside an action...uh oh... - res.setRenderParameter(PortletConstants.ACTION_PARAM, "freemarkerDirect"); - res.setRenderParameter("location", location); - res.setRenderParameter(PortletConstants.MODE_PARAM, PortletActionContext.getRequest().getPortletMode().toString()); - } - - /** - * Creates a Velocity context from the action, loads a Velocity template and - * executes the template. Output is written to the servlet output stream. - * - * @param finalLocation the location of the Velocity template - * @param invocation an encapsulation of the action execution state. - * @throws Exception if an error occurs when creating the Velocity context, - * loading or executing the template or writing output to the - * servlet response stream. - */ - public void executeRenderResult(String finalLocation, ActionInvocation invocation) throws Exception { - ValueStack stack = ActionContext.getContext().getValueStack(); - - HttpServletRequest request = ServletActionContext.getRequest(); - HttpServletResponse response = ServletActionContext.getResponse(); - ServletContext servletContext = ServletActionContext.getServletContext(); - Servlet servlet = JspSupportServlet.jspSupportServlet; - - velocityManager.init(servletContext); - - boolean usedJspFactory = false; - PageContext pageContext = ActionContext.getContext().getPageContext(); - - if (pageContext == null && servlet != null) { - pageContext = jspFactory.getPageContext(servlet, request, response, null, true, 8192, true); - ActionContext.getContext().withPageContext(pageContext); - usedJspFactory = true; - } - - try { - String encoding = getEncoding(finalLocation); - String contentType = getContentType(finalLocation); - - if (encoding != null) { - contentType = contentType + ";charset=" + encoding; - } - response.setContentType(contentType); - Template t = getTemplate(stack, velocityManager.getVelocityEngine(), invocation, finalLocation, encoding); - - Context context = createContext(velocityManager, stack, request, response, finalLocation); - Writer writer = new OutputStreamWriter(response.getOutputStream(), encoding); - - t.merge(context, writer); - - // always flush the writer (we used to only flush it if this was a - // jspWriter, but someone asked - // to do it all the time (WW-829). Since Velocity support is being - // deprecated, we'll oblige :) - writer.flush(); - } catch (Exception e) { - LOG.error("Unable to render Velocity Template, '" + finalLocation + "'", e); - throw e; - } finally { - if (usedJspFactory) { - jspFactory.releasePageContext(pageContext); - } - } - } - - /** - * Retrieve the content type for this template.
People can override - * this method if they want to provide specific content types for specific - * templates (eg text/xml). - * - * @param templateLocation location of templates - * - * @return The content type associated with this template (default - * "text/html") - */ - protected String getContentType(String templateLocation) { - return "text/html"; - } - - /** - * Retrieve the encoding for this template.
People can override this - * method if they want to provide specific encodings for specific templates. - * - * @param templateLocation location of templates - * - * @return The encoding associated with this template (defaults to the value - * of 'struts.i18n.encoding' property) - */ - protected String getEncoding(String templateLocation) { - String encoding = defaultEncoding; - if (encoding == null) { - encoding = System.getProperty("file.encoding"); - } - if (encoding == null) { - encoding = "UTF-8"; - } - return encoding; - } - - /** - * Given a value stack, a Velocity engine, and an action invocation, this - * method returns the appropriate Velocity template to render. - * - * @param stack the value stack to resolve the location again (when parse - * equals true) - * @param velocity the velocity engine to process the request against - * @param invocation an encapsulation of the action execution state. - * @param location the location of the template - * @param encoding the charset encoding of the template - * @return the template to render - * @throws Exception when the requested template could not be found - */ - protected Template getTemplate(ValueStack stack, VelocityEngine velocity, ActionInvocation invocation, - String location, String encoding) throws Exception { - if (!location.startsWith("/")) { - location = invocation.getProxy().getNamespace() + "/" + location; - } - return velocity.getTemplate(location, encoding); - } - - /** - * Creates the VelocityContext that we'll use to render this page. - * - * @param velocityManager a reference to the velocityManager to use - * @param stack the value stack to resolve the location against (when parse - * equals true) - * @param request servlet request - * @param response servlet response - * @param location the name of the template that is being used - * @return the a minted Velocity context. - */ - protected Context createContext(VelocityManager velocityManager, ValueStack stack, HttpServletRequest request, - HttpServletResponse response, String location) { - return velocityManager.createContext(stack, request, response); - } -} +/* + * 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.portlet.result; + +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.inject.Inject; +import com.opensymphony.xwork2.util.ValueStack; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.struts2.ServletActionContext; +import org.apache.struts2.StrutsConstants; +import org.apache.struts2.portlet.PortletConstants; +import org.apache.struts2.portlet.PortletPhase; +import org.apache.struts2.portlet.context.PortletActionContext; +import org.apache.struts2.result.StrutsResultSupport; +import org.apache.struts2.views.JspSupportServlet; +import org.apache.struts2.views.velocity.VelocityManager; +import org.apache.struts2.views.velocity.VelocityManagerInterface; +import org.apache.velocity.Template; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.context.Context; + +import javax.portlet.ActionResponse; +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.jsp.JspFactory; +import javax.servlet.jsp.PageContext; +import java.io.OutputStreamWriter; +import java.io.Writer; + +/** + * + * + * Using the Servlet container's {@link JspFactory}, this result mocks a JSP + * execution environment and then displays a Velocity template that will be + * streamed directly to the servlet output. + * + * + *

This result type takes the following parameters:

+ * + * + * + *
    + * + *
  • location (default) - the location of the template to process. + *
  • + * + *
  • parse - true by default. If set to false, the location param + * will not be parsed for Ognl expressions.
  • + * + *
+ *

+ * This result follows the same rules from {@link StrutsResultSupport}. + *

+ * + * + * + *

Example:

+ * + *
+ * <!-- START SNIPPET: example -->
+ *  <result name="success" type="velocity">
+ *    <param name="location">foo.vm</param>
+ *  </result>
+ *  <!-- END SNIPPET: example -->
+ * 
+ * + */ +public class PortletVelocityResult extends StrutsResultSupport { + + private static final long serialVersionUID = -8241086555872212274L; + + private static final Logger LOG = LogManager.getLogger(PortletVelocityResult.class); + + private String defaultEncoding; + private VelocityManagerInterface velocityManager; + private JspFactory jspFactory = JspFactory.getDefaultFactory(); + + public PortletVelocityResult() { + super(); + } + + public PortletVelocityResult(String location) { + super(location); + } + + @Inject + public void setVelocityManager(VelocityManagerInterface mgr) { + this.velocityManager = mgr; + } + + /** + * @deprecated since 6.4.0 + */ + @Deprecated + public void setVelocityManager(VelocityManager mgr) { + setVelocityManager((VelocityManagerInterface) mgr); + } + + @Inject(StrutsConstants.STRUTS_I18N_ENCODING) + public void setDefaultEncoding(String encoding) { + this.defaultEncoding = encoding; + } + + /* (non-Javadoc) + * @see org.apache.struts2.result.StrutsResultSupport#doExecute(java.lang.String, com.opensymphony.xwork2.ActionInvocation) + */ + public void doExecute(String location, ActionInvocation invocation) throws Exception { + PortletPhase phase = PortletActionContext.getPhase(); + if (phase.isAction()) { + executeActionResult(location, invocation); + } else if (phase.isRender()) { + executeRenderResult(location, invocation); + } + } + + /** + * Executes the result + * + * @param location The location string + * @param invocation The action invocation + */ + private void executeActionResult(String location, ActionInvocation invocation) { + ActionResponse res = PortletActionContext.getActionResponse(); + // View is rendered outside an action...uh oh... + res.setRenderParameter(PortletConstants.ACTION_PARAM, "freemarkerDirect"); + res.setRenderParameter("location", location); + res.setRenderParameter(PortletConstants.MODE_PARAM, PortletActionContext.getRequest().getPortletMode().toString()); + } + + /** + * Creates a Velocity context from the action, loads a Velocity template and + * executes the template. Output is written to the servlet output stream. + * + * @param finalLocation the location of the Velocity template + * @param invocation an encapsulation of the action execution state. + * @throws Exception if an error occurs when creating the Velocity context, + * loading or executing the template or writing output to the + * servlet response stream. + */ + public void executeRenderResult(String finalLocation, ActionInvocation invocation) throws Exception { + ValueStack stack = ActionContext.getContext().getValueStack(); + + HttpServletRequest request = ServletActionContext.getRequest(); + HttpServletResponse response = ServletActionContext.getResponse(); + ServletContext servletContext = ServletActionContext.getServletContext(); + Servlet servlet = JspSupportServlet.jspSupportServlet; + + velocityManager.init(servletContext); + + boolean usedJspFactory = false; + PageContext pageContext = ActionContext.getContext().getPageContext(); + + if (pageContext == null && servlet != null) { + pageContext = jspFactory.getPageContext(servlet, request, response, null, true, 8192, true); + ActionContext.getContext().withPageContext(pageContext); + usedJspFactory = true; + } + + try { + String encoding = getEncoding(finalLocation); + String contentType = getContentType(finalLocation); + + if (encoding != null) { + contentType = contentType + ";charset=" + encoding; + } + response.setContentType(contentType); + Template t = getTemplate(stack, velocityManager.getVelocityEngine(), invocation, finalLocation, encoding); + + Context context = createContext(velocityManager, stack, request, response, finalLocation); + Writer writer = new OutputStreamWriter(response.getOutputStream(), encoding); + + t.merge(context, writer); + + // always flush the writer (we used to only flush it if this was a + // jspWriter, but someone asked + // to do it all the time (WW-829). Since Velocity support is being + // deprecated, we'll oblige :) + writer.flush(); + } catch (Exception e) { + LOG.error("Unable to render Velocity Template, '" + finalLocation + "'", e); + throw e; + } finally { + if (usedJspFactory) { + jspFactory.releasePageContext(pageContext); + } + } + } + + /** + * Retrieve the content type for this template.
People can override + * this method if they want to provide specific content types for specific + * templates (eg text/xml). + * + * @param templateLocation location of templates + * + * @return The content type associated with this template (default + * "text/html") + */ + protected String getContentType(String templateLocation) { + return "text/html"; + } + + /** + * Retrieve the encoding for this template.
People can override this + * method if they want to provide specific encodings for specific templates. + * + * @param templateLocation location of templates + * + * @return The encoding associated with this template (defaults to the value + * of 'struts.i18n.encoding' property) + */ + protected String getEncoding(String templateLocation) { + String encoding = defaultEncoding; + if (encoding == null) { + encoding = System.getProperty("file.encoding"); + } + if (encoding == null) { + encoding = "UTF-8"; + } + return encoding; + } + + /** + * Given a value stack, a Velocity engine, and an action invocation, this + * method returns the appropriate Velocity template to render. + * + * @param stack the value stack to resolve the location again (when parse + * equals true) + * @param velocity the velocity engine to process the request against + * @param invocation an encapsulation of the action execution state. + * @param location the location of the template + * @param encoding the charset encoding of the template + * @return the template to render + * @throws Exception when the requested template could not be found + */ + protected Template getTemplate(ValueStack stack, VelocityEngine velocity, ActionInvocation invocation, + String location, String encoding) throws Exception { + if (!location.startsWith("/")) { + location = invocation.getProxy().getNamespace() + "/" + location; + } + return velocity.getTemplate(location, encoding); + } + + /** + * Creates the VelocityContext that we'll use to render this page. + * + * @param velocityManager a reference to the velocityManager to use + * @param stack the value stack to resolve the location against (when parse + * equals true) + * @param request servlet request + * @param response servlet response + * @param location the name of the template that is being used + * @return the a minted Velocity context. + */ + protected Context createContext(VelocityManagerInterface velocityManager, + ValueStack stack, + HttpServletRequest request, + HttpServletResponse response, + String location) { + return velocityManager.createContext(stack, request, response); + } + + /** + * @deprecated since 6.4.0 + */ + @Deprecated + protected Context createContext(VelocityManager velocityManager, + ValueStack stack, + HttpServletRequest request, + HttpServletResponse response, + String location) { + return createContext((VelocityManagerInterface) velocityManager, stack, request, response, location); + } +} diff --git a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/VelocityBeanSelectionProvider.java b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/VelocityBeanSelectionProvider.java index f53ec6607..d2c195b0f 100644 --- a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/VelocityBeanSelectionProvider.java +++ b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/VelocityBeanSelectionProvider.java @@ -49,7 +49,7 @@ public class VelocityBeanSelectionProvider extends AbstractBeanSelectionProvider @Override public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException { - alias(VelocityManager.class, VelocityConstants.STRUTS_VELOCITY_MANAGER_CLASSNAME, builder, props); + alias(VelocityManagerInterface.class, VelocityConstants.STRUTS_VELOCITY_MANAGER_CLASSNAME, builder, props); } } diff --git a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/VelocityManager.java b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/VelocityManager.java index 2b9e00191..e1764afc4 100644 --- a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/VelocityManager.java +++ b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/VelocityManager.java @@ -62,7 +62,7 @@ import static org.apache.struts2.views.util.ContextUtil.STRUTS; /** * Manages the environment for Velocity result types */ -public class VelocityManager { +public class VelocityManager implements VelocityManagerInterface { private static final Logger LOG = LogManager.getLogger(VelocityManager.class); @@ -105,6 +105,7 @@ public class VelocityManager { * @return a reference to the VelocityEngine used by all Struts Velocity results except directly * accessed *.vm pages (unless otherwise configured) */ + @Override public VelocityEngine getVelocityEngine() { return velocityEngine; } @@ -117,6 +118,7 @@ public class VelocityManager { * @param res the current HttpServletResponse * @return a new StrutsVelocityContext */ + @Override public Context createContext(ValueStack stack, HttpServletRequest req, HttpServletResponse res) { Context context = buildToolContext(); if (context == null) { @@ -182,6 +184,7 @@ public class VelocityManager { * * @param context the current servlet context */ + @Override public synchronized void init(ServletContext context) { if (velocityEngine == null) { velocityEngine = newVelocityEngine(context); diff --git a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/VelocityManagerInterface.java b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/VelocityManagerInterface.java new file mode 100644 index 000000000..66a9f46fe --- /dev/null +++ b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/VelocityManagerInterface.java @@ -0,0 +1,39 @@ +/* + * 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.views.velocity; + +import com.opensymphony.xwork2.util.ValueStack; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.context.Context; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * @since 6.4.0 + */ +public interface VelocityManagerInterface { + + Context createContext(ValueStack stack, HttpServletRequest req, HttpServletResponse res); + + VelocityEngine getVelocityEngine(); + + void init(ServletContext context); +} diff --git a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/result/VelocityResult.java b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/result/VelocityResult.java index 68b56451b..e65efd4f6 100644 --- a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/result/VelocityResult.java +++ b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/result/VelocityResult.java @@ -29,6 +29,7 @@ import org.apache.struts2.StrutsConstants; import org.apache.struts2.result.StrutsResultSupport; import org.apache.struts2.views.JspSupportServlet; import org.apache.struts2.views.velocity.VelocityManager; +import org.apache.struts2.views.velocity.VelocityManagerInterface; import org.apache.velocity.Template; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.context.Context; @@ -85,9 +86,9 @@ public class VelocityResult extends StrutsResultSupport { private static final long serialVersionUID = 7268830767762559424L; private static final Logger LOG = LogManager.getLogger(VelocityResult.class); - + private String defaultEncoding; - private VelocityManager velocityManager; + private VelocityManagerInterface velocityManager; private JspFactory jspFactory = JspFactory.getDefaultFactory(); public VelocityResult() { @@ -97,17 +98,25 @@ public class VelocityResult extends StrutsResultSupport { public VelocityResult(String location) { super(location); } - + @Inject(StrutsConstants.STRUTS_I18N_ENCODING) public void setDefaultEncoding(String val) { defaultEncoding = val; } - + @Inject - public void setVelocityManager(VelocityManager mgr) { + public void setVelocityManager(VelocityManagerInterface mgr) { this.velocityManager = mgr; } + /** + * @deprecated since 6.4.0 + */ + @Deprecated + public void setVelocityManager(VelocityManager mgr) { + setVelocityManager((VelocityManagerInterface) mgr); + } + /** * Creates a Velocity context from the action, loads a Velocity template and executes the * template. Output is written to the servlet output stream. @@ -232,7 +241,23 @@ public class VelocityResult extends StrutsResultSupport { * @param location the name of the template that is being used * @return the a minted Velocity context. */ - protected Context createContext(VelocityManager velocityManager, ValueStack stack, HttpServletRequest request, HttpServletResponse response, String location) { + protected Context createContext(VelocityManagerInterface velocityManager, + ValueStack stack, + HttpServletRequest request, + HttpServletResponse response, + String location) { return velocityManager.createContext(stack, request, response); } + + /** + * @deprecated since 6.4.0 + */ + @Deprecated + protected Context createContext(VelocityManager velocityManager, + ValueStack stack, + HttpServletRequest request, + HttpServletResponse response, + String location) { + return createContext((VelocityManagerInterface) velocityManager, stack, request, response, location); + } } diff --git a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/template/VelocityTemplateEngine.java b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/template/VelocityTemplateEngine.java index 423029e32..56641487c 100644 --- a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/template/VelocityTemplateEngine.java +++ b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/template/VelocityTemplateEngine.java @@ -26,6 +26,7 @@ import org.apache.struts2.components.template.BaseTemplateEngine; import org.apache.struts2.components.template.Template; import org.apache.struts2.components.template.TemplateRenderingContext; import org.apache.struts2.views.velocity.VelocityManager; +import org.apache.struts2.views.velocity.VelocityManagerInterface; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.context.Context; @@ -41,14 +42,22 @@ import java.util.Map; */ public class VelocityTemplateEngine extends BaseTemplateEngine { private static final Logger LOG = LogManager.getLogger(VelocityTemplateEngine.class); - - private VelocityManager velocityManager; - + + private VelocityManagerInterface velocityManager; + @Inject - public void setVelocityManager(VelocityManager mgr) { + public void setVelocityManager(VelocityManagerInterface mgr) { this.velocityManager = mgr; } + /** + * @deprecated since 6.4.0 + */ + @Deprecated + public void setVelocityManager(VelocityManager mgr) { + setVelocityManager((VelocityManagerInterface) mgr); + } + public void renderTemplate(TemplateRenderingContext templateContext) throws Exception { // get the various items required from the stack Map actionContext = templateContext.getStack().getContext(); From ace6a713c42fa9297ce4f0595371af0ecad1547d Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Fri, 2 Feb 2024 17:34:58 +1100 Subject: [PATCH 14/24] WW-5391 Fix VelocityDecoratorServlet --- .../sitemesh/VelocityDecoratorServlet.java | 389 +++++++++--------- 1 file changed, 196 insertions(+), 193 deletions(-) diff --git a/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/VelocityDecoratorServlet.java b/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/VelocityDecoratorServlet.java index 4859c4f59..b2079c2f2 100644 --- a/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/VelocityDecoratorServlet.java +++ b/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/VelocityDecoratorServlet.java @@ -1,193 +1,196 @@ -/* - * 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.sitemesh; - - -import com.opensymphony.module.sitemesh.*; -import com.opensymphony.module.sitemesh.util.OutputConverter; -import com.opensymphony.xwork2.ActionContext; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.struts2.ServletActionContext; -import org.apache.struts2.StrutsStatics; -import org.apache.struts2.dispatcher.Dispatcher; -import org.apache.struts2.dispatcher.listener.StrutsListener; -import org.apache.struts2.views.velocity.VelocityManager; -import org.apache.velocity.Template; -import org.apache.velocity.context.Context; -import org.apache.velocity.runtime.RuntimeConstants; -import org.apache.velocity.tools.view.VelocityView; -import org.apache.velocity.tools.view.VelocityViewServlet; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import java.io.IOException; -import java.io.StringWriter; - -/** - *

This is a SiteMesh Velocity view servlet.

- * - *

It overrides the SiteMesh servlet to rely on the - * Velocity Manager in Struts instead of creating it's - * own manager

- */ -public class VelocityDecoratorServlet extends VelocityViewServlet { - - private static final Logger LOG = LogManager.getLogger(VelocityDecoratorServlet.class); - - private static final long serialVersionUID = -6731485159371716918L; - - protected VelocityManager velocityManager; - protected String defaultContentType; - - /** - *

Initializes servlet, toolbox and Velocity template engine. - * Called by the servlet container on loading.

- * - *

NOTE: If no charset is specified in the default.contentType - * property (in your velocity.properties) and you have specified - * an output.encoding property, then that will be used as the - * charset for the default content-type of pages served by this - * servlet.

- * - * @param config servlet configuration - */ - public void init(ServletConfig config) throws ServletException { - super.init(config); - Dispatcher dispatcher = Dispatcher.getInstance(getServletContext()); - if (dispatcher == null) { - throw new IllegalStateException("Unable to find the Dispatcher in the Servlet Context. Is '" + StrutsListener.class.getName() + "' missing in web.xml?"); - } - velocityManager = dispatcher.getContainer().getInstance(VelocityManager.class); - velocityManager.init(config.getServletContext()); - - // do whatever we have to do to init Velocity - getVelocityView().setVelocityEngine(velocityManager.getVelocityEngine()); - // toolboxManager = velocityManager.getToolboxManager(); - - - // we can get these now that velocity is initialized - defaultContentType = getVelocityProperty(VelocityView.CONTENT_TYPE_KEY, VelocityView.DEFAULT_CONTENT_TYPE); - - String encoding = getVelocityProperty(RuntimeConstants.ENCODING_DEFAULT, VelocityView.DEFAULT_OUTPUT_ENCODING); - - // For non Latin-1 encodings, ensure that the charset is - // included in the Content-Type header. - if (!VelocityView.DEFAULT_OUTPUT_ENCODING.equalsIgnoreCase(encoding)) { - int index = defaultContentType.lastIndexOf("charset"); - if (index < 0) { - // the charset specifier is not yet present in header. - // append character encoding to default content-type - defaultContentType += "; charset=" + encoding; - } else { - // The user may have configuration issues. - getVelocityView().getVelocityEngine().getLog().warn("VelocityViewServlet: Charset was already " + "specified in the Content-Type property. " + "Output encoding property will be ignored."); - } - } - - getVelocityView().getVelocityEngine().getLog().info("VelocityViewServlet: Default content-type is: " + defaultContentType); - } - - public Template handleRequest(HttpServletRequest request, HttpServletResponse response, Context context) { - HTMLPage htmlPage = (HTMLPage) request.getAttribute(RequestConstants.PAGE); - String template; - - context.put("base", request.getContextPath()); - // For backwards compatibility with apps that used the old VelocityDecoratorServlet - // that extended VelocityServlet instead of VelocityViewServlet - context.put("req", request); - context.put("res", response); - - if (htmlPage == null) { - context.put("title", "Title?"); - context.put("body", "

Body?

"); - context.put("head", ""); - template = request.getServletPath(); - } else { - try { - context.put("title", OutputConverter.convert(htmlPage.getTitle())); - { - StringWriter buffer = new StringWriter(); - htmlPage.writeBody(OutputConverter.getWriter(buffer)); - context.put("body", buffer.toString()); - } - { - StringWriter buffer = new StringWriter(); - htmlPage.writeHead(OutputConverter.getWriter(buffer)); - context.put("head", buffer.toString()); - } - } catch (IOException e) { - LOG.error("IOException handle request template", e); - } - context.put("page", htmlPage); - DecoratorMapper decoratorMapper = getDecoratorMapper(); - Decorator decorator = decoratorMapper.getDecorator(request, htmlPage); - template = decorator.getPage(); - } - - return getTemplate(template); - } - - private DecoratorMapper getDecoratorMapper() { - Factory factory = Factory.getInstance(new Config(getServletConfig())); - return factory.getDecoratorMapper(); - } - - /** - *

Creates and returns an initialized Velocity context.

- * - * @param request servlet request from client - * @param response servlet reponse to client - */ - protected Context createContext(HttpServletRequest request, HttpServletResponse response) { - Context context = (Context) request.getAttribute(VelocityManager.KEY_VELOCITY_STRUTS_CONTEXT); - if (context == null) { - ActionContext ctx = ServletActionContext.getActionContext(request); - context = velocityManager.createContext(ctx.getValueStack(), request, response); - } - return context; - } - - /** - *

- * Sets the content type of the response. This is available to be overridden - * by a derived class. - *

- *

The default implementation is:

- *
-     *
-     *    response.setContentType(defaultContentType);
-     *
-     * 
- *

- * where defaultContentType is set to the value of the default.contentType - * property, or "text/html" if that is not set.

- * - * @param request servlet request from client - * @param response servlet reponse to client - */ - protected void setContentType(HttpServletRequest request, HttpServletResponse response) { - response.setContentType(defaultContentType); - } - -} +/* + * 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.sitemesh; + + +import com.opensymphony.module.sitemesh.Config; +import com.opensymphony.module.sitemesh.Decorator; +import com.opensymphony.module.sitemesh.DecoratorMapper; +import com.opensymphony.module.sitemesh.Factory; +import com.opensymphony.module.sitemesh.HTMLPage; +import com.opensymphony.module.sitemesh.RequestConstants; +import com.opensymphony.module.sitemesh.util.OutputConverter; +import com.opensymphony.xwork2.ActionContext; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.struts2.ServletActionContext; +import org.apache.struts2.dispatcher.Dispatcher; +import org.apache.struts2.dispatcher.listener.StrutsListener; +import org.apache.struts2.views.velocity.VelocityManager; +import org.apache.struts2.views.velocity.VelocityManagerInterface; +import org.apache.velocity.Template; +import org.apache.velocity.context.Context; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.tools.view.VelocityView; +import org.apache.velocity.tools.view.VelocityViewServlet; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.StringWriter; + +/** + *

This is a SiteMesh Velocity view servlet.

+ * + *

It overrides the SiteMesh servlet to rely on the + * Velocity Manager in Struts instead of creating it's + * own manager

+ */ +public class VelocityDecoratorServlet extends VelocityViewServlet { + + private static final Logger LOG = LogManager.getLogger(VelocityDecoratorServlet.class); + + private static final long serialVersionUID = -6731485159371716918L; + + protected VelocityManagerInterface velocityManager; + protected String defaultContentType; + + /** + *

Initializes servlet, toolbox and Velocity template engine. + * Called by the servlet container on loading.

+ * + *

NOTE: If no charset is specified in the default.contentType + * property (in your velocity.properties) and you have specified + * an output.encoding property, then that will be used as the + * charset for the default content-type of pages served by this + * servlet.

+ * + * @param config servlet configuration + */ + public void init(ServletConfig config) throws ServletException { + super.init(config); + Dispatcher dispatcher = Dispatcher.getInstance(getServletContext()); + if (dispatcher == null) { + throw new IllegalStateException("Unable to find the Dispatcher in the Servlet Context. Is '" + StrutsListener.class.getName() + "' missing in web.xml?"); + } + velocityManager = dispatcher.getContainer().getInstance(VelocityManagerInterface.class); + velocityManager.init(config.getServletContext()); + + // do whatever we have to do to init Velocity + getVelocityView().setVelocityEngine(velocityManager.getVelocityEngine()); + // toolboxManager = velocityManager.getToolboxManager(); + + + // we can get these now that velocity is initialized + defaultContentType = getVelocityProperty(VelocityView.CONTENT_TYPE_KEY, VelocityView.DEFAULT_CONTENT_TYPE); + + String encoding = getVelocityProperty(RuntimeConstants.ENCODING_DEFAULT, VelocityView.DEFAULT_OUTPUT_ENCODING); + + // For non Latin-1 encodings, ensure that the charset is + // included in the Content-Type header. + if (!VelocityView.DEFAULT_OUTPUT_ENCODING.equalsIgnoreCase(encoding)) { + int index = defaultContentType.lastIndexOf("charset"); + if (index < 0) { + // the charset specifier is not yet present in header. + // append character encoding to default content-type + defaultContentType += "; charset=" + encoding; + } else { + // The user may have configuration issues. + getVelocityView().getVelocityEngine().getLog().warn("VelocityViewServlet: Charset was already " + "specified in the Content-Type property. " + "Output encoding property will be ignored."); + } + } + + getVelocityView().getVelocityEngine().getLog().info("VelocityViewServlet: Default content-type is: " + defaultContentType); + } + + public Template handleRequest(HttpServletRequest request, HttpServletResponse response, Context context) { + HTMLPage htmlPage = (HTMLPage) request.getAttribute(RequestConstants.PAGE); + String template; + + context.put("base", request.getContextPath()); + // For backwards compatibility with apps that used the old VelocityDecoratorServlet + // that extended VelocityServlet instead of VelocityViewServlet + context.put("req", request); + context.put("res", response); + + if (htmlPage == null) { + context.put("title", "Title?"); + context.put("body", "

Body?

"); + context.put("head", ""); + template = request.getServletPath(); + } else { + try { + context.put("title", OutputConverter.convert(htmlPage.getTitle())); + { + StringWriter buffer = new StringWriter(); + htmlPage.writeBody(OutputConverter.getWriter(buffer)); + context.put("body", buffer.toString()); + } + { + StringWriter buffer = new StringWriter(); + htmlPage.writeHead(OutputConverter.getWriter(buffer)); + context.put("head", buffer.toString()); + } + } catch (IOException e) { + LOG.error("IOException handle request template", e); + } + context.put("page", htmlPage); + DecoratorMapper decoratorMapper = getDecoratorMapper(); + Decorator decorator = decoratorMapper.getDecorator(request, htmlPage); + template = decorator.getPage(); + } + + return getTemplate(template); + } + + private DecoratorMapper getDecoratorMapper() { + Factory factory = Factory.getInstance(new Config(getServletConfig())); + return factory.getDecoratorMapper(); + } + + /** + *

Creates and returns an initialized Velocity context.

+ * + * @param request servlet request from client + * @param response servlet reponse to client + */ + protected Context createContext(HttpServletRequest request, HttpServletResponse response) { + Context context = (Context) request.getAttribute(VelocityManager.KEY_VELOCITY_STRUTS_CONTEXT); + if (context == null) { + ActionContext ctx = ServletActionContext.getActionContext(request); + context = velocityManager.createContext(ctx.getValueStack(), request, response); + } + return context; + } + + /** + *

+ * Sets the content type of the response. This is available to be overridden + * by a derived class. + *

+ *

The default implementation is:

+ *
+     *
+     *    response.setContentType(defaultContentType);
+     *
+     * 
+ *

+ * where defaultContentType is set to the value of the default.contentType + * property, or "text/html" if that is not set.

+ * + * @param request servlet request from client + * @param response servlet reponse to client + */ + protected void setContentType(HttpServletRequest request, HttpServletResponse response) { + response.setContentType(defaultContentType); + } + +} From b5fca66ad0f182f5d239aa9c45a9068e4f227f59 Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Fri, 2 Feb 2024 17:42:56 +1100 Subject: [PATCH 15/24] WW-5391 Migrate other usages --- .../config_browser/ShowBeansAction.java | 4 +- ...dDecorator2NewStrutsVelocityDecorator.java | 211 +++++++++--------- .../struts2/sitemesh/VelocityPageFilter.java | 24 +- 3 files changed, 128 insertions(+), 111 deletions(-) diff --git a/plugins/config-browser/src/main/java/org/apache/struts2/config_browser/ShowBeansAction.java b/plugins/config-browser/src/main/java/org/apache/struts2/config_browser/ShowBeansAction.java index 8e97a87fd..1e8dab8be 100644 --- a/plugins/config-browser/src/main/java/org/apache/struts2/config_browser/ShowBeansAction.java +++ b/plugins/config-browser/src/main/java/org/apache/struts2/config_browser/ShowBeansAction.java @@ -30,7 +30,7 @@ import org.apache.struts2.dispatcher.mapper.ActionMapper; import org.apache.struts2.dispatcher.multipart.MultiPartRequest; import org.apache.struts2.views.freemarker.FreemarkerManager; import org.apache.struts2.views.velocity.VelocityConstants; -import org.apache.struts2.views.velocity.VelocityManager; +import org.apache.struts2.views.velocity.VelocityManagerInterface; import java.util.Map; import java.util.Set; @@ -56,7 +56,7 @@ public class ShowBeansAction extends ActionNamesAction { bindings.put(ActionMapper.class.getName(), addBindings(container, ActionMapper.class, StrutsConstants.STRUTS_MAPPER_CLASS)); bindings.put(MultiPartRequest.class.getName(), addBindings(container, MultiPartRequest.class, StrutsConstants.STRUTS_MULTIPART_PARSER)); bindings.put(FreemarkerManager.class.getName(), addBindings(container, FreemarkerManager.class, StrutsConstants.STRUTS_FREEMARKER_MANAGER_CLASSNAME)); - bindings.put(VelocityManager.class.getName(), addBindings(container, VelocityManager.class, VelocityConstants.STRUTS_VELOCITY_MANAGER_CLASSNAME)); + bindings.put(VelocityManagerInterface.class.getName(), addBindings(container, VelocityManagerInterface.class, VelocityConstants.STRUTS_VELOCITY_MANAGER_CLASSNAME)); bindings.put(UrlRenderer.class.getName(), addBindings(container, UrlRenderer.class, StrutsConstants.STRUTS_URL_RENDERER)); } diff --git a/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsVelocityDecorator.java b/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsVelocityDecorator.java index cd0417364..33d5b1f3a 100644 --- a/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsVelocityDecorator.java +++ b/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsVelocityDecorator.java @@ -1,101 +1,110 @@ -/* - * 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.sitemesh; - -import com.opensymphony.module.sitemesh.HTMLPage; -import com.opensymphony.sitemesh.Content; -import com.opensymphony.sitemesh.compatability.Content2HTMLPage; -import com.opensymphony.xwork2.ActionContext; -import com.opensymphony.xwork2.inject.Inject; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.LogManager; -import org.apache.struts2.views.velocity.VelocityManager; -import org.apache.velocity.context.Context; - -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.PrintWriter; - -/** - * Extends OldDecorator2NewStrutsDecorator to add Struts functionality for Velocity - */ -public class OldDecorator2NewStrutsVelocityDecorator extends OldDecorator2NewStrutsDecorator { - private static final Logger LOG = LogManager.getLogger(OldDecorator2NewStrutsFreemarkerDecorator.class); - - private static VelocityManager velocityManager; - - @Inject(required = false) - public static void setVelocityManager(VelocityManager mgr) { - velocityManager = mgr; - } - - public OldDecorator2NewStrutsVelocityDecorator(com.opensymphony.module.sitemesh.Decorator oldDecorator) { - this.oldDecorator = oldDecorator; - } - - /** - * Applies the decorator, using the relevent contexts - * - * @param content The content - * @param request The servlet request - * @param response The servlet response - * @param servletContext The servlet context - * @param ctx The action context for this request, populated with the server state - */ - protected void render(Content content, HttpServletRequest request, HttpServletResponse response, ServletContext servletContext, ActionContext ctx) throws ServletException, IOException { - if (velocityManager == null) { - throw new ServletException("Missing freemarker dependency"); - } - - try { - - // init (if needed) - velocityManager.init(servletContext); - - // get encoding - String encoding = getEncoding(); - - HTMLPage htmlPage = new Content2HTMLPage(content, request); - - // get the template and context - org.apache.velocity.Template template = velocityManager.getVelocityEngine().getTemplate(oldDecorator.getPage(), encoding); - Context context = velocityManager.createContext(ctx.getValueStack(), request, response); - - // put the page in the context - context.put("page", htmlPage); - context.put("head", htmlPage.getHead()); - context.put("title", htmlPage.getTitle()); - context.put("body", htmlPage.getBody()); - - // finally, render it - PrintWriter writer = response.getWriter(); - template.merge(context, writer); - writer.flush(); - } catch (Exception e) { - String msg = "Error applying decorator to request: " + request.getRequestURL() + "?" + request.getQueryString() + " with message:" + e.getMessage(); - LOG.error(msg, e); - throw new ServletException(msg, e); - } - } - -} - +/* + * 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.sitemesh; + +import com.opensymphony.module.sitemesh.HTMLPage; +import com.opensymphony.sitemesh.Content; +import com.opensymphony.sitemesh.compatability.Content2HTMLPage; +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.inject.Inject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.struts2.views.velocity.VelocityManager; +import org.apache.struts2.views.velocity.VelocityManagerInterface; +import org.apache.velocity.context.Context; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +/** + * Extends OldDecorator2NewStrutsDecorator to add Struts functionality for Velocity + */ +public class OldDecorator2NewStrutsVelocityDecorator extends OldDecorator2NewStrutsDecorator { + private static final Logger LOG = LogManager.getLogger(OldDecorator2NewStrutsFreemarkerDecorator.class); + + private static VelocityManagerInterface velocityManager; + + @Inject(required = false) + public static void setVelocityManager(VelocityManagerInterface mgr) { + velocityManager = mgr; + } + + /** + * @deprecated since 6.4.0 + */ + @Deprecated + public static void setVelocityManager(VelocityManager mgr) { + setVelocityManager((VelocityManagerInterface) mgr); + } + + public OldDecorator2NewStrutsVelocityDecorator(com.opensymphony.module.sitemesh.Decorator oldDecorator) { + this.oldDecorator = oldDecorator; + } + + /** + * Applies the decorator, using the relevent contexts + * + * @param content The content + * @param request The servlet request + * @param response The servlet response + * @param servletContext The servlet context + * @param ctx The action context for this request, populated with the server state + */ + protected void render(Content content, HttpServletRequest request, HttpServletResponse response, ServletContext servletContext, ActionContext ctx) throws ServletException, IOException { + if (velocityManager == null) { + throw new ServletException("Missing freemarker dependency"); + } + + try { + + // init (if needed) + velocityManager.init(servletContext); + + // get encoding + String encoding = getEncoding(); + + HTMLPage htmlPage = new Content2HTMLPage(content, request); + + // get the template and context + org.apache.velocity.Template template = velocityManager.getVelocityEngine().getTemplate(oldDecorator.getPage(), encoding); + Context context = velocityManager.createContext(ctx.getValueStack(), request, response); + + // put the page in the context + context.put("page", htmlPage); + context.put("head", htmlPage.getHead()); + context.put("title", htmlPage.getTitle()); + context.put("body", htmlPage.getBody()); + + // finally, render it + PrintWriter writer = response.getWriter(); + template.merge(context, writer); + writer.flush(); + } catch (Exception e) { + String msg = "Error applying decorator to request: " + request.getRequestURL() + "?" + request.getQueryString() + " with message:" + e.getMessage(); + LOG.error(msg, e); + throw new ServletException(msg, e); + } + } + +} + diff --git a/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/VelocityPageFilter.java b/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/VelocityPageFilter.java index 22de2c60a..d4a2314df 100644 --- a/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/VelocityPageFilter.java +++ b/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/VelocityPageFilter.java @@ -18,16 +18,16 @@ */ package org.apache.struts2.sitemesh; -import com.opensymphony.sitemesh.webapp.SiteMeshWebAppContext; -import com.opensymphony.sitemesh.webapp.SiteMeshFilter; -import com.opensymphony.sitemesh.DecoratorSelector; -import com.opensymphony.module.sitemesh.Factory; import com.opensymphony.module.sitemesh.Config; +import com.opensymphony.module.sitemesh.Factory; +import com.opensymphony.sitemesh.DecoratorSelector; +import com.opensymphony.sitemesh.webapp.SiteMeshFilter; +import com.opensymphony.sitemesh.webapp.SiteMeshWebAppContext; import com.opensymphony.xwork2.inject.Inject; - -import javax.servlet.*; - import org.apache.struts2.views.velocity.VelocityManager; +import org.apache.struts2.views.velocity.VelocityManagerInterface; + +import javax.servlet.FilterConfig; /** * Core Filter for integrating SiteMesh into a Java web application. @@ -35,10 +35,18 @@ import org.apache.struts2.views.velocity.VelocityManager; public class VelocityPageFilter extends SiteMeshFilter { @Inject(required=false) - public static void setVelocityManager(VelocityManager mgr) { + public static void setVelocityManager(VelocityManagerInterface mgr) { OldDecorator2NewStrutsVelocityDecorator.setVelocityManager(mgr); } + /** + * @deprecated since 6.4.0 + */ + @Deprecated + public static void setVelocityManager(VelocityManager mgr) { + setVelocityManager((VelocityManagerInterface) mgr); + } + private FilterConfig filterConfig; public void init(FilterConfig filterConfig) { From 93f0a5116bbab250751afc56d8d6fa0b1592ab52 Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Fri, 2 Feb 2024 17:48:14 +1100 Subject: [PATCH 16/24] WW-5391 Fix bean definition --- plugins/velocity/src/main/resources/struts-plugin.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/velocity/src/main/resources/struts-plugin.xml b/plugins/velocity/src/main/resources/struts-plugin.xml index 7630d41e3..b19aec9f2 100644 --- a/plugins/velocity/src/main/resources/struts-plugin.xml +++ b/plugins/velocity/src/main/resources/struts-plugin.xml @@ -25,6 +25,10 @@ + + + Date: Sat, 3 Feb 2024 13:18:02 +1100 Subject: [PATCH 17/24] WW-5391 Fix serialisation warnings --- .../apache/struts2/portlet/result/PortletVelocityResult.java | 2 +- .../apache/struts2/views/velocity/result/VelocityResult.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/portlet/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java index d40ce9331..d4e1ba2ee 100644 --- a/plugins/portlet/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java +++ b/plugins/portlet/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java @@ -92,7 +92,7 @@ public class PortletVelocityResult extends StrutsResultSupport { private static final Logger LOG = LogManager.getLogger(PortletVelocityResult.class); private String defaultEncoding; - private VelocityManagerInterface velocityManager; + private transient VelocityManagerInterface velocityManager; private JspFactory jspFactory = JspFactory.getDefaultFactory(); public PortletVelocityResult() { diff --git a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/result/VelocityResult.java b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/result/VelocityResult.java index e65efd4f6..a6ef31574 100644 --- a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/result/VelocityResult.java +++ b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/result/VelocityResult.java @@ -88,7 +88,7 @@ public class VelocityResult extends StrutsResultSupport { private static final Logger LOG = LogManager.getLogger(VelocityResult.class); private String defaultEncoding; - private VelocityManagerInterface velocityManager; + private transient VelocityManagerInterface velocityManager; private JspFactory jspFactory = JspFactory.getDefaultFactory(); public VelocityResult() { From 6d6097c729dc3cf33e74fa3030b8843817b2c538 Mon Sep 17 00:00:00 2001 From: Aleksandr Mashchenko Date: Sat, 10 Feb 2024 15:48:06 +0200 Subject: [PATCH 18/24] WW-5394 Use request encoding --- .../struts2/rest/ContentTypeInterceptor.java | 3 +- .../rest/ContentTypeInterceptorTest.java | 154 ++++++++++++++++++ 2 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 plugins/rest/src/test/java/org/apache/struts2/rest/ContentTypeInterceptorTest.java diff --git a/plugins/rest/src/main/java/org/apache/struts2/rest/ContentTypeInterceptor.java b/plugins/rest/src/main/java/org/apache/struts2/rest/ContentTypeInterceptor.java index 40924fc5a..03d299c86 100644 --- a/plugins/rest/src/main/java/org/apache/struts2/rest/ContentTypeInterceptor.java +++ b/plugins/rest/src/main/java/org/apache/struts2/rest/ContentTypeInterceptor.java @@ -51,8 +51,9 @@ public class ContentTypeInterceptor extends AbstractInterceptor { } if (request.getContentLength() > 0) { + final String encoding = request.getCharacterEncoding(); InputStream is = request.getInputStream(); - InputStreamReader reader = new InputStreamReader(is); + InputStreamReader reader = encoding == null ? new InputStreamReader(is) : new InputStreamReader(is, encoding); handler.toObject(invocation, reader, target); } return invocation.invoke(); diff --git a/plugins/rest/src/test/java/org/apache/struts2/rest/ContentTypeInterceptorTest.java b/plugins/rest/src/test/java/org/apache/struts2/rest/ContentTypeInterceptorTest.java new file mode 100644 index 000000000..ed1f7e8e7 --- /dev/null +++ b/plugins/rest/src/test/java/org/apache/struts2/rest/ContentTypeInterceptorTest.java @@ -0,0 +1,154 @@ +/* + * 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.rest; + +import com.mockobjects.dynamic.AnyConstraintMatcher; +import com.mockobjects.dynamic.Mock; +import com.opensymphony.xwork2.Action; +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.ActionSupport; +import junit.framework.TestCase; + +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +import org.apache.struts2.dispatcher.mapper.ActionMapping; +import org.apache.struts2.rest.handler.ContentTypeHandler; +import org.springframework.mock.web.MockHttpServletRequest; + +public class ContentTypeInterceptorTest extends TestCase { + + public void testRequestWithoutEncoding() throws Exception { + ContentTypeInterceptor interceptor = new ContentTypeInterceptor(); + + ActionSupport action = new ActionSupport(); + + Mock mockActionInvocation = new Mock(ActionInvocation.class); + Mock mockContentTypeHandler = new Mock(ContentTypeHandler.class); + mockContentTypeHandler.expect("toObject", new AnyConstraintMatcher() { + public boolean matches(Object[] args) { + return true; + } + }); + mockActionInvocation.expectAndReturn("invoke", Action.SUCCESS); + mockActionInvocation.expectAndReturn("getAction", action); + Mock mockContentTypeHandlerManager = new Mock(ContentTypeHandlerManager.class); + mockContentTypeHandlerManager.expectAndReturn("getHandlerForRequest", new AnyConstraintMatcher() { + public boolean matches(Object[] args) { + return true; + } + }, mockContentTypeHandler.proxy()); + interceptor.setContentTypeHandlerSelector((ContentTypeHandlerManager) mockContentTypeHandlerManager.proxy()); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setContent(new byte[] {1}); + + ActionContext.of() + .withActionMapping(new ActionMapping()) + .withServletRequest(request) + .bind(); + + interceptor.intercept((ActionInvocation) mockActionInvocation.proxy()); + mockContentTypeHandlerManager.verify(); + mockActionInvocation.verify(); + mockContentTypeHandler.verify(); + } + + public void testRequestWithEncodingAscii() throws Exception { + final Charset charset = StandardCharsets.US_ASCII; + + ContentTypeInterceptor interceptor = new ContentTypeInterceptor(); + + ActionSupport action = new ActionSupport(); + + Mock mockActionInvocation = new Mock(ActionInvocation.class); + Mock mockContentTypeHandler = new Mock(ContentTypeHandler.class); + mockContentTypeHandler.expect("toObject", new AnyConstraintMatcher() { + public boolean matches(Object[] args) { + InputStreamReader in = (InputStreamReader) args[1]; + return charset.equals(Charset.forName(in.getEncoding())); + } + }); + mockActionInvocation.expectAndReturn("invoke", Action.SUCCESS); + mockActionInvocation.expectAndReturn("getAction", action); + Mock mockContentTypeHandlerManager = new Mock(ContentTypeHandlerManager.class); + mockContentTypeHandlerManager.expectAndReturn("getHandlerForRequest", new AnyConstraintMatcher() { + public boolean matches(Object[] args) { + return true; + } + }, mockContentTypeHandler.proxy()); + interceptor.setContentTypeHandlerSelector((ContentTypeHandlerManager) mockContentTypeHandlerManager.proxy()); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setContent(new byte[] {1}); + request.setCharacterEncoding(charset.name()); + + ActionContext.of() + .withActionMapping(new ActionMapping()) + .withServletRequest(request) + .bind(); + + interceptor.intercept((ActionInvocation) mockActionInvocation.proxy()); + mockContentTypeHandlerManager.verify(); + mockActionInvocation.verify(); + mockContentTypeHandler.verify(); + } + + public void testRequestWithEncodingUtf() throws Exception { + final Charset charset = StandardCharsets.UTF_8; + + ContentTypeInterceptor interceptor = new ContentTypeInterceptor(); + + ActionSupport action = new ActionSupport(); + + Mock mockActionInvocation = new Mock(ActionInvocation.class); + Mock mockContentTypeHandler = new Mock(ContentTypeHandler.class); + mockContentTypeHandler.expect("toObject", new AnyConstraintMatcher() { + public boolean matches(Object[] args) { + InputStreamReader in = (InputStreamReader) args[1]; + return charset.equals(Charset.forName(in.getEncoding())); + } + }); + mockActionInvocation.expectAndReturn("invoke", Action.SUCCESS); + mockActionInvocation.expectAndReturn("getAction", action); + Mock mockContentTypeHandlerManager = new Mock(ContentTypeHandlerManager.class); + mockContentTypeHandlerManager.expectAndReturn("getHandlerForRequest", new AnyConstraintMatcher() { + public boolean matches(Object[] args) { + return true; + } + }, mockContentTypeHandler.proxy()); + interceptor.setContentTypeHandlerSelector((ContentTypeHandlerManager) mockContentTypeHandlerManager.proxy()); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setContent(new byte[] {1}); + request.setCharacterEncoding(charset.name()); + + ActionContext.of() + .withActionMapping(new ActionMapping()) + .withServletRequest(request) + .bind(); + + interceptor.intercept((ActionInvocation) mockActionInvocation.proxy()); + mockContentTypeHandlerManager.verify(); + mockActionInvocation.verify(); + mockContentTypeHandler.verify(); + } +} From 07f0d1eddb3d26157b6fa2c4455831f45755836a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 01:50:29 +0000 Subject: [PATCH 19/24] Bump commons-logging:commons-logging from 1.2 to 1.3.0 Bumps commons-logging:commons-logging from 1.2 to 1.3.0. --- updated-dependencies: - dependency-name: commons-logging:commons-logging dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3fd6b92f7..80bb602a6 100644 --- a/pom.xml +++ b/pom.xml @@ -851,7 +851,7 @@ commons-logging commons-logging - 1.2 + 1.3.0 org.apache.commons From e9eae281c32bac411d4a29308152ff17a4da9c81 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 01:53:45 +0000 Subject: [PATCH 20/24] Bump actions/upload-artifact from 4.3.0 to 4.3.1 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.3.0 to 4.3.1. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/26f96dfa697d77e81fd5907df203aa23a56210a8...5d5d22a31266ced268874388b861e4b58bb5c2f3) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/scorecards-analysis.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards-analysis.yaml b/.github/workflows/scorecards-analysis.yaml index 192f6cda6..67faabc82 100644 --- a/.github/workflows/scorecards-analysis.yaml +++ b/.github/workflows/scorecards-analysis.yaml @@ -57,7 +57,7 @@ jobs: publish_results: true - name: "Upload artifact" - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # 4.3.0 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # 4.3.1 with: name: SARIF file path: results.sarif From e3ca240b7059c50b762fee490d7d53e6804452be Mon Sep 17 00:00:00 2001 From: Greg Huber Date: Wed, 14 Feb 2024 10:50:50 +0000 Subject: [PATCH 21/24] s:file shows server/file location WW-5396 --- .../java/org/apache/struts2/views/java/simple/FileHandler.java | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/FileHandler.java b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/FileHandler.java index 1c0b7275a..1ccdd8efa 100644 --- a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/FileHandler.java +++ b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/FileHandler.java @@ -33,7 +33,6 @@ public class FileHandler extends AbstractTagHandler implements TagGenerator { a.addDefaultToEmpty("name", params.get("name")) .add("type", "file") .addIfExists("size", params.get("size")) - .addIfExists("value", params.get("nameValue")) .addIfTrue("disabled", params.get("disabled")) .addIfExists("accept", params.get("accept")) .addIfExists("tabindex", params.get("tabindex")) From de9aacef61e280bed62a74008e060ae5a24005ab Mon Sep 17 00:00:00 2001 From: Greg Huber Date: Wed, 14 Feb 2024 11:04:43 +0000 Subject: [PATCH 22/24] s:file shows server/file location WW-5396 --- .../java/org/apache/struts2/views/java/simple/FileTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FileTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FileTest.java index 0a455c28a..16ce86b65 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FileTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FileTest.java @@ -28,7 +28,6 @@ public class FileTest extends AbstractCommonAttributesTest { public void testRenderTextField() { tag.setName("name"); - tag.setValue("val1"); tag.setSize("10"); tag.setDisabled("true"); tag.setAccept("accept_"); @@ -43,7 +42,7 @@ public class FileTest extends AbstractCommonAttributesTest { map.putAll(tag.getParameters()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); - String expected = s(""); + String expected = s(""); assertEquals(expected, output); } From 1c59b45a23e843238be74fdefb77e5368dc137c1 Mon Sep 17 00:00:00 2001 From: Greg Huber Date: Wed, 14 Feb 2024 11:52:38 +0000 Subject: [PATCH 23/24] s:file shows server/file location WW-5396 --- core/src/main/java/org/apache/struts2/components/File.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/src/main/java/org/apache/struts2/components/File.java b/core/src/main/java/org/apache/struts2/components/File.java index 09b91a7ad..f93ac7742 100644 --- a/core/src/main/java/org/apache/struts2/components/File.java +++ b/core/src/main/java/org/apache/struts2/components/File.java @@ -99,4 +99,10 @@ public class File extends UIBean { public void setSize(String size) { this.size = size; } + + @Override + @StrutsTagAttribute(description="Ignored during file upload") + public void setValue(String value) { + // ignores provided value + } } From bb3edaec0630b19d7dcc10026113fe3183f57938 Mon Sep 17 00:00:00 2001 From: Greg Huber Date: Wed, 14 Feb 2024 12:00:53 +0000 Subject: [PATCH 24/24] s:file shows server/file location WW-5396 --- core/src/site/resources/tags/file-attributes.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/site/resources/tags/file-attributes.html b/core/src/site/resources/tags/file-attributes.html index 5f51badb6..e23f5dca5 100644 --- a/core/src/site/resources/tags/file-attributes.html +++ b/core/src/site/resources/tags/file-attributes.html @@ -371,6 +371,6 @@ false String - Preset the value of input element. + Ignored during file upload