From 09eb2860207f9237b3326ea2100591771dadf3a5 Mon Sep 17 00:00:00 2001 From: JCgH4164838Gh792C124B5 <43964333+JCgH4164838Gh792C124B5@users.noreply.github.com> Date: Sun, 6 Oct 2024 15:37:16 -0400 Subject: [PATCH 01/33] Initial Commit: - Fix for boundary condition bug in JakartaMultipartRequest that results in a NPE when struts.multipart.maxStringLength is not explicitly set, and normal fields are processed along with a file upload. - Additional unit tests for file upload interceptors to confirm functionality with-or-without max parameters being set when a file upload is processed alone as well as with normal fields. --- .../multipart/JakartaMultiPartRequest.java | 2 +- .../ActionFileUploadInterceptorTest.java | 151 +++++++++++++++ .../FileUploadInterceptorTest.java | 181 +++++++++++++++++- 3 files changed, 332 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java b/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java index 491d3d41d..c2cc07dbb 100644 --- a/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java +++ b/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java @@ -142,7 +142,7 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest { } long size = item.getSize(); - if (size > maxStringLength) { + if (maxStringLength != null && size > maxStringLength) { LOG.debug("Form field {} of size {} bytes exceeds limit of {}.", sanitizeNewlines(item.getFieldName()), size, maxStringLength); String errorKey = "struts.messages.upload.error.parameter.too.long"; LocalizedMessage localizedMessage = new LocalizedMessage(this.getClass(), errorKey, null, diff --git a/core/src/test/java/org/apache/struts2/interceptor/ActionFileUploadInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/ActionFileUploadInterceptorTest.java index 1fbb5017b..81aa122ed 100644 --- a/core/src/test/java/org/apache/struts2/interceptor/ActionFileUploadInterceptorTest.java +++ b/core/src/test/java/org/apache/struts2/interceptor/ActionFileUploadInterceptorTest.java @@ -324,6 +324,148 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase { assertNotNull("deleteme.txt", files.get(0).getOriginalName()); } + public void testSuccessUploadOfATextFileMultipartRequestNoMaxParamsSet() throws Exception { + MockHttpServletRequest req = new MockHttpServletRequest(); + req.setCharacterEncoding(StandardCharsets.UTF_8.name()); + req.setMethod("post"); + req.addHeader("Content-type", "multipart/form-data; boundary=---1234"); + + // inspired by the unit tests for jakarta commons fileupload + String content = ("-----1234\r\n" + + "Content-Disposition: form-data; name=\"file\"; filename=\"deleteme.txt\"\r\n" + + "Content-Type: text/html\r\n" + + "\r\n" + + "Unit test of ActionFileUploadInterceptor" + + "\r\n" + + "-----1234--\r\n"); + req.setContent(content.getBytes(StandardCharsets.US_ASCII)); + + MyFileUploadAction action = new MyFileUploadAction(); + + MockActionInvocation mai = new MockActionInvocation(); + mai.setAction(action); + mai.setResultCode("success"); + mai.setInvocationContext(ActionContext.getContext()); + ActionContext.getContext().withServletRequest(createMultipartRequestNoMaxParamsSet(req)); + + interceptor.intercept(mai); + + assertFalse(action.hasErrors()); + + List files = action.getUploadFiles(); + + assertNotNull(files); + assertEquals(1, files.size()); + assertEquals("text/html", files.get(0).getContentType()); + assertNotNull("deleteme.txt", files.get(0).getOriginalName()); + } + + public void testSuccessUploadOfATextFileMultipartRequestWithNormalFieldsMaxParamsSet() throws Exception { + MockHttpServletRequest req = new MockHttpServletRequest(); + req.setCharacterEncoding(StandardCharsets.UTF_8.name()); + req.setMethod("post"); + req.addHeader("Content-type", "multipart/form-data; boundary=---1234"); + + // inspired by the unit tests for jakarta commons fileupload + String content = ("-----1234\r\n" + + "Content-Disposition: form-data; name=\"file\"; filename=\"deleteme.txt\"\r\n" + + "Content-Type: text/html\r\n" + + "\r\n" + + "Unit test of ActionFileUploadInterceptor" + + "\r\n" + + "-----1234\r\n" + + "Content-Disposition: form-data; name=\"normalFormField1\"\r\n" + + "\r\n" + + "normal field 1" + + "\r\n" + + "-----1234\r\n" + + "Content-Disposition: form-data; name=\"normalFormField2\"\r\n" + + "\r\n" + + "normal field 2" + + "\r\n" + + "-----1234--\r\n"); + req.setContent(content.getBytes(StandardCharsets.US_ASCII)); + + MyFileUploadAction action = new MyFileUploadAction(); + + MockActionInvocation mai = new MockActionInvocation(); + mai.setAction(action); + mai.setResultCode("success"); + mai.setInvocationContext(ActionContext.getContext()); + ActionContext.getContext().withServletRequest(createMultipartRequest(req, 2000, 2000, 5, 100)); + + interceptor.intercept(mai); + + assertFalse(action.hasErrors()); + + List files = action.getUploadFiles(); + + assertNotNull(files); + assertEquals(1, files.size()); + assertEquals("text/html", files.get(0).getContentType()); + assertNotNull("deleteme.txt", files.get(0).getOriginalName()); + + // Confirm normalFormField1, normalFormField2 were processed by the MultiPartRequestWrapper. + HttpServletRequest invocationServletRequest = mai.getInvocationContext().getServletRequest(); + assertTrue("invocation servelt request is not a MultiPartRequestWrapper ?", invocationServletRequest instanceof MultiPartRequestWrapper); + MultiPartRequestWrapper multipartRequestWrapper = (MultiPartRequestWrapper) invocationServletRequest; + assertNotNull("normalFormField1 missing from MultiPartRequestWrapper parameters ?", multipartRequestWrapper.getParameter("normalFormField1")); + assertNotNull("normalFormField2 missing from MultiPartRequestWrapper parameters ?", multipartRequestWrapper.getParameter("normalFormField2")); + } + + public void testSuccessUploadOfATextFileMultipartRequestWithNormalFieldsNoMaxParamsSet() throws Exception { + MockHttpServletRequest req = new MockHttpServletRequest(); + req.setCharacterEncoding(StandardCharsets.UTF_8.name()); + req.setMethod("post"); + req.addHeader("Content-type", "multipart/form-data; boundary=---1234"); + + // inspired by the unit tests for jakarta commons fileupload + String content = ("-----1234\r\n" + + "Content-Disposition: form-data; name=\"file\"; filename=\"deleteme.txt\"\r\n" + + "Content-Type: text/html\r\n" + + "\r\n" + + "Unit test of ActionFileUploadInterceptor" + + "\r\n" + + "-----1234\r\n" + + "Content-Disposition: form-data; name=\"normalFormField1\"\r\n" + + "\r\n" + + "normal field 1" + + "\r\n" + + "-----1234\r\n" + + "Content-Disposition: form-data; name=\"normalFormField2\"\r\n" + + "\r\n" + + "normal field 2" + + "\r\n" + + "-----1234--\r\n"); + req.setContent(content.getBytes(StandardCharsets.US_ASCII)); + + MyFileUploadAction action = new MyFileUploadAction(); + + MockActionInvocation mai = new MockActionInvocation(); + mai.setAction(action); + mai.setResultCode("success"); + mai.setInvocationContext(ActionContext.getContext()); + ActionContext.getContext().withServletRequest(createMultipartRequestNoMaxParamsSet(req)); + + interceptor.intercept(mai); + + assertFalse(action.hasErrors()); + + List files = action.getUploadFiles(); + + assertNotNull(files); + assertEquals(1, files.size()); + assertEquals("text/html", files.get(0).getContentType()); + assertNotNull("deleteme.txt", files.get(0).getOriginalName()); + + // Confirm normalFormField1, normalFormField2 were processed by the MultiPartRequestWrapper. + HttpServletRequest invocationServletRequest = mai.getInvocationContext().getServletRequest(); + assertTrue("invocation servelt request is not a MultiPartRequestWrapper ?", invocationServletRequest instanceof MultiPartRequestWrapper); + MultiPartRequestWrapper multipartRequestWrapper = (MultiPartRequestWrapper) invocationServletRequest; + assertNotNull("normalFormField1 missing from MultiPartRequestWrapper parameters ?", multipartRequestWrapper.getParameter("normalFormField1")); + assertNotNull("normalFormField2 missing from MultiPartRequestWrapper parameters ?", multipartRequestWrapper.getParameter("normalFormField2")); + } + /** * tests whether with multiple files sent with the same name, the ones with forbiddenTypes (see * ActionFileUploadInterceptor.setAllowedTypes(...) ) are sorted out. @@ -564,6 +706,12 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase { return new MultiPartRequestWrapper(jak, req, tempDir.getAbsolutePath(), new DefaultLocaleProvider()); } + private MultiPartRequestWrapper createMultipartRequestNoMaxParamsSet(HttpServletRequest req) { + + JakartaMultiPartRequest jak = new JakartaMultiPartRequest(); + return new MultiPartRequestWrapper(jak, req, tempDir.getAbsolutePath(), new DefaultLocaleProvider()); + } + protected void setUp() throws Exception { super.setUp(); @@ -583,6 +731,9 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase { public static class MyFileUploadAction extends ActionSupport implements UploadedFilesAware { private List uploadedFiles; + // Note: We do not currently need fields/getters/setters for normalFormField1, normalFormField2 since + // the upload interceptor only prepares the normal field parameters. + @Override public void withUploadedFiles(List uploadedFiles) { this.uploadedFiles = uploadedFiles; diff --git a/core/src/test/java/org/apache/struts2/interceptor/FileUploadInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/FileUploadInterceptorTest.java index 040a2f61a..36fad5847 100644 --- a/core/src/test/java/org/apache/struts2/interceptor/FileUploadInterceptorTest.java +++ b/core/src/test/java/org/apache/struts2/interceptor/FileUploadInterceptorTest.java @@ -329,6 +329,178 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase { assertNotNull("deleteme.txt", fileRealFilenames[0]); } + public void testSuccessUploadOfATextFileMultipartRequestNoMaxParamsSet() throws Exception { + MockHttpServletRequest req = new MockHttpServletRequest(); + req.setCharacterEncoding(StandardCharsets.UTF_8.name()); + req.setMethod("post"); + req.addHeader("Content-type", "multipart/form-data; boundary=---1234"); + + // inspired by the unit tests for jakarta commons fileupload + String content = ("-----1234\r\n" + + "Content-Disposition: form-data; name=\"file\"; filename=\"deleteme.txt\"\r\n" + + "Content-Type: text/html\r\n" + + "\r\n" + + "Unit test of FileUploadInterceptor" + + "\r\n" + + "-----1234--\r\n"); + req.setContent(content.getBytes(StandardCharsets.US_ASCII)); + + MyFileupAction action = new MyFileupAction(); + + MockActionInvocation mai = new MockActionInvocation(); + mai.setAction(action); + mai.setResultCode("success"); + mai.setInvocationContext(ActionContext.getContext()); + Map param = new HashMap<>(); + ActionContext.getContext().withParameters(HttpParameters.create(param).build()); + ActionContext.getContext().withServletRequest(createMultipartRequestNoMaxParamsSet(req)); + + interceptor.intercept(mai); + + assertFalse(action.hasErrors()); + + HttpParameters parameters = mai.getInvocationContext().getParameters(); + assertEquals(3, parameters.keySet().size()); + UploadedFile[] files = (UploadedFile[]) parameters.get("file").getObject(); + String[] fileContentTypes = parameters.get("fileContentType").getMultipleValues(); + String[] fileRealFilenames = parameters.get("fileFileName").getMultipleValues(); + + assertNotNull(files); + assertNotNull(fileContentTypes); + assertNotNull(fileRealFilenames); + assertEquals(1, files.length); + assertEquals(1, fileContentTypes.length); + assertEquals(1, fileRealFilenames.length); + assertEquals("text/html", fileContentTypes[0]); + assertNotNull("deleteme.txt", fileRealFilenames[0]); + } + + public void testSuccessUploadOfATextFileMultipartRequestWithNormalFieldsMaxParamsSet() throws Exception { + MockHttpServletRequest req = new MockHttpServletRequest(); + req.setCharacterEncoding(StandardCharsets.UTF_8.name()); + req.setMethod("post"); + req.addHeader("Content-type", "multipart/form-data; boundary=---1234"); + + // inspired by the unit tests for jakarta commons fileupload + String content = ("-----1234\r\n" + + "Content-Disposition: form-data; name=\"file\"; filename=\"deleteme.txt\"\r\n" + + "Content-Type: text/html\r\n" + + "\r\n" + + "Unit test of FileUploadInterceptor" + + "\r\n" + + "-----1234\r\n" + + "Content-Disposition: form-data; name=\"normalFormField1\"\r\n" + + "\r\n" + + "normal field 1" + + "\r\n" + + "-----1234\r\n" + + "Content-Disposition: form-data; name=\"normalFormField2\"\r\n" + + "\r\n" + + "normal field 2" + + "\r\n" + + "-----1234--\r\n"); + req.setContent(content.getBytes(StandardCharsets.US_ASCII)); + + MyFileupAction action = new MyFileupAction(); + + MockActionInvocation mai = new MockActionInvocation(); + mai.setAction(action); + mai.setResultCode("success"); + mai.setInvocationContext(ActionContext.getContext()); + Map param = new HashMap<>(); + ActionContext.getContext().withParameters(HttpParameters.create(param).build()); + ActionContext.getContext().withServletRequest(createMultipartRequest(req, 2000, 2000, 5, 100)); + + interceptor.intercept(mai); + + assertFalse(action.hasErrors()); + + HttpParameters parameters = mai.getInvocationContext().getParameters(); + assertEquals(3, parameters.keySet().size()); + UploadedFile[] files = (UploadedFile[]) parameters.get("file").getObject(); + String[] fileContentTypes = parameters.get("fileContentType").getMultipleValues(); + String[] fileRealFilenames = parameters.get("fileFileName").getMultipleValues(); + + assertNotNull(files); + assertNotNull(fileContentTypes); + assertNotNull(fileRealFilenames); + assertEquals(1, files.length); + assertEquals(1, fileContentTypes.length); + assertEquals(1, fileRealFilenames.length); + assertEquals("text/html", fileContentTypes[0]); + assertNotNull("deleteme.txt", fileRealFilenames[0]); + + // Confirm normalFormField1, normalFormField2 were processed by the MultiPartRequestWrapper. + HttpServletRequest invocationServletRequest = mai.getInvocationContext().getServletRequest(); + assertTrue("invocation servelt request is not a MultiPartRequestWrapper ?", invocationServletRequest instanceof MultiPartRequestWrapper); + MultiPartRequestWrapper multipartRequestWrapper = (MultiPartRequestWrapper) invocationServletRequest; + assertNotNull("normalFormField1 missing from MultiPartRequestWrapper parameters ?", multipartRequestWrapper.getParameter("normalFormField1")); + assertNotNull("normalFormField2 missing from MultiPartRequestWrapper parameters ?", multipartRequestWrapper.getParameter("normalFormField2")); + } + + public void testSuccessUploadOfATextFileMultipartRequestWithNormalFieldsNoMaxParamsSet() throws Exception { + MockHttpServletRequest req = new MockHttpServletRequest(); + req.setCharacterEncoding(StandardCharsets.UTF_8.name()); + req.setMethod("post"); + req.addHeader("Content-type", "multipart/form-data; boundary=---1234"); + + // inspired by the unit tests for jakarta commons fileupload + String content = ("-----1234\r\n" + + "Content-Disposition: form-data; name=\"file\"; filename=\"deleteme.txt\"\r\n" + + "Content-Type: text/html\r\n" + + "\r\n" + + "Unit test of FileUploadInterceptor" + + "\r\n" + + "-----1234\r\n" + + "Content-Disposition: form-data; name=\"normalFormField1\"\r\n" + + "\r\n" + + "normal field 1 with no max parameters set" + + "\r\n" + + "-----1234\r\n" + + "Content-Disposition: form-data; name=\"normalFormField2\"\r\n" + + "\r\n" + + "normal field 2 with no max parameters set" + + "\r\n" + + "-----1234--\r\n"); + req.setContent(content.getBytes(StandardCharsets.US_ASCII)); + + MyFileupAction action = new MyFileupAction(); + + MockActionInvocation mai = new MockActionInvocation(); + mai.setAction(action); + mai.setResultCode("success"); + mai.setInvocationContext(ActionContext.getContext()); + Map param = new HashMap<>(); + ActionContext.getContext().withParameters(HttpParameters.create(param).build()); + ActionContext.getContext().withServletRequest(createMultipartRequestNoMaxParamsSet(req)); + + interceptor.intercept(mai); + + assertFalse(action.hasErrors()); + + HttpParameters parameters = mai.getInvocationContext().getParameters(); + assertEquals(3, parameters.keySet().size()); + UploadedFile[] files = (UploadedFile[]) parameters.get("file").getObject(); + String[] fileContentTypes = parameters.get("fileContentType").getMultipleValues(); + String[] fileRealFilenames = parameters.get("fileFileName").getMultipleValues(); + + assertNotNull(files); + assertNotNull(fileContentTypes); + assertNotNull(fileRealFilenames); + assertEquals(1, files.length); + assertEquals(1, fileContentTypes.length); + assertEquals(1, fileRealFilenames.length); + assertEquals("text/html", fileContentTypes[0]); + assertNotNull("deleteme.txt", fileRealFilenames[0]); + + // Confirm normalFormField1, normalFormField2 were processed by the MultiPartRequestWrapper. + HttpServletRequest invocationServletRequest = mai.getInvocationContext().getServletRequest(); + assertTrue("invocation servelt request is not a MultiPartRequestWrapper ?", invocationServletRequest instanceof MultiPartRequestWrapper); + MultiPartRequestWrapper multipartRequestWrapper = (MultiPartRequestWrapper) invocationServletRequest; + assertNotNull("normalFormField1 missing from MultiPartRequestWrapper parameters ?", multipartRequestWrapper.getParameter("normalFormField1")); + assertNotNull("normalFormField2 missing from MultiPartRequestWrapper parameters ?", multipartRequestWrapper.getParameter("normalFormField2")); + } + /** * tests whether with multiple files sent with the same name, the ones with forbiddenTypes (see * FileUploadInterceptor.setAllowedTypes(...) ) are sorted out. @@ -598,6 +770,12 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase { return new MultiPartRequestWrapper(jak, req, tempDir.getAbsolutePath(), new DefaultLocaleProvider()); } + private MultiPartRequestWrapper createMultipartRequestNoMaxParamsSet(HttpServletRequest req) { + + JakartaMultiPartRequest jak = new JakartaMultiPartRequest(); + return new MultiPartRequestWrapper(jak, req, tempDir.getAbsolutePath(), new DefaultLocaleProvider()); + } + @Override protected void setUp() throws Exception { super.setUp(); @@ -621,7 +799,8 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase { private static final long serialVersionUID = 6255238895447968889L; // no methods + // Note: We do not currently need fields/getters/setters for normalFormField1, normalFormField2 since + // the upload interceptor only prepares the normal field parameters. } - } From 49ddf6130a4cc28bddee84c2d56887c138991713 Mon Sep 17 00:00:00 2001 From: Lukasz Lenart Date: Mon, 14 Oct 2024 07:50:00 +0200 Subject: [PATCH 02/33] WW-5471 Marks Sitemesh plugin as deprecated --- plugins/sitemesh/pom.xml | 2 +- .../apache/struts2/sitemesh/FreemarkerDecoratorServlet.java | 4 ++++ .../org/apache/struts2/sitemesh/VelocityDecoratorServlet.java | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/sitemesh/pom.xml b/plugins/sitemesh/pom.xml index 0c3d1a35a..11db635f4 100644 --- a/plugins/sitemesh/pom.xml +++ b/plugins/sitemesh/pom.xml @@ -29,7 +29,7 @@ struts2-sitemesh-plugin jar - Struts 2 Sitemesh Plugin + DEPRECATED: Struts 2 Sitemesh Plugin diff --git a/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreemarkerDecoratorServlet.java b/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreemarkerDecoratorServlet.java index b6bd1ac74..a63b7c0fa 100644 --- a/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreemarkerDecoratorServlet.java +++ b/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreemarkerDecoratorServlet.java @@ -53,7 +53,10 @@ import java.util.Locale; *

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

+ * + * @deprecated Sitemesh 2 based plugin is not supported anymore */ +@Deprecated public class FreemarkerDecoratorServlet extends freemarker.ext.servlet.FreemarkerServlet { private static final Logger LOG = LogManager.getLogger(FreemarkerDecoratorServlet.class); @@ -69,6 +72,7 @@ public class FreemarkerDecoratorServlet extends freemarker.ext.servlet.Freemarke private boolean noCharsetInContentType; public void init() throws ServletException { + LOG.warn("This plugin is deprecated. Please migrate to a plugin which bases on Sitemesh 3!"); try { Dispatcher dispatcher = Dispatcher.getInstance(getServletContext()); if (dispatcher == null) { 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 b2079c2f2..32f202913 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 @@ -53,7 +53,10 @@ import java.io.StringWriter; *

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

+ * + * @deprecated Sitemesh 2 based plugin is not supported anymore */ +@Deprecated public class VelocityDecoratorServlet extends VelocityViewServlet { private static final Logger LOG = LogManager.getLogger(VelocityDecoratorServlet.class); @@ -76,6 +79,7 @@ public class VelocityDecoratorServlet extends VelocityViewServlet { * @param config servlet configuration */ public void init(ServletConfig config) throws ServletException { + LOG.warn("This plugin is deprecated. Please migrate to a plugin which bases on Sitemesh 3!"); super.init(config); Dispatcher dispatcher = Dispatcher.getInstance(getServletContext()); if (dispatcher == null) { From 7deb4812982af9ee073eead29cc359d0db57bebf Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Thu, 17 Oct 2024 13:12:57 +1100 Subject: [PATCH 03/33] WW-3714 Deprecate and migrate Action, Interceptor, Result --- .../java/com/opensymphony/xwork2/Action.java | 70 +----- .../java/com/opensymphony/xwork2/Result.java | 30 +-- .../xwork2/interceptor/Interceptor.java | 202 +--------------- .../main/java/org/apache/struts2/Action.java | 88 +++++++ .../main/java/org/apache/struts2/Result.java | 53 +++++ .../struts2/interceptor/Interceptor.java | 222 ++++++++++++++++++ ...onfigurationProviderOgnlAllowlistTest.java | 15 +- 7 files changed, 388 insertions(+), 292 deletions(-) create mode 100644 core/src/main/java/org/apache/struts2/Action.java create mode 100644 core/src/main/java/org/apache/struts2/Result.java create mode 100644 core/src/main/java/org/apache/struts2/interceptor/Interceptor.java diff --git a/core/src/main/java/com/opensymphony/xwork2/Action.java b/core/src/main/java/com/opensymphony/xwork2/Action.java index 4c96617c4..57d767834 100644 --- a/core/src/main/java/com/opensymphony/xwork2/Action.java +++ b/core/src/main/java/com/opensymphony/xwork2/Action.java @@ -19,70 +19,10 @@ package com.opensymphony.xwork2; /** - * All actions may implement this interface, which exposes the execute() method. - *

- * However, as of XWork 1.1, this is not required and is only here to assist users. You are free to create POJOs - * that honor the same contract defined by this interface without actually implementing the interface. - *

+ * {@inheritDoc} + * + * @deprecated since 6.7.0, use {@link org.apache.struts2.Action} instead. */ -public interface Action { - - /** - * The action execution was successful. Show result - * view to the end user. - */ - public static final String SUCCESS = "success"; - - /** - * The action execution was successful but do not - * show a view. This is useful for actions that are - * handling the view in another fashion like redirect. - */ - public static final String NONE = "none"; - - /** - * The action execution was a failure. - * Show an error view, possibly asking the - * user to retry entering data. - */ - public static final String ERROR = "error"; - - /** - *

- * The action execution require more input - * in order to succeed. - * This result is typically used if a form - * handling action has been executed so as - * to provide defaults for a form. The - * form associated with the handler should be - * shown to the end user. - *

- * - *

- * This result is also used if the given input - * params are invalid, meaning the user - * should try providing input again. - *

- */ - public static final String INPUT = "input"; - - /** - * The action could not execute, since the - * user most was not logged in. The login view - * should be shown. - */ - public static final String LOGIN = "login"; - - - /** - * Where the logic of the action is executed. - * - * @return a string representing the logical result of the execution. - * See constants in this interface for a list of standard result values. - * @throws Exception thrown if a system level exception occurs. - * Note: Application level exceptions should be handled by returning - * an error value, such as Action.ERROR. - */ - public String execute() throws Exception; - +@Deprecated +public interface Action extends org.apache.struts2.Action { } diff --git a/core/src/main/java/com/opensymphony/xwork2/Result.java b/core/src/main/java/com/opensymphony/xwork2/Result.java index 8c1687e5a..ccd238751 100644 --- a/core/src/main/java/com/opensymphony/xwork2/Result.java +++ b/core/src/main/java/com/opensymphony/xwork2/Result.java @@ -18,33 +18,11 @@ */ package com.opensymphony.xwork2; -import java.io.Serializable; - /** - * All results (except for Action.NONE) of an {@link Action} are mapped to a View implementation. + * {@inheritDoc} * - *

- * Examples of Views might be: - *

- * - *
    - *
  • SwingPanelView - pops up a new Swing panel
  • - *
  • ActionChainView - executes another action
  • - *
  • SerlvetRedirectView - redirects the HTTP response to a URL
  • - *
  • ServletDispatcherView - dispatches the HTTP response to a URL
  • - *
- * - * @author plightbo + * @deprecated since 6.7.0, use {@link org.apache.struts2.Result} instead. */ -public interface Result extends Serializable { - - /** - * Represents a generic interface for all action execution results. - * Whether that be displaying a webpage, generating an email, sending a JMS message, etc. - * - * @param invocation the invocation context. - * @throws Exception can be thrown. - */ - void execute(ActionInvocation invocation) throws Exception; - +@Deprecated +public interface Result extends org.apache.struts2.Result { } diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/Interceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/Interceptor.java index cafa08fc0..87041a269 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/Interceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/Interceptor.java @@ -18,205 +18,11 @@ */ package com.opensymphony.xwork2.interceptor; -import com.opensymphony.xwork2.ActionInvocation; - -import java.io.Serializable; - /** - * + * {@inheritDoc} * - *

- * An interceptor is a stateless class that follows the interceptor pattern, as - * found in {@link javax.servlet.Filter} and in AOP languages. - *

- * - *

- * Interceptors are objects that dynamically intercept Action invocations. - * They provide the developer with the opportunity to define code that can be executed - * before and/or after the execution of an action. They also have the ability - * to prevent an action from executing. Interceptors provide developers a way to - * encapsulate common functionality in a re-usable form that can be applied to - * one or more Actions. - *

- * - *

- * Interceptors must be stateless and not assume that a new instance will be created for each request or Action. - * Interceptors may choose to either short-circuit the {@link ActionInvocation} execution and return a return code - * (such as {@link com.opensymphony.xwork2.Action#SUCCESS}), or it may choose to do some processing before - * and/or after delegating the rest of the procesing using {@link ActionInvocation#invoke()}. - *

- * - * - * - *

- * Interceptor's parameter could be overridden through the following ways :- - *

- - * Method 1: - *
- * <action name="myAction" class="myActionClass">
- *     <interceptor-ref name="exception"/>
- *     <interceptor-ref name="alias"/>
- *     <interceptor-ref name="params"/>
- *     <interceptor-ref name="servletConfig"/>
- *     <interceptor-ref name="prepare"/>
- *     <interceptor-ref name="i18n"/>
- *     <interceptor-ref name="chain"/>
- *     <interceptor-ref name="modelDriven"/>
- *     <interceptor-ref name="fileUpload"/>
- *     <interceptor-ref name="staticParams"/>
- *     <interceptor-ref name="params"/>
- *     <interceptor-ref name="conversionError"/>
- *     <interceptor-ref name="validation">
- *     <param name="excludeMethods">myValidationExcudeMethod</param>
- *     </interceptor-ref>
- *     <interceptor-ref name="workflow">
- *     <param name="excludeMethods">myWorkflowExcludeMethod</param>
- *     </interceptor-ref>
- * </action>
- * 
- * - * Method 2: - *
- * <action name="myAction" class="myActionClass">
- *   <interceptor-ref name="defaultStack">
- *     <param name="validation.excludeMethods">myValidationExcludeMethod</param>
- *     <param name="workflow.excludeMethods">myWorkflowExcludeMethod</param>
- *   </interceptor-ref>
- * </action>
- * 
- * - *

- * In the first method, the whole default stack is copied and the parameter then - * changed accordingly. - *

- * - *

- * In the second method, the 'interceptor-ref' refer to an existing - * interceptor-stack, namely defaultStack in this example, and override the validator - * and workflow interceptor excludeMethods typically in this case. Note that in the - * 'param' tag, the name attribute contains a dot (.) the word before the dot(.) - * specifies the interceptor name whose parameter is to be overridden and the word after - * the dot (.) specifies the parameter itself. Essetially it is as follows :- - *

- * - *
- *    <interceptor-name>.<parameter-name>
- * 
- *

- * Note also that in this case the 'interceptor-ref' name attribute - * is used to indicate an interceptor stack which makes sense as if it is referring - * to the interceptor itself it would be just using Method 1 describe above. - *

- * - * - *

- * Nested Interceptor param overriding - *

- * - * - *

- * Interceptor stack parameter overriding could be nested into as many level as possible, though it would - * be advisable not to nest it too deep as to avoid confusion, For example, - *

- *
- * <interceptor name="interceptor1" class="foo.bar.Interceptor1" />
- * <interceptor name="interceptor2" class="foo.bar.Interceptor2" />
- * <interceptor name="interceptor3" class="foo.bar.Interceptor3" />
- * <interceptor name="interceptor4" class="foo.bar.Interceptor4" />
- * <interceptor-stack name="stack1">
- *     <interceptor-ref name="interceptor1" />
- * </interceptor-stack>
- * <interceptor-stack name="stack2">
- *     <interceptor-ref name="intercetor2" />
- *     <interceptor-ref name="stack1" />
- * </interceptor-stack>
- * <interceptor-stack name="stack3">
- *     <interceptor-ref name="interceptor3" />
- *     <interceptor-ref name="stack2" />
- * </interceptor-stack>
- * <interceptor-stack name="stack4">
- *     <interceptor-ref name="interceptor4" />
- *     <interceptor-ref name="stack3" />
- *  </interceptor-stack>
- * 
- * - *

- * Assuming the interceptor has the following properties - *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Interceptorproperty
Interceptor1param1
Interceptor2param2
Interceptor3param3
Interceptor4param4
- * - *

- * We could override them as follows : - *

- * - *
- *    <action ... >
- *        <!-- to override parameters of interceptor located directly in the stack  -->
- *        <interceptor-ref name="stack4">
- *           <param name="interceptor4.param4"> ... </param>
- *        </interceptor-ref>
- *    </action>
- *
- *    <action ... >
- *        <!-- to override parameters of interceptor located under nested stack -->
- *        <interceptor-ref name="stack4">
- *            <param name="stack3.interceptor3.param3"> ... </param>
- *            <param name="stack3.stack2.interceptor2.param2"> ... </param>
- *            <param name="stack3.stack2.stack1.interceptor1.param1"> ... </param>
- *        </interceptor-ref>
- *    </action>
- *  
- * - * - * - * @author Jason Carreira - * @author tmjee + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.Interceptor} instead. */ -public interface Interceptor extends Serializable { - - /** - * Called to let an interceptor clean up any resources it has allocated. - */ - void destroy(); - - /** - * Called after an interceptor is created, but before any requests are processed using - * {@link #intercept(com.opensymphony.xwork2.ActionInvocation) intercept} , giving - * the Interceptor a chance to initialize any needed resources. - */ - void init(); - - /** - * Allows the Interceptor to do some processing on the request before and/or after the rest of the processing of the - * request by the {@link ActionInvocation} or to short-circuit the processing and just return a String return code. - * - * @param invocation the action invocation - * @return the return code, either returned from {@link ActionInvocation#invoke()}, or from the interceptor itself. - * @throws Exception any system-level error, as defined in {@link com.opensymphony.xwork2.Action#execute()}. - */ - String intercept(ActionInvocation invocation) throws Exception; - +@Deprecated +public interface Interceptor extends org.apache.struts2.interceptor.Interceptor { } diff --git a/core/src/main/java/org/apache/struts2/Action.java b/core/src/main/java/org/apache/struts2/Action.java new file mode 100644 index 000000000..cc3fb83ac --- /dev/null +++ b/core/src/main/java/org/apache/struts2/Action.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; + +/** + * All actions may implement this interface, which exposes the execute() method. + *

+ * However, as of XWork 1.1, this is not required and is only here to assist users. You are free to create POJOs + * that honor the same contract defined by this interface without actually implementing the interface. + *

+ */ +public interface Action { + + /** + * The action execution was successful. Show result + * view to the end user. + */ + String SUCCESS = "success"; + + /** + * The action execution was successful but do not + * show a view. This is useful for actions that are + * handling the view in another fashion like redirect. + */ + String NONE = "none"; + + /** + * The action execution was a failure. + * Show an error view, possibly asking the + * user to retry entering data. + */ + String ERROR = "error"; + + /** + *

+ * The action execution require more input + * in order to succeed. + * This result is typically used if a form + * handling action has been executed so as + * to provide defaults for a form. The + * form associated with the handler should be + * shown to the end user. + *

+ * + *

+ * This result is also used if the given input + * params are invalid, meaning the user + * should try providing input again. + *

+ */ + String INPUT = "input"; + + /** + * The action could not execute, since the + * user most was not logged in. The login view + * should be shown. + */ + String LOGIN = "login"; + + + /** + * Where the logic of the action is executed. + * + * @return a string representing the logical result of the execution. + * See constants in this interface for a list of standard result values. + * @throws Exception thrown if a system level exception occurs. + * Note: Application level exceptions should be handled by returning + * an error value, such as Action.ERROR. + */ + String execute() throws Exception; + +} diff --git a/core/src/main/java/org/apache/struts2/Result.java b/core/src/main/java/org/apache/struts2/Result.java new file mode 100644 index 000000000..4dc912772 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/Result.java @@ -0,0 +1,53 @@ +/* + * 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; + +import com.opensymphony.xwork2.Action; +import com.opensymphony.xwork2.ActionInvocation; + +import java.io.Serializable; + +/** + * All results (except for Action.NONE) of an {@link Action} are mapped to a View implementation. + * + *

+ * Examples of Views might be: + *

+ * + *
    + *
  • SwingPanelView - pops up a new Swing panel
  • + *
  • ActionChainView - executes another action
  • + *
  • SerlvetRedirectView - redirects the HTTP response to a URL
  • + *
  • ServletDispatcherView - dispatches the HTTP response to a URL
  • + *
+ * + * @author plightbo + */ +public interface Result extends Serializable { + + /** + * Represents a generic interface for all action execution results. + * Whether that be displaying a webpage, generating an email, sending a JMS message, etc. + * + * @param invocation the invocation context. + * @throws Exception can be thrown. + */ + void execute(ActionInvocation invocation) throws Exception; + +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/Interceptor.java b/core/src/main/java/org/apache/struts2/interceptor/Interceptor.java new file mode 100644 index 000000000..9c36bde77 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/Interceptor.java @@ -0,0 +1,222 @@ +/* + * 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.interceptor; + +import com.opensymphony.xwork2.ActionInvocation; + +import java.io.Serializable; + +/** + * + * + *

+ * An interceptor is a stateless class that follows the interceptor pattern, as + * found in {@link javax.servlet.Filter} and in AOP languages. + *

+ * + *

+ * Interceptors are objects that dynamically intercept Action invocations. + * They provide the developer with the opportunity to define code that can be executed + * before and/or after the execution of an action. They also have the ability + * to prevent an action from executing. Interceptors provide developers a way to + * encapsulate common functionality in a re-usable form that can be applied to + * one or more Actions. + *

+ * + *

+ * Interceptors must be stateless and not assume that a new instance will be created for each request or Action. + * Interceptors may choose to either short-circuit the {@link ActionInvocation} execution and return a return code + * (such as {@link com.opensymphony.xwork2.Action#SUCCESS}), or it may choose to do some processing before + * and/or after delegating the rest of the procesing using {@link ActionInvocation#invoke()}. + *

+ * + * + * + *

+ * Interceptor's parameter could be overridden through the following ways :- + *

+ + * Method 1: + *
+ * <action name="myAction" class="myActionClass">
+ *     <interceptor-ref name="exception"/>
+ *     <interceptor-ref name="alias"/>
+ *     <interceptor-ref name="params"/>
+ *     <interceptor-ref name="servletConfig"/>
+ *     <interceptor-ref name="prepare"/>
+ *     <interceptor-ref name="i18n"/>
+ *     <interceptor-ref name="chain"/>
+ *     <interceptor-ref name="modelDriven"/>
+ *     <interceptor-ref name="fileUpload"/>
+ *     <interceptor-ref name="staticParams"/>
+ *     <interceptor-ref name="params"/>
+ *     <interceptor-ref name="conversionError"/>
+ *     <interceptor-ref name="validation">
+ *     <param name="excludeMethods">myValidationExcudeMethod</param>
+ *     </interceptor-ref>
+ *     <interceptor-ref name="workflow">
+ *     <param name="excludeMethods">myWorkflowExcludeMethod</param>
+ *     </interceptor-ref>
+ * </action>
+ * 
+ * + * Method 2: + *
+ * <action name="myAction" class="myActionClass">
+ *   <interceptor-ref name="defaultStack">
+ *     <param name="validation.excludeMethods">myValidationExcludeMethod</param>
+ *     <param name="workflow.excludeMethods">myWorkflowExcludeMethod</param>
+ *   </interceptor-ref>
+ * </action>
+ * 
+ * + *

+ * In the first method, the whole default stack is copied and the parameter then + * changed accordingly. + *

+ * + *

+ * In the second method, the 'interceptor-ref' refer to an existing + * interceptor-stack, namely defaultStack in this example, and override the validator + * and workflow interceptor excludeMethods typically in this case. Note that in the + * 'param' tag, the name attribute contains a dot (.) the word before the dot(.) + * specifies the interceptor name whose parameter is to be overridden and the word after + * the dot (.) specifies the parameter itself. Essetially it is as follows :- + *

+ * + *
+ *    <interceptor-name>.<parameter-name>
+ * 
+ *

+ * Note also that in this case the 'interceptor-ref' name attribute + * is used to indicate an interceptor stack which makes sense as if it is referring + * to the interceptor itself it would be just using Method 1 describe above. + *

+ * + * + *

+ * Nested Interceptor param overriding + *

+ * + * + *

+ * Interceptor stack parameter overriding could be nested into as many level as possible, though it would + * be advisable not to nest it too deep as to avoid confusion, For example, + *

+ *
+ * <interceptor name="interceptor1" class="foo.bar.Interceptor1" />
+ * <interceptor name="interceptor2" class="foo.bar.Interceptor2" />
+ * <interceptor name="interceptor3" class="foo.bar.Interceptor3" />
+ * <interceptor name="interceptor4" class="foo.bar.Interceptor4" />
+ * <interceptor-stack name="stack1">
+ *     <interceptor-ref name="interceptor1" />
+ * </interceptor-stack>
+ * <interceptor-stack name="stack2">
+ *     <interceptor-ref name="intercetor2" />
+ *     <interceptor-ref name="stack1" />
+ * </interceptor-stack>
+ * <interceptor-stack name="stack3">
+ *     <interceptor-ref name="interceptor3" />
+ *     <interceptor-ref name="stack2" />
+ * </interceptor-stack>
+ * <interceptor-stack name="stack4">
+ *     <interceptor-ref name="interceptor4" />
+ *     <interceptor-ref name="stack3" />
+ *  </interceptor-stack>
+ * 
+ * + *

+ * Assuming the interceptor has the following properties + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Interceptorproperty
Interceptor1param1
Interceptor2param2
Interceptor3param3
Interceptor4param4
+ * + *

+ * We could override them as follows : + *

+ * + *
+ *    <action ... >
+ *        <!-- to override parameters of interceptor located directly in the stack  -->
+ *        <interceptor-ref name="stack4">
+ *           <param name="interceptor4.param4"> ... </param>
+ *        </interceptor-ref>
+ *    </action>
+ *
+ *    <action ... >
+ *        <!-- to override parameters of interceptor located under nested stack -->
+ *        <interceptor-ref name="stack4">
+ *            <param name="stack3.interceptor3.param3"> ... </param>
+ *            <param name="stack3.stack2.interceptor2.param2"> ... </param>
+ *            <param name="stack3.stack2.stack1.interceptor1.param1"> ... </param>
+ *        </interceptor-ref>
+ *    </action>
+ *  
+ * + * + * + * @author Jason Carreira + * @author tmjee + */ +public interface Interceptor extends Serializable { + + /** + * Called to let an interceptor clean up any resources it has allocated. + */ + void destroy(); + + /** + * Called after an interceptor is created, but before any requests are processed using + * {@link #intercept(ActionInvocation) intercept} , giving + * the Interceptor a chance to initialize any needed resources. + */ + void init(); + + /** + * Allows the Interceptor to do some processing on the request before and/or after the rest of the processing of the + * request by the {@link ActionInvocation} or to short-circuit the processing and just return a String return code. + * + * @param invocation the action invocation + * @return the return code, either returned from {@link ActionInvocation#invoke()}, or from the interceptor itself. + * @throws Exception any system-level error, as defined in {@link com.opensymphony.xwork2.Action#execute()}. + */ + String intercept(ActionInvocation invocation) throws Exception; + +} diff --git a/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java b/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java index 4fa4aad8b..77d6bbb22 100644 --- a/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java +++ b/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java @@ -61,7 +61,10 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase Class.forName("com.opensymphony.xwork2.Action"), Class.forName("com.opensymphony.xwork2.interceptor.AbstractInterceptor"), Class.forName("com.opensymphony.xwork2.Result"), - Class.forName("com.opensymphony.xwork2.SimpleAction") + Class.forName("com.opensymphony.xwork2.SimpleAction"), + Class.forName("org.apache.struts2.interceptor.Interceptor"), + Class.forName("org.apache.struts2.Result"), + Class.forName("org.apache.struts2.Action") ); } @@ -85,7 +88,10 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase Class.forName("com.opensymphony.xwork2.Action"), Class.forName("com.opensymphony.xwork2.interceptor.AbstractInterceptor"), Class.forName("com.opensymphony.xwork2.Result"), - Class.forName("com.opensymphony.xwork2.SimpleAction") + Class.forName("com.opensymphony.xwork2.SimpleAction"), + Class.forName("org.apache.struts2.interceptor.Interceptor"), + Class.forName("org.apache.struts2.Result"), + Class.forName("org.apache.struts2.Action") ); } @@ -108,7 +114,10 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase Class.forName("com.opensymphony.xwork2.Validateable"), Class.forName("com.opensymphony.xwork2.Action"), Class.forName("com.opensymphony.xwork2.interceptor.AbstractInterceptor"), - Class.forName("com.opensymphony.xwork2.Result") + Class.forName("com.opensymphony.xwork2.Result"), + Class.forName("org.apache.struts2.interceptor.Interceptor"), + Class.forName("org.apache.struts2.Result"), + Class.forName("org.apache.struts2.Action") ); } } From 8da6a79926b5bf04cc376fb639c1da1a0d587b48 Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Thu, 17 Oct 2024 13:13:28 +1100 Subject: [PATCH 04/33] WW-3714 Deprecate and migrate ActionContext --- .../opensymphony/xwork2/ActionContext.java | 459 +++------------ .../org/apache/struts2/ActionContext.java | 554 ++++++++++++++++++ 2 files changed, 644 insertions(+), 369 deletions(-) create mode 100644 core/src/main/java/org/apache/struts2/ActionContext.java diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java index fb7b0abcb..c2a4a39c2 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java @@ -21,8 +21,6 @@ package com.opensymphony.xwork2; import com.opensymphony.xwork2.conversion.impl.ConversionData; import com.opensymphony.xwork2.inject.Container; import com.opensymphony.xwork2.util.ValueStack; -import org.apache.struts2.StrutsException; -import org.apache.struts2.StrutsStatics; import org.apache.struts2.dispatcher.HttpParameters; import org.apache.struts2.dispatcher.mapper.ActionMapping; @@ -30,515 +28,238 @@ import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.PageContext; -import java.io.Serializable; -import java.util.HashMap; import java.util.Locale; import java.util.Map; /** - *

- * The ActionContext is the context in which an {@link Action} is executed. Each context is basically a - * container of objects an action needs for execution like the session, parameters, locale, etc. - *

+ * {@inheritDoc} * - *

- * The ActionContext is thread local which means that values stored in the ActionContext are - * unique per thread. See the {@link ThreadLocal} class for more information. The benefit of - * this is you don't need to worry about a user specific action context, you just get it: - *

- * - * ActionContext context = ActionContext.getContext(); - * - *

- * Finally, because of the thread local usage you don't need to worry about making your actions thread safe. - *

- * - * @author Patrick Lightbody - * @author Bill Lynch (docs) + * @deprecated since 6.7.0, use {@link org.apache.struts2.ActionContext} instead. */ -public class ActionContext implements Serializable { +@Deprecated +public class ActionContext extends org.apache.struts2.ActionContext { - private static final ThreadLocal actionContext = new ThreadLocal<>(); - - /** - * Constant for the name of the action being executed. - */ - private static final String ACTION_NAME = "org.apache.struts2.ActionContext.name"; - - /** - * Constant for the {@link com.opensymphony.xwork2.util.ValueStack OGNL value stack}. - */ - private static final String VALUE_STACK = ValueStack.VALUE_STACK; - - /** - * Constant for the action's session. - */ - private static final String SESSION = "org.apache.struts2.ActionContext.session"; - - /** - * Constant for the action's application context. - */ - private static final String APPLICATION = "org.apache.struts2.ActionContext.application"; - - /** - * Constant for the action's parameters. - */ - private static final String PARAMETERS = "org.apache.struts2.ActionContext.parameters"; - - /** - * Constant for the action's locale. - */ - private static final String LOCALE = "org.apache.struts2.ActionContext.locale"; - - /** - * Constant for the action's {@link com.opensymphony.xwork2.ActionInvocation invocation} context. - */ - private static final String ACTION_INVOCATION = "org.apache.struts2.ActionContext.actionInvocation"; - - /** - * Constant for the map of type conversion errors. - */ - private static final String CONVERSION_ERRORS = "org.apache.struts2.ActionContext.conversionErrors"; - - /** - * Constant for the container - */ - private static final String CONTAINER = "org.apache.struts2.ActionContext.container"; - - private final Map context; - - /** - * Creates a new ActionContext initialized with another context. - * - * @param context a context map. - */ - protected ActionContext(Map context) { - this.context = context; + private ActionContext(org.apache.struts2.ActionContext actualContext) { + super(actualContext.getContextMap()); + } + + private static ActionContext adapt(org.apache.struts2.ActionContext actualContext) { + return actualContext != null ? new ActionContext(actualContext) : null; } - /** - * Creates a new ActionContext based on passed in Map - * - * @param context a map with context values - * @return new ActionContext - */ public static ActionContext of(Map context) { - if (context == null) { - throw new IllegalArgumentException("Context cannot be null!"); - } - return new ActionContext(context); + return adapt(org.apache.struts2.ActionContext.of(context)); } - /** - * Creates a new ActionContext based on empty Map - * - * @return new ActionContext - */ public static ActionContext of() { - return of(new HashMap<>()); + return adapt(org.apache.struts2.ActionContext.of()); } - /** - * Binds the provided context with the current thread - * - * @param actionContext context to bind to the thread - * @return context which was bound to the thread - */ public static ActionContext bind(ActionContext actionContext) { - ActionContext.setContext(actionContext); - return ActionContext.getContext(); + return adapt(org.apache.struts2.ActionContext.bind(actionContext)); } public static boolean containsValueStack(Map context) { - return context != null && context.containsKey(VALUE_STACK); + return org.apache.struts2.ActionContext.containsValueStack(context); } - /** - * Binds this context with the current thread - * - * @return this context which was bound to the thread - */ - public ActionContext bind() { - ActionContext.setContext(this); - return ActionContext.getContext(); - } - - /** - * Wipes out current ActionContext, use wisely! - */ public static void clear() { - actionContext.remove(); + org.apache.struts2.ActionContext.clear(); } - /** - * Sets the action context for the current thread. - * - * @param context the action context. - */ - private static void setContext(ActionContext context) { - actionContext.set(context); - } - - /** - * Returns the ActionContext specific to the current thread. - * - * @return the ActionContext for the current thread, is never null. - */ public static ActionContext getContext() { - return actionContext.get(); + return adapt(org.apache.struts2.ActionContext.getContext()); } - /** - * Sets the action invocation (the execution state). - * - * @param actionInvocation the action execution state. - */ + @Override + public ActionContext bind() { + super.bind(); + return this; + } + + @Override public ActionContext withActionInvocation(ActionInvocation actionInvocation) { - put(ACTION_INVOCATION, actionInvocation); + super.withActionInvocation(actionInvocation); return this; } - /** - * Gets the action invocation (the execution state). - * - * @return the action invocation (the execution state). - */ + @Override public ActionInvocation getActionInvocation() { - return (ActionInvocation) get(ACTION_INVOCATION); + return super.getActionInvocation(); } - /** - * Sets the action's application context. - * - * @param application the action's application context. - */ + @Override public ActionContext withApplication(Map application) { - put(APPLICATION, application); + super.withApplication(application); return this; } - /** - * Returns a Map of the ServletContext when in a servlet environment or a generic application level Map otherwise. - * - * @return a Map of ServletContext or generic application level Map - */ - @SuppressWarnings("unchecked") + @Override public Map getApplication() { - return (Map) get(APPLICATION); + return super.getApplication(); } - /** - * Gets the context map. - * - * @return the context map. - */ + @Override public Map getContextMap() { - return context; + return super.getContextMap(); } - /** - * Sets conversion errors which occurred when executing the action. - * - * @param conversionErrors a Map of errors which occurred when executing the action. - */ + @Override public ActionContext withConversionErrors(Map conversionErrors) { - put(CONVERSION_ERRORS, conversionErrors); + super.withConversionErrors(conversionErrors); return this; } - /** - * Gets the map of conversion errors which occurred when executing the action. - * - * @return the map of conversion errors which occurred when executing the action or an empty map if - * there were no errors. - */ - @SuppressWarnings("unchecked") + @Override public Map getConversionErrors() { - Map errors = (Map) get(CONVERSION_ERRORS); - - if (errors == null) { - errors = withConversionErrors(new HashMap<>()).getConversionErrors(); - } - - return errors; + return super.getConversionErrors(); } - /** - * Sets the Locale for the current action. - * - * @param locale the Locale for the current action. - */ + @Override public ActionContext withLocale(Locale locale) { - put(LOCALE, locale); + super.withLocale(locale); return this; } - /** - * Gets the Locale of the current action. If no locale was ever specified the platform's - * {@link java.util.Locale#getDefault() default locale} is used. - * - * @return the Locale of the current action. - */ + @Override public Locale getLocale() { - Locale locale = (Locale) get(LOCALE); - - if (locale == null) { - locale = Locale.getDefault(); - withLocale(locale); - } - - return locale; + return super.getLocale(); } - /** - * Sets the name of the current Action in the ActionContext. - * - * @param actionName the name of the current action. - */ + @Override public ActionContext withActionName(String actionName) { - put(ACTION_NAME, actionName); + super.withActionName(actionName); return this; } - /** - * Gets the name of the current Action. - * - * @return the name of the current action. - */ + @Override public String getActionName() { - return (String) get(ACTION_NAME); + return super.getActionName(); } - /** - * Sets the action parameters. - * - * @param parameters the parameters for the current action. - */ + @Override public ActionContext withParameters(HttpParameters parameters) { - put(PARAMETERS, parameters); + super.withParameters(parameters); return this; } - /** - * Returns a Map of the HttpServletRequest parameters when in a servlet environment or a generic Map of - * parameters otherwise. - * - * @return a Map of HttpServletRequest parameters or a multipart map when in a servlet environment, or a - * generic Map of parameters otherwise. - */ + @Override public HttpParameters getParameters() { - return (HttpParameters) get(PARAMETERS); + return super.getParameters(); } - /** - * Sets a map of action session values. - * - * @param session the session values. - */ + @Override public ActionContext withSession(Map session) { - put(SESSION, session); + super.withSession(session); return this; } - /** - * Gets the Map of HttpSession values when in a servlet environment or a generic session map otherwise. - * - * @return the Map of HttpSession values when in a servlet environment or a generic session map otherwise. - */ - @SuppressWarnings("unchecked") + @Override public Map getSession() { - return (Map) get(SESSION); + return super.getSession(); } - /** - * Sets the OGNL value stack. - * - * @param valueStack the OGNL value stack. - */ + @Override public ActionContext withValueStack(ValueStack valueStack) { - put(VALUE_STACK, valueStack); + super.withValueStack(valueStack); return this; } - /** - * Gets the OGNL value stack. - * - * @return the OGNL value stack. - */ + @Override public ValueStack getValueStack() { - return (ValueStack) get(VALUE_STACK); + return super.getValueStack(); } - /** - * Gets the container for this request - * - * @param container The container - */ + @Override public ActionContext withContainer(Container container) { - put(CONTAINER, container); + super.withContainer(container); return this; } - /** - * Sets the container for this request - * - * @return The container - */ + @Override public Container getContainer() { - return (Container) get(CONTAINER); + return super.getContainer(); } + @Override public T getInstance(Class type) { - Container cont = getContainer(); - if (cont != null) { - return cont.getInstance(type); - } else { - throw new StrutsException("Cannot find an initialized container for this request."); - } + return super.getInstance(type); } - /** - * Returns a value that is stored in the current ActionContext by doing a lookup using the value's key. - * - * @param key the key used to find the value. - * @return the value that was found using the key or null if the key was not found. - */ + @Override public Object get(String key) { - return context.get(key); + return super.get(key); } - /** - * Stores a value in the current ActionContext. The value can be looked up using the key. - * - * @param key the key of the value. - * @param value the value to be stored. - */ + @Override public void put(String key, Object value) { - context.put(key, value); + super.put(key, value); } - /** - * Gets ServletContext associated with current action - * - * @return current ServletContext - */ + @Override public ServletContext getServletContext() { - return (ServletContext) get(StrutsStatics.SERVLET_CONTEXT); + return super.getServletContext(); } - /** - * Assigns ServletContext to action context - * - * @param servletContext associated with current request - * @return ActionContext - */ + @Override public ActionContext withServletContext(ServletContext servletContext) { - put(StrutsStatics.SERVLET_CONTEXT, servletContext); + super.withServletContext(servletContext); return this; } - /** - * Gets ServletRequest associated with current action - * - * @return current ServletRequest - */ + @Override public HttpServletRequest getServletRequest() { - return (HttpServletRequest) get(StrutsStatics.HTTP_REQUEST); + return super.getServletRequest(); } - /** - * Assigns ServletRequest to action context - * - * @param request associated with current request - * @return ActionContext - */ + @Override public ActionContext withServletRequest(HttpServletRequest request) { - put(StrutsStatics.HTTP_REQUEST, request); + super.withServletRequest(request); return this; } - /** - * Gets ServletResponse associated with current action - * - * @return current ServletResponse - */ + @Override public HttpServletResponse getServletResponse() { - return (HttpServletResponse) get(StrutsStatics.HTTP_RESPONSE); + return super.getServletResponse(); } - /** - * Assigns ServletResponse to action context - * - * @param response associated with current request - * @return ActionContext - */ + @Override public ActionContext withServletResponse(HttpServletResponse response) { - put(StrutsStatics.HTTP_RESPONSE, response); + super.withServletResponse(response); return this; } - /** - * Gets PageContext associated with current action - * - * @return current PageContext - */ + @Override public PageContext getPageContext() { - return (PageContext) get(StrutsStatics.PAGE_CONTEXT); + return super.getPageContext(); } - /** - * Assigns PageContext to action context - * - * @param pageContext associated with current request - * @return ActionContext - */ + @Override public ActionContext withPageContext(PageContext pageContext) { - put(StrutsStatics.PAGE_CONTEXT, pageContext); + super.withPageContext(pageContext); return this; } - /** - * Gets ActionMapping associated with current action - * - * @return current ActionMapping - */ + @Override public ActionMapping getActionMapping() { - return (ActionMapping) get(StrutsStatics.ACTION_MAPPING); + return super.getActionMapping(); } - /** - * Assigns ActionMapping to action context - * - * @param actionMapping associated with current request - * @return ActionContext - */ + @Override public ActionContext withActionMapping(ActionMapping actionMapping) { - put(StrutsStatics.ACTION_MAPPING, actionMapping); + super.withActionMapping(actionMapping); return this; } - /** - * Assigns an extra context map to action context - * - * @param extraContext to add to the current action context - * @return ActionContext - */ + @Override public ActionContext withExtraContext(Map extraContext) { - if (extraContext != null) { - context.putAll(extraContext); - } + super.withExtraContext(extraContext); return this; } - /** - * Adds arbitrary key to action context - * - * @param key a string - * @param value an object - * @return ActionContext - */ + @Override public ActionContext with(String key, Object value) { - put(key, value); + super.with(key, value); return this; } } diff --git a/core/src/main/java/org/apache/struts2/ActionContext.java b/core/src/main/java/org/apache/struts2/ActionContext.java new file mode 100644 index 000000000..8f155cc06 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/ActionContext.java @@ -0,0 +1,554 @@ +/* + * 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; + +import com.opensymphony.xwork2.Action; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.conversion.impl.ConversionData; +import com.opensymphony.xwork2.inject.Container; +import com.opensymphony.xwork2.util.ValueStack; +import org.apache.struts2.dispatcher.HttpParameters; +import org.apache.struts2.dispatcher.mapper.ActionMapping; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.jsp.PageContext; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; + +/** + *

+ * The ActionContext is the context in which an {@link Action} is executed. Each context is basically a + * container of objects an action needs for execution like the session, parameters, locale, etc. + *

+ * + *

+ * The ActionContext is thread local which means that values stored in the ActionContext are + * unique per thread. See the {@link ThreadLocal} class for more information. The benefit of + * this is you don't need to worry about a user specific action context, you just get it: + *

+ * + * ActionContext context = ActionContext.getContext(); + * + *

+ * Finally, because of the thread local usage you don't need to worry about making your actions thread safe. + *

+ * + * @author Patrick Lightbody + * @author Bill Lynch (docs) + */ +public class ActionContext implements Serializable { + + private static final ThreadLocal actionContext = new ThreadLocal<>(); + + /** + * Constant for the name of the action being executed. + */ + private static final String ACTION_NAME = "org.apache.struts2.ActionContext.name"; + + /** + * Constant for the {@link ValueStack OGNL value stack}. + */ + private static final String VALUE_STACK = ValueStack.VALUE_STACK; + + /** + * Constant for the action's session. + */ + private static final String SESSION = "org.apache.struts2.ActionContext.session"; + + /** + * Constant for the action's application context. + */ + private static final String APPLICATION = "org.apache.struts2.ActionContext.application"; + + /** + * Constant for the action's parameters. + */ + private static final String PARAMETERS = "org.apache.struts2.ActionContext.parameters"; + + /** + * Constant for the action's locale. + */ + private static final String LOCALE = "org.apache.struts2.ActionContext.locale"; + + /** + * Constant for the action's {@link ActionInvocation invocation} context. + */ + private static final String ACTION_INVOCATION = "org.apache.struts2.ActionContext.actionInvocation"; + + /** + * Constant for the map of type conversion errors. + */ + private static final String CONVERSION_ERRORS = "org.apache.struts2.ActionContext.conversionErrors"; + + /** + * Constant for the container + */ + private static final String CONTAINER = "org.apache.struts2.ActionContext.container"; + + private final Map context; + + /** + * Creates a new ActionContext initialized with another context. + * + * @param context a context map. + */ + protected ActionContext(Map context) { + this.context = context; + } + + /** + * Creates a new ActionContext based on passed in Map + * + * @param context a map with context values + * @return new ActionContext + */ + public static ActionContext of(Map context) { + if (context == null) { + throw new IllegalArgumentException("Context cannot be null!"); + } + return new ActionContext(context); + } + + /** + * Creates a new ActionContext based on empty Map + * + * @return new ActionContext + */ + public static ActionContext of() { + return of(new HashMap<>()); + } + + /** + * Binds the provided context with the current thread + * + * @param actionContext context to bind to the thread + * @return context which was bound to the thread + */ + public static ActionContext bind(ActionContext actionContext) { + ActionContext.setContext(actionContext); + return ActionContext.getContext(); + } + + public static boolean containsValueStack(Map context) { + return context != null && context.containsKey(VALUE_STACK); + } + + /** + * Binds this context with the current thread + * + * @return this context which was bound to the thread + */ + public ActionContext bind() { + ActionContext.setContext(this); + return ActionContext.getContext(); + } + + /** + * Wipes out current ActionContext, use wisely! + */ + public static void clear() { + actionContext.remove(); + } + + /** + * Sets the action context for the current thread. + * + * @param context the action context. + */ + private static void setContext(ActionContext context) { + actionContext.set(context); + } + + /** + * Returns the ActionContext specific to the current thread. + * + * @return the ActionContext for the current thread, is never null. + */ + public static ActionContext getContext() { + return actionContext.get(); + } + + /** + * Sets the action invocation (the execution state). + * + * @param actionInvocation the action execution state. + */ + public ActionContext withActionInvocation(ActionInvocation actionInvocation) { + put(ACTION_INVOCATION, actionInvocation); + return this; + } + + /** + * Gets the action invocation (the execution state). + * + * @return the action invocation (the execution state). + */ + public ActionInvocation getActionInvocation() { + return (ActionInvocation) get(ACTION_INVOCATION); + } + + /** + * Sets the action's application context. + * + * @param application the action's application context. + */ + public ActionContext withApplication(Map application) { + put(APPLICATION, application); + return this; + } + + /** + * Returns a Map of the ServletContext when in a servlet environment or a generic application level Map otherwise. + * + * @return a Map of ServletContext or generic application level Map + */ + @SuppressWarnings("unchecked") + public Map getApplication() { + return (Map) get(APPLICATION); + } + + /** + * Gets the context map. + * + * @return the context map. + */ + public Map getContextMap() { + return context; + } + + /** + * Sets conversion errors which occurred when executing the action. + * + * @param conversionErrors a Map of errors which occurred when executing the action. + */ + public ActionContext withConversionErrors(Map conversionErrors) { + put(CONVERSION_ERRORS, conversionErrors); + return this; + } + + /** + * Gets the map of conversion errors which occurred when executing the action. + * + * @return the map of conversion errors which occurred when executing the action or an empty map if + * there were no errors. + */ + @SuppressWarnings("unchecked") + public Map getConversionErrors() { + Map errors = (Map) get(CONVERSION_ERRORS); + + if (errors == null) { + errors = withConversionErrors(new HashMap<>()).getConversionErrors(); + } + + return errors; + } + + /** + * Sets the Locale for the current action. + * + * @param locale the Locale for the current action. + */ + public ActionContext withLocale(Locale locale) { + put(LOCALE, locale); + return this; + } + + /** + * Gets the Locale of the current action. If no locale was ever specified the platform's + * {@link Locale#getDefault() default locale} is used. + * + * @return the Locale of the current action. + */ + public Locale getLocale() { + Locale locale = (Locale) get(LOCALE); + + if (locale == null) { + locale = Locale.getDefault(); + withLocale(locale); + } + + return locale; + } + + /** + * Sets the name of the current Action in the ActionContext. + * + * @param actionName the name of the current action. + */ + public ActionContext withActionName(String actionName) { + put(ACTION_NAME, actionName); + return this; + } + + /** + * Gets the name of the current Action. + * + * @return the name of the current action. + */ + public String getActionName() { + return (String) get(ACTION_NAME); + } + + /** + * Sets the action parameters. + * + * @param parameters the parameters for the current action. + */ + public ActionContext withParameters(HttpParameters parameters) { + put(PARAMETERS, parameters); + return this; + } + + /** + * Returns a Map of the HttpServletRequest parameters when in a servlet environment or a generic Map of + * parameters otherwise. + * + * @return a Map of HttpServletRequest parameters or a multipart map when in a servlet environment, or a + * generic Map of parameters otherwise. + */ + public HttpParameters getParameters() { + return (HttpParameters) get(PARAMETERS); + } + + /** + * Sets a map of action session values. + * + * @param session the session values. + */ + public ActionContext withSession(Map session) { + put(SESSION, session); + return this; + } + + /** + * Gets the Map of HttpSession values when in a servlet environment or a generic session map otherwise. + * + * @return the Map of HttpSession values when in a servlet environment or a generic session map otherwise. + */ + @SuppressWarnings("unchecked") + public Map getSession() { + return (Map) get(SESSION); + } + + /** + * Sets the OGNL value stack. + * + * @param valueStack the OGNL value stack. + */ + public ActionContext withValueStack(ValueStack valueStack) { + put(VALUE_STACK, valueStack); + return this; + } + + /** + * Gets the OGNL value stack. + * + * @return the OGNL value stack. + */ + public ValueStack getValueStack() { + return (ValueStack) get(VALUE_STACK); + } + + /** + * Gets the container for this request + * + * @param container The container + */ + public ActionContext withContainer(Container container) { + put(CONTAINER, container); + return this; + } + + /** + * Sets the container for this request + * + * @return The container + */ + public Container getContainer() { + return (Container) get(CONTAINER); + } + + public T getInstance(Class type) { + Container cont = getContainer(); + if (cont != null) { + return cont.getInstance(type); + } else { + throw new StrutsException("Cannot find an initialized container for this request."); + } + } + + /** + * Returns a value that is stored in the current ActionContext by doing a lookup using the value's key. + * + * @param key the key used to find the value. + * @return the value that was found using the key or null if the key was not found. + */ + public Object get(String key) { + return context.get(key); + } + + /** + * Stores a value in the current ActionContext. The value can be looked up using the key. + * + * @param key the key of the value. + * @param value the value to be stored. + */ + public void put(String key, Object value) { + context.put(key, value); + } + + /** + * Gets ServletContext associated with current action + * + * @return current ServletContext + */ + public ServletContext getServletContext() { + return (ServletContext) get(StrutsStatics.SERVLET_CONTEXT); + } + + /** + * Assigns ServletContext to action context + * + * @param servletContext associated with current request + * @return ActionContext + */ + public ActionContext withServletContext(ServletContext servletContext) { + put(StrutsStatics.SERVLET_CONTEXT, servletContext); + return this; + } + + /** + * Gets ServletRequest associated with current action + * + * @return current ServletRequest + */ + public HttpServletRequest getServletRequest() { + return (HttpServletRequest) get(StrutsStatics.HTTP_REQUEST); + } + + /** + * Assigns ServletRequest to action context + * + * @param request associated with current request + * @return ActionContext + */ + public ActionContext withServletRequest(HttpServletRequest request) { + put(StrutsStatics.HTTP_REQUEST, request); + return this; + } + + /** + * Gets ServletResponse associated with current action + * + * @return current ServletResponse + */ + public HttpServletResponse getServletResponse() { + return (HttpServletResponse) get(StrutsStatics.HTTP_RESPONSE); + } + + /** + * Assigns ServletResponse to action context + * + * @param response associated with current request + * @return ActionContext + */ + public ActionContext withServletResponse(HttpServletResponse response) { + put(StrutsStatics.HTTP_RESPONSE, response); + return this; + } + + /** + * Gets PageContext associated with current action + * + * @return current PageContext + */ + public PageContext getPageContext() { + return (PageContext) get(StrutsStatics.PAGE_CONTEXT); + } + + /** + * Assigns PageContext to action context + * + * @param pageContext associated with current request + * @return ActionContext + */ + public ActionContext withPageContext(PageContext pageContext) { + put(StrutsStatics.PAGE_CONTEXT, pageContext); + return this; + } + + /** + * Gets ActionMapping associated with current action + * + * @return current ActionMapping + */ + public ActionMapping getActionMapping() { + return (ActionMapping) get(StrutsStatics.ACTION_MAPPING); + } + + /** + * Assigns ActionMapping to action context + * + * @param actionMapping associated with current request + * @return ActionContext + */ + public ActionContext withActionMapping(ActionMapping actionMapping) { + put(StrutsStatics.ACTION_MAPPING, actionMapping); + return this; + } + + /** + * Assigns an extra context map to action context + * + * @param extraContext to add to the current action context + * @return ActionContext + */ + public ActionContext withExtraContext(Map extraContext) { + if (extraContext != null) { + context.putAll(extraContext); + } + return this; + } + + /** + * Adds arbitrary key to action context + * + * @param key a string + * @param value an object + * @return ActionContext + */ + public ActionContext with(String key, Object value) { + put(key, value); + return this; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ActionContext)) { + return false; + } + ActionContext other = (ActionContext) obj; + return Objects.equals(getContextMap(), other.getContextMap()); + } +} From ae9dc42da76bd3128f59945f60710ea4173d89d9 Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Thu, 17 Oct 2024 14:19:18 +1100 Subject: [PATCH 05/33] WW-3714 Deprecate and migrate ConditionalInterceptor --- .../interceptor/ConditionalInterceptor.java | 19 ++------- .../interceptor/ConditionalInterceptor.java | 39 +++++++++++++++++++ ...onfigurationProviderOgnlAllowlistTest.java | 3 ++ 3 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 core/src/main/java/org/apache/struts2/interceptor/ConditionalInterceptor.java diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ConditionalInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ConditionalInterceptor.java index 12752fce8..40d856f48 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ConditionalInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ConditionalInterceptor.java @@ -18,22 +18,11 @@ */ package com.opensymphony.xwork2.interceptor; -import com.opensymphony.xwork2.ActionInvocation; - /** - * A marking interface, when implemented allows to conditionally execute a given interceptor - * within the current action invocation. + * {@inheritDoc} * - * @since Struts 6.1.1 + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.Interceptor} instead. */ -public interface ConditionalInterceptor extends Interceptor { - - /** - * Determines if a given interceptor should be executed in the current processing of action invocation. - * - * @param invocation current {@link ActionInvocation} to determine if the interceptor should be executed - * @return true if the given interceptor should be included in the current action invocation - * @since 6.1.1 - */ - boolean shouldIntercept(ActionInvocation invocation); +@Deprecated +public interface ConditionalInterceptor extends org.apache.struts2.interceptor.ConditionalInterceptor, Interceptor { } diff --git a/core/src/main/java/org/apache/struts2/interceptor/ConditionalInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/ConditionalInterceptor.java new file mode 100644 index 000000000..a6071327c --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/ConditionalInterceptor.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.interceptor; + +import com.opensymphony.xwork2.ActionInvocation; + +/** + * A marking interface, when implemented allows to conditionally execute a given interceptor + * within the current action invocation. + * + * @since Struts 6.1.1 + */ +public interface ConditionalInterceptor extends Interceptor { + + /** + * Determines if a given interceptor should be executed in the current processing of action invocation. + * + * @param invocation current {@link ActionInvocation} to determine if the interceptor should be executed + * @return true if the given interceptor should be included in the current action invocation + * @since 6.1.1 + */ + boolean shouldIntercept(ActionInvocation invocation); +} diff --git a/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java b/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java index 77d6bbb22..0349f6812 100644 --- a/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java +++ b/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java @@ -63,6 +63,7 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase Class.forName("com.opensymphony.xwork2.Result"), Class.forName("com.opensymphony.xwork2.SimpleAction"), Class.forName("org.apache.struts2.interceptor.Interceptor"), + Class.forName("org.apache.struts2.interceptor.ConditionalInterceptor"), Class.forName("org.apache.struts2.Result"), Class.forName("org.apache.struts2.Action") ); @@ -90,6 +91,7 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase Class.forName("com.opensymphony.xwork2.Result"), Class.forName("com.opensymphony.xwork2.SimpleAction"), Class.forName("org.apache.struts2.interceptor.Interceptor"), + Class.forName("org.apache.struts2.interceptor.ConditionalInterceptor"), Class.forName("org.apache.struts2.Result"), Class.forName("org.apache.struts2.Action") ); @@ -116,6 +118,7 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase Class.forName("com.opensymphony.xwork2.interceptor.AbstractInterceptor"), Class.forName("com.opensymphony.xwork2.Result"), Class.forName("org.apache.struts2.interceptor.Interceptor"), + Class.forName("org.apache.struts2.interceptor.ConditionalInterceptor"), Class.forName("org.apache.struts2.Result"), Class.forName("org.apache.struts2.Action") ); From 60095a6934266eb50e0636c9e3c39560e14a7c8f Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Thu, 17 Oct 2024 14:49:22 +1100 Subject: [PATCH 06/33] WW-3714 Deprecate and migrate ActionInvocation --- .../opensymphony/xwork2/ActionContext.java | 2 +- .../opensymphony/xwork2/ActionInvocation.java | 215 +++++++----------- .../java/com/opensymphony/xwork2/Result.java | 25 ++ .../interceptor/ConditionalInterceptor.java | 8 + .../xwork2/interceptor/Interceptor.java | 9 + .../org/apache/struts2/ActionInvocation.java | 182 +++++++++++++++ .../main/java/org/apache/struts2/Result.java | 3 - .../interceptor/ConditionalInterceptor.java | 2 +- .../struts2/interceptor/Interceptor.java | 2 +- 9 files changed, 303 insertions(+), 145 deletions(-) create mode 100644 core/src/main/java/org/apache/struts2/ActionInvocation.java diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java index c2a4a39c2..d62da3219 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java @@ -43,7 +43,7 @@ public class ActionContext extends org.apache.struts2.ActionContext { super(actualContext.getContextMap()); } - private static ActionContext adapt(org.apache.struts2.ActionContext actualContext) { + static ActionContext adapt(org.apache.struts2.ActionContext actualContext) { return actualContext != null ? new ActionContext(actualContext) : null; } diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java b/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java index 472f23ea7..6f70f993f 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java @@ -22,158 +22,95 @@ import com.opensymphony.xwork2.interceptor.PreResultListener; import com.opensymphony.xwork2.util.ValueStack; /** - * An {@link ActionInvocation} represents the execution state of an {@link Action}. It holds the Interceptors and the Action instance. - * By repeated re-entrant execution of the invoke() method, initially by the {@link ActionProxy}, then by the Interceptors, the - * Interceptors are all executed, and then the {@link Action} and the {@link Result}. + * {@inheritDoc} * - * @author Jason Carreira - * @see com.opensymphony.xwork2.ActionProxy + * @deprecated since 6.7.0, use {@link org.apache.struts2.ActionInvocation} instead. */ -public interface ActionInvocation { +@Deprecated +public interface ActionInvocation extends org.apache.struts2.ActionInvocation { - /** - * Get the Action associated with this ActionInvocation. - * - * @return the Action - */ - Object getAction(); - - /** - * Gets whether this ActionInvocation has executed before. - * This will be set after the Action and the Result have executed. - * - * @return true if this ActionInvocation has executed before. - */ - boolean isExecuted(); - - /** - * Gets the ActionContext associated with this ActionInvocation. The ActionProxy is - * responsible for setting this ActionContext onto the ThreadLocal before invoking - * the ActionInvocation and resetting the old ActionContext afterwards. - * - * @return the ActionContext. - */ + @Override ActionContext getInvocationContext(); - /** - * Get the ActionProxy holding this ActionInvocation. - * - * @return the ActionProxy. - */ - ActionProxy getProxy(); - - /** - * If the ActionInvocation has been executed before and the Result is an instance of {@link ActionChainResult}, this method - * will walk down the chain of ActionChainResults until it finds a non-chain result, which will be returned. If the - * ActionInvocation's result has not been executed before, the Result instance will be created and populated with - * the result params. - * - * @return the result. - * @throws Exception can be thrown. - */ + @Override Result getResult() throws Exception; - /** - * Gets the result code returned from this ActionInvocation. - * - * @return the result code - */ - String getResultCode(); + static ActionInvocation adapt(org.apache.struts2.ActionInvocation actualInvocation) { + return actualInvocation != null ? new LegacyAdapter(actualInvocation) : null; + } - /** - * Sets the result code, possibly overriding the one returned by the - * action. - * - *

- * The "intended" purpose of this method is to allow PreResultListeners to - * override the result code returned by the Action. - *

- * - *

- * If this method is used before the Action executes, the Action's returned - * result code will override what was set. However the Action could (if - * specifically coded to do so) inspect the ActionInvocation to see that - * someone "upstream" (e.g. an Interceptor) had suggested a value as the - * result, and it could therefore return the same value itself. - *

- * - *

- * If this method is called between the Action execution and the Result - * execution, then the value set here will override the result code the - * action had returned. Creating an Interceptor that implements - * {@link PreResultListener} will give you this opportunity. - *

- * - *

- * If this method is called after the Result has been executed, it will - * have the effect of raising an IllegalStateException. - *

- * - * @param resultCode the result code. - * @throws IllegalStateException if called after the Result has been executed. - * @see #isExecuted() - */ - void setResultCode(String resultCode); + class LegacyAdapter implements ActionInvocation { - /** - * Gets the ValueStack associated with this ActionInvocation. - * - * @return the ValueStack - */ - ValueStack getStack(); + private final org.apache.struts2.ActionInvocation adaptee; - /** - * Register a {@link PreResultListener} to be notified after the Action is executed and - * before the Result is executed. - * - *

- * The ActionInvocation implementation must guarantee that listeners will be called in - * the order in which they are registered. - *

- * - *

- * Listener registration and execution does not need to be thread-safe. - *

- * - * @param listener the listener to add. - */ - void addPreResultListener(PreResultListener listener); + private LegacyAdapter(org.apache.struts2.ActionInvocation adaptee) { + this.adaptee = adaptee; + } - /** - * Invokes the next step in processing this ActionInvocation. - * - *

- * If there are more Interceptors, this will call the next one. If Interceptors choose not to short-circuit - * ActionInvocation processing and return their own return code, they will call invoke() to allow the next Interceptor - * to execute. If there are no more Interceptors to be applied, the Action is executed. - * If the {@link ActionProxy#getExecuteResult()} method returns true, the Result is also executed. - *

- * - * @throws Exception can be thrown. - * @return the return code. - */ - String invoke() throws Exception; + @Override + public Object getAction() { + return adaptee.getAction(); + } - /** - * Invokes only the Action (not Interceptors or Results). - * - *

- * This is useful in rare situations where advanced usage with the interceptor/action/result workflow is - * being manipulated for certain functionality. - *

- * - * @return the return code. - * @throws Exception can be thrown. - */ - String invokeActionOnly() throws Exception; + @Override + public boolean isExecuted() { + return adaptee.isExecuted(); + } - /** - * Sets the action event listener to respond to key action events. - * - * @param listener the listener. - */ - void setActionEventListener(ActionEventListener listener); + @Override + public ActionContext getInvocationContext() { + return ActionContext.adapt(adaptee.getInvocationContext()); + } - void init(ActionProxy proxy) ; + @Override + public ActionProxy getProxy() { + return adaptee.getProxy(); + } + + @Override + public Result getResult() throws Exception { + return Result.adapt(adaptee.getResult()); + } + + @Override + public String getResultCode() { + return adaptee.getResultCode(); + } + + @Override + public void setResultCode(String resultCode) { + adaptee.setResultCode(resultCode); + } + + @Override + public ValueStack getStack() { + return adaptee.getStack(); + } + + @Override + public void addPreResultListener(PreResultListener listener) { + adaptee.addPreResultListener(listener); + } + + @Override + public String invoke() throws Exception { + return adaptee.invoke(); + } + + @Override + public String invokeActionOnly() throws Exception { + return adaptee.invokeActionOnly(); + } + + @Override + public void setActionEventListener(ActionEventListener listener) { + adaptee.setActionEventListener(listener); + } + + @Override + public void init(ActionProxy proxy) { + adaptee.init(proxy); + } + } } diff --git a/core/src/main/java/com/opensymphony/xwork2/Result.java b/core/src/main/java/com/opensymphony/xwork2/Result.java index ccd238751..294ada4d7 100644 --- a/core/src/main/java/com/opensymphony/xwork2/Result.java +++ b/core/src/main/java/com/opensymphony/xwork2/Result.java @@ -25,4 +25,29 @@ package com.opensymphony.xwork2; */ @Deprecated public interface Result extends org.apache.struts2.Result { + + @Override + default void execute(org.apache.struts2.ActionInvocation invocation) throws Exception { + execute(ActionInvocation.adapt(invocation)); + } + + void execute(ActionInvocation invocation) throws Exception; + + static Result adapt(org.apache.struts2.Result actualResult) { + return actualResult != null ? new LegacyAdapter(actualResult) : null; + } + + class LegacyAdapter implements Result { + + private final org.apache.struts2.Result adaptee; + + private LegacyAdapter(org.apache.struts2.Result adaptee) { + this.adaptee = adaptee; + } + + @Override + public void execute(ActionInvocation invocation) throws Exception { + adaptee.execute(ActionInvocation.adapt(invocation)); + } + } } diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ConditionalInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ConditionalInterceptor.java index 40d856f48..83c2bcb3e 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ConditionalInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ConditionalInterceptor.java @@ -18,6 +18,8 @@ */ package com.opensymphony.xwork2.interceptor; +import com.opensymphony.xwork2.ActionInvocation; + /** * {@inheritDoc} * @@ -25,4 +27,10 @@ package com.opensymphony.xwork2.interceptor; */ @Deprecated public interface ConditionalInterceptor extends org.apache.struts2.interceptor.ConditionalInterceptor, Interceptor { + + default boolean shouldIntercept(org.apache.struts2.ActionInvocation invocation) { + return shouldIntercept(ActionInvocation.adapt(invocation)); + } + + boolean shouldIntercept(ActionInvocation invocation); } diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/Interceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/Interceptor.java index 87041a269..628dda6f5 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/Interceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/Interceptor.java @@ -18,6 +18,8 @@ */ package com.opensymphony.xwork2.interceptor; +import com.opensymphony.xwork2.ActionInvocation; + /** * {@inheritDoc} * @@ -25,4 +27,11 @@ package com.opensymphony.xwork2.interceptor; */ @Deprecated public interface Interceptor extends org.apache.struts2.interceptor.Interceptor { + + @Override + default String intercept(org.apache.struts2.ActionInvocation invocation) throws Exception { + return intercept(ActionInvocation.adapt(invocation)); + } + + String intercept(ActionInvocation invocation) throws Exception; } diff --git a/core/src/main/java/org/apache/struts2/ActionInvocation.java b/core/src/main/java/org/apache/struts2/ActionInvocation.java new file mode 100644 index 000000000..46f1a5b0e --- /dev/null +++ b/core/src/main/java/org/apache/struts2/ActionInvocation.java @@ -0,0 +1,182 @@ +/* + * 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; + +import com.opensymphony.xwork2.ActionChainResult; +import com.opensymphony.xwork2.ActionEventListener; +import com.opensymphony.xwork2.ActionProxy; +import com.opensymphony.xwork2.interceptor.PreResultListener; +import com.opensymphony.xwork2.util.ValueStack; + +/** + * An {@link ActionInvocation} represents the execution state of an {@link com.opensymphony.xwork2.Action}. It holds the Interceptors and the Action instance. + * By repeated re-entrant execution of the invoke() method, initially by the {@link ActionProxy}, then by the Interceptors, the + * Interceptors are all executed, and then the {@link Action} and the {@link com.opensymphony.xwork2.Result}. + * + * @author Jason Carreira + * @see ActionProxy + */ +public interface ActionInvocation { + + /** + * Get the Action associated with this ActionInvocation. + * + * @return the Action + */ + Object getAction(); + + /** + * Gets whether this ActionInvocation has executed before. + * This will be set after the Action and the Result have executed. + * + * @return true if this ActionInvocation has executed before. + */ + boolean isExecuted(); + + /** + * Gets the ActionContext associated with this ActionInvocation. The ActionProxy is + * responsible for setting this ActionContext onto the ThreadLocal before invoking + * the ActionInvocation and resetting the old ActionContext afterwards. + * + * @return the ActionContext. + */ + ActionContext getInvocationContext(); + + /** + * Get the ActionProxy holding this ActionInvocation. + * + * @return the ActionProxy. + */ + ActionProxy getProxy(); + + /** + * If the ActionInvocation has been executed before and the Result is an instance of {@link ActionChainResult}, this method + * will walk down the chain of ActionChainResults until it finds a non-chain result, which will be returned. If the + * ActionInvocation's result has not been executed before, the Result instance will be created and populated with + * the result params. + * + * @return the result. + * @throws Exception can be thrown. + */ + Result getResult() throws Exception; + + /** + * Gets the result code returned from this ActionInvocation. + * + * @return the result code + */ + String getResultCode(); + + /** + * Sets the result code, possibly overriding the one returned by the + * action. + * + *

+ * The "intended" purpose of this method is to allow PreResultListeners to + * override the result code returned by the Action. + *

+ * + *

+ * If this method is used before the Action executes, the Action's returned + * result code will override what was set. However the Action could (if + * specifically coded to do so) inspect the ActionInvocation to see that + * someone "upstream" (e.g. an Interceptor) had suggested a value as the + * result, and it could therefore return the same value itself. + *

+ * + *

+ * If this method is called between the Action execution and the Result + * execution, then the value set here will override the result code the + * action had returned. Creating an Interceptor that implements + * {@link PreResultListener} will give you this opportunity. + *

+ * + *

+ * If this method is called after the Result has been executed, it will + * have the effect of raising an IllegalStateException. + *

+ * + * @param resultCode the result code. + * @throws IllegalStateException if called after the Result has been executed. + * @see #isExecuted() + */ + void setResultCode(String resultCode); + + /** + * Gets the ValueStack associated with this ActionInvocation. + * + * @return the ValueStack + */ + ValueStack getStack(); + + /** + * Register a {@link PreResultListener} to be notified after the Action is executed and + * before the Result is executed. + * + *

+ * The ActionInvocation implementation must guarantee that listeners will be called in + * the order in which they are registered. + *

+ * + *

+ * Listener registration and execution does not need to be thread-safe. + *

+ * + * @param listener the listener to add. + */ + void addPreResultListener(PreResultListener listener); + + /** + * Invokes the next step in processing this ActionInvocation. + * + *

+ * If there are more Interceptors, this will call the next one. If Interceptors choose not to short-circuit + * ActionInvocation processing and return their own return code, they will call invoke() to allow the next Interceptor + * to execute. If there are no more Interceptors to be applied, the Action is executed. + * If the {@link ActionProxy#getExecuteResult()} method returns true, the Result is also executed. + *

+ * + * @throws Exception can be thrown. + * @return the return code. + */ + String invoke() throws Exception; + + /** + * Invokes only the Action (not Interceptors or Results). + * + *

+ * This is useful in rare situations where advanced usage with the interceptor/action/result workflow is + * being manipulated for certain functionality. + *

+ * + * @return the return code. + * @throws Exception can be thrown. + */ + String invokeActionOnly() throws Exception; + + /** + * Sets the action event listener to respond to key action events. + * + * @param listener the listener. + */ + void setActionEventListener(ActionEventListener listener); + + void init(ActionProxy proxy) ; + +} diff --git a/core/src/main/java/org/apache/struts2/Result.java b/core/src/main/java/org/apache/struts2/Result.java index 4dc912772..407994eab 100644 --- a/core/src/main/java/org/apache/struts2/Result.java +++ b/core/src/main/java/org/apache/struts2/Result.java @@ -18,9 +18,6 @@ */ package org.apache.struts2; -import com.opensymphony.xwork2.Action; -import com.opensymphony.xwork2.ActionInvocation; - import java.io.Serializable; /** diff --git a/core/src/main/java/org/apache/struts2/interceptor/ConditionalInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/ConditionalInterceptor.java index a6071327c..716b58195 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/ConditionalInterceptor.java +++ b/core/src/main/java/org/apache/struts2/interceptor/ConditionalInterceptor.java @@ -18,7 +18,7 @@ */ package org.apache.struts2.interceptor; -import com.opensymphony.xwork2.ActionInvocation; +import org.apache.struts2.ActionInvocation; /** * A marking interface, when implemented allows to conditionally execute a given interceptor diff --git a/core/src/main/java/org/apache/struts2/interceptor/Interceptor.java b/core/src/main/java/org/apache/struts2/interceptor/Interceptor.java index 9c36bde77..7eabb85a8 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/Interceptor.java +++ b/core/src/main/java/org/apache/struts2/interceptor/Interceptor.java @@ -18,7 +18,7 @@ */ package org.apache.struts2.interceptor; -import com.opensymphony.xwork2.ActionInvocation; +import org.apache.struts2.ActionInvocation; import java.io.Serializable; From 272c2e7bba62fb0e82514f5c6f1b5ac71ea57677 Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Thu, 17 Oct 2024 15:04:53 +1100 Subject: [PATCH 07/33] WW-3714 Deprecate and migrate PreResultListener --- .../opensymphony/xwork2/ActionInvocation.java | 7 ++++ .../xwork2/interceptor/PreResultListener.java | 38 +++++++++++------ .../org/apache/struts2/ActionInvocation.java | 2 +- .../interceptor/PreResultListener.java | 41 +++++++++++++++++++ 4 files changed, 75 insertions(+), 13 deletions(-) create mode 100644 core/src/main/java/org/apache/struts2/interceptor/PreResultListener.java diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java b/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java index 6f70f993f..1d6e34859 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java @@ -35,6 +35,13 @@ public interface ActionInvocation extends org.apache.struts2.ActionInvocation { @Override Result getResult() throws Exception; + @Override + default void addPreResultListener(org.apache.struts2.interceptor.PreResultListener listener) { + addPreResultListener(PreResultListener.adapt(listener)); + } + + void addPreResultListener(PreResultListener listener); + static ActionInvocation adapt(org.apache.struts2.ActionInvocation actualInvocation) { return actualInvocation != null ? new LegacyAdapter(actualInvocation) : null; } diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/PreResultListener.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/PreResultListener.java index f9faa2377..469d3521b 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/PreResultListener.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/PreResultListener.java @@ -21,21 +21,35 @@ package com.opensymphony.xwork2.interceptor; import com.opensymphony.xwork2.ActionInvocation; /** - * PreResultListeners may be registered with an {@link ActionInvocation} to get a callback after the - * {@link com.opensymphony.xwork2.Action} has been executed but before the {@link com.opensymphony.xwork2.Result} - * is executed. + * {@inheritDoc} * - * @author Jason Carreira + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.PreResultListener} instead. */ -public interface PreResultListener { +@Deprecated +public interface PreResultListener extends org.apache.struts2.interceptor.PreResultListener { + + @Override + default void beforeResult(org.apache.struts2.ActionInvocation invocation, String resultCode) { + beforeResult(ActionInvocation.adapt(invocation), resultCode); + } - /** - * This callback method will be called after the {@link com.opensymphony.xwork2.Action} execution and - * before the {@link com.opensymphony.xwork2.Result} execution. - * - * @param invocation the action invocation - * @param resultCode the result code returned by the action (eg. success). - */ void beforeResult(ActionInvocation invocation, String resultCode); + static PreResultListener adapt(org.apache.struts2.interceptor.PreResultListener actualListener) { + return actualListener != null ? new LegacyAdapter(actualListener) : null; + } + + class LegacyAdapter implements PreResultListener { + + private final org.apache.struts2.interceptor.PreResultListener adaptee; + + private LegacyAdapter(org.apache.struts2.interceptor.PreResultListener adaptee) { + this.adaptee = adaptee; + } + + @Override + public void beforeResult(ActionInvocation invocation, String resultCode) { + adaptee.beforeResult(invocation, resultCode); + } + } } diff --git a/core/src/main/java/org/apache/struts2/ActionInvocation.java b/core/src/main/java/org/apache/struts2/ActionInvocation.java index 46f1a5b0e..8b789f50d 100644 --- a/core/src/main/java/org/apache/struts2/ActionInvocation.java +++ b/core/src/main/java/org/apache/struts2/ActionInvocation.java @@ -21,8 +21,8 @@ package org.apache.struts2; import com.opensymphony.xwork2.ActionChainResult; import com.opensymphony.xwork2.ActionEventListener; import com.opensymphony.xwork2.ActionProxy; -import com.opensymphony.xwork2.interceptor.PreResultListener; import com.opensymphony.xwork2.util.ValueStack; +import org.apache.struts2.interceptor.PreResultListener; /** * An {@link ActionInvocation} represents the execution state of an {@link com.opensymphony.xwork2.Action}. It holds the Interceptors and the Action instance. diff --git a/core/src/main/java/org/apache/struts2/interceptor/PreResultListener.java b/core/src/main/java/org/apache/struts2/interceptor/PreResultListener.java new file mode 100644 index 000000000..a8e9f6250 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/PreResultListener.java @@ -0,0 +1,41 @@ +/* + * 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.interceptor; + +import org.apache.struts2.ActionInvocation; + +/** + * PreResultListeners may be registered with an {@link ActionInvocation} to get a callback after the + * {@link com.opensymphony.xwork2.Action} has been executed but before the {@link com.opensymphony.xwork2.Result} + * is executed. + * + * @author Jason Carreira + */ +public interface PreResultListener { + + /** + * This callback method will be called after the {@link com.opensymphony.xwork2.Action} execution and + * before the {@link com.opensymphony.xwork2.Result} execution. + * + * @param invocation the action invocation + * @param resultCode the result code returned by the action (eg. success). + */ + void beforeResult(ActionInvocation invocation, String resultCode); + +} From e3fbe883556c6c20a9315b549aba3e1aa60369e4 Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Thu, 17 Oct 2024 17:21:24 +1100 Subject: [PATCH 08/33] WW-3714 Update new ActionContext with new ActionInvocation --- .../main/java/com/opensymphony/xwork2/ActionContext.java | 8 ++++++-- core/src/main/java/org/apache/struts2/ActionContext.java | 2 -- .../java/org/apache/struts2/views/jsp/ActionTagTest.java | 6 ++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java index d62da3219..c7864571f 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java @@ -77,15 +77,19 @@ public class ActionContext extends org.apache.struts2.ActionContext { return this; } - @Override public ActionContext withActionInvocation(ActionInvocation actionInvocation) { + return withActionInvocation((org.apache.struts2.ActionInvocation) actionInvocation); + } + + @Override + public ActionContext withActionInvocation(org.apache.struts2.ActionInvocation actionInvocation) { super.withActionInvocation(actionInvocation); return this; } @Override public ActionInvocation getActionInvocation() { - return super.getActionInvocation(); + return ActionInvocation.adapt(super.getActionInvocation()); } @Override diff --git a/core/src/main/java/org/apache/struts2/ActionContext.java b/core/src/main/java/org/apache/struts2/ActionContext.java index 8f155cc06..bfde35f12 100644 --- a/core/src/main/java/org/apache/struts2/ActionContext.java +++ b/core/src/main/java/org/apache/struts2/ActionContext.java @@ -18,8 +18,6 @@ */ package org.apache.struts2; -import com.opensymphony.xwork2.Action; -import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.conversion.impl.ConversionData; import com.opensymphony.xwork2.inject.Container; import com.opensymphony.xwork2.util.ValueStack; diff --git a/core/src/test/java/org/apache/struts2/views/jsp/ActionTagTest.java b/core/src/test/java/org/apache/struts2/views/jsp/ActionTagTest.java index 9678b600e..0319ca7cc 100644 --- a/core/src/test/java/org/apache/struts2/views/jsp/ActionTagTest.java +++ b/core/src/test/java/org/apache/struts2/views/jsp/ActionTagTest.java @@ -403,6 +403,7 @@ public class ActionTagTest extends AbstractTagTest { public void testExecuteButResetReturnSameInvocation() throws Exception { Mock mockActionInv = new Mock(ActionInvocation.class); + mockActionInv.matchAndReturn("invoke", "TEST"); ActionTag tag = new ActionTag(); tag.setPageContext(pageContext); tag.setNamespace(""); @@ -419,7 +420,7 @@ public class ActionTagTest extends AbstractTagTest { ActionComponent component = (ActionComponent) tag.getComponent(); tag.doEndTag(); - assertSame(oldInvocation, ActionContext.getContext().getActionInvocation()); + assertEquals(oldInvocation.invoke(), ActionContext.getContext().getActionInvocation().invoke()); // Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag(). ActionTag freshTag = new ActionTag(); @@ -432,6 +433,7 @@ public class ActionTagTest extends AbstractTagTest { public void testExecuteButResetReturnSameInvocation_clearTagStateSet() throws Exception { Mock mockActionInv = new Mock(ActionInvocation.class); + mockActionInv.matchAndReturn("invoke", "TEST"); ActionTag tag = new ActionTag(); tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing. tag.setPageContext(pageContext); @@ -450,7 +452,7 @@ public class ActionTagTest extends AbstractTagTest { ActionComponent component = (ActionComponent) tag.getComponent(); tag.doEndTag(); - assertTrue(oldInvocation == ActionContext.getContext().getActionInvocation()); + assertEquals(oldInvocation.invoke(), ActionContext.getContext().getActionInvocation().invoke()); // Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag(). ActionTag freshTag = new ActionTag(); From 36a890ba69ac80f5a279478f9229b7b4ff8912cd Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Thu, 17 Oct 2024 20:05:59 +1100 Subject: [PATCH 09/33] WW-3714 Add factory support for new Interceptor, Result interfaces --- .../factory/DefaultInterceptorFactory.java | 13 ++++--- .../xwork2/factory/DefaultResultFactory.java | 12 ++++++- .../interceptor/ConditionalInterceptor.java | 23 +++++++++++++ .../xwork2/interceptor/Interceptor.java | 34 +++++++++++++++++++ .../struts2/factory/StrutsResultFactory.java | 13 +++++-- 5 files changed, 88 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/com/opensymphony/xwork2/factory/DefaultInterceptorFactory.java b/core/src/main/java/com/opensymphony/xwork2/factory/DefaultInterceptorFactory.java index a1d9ee2ce..580464130 100644 --- a/core/src/main/java/com/opensymphony/xwork2/factory/DefaultInterceptorFactory.java +++ b/core/src/main/java/com/opensymphony/xwork2/factory/DefaultInterceptorFactory.java @@ -70,13 +70,18 @@ public class DefaultInterceptorFactory implements InterceptorFactory { reflectionProvider.setProperties(params, o); } + Interceptor interceptor = null; if (o instanceof Interceptor) { - Interceptor interceptor = (Interceptor) o; - interceptor.init(); - return interceptor; + interceptor = (Interceptor) o; + } else if (o instanceof org.apache.struts2.interceptor.Interceptor) { + interceptor = Interceptor.adapt((org.apache.struts2.interceptor.Interceptor) o); } - throw new ConfigurationException("Class [" + interceptorClassName + "] does not implement Interceptor", interceptorConfig); + if (interceptor == null) { + throw new ConfigurationException("Class [" + interceptorClassName + "] does not implement Interceptor", interceptorConfig); + } + interceptor.init(); + return interceptor; } catch (InstantiationException e) { cause = e; message = "Unable to instantiate an instance of Interceptor class [" + interceptorClassName + "]."; diff --git a/core/src/main/java/com/opensymphony/xwork2/factory/DefaultResultFactory.java b/core/src/main/java/com/opensymphony/xwork2/factory/DefaultResultFactory.java index e5fe5f8d5..5466a52ea 100644 --- a/core/src/main/java/com/opensymphony/xwork2/factory/DefaultResultFactory.java +++ b/core/src/main/java/com/opensymphony/xwork2/factory/DefaultResultFactory.java @@ -20,6 +20,7 @@ package com.opensymphony.xwork2.factory; import com.opensymphony.xwork2.ObjectFactory; import com.opensymphony.xwork2.Result; +import com.opensymphony.xwork2.config.ConfigurationException; import com.opensymphony.xwork2.config.entities.ResultConfig; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.util.reflection.ReflectionException; @@ -51,7 +52,16 @@ public class DefaultResultFactory implements ResultFactory { Result result = null; if (resultClassName != null) { - result = (Result) objectFactory.buildBean(resultClassName, extraContext); + Object o = objectFactory.buildBean(resultClassName, extraContext); + if (o instanceof Result) { + result = (Result) o; + } else if (o instanceof org.apache.struts2.Result) { + result = Result.adapt((org.apache.struts2.Result) o); + } + if (result == null) { + throw new ConfigurationException("Class [" + resultClassName + "] does not implement Result", resultConfig); + } + Map params = resultConfig.getParams(); if (params != null) { for (Map.Entry paramEntry : params.entrySet()) { diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ConditionalInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ConditionalInterceptor.java index 83c2bcb3e..0e83f64b2 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ConditionalInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ConditionalInterceptor.java @@ -28,9 +28,32 @@ import com.opensymphony.xwork2.ActionInvocation; @Deprecated public interface ConditionalInterceptor extends org.apache.struts2.interceptor.ConditionalInterceptor, Interceptor { + @Override default boolean shouldIntercept(org.apache.struts2.ActionInvocation invocation) { return shouldIntercept(ActionInvocation.adapt(invocation)); } boolean shouldIntercept(ActionInvocation invocation); + + static ConditionalInterceptor adapt(org.apache.struts2.interceptor.ConditionalInterceptor actualInterceptor) { + if (actualInterceptor instanceof ConditionalInterceptor) { + return (ConditionalInterceptor) actualInterceptor; + } + return actualInterceptor != null ? new LegacyAdapter(actualInterceptor) : null; + } + + class LegacyAdapter extends Interceptor.LegacyAdapter implements ConditionalInterceptor { + + private final org.apache.struts2.interceptor.ConditionalInterceptor adaptee; + + private LegacyAdapter(org.apache.struts2.interceptor.ConditionalInterceptor adaptee) { + super(adaptee); + this.adaptee = adaptee; + } + + @Override + public boolean shouldIntercept(ActionInvocation invocation) { + return adaptee.shouldIntercept(invocation); + } + } } diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/Interceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/Interceptor.java index 628dda6f5..e6ff42998 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/Interceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/Interceptor.java @@ -34,4 +34,38 @@ public interface Interceptor extends org.apache.struts2.interceptor.Interceptor } String intercept(ActionInvocation invocation) throws Exception; + + static Interceptor adapt(org.apache.struts2.interceptor.Interceptor actualInterceptor) { + if (actualInterceptor instanceof org.apache.struts2.interceptor.ConditionalInterceptor) { + return ConditionalInterceptor.adapt((org.apache.struts2.interceptor.ConditionalInterceptor) actualInterceptor); + } + if (actualInterceptor instanceof Interceptor) { + return (Interceptor) actualInterceptor; + } + return actualInterceptor != null ? new LegacyAdapter(actualInterceptor) : null; + } + + class LegacyAdapter implements Interceptor { + + private final org.apache.struts2.interceptor.Interceptor adaptee; + + protected LegacyAdapter(org.apache.struts2.interceptor.Interceptor adaptee) { + this.adaptee = adaptee; + } + + @Override + public String intercept(ActionInvocation invocation) throws Exception { + return adaptee.intercept(invocation); + } + + @Override + public void destroy() { + adaptee.destroy(); + } + + @Override + public void init() { + adaptee.init(); + } + } } diff --git a/core/src/main/java/org/apache/struts2/factory/StrutsResultFactory.java b/core/src/main/java/org/apache/struts2/factory/StrutsResultFactory.java index 0a758f213..2818f33dd 100644 --- a/core/src/main/java/org/apache/struts2/factory/StrutsResultFactory.java +++ b/core/src/main/java/org/apache/struts2/factory/StrutsResultFactory.java @@ -20,13 +20,14 @@ package org.apache.struts2.factory; import com.opensymphony.xwork2.ObjectFactory; import com.opensymphony.xwork2.Result; +import com.opensymphony.xwork2.config.ConfigurationException; import com.opensymphony.xwork2.config.entities.ResultConfig; import com.opensymphony.xwork2.factory.ResultFactory; import com.opensymphony.xwork2.inject.Inject; +import com.opensymphony.xwork2.result.ParamNameAwareResult; import com.opensymphony.xwork2.util.reflection.ReflectionException; import com.opensymphony.xwork2.util.reflection.ReflectionExceptionHandler; import com.opensymphony.xwork2.util.reflection.ReflectionProvider; -import com.opensymphony.xwork2.result.ParamNameAwareResult; import java.util.Map; @@ -53,7 +54,15 @@ public class StrutsResultFactory implements ResultFactory { Result result = null; if (resultClassName != null) { - result = (Result) objectFactory.buildBean(resultClassName, extraContext); + Object o = objectFactory.buildBean(resultClassName, extraContext); + if (o instanceof Result) { + result = (Result) o; + } else if (o instanceof org.apache.struts2.Result) { + result = Result.adapt((org.apache.struts2.Result) o); + } + if (result == null) { + throw new ConfigurationException("Class [" + resultClassName + "] does not implement Result", resultConfig); + } Map params = resultConfig.getParams(); if (params != null) { setParameters(extraContext, result, params); From d1695f7a4d83c8ed8aa9b67176795053f4d2d748 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 01:29:19 +0000 Subject: [PATCH 10/33] Bump github/codeql-action from 3.26.12 to 3.26.13 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.26.12 to 3.26.13. - [Release notes](https://github.com/github/codeql-action/releases) - [Commits](https://github.com/github/codeql-action/compare/v3.26.12...v3.26.13) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql.yml | 6 +++--- .github/workflows/scorecards-analysis.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 26db59be1..5e616eab6 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -44,12 +44,12 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - name: Initialize CodeQL - uses: github/codeql-action/init@v3.26.12 + uses: github/codeql-action/init@v3.26.13 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@v3.26.12 + uses: github/codeql-action/autobuild@v3.26.13 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3.26.12 + uses: github/codeql-action/analyze@v3.26.13 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecards-analysis.yaml b/.github/workflows/scorecards-analysis.yaml index 866d87936..44c6ac646 100644 --- a/.github/workflows/scorecards-analysis.yaml +++ b/.github/workflows/scorecards-analysis.yaml @@ -64,6 +64,6 @@ jobs: retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@ea2cd92c21b192add69983116b8b3222b09da33b # 2.22.11 + uses: github/codeql-action/upload-sarif@af56b044b5d41c317aef5d19920b3183cb4fbbec # 2.22.11 with: sarif_file: results.sarif From 28c8f1503d6a99e049aeb31da37cf38a59fa0497 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 01:47:53 +0000 Subject: [PATCH 11/33] Bump maven-surefire-plugin.version from 3.5.0 to 3.5.1 Bumps `maven-surefire-plugin.version` from 3.5.0 to 3.5.1. Updates `org.apache.maven.surefire:surefire-junit47` from 3.5.0 to 3.5.1 Updates `org.apache.maven.plugins:maven-surefire-plugin` from 3.5.0 to 3.5.1 - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.0...surefire-3.5.1) --- updated-dependencies: - dependency-name: org.apache.maven.surefire:surefire-junit47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8534610fe..e23efe790 100644 --- a/pom.xml +++ b/pom.xml @@ -117,7 +117,7 @@ 5.3.39 3.0.8 1.0.7 - 3.5.0 + 3.5.1 6.2.4.Final 2.3.33 From b18fbda1f7e971c357453343a36be20f7a330013 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 01:48:01 +0000 Subject: [PATCH 12/33] Bump org.apache.maven.doxia:doxia-core from 1.12.0 to 2.0.0 Bumps [org.apache.maven.doxia:doxia-core](https://github.com/apache/maven-doxia) from 1.12.0 to 2.0.0. - [Release notes](https://github.com/apache/maven-doxia/releases) - [Commits](https://github.com/apache/maven-doxia/compare/doxia-1.12.0...doxia-2.0.0) --- updated-dependencies: - dependency-name: org.apache.maven.doxia:doxia-core dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8534610fe..378d31163 100644 --- a/pom.xml +++ b/pom.xml @@ -415,7 +415,7 @@ org.apache.maven.doxia doxia-core - 1.12.0 + 2.0.0 org.apache.maven.doxia From 48ee44bbc2ae83baa809a63d81fa0984273f6af7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 01:48:04 +0000 Subject: [PATCH 13/33] Bump org.apache.commons:commons-lang3 from 3.15.0 to 3.17.0 Bumps org.apache.commons:commons-lang3 from 3.15.0 to 3.17.0. --- updated-dependencies: - dependency-name: org.apache.commons:commons-lang3 dependency-type: direct:production 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 8534610fe..7f5785a77 100644 --- a/pom.xml +++ b/pom.xml @@ -866,7 +866,7 @@ org.apache.commons commons-lang3 - 3.15.0 + 3.17.0 org.apache.commons From cf6cbf3816ea43f1eb35c08d121aa8049f64ed61 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 01:48:11 +0000 Subject: [PATCH 14/33] Bump org.apache.maven.plugins:maven-failsafe-plugin from 3.3.1 to 3.5.1 Bumps [org.apache.maven.plugins:maven-failsafe-plugin](https://github.com/apache/maven-surefire) from 3.3.1 to 3.5.1. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.3.1...surefire-3.5.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-failsafe-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- apps/showcase/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/showcase/pom.xml b/apps/showcase/pom.xml index 21a02f768..7054c18f6 100644 --- a/apps/showcase/pom.xml +++ b/apps/showcase/pom.xml @@ -163,7 +163,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 3.3.1 + 3.5.1 it.org.apache.struts2.showcase.*Test From b622e5d725857664cfb5905c0d4501911fa5596f Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Tue, 22 Oct 2024 13:50:45 +1100 Subject: [PATCH 15/33] WW-3714 Ensure ReflectionExceptionHandler, WithLazyParams, ParamNameAwareResult marker interfaces respected --- .../xwork2/DefaultActionInvocation.java | 3 ++ .../xwork2/factory/DefaultResultFactory.java | 27 +++++++-------- .../xwork2/interceptor/Interceptor.java | 4 +++ .../xwork2/interceptor/WithLazyParams.java | 5 ++- .../struts2/factory/StrutsResultFactory.java | 33 ++++++++++++++++--- 5 files changed, 53 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java b/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java index 772e0adb0..84accbef7 100644 --- a/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java +++ b/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java @@ -248,6 +248,9 @@ public class DefaultActionInvocation implements ActionInvocation { Interceptor interceptor = interceptorMapping.getInterceptor(); if (interceptor instanceof WithLazyParams) { interceptor = lazyParamInjector.injectParams(interceptor, interceptorMapping.getParams(), invocationContext); + } else if (interceptor instanceof Interceptor.LegacyAdapter && ((Interceptor.LegacyAdapter) interceptor).getAdaptee() instanceof WithLazyParams) { + org.apache.struts2.interceptor.Interceptor adaptee = ((Interceptor.LegacyAdapter) interceptor).getAdaptee(); + lazyParamInjector.injectParams(adaptee, interceptorMapping.getParams(), invocationContext); } if (interceptor instanceof ConditionalInterceptor) { resultCode = executeConditional((ConditionalInterceptor) interceptor); diff --git a/core/src/main/java/com/opensymphony/xwork2/factory/DefaultResultFactory.java b/core/src/main/java/com/opensymphony/xwork2/factory/DefaultResultFactory.java index 5466a52ea..42527494e 100644 --- a/core/src/main/java/com/opensymphony/xwork2/factory/DefaultResultFactory.java +++ b/core/src/main/java/com/opensymphony/xwork2/factory/DefaultResultFactory.java @@ -53,6 +53,20 @@ public class DefaultResultFactory implements ResultFactory { if (resultClassName != null) { Object o = objectFactory.buildBean(resultClassName, extraContext); + + Map params = resultConfig.getParams(); + if (params != null) { + for (Map.Entry paramEntry : params.entrySet()) { + try { + reflectionProvider.setProperty(paramEntry.getKey(), paramEntry.getValue(), o, extraContext, true); + } catch (ReflectionException ex) { + if (o instanceof ReflectionExceptionHandler) { + ((ReflectionExceptionHandler) o).handle(ex); + } + } + } + } + if (o instanceof Result) { result = (Result) o; } else if (o instanceof org.apache.struts2.Result) { @@ -61,19 +75,6 @@ public class DefaultResultFactory implements ResultFactory { if (result == null) { throw new ConfigurationException("Class [" + resultClassName + "] does not implement Result", resultConfig); } - - Map params = resultConfig.getParams(); - if (params != null) { - for (Map.Entry paramEntry : params.entrySet()) { - try { - reflectionProvider.setProperty(paramEntry.getKey(), paramEntry.getValue(), result, extraContext, true); - } catch (ReflectionException ex) { - if (result instanceof ReflectionExceptionHandler) { - ((ReflectionExceptionHandler) result).handle(ex); - } - } - } - } } return result; diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/Interceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/Interceptor.java index e6ff42998..4287ca8c0 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/Interceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/Interceptor.java @@ -53,6 +53,10 @@ public interface Interceptor extends org.apache.struts2.interceptor.Interceptor this.adaptee = adaptee; } + public org.apache.struts2.interceptor.Interceptor getAdaptee() { + return adaptee; + } + @Override public String intercept(ActionInvocation invocation) throws Exception { return adaptee.intercept(invocation); diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/WithLazyParams.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/WithLazyParams.java index 3e111d69c..5b9401d3d 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/WithLazyParams.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/WithLazyParams.java @@ -70,11 +70,14 @@ public interface WithLazyParams { } public Interceptor injectParams(Interceptor interceptor, Map params, ActionContext invocationContext) { + return (Interceptor) injectParams((org.apache.struts2.interceptor.Interceptor) interceptor, params, invocationContext); + } + + public org.apache.struts2.interceptor.Interceptor injectParams(org.apache.struts2.interceptor.Interceptor interceptor, Map params, ActionContext invocationContext) { for (Map.Entry entry : params.entrySet()) { Object paramValue = textParser.evaluate(new char[]{ '$' }, entry.getValue(), valueEvaluator, TextParser.DEFAULT_LOOP_COUNT); ognlUtil.setProperty(entry.getKey(), paramValue, interceptor, invocationContext.getContextMap()); } - return interceptor; } } diff --git a/core/src/main/java/org/apache/struts2/factory/StrutsResultFactory.java b/core/src/main/java/org/apache/struts2/factory/StrutsResultFactory.java index 2818f33dd..8a653bdaf 100644 --- a/core/src/main/java/org/apache/struts2/factory/StrutsResultFactory.java +++ b/core/src/main/java/org/apache/struts2/factory/StrutsResultFactory.java @@ -55,6 +55,10 @@ public class StrutsResultFactory implements ResultFactory { if (resultClassName != null) { Object o = objectFactory.buildBean(resultClassName, extraContext); + Map params = resultConfig.getParams(); + if (params != null) { + setParameters(extraContext, o, params); + } if (o instanceof Result) { result = (Result) o; } else if (o instanceof org.apache.struts2.Result) { @@ -63,15 +67,23 @@ public class StrutsResultFactory implements ResultFactory { if (result == null) { throw new ConfigurationException("Class [" + resultClassName + "] does not implement Result", resultConfig); } - Map params = resultConfig.getParams(); - if (params != null) { - setParameters(extraContext, result, params); - } } return result; } protected void setParameters(Map extraContext, Result result, Map params) { + setParametersHelper(extraContext, result, params); + } + + protected void setParameters(Map extraContext, Object result, Map params) { + if (result instanceof Result) { + setParameters(extraContext, (Result) result, params); + } else { + setParametersHelper(extraContext, result, params); + } + } + + private void setParametersHelper(Map extraContext, Object result, Map params) { for (Map.Entry paramEntry : params.entrySet()) { try { String name = paramEntry.getKey(); @@ -86,6 +98,18 @@ public class StrutsResultFactory implements ResultFactory { } protected void setParameter(Result result, String name, String value, Map extraContext) { + setParameterHelper(result, name, value, extraContext); + } + + private void setParameter(Object result, String name, String value, Map extraContext) { + if (result instanceof Result) { + setParameter((Result) result, name, value, extraContext); + } else { + setParameterHelper(result, name, value, extraContext); + } + } + + private void setParameterHelper(Object result, String name, String value, Map extraContext) { if (result instanceof ParamNameAwareResult) { if (((ParamNameAwareResult) result).acceptableParameterName(name, value)) { reflectionProvider.setProperty(name, value, result, extraContext, true); @@ -94,5 +118,4 @@ public class StrutsResultFactory implements ResultFactory { reflectionProvider.setProperty(name, value, result, extraContext, true); } } - } From bbca2717f9815af2fccdc56aeb5194efc28f05dc Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Thu, 17 Oct 2024 15:17:14 +1100 Subject: [PATCH 16/33] WW-3714 Deprecate and migrate ActionEventListener --- .../xwork2/ActionEventListener.java | 47 +++++++++++-------- .../opensymphony/xwork2/ActionInvocation.java | 7 +++ .../apache/struts2/ActionEventListener.java | 44 +++++++++++++++++ .../org/apache/struts2/ActionInvocation.java | 1 - 4 files changed, 79 insertions(+), 20 deletions(-) create mode 100644 core/src/main/java/org/apache/struts2/ActionEventListener.java diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionEventListener.java b/core/src/main/java/com/opensymphony/xwork2/ActionEventListener.java index 00690a7f4..4d2143848 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionEventListener.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionEventListener.java @@ -21,24 +21,33 @@ package com.opensymphony.xwork2; import com.opensymphony.xwork2.util.ValueStack; /** - * Provides hooks for handling key action events + * {@inheritDoc} + * + * @deprecated since 6.7.0, use {@link org.apache.struts2.ActionEventListener} instead. */ -public interface ActionEventListener { - /** - * Called after an action has been created. - * - * @param action The action - * @param stack The current value stack - * @return The action to use - */ - public Object prepare(Object action, ValueStack stack); - - /** - * Called when an exception is thrown by the action - * - * @param t The exception/error that was thrown - * @param stack The current value stack - * @return A result code to execute, can be null - */ - public String handleException(Throwable t, ValueStack stack); +@Deprecated +public interface ActionEventListener extends org.apache.struts2.ActionEventListener { + + static ActionEventListener adapt(org.apache.struts2.ActionEventListener actualListener) { + return actualListener != null ? new LegacyAdapter(actualListener) : null; + } + + class LegacyAdapter implements ActionEventListener { + + private final org.apache.struts2.ActionEventListener adaptee; + + private LegacyAdapter(org.apache.struts2.ActionEventListener adaptee) { + this.adaptee = adaptee; + } + + @Override + public Object prepare(Object action, ValueStack stack) { + return adaptee.prepare(action, stack); + } + + @Override + public String handleException(Throwable t, ValueStack stack) { + return adaptee.handleException(t, stack); + } + } } diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java b/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java index 1d6e34859..56ea6ad6e 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java @@ -42,6 +42,13 @@ public interface ActionInvocation extends org.apache.struts2.ActionInvocation { void addPreResultListener(PreResultListener listener); + @Override + default void setActionEventListener(org.apache.struts2.ActionEventListener listener) { + setActionEventListener(ActionEventListener.adapt(listener)); + } + + void setActionEventListener(ActionEventListener listener); + static ActionInvocation adapt(org.apache.struts2.ActionInvocation actualInvocation) { return actualInvocation != null ? new LegacyAdapter(actualInvocation) : null; } diff --git a/core/src/main/java/org/apache/struts2/ActionEventListener.java b/core/src/main/java/org/apache/struts2/ActionEventListener.java new file mode 100644 index 000000000..8c01a9a23 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/ActionEventListener.java @@ -0,0 +1,44 @@ +/* + * 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; + +import com.opensymphony.xwork2.util.ValueStack; + +/** + * Provides hooks for handling key action events + */ +public interface ActionEventListener { + /** + * Called after an action has been created. + * + * @param action The action + * @param stack The current value stack + * @return The action to use + */ + Object prepare(Object action, ValueStack stack); + + /** + * Called when an exception is thrown by the action + * + * @param t The exception/error that was thrown + * @param stack The current value stack + * @return A result code to execute, can be null + */ + String handleException(Throwable t, ValueStack stack); +} diff --git a/core/src/main/java/org/apache/struts2/ActionInvocation.java b/core/src/main/java/org/apache/struts2/ActionInvocation.java index 8b789f50d..14e930a50 100644 --- a/core/src/main/java/org/apache/struts2/ActionInvocation.java +++ b/core/src/main/java/org/apache/struts2/ActionInvocation.java @@ -19,7 +19,6 @@ package org.apache.struts2; import com.opensymphony.xwork2.ActionChainResult; -import com.opensymphony.xwork2.ActionEventListener; import com.opensymphony.xwork2.ActionProxy; import com.opensymphony.xwork2.util.ValueStack; import org.apache.struts2.interceptor.PreResultListener; From 14bd4b80cf4201dbc08b095890bcea342c44ced9 Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Thu, 17 Oct 2024 15:32:34 +1100 Subject: [PATCH 17/33] WW-3714 Deprecate and migrate ActionProxy --- .../opensymphony/xwork2/ActionInvocation.java | 12 +- .../com/opensymphony/xwork2/ActionProxy.java | 140 ++++++++---------- .../org/apache/struts2/ActionInvocation.java | 3 +- .../java/org/apache/struts2/ActionProxy.java | 102 +++++++++++++ 4 files changed, 176 insertions(+), 81 deletions(-) create mode 100644 core/src/main/java/org/apache/struts2/ActionProxy.java diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java b/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java index 56ea6ad6e..82020bbe1 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java @@ -35,6 +35,9 @@ public interface ActionInvocation extends org.apache.struts2.ActionInvocation { @Override Result getResult() throws Exception; + @Override + ActionProxy getProxy(); + @Override default void addPreResultListener(org.apache.struts2.interceptor.PreResultListener listener) { addPreResultListener(PreResultListener.adapt(listener)); @@ -49,6 +52,13 @@ public interface ActionInvocation extends org.apache.struts2.ActionInvocation { void setActionEventListener(ActionEventListener listener); + @Override + default void init(org.apache.struts2.ActionProxy proxy) { + init(ActionProxy.adapt(proxy)); + } + + void init(ActionProxy proxy); + static ActionInvocation adapt(org.apache.struts2.ActionInvocation actualInvocation) { return actualInvocation != null ? new LegacyAdapter(actualInvocation) : null; } @@ -78,7 +88,7 @@ public interface ActionInvocation extends org.apache.struts2.ActionInvocation { @Override public ActionProxy getProxy() { - return adaptee.getProxy(); + return ActionProxy.adapt(adaptee.getProxy()); } @Override diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionProxy.java b/core/src/main/java/com/opensymphony/xwork2/ActionProxy.java index 595671462..18a1e6a6e 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionProxy.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionProxy.java @@ -20,88 +20,72 @@ package com.opensymphony.xwork2; import com.opensymphony.xwork2.config.entities.ActionConfig; -/** - * ActionProxy is an extra layer between XWork and the action so that different proxies are possible. - * - *

- * An example of this would be a remote proxy, where the layer between XWork and the action might be RMI or SOAP. - *

- * - * @author Jason Carreira - */ -public interface ActionProxy { +@Deprecated +public interface ActionProxy extends org.apache.struts2.ActionProxy { - /** - * Gets the Action instance for this Proxy. - * - * @return the Action instance - */ - Object getAction(); - - /** - * Gets the alias name this ActionProxy is mapped to. - * - * @return the alias name - */ - String getActionName(); - - /** - * Gets the ActionConfig this ActionProxy is built from. - * - * @return the ActionConfig - */ - ActionConfig getConfig(); - - /** - * Sets whether this ActionProxy should also execute the Result after executing the Action. - * - * @param executeResult true to also execute the Result. - */ - void setExecuteResult(boolean executeResult); - - /** - * Gets the status of whether the ActionProxy is set to execute the Result after the Action is executed. - * - * @return the status - */ - boolean getExecuteResult(); - - /** - * Gets the ActionInvocation associated with this ActionProxy. - * - * @return the ActionInvocation - */ + @Override ActionInvocation getInvocation(); - /** - * Gets the namespace the ActionConfig for this ActionProxy is mapped to. - * - * @return the namespace - */ - String getNamespace(); + static ActionProxy adapt(org.apache.struts2.ActionProxy actualProxy) { + return actualProxy != null ? new LegacyAdapter(actualProxy) : null; + } - /** - * Execute this ActionProxy. This will set the ActionContext from the ActionInvocation into the ActionContext - * ThreadLocal before invoking the ActionInvocation, then set the old ActionContext back into the ThreadLocal. - * - * @return the result code returned from executing the ActionInvocation - * @throws Exception can be thrown. - * @see ActionInvocation - */ - String execute() throws Exception; + class LegacyAdapter implements ActionProxy { - /** - * Gets the method name to execute, or null if no method has been specified (meaning execute will be invoked). - * - * @return the method to execute - */ - String getMethod(); + private final org.apache.struts2.ActionProxy adaptee; - /** - * Gets status of the method value's initialization. - * - * @return true if the method returned by getMethod() is not a default initializer value. - */ - boolean isMethodSpecified(); - + private LegacyAdapter(org.apache.struts2.ActionProxy adaptee) { + this.adaptee = adaptee; + } + + @Override + public Object getAction() { + return adaptee.getAction(); + } + + @Override + public String getActionName() { + return adaptee.getActionName(); + } + + @Override + public ActionConfig getConfig() { + return adaptee.getConfig(); + } + + @Override + public void setExecuteResult(boolean executeResult) { + adaptee.setExecuteResult(executeResult); + } + + @Override + public boolean getExecuteResult() { + return adaptee.getExecuteResult(); + } + + @Override + public ActionInvocation getInvocation() { + return ActionInvocation.adapt(adaptee.getInvocation()); + } + + @Override + public String getNamespace() { + return adaptee.getNamespace(); + } + + @Override + public String execute() throws Exception { + return adaptee.execute(); + } + + @Override + public String getMethod() { + return adaptee.getMethod(); + } + + @Override + public boolean isMethodSpecified() { + return adaptee.isMethodSpecified(); + } + } } diff --git a/core/src/main/java/org/apache/struts2/ActionInvocation.java b/core/src/main/java/org/apache/struts2/ActionInvocation.java index 14e930a50..e3d446bc0 100644 --- a/core/src/main/java/org/apache/struts2/ActionInvocation.java +++ b/core/src/main/java/org/apache/struts2/ActionInvocation.java @@ -19,7 +19,6 @@ package org.apache.struts2; import com.opensymphony.xwork2.ActionChainResult; -import com.opensymphony.xwork2.ActionProxy; import com.opensymphony.xwork2.util.ValueStack; import org.apache.struts2.interceptor.PreResultListener; @@ -176,6 +175,6 @@ public interface ActionInvocation { */ void setActionEventListener(ActionEventListener listener); - void init(ActionProxy proxy) ; + void init(ActionProxy proxy); } diff --git a/core/src/main/java/org/apache/struts2/ActionProxy.java b/core/src/main/java/org/apache/struts2/ActionProxy.java new file mode 100644 index 000000000..d5e19e44d --- /dev/null +++ b/core/src/main/java/org/apache/struts2/ActionProxy.java @@ -0,0 +1,102 @@ +/* + * 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; + +import com.opensymphony.xwork2.config.entities.ActionConfig; + +/** + * ActionProxy is an extra layer between XWork and the action so that different proxies are possible. + * + *

+ * An example of this would be a remote proxy, where the layer between XWork and the action might be RMI or SOAP. + *

+ * + * @author Jason Carreira + */ +public interface ActionProxy { + + /** + * Gets the Action instance for this Proxy. + * + * @return the Action instance + */ + Object getAction(); + + /** + * Gets the alias name this ActionProxy is mapped to. + * + * @return the alias name + */ + String getActionName(); + + /** + * Gets the ActionConfig this ActionProxy is built from. + * + * @return the ActionConfig + */ + ActionConfig getConfig(); + + /** + * Sets whether this ActionProxy should also execute the Result after executing the Action. + * + * @param executeResult true to also execute the Result. + */ + void setExecuteResult(boolean executeResult); + + /** + * Gets the status of whether the ActionProxy is set to execute the Result after the Action is executed. + * + * @return the status + */ + boolean getExecuteResult(); + + ActionInvocation getInvocation(); + + /** + * Gets the namespace the ActionConfig for this ActionProxy is mapped to. + * + * @return the namespace + */ + String getNamespace(); + + /** + * Execute this ActionProxy. This will set the ActionContext from the ActionInvocation into the ActionContext + * ThreadLocal before invoking the ActionInvocation, then set the old ActionContext back into the ThreadLocal. + * + * @return the result code returned from executing the ActionInvocation + * @throws Exception can be thrown. + * @see ActionInvocation + */ + String execute() throws Exception; + + /** + * Gets the method name to execute, or null if no method has been specified (meaning execute will be invoked). + * + * @return the method to execute + */ + String getMethod(); + + /** + * Gets status of the method value's initialization. + * + * @return true if the method returned by getMethod() is not a default initializer value. + */ + boolean isMethodSpecified(); + +} From 8ba8ee5fe6298aaa3debfb5a1197abb4cae6ad99 Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Thu, 17 Oct 2024 15:46:25 +1100 Subject: [PATCH 18/33] WW-3714 Deprecate and migrate ValueStack --- .../opensymphony/xwork2/ActionContext.java | 2 +- .../xwork2/ActionEventListener.java | 14 ++ .../opensymphony/xwork2/ActionInvocation.java | 5 +- .../opensymphony/xwork2/util/ValueStack.java | 222 ++++++++---------- .../apache/struts2/ActionEventListener.java | 2 +- .../org/apache/struts2/ActionInvocation.java | 2 +- .../org/apache/struts2/util/ValueStack.java | 167 +++++++++++++ 7 files changed, 289 insertions(+), 125 deletions(-) create mode 100644 core/src/main/java/org/apache/struts2/util/ValueStack.java diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java index c7864571f..786c896d2 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java @@ -43,7 +43,7 @@ public class ActionContext extends org.apache.struts2.ActionContext { super(actualContext.getContextMap()); } - static ActionContext adapt(org.apache.struts2.ActionContext actualContext) { + public static ActionContext adapt(org.apache.struts2.ActionContext actualContext) { return actualContext != null ? new ActionContext(actualContext) : null; } diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionEventListener.java b/core/src/main/java/com/opensymphony/xwork2/ActionEventListener.java index 4d2143848..5bd4f86d5 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionEventListener.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionEventListener.java @@ -28,6 +28,20 @@ import com.opensymphony.xwork2.util.ValueStack; @Deprecated public interface ActionEventListener extends org.apache.struts2.ActionEventListener { + @Override + default Object prepare(Object action, org.apache.struts2.util.ValueStack stack) { + return prepare(action, ValueStack.adapt(stack)); + } + + @Override + default String handleException(Throwable t, org.apache.struts2.util.ValueStack stack) { + return handleException(t, ValueStack.adapt(stack)); + } + + Object prepare(Object action, ValueStack stack); + + String handleException(Throwable t, ValueStack stack); + static ActionEventListener adapt(org.apache.struts2.ActionEventListener actualListener) { return actualListener != null ? new LegacyAdapter(actualListener) : null; } diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java b/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java index 82020bbe1..76929a647 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java @@ -38,6 +38,9 @@ public interface ActionInvocation extends org.apache.struts2.ActionInvocation { @Override ActionProxy getProxy(); + @Override + ValueStack getStack(); + @Override default void addPreResultListener(org.apache.struts2.interceptor.PreResultListener listener) { addPreResultListener(PreResultListener.adapt(listener)); @@ -108,7 +111,7 @@ public interface ActionInvocation extends org.apache.struts2.ActionInvocation { @Override public ValueStack getStack() { - return adaptee.getStack(); + return ValueStack.adapt(adaptee.getStack()); } @Override diff --git a/core/src/main/java/com/opensymphony/xwork2/util/ValueStack.java b/core/src/main/java/com/opensymphony/xwork2/util/ValueStack.java index 4d02b235f..9e3e98b57 100644 --- a/core/src/main/java/com/opensymphony/xwork2/util/ValueStack.java +++ b/core/src/main/java/com/opensymphony/xwork2/util/ValueStack.java @@ -23,144 +23,124 @@ import com.opensymphony.xwork2.ActionContext; import java.util.Map; /** - * ValueStack allows multiple beans to be pushed in and dynamic EL expressions to be evaluated against it. When - * evaluating an expression, the stack will be searched down the stack, from the latest objects pushed in to the - * earliest, looking for a bean with a getter or setter for the given property or a method of the given name (depending - * on the expression being evaluated). + * @deprecated since 6.7.0, use {@link org.apache.struts2.util.ValueStack} instead. */ -public interface ValueStack { - - String VALUE_STACK = "com.opensymphony.xwork2.util.ValueStack.ValueStack"; - - String REPORT_ERRORS_ON_NO_PROP = "com.opensymphony.xwork2.util.ValueStack.ReportErrorsOnNoProp"; - - /** - * Gets the context for this value stack. The context holds all the information in the value stack and it's surroundings. - * - * @return the context. - */ - Map getContext(); +@Deprecated +public interface ValueStack extends org.apache.struts2.util.ValueStack { + @Override ActionContext getActionContext(); - /** - * Sets the default type to convert to if no type is provided when getting a value. - * - * @param defaultType the new default type - */ - void setDefaultType(Class defaultType); + static ValueStack adapt(org.apache.struts2.util.ValueStack actualStack) { + return actualStack != null ? new LegacyAdapter(actualStack) : null; + } - /** - * Set a override map containing key -> values that takes precedent when doing find operations on the ValueStack. - *

- * See the unit test for ValueStackTest for examples. - *

- * - * @param overrides overrides map. - */ - void setExprOverrides(Map overrides); + class LegacyAdapter implements ValueStack { - /** - * Gets the override map if anyone exists. - * - * @return the override map, null if not set. - */ - Map getExprOverrides(); + private final org.apache.struts2.util.ValueStack adaptee; - /** - * Get the CompoundRoot which holds the objects pushed onto the stack - * - * @return the root - */ - CompoundRoot getRoot(); + private LegacyAdapter(org.apache.struts2.util.ValueStack adaptee) { + this.adaptee = adaptee; + } - /** - * Attempts to set a property on a bean in the stack with the given expression using the default search order. - * - * @param expr the expression defining the path to the property to be set. - * @param value the value to be set into the named property - */ - void setValue(String expr, Object value); + @Override + public Map getContext() { + return adaptee.getContext(); + } - /** - * Attempts to set a property on a bean in the stack with the given expression using the default search order. - * N.B.: unlike #setValue(String,Object) it doesn't allow eval expression. - * @param expr the expression defining the path to the property to be set. - * @param value the value to be set into the named property - */ - void setParameter(String expr, Object value); + @Override + public ActionContext getActionContext() { + return ActionContext.adapt(adaptee.getActionContext()); + } - /** - * Attempts to set a property on a bean in the stack with the given expression using the default search order. - * - * @param expr the expression defining the path to the property to be set. - * @param value the value to be set into the named property - * @param throwExceptionOnFailure a flag to tell whether an exception should be thrown if there is no property with - * the given name. - */ - void setValue(String expr, Object value, boolean throwExceptionOnFailure); + @Override + public void setDefaultType(Class defaultType) { + adaptee.setDefaultType(defaultType); + } - String findString(String expr); - String findString(String expr, boolean throwExceptionOnFailure); + @Override + public void setExprOverrides(Map overrides) { + adaptee.setExprOverrides(overrides); + } - /** - * Find a value by evaluating the given expression against the stack in the default search order. - * - * @param expr the expression giving the path of properties to navigate to find the property value to return - * @return the result of evaluating the expression - */ - Object findValue(String expr); + @Override + public Map getExprOverrides() { + return adaptee.getExprOverrides(); + } - Object findValue(String expr, boolean throwExceptionOnFailure); + @Override + public CompoundRoot getRoot() { + return adaptee.getRoot(); + } - /** - * Find a value by evaluating the given expression against the stack in the default search order. - * - * @param expr the expression giving the path of properties to navigate to find the property value to return - * @param asType the type to convert the return value to - * @return the result of evaluating the expression - */ - Object findValue(String expr, Class asType); - Object findValue(String expr, Class asType, boolean throwExceptionOnFailure); + @Override + public void setValue(String expr, Object value) { + adaptee.setValue(expr, value); + } - /** - * Get the object on the top of the stack without changing the stack. - * - * @return the object on the top. - * @see CompoundRoot#peek() - */ - Object peek(); + @Override + public void setParameter(String expr, Object value) { + adaptee.setParameter(expr, value); + } - /** - * Get the object on the top of the stack and remove it from the stack. - * - * @return the object on the top of the stack - * @see CompoundRoot#pop() - */ - Object pop(); + @Override + public void setValue(String expr, Object value, boolean throwExceptionOnFailure) { + adaptee.setValue(expr, value, throwExceptionOnFailure); + } - /** - * Put this object onto the top of the stack - * - * @param o the object to be pushed onto the stack - * @see CompoundRoot#push(Object) - */ - void push(Object o); + @Override + public String findString(String expr) { + return adaptee.findString(expr); + } - /** - * Sets an object on the stack with the given key - * so it is retrievable by {@link #findValue(String)}, {@link #findValue(String, Class)} - * - * @param key the key - * @param o the object - */ - void set(String key, Object o); + @Override + public String findString(String expr, boolean throwExceptionOnFailure) { + return adaptee.findString(expr, throwExceptionOnFailure); + } - /** - * Get the number of objects in the stack - * - * @return the number of objects in the stack - */ - int size(); + @Override + public Object findValue(String expr) { + return adaptee.findValue(expr); + } -} \ No newline at end of file + @Override + public Object findValue(String expr, boolean throwExceptionOnFailure) { + return adaptee.findValue(expr, throwExceptionOnFailure); + } + + @Override + public Object findValue(String expr, Class asType) { + return adaptee.findValue(expr, asType); + } + + @Override + public Object findValue(String expr, Class asType, boolean throwExceptionOnFailure) { + return adaptee.findValue(expr, asType, throwExceptionOnFailure); + } + + @Override + public Object peek() { + return adaptee.peek(); + } + + @Override + public Object pop() { + return adaptee.pop(); + } + + @Override + public void push(Object o) { + adaptee.push(o); + } + + @Override + public void set(String key, Object o) { + adaptee.set(key, o); + } + + @Override + public int size() { + return adaptee.size(); + } + } +} diff --git a/core/src/main/java/org/apache/struts2/ActionEventListener.java b/core/src/main/java/org/apache/struts2/ActionEventListener.java index 8c01a9a23..23077cc9a 100644 --- a/core/src/main/java/org/apache/struts2/ActionEventListener.java +++ b/core/src/main/java/org/apache/struts2/ActionEventListener.java @@ -18,7 +18,7 @@ */ package org.apache.struts2; -import com.opensymphony.xwork2.util.ValueStack; +import org.apache.struts2.util.ValueStack; /** * Provides hooks for handling key action events diff --git a/core/src/main/java/org/apache/struts2/ActionInvocation.java b/core/src/main/java/org/apache/struts2/ActionInvocation.java index e3d446bc0..5fcbc75ec 100644 --- a/core/src/main/java/org/apache/struts2/ActionInvocation.java +++ b/core/src/main/java/org/apache/struts2/ActionInvocation.java @@ -19,8 +19,8 @@ package org.apache.struts2; import com.opensymphony.xwork2.ActionChainResult; -import com.opensymphony.xwork2.util.ValueStack; import org.apache.struts2.interceptor.PreResultListener; +import org.apache.struts2.util.ValueStack; /** * An {@link ActionInvocation} represents the execution state of an {@link com.opensymphony.xwork2.Action}. It holds the Interceptors and the Action instance. diff --git a/core/src/main/java/org/apache/struts2/util/ValueStack.java b/core/src/main/java/org/apache/struts2/util/ValueStack.java new file mode 100644 index 000000000..f7d70a35d --- /dev/null +++ b/core/src/main/java/org/apache/struts2/util/ValueStack.java @@ -0,0 +1,167 @@ +/* + * 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.util; + +import com.opensymphony.xwork2.util.CompoundRoot; +import org.apache.struts2.ActionContext; + +import java.util.Map; + +/** + * ValueStack allows multiple beans to be pushed in and dynamic EL expressions to be evaluated against it. When + * evaluating an expression, the stack will be searched down the stack, from the latest objects pushed in to the + * earliest, looking for a bean with a getter or setter for the given property or a method of the given name (depending + * on the expression being evaluated). + */ +public interface ValueStack { + + String VALUE_STACK = "com.opensymphony.xwork2.util.ValueStack.ValueStack"; + + String REPORT_ERRORS_ON_NO_PROP = "com.opensymphony.xwork2.util.ValueStack.ReportErrorsOnNoProp"; + + /** + * Gets the context for this value stack. The context holds all the information in the value stack and it's surroundings. + * + * @return the context. + */ + Map getContext(); + + ActionContext getActionContext(); + + /** + * Sets the default type to convert to if no type is provided when getting a value. + * + * @param defaultType the new default type + */ + void setDefaultType(Class defaultType); + + /** + * Set a override map containing key -> values that takes precedent when doing find operations on the ValueStack. + *

+ * See the unit test for ValueStackTest for examples. + *

+ * + * @param overrides overrides map. + */ + void setExprOverrides(Map overrides); + + /** + * Gets the override map if anyone exists. + * + * @return the override map, null if not set. + */ + Map getExprOverrides(); + + /** + * Get the CompoundRoot which holds the objects pushed onto the stack + * + * @return the root + */ + CompoundRoot getRoot(); + + /** + * Attempts to set a property on a bean in the stack with the given expression using the default search order. + * + * @param expr the expression defining the path to the property to be set. + * @param value the value to be set into the named property + */ + void setValue(String expr, Object value); + + /** + * Attempts to set a property on a bean in the stack with the given expression using the default search order. + * N.B.: unlike #setValue(String,Object) it doesn't allow eval expression. + * @param expr the expression defining the path to the property to be set. + * @param value the value to be set into the named property + */ + void setParameter(String expr, Object value); + + /** + * Attempts to set a property on a bean in the stack with the given expression using the default search order. + * + * @param expr the expression defining the path to the property to be set. + * @param value the value to be set into the named property + * @param throwExceptionOnFailure a flag to tell whether an exception should be thrown if there is no property with + * the given name. + */ + void setValue(String expr, Object value, boolean throwExceptionOnFailure); + + String findString(String expr); + String findString(String expr, boolean throwExceptionOnFailure); + + /** + * Find a value by evaluating the given expression against the stack in the default search order. + * + * @param expr the expression giving the path of properties to navigate to find the property value to return + * @return the result of evaluating the expression + */ + Object findValue(String expr); + + Object findValue(String expr, boolean throwExceptionOnFailure); + + /** + * Find a value by evaluating the given expression against the stack in the default search order. + * + * @param expr the expression giving the path of properties to navigate to find the property value to return + * @param asType the type to convert the return value to + * @return the result of evaluating the expression + */ + Object findValue(String expr, Class asType); + Object findValue(String expr, Class asType, boolean throwExceptionOnFailure); + + /** + * Get the object on the top of the stack without changing the stack. + * + * @return the object on the top. + * @see CompoundRoot#peek() + */ + Object peek(); + + /** + * Get the object on the top of the stack and remove it from the stack. + * + * @return the object on the top of the stack + * @see CompoundRoot#pop() + */ + Object pop(); + + /** + * Put this object onto the top of the stack + * + * @param o the object to be pushed onto the stack + * @see CompoundRoot#push(Object) + */ + void push(Object o); + + /** + * Sets an object on the stack with the given key + * so it is retrievable by {@link #findValue(String)}, {@link #findValue(String, Class)} + * + * @param key the key + * @param o the object + */ + void set(String key, Object o); + + /** + * Get the number of objects in the stack + * + * @return the number of objects in the stack + */ + int size(); + +} From 111bc256504d114bc1c42fa34e7bb05587398cd9 Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Thu, 17 Oct 2024 16:12:01 +1100 Subject: [PATCH 19/33] WW-3714 Deprecate and migrate assorted marker interfaces --- .../com/opensymphony/xwork2/ModelDriven.java | 16 +-- .../com/opensymphony/xwork2/Preparable.java | 17 +-- .../com/opensymphony/xwork2/Unchainable.java | 7 +- .../com/opensymphony/xwork2/Validateable.java | 15 +- .../xwork2/interceptor/ScopedModelDriven.java | 21 +-- .../xwork2/interceptor/ValidationAware.java | 111 +-------------- .../interceptor/ValidationErrorAware.java | 20 +-- .../interceptor/ValidationWorkflowAware.java | 10 +- .../java/org/apache/struts2/ModelDriven.java | 36 +++++ .../java/org/apache/struts2/Preparable.java | 37 +++++ .../java/org/apache/struts2/Unchainable.java | 27 ++++ .../java/org/apache/struts2/Validateable.java | 35 +++++ .../interceptor/ScopedModelDriven.java | 43 ++++++ .../struts2/interceptor/ValidationAware.java | 131 ++++++++++++++++++ .../interceptor/ValidationErrorAware.java | 40 ++++++ .../interceptor/ValidationWorkflowAware.java | 30 ++++ ...onfigurationProviderOgnlAllowlistTest.java | 12 +- 17 files changed, 412 insertions(+), 196 deletions(-) create mode 100644 core/src/main/java/org/apache/struts2/ModelDriven.java create mode 100644 core/src/main/java/org/apache/struts2/Preparable.java create mode 100644 core/src/main/java/org/apache/struts2/Unchainable.java create mode 100644 core/src/main/java/org/apache/struts2/Validateable.java create mode 100644 core/src/main/java/org/apache/struts2/interceptor/ScopedModelDriven.java create mode 100644 core/src/main/java/org/apache/struts2/interceptor/ValidationAware.java create mode 100644 core/src/main/java/org/apache/struts2/interceptor/ValidationErrorAware.java create mode 100644 core/src/main/java/org/apache/struts2/interceptor/ValidationWorkflowAware.java diff --git a/core/src/main/java/com/opensymphony/xwork2/ModelDriven.java b/core/src/main/java/com/opensymphony/xwork2/ModelDriven.java index c07c6bbe7..f3ae25cab 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ModelDriven.java +++ b/core/src/main/java/com/opensymphony/xwork2/ModelDriven.java @@ -19,18 +19,8 @@ package com.opensymphony.xwork2; /** - * ModelDriven Actions provide a model object to be pushed onto the ValueStack - * in addition to the Action itself, allowing a FormBean type approach like Struts. - * - * @author Jason Carreira + * @deprecated since 6.7.0, use {@link org.apache.struts2.ModelDriven} instead. */ -public interface ModelDriven { - - /** - * Gets the model to be pushed onto the ValueStack instead of the Action itself. - * - * @return the model - */ - T getModel(); - +@Deprecated +public interface ModelDriven extends org.apache.struts2.ModelDriven { } diff --git a/core/src/main/java/com/opensymphony/xwork2/Preparable.java b/core/src/main/java/com/opensymphony/xwork2/Preparable.java index 23fdf68ae..2c03088e8 100644 --- a/core/src/main/java/com/opensymphony/xwork2/Preparable.java +++ b/core/src/main/java/com/opensymphony/xwork2/Preparable.java @@ -19,19 +19,8 @@ package com.opensymphony.xwork2; /** - * Preparable Actions will have their prepare() method called if the {@link com.opensymphony.xwork2.interceptor.PrepareInterceptor} - * is applied to the ActionConfig. - * - * @author Jason Carreira - * @see com.opensymphony.xwork2.interceptor.PrepareInterceptor + * @deprecated since 6.7.0, use {@link org.apache.struts2.Preparable} instead. */ -public interface Preparable { - - /** - * This method is called to allow the action to prepare itself. - * - * @throws Exception thrown if a system level exception occurs. - */ - void prepare() throws Exception; - +@Deprecated +public interface Preparable extends org.apache.struts2.Preparable { } diff --git a/core/src/main/java/com/opensymphony/xwork2/Unchainable.java b/core/src/main/java/com/opensymphony/xwork2/Unchainable.java index 9f96b92dc..506f4f283 100644 --- a/core/src/main/java/com/opensymphony/xwork2/Unchainable.java +++ b/core/src/main/java/com/opensymphony/xwork2/Unchainable.java @@ -19,9 +19,8 @@ package com.opensymphony.xwork2; /** - * Simple marker interface to indicate an object should not have its properties copied during chaining. - * - * @see com.opensymphony.xwork2.interceptor.ChainingInterceptor + * @deprecated since 6.7.0, use {@link org.apache.struts2.Unchainable} instead. */ -public interface Unchainable { +@Deprecated +public interface Unchainable extends org.apache.struts2.Unchainable { } diff --git a/core/src/main/java/com/opensymphony/xwork2/Validateable.java b/core/src/main/java/com/opensymphony/xwork2/Validateable.java index ed7226380..c92170e73 100644 --- a/core/src/main/java/com/opensymphony/xwork2/Validateable.java +++ b/core/src/main/java/com/opensymphony/xwork2/Validateable.java @@ -19,17 +19,8 @@ package com.opensymphony.xwork2; /** - * Provides an interface in which a call for a validation check can be done. - * - * @author Jason Carreira - * @see ActionSupport - * @see com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor + * @deprecated since 6.7.0, use {@link org.apache.struts2.Validateable} instead. */ -public interface Validateable { - - /** - * Performs validation. - */ - void validate(); - +@Deprecated +public interface Validateable extends org.apache.struts2.Validateable { } diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDriven.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDriven.java index 42ddb09b3..d5413b4e5 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDriven.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDriven.java @@ -21,23 +21,8 @@ package com.opensymphony.xwork2.interceptor; import com.opensymphony.xwork2.ModelDriven; /** - * Adds the ability to set a model, probably retrieved from a given state. + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ScopedModelDriven} instead. */ -public interface ScopedModelDriven extends ModelDriven { - - /** - * @param model sets the model - */ - void setModel(T model); - - /** - * Sets the key under which the model is stored - * @param key The model key - */ - void setScopeKey(String key); - - /** - * @return the key under which the model is stored - */ - String getScopeKey(); +@Deprecated +public interface ScopedModelDriven extends org.apache.struts2.interceptor.ScopedModelDriven, ModelDriven { } diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationAware.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationAware.java index 485cb42fb..c959f19d7 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationAware.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationAware.java @@ -18,114 +18,9 @@ */ package com.opensymphony.xwork2.interceptor; -import java.util.Collection; -import java.util.List; -import java.util.Map; - /** - * ValidationAware classes can accept Action (class level) or field level error messages. Action level messages are kept - * in a Collection. Field level error messages are kept in a Map from String field name to a List of field error msgs. + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ValidationAware} instead. */ -public interface ValidationAware { - - /** - * Set the Collection of Action-level String error messages. - * - * @param errorMessages Collection of String error messages - */ - void setActionErrors(Collection errorMessages); - - /** - * Get the Collection of Action-level error messages for this action. Error messages should not - * be added directly here, as implementations are free to return a new Collection or an - * Unmodifiable Collection. - * - * @return Collection of String error messages - */ - Collection getActionErrors(); - - /** - * Set the Collection of Action-level String messages (not errors). - * - * @param messages Collection of String messages (not errors). - */ - void setActionMessages(Collection messages); - - /** - * Get the Collection of Action-level messages for this action. Messages should not be added - * directly here, as implementations are free to return a new Collection or an Unmodifiable - * Collection. - * - * @return Collection of String messages - */ - Collection getActionMessages(); - - /** - * Set the field error map of fieldname (String) to Collection of String error messages. - * - * @param errorMap field error map - */ - void setFieldErrors(Map> errorMap); - - /** - * Get the field specific errors associated with this action. Error messages should not be added - * directly here, as implementations are free to return a new Collection or an Unmodifiable - * Collection. - * - * @return Map with errors mapped from fieldname (String) to Collection of String error messages - */ - Map> getFieldErrors(); - - /** - * Add an Action-level error message to this Action. - * - * @param anErrorMessage the error message - */ - void addActionError(String anErrorMessage); - - /** - * Add an Action-level message to this Action. - * - * @param aMessage the message - */ - void addActionMessage(String aMessage); - - /** - * Add an error message for a given field. - * - * @param fieldName name of field - * @param errorMessage the error message - */ - void addFieldError(String fieldName, String errorMessage); - - /** - * Check whether there are any Action-level error messages. - * - * @return true if any Action-level error messages have been registered - */ - boolean hasActionErrors(); - - /** - * Checks whether there are any Action-level messages. - * - * @return true if any Action-level messages have been registered - */ - boolean hasActionMessages(); - - /** - * Checks whether there are any action errors or field errors. - * - * @return (hasActionErrors() || hasFieldErrors()) - */ - default boolean hasErrors() { - return hasActionErrors() || hasFieldErrors(); - } - - /** - * Check whether there are any field errors associated with this action. - * - * @return whether there are any field errors - */ - boolean hasFieldErrors(); - +@Deprecated +public interface ValidationAware extends org.apache.struts2.interceptor.ValidationAware { } diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationErrorAware.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationErrorAware.java index 4d04fa6dc..184cf1339 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationErrorAware.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationErrorAware.java @@ -19,22 +19,8 @@ package com.opensymphony.xwork2.interceptor; /** - * ValidationErrorAware classes can be notified about validation errors - * before {@link com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor} will return 'inputResultName' result - * to allow change or not the result name - * - * This interface can be only applied to action which already implements {@link ValidationAware} interface! - * - * @since 2.3.15 + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ValidationErrorAware} instead. */ -public interface ValidationErrorAware { - - /** - * Allows to notify action about occurred action/field errors - * - * @param currentResultName current result name, action can change it or return the same - * @return new result name or passed currentResultName - */ - String actionErrorOccurred(final String currentResultName); - +@Deprecated +public interface ValidationErrorAware extends org.apache.struts2.interceptor.ValidationErrorAware { } diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationWorkflowAware.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationWorkflowAware.java index b6c25ed31..fc0218d43 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationWorkflowAware.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationWorkflowAware.java @@ -19,12 +19,8 @@ package com.opensymphony.xwork2.interceptor; /** - * ValidationWorkflowAware classes can programmatically change result name when errors occurred - * - * This interface can be only applied to action which already implements {@link ValidationAware} interface! + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ValidationWorkflowAware} instead. */ -public interface ValidationWorkflowAware { - - String getInputResultName(); - +@Deprecated +public interface ValidationWorkflowAware extends org.apache.struts2.interceptor.ValidationWorkflowAware { } diff --git a/core/src/main/java/org/apache/struts2/ModelDriven.java b/core/src/main/java/org/apache/struts2/ModelDriven.java new file mode 100644 index 000000000..0704109f1 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/ModelDriven.java @@ -0,0 +1,36 @@ +/* + * 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; + +/** + * ModelDriven Actions provide a model object to be pushed onto the ValueStack + * in addition to the Action itself, allowing a FormBean type approach like Struts. + * + * @author Jason Carreira + */ +public interface ModelDriven { + + /** + * Gets the model to be pushed onto the ValueStack instead of the Action itself. + * + * @return the model + */ + T getModel(); + +} diff --git a/core/src/main/java/org/apache/struts2/Preparable.java b/core/src/main/java/org/apache/struts2/Preparable.java new file mode 100644 index 000000000..70b0f464d --- /dev/null +++ b/core/src/main/java/org/apache/struts2/Preparable.java @@ -0,0 +1,37 @@ +/* + * 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; + +/** + * Preparable Actions will have their prepare() method called if the {@link com.opensymphony.xwork2.interceptor.PrepareInterceptor} + * is applied to the ActionConfig. + * + * @author Jason Carreira + * @see com.opensymphony.xwork2.interceptor.PrepareInterceptor + */ +public interface Preparable { + + /** + * This method is called to allow the action to prepare itself. + * + * @throws Exception thrown if a system level exception occurs. + */ + void prepare() throws Exception; + +} diff --git a/core/src/main/java/org/apache/struts2/Unchainable.java b/core/src/main/java/org/apache/struts2/Unchainable.java new file mode 100644 index 000000000..02e010142 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/Unchainable.java @@ -0,0 +1,27 @@ +/* + * 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; + +/** + * Simple marker interface to indicate an object should not have its properties copied during chaining. + * + * @see com.opensymphony.xwork2.interceptor.ChainingInterceptor + */ +public interface Unchainable { +} diff --git a/core/src/main/java/org/apache/struts2/Validateable.java b/core/src/main/java/org/apache/struts2/Validateable.java new file mode 100644 index 000000000..d563e7905 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/Validateable.java @@ -0,0 +1,35 @@ +/* + * 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; + +/** + * Provides an interface in which a call for a validation check can be done. + * + * @author Jason Carreira + * @see com.opensymphony.xwork2.ActionSupport + * @see com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor + */ +public interface Validateable { + + /** + * Performs validation. + */ + void validate(); + +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/ScopedModelDriven.java b/core/src/main/java/org/apache/struts2/interceptor/ScopedModelDriven.java new file mode 100644 index 000000000..d18ef0880 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/ScopedModelDriven.java @@ -0,0 +1,43 @@ +/* + * 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.interceptor; + +import org.apache.struts2.ModelDriven; + +/** + * Adds the ability to set a model, probably retrieved from a given state. + */ +public interface ScopedModelDriven extends ModelDriven { + + /** + * @param model sets the model + */ + void setModel(T model); + + /** + * Sets the key under which the model is stored + * @param key The model key + */ + void setScopeKey(String key); + + /** + * @return the key under which the model is stored + */ + String getScopeKey(); +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/ValidationAware.java b/core/src/main/java/org/apache/struts2/interceptor/ValidationAware.java new file mode 100644 index 000000000..a1e611a1c --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/ValidationAware.java @@ -0,0 +1,131 @@ +/* + * 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.interceptor; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * ValidationAware classes can accept Action (class level) or field level error messages. Action level messages are kept + * in a Collection. Field level error messages are kept in a Map from String field name to a List of field error msgs. + */ +public interface ValidationAware { + + /** + * Set the Collection of Action-level String error messages. + * + * @param errorMessages Collection of String error messages + */ + void setActionErrors(Collection errorMessages); + + /** + * Get the Collection of Action-level error messages for this action. Error messages should not + * be added directly here, as implementations are free to return a new Collection or an + * Unmodifiable Collection. + * + * @return Collection of String error messages + */ + Collection getActionErrors(); + + /** + * Set the Collection of Action-level String messages (not errors). + * + * @param messages Collection of String messages (not errors). + */ + void setActionMessages(Collection messages); + + /** + * Get the Collection of Action-level messages for this action. Messages should not be added + * directly here, as implementations are free to return a new Collection or an Unmodifiable + * Collection. + * + * @return Collection of String messages + */ + Collection getActionMessages(); + + /** + * Set the field error map of fieldname (String) to Collection of String error messages. + * + * @param errorMap field error map + */ + void setFieldErrors(Map> errorMap); + + /** + * Get the field specific errors associated with this action. Error messages should not be added + * directly here, as implementations are free to return a new Collection or an Unmodifiable + * Collection. + * + * @return Map with errors mapped from fieldname (String) to Collection of String error messages + */ + Map> getFieldErrors(); + + /** + * Add an Action-level error message to this Action. + * + * @param anErrorMessage the error message + */ + void addActionError(String anErrorMessage); + + /** + * Add an Action-level message to this Action. + * + * @param aMessage the message + */ + void addActionMessage(String aMessage); + + /** + * Add an error message for a given field. + * + * @param fieldName name of field + * @param errorMessage the error message + */ + void addFieldError(String fieldName, String errorMessage); + + /** + * Check whether there are any Action-level error messages. + * + * @return true if any Action-level error messages have been registered + */ + boolean hasActionErrors(); + + /** + * Checks whether there are any Action-level messages. + * + * @return true if any Action-level messages have been registered + */ + boolean hasActionMessages(); + + /** + * Checks whether there are any action errors or field errors. + * + * @return (hasActionErrors() || hasFieldErrors()) + */ + default boolean hasErrors() { + return hasActionErrors() || hasFieldErrors(); + } + + /** + * Check whether there are any field errors associated with this action. + * + * @return whether there are any field errors + */ + boolean hasFieldErrors(); + +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/ValidationErrorAware.java b/core/src/main/java/org/apache/struts2/interceptor/ValidationErrorAware.java new file mode 100644 index 000000000..7722ed9ec --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/ValidationErrorAware.java @@ -0,0 +1,40 @@ +/* + * 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.interceptor; + +/** + * ValidationErrorAware classes can be notified about validation errors + * before {@link com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor} will return 'inputResultName' result + * to allow change or not the result name + * + * This interface can be only applied to action which already implements {@link ValidationAware} interface! + * + * @since 2.3.15 + */ +public interface ValidationErrorAware { + + /** + * Allows to notify action about occurred action/field errors + * + * @param currentResultName current result name, action can change it or return the same + * @return new result name or passed currentResultName + */ + String actionErrorOccurred(final String currentResultName); + +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/ValidationWorkflowAware.java b/core/src/main/java/org/apache/struts2/interceptor/ValidationWorkflowAware.java new file mode 100644 index 000000000..e3f4a4385 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/ValidationWorkflowAware.java @@ -0,0 +1,30 @@ +/* + * 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.interceptor; + +/** + * ValidationWorkflowAware classes can programmatically change result name when errors occurred + * + * This interface can be only applied to action which already implements {@link ValidationAware} interface! + */ +public interface ValidationWorkflowAware { + + String getInputResultName(); + +} diff --git a/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java b/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java index 0349f6812..2379216bc 100644 --- a/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java +++ b/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java @@ -65,7 +65,9 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase Class.forName("org.apache.struts2.interceptor.Interceptor"), Class.forName("org.apache.struts2.interceptor.ConditionalInterceptor"), Class.forName("org.apache.struts2.Result"), - Class.forName("org.apache.struts2.Action") + Class.forName("org.apache.struts2.Action"), + Class.forName("org.apache.struts2.Validateable"), + Class.forName("org.apache.struts2.interceptor.ValidationAware") ); } @@ -93,7 +95,9 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase Class.forName("org.apache.struts2.interceptor.Interceptor"), Class.forName("org.apache.struts2.interceptor.ConditionalInterceptor"), Class.forName("org.apache.struts2.Result"), - Class.forName("org.apache.struts2.Action") + Class.forName("org.apache.struts2.Action"), + Class.forName("org.apache.struts2.Validateable"), + Class.forName("org.apache.struts2.interceptor.ValidationAware") ); } @@ -120,7 +124,9 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase Class.forName("org.apache.struts2.interceptor.Interceptor"), Class.forName("org.apache.struts2.interceptor.ConditionalInterceptor"), Class.forName("org.apache.struts2.Result"), - Class.forName("org.apache.struts2.Action") + Class.forName("org.apache.struts2.Action"), + Class.forName("org.apache.struts2.Validateable"), + Class.forName("org.apache.struts2.interceptor.ValidationAware") ); } } From dfd07190bdb0dde410b8bb0478e6f105dbb569ba Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Thu, 17 Oct 2024 17:27:47 +1100 Subject: [PATCH 20/33] WW-3714 Update new ActionContext with new ValueStack --- .../main/java/com/opensymphony/xwork2/ActionContext.java | 8 ++++++-- core/src/main/java/org/apache/struts2/ActionContext.java | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java index 786c896d2..1e6d1efbd 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java @@ -163,15 +163,19 @@ public class ActionContext extends org.apache.struts2.ActionContext { return super.getSession(); } - @Override public ActionContext withValueStack(ValueStack valueStack) { + return withValueStack((org.apache.struts2.util.ValueStack) valueStack); + } + + @Override + public ActionContext withValueStack(org.apache.struts2.util.ValueStack valueStack) { super.withValueStack(valueStack); return this; } @Override public ValueStack getValueStack() { - return super.getValueStack(); + return ValueStack.adapt(super.getValueStack()); } @Override diff --git a/core/src/main/java/org/apache/struts2/ActionContext.java b/core/src/main/java/org/apache/struts2/ActionContext.java index bfde35f12..79f7552d5 100644 --- a/core/src/main/java/org/apache/struts2/ActionContext.java +++ b/core/src/main/java/org/apache/struts2/ActionContext.java @@ -20,9 +20,9 @@ package org.apache.struts2; import com.opensymphony.xwork2.conversion.impl.ConversionData; import com.opensymphony.xwork2.inject.Container; -import com.opensymphony.xwork2.util.ValueStack; import org.apache.struts2.dispatcher.HttpParameters; import org.apache.struts2.dispatcher.mapper.ActionMapping; +import org.apache.struts2.util.ValueStack; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; From 7ce8f484e0eb929b11532caa5864aba314149f0e Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Thu, 17 Oct 2024 16:51:29 +1100 Subject: [PATCH 21/33] WW-3714 Shortcut adapters --- core/src/main/java/com/opensymphony/xwork2/ActionContext.java | 3 +++ .../main/java/com/opensymphony/xwork2/ActionEventListener.java | 3 +++ .../main/java/com/opensymphony/xwork2/ActionInvocation.java | 3 +++ core/src/main/java/com/opensymphony/xwork2/ActionProxy.java | 3 +++ core/src/main/java/com/opensymphony/xwork2/Result.java | 3 +++ .../com/opensymphony/xwork2/interceptor/PreResultListener.java | 3 +++ .../src/main/java/com/opensymphony/xwork2/util/ValueStack.java | 3 +++ 7 files changed, 21 insertions(+) diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java index 1e6d1efbd..ac9026b6f 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java @@ -44,6 +44,9 @@ public class ActionContext extends org.apache.struts2.ActionContext { } public static ActionContext adapt(org.apache.struts2.ActionContext actualContext) { + if (actualContext instanceof ActionContext) { + return (ActionContext) actualContext; + } return actualContext != null ? new ActionContext(actualContext) : null; } diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionEventListener.java b/core/src/main/java/com/opensymphony/xwork2/ActionEventListener.java index 5bd4f86d5..28d46e992 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionEventListener.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionEventListener.java @@ -43,6 +43,9 @@ public interface ActionEventListener extends org.apache.struts2.ActionEventListe String handleException(Throwable t, ValueStack stack); static ActionEventListener adapt(org.apache.struts2.ActionEventListener actualListener) { + if (actualListener instanceof ActionEventListener) { + return (ActionEventListener) actualListener; + } return actualListener != null ? new LegacyAdapter(actualListener) : null; } diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java b/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java index 76929a647..81e55d592 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionInvocation.java @@ -63,6 +63,9 @@ public interface ActionInvocation extends org.apache.struts2.ActionInvocation { void init(ActionProxy proxy); static ActionInvocation adapt(org.apache.struts2.ActionInvocation actualInvocation) { + if (actualInvocation instanceof ActionInvocation) { + return (ActionInvocation) actualInvocation; + } return actualInvocation != null ? new LegacyAdapter(actualInvocation) : null; } diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionProxy.java b/core/src/main/java/com/opensymphony/xwork2/ActionProxy.java index 18a1e6a6e..c3905a1a0 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionProxy.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionProxy.java @@ -27,6 +27,9 @@ public interface ActionProxy extends org.apache.struts2.ActionProxy { ActionInvocation getInvocation(); static ActionProxy adapt(org.apache.struts2.ActionProxy actualProxy) { + if (actualProxy instanceof ActionProxy) { + return (ActionProxy) actualProxy; + } return actualProxy != null ? new LegacyAdapter(actualProxy) : null; } diff --git a/core/src/main/java/com/opensymphony/xwork2/Result.java b/core/src/main/java/com/opensymphony/xwork2/Result.java index 294ada4d7..36a93438a 100644 --- a/core/src/main/java/com/opensymphony/xwork2/Result.java +++ b/core/src/main/java/com/opensymphony/xwork2/Result.java @@ -34,6 +34,9 @@ public interface Result extends org.apache.struts2.Result { void execute(ActionInvocation invocation) throws Exception; static Result adapt(org.apache.struts2.Result actualResult) { + if (actualResult instanceof Result) { + return (Result) actualResult; + } return actualResult != null ? new LegacyAdapter(actualResult) : null; } diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/PreResultListener.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/PreResultListener.java index 469d3521b..25ba59a42 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/PreResultListener.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/PreResultListener.java @@ -36,6 +36,9 @@ public interface PreResultListener extends org.apache.struts2.interceptor.PreRes void beforeResult(ActionInvocation invocation, String resultCode); static PreResultListener adapt(org.apache.struts2.interceptor.PreResultListener actualListener) { + if (actualListener instanceof PreResultListener) { + return (PreResultListener) actualListener; + } return actualListener != null ? new LegacyAdapter(actualListener) : null; } diff --git a/core/src/main/java/com/opensymphony/xwork2/util/ValueStack.java b/core/src/main/java/com/opensymphony/xwork2/util/ValueStack.java index 9e3e98b57..22f5bc428 100644 --- a/core/src/main/java/com/opensymphony/xwork2/util/ValueStack.java +++ b/core/src/main/java/com/opensymphony/xwork2/util/ValueStack.java @@ -32,6 +32,9 @@ public interface ValueStack extends org.apache.struts2.util.ValueStack { ActionContext getActionContext(); static ValueStack adapt(org.apache.struts2.util.ValueStack actualStack) { + if (actualStack instanceof ValueStack) { + return (ValueStack) actualStack; + } return actualStack != null ? new LegacyAdapter(actualStack) : null; } From ebedd7391fec19a039d00190d97bbd5705f2f45d Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Thu, 17 Oct 2024 19:28:41 +1100 Subject: [PATCH 22/33] WW-3714 Marker interface migration follow-up --- .../xwork2/interceptor/AliasInterceptor.java | 9 ++-- .../interceptor/ChainingInterceptor.java | 15 ++++-- .../ConversionErrorInterceptor.java | 1 + .../DefaultWorkflowInterceptor.java | 3 ++ .../interceptor/ModelDrivenInterceptor.java | 2 +- .../interceptor/PrepareInterceptor.java | 4 +- .../ScopedModelDrivenInterceptor.java | 1 + .../StaticParametersInterceptor.java | 3 +- .../util/StrutsLocalizedTextProvider.java | 6 +-- .../validator/ValidationInterceptor.java | 52 +++++++++---------- .../AbstractFileUploadInterceptor.java | 1 - .../ActionFileUploadInterceptor.java | 1 - .../interceptor/MessageStoreInterceptor.java | 5 +- .../MessageStorePreResultListener.java | 1 - .../BeanValidationInterceptor.java | 2 +- .../struts2/validators/DWRValidator.java | 2 +- .../org/apache/struts2/json/JSONResult.java | 2 +- .../json/JSONValidationInterceptor.java | 8 +-- .../OValValidationInterceptor.java | 3 +- .../struts2/rest/ContentTypeInterceptor.java | 2 +- .../struts2/rest/RestActionInvocation.java | 12 +++-- .../struts2/rest/RestWorkflowInterceptor.java | 2 +- .../struts2/rest/handler/XStreamHandler.java | 2 +- 23 files changed, 73 insertions(+), 66 deletions(-) diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/AliasInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/AliasInterceptor.java index 9edafe3fc..334525d27 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/AliasInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/AliasInterceptor.java @@ -20,21 +20,22 @@ package com.opensymphony.xwork2.interceptor; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.LocalizedTextProvider; import com.opensymphony.xwork2.config.entities.ActionConfig; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.security.AcceptedPatternsChecker; import com.opensymphony.xwork2.security.ExcludedPatternsChecker; import com.opensymphony.xwork2.util.ClearableValueStack; import com.opensymphony.xwork2.util.Evaluated; -import com.opensymphony.xwork2.LocalizedTextProvider; import com.opensymphony.xwork2.util.ValueStack; import com.opensymphony.xwork2.util.ValueStackFactory; import com.opensymphony.xwork2.util.reflection.ReflectionContextState; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.struts2.StrutsConstants; import org.apache.struts2.dispatcher.HttpParameters; import org.apache.struts2.dispatcher.Parameter; -import org.apache.struts2.StrutsConstants; +import org.apache.struts2.interceptor.ValidationAware; import java.util.Map; @@ -108,7 +109,7 @@ public class AliasInterceptor extends AbstractInterceptor { @Inject(StrutsConstants.STRUTS_DEVMODE) public void setDevMode(String mode) { this.devMode = Boolean.parseBoolean(mode); - } + } @Inject public void setValueStackFactory(ValueStackFactory valueStackFactory) { @@ -225,7 +226,7 @@ public class AliasInterceptor extends AbstractInterceptor { LOG.debug("invalid alias expression: {}", aliasesKey); } } - + return invocation.invoke(); } diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java index 31b0075a3..7284dc037 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java @@ -21,18 +21,23 @@ package com.opensymphony.xwork2.interceptor; import com.opensymphony.xwork2.ActionChainResult; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.Result; -import com.opensymphony.xwork2.Unchainable; import com.opensymphony.xwork2.inject.Inject; -import com.opensymphony.xwork2.util.ProxyUtil; import com.opensymphony.xwork2.util.CompoundRoot; +import com.opensymphony.xwork2.util.ProxyUtil; import com.opensymphony.xwork2.util.TextParseUtil; import com.opensymphony.xwork2.util.ValueStack; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.LogManager; import com.opensymphony.xwork2.util.reflection.ReflectionProvider; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.apache.struts2.StrutsConstants; +import org.apache.struts2.Unchainable; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; /** diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ConversionErrorInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ConversionErrorInterceptor.java index ee8e39281..b549cc019 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ConversionErrorInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ConversionErrorInterceptor.java @@ -24,6 +24,7 @@ import com.opensymphony.xwork2.conversion.impl.ConversionData; import com.opensymphony.xwork2.conversion.impl.XWorkConverter; import com.opensymphony.xwork2.util.ValueStack; import org.apache.commons.text.StringEscapeUtils; +import org.apache.struts2.interceptor.ValidationAware; import java.util.HashMap; import java.util.Map; diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/DefaultWorkflowInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/DefaultWorkflowInterceptor.java index d2cbd0b78..05749ae19 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/DefaultWorkflowInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/DefaultWorkflowInterceptor.java @@ -25,6 +25,9 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.reflect.MethodUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.struts2.interceptor.ValidationAware; +import org.apache.struts2.interceptor.ValidationErrorAware; +import org.apache.struts2.interceptor.ValidationWorkflowAware; /** * diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptor.java index fa90a315c..f513deb1c 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptor.java @@ -19,9 +19,9 @@ package com.opensymphony.xwork2.interceptor; import com.opensymphony.xwork2.ActionInvocation; -import com.opensymphony.xwork2.ModelDriven; import com.opensymphony.xwork2.util.CompoundRoot; import com.opensymphony.xwork2.util.ValueStack; +import org.apache.struts2.ModelDriven; /** * diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/PrepareInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/PrepareInterceptor.java index 4516d760c..e4d5af634 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/PrepareInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/PrepareInterceptor.java @@ -19,9 +19,7 @@ package com.opensymphony.xwork2.interceptor; import com.opensymphony.xwork2.ActionInvocation; -import com.opensymphony.xwork2.Preparable; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.LogManager; +import org.apache.struts2.Preparable; import java.lang.reflect.InvocationTargetException; diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java index 22da179d4..ae2266be0 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java @@ -24,6 +24,7 @@ import com.opensymphony.xwork2.ObjectFactory; import com.opensymphony.xwork2.config.entities.ActionConfig; import com.opensymphony.xwork2.inject.Inject; import org.apache.struts2.StrutsException; +import org.apache.struts2.interceptor.ScopedModelDriven; import java.lang.reflect.Method; import java.util.Map; diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/StaticParametersInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/StaticParametersInterceptor.java index 9d32a8a18..d560e1dd4 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/StaticParametersInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/StaticParametersInterceptor.java @@ -20,11 +20,11 @@ package com.opensymphony.xwork2.interceptor; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.LocalizedTextProvider; import com.opensymphony.xwork2.config.entities.ActionConfig; import com.opensymphony.xwork2.config.entities.Parameterizable; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.util.ClearableValueStack; -import com.opensymphony.xwork2.LocalizedTextProvider; import com.opensymphony.xwork2.util.TextParseUtil; import com.opensymphony.xwork2.util.ValueStack; import com.opensymphony.xwork2.util.ValueStackFactory; @@ -34,6 +34,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.struts2.StrutsConstants; import org.apache.struts2.dispatcher.HttpParameters; +import org.apache.struts2.interceptor.ValidationAware; import java.util.Collections; import java.util.Map; diff --git a/core/src/main/java/com/opensymphony/xwork2/util/StrutsLocalizedTextProvider.java b/core/src/main/java/com/opensymphony/xwork2/util/StrutsLocalizedTextProvider.java index 48acc4274..60ef3477a 100644 --- a/core/src/main/java/com/opensymphony/xwork2/util/StrutsLocalizedTextProvider.java +++ b/core/src/main/java/com/opensymphony/xwork2/util/StrutsLocalizedTextProvider.java @@ -20,11 +20,11 @@ package com.opensymphony.xwork2.util; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; -import com.opensymphony.xwork2.ModelDriven; import com.opensymphony.xwork2.conversion.impl.XWorkConverter; import com.opensymphony.xwork2.util.reflection.ReflectionProviderFactory; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.struts2.ModelDriven; import java.beans.PropertyDescriptor; import java.util.Locale; @@ -135,7 +135,7 @@ public class StrutsLocalizedTextProvider extends AbstractLocalizedTextProvider { * object. If so, repeat the entire process from the beginning with the object's class as * aClass and "address.state" as the message key. *
  • If not found, look for the message in aClass' package hierarchy.
  • - *
  • If still not found, look for the message in the default resource bundles + *
  • If still not found, look for the message in the default resource bundles * (Note: the lookup is not repeated again if {@link #searchDefaultBundlesFirst} was true).
  • *
  • Return defaultMessage
  • * @@ -190,7 +190,7 @@ public class StrutsLocalizedTextProvider extends AbstractLocalizedTextProvider { * object. If so, repeat the entire process from the beginning with the object's class as * aClass and "address.state" as the message key. *
  • If not found, look for the message in aClass' package hierarchy.
  • - *
  • If still not found, look for the message in the default resource bundles + *
  • If still not found, look for the message in the default resource bundles * (Note: the lookup is not repeated again if {@link #searchDefaultBundlesFirst} was true).
  • *
  • Return defaultMessage
  • * diff --git a/core/src/main/java/com/opensymphony/xwork2/validator/ValidationInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/validator/ValidationInterceptor.java index b0852ed03..cc22250e3 100644 --- a/core/src/main/java/com/opensymphony/xwork2/validator/ValidationInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/validator/ValidationInterceptor.java @@ -20,13 +20,13 @@ package com.opensymphony.xwork2.validator; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.ActionProxy; -import com.opensymphony.xwork2.Validateable; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; import com.opensymphony.xwork2.interceptor.PrefixMethodInvocationUtil; import com.opensymphony.xwork2.interceptor.ValidationAware; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.struts2.Validateable; /** * @@ -71,9 +71,9 @@ import org.apache.logging.log4j.Logger; *
  • programmatic - Defaults to true. If true and the action is Validateable call validate(), * and any method that starts with "validate". *
  • - * + * *
  • declarative - Defaults to true. Perform validation based on xml or annotations.
  • - * + * * * * @@ -90,14 +90,14 @@ import org.apache.logging.log4j.Logger; * *
      * 
    - * 
    + *
      * <action name="someAction" class="com.examples.SomeAction">
      *     <interceptor-ref name="params"/>
      *     <interceptor-ref name="validation"/>
      *     <interceptor-ref name="workflow"/>
      *     <result name="success">good_result.ftl</result>
      * </action>
    - * 
    + *
      * <-- in the following case myMethod of the action class will not
      *        get validated -->
      * <action name="someAction" class="com.examples.SomeAction">
    @@ -108,7 +108,7 @@ import org.apache.logging.log4j.Logger;
      *     <interceptor-ref name="workflow"/>
      *     <result name="success">good_result.ftl</result>
      * </action>
    - * 
    + *
      * <-- in the following case only annotated methods of the action class will
      *        be validated -->
      * <action name="someAction" class="com.examples.SomeAction">
    @@ -138,9 +138,9 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
         private final static String ALT_VALIDATE_PREFIX = "validateDo";
     
         private boolean validateAnnotatedMethodOnly;
    -    
    +
         private ActionValidatorManager actionValidatorManager;
    -    
    +
         private boolean alwaysInvokeValidate = true;
         private boolean programmatic = true;
         private boolean declarative = true;
    @@ -149,11 +149,11 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
         public void setActionValidatorManager(ActionValidatorManager mgr) {
             this.actionValidatorManager = mgr;
         }
    -    
    +
         /**
          * Determines if {@link Validateable}'s validate() should be called,
          * as well as methods whose name that start with "validate". Defaults to "true".
    -     * 
    +     *
          * @param programmatic true then validate() is invoked.
          */
         public void setProgrammatic(boolean programmatic) {
    @@ -161,9 +161,9 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
         }
     
         /**
    -     * Determines if validation based on annotations or xml should be performed. Defaults 
    +     * Determines if validation based on annotations or xml should be performed. Defaults
          * to "true".
    -     * 
    +     *
          * @param declarative true then perform validation based on annotations or xml.
          */
         public void setDeclarative(boolean declarative) {
    @@ -171,9 +171,9 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
         }
     
         /**
    -     * Determines if {@link Validateable}'s validate() should always 
    +     * Determines if {@link Validateable}'s validate() should always
          * be invoked. Default to "true".
    -     * 
    +     *
          * @param alwaysInvokeValidate true then validate() is always invoked.
          */
         public void setAlwaysInvokeValidate(String alwaysInvokeValidate) {
    @@ -218,7 +218,7 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
             if (LOG.isDebugEnabled()) {
                 LOG.debug("Validating {}/{} with method {}.", invocation.getProxy().getNamespace(), invocation.getProxy().getActionName(), method);
             }
    -        
    +
     
             if (declarative) {
                if (validateAnnotatedMethodOnly) {
    @@ -226,12 +226,12 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
                } else {
                    actionValidatorManager.validate(action, context);
                }
    -       }    
    -        
    +       }
    +
             if (action instanceof Validateable && programmatic) {
                 // keep exception that might occured in validateXXX or validateDoXXX
    -            Exception exception = null; 
    -            
    +            Exception exception = null;
    +
                 Validateable validateable = (Validateable) action;
                 LOG.debug("Invoking validate() on action {}", validateable);
     
    @@ -239,19 +239,19 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
                     PrefixMethodInvocationUtil.invokePrefixMethod(invocation, new String[]{VALIDATE_PREFIX, ALT_VALIDATE_PREFIX});
                 }
                 catch(Exception e) {
    -                // If any exception occurred while doing reflection, we want 
    +                // If any exception occurred while doing reflection, we want
                     // validate() to be executed
                     LOG.warn("an exception occured while executing the prefix method", e);
                     exception = e;
                 }
    -            
    -            
    +
    +
                 if (alwaysInvokeValidate) {
                     validateable.validate();
                 }
    -            
    -            if (exception != null) { 
    -                // rethrow if something is wrong while doing validateXXX / validateDoXXX 
    +
    +            if (exception != null) {
    +                // rethrow if something is wrong while doing validateXXX / validateDoXXX
                     throw exception;
                 }
             }
    @@ -262,7 +262,7 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
             doBeforeInvocation(invocation);
             return invocation.invoke();
         }
    -    
    +
         /**
          * 

    * Returns the context that will be used by the diff --git a/core/src/main/java/org/apache/struts2/interceptor/AbstractFileUploadInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/AbstractFileUploadInterceptor.java index 1113f4491..ecebd3748 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/AbstractFileUploadInterceptor.java +++ b/core/src/main/java/org/apache/struts2/interceptor/AbstractFileUploadInterceptor.java @@ -25,7 +25,6 @@ import com.opensymphony.xwork2.TextProviderFactory; import com.opensymphony.xwork2.inject.Container; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; -import com.opensymphony.xwork2.interceptor.ValidationAware; import com.opensymphony.xwork2.util.TextParseUtil; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/core/src/main/java/org/apache/struts2/interceptor/ActionFileUploadInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/ActionFileUploadInterceptor.java index c42d125af..681a8ab92 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/ActionFileUploadInterceptor.java +++ b/core/src/main/java/org/apache/struts2/interceptor/ActionFileUploadInterceptor.java @@ -20,7 +20,6 @@ package org.apache.struts2.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.ActionProxy; -import com.opensymphony.xwork2.interceptor.ValidationAware; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.struts2.action.UploadedFilesAware; diff --git a/core/src/main/java/org/apache/struts2/interceptor/MessageStoreInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/MessageStoreInterceptor.java index 1596be589..1d1522828 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/MessageStoreInterceptor.java +++ b/core/src/main/java/org/apache/struts2/interceptor/MessageStoreInterceptor.java @@ -18,14 +18,11 @@ */ package org.apache.struts2.interceptor; -import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; -import com.opensymphony.xwork2.interceptor.ValidationAware; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.struts2.dispatcher.HttpParameters; - import org.apache.struts2.result.ServletRedirectResult; import java.util.ArrayList; @@ -58,7 +55,7 @@ import java.util.Map; * *

    * In the 'AUTOMATIC' mode, the interceptor will always retrieve the stored action's message / errors - * and field errors and put them back into the {@link ValidationAware} action, and after Action execution, + * and field errors and put them back into the {@link ValidationAware} action, and after Action execution, * if the {@link com.opensymphony.xwork2.Result} is an instance of {@link ServletRedirectResult}, the action's message / errors * and field errors into automatically be stored in the HTTP session.. *

    diff --git a/core/src/main/java/org/apache/struts2/interceptor/MessageStorePreResultListener.java b/core/src/main/java/org/apache/struts2/interceptor/MessageStorePreResultListener.java index bf40e148b..6c6dc8041 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/MessageStorePreResultListener.java +++ b/core/src/main/java/org/apache/struts2/interceptor/MessageStorePreResultListener.java @@ -21,7 +21,6 @@ package org.apache.struts2.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.config.entities.ResultConfig; import com.opensymphony.xwork2.interceptor.PreResultListener; -import com.opensymphony.xwork2.interceptor.ValidationAware; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.struts2.ServletActionContext; diff --git a/plugins/bean-validation/src/main/java/org/apache/struts/beanvalidation/validation/interceptor/BeanValidationInterceptor.java b/plugins/bean-validation/src/main/java/org/apache/struts/beanvalidation/validation/interceptor/BeanValidationInterceptor.java index 75c25f9c3..e36e3c63c 100644 --- a/plugins/bean-validation/src/main/java/org/apache/struts/beanvalidation/validation/interceptor/BeanValidationInterceptor.java +++ b/plugins/bean-validation/src/main/java/org/apache/struts/beanvalidation/validation/interceptor/BeanValidationInterceptor.java @@ -20,7 +20,6 @@ package org.apache.struts.beanvalidation.validation.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.ActionProxy; -import com.opensymphony.xwork2.ModelDriven; import com.opensymphony.xwork2.TextProviderFactory; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; @@ -33,6 +32,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.struts.beanvalidation.constraints.ValidationGroup; import org.apache.struts.beanvalidation.validation.constant.ValidatorConstants; +import org.apache.struts2.ModelDriven; import org.apache.struts2.interceptor.validation.SkipValidation; import javax.validation.ConstraintViolation; diff --git a/plugins/dwr/src/main/java/org/apache/struts2/validators/DWRValidator.java b/plugins/dwr/src/main/java/org/apache/struts2/validators/DWRValidator.java index f189cd182..46c2953b5 100644 --- a/plugins/dwr/src/main/java/org/apache/struts2/validators/DWRValidator.java +++ b/plugins/dwr/src/main/java/org/apache/struts2/validators/DWRValidator.java @@ -24,7 +24,6 @@ import com.opensymphony.xwork2.ActionProxyFactory; import com.opensymphony.xwork2.DefaultActionInvocation; import com.opensymphony.xwork2.ValidationAwareSupport; import com.opensymphony.xwork2.config.entities.ActionConfig; -import com.opensymphony.xwork2.interceptor.ValidationAware; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.struts2.dispatcher.ApplicationMap; @@ -32,6 +31,7 @@ import org.apache.struts2.dispatcher.Dispatcher; import org.apache.struts2.dispatcher.HttpParameters; import org.apache.struts2.dispatcher.RequestMap; import org.apache.struts2.dispatcher.SessionMap; +import org.apache.struts2.interceptor.ValidationAware; import org.directwebremoting.WebContextFactory; import javax.servlet.ServletContext; diff --git a/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java b/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java index 2161ef0c1..6d9a8d026 100644 --- a/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java +++ b/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java @@ -20,7 +20,6 @@ package org.apache.struts2.json; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; -import com.opensymphony.xwork2.ModelDriven; import com.opensymphony.xwork2.Result; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.util.ValueStack; @@ -29,6 +28,7 @@ import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.struts2.ModelDriven; import org.apache.struts2.StrutsConstants; import org.apache.struts2.json.smd.SMDGenerator; diff --git a/plugins/json/src/main/java/org/apache/struts2/json/JSONValidationInterceptor.java b/plugins/json/src/main/java/org/apache/struts2/json/JSONValidationInterceptor.java index 4e5938904..354780b38 100644 --- a/plugins/json/src/main/java/org/apache/struts2/json/JSONValidationInterceptor.java +++ b/plugins/json/src/main/java/org/apache/struts2/json/JSONValidationInterceptor.java @@ -20,13 +20,13 @@ package org.apache.struts2.json; import com.opensymphony.xwork2.Action; import com.opensymphony.xwork2.ActionInvocation; -import com.opensymphony.xwork2.ModelDriven; -import com.opensymphony.xwork2.interceptor.ValidationAware; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.LogManager; import org.apache.commons.text.StringEscapeUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.struts2.ModelDriven; import org.apache.struts2.ServletActionContext; +import org.apache.struts2.interceptor.ValidationAware; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; diff --git a/plugins/oval/src/main/java/org/apache/struts2/oval/interceptor/OValValidationInterceptor.java b/plugins/oval/src/main/java/org/apache/struts2/oval/interceptor/OValValidationInterceptor.java index 0bb2bba88..0350c027d 100644 --- a/plugins/oval/src/main/java/org/apache/struts2/oval/interceptor/OValValidationInterceptor.java +++ b/plugins/oval/src/main/java/org/apache/struts2/oval/interceptor/OValValidationInterceptor.java @@ -21,9 +21,7 @@ package org.apache.struts2.oval.interceptor; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.ActionProxy; -import com.opensymphony.xwork2.ModelDriven; import com.opensymphony.xwork2.TextProviderFactory; -import com.opensymphony.xwork2.Validateable; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; import com.opensymphony.xwork2.interceptor.PrefixMethodInvocationUtil; @@ -48,6 +46,7 @@ import ognl.OgnlException; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.struts2.Validateable; import org.apache.struts2.oval.annotation.Profiles; import java.lang.reflect.Field; 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 03d299c86..01a28e6c5 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 @@ -19,9 +19,9 @@ package org.apache.struts2.rest; import com.opensymphony.xwork2.ActionInvocation; -import com.opensymphony.xwork2.ModelDriven; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; +import org.apache.struts2.ModelDriven; import org.apache.struts2.ServletActionContext; import org.apache.struts2.rest.handler.ContentTypeHandler; diff --git a/plugins/rest/src/main/java/org/apache/struts2/rest/RestActionInvocation.java b/plugins/rest/src/main/java/org/apache/struts2/rest/RestActionInvocation.java index 286c80db1..076f94d87 100644 --- a/plugins/rest/src/main/java/org/apache/struts2/rest/RestActionInvocation.java +++ b/plugins/rest/src/main/java/org/apache/struts2/rest/RestActionInvocation.java @@ -18,19 +18,23 @@ */ package org.apache.struts2.rest; -import com.opensymphony.xwork2.*; +import com.opensymphony.xwork2.Action; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.DefaultActionInvocation; +import com.opensymphony.xwork2.Result; import com.opensymphony.xwork2.config.ConfigurationException; import com.opensymphony.xwork2.config.entities.ActionConfig; import com.opensymphony.xwork2.config.entities.ResultConfig; import com.opensymphony.xwork2.inject.Inject; -import com.opensymphony.xwork2.interceptor.ValidationAware; import org.apache.commons.lang3.BooleanUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.struts2.ModelDriven; import org.apache.struts2.ServletActionContext; -import org.apache.struts2.result.HttpHeaderResult; +import org.apache.struts2.interceptor.ValidationAware; import org.apache.struts2.rest.handler.ContentTypeHandler; import org.apache.struts2.rest.handler.HtmlHandler; +import org.apache.struts2.result.HttpHeaderResult; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -74,7 +78,7 @@ public class RestActionInvocation extends DefaultActionInvocation { /** * If set to true (by default) blocks returning content from any other methods than GET, * if set to false, the content can be returned for any kind of method - * + * * @param restrictToGet true or false */ @Inject(value = RestConstants.REST_CONTENT_RESTRICT_TO_GET, required = false) diff --git a/plugins/rest/src/main/java/org/apache/struts2/rest/RestWorkflowInterceptor.java b/plugins/rest/src/main/java/org/apache/struts2/rest/RestWorkflowInterceptor.java index 6a981c8e5..3bfbe779c 100644 --- a/plugins/rest/src/main/java/org/apache/struts2/rest/RestWorkflowInterceptor.java +++ b/plugins/rest/src/main/java/org/apache/struts2/rest/RestWorkflowInterceptor.java @@ -23,10 +23,10 @@ import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; -import com.opensymphony.xwork2.interceptor.ValidationAware; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.struts2.dispatcher.mapper.ActionMapping; +import org.apache.struts2.interceptor.ValidationAware; import java.util.HashMap; import java.util.Map; diff --git a/plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamHandler.java b/plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamHandler.java index 13831093f..b482c0715 100644 --- a/plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamHandler.java +++ b/plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamHandler.java @@ -19,7 +19,6 @@ package org.apache.struts2.rest.handler; import com.opensymphony.xwork2.ActionInvocation; -import com.opensymphony.xwork2.ModelDriven; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.StaxDriver; import com.thoughtworks.xstream.security.ArrayTypePermission; @@ -29,6 +28,7 @@ import com.thoughtworks.xstream.security.PrimitiveTypePermission; import com.thoughtworks.xstream.security.TypePermission; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.struts2.ModelDriven; import org.apache.struts2.rest.handler.xstream.XStreamAllowedClassNames; import org.apache.struts2.rest.handler.xstream.XStreamAllowedClasses; import org.apache.struts2.rest.handler.xstream.XStreamPermissionProvider; From 2757c23572f56335219fdad5cad285e79dcbbcfa Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Tue, 22 Oct 2024 16:48:49 +1100 Subject: [PATCH 23/33] WW-3714 Fix replacement ValidationAware marker not recognised --- .../xwork2/interceptor/ValidationAware.java | 80 +++++++++++++++++++ .../opensymphony/xwork2/util/DebugUtils.java | 2 +- .../validator/DelegatingValidatorContext.java | 18 ++++- .../struts2/interceptor/TokenInterceptor.java | 1 - .../struts2/junit/StrutsJUnit4TestCase.java | 2 +- 5 files changed, 96 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationAware.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationAware.java index c959f19d7..aa9e6f5ff 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationAware.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationAware.java @@ -18,9 +18,89 @@ */ package com.opensymphony.xwork2.interceptor; +import java.util.Collection; +import java.util.List; +import java.util.Map; + /** * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ValidationAware} instead. */ @Deprecated public interface ValidationAware extends org.apache.struts2.interceptor.ValidationAware { + + static ValidationAware adapt(org.apache.struts2.interceptor.ValidationAware actualValidation) { + if (actualValidation instanceof ValidationAware) { + return (ValidationAware) actualValidation; + } + return actualValidation != null ? new LegacyAdapter(actualValidation) : null; + } + + class LegacyAdapter implements ValidationAware { + + private final org.apache.struts2.interceptor.ValidationAware adaptee; + + private LegacyAdapter(org.apache.struts2.interceptor.ValidationAware adaptee) { + this.adaptee = adaptee; + } + + @Override + public void setActionErrors(Collection errorMessages) { + adaptee.setActionErrors(errorMessages); + } + + @Override + public Collection getActionErrors() { + return adaptee.getActionErrors(); + } + + @Override + public void setActionMessages(Collection messages) { + adaptee.setActionMessages(messages); + } + + @Override + public Collection getActionMessages() { + return adaptee.getActionMessages(); + } + + @Override + public void setFieldErrors(Map> errorMap) { + adaptee.setFieldErrors(errorMap); + } + + @Override + public Map> getFieldErrors() { + return adaptee.getFieldErrors(); + } + + @Override + public void addActionError(String anErrorMessage) { + adaptee.addActionError(anErrorMessage); + } + + @Override + public void addActionMessage(String aMessage) { + adaptee.addActionMessage(aMessage); + } + + @Override + public void addFieldError(String fieldName, String errorMessage) { + adaptee.addFieldError(fieldName, errorMessage); + } + + @Override + public boolean hasActionErrors() { + return adaptee.hasActionErrors(); + } + + @Override + public boolean hasActionMessages() { + return adaptee.hasActionMessages(); + } + + @Override + public boolean hasFieldErrors() { + return adaptee.hasFieldErrors(); + } + } } diff --git a/core/src/main/java/com/opensymphony/xwork2/util/DebugUtils.java b/core/src/main/java/com/opensymphony/xwork2/util/DebugUtils.java index 3fdf8b0a7..ff7042b59 100644 --- a/core/src/main/java/com/opensymphony/xwork2/util/DebugUtils.java +++ b/core/src/main/java/com/opensymphony/xwork2/util/DebugUtils.java @@ -19,8 +19,8 @@ package com.opensymphony.xwork2.util; import com.opensymphony.xwork2.TextProvider; -import com.opensymphony.xwork2.interceptor.ValidationAware; import org.apache.logging.log4j.Logger; +import org.apache.struts2.interceptor.ValidationAware; /** * @since 6.5.0 diff --git a/core/src/main/java/com/opensymphony/xwork2/validator/DelegatingValidatorContext.java b/core/src/main/java/com/opensymphony/xwork2/validator/DelegatingValidatorContext.java index bc8c88875..b0b41e719 100644 --- a/core/src/main/java/com/opensymphony/xwork2/validator/DelegatingValidatorContext.java +++ b/core/src/main/java/com/opensymphony/xwork2/validator/DelegatingValidatorContext.java @@ -18,13 +18,23 @@ */ package com.opensymphony.xwork2.validator; -import com.opensymphony.xwork2.*; +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.CompositeTextProvider; +import com.opensymphony.xwork2.LocaleProvider; +import com.opensymphony.xwork2.LocaleProviderFactory; +import com.opensymphony.xwork2.StrutsTextProviderFactory; +import com.opensymphony.xwork2.TextProvider; +import com.opensymphony.xwork2.TextProviderFactory; import com.opensymphony.xwork2.interceptor.ValidationAware; import com.opensymphony.xwork2.util.ValueStack; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; /** * A default implementation of the {@link ValidatorContext} interface. @@ -233,8 +243,8 @@ public class DelegatingValidatorContext implements ValidatorContext { } protected static ValidationAware makeValidationAware(Object object) { - if (object instanceof ValidationAware) { - return (ValidationAware) object; + if (object instanceof org.apache.struts2.interceptor.ValidationAware) { + return ValidationAware.adapt((org.apache.struts2.interceptor.ValidationAware) object); } else { return new LoggingValidationAware(object); } diff --git a/core/src/main/java/org/apache/struts2/interceptor/TokenInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/TokenInterceptor.java index c6859d05b..b67ef6422 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/TokenInterceptor.java +++ b/core/src/main/java/org/apache/struts2/interceptor/TokenInterceptor.java @@ -21,7 +21,6 @@ package org.apache.struts2.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.TextProvider; import com.opensymphony.xwork2.TextProviderFactory; -import com.opensymphony.xwork2.interceptor.ValidationAware; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; import org.apache.logging.log4j.LogManager; diff --git a/plugins/junit/src/main/java/org/apache/struts2/junit/StrutsJUnit4TestCase.java b/plugins/junit/src/main/java/org/apache/struts2/junit/StrutsJUnit4TestCase.java index ee486d6cc..93a08e399 100644 --- a/plugins/junit/src/main/java/org/apache/struts2/junit/StrutsJUnit4TestCase.java +++ b/plugins/junit/src/main/java/org/apache/struts2/junit/StrutsJUnit4TestCase.java @@ -22,7 +22,6 @@ import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionProxy; import com.opensymphony.xwork2.ActionProxyFactory; import com.opensymphony.xwork2.config.Configuration; -import com.opensymphony.xwork2.interceptor.ValidationAware; import com.opensymphony.xwork2.interceptor.annotations.After; import com.opensymphony.xwork2.interceptor.annotations.Before; import org.apache.commons.lang3.StringUtils; @@ -31,6 +30,7 @@ import org.apache.struts2.dispatcher.Dispatcher; import org.apache.struts2.dispatcher.HttpParameters; import org.apache.struts2.dispatcher.mapper.ActionMapper; import org.apache.struts2.dispatcher.mapper.ActionMapping; +import org.apache.struts2.interceptor.ValidationAware; import org.apache.struts2.util.StrutsTestCaseHelper; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.mock.web.MockHttpServletRequest; From a623842bcee720e48c2f142d9854048f39b3ba4a Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Thu, 17 Oct 2024 16:19:33 +1100 Subject: [PATCH 24/33] WW-3714 Deprecate and migrate ActionSupport --- .../opensymphony/xwork2/ActionSupport.java | 339 +--------------- .../org/apache/struts2/ActionSupport.java | 371 ++++++++++++++++++ ...onfigurationProviderOgnlAllowlistTest.java | 3 + 3 files changed, 377 insertions(+), 336 deletions(-) create mode 100644 core/src/main/java/org/apache/struts2/ActionSupport.java diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionSupport.java b/core/src/main/java/com/opensymphony/xwork2/ActionSupport.java index ab1a18099..a775c9bb7 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionSupport.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionSupport.java @@ -18,342 +18,9 @@ */ package com.opensymphony.xwork2; -import com.opensymphony.xwork2.conversion.impl.ConversionData; -import com.opensymphony.xwork2.inject.Container; -import com.opensymphony.xwork2.inject.Inject; -import com.opensymphony.xwork2.interceptor.ValidationAware; -import com.opensymphony.xwork2.util.ValueStack; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.struts2.StrutsConstants; - -import java.io.Serializable; -import java.util.*; - /** - * Provides a default implementation for the most common actions. - * See the documentation for all the interfaces this class implements for more detailed information. + * @deprecated since 6.7.0, use {@link org.apache.struts2.ActionSupport} instead. */ -public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable { - - private static final Logger LOG = LogManager.getLogger(ActionSupport.class); - - private final ValidationAwareSupport validationAware = new ValidationAwareSupport(); - - private transient TextProvider textProvider; - private transient LocaleProvider localeProvider; - - protected Container container; - - @Override - public void setActionErrors(Collection errorMessages) { - validationAware.setActionErrors(errorMessages); - } - - @Override - public Collection getActionErrors() { - return validationAware.getActionErrors(); - } - - @Override - public void setActionMessages(Collection messages) { - validationAware.setActionMessages(messages); - } - - @Override - public Collection getActionMessages() { - return validationAware.getActionMessages(); - } - - @Override - public void setFieldErrors(Map> errorMap) { - validationAware.setFieldErrors(errorMap); - } - - @Override - public Map> getFieldErrors() { - return validationAware.getFieldErrors(); - } - - @Override - public Locale getLocale() { - return getLocaleProvider().getLocale(); - } - - @Override - public boolean isValidLocaleString(String localeStr) { - return getLocaleProvider().isValidLocaleString(localeStr); - } - - @Override - public boolean isValidLocale(Locale locale) { - return getLocaleProvider().isValidLocale(locale); - } - - @Override - public Locale toLocale(String localeStr) { - return getLocaleProvider().toLocale(localeStr); - } - - @Override - public boolean hasKey(String key) { - return getTextProvider().hasKey(key); - } - - @Override - public String getText(String aTextName) { - return getTextProvider().getText(aTextName); - } - - @Override - public String getText(String aTextName, String defaultValue) { - return getTextProvider().getText(aTextName, defaultValue); - } - - @Override - public String getText(String aTextName, String defaultValue, String obj) { - return getTextProvider().getText(aTextName, defaultValue, obj); - } - - @Override - public String getText(String aTextName, List args) { - return getTextProvider().getText(aTextName, args); - } - - @Override - public String getText(String key, String[] args) { - return getTextProvider().getText(key, args); - } - - @Override - public String getText(String aTextName, String defaultValue, List args) { - return getTextProvider().getText(aTextName, defaultValue, args); - } - - @Override - public String getText(String key, String defaultValue, String[] args) { - return getTextProvider().getText(key, defaultValue, args); - } - - @Override - public String getText(String key, String defaultValue, List args, ValueStack stack) { - return getTextProvider().getText(key, defaultValue, args, stack); - } - - @Override - public String getText(String key, String defaultValue, String[] args, ValueStack stack) { - return getTextProvider().getText(key, defaultValue, args, stack); - } - - /** - * Dedicated method to support I10N and conversion errors - * - * @param key message which contains formatting string - * @param expr that should be formatted - * @return formatted expr with format specified by key - */ - public String getFormatted(String key, String expr) { - Map conversionErrors = ActionContext.getContext().getConversionErrors(); - if (conversionErrors.containsKey(expr)) { - String[] vals = (String[]) conversionErrors.get(expr).getValue(); - return vals[0]; - } else { - final ValueStack valueStack = ActionContext.getContext().getValueStack(); - final Object val = valueStack.findValue(expr); - return getText(key, Arrays.asList(val)); - } - } - - @Override - public ResourceBundle getTexts() { - return getTextProvider().getTexts(); - } - - @Override - public ResourceBundle getTexts(String aBundleName) { - return getTextProvider().getTexts(aBundleName); - } - - @Override - public void addActionError(String anErrorMessage) { - validationAware.addActionError(anErrorMessage); - } - - @Override - public void addActionMessage(String aMessage) { - validationAware.addActionMessage(aMessage); - } - - @Override - public void addFieldError(String fieldName, String errorMessage) { - validationAware.addFieldError(fieldName, errorMessage); - } - - public String input() throws Exception { - return INPUT; - } - - /** - * A default implementation that does nothing an returns "success". - * - *

    - * Subclasses should override this method to provide their business logic. - *

    - * - *

    - * See also {@link com.opensymphony.xwork2.Action#execute()}. - *

    - * - * @return returns {@link #SUCCESS} - * @throws Exception can be thrown by subclasses. - */ - @Override - public String execute() throws Exception { - return SUCCESS; - } - - @Override - public boolean hasActionErrors() { - return validationAware.hasActionErrors(); - } - - @Override - public boolean hasActionMessages() { - return validationAware.hasActionMessages(); - } - - @Override - public boolean hasErrors() { - return validationAware.hasErrors(); - } - - @Override - public boolean hasFieldErrors() { - return validationAware.hasFieldErrors(); - } - - /** - * Clears field errors. Useful for Continuations and other situations - * where you might want to clear parts of the state on the same action. - */ - public void clearFieldErrors() { - validationAware.clearFieldErrors(); - } - - /** - * Clears action errors. Useful for Continuations and other situations - * where you might want to clear parts of the state on the same action. - */ - public void clearActionErrors() { - validationAware.clearActionErrors(); - } - - /** - * Clears messages. Useful for Continuations and other situations - * where you might want to clear parts of the state on the same action. - */ - public void clearMessages() { - validationAware.clearMessages(); - } - - /** - * Clears all errors. Useful for Continuations and other situations - * where you might want to clear parts of the state on the same action. - */ - public void clearErrors() { - validationAware.clearErrors(); - } - - /** - * Clears all errors and messages. Useful for Continuations and other situations - * where you might want to clear parts of the state on the same action. - */ - public void clearErrorsAndMessages() { - validationAware.clearErrorsAndMessages(); - } - - /** - * A default implementation that validates nothing. - * Subclasses should override this method to provide validations. - */ - @Override - public void validate() { - // A default implementation that validates nothing - } - - @Override - public Object clone() throws CloneNotSupportedException { - return super.clone(); - } - - /** - * - * Stops the action invocation immediately (by throwing a PauseException) and causes the action invocation to return - * the specified result, such as {@link #SUCCESS}, {@link #INPUT}, etc. - * - *

    - * The next time this action is invoked (and using the same continuation ID), the method will resume immediately - * after where this method was called, with the entire call stack in the execute method restored. - *

    - * - *

    - * Note: this method can only be called within the {@link #execute()} method. - *

    - * - * - * - * @param result the result to return - the same type of return value in the {@link #execute()} method. - */ - public void pause(String result) { - } - - /** - * If called first time it will create {@link com.opensymphony.xwork2.TextProviderFactory}, - * inject dependency (if {@link com.opensymphony.xwork2.inject.Container} is accesible) into in, - * then will create new {@link com.opensymphony.xwork2.TextProvider} and store it in a field - * for future references and at the returns reference to that field - * - * @return reference to field with TextProvider - */ - protected TextProvider getTextProvider() { - if (textProvider == null) { - final TextProviderFactory tpf = getContainer().getInstance(TextProviderFactory.class); - textProvider = tpf.createInstance(getClass()); - } - return textProvider; - } - - protected LocaleProvider getLocaleProvider() { - if (localeProvider == null) { - final LocaleProviderFactory localeProviderFactory = getContainer().getInstance(LocaleProviderFactory.class); - localeProvider = localeProviderFactory.createLocaleProvider(); - } - return localeProvider; - } - - /** - * TODO: This a temporary solution, maybe we should consider stop injecting container into beans - */ - protected Container getContainer() { - if (container == null) { - container = ActionContext.getContext().getContainer(); - if (container != null) { - boolean devMode = Boolean.parseBoolean(container.getInstance(String.class, StrutsConstants.STRUTS_DEVMODE)); - if (devMode) { - LOG.warn("Container is null, action was created manually? Fallback to ActionContext"); - } else { - LOG.debug("Container is null, action was created manually? Fallback to ActionContext"); - } - } else { - LOG.warn("Container is null, action was created out of ActionContext scope?!?"); - } - } - return container; - } - - @Inject - public void setContainer(Container container) { - this.container = container; - } - +@Deprecated +public class ActionSupport extends org.apache.struts2.ActionSupport { } diff --git a/core/src/main/java/org/apache/struts2/ActionSupport.java b/core/src/main/java/org/apache/struts2/ActionSupport.java new file mode 100644 index 000000000..3f2715731 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/ActionSupport.java @@ -0,0 +1,371 @@ +/* + * 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; + +import com.opensymphony.xwork2.Action; +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.LocaleProvider; +import com.opensymphony.xwork2.LocaleProviderFactory; +import com.opensymphony.xwork2.TextProvider; +import com.opensymphony.xwork2.TextProviderFactory; +import com.opensymphony.xwork2.Validateable; +import com.opensymphony.xwork2.ValidationAwareSupport; +import com.opensymphony.xwork2.conversion.impl.ConversionData; +import com.opensymphony.xwork2.inject.Container; +import com.opensymphony.xwork2.inject.Inject; +import com.opensymphony.xwork2.interceptor.ValidationAware; +import com.opensymphony.xwork2.util.ValueStack; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; + +/** + * Provides a default implementation for the most common actions. + * See the documentation for all the interfaces this class implements for more detailed information. + */ +public class ActionSupport implements com.opensymphony.xwork2.Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable { + + private static final Logger LOG = LogManager.getLogger(ActionSupport.class); + + private final ValidationAwareSupport validationAware = new ValidationAwareSupport(); + + private transient TextProvider textProvider; + private transient LocaleProvider localeProvider; + + protected Container container; + + @Override + public void setActionErrors(Collection errorMessages) { + validationAware.setActionErrors(errorMessages); + } + + @Override + public Collection getActionErrors() { + return validationAware.getActionErrors(); + } + + @Override + public void setActionMessages(Collection messages) { + validationAware.setActionMessages(messages); + } + + @Override + public Collection getActionMessages() { + return validationAware.getActionMessages(); + } + + @Override + public void setFieldErrors(Map> errorMap) { + validationAware.setFieldErrors(errorMap); + } + + @Override + public Map> getFieldErrors() { + return validationAware.getFieldErrors(); + } + + @Override + public Locale getLocale() { + return getLocaleProvider().getLocale(); + } + + @Override + public boolean isValidLocaleString(String localeStr) { + return getLocaleProvider().isValidLocaleString(localeStr); + } + + @Override + public boolean isValidLocale(Locale locale) { + return getLocaleProvider().isValidLocale(locale); + } + + @Override + public Locale toLocale(String localeStr) { + return getLocaleProvider().toLocale(localeStr); + } + + @Override + public boolean hasKey(String key) { + return getTextProvider().hasKey(key); + } + + @Override + public String getText(String aTextName) { + return getTextProvider().getText(aTextName); + } + + @Override + public String getText(String aTextName, String defaultValue) { + return getTextProvider().getText(aTextName, defaultValue); + } + + @Override + public String getText(String aTextName, String defaultValue, String obj) { + return getTextProvider().getText(aTextName, defaultValue, obj); + } + + @Override + public String getText(String aTextName, List args) { + return getTextProvider().getText(aTextName, args); + } + + @Override + public String getText(String key, String[] args) { + return getTextProvider().getText(key, args); + } + + @Override + public String getText(String aTextName, String defaultValue, List args) { + return getTextProvider().getText(aTextName, defaultValue, args); + } + + @Override + public String getText(String key, String defaultValue, String[] args) { + return getTextProvider().getText(key, defaultValue, args); + } + + @Override + public String getText(String key, String defaultValue, List args, ValueStack stack) { + return getTextProvider().getText(key, defaultValue, args, stack); + } + + @Override + public String getText(String key, String defaultValue, String[] args, ValueStack stack) { + return getTextProvider().getText(key, defaultValue, args, stack); + } + + /** + * Dedicated method to support I10N and conversion errors + * + * @param key message which contains formatting string + * @param expr that should be formatted + * @return formatted expr with format specified by key + */ + public String getFormatted(String key, String expr) { + Map conversionErrors = com.opensymphony.xwork2.ActionContext.getContext().getConversionErrors(); + if (conversionErrors.containsKey(expr)) { + String[] vals = (String[]) conversionErrors.get(expr).getValue(); + return vals[0]; + } else { + final ValueStack valueStack = com.opensymphony.xwork2.ActionContext.getContext().getValueStack(); + final Object val = valueStack.findValue(expr); + return getText(key, Arrays.asList(val)); + } + } + + @Override + public ResourceBundle getTexts() { + return getTextProvider().getTexts(); + } + + @Override + public ResourceBundle getTexts(String aBundleName) { + return getTextProvider().getTexts(aBundleName); + } + + @Override + public void addActionError(String anErrorMessage) { + validationAware.addActionError(anErrorMessage); + } + + @Override + public void addActionMessage(String aMessage) { + validationAware.addActionMessage(aMessage); + } + + @Override + public void addFieldError(String fieldName, String errorMessage) { + validationAware.addFieldError(fieldName, errorMessage); + } + + public String input() throws Exception { + return INPUT; + } + + /** + * A default implementation that does nothing an returns "success". + * + *

    + * Subclasses should override this method to provide their business logic. + *

    + * + *

    + * See also {@link Action#execute()}. + *

    + * + * @return returns {@link #SUCCESS} + * @throws Exception can be thrown by subclasses. + */ + @Override + public String execute() throws Exception { + return SUCCESS; + } + + @Override + public boolean hasActionErrors() { + return validationAware.hasActionErrors(); + } + + @Override + public boolean hasActionMessages() { + return validationAware.hasActionMessages(); + } + + @Override + public boolean hasErrors() { + return validationAware.hasErrors(); + } + + @Override + public boolean hasFieldErrors() { + return validationAware.hasFieldErrors(); + } + + /** + * Clears field errors. Useful for Continuations and other situations + * where you might want to clear parts of the state on the same action. + */ + public void clearFieldErrors() { + validationAware.clearFieldErrors(); + } + + /** + * Clears action errors. Useful for Continuations and other situations + * where you might want to clear parts of the state on the same action. + */ + public void clearActionErrors() { + validationAware.clearActionErrors(); + } + + /** + * Clears messages. Useful for Continuations and other situations + * where you might want to clear parts of the state on the same action. + */ + public void clearMessages() { + validationAware.clearMessages(); + } + + /** + * Clears all errors. Useful for Continuations and other situations + * where you might want to clear parts of the state on the same action. + */ + public void clearErrors() { + validationAware.clearErrors(); + } + + /** + * Clears all errors and messages. Useful for Continuations and other situations + * where you might want to clear parts of the state on the same action. + */ + public void clearErrorsAndMessages() { + validationAware.clearErrorsAndMessages(); + } + + /** + * A default implementation that validates nothing. + * Subclasses should override this method to provide validations. + */ + @Override + public void validate() { + // A default implementation that validates nothing + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + /** + * + * Stops the action invocation immediately (by throwing a PauseException) and causes the action invocation to return + * the specified result, such as {@link #SUCCESS}, {@link #INPUT}, etc. + * + *

    + * The next time this action is invoked (and using the same continuation ID), the method will resume immediately + * after where this method was called, with the entire call stack in the execute method restored. + *

    + * + *

    + * Note: this method can only be called within the {@link #execute()} method. + *

    + * + * + * + * @param result the result to return - the same type of return value in the {@link #execute()} method. + */ + public void pause(String result) { + } + + /** + * If called first time it will create {@link TextProviderFactory}, + * inject dependency (if {@link Container} is accesible) into in, + * then will create new {@link TextProvider} and store it in a field + * for future references and at the returns reference to that field + * + * @return reference to field with TextProvider + */ + protected TextProvider getTextProvider() { + if (textProvider == null) { + final TextProviderFactory tpf = getContainer().getInstance(TextProviderFactory.class); + textProvider = tpf.createInstance(getClass()); + } + return textProvider; + } + + protected LocaleProvider getLocaleProvider() { + if (localeProvider == null) { + final LocaleProviderFactory localeProviderFactory = getContainer().getInstance(LocaleProviderFactory.class); + localeProvider = localeProviderFactory.createLocaleProvider(); + } + return localeProvider; + } + + /** + * TODO: This a temporary solution, maybe we should consider stop injecting container into beans + */ + protected Container getContainer() { + if (container == null) { + container = ActionContext.getContext().getContainer(); + if (container != null) { + boolean devMode = Boolean.parseBoolean(container.getInstance(String.class, StrutsConstants.STRUTS_DEVMODE)); + if (devMode) { + LOG.warn("Container is null, action was created manually? Fallback to ActionContext"); + } else { + LOG.debug("Container is null, action was created manually? Fallback to ActionContext"); + } + } else { + LOG.warn("Container is null, action was created out of ActionContext scope?!?"); + } + } + return container; + } + + @Inject + public void setContainer(Container container) { + this.container = container; + } + +} diff --git a/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java b/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java index 2379216bc..b3f65973d 100644 --- a/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java +++ b/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java @@ -50,6 +50,7 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase Class.forName("java.io.Serializable"), Class.forName("com.opensymphony.xwork2.mock.MockResult"), Class.forName("com.opensymphony.xwork2.interceptor.ConditionalInterceptor"), + Class.forName("org.apache.struts2.ActionSupport"), Class.forName("com.opensymphony.xwork2.ActionSupport"), Class.forName("com.opensymphony.xwork2.ActionChainResult"), Class.forName("com.opensymphony.xwork2.TextProvider"), @@ -82,6 +83,7 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase Class.forName("java.io.Serializable"), Class.forName("com.opensymphony.xwork2.mock.MockResult"), Class.forName("com.opensymphony.xwork2.interceptor.ConditionalInterceptor"), + Class.forName("org.apache.struts2.ActionSupport"), Class.forName("com.opensymphony.xwork2.ActionSupport"), Class.forName("com.opensymphony.xwork2.TextProvider"), Class.forName("com.opensymphony.xwork2.interceptor.Interceptor"), @@ -111,6 +113,7 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase Class.forName("com.opensymphony.xwork2.LocaleProvider"), Class.forName("java.io.Serializable"), Class.forName("com.opensymphony.xwork2.interceptor.ConditionalInterceptor"), + Class.forName("org.apache.struts2.ActionSupport"), Class.forName("com.opensymphony.xwork2.ActionSupport"), Class.forName("com.opensymphony.xwork2.ActionChainResult"), Class.forName("com.opensymphony.xwork2.TextProvider"), From 9e23fbe665540a050b64975c690196dd291339ac Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Thu, 17 Oct 2024 16:26:01 +1100 Subject: [PATCH 25/33] WW-3714 Deprecate and migrate AbstractInterceptor and MethodFilterInterceptor --- .../interceptor/AbstractInterceptor.java | 32 +--- .../interceptor/MethodFilterInterceptor.java | 45 +++--- .../MethodFilterInterceptorUtil.java | 128 +-------------- .../interceptor/AbstractInterceptor.java | 61 ++++++++ .../interceptor/MethodFilterInterceptor.java | 123 +++++++++++++++ .../MethodFilterInterceptorUtil.java | 148 ++++++++++++++++++ ...onfigurationProviderOgnlAllowlistTest.java | 3 + 7 files changed, 369 insertions(+), 171 deletions(-) create mode 100644 core/src/main/java/org/apache/struts2/interceptor/AbstractInterceptor.java create mode 100644 core/src/main/java/org/apache/struts2/interceptor/MethodFilterInterceptor.java create mode 100644 core/src/main/java/org/apache/struts2/interceptor/MethodFilterInterceptorUtil.java diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/AbstractInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/AbstractInterceptor.java index 21e459c29..69c667462 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/AbstractInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/AbstractInterceptor.java @@ -21,41 +21,23 @@ package com.opensymphony.xwork2.interceptor; import com.opensymphony.xwork2.ActionInvocation; /** - * Provides default implementations of optional lifecycle methods + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.AbstractInterceptor} instead. */ -public abstract class AbstractInterceptor implements ConditionalInterceptor { - - private boolean disabled; - - /** - * Does nothing - */ - public void init() { - } - - /** - * Does nothing - */ - public void destroy() { - } +@Deprecated +public abstract class AbstractInterceptor extends org.apache.struts2.interceptor.AbstractInterceptor implements ConditionalInterceptor { /** * Override to handle interception */ public abstract String intercept(ActionInvocation invocation) throws Exception; - /** - * Allows to skip executing a given interceptor, just define {@code true} - * or use other way to override interceptor's parameters, see - * docs. - * @param disable if set to true, execution of a given interceptor will be skipped. - */ - public void setDisabled(String disable) { - this.disabled = Boolean.parseBoolean(disable); + @Override + public String intercept(org.apache.struts2.ActionInvocation invocation) throws Exception { + return intercept(ActionInvocation.adapt(invocation)); } @Override public boolean shouldIntercept(ActionInvocation invocation) { - return !this.disabled; + return shouldIntercept((org.apache.struts2.ActionInvocation) invocation); } } diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptor.java index e96951cfa..bcce3da12 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptor.java @@ -31,56 +31,59 @@ import java.util.Set; * *

    * MethodFilterInterceptor is an abstract Interceptor used as - * a base class for interceptors that will filter execution based on method + * a base class for interceptors that will filter execution based on method * names according to specified included/excluded method lists. - * + * *

    - * + * * Settable parameters are as follows: - * + * *
      *
    • excludeMethods - method names to be excluded from interceptor processing
    • *
    • includeMethods - method names to be included in interceptor processing
    • *
    - * + * *

    - * - * NOTE: If method name are available in both includeMethods and - * excludeMethods, it will be considered as an included method: + * + * NOTE: If method name are available in both includeMethods and + * excludeMethods, it will be considered as an included method: * includeMethods takes precedence over excludeMethods. - * + * *

    - * + * * Interceptors that extends this capability include: - * + * *
      *
    • TokenInterceptor
    • *
    • TokenSessionStoreInterceptor
    • *
    • DefaultWorkflowInterceptor
    • *
    • ValidationInterceptor
    • *
    - * + * * - * + * * @author Alexandru Popescu * @author Rainer Hermanns - * + * * @see org.apache.struts2.interceptor.TokenInterceptor * @see org.apache.struts2.interceptor.TokenSessionStoreInterceptor * @see com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor * @see com.opensymphony.xwork2.validator.ValidationInterceptor + * + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.MethodFilterInterceptor} instead. */ +@Deprecated public abstract class MethodFilterInterceptor extends AbstractInterceptor { private static final Logger LOG = LogManager.getLogger(MethodFilterInterceptor.class); - + protected Set excludeMethods = Collections.emptySet(); protected Set includeMethods = Collections.emptySet(); public void setExcludeMethods(String excludeMethods) { this.excludeMethods = TextParseUtil.commaDelimitedStringToSet(excludeMethods); } - + public Set getExcludeMethodsSet() { return excludeMethods; } @@ -88,7 +91,7 @@ public abstract class MethodFilterInterceptor extends AbstractInterceptor { public void setIncludeMethods(String includeMethods) { this.includeMethods = TextParseUtil.commaDelimitedStringToSet(includeMethods); } - + public Set getIncludeMethodsSet() { return includeMethods; } @@ -97,7 +100,7 @@ public abstract class MethodFilterInterceptor extends AbstractInterceptor { public String intercept(ActionInvocation invocation) throws Exception { if (applyInterceptor(invocation)) { return doIntercept(invocation); - } + } return invocation.invoke(); } @@ -110,14 +113,14 @@ public abstract class MethodFilterInterceptor extends AbstractInterceptor { } return applyMethod; } - + /** * Subclasses must override to implement the interceptor logic. - * + * * @param invocation the action invocation * @return the result of invocation * @throws Exception in case of any errors */ protected abstract String doIntercept(ActionInvocation invocation) throws Exception; - + } diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptorUtil.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptorUtil.java index beacb8784..7e1a2c434 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptorUtil.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptorUtil.java @@ -18,131 +18,9 @@ */ package com.opensymphony.xwork2.interceptor; -import com.opensymphony.xwork2.util.TextParseUtil; -import com.opensymphony.xwork2.util.WildcardHelper; - -import java.util.HashMap; -import java.util.Set; - /** - * Utility class contains common methods used by - * {@link com.opensymphony.xwork2.interceptor.MethodFilterInterceptor}. - * - * @author tm_jee + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.MethodFilterInterceptorUtil} instead. */ -public class MethodFilterInterceptorUtil { - - /** - * Static method to decide if the specified method should be - * apply (not filtered) depending on the set of excludeMethods and - * includeMethods. - * - *
      - *
    • - * includeMethods takes precedence over excludeMethods - *
    • - *
    - * Note: Supports wildcard listings in includeMethods/excludeMethods - * - * @param excludeMethods list of methods to exclude. - * @param includeMethods list of methods to include. - * @param method the specified method to check - * @return true if the method should be applied. - */ - public static boolean applyMethod(Set excludeMethods, Set includeMethods, String method) { - - // quick check to see if any actual pattern matching is needed - boolean needsPatternMatch = false; - for (String includeMethod : includeMethods) { - if (!"*".equals(includeMethod) && includeMethod.contains("*")) { - needsPatternMatch = true; - break; - } - } - - for (String excludeMethod : excludeMethods) { - if (!"*".equals(excludeMethod) && excludeMethod.contains("*")) { - needsPatternMatch = true; - break; - } - } - - // this section will try to honor the original logic, while - // still allowing for wildcards later - if (!needsPatternMatch && (includeMethods.contains("*") || includeMethods.size() == 0) ) { - if (excludeMethods != null - && excludeMethods.contains(method) - && !includeMethods.contains(method) ) { - return false; - } - } - - // test the methods using pattern matching - WildcardHelper wildcard = new WildcardHelper(); - String methodCopy ; - if (method == null ) { // no method specified - methodCopy = ""; - } - else { - methodCopy = new String(method); - } - for (String pattern : includeMethods) { - if (pattern.contains("*")) { - int[] compiledPattern = wildcard.compilePattern(pattern); - HashMap matchedPatterns = new HashMap<>(); - boolean matches = wildcard.match(matchedPatterns, methodCopy, compiledPattern); - if (matches) { - return true; // run it, includeMethods takes precedence - } - } - else { - if (pattern.equals(methodCopy)) { - return true; // run it, includeMethods takes precedence - } - } - } - if (excludeMethods.contains("*") ) { - return false; - } - - // CHECK ME: Previous implementation used include method - for ( String pattern : excludeMethods) { - if (pattern.contains("*")) { - int[] compiledPattern = wildcard.compilePattern(pattern); - HashMap matchedPatterns = new HashMap<>(); - boolean matches = wildcard.match(matchedPatterns, methodCopy, compiledPattern); - if (matches) { - // if found, and wasn't included earlier, don't run it - return false; - } - } - else { - if (pattern.equals(methodCopy)) { - // if found, and wasn't included earlier, don't run it - return false; - } - } - } - - - // default fall-back from before changes - return includeMethods.size() == 0 || includeMethods.contains(method) || includeMethods.contains("*"); - } - - /** - * Same as {@link #applyMethod(Set, Set, String)}, except that excludeMethods - * and includeMethods are supplied as comma separated string. - * - * @param excludeMethods comma seperated string of methods to exclude. - * @param includeMethods comma seperated string of methods to include. - * @param method the specified method to check - * @return true if the method should be applied. - */ - public static boolean applyMethod(String excludeMethods, String includeMethods, String method) { - Set includeMethodsSet = TextParseUtil.commaDelimitedStringToSet(includeMethods == null? "" : includeMethods); - Set excludeMethodsSet = TextParseUtil.commaDelimitedStringToSet(excludeMethods == null? "" : excludeMethods); - - return applyMethod(excludeMethodsSet, includeMethodsSet, method); - } - +@Deprecated +public class MethodFilterInterceptorUtil extends org.apache.struts2.interceptor.MethodFilterInterceptorUtil { } diff --git a/core/src/main/java/org/apache/struts2/interceptor/AbstractInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/AbstractInterceptor.java new file mode 100644 index 000000000..ddb48a0d7 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/AbstractInterceptor.java @@ -0,0 +1,61 @@ +/* + * 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.interceptor; + +import org.apache.struts2.ActionInvocation; + +/** + * Provides default implementations of optional lifecycle methods + */ +public abstract class AbstractInterceptor implements ConditionalInterceptor { + + private boolean disabled; + + /** + * Does nothing + */ + public void init() { + } + + /** + * Does nothing + */ + public void destroy() { + } + + /** + * Override to handle interception + */ + public abstract String intercept(ActionInvocation invocation) throws Exception; + + /** + * Allows to skip executing a given interceptor, just define {@code true} + * or use other way to override interceptor's parameters, see + * docs. + * @param disable if set to true, execution of a given interceptor will be skipped. + */ + public void setDisabled(String disable) { + this.disabled = Boolean.parseBoolean(disable); + } + + @Override + public boolean shouldIntercept(ActionInvocation invocation) { + return !this.disabled; + } +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/MethodFilterInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/MethodFilterInterceptor.java new file mode 100644 index 000000000..1ffe68261 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/MethodFilterInterceptor.java @@ -0,0 +1,123 @@ +/* + * 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.interceptor; + +import com.opensymphony.xwork2.util.TextParseUtil; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.struts2.ActionInvocation; + +import java.util.Collections; +import java.util.Set; + +/** + * + * + *

    + * MethodFilterInterceptor is an abstract Interceptor used as + * a base class for interceptors that will filter execution based on method + * names according to specified included/excluded method lists. + * + *

    + * + * Settable parameters are as follows: + * + *
      + *
    • excludeMethods - method names to be excluded from interceptor processing
    • + *
    • includeMethods - method names to be included in interceptor processing
    • + *
    + * + *

    + * + * NOTE: If method name are available in both includeMethods and + * excludeMethods, it will be considered as an included method: + * includeMethods takes precedence over excludeMethods. + * + *

    + * + * Interceptors that extends this capability include: + * + *
      + *
    • TokenInterceptor
    • + *
    • TokenSessionStoreInterceptor
    • + *
    • DefaultWorkflowInterceptor
    • + *
    • ValidationInterceptor
    • + *
    + * + * + * + * @author Alexandru Popescu + * @author Rainer Hermanns + * + * @see TokenInterceptor + * @see TokenSessionStoreInterceptor + * @see com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor + * @see com.opensymphony.xwork2.validator.ValidationInterceptor + */ +public abstract class MethodFilterInterceptor extends AbstractInterceptor { + + private static final Logger LOG = LogManager.getLogger(MethodFilterInterceptor.class); + + protected Set excludeMethods = Collections.emptySet(); + protected Set includeMethods = Collections.emptySet(); + + public void setExcludeMethods(String excludeMethods) { + this.excludeMethods = TextParseUtil.commaDelimitedStringToSet(excludeMethods); + } + + public Set getExcludeMethodsSet() { + return excludeMethods; + } + + public void setIncludeMethods(String includeMethods) { + this.includeMethods = TextParseUtil.commaDelimitedStringToSet(includeMethods); + } + + public Set getIncludeMethodsSet() { + return includeMethods; + } + + @Override + public String intercept(ActionInvocation invocation) throws Exception { + if (applyInterceptor(invocation)) { + return doIntercept(invocation); + } + return invocation.invoke(); + } + + protected boolean applyInterceptor(ActionInvocation invocation) { + String method = invocation.getProxy().getMethod(); + // ValidationInterceptor + boolean applyMethod = MethodFilterInterceptorUtil.applyMethod(excludeMethods, includeMethods, method); + if (!applyMethod) { + LOG.debug("Skipping Interceptor... Method [{}] found in exclude list.", method); + } + return applyMethod; + } + + /** + * Subclasses must override to implement the interceptor logic. + * + * @param invocation the action invocation + * @return the result of invocation + * @throws Exception in case of any errors + */ + protected abstract String doIntercept(ActionInvocation invocation) throws Exception; + +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/MethodFilterInterceptorUtil.java b/core/src/main/java/org/apache/struts2/interceptor/MethodFilterInterceptorUtil.java new file mode 100644 index 000000000..2a43ba2ff --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/MethodFilterInterceptorUtil.java @@ -0,0 +1,148 @@ +/* + * 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.interceptor; + +import com.opensymphony.xwork2.util.TextParseUtil; +import com.opensymphony.xwork2.util.WildcardHelper; + +import java.util.HashMap; +import java.util.Set; + +/** + * Utility class contains common methods used by + * {@link MethodFilterInterceptor}. + * + * @author tm_jee + */ +public class MethodFilterInterceptorUtil { + + /** + * Static method to decide if the specified method should be + * apply (not filtered) depending on the set of excludeMethods and + * includeMethods. + * + *
      + *
    • + * includeMethods takes precedence over excludeMethods + *
    • + *
    + * Note: Supports wildcard listings in includeMethods/excludeMethods + * + * @param excludeMethods list of methods to exclude. + * @param includeMethods list of methods to include. + * @param method the specified method to check + * @return true if the method should be applied. + */ + public static boolean applyMethod(Set excludeMethods, Set includeMethods, String method) { + + // quick check to see if any actual pattern matching is needed + boolean needsPatternMatch = false; + for (String includeMethod : includeMethods) { + if (!"*".equals(includeMethod) && includeMethod.contains("*")) { + needsPatternMatch = true; + break; + } + } + + for (String excludeMethod : excludeMethods) { + if (!"*".equals(excludeMethod) && excludeMethod.contains("*")) { + needsPatternMatch = true; + break; + } + } + + // this section will try to honor the original logic, while + // still allowing for wildcards later + if (!needsPatternMatch && (includeMethods.contains("*") || includeMethods.size() == 0) ) { + if (excludeMethods != null + && excludeMethods.contains(method) + && !includeMethods.contains(method) ) { + return false; + } + } + + // test the methods using pattern matching + WildcardHelper wildcard = new WildcardHelper(); + String methodCopy ; + if (method == null ) { // no method specified + methodCopy = ""; + } + else { + methodCopy = new String(method); + } + for (String pattern : includeMethods) { + if (pattern.contains("*")) { + int[] compiledPattern = wildcard.compilePattern(pattern); + HashMap matchedPatterns = new HashMap<>(); + boolean matches = wildcard.match(matchedPatterns, methodCopy, compiledPattern); + if (matches) { + return true; // run it, includeMethods takes precedence + } + } + else { + if (pattern.equals(methodCopy)) { + return true; // run it, includeMethods takes precedence + } + } + } + if (excludeMethods.contains("*") ) { + return false; + } + + // CHECK ME: Previous implementation used include method + for ( String pattern : excludeMethods) { + if (pattern.contains("*")) { + int[] compiledPattern = wildcard.compilePattern(pattern); + HashMap matchedPatterns = new HashMap<>(); + boolean matches = wildcard.match(matchedPatterns, methodCopy, compiledPattern); + if (matches) { + // if found, and wasn't included earlier, don't run it + return false; + } + } + else { + if (pattern.equals(methodCopy)) { + // if found, and wasn't included earlier, don't run it + return false; + } + } + } + + + // default fall-back from before changes + return includeMethods.size() == 0 || includeMethods.contains(method) || includeMethods.contains("*"); + } + + /** + * Same as {@link #applyMethod(Set, Set, String)}, except that excludeMethods + * and includeMethods are supplied as comma separated string. + * + * @param excludeMethods comma seperated string of methods to exclude. + * @param includeMethods comma seperated string of methods to include. + * @param method the specified method to check + * @return true if the method should be applied. + */ + public static boolean applyMethod(String excludeMethods, String includeMethods, String method) { + Set includeMethodsSet = TextParseUtil.commaDelimitedStringToSet(includeMethods == null? "" : includeMethods); + Set excludeMethodsSet = TextParseUtil.commaDelimitedStringToSet(excludeMethods == null? "" : excludeMethods); + + return applyMethod(excludeMethodsSet, includeMethodsSet, method); + } + +} diff --git a/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java b/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java index b3f65973d..51d2f96f2 100644 --- a/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java +++ b/core/src/test/java/com/opensymphony/xwork2/config/providers/ConfigurationProviderOgnlAllowlistTest.java @@ -61,6 +61,7 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase Class.forName("com.opensymphony.xwork2.mock.MockInterceptor"), Class.forName("com.opensymphony.xwork2.Action"), Class.forName("com.opensymphony.xwork2.interceptor.AbstractInterceptor"), + Class.forName("org.apache.struts2.interceptor.AbstractInterceptor"), Class.forName("com.opensymphony.xwork2.Result"), Class.forName("com.opensymphony.xwork2.SimpleAction"), Class.forName("org.apache.struts2.interceptor.Interceptor"), @@ -92,6 +93,7 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase Class.forName("com.opensymphony.xwork2.mock.MockInterceptor"), Class.forName("com.opensymphony.xwork2.Action"), Class.forName("com.opensymphony.xwork2.interceptor.AbstractInterceptor"), + Class.forName("org.apache.struts2.interceptor.AbstractInterceptor"), Class.forName("com.opensymphony.xwork2.Result"), Class.forName("com.opensymphony.xwork2.SimpleAction"), Class.forName("org.apache.struts2.interceptor.Interceptor"), @@ -123,6 +125,7 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase Class.forName("com.opensymphony.xwork2.Validateable"), Class.forName("com.opensymphony.xwork2.Action"), Class.forName("com.opensymphony.xwork2.interceptor.AbstractInterceptor"), + Class.forName("org.apache.struts2.interceptor.AbstractInterceptor"), Class.forName("com.opensymphony.xwork2.Result"), Class.forName("org.apache.struts2.interceptor.Interceptor"), Class.forName("org.apache.struts2.interceptor.ConditionalInterceptor"), From f95f9a7cd3ff0710cd7d4e0d2054fbf562fbf7e9 Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Tue, 22 Oct 2024 10:57:57 +1100 Subject: [PATCH 26/33] WW-3714 Add alternative constructors in InterceptorMapping --- .../xwork2/config/entities/InterceptorMapping.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/opensymphony/xwork2/config/entities/InterceptorMapping.java b/core/src/main/java/com/opensymphony/xwork2/config/entities/InterceptorMapping.java index 260ae325b..6625bc7a1 100644 --- a/core/src/main/java/com/opensymphony/xwork2/config/entities/InterceptorMapping.java +++ b/core/src/main/java/com/opensymphony/xwork2/config/entities/InterceptorMapping.java @@ -36,8 +36,16 @@ public class InterceptorMapping implements Serializable { private Interceptor interceptor; private final Map params; + public InterceptorMapping(String name, org.apache.struts2.interceptor.Interceptor interceptor) { + this(name, Interceptor.adapt(interceptor)); + } + + public InterceptorMapping(String name, org.apache.struts2.interceptor.Interceptor interceptor, Map params) { + this(name, Interceptor.adapt(interceptor), params); + } + public InterceptorMapping(String name, Interceptor interceptor) { - this(name, interceptor, new HashMap()); + this(name, interceptor, new HashMap<>()); } public InterceptorMapping(String name, Interceptor interceptor, Map params) { From deb6c09bce253f25f8d47a5eac2552b05ba38d71 Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Tue, 22 Oct 2024 10:58:50 +1100 Subject: [PATCH 27/33] WW-3714 Replace deprecated APIs in new ActionSupport --- .../java/com/opensymphony/xwork2/ActionSupport.java | 4 +++- .../main/java/org/apache/struts2/ActionSupport.java | 11 ++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionSupport.java b/core/src/main/java/com/opensymphony/xwork2/ActionSupport.java index a775c9bb7..be9cc29ca 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ActionSupport.java +++ b/core/src/main/java/com/opensymphony/xwork2/ActionSupport.java @@ -18,9 +18,11 @@ */ package com.opensymphony.xwork2; +import com.opensymphony.xwork2.interceptor.ValidationAware; + /** * @deprecated since 6.7.0, use {@link org.apache.struts2.ActionSupport} instead. */ @Deprecated -public class ActionSupport extends org.apache.struts2.ActionSupport { +public class ActionSupport extends org.apache.struts2.ActionSupport implements Action, Validateable, ValidationAware { } diff --git a/core/src/main/java/org/apache/struts2/ActionSupport.java b/core/src/main/java/org/apache/struts2/ActionSupport.java index 3f2715731..04c513f3a 100644 --- a/core/src/main/java/org/apache/struts2/ActionSupport.java +++ b/core/src/main/java/org/apache/struts2/ActionSupport.java @@ -18,21 +18,18 @@ */ package org.apache.struts2; -import com.opensymphony.xwork2.Action; -import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.LocaleProvider; import com.opensymphony.xwork2.LocaleProviderFactory; import com.opensymphony.xwork2.TextProvider; import com.opensymphony.xwork2.TextProviderFactory; -import com.opensymphony.xwork2.Validateable; import com.opensymphony.xwork2.ValidationAwareSupport; import com.opensymphony.xwork2.conversion.impl.ConversionData; import com.opensymphony.xwork2.inject.Container; import com.opensymphony.xwork2.inject.Inject; -import com.opensymphony.xwork2.interceptor.ValidationAware; import com.opensymphony.xwork2.util.ValueStack; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.struts2.interceptor.ValidationAware; import java.io.Serializable; import java.util.Arrays; @@ -46,7 +43,7 @@ import java.util.ResourceBundle; * Provides a default implementation for the most common actions. * See the documentation for all the interfaces this class implements for more detailed information. */ -public class ActionSupport implements com.opensymphony.xwork2.Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable { +public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable { private static final Logger LOG = LogManager.getLogger(ActionSupport.class); @@ -165,12 +162,12 @@ public class ActionSupport implements com.opensymphony.xwork2.Action, Validateab * @return formatted expr with format specified by key */ public String getFormatted(String key, String expr) { - Map conversionErrors = com.opensymphony.xwork2.ActionContext.getContext().getConversionErrors(); + Map conversionErrors = ActionContext.getContext().getConversionErrors(); if (conversionErrors.containsKey(expr)) { String[] vals = (String[]) conversionErrors.get(expr).getValue(); return vals[0]; } else { - final ValueStack valueStack = com.opensymphony.xwork2.ActionContext.getContext().getValueStack(); + final ValueStack valueStack = ValueStack.adapt(ActionContext.getContext().getValueStack()); final Object val = valueStack.findValue(expr); return getText(key, Arrays.asList(val)); } From 45a1f5efc6e5997e7f1e3106dfd03a52f6091c7f Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Thu, 17 Oct 2024 17:53:30 +1100 Subject: [PATCH 28/33] WW-3714 Deprecate and migrate assorted Interceptors --- .../xwork2/interceptor/AliasInterceptor.java | 3 + .../interceptor/ChainingInterceptor.java | 3 + .../ConversionErrorInterceptor.java | 7 +- .../DefaultWorkflowInterceptor.java | 5 +- .../ExceptionMappingInterceptor.java | 5 +- .../interceptor/LoggingInterceptor.java | 3 + .../interceptor/ModelDrivenInterceptor.java | 5 +- .../ParameterRemoverInterceptor.java | 3 + .../PrefixMethodInvocationUtil.java | 51 +-- .../interceptor/PrepareInterceptor.java | 3 + .../ScopedModelDrivenInterceptor.java | 25 +- .../StaticParametersInterceptor.java | 3 + .../struts2/interceptor/AliasInterceptor.java | 293 ++++++++++++++++ .../interceptor/ChainingInterceptor.java | 275 +++++++++++++++ .../ConversionErrorInterceptor.java | 149 ++++++++ .../DefaultWorkflowInterceptor.java | 245 +++++++++++++ .../ExceptionMappingInterceptor.java | 324 ++++++++++++++++++ .../interceptor/LoggingInterceptor.java | 90 +++++ .../interceptor/ModelDrivenInterceptor.java | 148 ++++++++ .../ParameterRemoverInterceptor.java | 124 +++++++ .../interceptor/PrepareInterceptor.java | 177 ++++++++++ .../ScopedModelDrivenInterceptor.java | 165 +++++++++ .../StaticParametersInterceptor.java | 242 +++++++++++++ 23 files changed, 2308 insertions(+), 40 deletions(-) create mode 100644 core/src/main/java/org/apache/struts2/interceptor/AliasInterceptor.java create mode 100644 core/src/main/java/org/apache/struts2/interceptor/ChainingInterceptor.java create mode 100644 core/src/main/java/org/apache/struts2/interceptor/ConversionErrorInterceptor.java create mode 100644 core/src/main/java/org/apache/struts2/interceptor/DefaultWorkflowInterceptor.java create mode 100644 core/src/main/java/org/apache/struts2/interceptor/ExceptionMappingInterceptor.java create mode 100644 core/src/main/java/org/apache/struts2/interceptor/LoggingInterceptor.java create mode 100644 core/src/main/java/org/apache/struts2/interceptor/ModelDrivenInterceptor.java create mode 100644 core/src/main/java/org/apache/struts2/interceptor/ParameterRemoverInterceptor.java create mode 100644 core/src/main/java/org/apache/struts2/interceptor/PrepareInterceptor.java create mode 100644 core/src/main/java/org/apache/struts2/interceptor/ScopedModelDrivenInterceptor.java create mode 100644 core/src/main/java/org/apache/struts2/interceptor/StaticParametersInterceptor.java diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/AliasInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/AliasInterceptor.java index 334525d27..943aaacf4 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/AliasInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/AliasInterceptor.java @@ -91,7 +91,10 @@ import java.util.Map; *
    * * @author Matthew Payne + * + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.AliasInterceptor} instead. */ +@Deprecated public class AliasInterceptor extends AbstractInterceptor { private static final Logger LOG = LogManager.getLogger(AliasInterceptor.class); diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java index 7284dc037..a21d18c56 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java @@ -118,7 +118,10 @@ import java.util.Map; * @author mrdon * @author tm_jee ( tm_jee(at)yahoo.co.uk ) * @see com.opensymphony.xwork2.ActionChainResult + * + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ChainingInterceptor} instead. */ +@Deprecated public class ChainingInterceptor extends AbstractInterceptor { private static final Logger LOG = LogManager.getLogger(ChainingInterceptor.class); diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ConversionErrorInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ConversionErrorInterceptor.java index b549cc019..21e3d9f65 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ConversionErrorInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ConversionErrorInterceptor.java @@ -42,13 +42,13 @@ import java.util.Map; * display the original string ("abc") again rather than the int value (likely 0, which would make very little sense to * the user). *

    - * + * *

    * Note: Since 2.5.2, this interceptor extends {@link MethodFilterInterceptor}, therefore being * able to deal with excludeMethods / includeMethods parameters. See [Workflow Interceptor] * (class {@link DefaultWorkflowInterceptor}) for documentation and examples on how to use this feature. *

    - * + * * * *

    Interceptor parameters:

    @@ -85,7 +85,10 @@ import java.util.Map; * * * @author Jason Carreira + * + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ConversionErrorInterceptor} instead. */ +@Deprecated public class ConversionErrorInterceptor extends MethodFilterInterceptor { public static final String ORIGINAL_PROPERTY_OVERRIDE = "original.property.override"; diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/DefaultWorkflowInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/DefaultWorkflowInterceptor.java index 05749ae19..d238e1ceb 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/DefaultWorkflowInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/DefaultWorkflowInterceptor.java @@ -32,7 +32,7 @@ import org.apache.struts2.interceptor.ValidationWorkflowAware; /** * *

    - * An interceptor that makes sure there are not validation, conversion or action errors before allowing the interceptor chain to continue. + * An interceptor that makes sure there are not validation, conversion or action errors before allowing the interceptor chain to continue. * If a single FieldError or ActionError (including the ones replicated by the Message Store Interceptor in a redirection) is found, the INPUT result will be triggered. * This interceptor does not perform any validation. *

    @@ -132,7 +132,10 @@ import org.apache.struts2.interceptor.ValidationWorkflowAware; * @author Alexandru Popescu * @author Philip Luppens * @author tm_jee + * + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.DefaultWorkflowInterceptor} instead. */ +@Deprecated public class DefaultWorkflowInterceptor extends MethodFilterInterceptor { private static final long serialVersionUID = 7563014655616490865L; diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ExceptionMappingInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ExceptionMappingInterceptor.java index e60550ca6..3bb70bcb8 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ExceptionMappingInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ExceptionMappingInterceptor.java @@ -20,8 +20,8 @@ package com.opensymphony.xwork2.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.config.entities.ExceptionMappingConfig; -import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.apache.struts2.dispatcher.HttpParameters; import java.util.List; @@ -153,7 +153,10 @@ import java.util.Map; * * @author Matthew E. Porter (matthew dot porter at metissian dot com) * @author Claus Ibsen + * + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ExceptionMappingInterceptor} instead. */ +@Deprecated public class ExceptionMappingInterceptor extends AbstractInterceptor { private static final Logger LOG = LogManager.getLogger(ExceptionMappingInterceptor.class); diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/LoggingInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/LoggingInterceptor.java index 6ba498b3c..3f012288c 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/LoggingInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/LoggingInterceptor.java @@ -59,7 +59,10 @@ import org.apache.logging.log4j.Logger; * * * @author Jason Carreira + * + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.LoggingInterceptor} instead. */ +@Deprecated public class LoggingInterceptor extends AbstractInterceptor { private static final Logger LOG = LogManager.getLogger(LoggingInterceptor.class); private static final String FINISH_MESSAGE = "Finishing execution stack for action "; diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptor.java index f513deb1c..84170b669 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptor.java @@ -71,10 +71,13 @@ import org.apache.struts2.ModelDriven; * </action> * * - * + * * @author tm_jee * @version $Date$ $Id$ + * + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ModelDrivenInterceptor} instead. */ +@Deprecated public class ModelDrivenInterceptor extends AbstractInterceptor { protected boolean refreshModelBeforeResult = false; diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterRemoverInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterRemoverInterceptor.java index c0f83765c..f33ebf6e2 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterRemoverInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterRemoverInterceptor.java @@ -66,7 +66,10 @@ import java.util.Set; * ... * </action> * + * + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ParameterRemoverInterceptor} instead. */ +@Deprecated public class ParameterRemoverInterceptor extends AbstractInterceptor { private static final Logger LOG = LogManager.getLogger(ParameterRemoverInterceptor.class); diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/PrefixMethodInvocationUtil.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/PrefixMethodInvocationUtil.java index 040080824..0ac840c7a 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/PrefixMethodInvocationUtil.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/PrefixMethodInvocationUtil.java @@ -19,8 +19,8 @@ package com.opensymphony.xwork2.interceptor; import com.opensymphony.xwork2.ActionInvocation; -import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -28,7 +28,7 @@ import java.lang.reflect.Method; /** *

    * A utility class for invoking prefixed methods in action class. - * + * * Interceptors that made use of this class are: *

    *
      @@ -37,7 +37,7 @@ import java.lang.reflect.Method; *
    * * * - * + * * In DefaultWorkflowInterceptor *

    applies only when action implements {@link com.opensymphony.xwork2.Validateable}

    *
      @@ -45,12 +45,12 @@ import java.lang.reflect.Method; *
    1. else if the action class have validateDo{MethodName}(), it will be invoked
    2. *
    3. no matter if 1] or 2] is performed, if alwaysInvokeValidate property of the interceptor is "true" (which is by default "true"), validate() will be invoked.
    4. *
    - * + * * - * - * + * + * * - * + * * In PrepareInterceptor *

    Applies only when action implements Preparable

    *
      @@ -58,14 +58,14 @@ import java.lang.reflect.Method; *
    1. else if the action class have prepareDo(MethodName()}(), it will be invoked
    2. *
    3. no matter if 1] or 2] is performed, if alwaysinvokePrepare property of the interceptor is "true" (which is by default "true"), prepare() will be invoked.
    4. *
    - * + * * - * + * * @author Philip Luppens * @author tm_jee */ public class PrefixMethodInvocationUtil { - + private static final Logger LOG = LogManager.getLogger(PrefixMethodInvocationUtil.class); private static final String DEFAULT_INVOCATION_METHODNAME = "execute"; @@ -76,7 +76,7 @@ public class PrefixMethodInvocationUtil { *

    * This method will prefix actionInvocation's ActionProxy's * method with prefixes before invoking the prefixed method. - * Order of the prefixes is important, as this method will return once + * Order of the prefixes is important, as this method will return once * a prefixed method is found in the action class. *

    * @@ -89,7 +89,7 @@ public class PrefixMethodInvocationUtil { * * *

    - * Assuming actionInvocation.getProxy(),getMethod() returns "submit", + * Assuming actionInvocation.getProxy(),getMethod() returns "submit", * the order of invocation would be as follows:- *

    * @@ -99,12 +99,12 @@ public class PrefixMethodInvocationUtil { * * *

    - * If prepareSubmit() exists, it will be invoked and this method - * will return, prepareDoSubmit() will NOT be invoked. + * If prepareSubmit() exists, it will be invoked and this method + * will return, prepareDoSubmit() will NOT be invoked. *

    * *

    - * On the other hand, if prepareDoSubmit() does not exists, and + * On the other hand, if prepareDoSubmit() does not exists, and * prepareDoSubmit() exists, it will be invoked. *

    * @@ -119,29 +119,32 @@ public class PrefixMethodInvocationUtil { */ public static void invokePrefixMethod(ActionInvocation actionInvocation, String[] prefixes) throws InvocationTargetException, IllegalAccessException { Object action = actionInvocation.getAction(); - + String methodName = actionInvocation.getProxy().getMethod(); - + if (methodName == null) { - // if null returns (possible according to the docs), use the default execute + // if null returns (possible according to the docs), use the default execute methodName = DEFAULT_INVOCATION_METHODNAME; } - + Method method = getPrefixedMethod(prefixes, methodName, action); if (method != null) { method.invoke(action, new Object[0]); } } - - + + public static void invokePrefixMethod(org.apache.struts2.ActionInvocation actionInvocation, String[] prefixes) throws InvocationTargetException, IllegalAccessException { + invokePrefixMethod(ActionInvocation.adapt(actionInvocation), prefixes); + } + /** - * This method returns a {@link Method} in action. The method + * This method returns a {@link Method} in action. The method * returned is found by searching for method in action whose method name * is equals to the result of appending each prefixes * to methodName. Only the first method found will be returned, hence * the order of prefixes is important. If none is found this method * will return null. - * + * * @param prefixes the prefixes to prefix the methodName * @param methodName the method name to be prefixed with prefixes * @param action the action class of which the prefixed method is to be search for. @@ -162,7 +165,7 @@ public class PrefixMethodInvocationUtil { } return null; } - + /** *

    * This method capitalized the first character of methodName. diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/PrepareInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/PrepareInterceptor.java index e4d5af634..43bb12c2b 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/PrepareInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/PrepareInterceptor.java @@ -96,7 +96,10 @@ import java.lang.reflect.InvocationTargetException; * @author Philip Luppens * @author tm_jee * @see com.opensymphony.xwork2.Preparable + * + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.PrepareInterceptor} instead. */ +@Deprecated public class PrepareInterceptor extends MethodFilterInterceptor { private static final long serialVersionUID = -5216969014510719786L; diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java index ae2266be0..03473034d 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java @@ -36,7 +36,7 @@ import java.util.Map; * *

    This interceptor only activates on actions that implement the {@link ScopedModelDriven} interface. If * detected, it will retrieve the model class from the configured scope, then provide it to the Action.

    - * + * * * *

    Interceptor parameters:

    @@ -46,7 +46,7 @@ import java.util.Map; *
      * *
    • className - The model class name. Defaults to the class name of the object returned by the getModel() method.
    • - * + * *
    • name - The key to use when storing or retrieving the instance in a scope. Defaults to the model * class name.
    • * @@ -67,42 +67,45 @@ import java.util.Map; * *
        * 
      - * 
      + *
        * <-- Basic usage -->
        * <interceptor name="scopedModelDriven" class="com.opensymphony.interceptor.ScopedModelDrivenInterceptor" />
      - * 
      + *
        * <-- Using all available parameters -->
        * <interceptor name="gangsterForm" class="com.opensymphony.interceptor.ScopedModelDrivenInterceptor">
        *      <param name="scope">session</param>
        *      <param name="name">gangsterForm</param>
        *      <param name="className">com.opensymphony.example.GangsterForm</param>
        *  </interceptor>
      - * 
      + *
        * 
        * 
      + * + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ScopedModelDrivenInterceptor} instead. */ +@Deprecated public class ScopedModelDrivenInterceptor extends AbstractInterceptor { private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; - + private static final String GET_MODEL = "getModel"; private String scope; private String name; private String className; private ObjectFactory objectFactory; - + @Inject public void setObjectFactory(ObjectFactory factory) { this.objectFactory = factory; } - + protected Object resolveModel(ObjectFactory factory, ActionContext actionContext, String modelClassName, String modelScope, String modelName) throws Exception { Object model; Map scopeMap = actionContext.getContextMap(); if ("session".equals(modelScope)) { scopeMap = actionContext.getSession(); } - + model = scopeMap.get(modelName); if (model == null) { model = factory.buildBean(modelClassName, null); @@ -120,7 +123,7 @@ public class ScopedModelDrivenInterceptor extends AbstractInterceptor { if (modelDriven.getModel() == null) { ActionContext ctx = ActionContext.getContext(); ActionConfig config = invocation.getProxy().getConfig(); - + String cName = className; if (cName == null) { try { @@ -162,5 +165,5 @@ public class ScopedModelDrivenInterceptor extends AbstractInterceptor { */ public void setScope(String scope) { this.scope = scope; - } + } } diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/StaticParametersInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/StaticParametersInterceptor.java index d560e1dd4..f5d4382ae 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/StaticParametersInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/StaticParametersInterceptor.java @@ -85,7 +85,10 @@ import java.util.Map; * * * @author Patrick Lightbody + * + * @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.StaticParametersInterceptor} instead. */ +@Deprecated public class StaticParametersInterceptor extends AbstractInterceptor { private boolean parse; diff --git a/core/src/main/java/org/apache/struts2/interceptor/AliasInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/AliasInterceptor.java new file mode 100644 index 000000000..c5aa9fb3c --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/AliasInterceptor.java @@ -0,0 +1,293 @@ +/* + * 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.interceptor; + +import com.opensymphony.xwork2.LocalizedTextProvider; +import com.opensymphony.xwork2.config.entities.ActionConfig; +import com.opensymphony.xwork2.inject.Inject; +import com.opensymphony.xwork2.interceptor.ParametersInterceptor; +import com.opensymphony.xwork2.security.AcceptedPatternsChecker; +import com.opensymphony.xwork2.security.ExcludedPatternsChecker; +import com.opensymphony.xwork2.util.ClearableValueStack; +import com.opensymphony.xwork2.util.Evaluated; +import com.opensymphony.xwork2.util.ValueStackFactory; +import com.opensymphony.xwork2.util.reflection.ReflectionContextState; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.struts2.ActionContext; +import org.apache.struts2.ActionInvocation; +import org.apache.struts2.StrutsConstants; +import org.apache.struts2.dispatcher.HttpParameters; +import org.apache.struts2.dispatcher.Parameter; +import org.apache.struts2.util.ValueStack; + +import java.util.Map; + + +/** + * + * + * The aim of this Interceptor is to alias a named parameter to a different named parameter. By acting as the glue + * between actions sharing similar parameters (but with different names), it can help greatly with action chaining. + * + *

      Action's alias expressions should be in the form of #{ "name1" : "alias1", "name2" : "alias2" }. + * This means that assuming an action (or something else in the stack) has a value for the expression named name1 and the + * action this interceptor is applied to has a setter named alias1, alias1 will be set with the value from + * name1. + *

      + * + * + * + *

      Interceptor parameters:

      + * + * + * + *
        + * + *
      • aliasesKey (optional) - the name of the action parameter to look for the alias map (by default this is + * aliases).
      • + * + *
      + * + * + * + *

      Extending the interceptor:

      + * + * + * + * This interceptor does not have any known extension points. + * + * + * + *

      Example code:

      + * + *
      + * 
      + * <action name="someAction" class="com.examples.SomeAction">
      + *     <!-- The value for the foo parameter will be applied as if it were named bar -->
      + *     <param name="aliases">#{ 'foo' : 'bar' }</param>
      + *
      + *     <interceptor-ref name="alias"/>
      + *     <interceptor-ref name="basicStack"/>
      + *     <result name="success">good_result.ftl</result>
      + * </action>
      + * 
      + * 
      + * + * @author Matthew Payne + */ +public class AliasInterceptor extends AbstractInterceptor { + + private static final Logger LOG = LogManager.getLogger(AliasInterceptor.class); + + private static final String DEFAULT_ALIAS_KEY = "aliases"; + protected String aliasesKey = DEFAULT_ALIAS_KEY; + + protected ValueStackFactory valueStackFactory; + protected LocalizedTextProvider localizedTextProvider; + protected boolean devMode = false; + + private ExcludedPatternsChecker excludedPatterns; + private AcceptedPatternsChecker acceptedPatterns; + + @Inject(StrutsConstants.STRUTS_DEVMODE) + public void setDevMode(String mode) { + this.devMode = Boolean.parseBoolean(mode); + } + + @Inject + public void setValueStackFactory(ValueStackFactory valueStackFactory) { + this.valueStackFactory = valueStackFactory; + } + + @Inject + public void setLocalizedTextProvider(LocalizedTextProvider localizedTextProvider) { + this.localizedTextProvider = localizedTextProvider; + } + + @Inject + public void setExcludedPatterns(ExcludedPatternsChecker excludedPatterns) { + this.excludedPatterns = excludedPatterns; + } + + @Inject + public void setAcceptedPatterns(AcceptedPatternsChecker acceptedPatterns) { + this.acceptedPatterns = acceptedPatterns; + } + + /** + *

      + * Sets the name of the action parameter to look for the alias map. + *

      + * + *

      + * Default is aliases. + *

      + * + * @param aliasesKey the name of the action parameter + */ + public void setAliasesKey(String aliasesKey) { + this.aliasesKey = aliasesKey; + } + + @Override public String intercept(ActionInvocation invocation) throws Exception { + + ActionConfig config = invocation.getProxy().getConfig(); + ActionContext ac = invocation.getInvocationContext(); + Object action = invocation.getAction(); + + // get the action's parameters + final Map parameters = config.getParams(); + + if (parameters.containsKey(aliasesKey)) { + + String aliasExpression = parameters.get(aliasesKey); + ValueStack stack = ac.getValueStack(); + Object obj = stack.findValue(aliasExpression); + + if (obj instanceof Map) { + //get secure stack + ValueStack newStack = valueStackFactory.createValueStack(com.opensymphony.xwork2.util.ValueStack.adapt(stack)); + boolean clearableStack = newStack instanceof ClearableValueStack; + if (clearableStack) { + //if the stack's context can be cleared, do that to prevent OGNL + //from having access to objects in the stack, see XW-641 + ((ClearableValueStack)newStack).clearContextValues(); + Map context = newStack.getContext(); + ReflectionContextState.setCreatingNullObjects(context, true); + ReflectionContextState.setDenyMethodExecution(context, true); + ReflectionContextState.setReportingConversionErrors(context, true); + + //keep locale from original context + newStack.getActionContext().withLocale(stack.getActionContext().getLocale()); + } + + // override + Map aliases = (Map) obj; + for (Object o : aliases.entrySet()) { + Map.Entry entry = (Map.Entry) o; + String name = entry.getKey().toString(); + if (isNotAcceptableExpression(name)) { + continue; + } + String alias = (String) entry.getValue(); + if (isNotAcceptableExpression(alias)) { + continue; + } + Evaluated value = new Evaluated(stack.findValue(name)); + if (!value.isDefined()) { + // workaround + HttpParameters contextParameters = ActionContext.getContext().getParameters(); + + if (null != contextParameters) { + Parameter param = contextParameters.get(name); + if (param.isDefined()) { + value = new Evaluated(param.getValue()); + } + } + } + if (value.isDefined()) { + try { + newStack.setValue(alias, value.get()); + } catch (RuntimeException e) { + if (devMode) { + String developerNotification = localizedTextProvider.findText(ParametersInterceptor.class, "devmode.notification", ActionContext.getContext().getLocale(), "Developer Notification:\n{0}", new Object[]{ + "Unexpected Exception caught setting '" + entry.getKey() + "' on '" + action.getClass() + ": " + e.getMessage() + }); + LOG.error(developerNotification); + if (action instanceof ValidationAware) { + ((ValidationAware) action).addActionMessage(developerNotification); + } + } + } + } + } + + if (clearableStack) { + stack.getActionContext().withConversionErrors(newStack.getActionContext().getConversionErrors()); + } + } else { + LOG.debug("invalid alias expression: {}", aliasesKey); + } + } + + return invocation.invoke(); + } + + protected boolean isAccepted(String paramName) { + AcceptedPatternsChecker.IsAccepted result = acceptedPatterns.isAccepted(paramName); + if (result.isAccepted()) { + return true; + } + + LOG.warn("Parameter [{}] didn't match accepted pattern [{}]! See Accepted / Excluded patterns at\n" + + "https://struts.apache.org/security/#accepted--excluded-patterns", + paramName, result.getAcceptedPattern()); + + return false; + } + + protected boolean isExcluded(String paramName) { + ExcludedPatternsChecker.IsExcluded result = excludedPatterns.isExcluded(paramName); + if (!result.isExcluded()) { + return false; + } + + LOG.warn("Parameter [{}] matches excluded pattern [{}]! See Accepted / Excluded patterns at\n" + + "https://struts.apache.org/security/#accepted--excluded-patterns", + paramName, result.getExcludedPattern()); + + return true; + } + + /** + * Checks if expression contains vulnerable code + * + * @param expression of interceptor + * @return true|false + */ + protected boolean isNotAcceptableExpression(String expression) { + return isExcluded(expression) || !isAccepted(expression); + } + + /** + * Sets a comma-delimited list of regular expressions to match + * parameters that are allowed in the parameter map (aka whitelist). + *

      + * Don't change the default unless you know what you are doing in terms + * of security implications. + *

      + * + * @param commaDelim A comma-delimited list of regular expressions + */ + public void setAcceptParamNames(String commaDelim) { + acceptedPatterns.setAcceptedPatterns(commaDelim); + } + + /** + * Sets a comma-delimited list of regular expressions to match + * parameters that should be removed from the parameter map. + * + * @param commaDelim A comma-delimited list of regular expressions + */ + public void setExcludeParams(String commaDelim) { + excludedPatterns.setExcludedPatterns(commaDelim); + } + +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/ChainingInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/ChainingInterceptor.java new file mode 100644 index 000000000..fd3c25a65 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/ChainingInterceptor.java @@ -0,0 +1,275 @@ +/* + * 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.interceptor; + +import com.opensymphony.xwork2.ActionChainResult; +import com.opensymphony.xwork2.inject.Inject; +import com.opensymphony.xwork2.util.CompoundRoot; +import com.opensymphony.xwork2.util.ProxyUtil; +import com.opensymphony.xwork2.util.TextParseUtil; +import com.opensymphony.xwork2.util.reflection.ReflectionProvider; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.struts2.ActionInvocation; +import org.apache.struts2.Result; +import org.apache.struts2.StrutsConstants; +import org.apache.struts2.Unchainable; +import org.apache.struts2.util.ValueStack; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + + +/** + * + *

      + * An interceptor that copies all the properties of every object in the value stack to the currently executing object, + * except for any object that implements {@link Unchainable}. A collection of optional includes and + * excludes may be provided to control how and which parameters are copied. Only includes or excludes may be + * specified. Specifying both results in undefined behavior. See the javadocs for {@link ReflectionProvider#copy(Object, Object, + * Map, Collection, Collection)} for more information. + *

      + * + *

      + * Note: It is important to remember that this interceptor does nothing if there are no objects already on the stack. + *
      This means two things: + *
      One, you can safely apply it to all your actions without any worry of adverse affects. + *
      Two, it is up to you to ensure an object exists in the stack prior to invoking this action. The most typical way this is done + * is through the use of the chain result type, which combines with this interceptor to make up the action + * chaining feature. + *

      + * + *

      + * Note: By default Errors, Field errors and Message aren't copied during chaining, to change the behaviour you can specify + * the below three constants in struts.properties or struts.xml: + *

      + * + *
        + *
      • struts.chaining.copyErrors - set to true to copy Action Errors
      • + *
      • struts.chaining.copyFieldErrors - set to true to copy Field Errors
      • + *
      • struts.chaining.copyMessages - set to true to copy Action Messages
      • + *
      + * + *

      + * Example: + *

      + * + *
      + * <constant name="struts.xwork.chaining.copyErrors" value="true"/>
      + * 
      + * + *

      + * Note: By default actionErrors and actionMessages are excluded when copping object's properties. + *

      + * + * Interceptor parameters: + * + *
        + *
      • excludes (optional) - the list of parameter names to exclude from copying (all others will be included).
      • + *
      • includes (optional) - the list of parameter names to include when copying (all others will be excluded).
      • + *
      + * + * Extending the interceptor: + * + *

      + * There are no known extension points to this interceptor. + *

      + * + * Example code: + * + * + *
      + * <action name="someAction" class="com.examples.SomeAction">
      + *     <interceptor-ref name="basicStack"/>
      + *     <result name="success" type="chain">otherAction</result>
      + * </action>
      + * 
      + * + *
      + * <action name="otherAction" class="com.examples.OtherAction">
      + *     <interceptor-ref name="chain"/>
      + *     <interceptor-ref name="basicStack"/>
      + *     <result name="success">good_result.ftl</result>
      + * </action>
      + * 
      + * + * + * + * @author mrdon + * @author tm_jee ( tm_jee(at)yahoo.co.uk ) + * @see ActionChainResult + */ +public class ChainingInterceptor extends AbstractInterceptor { + + private static final Logger LOG = LogManager.getLogger(ChainingInterceptor.class); + + private static final String ACTION_ERRORS = "actionErrors"; + private static final String FIELD_ERRORS = "fieldErrors"; + private static final String ACTION_MESSAGES = "actionMessages"; + + private boolean copyMessages = false; + private boolean copyErrors = false; + private boolean copyFieldErrors = false; + + protected Collection excludes; + + protected Collection includes; + protected ReflectionProvider reflectionProvider; + + @Inject + public void setReflectionProvider(ReflectionProvider prov) { + this.reflectionProvider = prov; + } + + @Inject(value = StrutsConstants.STRUTS_CHAINING_COPY_ERRORS, required = false) + public void setCopyErrors(String copyErrors) { + this.copyErrors = "true".equalsIgnoreCase(copyErrors); + } + + @Inject(value = StrutsConstants.STRUTS_CHAINING_COPY_FIELD_ERRORS, required = false) + public void setCopyFieldErrors(String copyFieldErrors) { + this.copyFieldErrors = "true".equalsIgnoreCase(copyFieldErrors); + } + + @Inject(value = StrutsConstants.STRUTS_CHAINING_COPY_MESSAGES, required = false) + public void setCopyMessages(String copyMessages) { + this.copyMessages = "true".equalsIgnoreCase(copyMessages); + } + + @Override + public String intercept(ActionInvocation invocation) throws Exception { + ValueStack stack = invocation.getStack(); + CompoundRoot root = stack.getRoot(); + if (shouldCopyStack(invocation, root)) { + copyStack(invocation, root); + } + return invocation.invoke(); + } + + private void copyStack(ActionInvocation invocation, CompoundRoot root) { + List list = prepareList(root); + Map ctxMap = invocation.getInvocationContext().getContextMap(); + for (Object object : list) { + if (shouldCopy(object)) { + Object action = invocation.getAction(); + Class editable = null; + if(ProxyUtil.isProxy(action)) { + editable = ProxyUtil.ultimateTargetClass(action); + } + reflectionProvider.copy(object, action, ctxMap, prepareExcludes(), includes, editable); + } + } + } + + private Collection prepareExcludes() { + Collection localExcludes = excludes; + if (!copyErrors || !copyMessages ||!copyFieldErrors) { + if (localExcludes == null) { + localExcludes = new HashSet(); + if (!copyErrors) { + localExcludes.add(ACTION_ERRORS); + } + if (!copyMessages) { + localExcludes.add(ACTION_MESSAGES); + } + if (!copyFieldErrors) { + localExcludes.add(FIELD_ERRORS); + } + } + } + return localExcludes; + } + + private boolean shouldCopy(Object o) { + return o != null && !(o instanceof Unchainable); + } + + @SuppressWarnings("unchecked") + private List prepareList(CompoundRoot root) { + List list = new ArrayList(root); + list.remove(0); + Collections.reverse(list); + return list; + } + + private boolean shouldCopyStack(ActionInvocation invocation, CompoundRoot root) throws Exception { + Result result = invocation.getResult(); + return root.size() > 1 && (result == null || ActionChainResult.class.isAssignableFrom(result.getClass())); + } + + /** + * Gets list of parameter names to exclude + * + * @return the exclude list + */ + public Collection getExcludes() { + return excludes; + } + + /** + * Sets the list of parameter names to exclude from copying (all others will be included). + * + * @param excludes the excludes list as comma separated String + */ + public void setExcludes(String excludes) { + this.excludes = TextParseUtil.commaDelimitedStringToSet(excludes); + } + + /** + * Sets the list of parameter names to exclude from copying (all others will be included). + * + * @param excludes the excludes list + */ + public void setExcludesCollection(Collection excludes) { + this.excludes = excludes; + } + + /** + * Gets list of parameter names to include + * + * @return the include list + */ + public Collection getIncludes() { + return includes; + } + + /** + * Sets the list of parameter names to include when copying (all others will be excluded). + * + * @param includes the includes list as comma separated String + */ + public void setIncludes(String includes) { + this.includes = TextParseUtil.commaDelimitedStringToSet(includes); + } + + + /** + * Sets the list of parameter names to include when copying (all others will be excluded). + * + * @param includes the includes list + */ + public void setIncludesCollection(Collection includes) { + this.includes = includes; + } + +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/ConversionErrorInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/ConversionErrorInterceptor.java new file mode 100644 index 000000000..e795543d4 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/ConversionErrorInterceptor.java @@ -0,0 +1,149 @@ +/* + * 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.interceptor; + +import com.opensymphony.xwork2.conversion.impl.ConversionData; +import com.opensymphony.xwork2.conversion.impl.XWorkConverter; +import org.apache.commons.text.StringEscapeUtils; +import org.apache.struts2.ActionContext; +import org.apache.struts2.ActionInvocation; +import org.apache.struts2.util.ValueStack; + +import java.util.HashMap; +import java.util.Map; + + +/** + * + * ConversionErrorInterceptor adds conversion errors from the ActionContext to the Action's field errors. + * + *

      + * This interceptor adds any error found in the {@link ActionContext}'s conversionErrors map as a field error (provided + * that the action implements {@link ValidationAware}). In addition, any field that contains a validation error has its + * original value saved such that any subsequent requests for that value return the original value rather than the value + * in the action. This is important because if the value "abc" is submitted and can't be converted to an int, we want to + * display the original string ("abc") again rather than the int value (likely 0, which would make very little sense to + * the user). + *

      + * + *

      + * Note: Since 2.5.2, this interceptor extends {@link MethodFilterInterceptor}, therefore being + * able to deal with excludeMethods / includeMethods parameters. See [Workflow Interceptor] + * (class {@link DefaultWorkflowInterceptor}) for documentation and examples on how to use this feature. + *

      + * + * + * + *

      Interceptor parameters:

      + * + * + * + *
        + *
      • None
      • + *
      + * + * + * + *

      Extending the interceptor:

      + * + * + * + * Because this interceptor is not web-specific, it abstracts the logic for whether an error should be added. This + * allows for web-specific interceptors to use more complex logic in the {@link #shouldAddError} method for when a value + * has a conversion error but is null or empty or otherwise indicates that the value was never actually entered by the + * user. + * + * + * + *

      Example code:

      + * + *
      + * 
      + * <action name="someAction" class="com.examples.SomeAction">
      + *     <interceptor-ref name="params"/>
      + *     <interceptor-ref name="conversionError"/>
      + *     <result name="success">good_result.ftl</result>
      + * </action>
      + * 
      + * 
      + * + * @author Jason Carreira + */ +public class ConversionErrorInterceptor extends MethodFilterInterceptor { + + public static final String ORIGINAL_PROPERTY_OVERRIDE = "original.property.override"; + + protected Object getOverrideExpr(ActionInvocation invocation, Object value) { + return escape(value); + } + + protected String escape(Object value) { + return "\"" + StringEscapeUtils.escapeJava(String.valueOf(value)) + "\""; + } + + @Override + public String doIntercept(ActionInvocation invocation) throws Exception { + + ActionContext invocationContext = invocation.getInvocationContext(); + Map conversionErrors = invocationContext.getConversionErrors(); + ValueStack stack = invocationContext.getValueStack(); + + HashMap fakie = null; + + for (Map.Entry entry : conversionErrors.entrySet()) { + String propertyName = entry.getKey(); + ConversionData conversionData = entry.getValue(); + + if (shouldAddError(propertyName, conversionData.getValue())) { + String message = XWorkConverter.getConversionErrorMessage(propertyName, conversionData.getToClass(), com.opensymphony.xwork2.util.ValueStack.adapt(stack)); + + Object action = invocation.getAction(); + if (action instanceof ValidationAware) { + ValidationAware va = (ValidationAware) action; + va.addFieldError(propertyName, message); + } + + if (fakie == null) { + fakie = new HashMap<>(); + } + + fakie.put(propertyName, getOverrideExpr(invocation, conversionData.getValue())); + } + } + + if (fakie != null) { + // if there were some errors, put the original (fake) values in place right before the result + stack.getContext().put(ORIGINAL_PROPERTY_OVERRIDE, fakie); + invocation.addPreResultListener(new PreResultListener() { + public void beforeResult(ActionInvocation invocation, String resultCode) { + Map fakie = (Map) invocation.getInvocationContext().get(ORIGINAL_PROPERTY_OVERRIDE); + + if (fakie != null) { + invocation.getStack().setExprOverrides(fakie); + } + } + }); + } + return invocation.invoke(); + } + + protected boolean shouldAddError(String propertyName, Object value) { + return true; + } +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/DefaultWorkflowInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/DefaultWorkflowInterceptor.java new file mode 100644 index 000000000..c4dd70154 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/DefaultWorkflowInterceptor.java @@ -0,0 +1,245 @@ +/* + * 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.interceptor; + +import com.opensymphony.xwork2.Action; +import com.opensymphony.xwork2.interceptor.annotations.InputConfig; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.reflect.MethodUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.struts2.ActionInvocation; + +/** + * + *

      + * An interceptor that makes sure there are not validation, conversion or action errors before allowing the interceptor chain to continue. + * If a single FieldError or ActionError (including the ones replicated by the Message Store Interceptor in a redirection) is found, the INPUT result will be triggered. + * This interceptor does not perform any validation. + *

      + * + *

      + * This interceptor does nothing if the name of the method being invoked is specified in the excludeMethods + * parameter. excludeMethods accepts a comma-delimited list of method names. For example, requests to + * foo!input.action and foo!back.action will be skipped by this interceptor if you set the + * excludeMethods parameter to "input, back". + *

      + * + *

      + * Note: As this method extends off MethodFilterInterceptor, it is capable of + * deciding if it is applicable only to selective methods in the action class. This is done by adding param tags + * for the interceptor element, naming either a list of excluded method names and/or a list of included method + * names, whereby includeMethods overrides excludedMethods. A single * sign is interpreted as wildcard matching + * all methods for both parameters. + * See {@link MethodFilterInterceptor} for more info. + *

      + * + *

      + * This interceptor also supports the following interfaces which can implemented by actions: + *

      + * + *
        + *
      • ValidationAware - implemented by ActionSupport class
      • + *
      • ValidationWorkflowAware - allows changing result name programmatically
      • + *
      • ValidationErrorAware - notifies action about errors and also allow change result name
      • + *
      + * + *

      + * You can also use InputConfig annotation to change result name returned when validation errors occurred. + *

      + * + * + * + *

      Interceptor parameters:

      + * + * + *
        + *
      • inputResultName - Default to "input". Determine the result name to be returned when + * an action / field error is found.
      • + *
      + * + * + *

      Extending the interceptor:

      + * + * + * + *

      There are no known extension points for this interceptor.

      + * + * + * + *

      Example code:

      + * + *
      + * 
      + *
      + * <action name="someAction" class="com.examples.SomeAction">
      + *     <interceptor-ref name="params"/>
      + *     <interceptor-ref name="validation"/>
      + *     <interceptor-ref name="workflow"/>
      + *     <result name="success">good_result.ftl</result>
      + * </action>
      + *
      + * <-- In this case myMethod as well as mySecondMethod of the action class
      + *        will not pass through the workflow process -->
      + * <action name="someAction" class="com.examples.SomeAction">
      + *     <interceptor-ref name="params"/>
      + *     <interceptor-ref name="validation"/>
      + *     <interceptor-ref name="workflow">
      + *         <param name="excludeMethods">myMethod,mySecondMethod</param>
      + *     </interceptor-ref name="workflow">
      + *     <result name="success">good_result.ftl</result>
      + * </action>
      + *
      + * <-- In this case, the result named "error" will be used when
      + *        an action / field error is found -->
      + * <-- The Interceptor will only be applied for myWorkflowMethod method of action
      + *        classes, since this is the only included method while any others are excluded -->
      + * <action name="someAction" class="com.examples.SomeAction">
      + *     <interceptor-ref name="params"/>
      + *     <interceptor-ref name="validation"/>
      + *     <interceptor-ref name="workflow">
      + *        <param name="inputResultName">error</param>
      + *         <param name="excludeMethods">*</param>
      + *         <param name="includeMethods">myWorkflowMethod</param>
      + *     </interceptor-ref>
      + *     <result name="success">good_result.ftl</result>
      + * </action>
      + *
      + * 
      + * 
      + * + * @author Jason Carreira + * @author Rainer Hermanns + * @author Alexandru Popescu + * @author Philip Luppens + * @author tm_jee + */ +public class DefaultWorkflowInterceptor extends MethodFilterInterceptor { + + private static final long serialVersionUID = 7563014655616490865L; + + private static final Logger LOG = LogManager.getLogger(DefaultWorkflowInterceptor.class); + + private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; + + private String inputResultName = Action.INPUT; + + /** + * Set the inputResultName (result name to be returned when + * a action / field error is found registered). Default to {@link Action#INPUT} + * + * @param inputResultName what result name to use when there was validation error(s). + */ + public void setInputResultName(String inputResultName) { + this.inputResultName = inputResultName; + } + + /** + * Intercept {@link ActionInvocation} and returns a inputResultName + * when action / field errors is found registered. + * + * @param invocation the action invocation + * @return String result name + */ + @Override + protected String doIntercept(ActionInvocation invocation) throws Exception { + Object action = invocation.getAction(); + + if (action instanceof ValidationAware) { + ValidationAware validationAwareAction = (ValidationAware) action; + + if (validationAwareAction.hasErrors()) { + LOG.debug("Errors on action [{}], returning result name [{}]", validationAwareAction, inputResultName); + + String resultName = inputResultName; + resultName = processValidationWorkflowAware(action, resultName); + resultName = processInputConfig(action, invocation.getProxy().getMethod(), resultName); + resultName = processValidationErrorAware(action, resultName); + + return resultName; + } + } + + return invocation.invoke(); + } + + /** + * Process {@link com.opensymphony.xwork2.interceptor.ValidationWorkflowAware} interface + * + * @param action action object + * @param currentResultName current result name + * + * @return result name + */ + private String processValidationWorkflowAware(final Object action, final String currentResultName) { + String resultName = currentResultName; + if (action instanceof ValidationWorkflowAware) { + resultName = ((ValidationWorkflowAware) action).getInputResultName(); + LOG.debug("Changing result name from [{}] to [{}] because of processing [{}] interface applied to [{}]", + currentResultName, resultName, ValidationWorkflowAware.class.getSimpleName(), action); + } + return resultName; + } + + /** + * Process {@link InputConfig} annotation applied to method + * @param action action object + * @param method method + * @param currentResultName current result name + * + * @return result name + * + * @throws Exception in case of any errors + */ + protected String processInputConfig(final Object action, final String method, final String currentResultName) throws Exception { + String resultName = currentResultName; + InputConfig annotation = MethodUtils.getAnnotation(action.getClass().getMethod(method, EMPTY_CLASS_ARRAY), + InputConfig.class ,true,true); + if (annotation != null) { + if (StringUtils.isNotEmpty(annotation.methodName())) { + resultName = (String) MethodUtils.invokeMethod(action, true, annotation.methodName()); + } else { + resultName = annotation.resultName(); + } + LOG.debug("Changing result name from [{}] to [{}] because of processing annotation [{}] on action [{}]", + currentResultName, resultName, InputConfig.class.getSimpleName(), action); + } + return resultName; + } + + /** + * Notify action if it implements {@link com.opensymphony.xwork2.interceptor.ValidationErrorAware} interface + * + * @param action action object + * @param currentResultName current result name + * + * @return result name + * @see com.opensymphony.xwork2.interceptor.ValidationErrorAware + */ + protected String processValidationErrorAware(final Object action, final String currentResultName) { + String resultName = currentResultName; + if (action instanceof ValidationErrorAware) { + resultName = ((ValidationErrorAware) action).actionErrorOccurred(currentResultName); + LOG.debug("Changing result name from [{}] to [{}] because of processing interface [{}] on action [{}]", + currentResultName, resultName, ValidationErrorAware.class.getSimpleName(), action); + } + return resultName; + } + +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/ExceptionMappingInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/ExceptionMappingInterceptor.java new file mode 100644 index 000000000..277fc33df --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/ExceptionMappingInterceptor.java @@ -0,0 +1,324 @@ +/* + * 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.interceptor; + +import com.opensymphony.xwork2.config.entities.ExceptionMappingConfig; +import com.opensymphony.xwork2.interceptor.ExceptionHolder; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.struts2.ActionInvocation; +import org.apache.struts2.dispatcher.HttpParameters; + +import java.util.List; +import java.util.Map; + +/** + * + *

      + * This interceptor forms the core functionality of the exception handling feature. Exception handling allows you to map + * an exception to a result code, just as if the action returned a result code instead of throwing an unexpected + * exception. When an exception is encountered, it is wrapped with an {@link ExceptionHolder} and pushed on the stack, + * providing easy access to the exception from within your result. + *

      + * + *

      + * Note: While you can configure exception mapping in your configuration file at any point, the configuration + * will not have any effect if this interceptor is not in the interceptor stack for your actions. It is recommended that + * you make this interceptor the first interceptor on the stack, ensuring that it has full access to catch any + * exception, even those caused by other interceptors. + *

      + * + * + * + *

      Interceptor parameters:

      + * + * + * + *
        + * + *
      • logEnabled (optional) - Should exceptions also be logged? (boolean true|false)
      • + * + *
      • logLevel (optional) - what log level should we use (trace, debug, info, warn, error, fatal)? - defaut is debug
      • + * + *
      • logCategory (optional) - If provided we would use this category (eg. com.mycompany.app). + * Default is to use com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.
      • + * + *
      + * + *

      + * The parameters above enables us to log all thrown exceptions with stacktace in our own logfile, + * and present a friendly webpage (with no stacktrace) to the end user. + *

      + * + * + * + *

      Extending the interceptor:

      + * + * + *

      + * If you want to add custom handling for publishing the Exception, you may override + * {@link #publishException(ActionInvocation, ExceptionHolder)}. The default implementation + * pushes the given ExceptionHolder on value stack. A custom implementation could add additional logging etc. + *

      + * + * + *

      Example code:

      + * + *
      + * 
      + * <xwork>
      + *     <package name="default" extends="xwork-default">
      + *         <global-results>
      + *             <result name="error" type="freemarker">error.ftl</result>
      + *         </global-results>
      + *
      + *         <global-exception-mappings>
      + *             <exception-mapping exception="java.lang.Exception" result="error"/>
      + *         </global-exception-mappings>
      + *
      + *         <action name="test">
      + *             <interceptor-ref name="exception"/>
      + *             <interceptor-ref name="basicStack"/>
      + *             <exception-mapping exception="com.acme.CustomException" result="custom_error"/>
      + *             <result name="custom_error">custom_error.ftl</result>
      + *             <result name="success" type="freemarker">test.ftl</result>
      + *         </action>
      + *     </package>
      + * </xwork>
      + * 
      + * 
      + * + *

      + * This second example will also log the exceptions using our own category + * com.mycompany.app.unhandled at WARN level. + *

      + * + *
      + * 
      + * <xwork>
      + *   <package name="something" extends="xwork-default">
      + *      <interceptors>
      + *          <interceptor-stack name="exceptionmappingStack">
      + *              <interceptor-ref name="exception">
      + *                  <param name="logEnabled">true</param>
      + *                  <param name="logCategory">com.mycompany.app.unhandled</param>
      + *                  <param name="logLevel">WARN</param>
      + *              </interceptor-ref>
      + *              <interceptor-ref name="i18n"/>
      + *              <interceptor-ref name="staticParams"/>
      + *              <interceptor-ref name="params"/>
      + *              <interceptor-ref name="validation">
      + *                  <param name="excludeMethods">input,back,cancel,browse</param>
      + *              </interceptor-ref>
      + *          </interceptor-stack>
      + *      </interceptors>
      + *
      + *      <default-interceptor-ref name="exceptionmappingStack"/>
      + *
      + *      <global-results>
      + *           <result name="unhandledException">/unhandled-exception.jsp</result>
      + *      </global-results>
      + *
      + *      <global-exception-mappings>
      + *           <exception-mapping exception="java.lang.Exception" result="unhandledException"/>
      + *      </global-exception-mappings>
      + *
      + *      <action name="exceptionDemo" class="org.apache.struts2.showcase.exceptionmapping.ExceptionMappingAction">
      + *          <exception-mapping exception="org.apache.struts2.showcase.exceptionmapping.ExceptionMappingException"
      + *                             result="damm"/>
      + *          <result name="input">index.jsp</result>
      + *          <result name="success">success.jsp</result>
      + *          <result name="damm">damm.jsp</result>
      + *      </action>
      + *
      + *   </package>
      + * </xwork>
      + * 
      + * 
      + * + * @author Matthew E. Porter (matthew dot porter at metissian dot com) + * @author Claus Ibsen + */ +public class ExceptionMappingInterceptor extends AbstractInterceptor { + + private static final Logger LOG = LogManager.getLogger(ExceptionMappingInterceptor.class); + + protected Logger categoryLogger; + protected boolean logEnabled = false; + protected String logCategory; + protected String logLevel; + + + public boolean isLogEnabled() { + return logEnabled; + } + + public void setLogEnabled(boolean logEnabled) { + this.logEnabled = logEnabled; + } + + public String getLogCategory() { + return logCategory; + } + + public void setLogCategory(String logCatgory) { + this.logCategory = logCatgory; + } + + public String getLogLevel() { + return logLevel; + } + + public void setLogLevel(String logLevel) { + this.logLevel = logLevel; + } + + @Override + public String intercept(ActionInvocation invocation) throws Exception { + String result; + + try { + result = invocation.invoke(); + } catch (Exception e) { + if (isLogEnabled()) { + handleLogging(e); + } + List exceptionMappings = invocation.getProxy().getConfig().getExceptionMappings(); + ExceptionMappingConfig mappingConfig = this.findMappingFromExceptions(exceptionMappings, e); + if (mappingConfig != null && mappingConfig.getResult()!=null) { + Map mappingParams = mappingConfig.getParams(); + // create a mutable HashMap since some interceptors will remove parameters, and parameterMap is immutable + HttpParameters parameters = HttpParameters.create(mappingParams).build(); + invocation.getInvocationContext().withParameters(parameters); + result = mappingConfig.getResult(); + publishException(invocation, new ExceptionHolder(e)); + } else { + throw e; + } + } + + return result; + } + + /** + * Handles the logging of the exception. + * + * @param e the exception to log. + */ + protected void handleLogging(Exception e) { + if (logCategory != null) { + if (categoryLogger == null) { + // init category logger + categoryLogger = LogManager.getLogger(logCategory); + } + doLog(categoryLogger, e); + } else { + doLog(LOG, e); + } + } + + /** + * Performs the actual logging. + * + * @param logger the provided logger to use. + * @param e the exception to log. + */ + protected void doLog(Logger logger, Exception e) { + if (logLevel == null) { + logger.debug(e.getMessage(), e); + return; + } + + if ("trace".equalsIgnoreCase(logLevel)) { + logger.trace(e.getMessage(), e); + } else if ("debug".equalsIgnoreCase(logLevel)) { + logger.debug(e.getMessage(), e); + } else if ("info".equalsIgnoreCase(logLevel)) { + logger.info(e.getMessage(), e); + } else if ("warn".equalsIgnoreCase(logLevel)) { + logger.warn(e.getMessage(), e); + } else if ("error".equalsIgnoreCase(logLevel)) { + logger.error(e.getMessage(), e); + } else if ("fatal".equalsIgnoreCase(logLevel)) { + logger.fatal(e.getMessage(), e); + } else { + throw new IllegalArgumentException("LogLevel [" + logLevel + "] is not supported"); + } + } + + /** + * Try to find appropriate {@link ExceptionMappingConfig} based on provided Throwable + * + * @param exceptionMappings list of defined exception mappings + * @param t caught exception + * @return appropriate mapping or null + */ + protected ExceptionMappingConfig findMappingFromExceptions(List exceptionMappings, Throwable t) { + ExceptionMappingConfig config = null; + // Check for specific exception mappings. + if (exceptionMappings != null) { + int deepest = Integer.MAX_VALUE; + for (Object exceptionMapping : exceptionMappings) { + ExceptionMappingConfig exceptionMappingConfig = (ExceptionMappingConfig) exceptionMapping; + int depth = getDepth(exceptionMappingConfig.getExceptionClassName(), t); + if (depth >= 0 && depth < deepest) { + deepest = depth; + config = exceptionMappingConfig; + } + } + } + return config; + } + + /** + * Return the depth to the superclass matching. 0 means ex matches exactly. Returns -1 if there's no match. + * Otherwise, returns depth. Lowest depth wins. + * + * @param exceptionMapping the mapping classname + * @param t the cause + * @return the depth, if not found -1 is returned. + */ + public int getDepth(String exceptionMapping, Throwable t) { + return getDepth(exceptionMapping, t.getClass(), 0); + } + + private int getDepth(String exceptionMapping, Class exceptionClass, int depth) { + if (exceptionClass.getName().contains(exceptionMapping)) { + // Found it! + return depth; + } + // If we've gone as far as we can go and haven't found it... + if (exceptionClass.equals(Throwable.class)) { + return -1; + } + return getDepth(exceptionMapping, exceptionClass.getSuperclass(), depth + 1); + } + + /** + * Default implementation to handle ExceptionHolder publishing. Pushes given ExceptionHolder on the stack. + * Subclasses may override this to customize publishing. + * + * @param invocation The invocation to publish Exception for. + * @param exceptionHolder The exceptionHolder wrapping the Exception to publish. + */ + protected void publishException(ActionInvocation invocation, ExceptionHolder exceptionHolder) { + invocation.getStack().push(exceptionHolder); + } + +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/LoggingInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/LoggingInterceptor.java new file mode 100644 index 000000000..4536d462b --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/LoggingInterceptor.java @@ -0,0 +1,90 @@ +/* + * 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.interceptor; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.struts2.ActionInvocation; + + +/** + * + *

      + * This interceptor logs the start and end of the execution an action (in English-only, not internationalized). + *
      + * Note:: This interceptor will log at INFO level. + *

      + * + * + * + * There are no parameters for this interceptor. + * + * + * + * There are no obvious extensions to the existing interceptor. + * + * + *
      + * 
      + * <!-- prints out a message before and after the immediate action execution -->
      + * <action name="someAction" class="com.examples.SomeAction">
      + *     <interceptor-ref name="completeStack"/>
      + *     <interceptor-ref name="logger"/>
      + *     <result name="success">good_result.ftl</result>
      + * </action>
      + *
      + * <!-- prints out a message before any more interceptors continue and after they have finished -->
      + * <action name="someAction" class="com.examples.SomeAction">
      + *     <interceptor-ref name="logger"/>
      + *     <interceptor-ref name="completeStack"/>
      + *     <result name="success">good_result.ftl</result>
      + * </action>
      + * 
      + * 
      + * + * @author Jason Carreira + */ +public class LoggingInterceptor extends AbstractInterceptor { + private static final Logger LOG = LogManager.getLogger(LoggingInterceptor.class); + private static final String FINISH_MESSAGE = "Finishing execution stack for action "; + private static final String START_MESSAGE = "Starting execution stack for action "; + + @Override + public String intercept(ActionInvocation invocation) throws Exception { + logMessage(invocation, START_MESSAGE); + String result = invocation.invoke(); + logMessage(invocation, FINISH_MESSAGE); + return result; + } + + private void logMessage(ActionInvocation invocation, String baseMessage) { + if (LOG.isInfoEnabled()) { + StringBuilder message = new StringBuilder(baseMessage); + String namespace = invocation.getProxy().getNamespace(); + + if ((namespace != null) && (namespace.trim().length() > 0)) { + message.append(namespace).append("/"); + } + + message.append(invocation.getProxy().getActionName()); + LOG.info(message.toString()); + } + } + +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/ModelDrivenInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/ModelDrivenInterceptor.java new file mode 100644 index 000000000..d2679ebd6 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/ModelDrivenInterceptor.java @@ -0,0 +1,148 @@ +/* + * 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.interceptor; + +import com.opensymphony.xwork2.util.CompoundRoot; +import org.apache.struts2.ActionInvocation; +import org.apache.struts2.ModelDriven; +import org.apache.struts2.interceptor.parameter.ParametersInterceptor; +import org.apache.struts2.util.ValueStack; + +/** + * + * + * Watches for {@link ModelDriven} actions and adds the action's model on to the value stack. + * + *

      Note: The ModelDrivenInterceptor must come before the both {@link StaticParametersInterceptor} and + * {@link ParametersInterceptor} if you want the parameters to be applied to the model. + *

      + *

      Note: The ModelDrivenInterceptor will only push the model into the stack when the + * model is not null, else it will be ignored. + *

      + * + * + * + *

      Interceptor parameters:

      + * + * + * + *
        + * + *
      • refreshModelBeforeResult - set to true if you want the model to be refreshed on the value stack after action + * execution and before result execution. The setting is useful if you want to change the model instance during the + * action execution phase, like when loading it from the data layer. This will result in getModel() being called at + * least twice.
      • + * + *
      + * + * + * + *

      Extending the interceptor:

      + * + * + * + * There are no known extension points to this interceptor. + * + * + * + *

      Example code:

      + * + *
      + * 
      + * <action name="someAction" class="com.examples.SomeAction">
      + *     <interceptor-ref name="modelDriven"/>
      + *     <interceptor-ref name="basicStack"/>
      + *     <result name="success">good_result.ftl</result>
      + * </action>
      + * 
      + * 
      + * + * @author tm_jee + * @version $Date$ $Id$ + */ +public class ModelDrivenInterceptor extends AbstractInterceptor { + + protected boolean refreshModelBeforeResult = false; + + public void setRefreshModelBeforeResult(boolean val) { + this.refreshModelBeforeResult = val; + } + + @Override + public String intercept(ActionInvocation invocation) throws Exception { + Object action = invocation.getAction(); + + if (action instanceof ModelDriven) { + ModelDriven modelDriven = (ModelDriven) action; + ValueStack stack = invocation.getStack(); + Object model = modelDriven.getModel(); + if (model != null) { + stack.push(model); + } + if (refreshModelBeforeResult) { + invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model)); + } + } + return invocation.invoke(); + } + + /** + * Refreshes the model instance on the value stack, if it has changed + */ + protected static class RefreshModelBeforeResult implements PreResultListener { + private Object originalModel; + protected ModelDriven action; + + + public RefreshModelBeforeResult(ModelDriven action, Object model) { + this.originalModel = model; + this.action = action; + } + + public void beforeResult(ActionInvocation invocation, String resultCode) { + ValueStack stack = invocation.getStack(); + CompoundRoot root = stack.getRoot(); + + boolean needsRefresh = true; + Object newModel = action.getModel(); + + // Check to see if the new model instance is already on the stack + if (newModel != null) { + for (Object item : root) { + if (item == newModel) { + needsRefresh = false; + break; + } + } + } + + // Add the new model on the stack + if (needsRefresh) { + + // Clear off the old model instance + if (originalModel != null) { + root.remove(originalModel); + } + if (newModel != null) { + stack.push(newModel); + } + } + } + } +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/ParameterRemoverInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/ParameterRemoverInterceptor.java new file mode 100644 index 000000000..ad72d5853 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/ParameterRemoverInterceptor.java @@ -0,0 +1,124 @@ +/* + * 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.interceptor; + +import com.opensymphony.xwork2.util.TextParseUtil; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.struts2.ActionContext; +import org.apache.struts2.ActionInvocation; +import org.apache.struts2.action.NoParameters; +import org.apache.struts2.dispatcher.HttpParameters; +import org.apache.struts2.dispatcher.Parameter; + +import java.util.Collections; +import java.util.Set; + +/** + * This is a simple XWork interceptor that allows parameters (matching + * one of the paramNames attribute csv value) to be + * removed from the parameter map if they match a certain value + * (matching one of the paramValues attribute csv value), before they + * are set on the action. A typical usage would be to want a dropdown/select + * to map onto a boolean value on an action. The select had the options + * none, yes and no with values -1, true and false. The true and false would + * map across correctly. However the -1 would be set to false. + * This was not desired as one might needed the value on the action to stay null. + * This interceptor fixes this by preventing the parameter from ever reaching + * the action. + * + *
        + *
      • paramNames - A comma separated value (csv) indicating the parameter name + * whose param value should be considered that if they match any of the + * comma separated value (csv) from paramValues attribute, shall be + * removed from the parameter map such that they will not be applied + * to the action
      • + *
      • paramValues - A comma separated value (csv) indicating the parameter value that if + * matched shall have its parameter be removed from the parameter map + * such that they will not be applied to the action
      • + *
      + *

      + * No intended extension point + * + *

      + * <action name="sample" class="org.martingilday.Sample">
      + * 	<interceptor-ref name="paramRemover">
      + *          <param name="paramNames">aParam,anotherParam</param>
      + *          <param name="paramValues">--,-1</param>
      + * 	</interceptor-ref>
      + * 	<interceptor-ref name="defaultStack" />
      + * 	...
      + * </action>
      + * 
      + */ +public class ParameterRemoverInterceptor extends AbstractInterceptor { + + private static final Logger LOG = LogManager.getLogger(ParameterRemoverInterceptor.class); + + private Set paramNames = Collections.emptySet(); + private Set paramValues = Collections.emptySet(); + + /** + * Decide if the parameter should be removed from the parameter map based on + * paramNames and paramValues. + * + * @see AbstractInterceptor + */ + @Override + public String intercept(ActionInvocation invocation) throws Exception { + if (!(invocation.getAction() instanceof NoParameters) + && (null != this.paramNames)) { + ActionContext ac = invocation.getInvocationContext(); + HttpParameters parameters = ac.getParameters(); + + if (parameters != null) { + for (String removeName : paramNames) { + try { + Parameter parameter = parameters.get(removeName); + if (parameter.isDefined() && this.paramValues.contains(parameter.getValue())) { + parameters.remove(removeName); + } + } catch (Exception e) { + LOG.error("Failed to convert parameter to string", e); + } + } + } + } + return invocation.invoke(); + } + + /** + * Allows paramNames attribute to be set as comma-separated-values (csv). + * + * @param paramNames the paramNames to set + */ + public void setParamNames(String paramNames) { + this.paramNames = TextParseUtil.commaDelimitedStringToSet(paramNames); + } + + /** + * Allows paramValues attribute to be set as a comma-separated-values (csv). + * + * @param paramValues the paramValues to set + */ + public void setParamValues(String paramValues) { + this.paramValues = TextParseUtil.commaDelimitedStringToSet(paramValues); + } + +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/PrepareInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/PrepareInterceptor.java new file mode 100644 index 000000000..a410c3b12 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/PrepareInterceptor.java @@ -0,0 +1,177 @@ +/* + * 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.interceptor; + +import com.opensymphony.xwork2.interceptor.PrefixMethodInvocationUtil; +import org.apache.struts2.ActionInvocation; +import org.apache.struts2.Preparable; + +import java.lang.reflect.InvocationTargetException; + +/** + * + * + * This interceptor calls prepare() on actions which implement + * {@link Preparable}. This interceptor is very useful for any situation where + * you need to ensure some logic runs before the actual execute method runs. + * + *

      + * A typical use of this is to run some logic to load an object from the + * database so that when parameters are set they can be set on this object. For + * example, suppose you have a User object with two properties: id and + * name. Provided that the params interceptor is called twice (once + * before and once after this interceptor), you can load the User object using + * the id property, and then when the second params interceptor is called the + * parameter user.name will be set, as desired, on the actual object + * loaded from the database. See the example for more info. + *

      + *

      + * Note: Since XWork 2.0.2, this interceptor extends {@link MethodFilterInterceptor}, therefore being + * able to deal with excludeMethods / includeMethods parameters. See [Workflow Interceptor] + * (class {@link DefaultWorkflowInterceptor}) for documentation and examples on how to use this feature. + *

      + * + *

      + * Update: Added logic to execute a prepare{MethodName} and conditionally + * the a general prepare() Method, depending on the 'alwaysInvokePrepare' parameter/property + * which is by default true. This allows us to run some logic based on the method + * name we specify in the {@link org.apache.struts2.ActionProxy}. For example, you can specify a + * prepareInput() method that will be run before the invocation of the input method. + *

      + * + * + * + *

      Interceptor parameters:

      + * + * + * + *
        + * + *
      • alwaysInvokePrepare - Default to true. If true, prepare will always be invoked, + * otherwise it will not.
      • + * + *
      + * + * + * + *

      Extending the interceptor:

      + * + * + * + * There are no known extension points to this interceptor. + * + * + * + *

      Example code:

      + * + *
      + * 
      + * <!-- Calls the params interceptor twice, allowing you to
      + *       pre-load data for the second time parameters are set -->
      + *  <action name="someAction" class="com.examples.SomeAction">
      + *      <interceptor-ref name="params"/>
      + *      <interceptor-ref name="prepare"/>
      + *      <interceptor-ref name="basicStack"/>
      + *      <result name="success">good_result.ftl</result>
      + *  </action>
      + * 
      + * 
      + * + * @author Jason Carreira + * @author Philip Luppens + * @author tm_jee + * @see Preparable + */ +public class PrepareInterceptor extends MethodFilterInterceptor { + + private static final long serialVersionUID = -5216969014510719786L; + + private final static String PREPARE_PREFIX = "prepare"; + private final static String ALT_PREPARE_PREFIX = "prepareDo"; + + private boolean alwaysInvokePrepare = true; + private boolean firstCallPrepareDo = false; + + /** + * Sets if the prepare method should always be executed. + *

      + * Default is true. + *

      + * + * @param alwaysInvokePrepare if prepare should always be executed or not. + */ + public void setAlwaysInvokePrepare(String alwaysInvokePrepare) { + this.alwaysInvokePrepare = Boolean.parseBoolean(alwaysInvokePrepare); + } + + /** + * Sets if the prepareDoXXX method should be called first + *

      + * Default is false for backward compatibility + *

      + * @param firstCallPrepareDo if prepareDoXXX should be called first + */ + public void setFirstCallPrepareDo(String firstCallPrepareDo) { + this.firstCallPrepareDo = Boolean.parseBoolean(firstCallPrepareDo); + } + + @Override + public String doIntercept(ActionInvocation invocation) throws Exception { + Object action = invocation.getAction(); + + if (action instanceof Preparable) { + try { + String[] prefixes; + if (firstCallPrepareDo) { + prefixes = new String[] {ALT_PREPARE_PREFIX, PREPARE_PREFIX}; + } else { + prefixes = new String[] {PREPARE_PREFIX, ALT_PREPARE_PREFIX}; + } + PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes); + } + catch (InvocationTargetException e) { + /* + * The invoked method threw an exception and reflection wrapped it + * in an InvocationTargetException. + * If possible re-throw the original exception so that normal + * exception handling will take place. + */ + Throwable cause = e.getCause(); + if (cause instanceof Exception) { + throw (Exception) cause; + } else if(cause instanceof Error) { + throw (Error) cause; + } else { + /* + * The cause is not an Exception or Error (must be Throwable) so + * just re-throw the wrapped exception. + */ + throw e; + } + } + + if (alwaysInvokePrepare) { + ((Preparable) action).prepare(); + } + } + + return invocation.invoke(); + } + +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/ScopedModelDrivenInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/ScopedModelDrivenInterceptor.java new file mode 100644 index 000000000..ddf426519 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/ScopedModelDrivenInterceptor.java @@ -0,0 +1,165 @@ +/* + * 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.interceptor; + +import com.opensymphony.xwork2.ObjectFactory; +import com.opensymphony.xwork2.config.entities.ActionConfig; +import com.opensymphony.xwork2.inject.Inject; +import org.apache.struts2.ActionContext; +import org.apache.struts2.ActionInvocation; +import org.apache.struts2.StrutsException; + +import java.lang.reflect.Method; +import java.util.Map; + +/** + * + * + * An interceptor that enables scoped model-driven actions. + * + *

      This interceptor only activates on actions that implement the {@link ScopedModelDriven} interface. If + * detected, it will retrieve the model class from the configured scope, then provide it to the Action.

      + * + * + * + *

      Interceptor parameters:

      + * + * + * + *
        + * + *
      • className - The model class name. Defaults to the class name of the object returned by the getModel() method.
      • + * + *
      • name - The key to use when storing or retrieving the instance in a scope. Defaults to the model + * class name.
      • + * + *
      • scope - The scope to store and retrieve the model. Defaults to 'request' but can also be 'session'.
      • + *
      + * + * + * + *

      Extending the interceptor:

      + * + * + * + * There are no known extension points for this interceptor. + * + * + * + *

      Example code:

      + * + *
      + * 
      + *
      + * <-- Basic usage -->
      + * <interceptor name="scopedModelDriven" class="org.apache.struts2.interceptor.ScopedModelDrivenInterceptor" />
      + *
      + * <-- Using all available parameters -->
      + * <interceptor name="gangsterForm" class="org.apache.struts2.interceptor.ScopedModelDrivenInterceptor">
      + *      <param name="scope">session</param>
      + *      <param name="name">gangsterForm</param>
      + *      <param name="className">com.opensymphony.example.GangsterForm</param>
      + *  </interceptor>
      + *
      + * 
      + * 
      + */ +public class ScopedModelDrivenInterceptor extends AbstractInterceptor { + + private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; + + private static final String GET_MODEL = "getModel"; + private String scope; + private String name; + private String className; + private ObjectFactory objectFactory; + + @Inject + public void setObjectFactory(ObjectFactory factory) { + this.objectFactory = factory; + } + + protected Object resolveModel(ObjectFactory factory, ActionContext actionContext, String modelClassName, String modelScope, String modelName) throws Exception { + Object model; + Map scopeMap = actionContext.getContextMap(); + if ("session".equals(modelScope)) { + scopeMap = actionContext.getSession(); + } + + model = scopeMap.get(modelName); + if (model == null) { + model = factory.buildBean(modelClassName, null); + scopeMap.put(modelName, model); + } + return model; + } + + @Override + public String intercept(ActionInvocation invocation) throws Exception { + Object action = invocation.getAction(); + + if (action instanceof ScopedModelDriven) { + ScopedModelDriven modelDriven = (ScopedModelDriven) action; + if (modelDriven.getModel() == null) { + ActionContext ctx = ActionContext.getContext(); + ActionConfig config = invocation.getProxy().getConfig(); + + String cName = className; + if (cName == null) { + try { + Method method = action.getClass().getMethod(GET_MODEL, EMPTY_CLASS_ARRAY); + Class cls = method.getReturnType(); + cName = cls.getName(); + } catch (NoSuchMethodException e) { + throw new StrutsException("The " + GET_MODEL + "() is not defined in action " + action.getClass() + "", config); + } + } + String modelName = name; + if (modelName == null) { + modelName = cName; + } + Object model = resolveModel(objectFactory, ctx, cName, scope, modelName); + modelDriven.setModel(model); + modelDriven.setScopeKey(modelName); + } + } + return invocation.invoke(); + } + + /** + * @param className the className to set + */ + public void setClassName(String className) { + this.className = className; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @param scope the scope to set + */ + public void setScope(String scope) { + this.scope = scope; + } +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/StaticParametersInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/StaticParametersInterceptor.java new file mode 100644 index 000000000..5b00ffca6 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/StaticParametersInterceptor.java @@ -0,0 +1,242 @@ +/* + * 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.interceptor; + +import com.opensymphony.xwork2.LocalizedTextProvider; +import com.opensymphony.xwork2.config.entities.ActionConfig; +import com.opensymphony.xwork2.config.entities.Parameterizable; +import com.opensymphony.xwork2.inject.Inject; +import com.opensymphony.xwork2.interceptor.ParametersInterceptor; +import com.opensymphony.xwork2.util.ClearableValueStack; +import com.opensymphony.xwork2.util.TextParseUtil; +import com.opensymphony.xwork2.util.ValueStackFactory; +import com.opensymphony.xwork2.util.reflection.ReflectionContextState; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.struts2.ActionContext; +import org.apache.struts2.ActionInvocation; +import org.apache.struts2.StrutsConstants; +import org.apache.struts2.dispatcher.HttpParameters; +import org.apache.struts2.util.ValueStack; + +import java.util.Collections; +import java.util.Map; + +/** + * + * + * This interceptor populates the action with the static parameters defined in the action configuration. If the action + * implements {@link Parameterizable}, a map of the static parameters will be also be passed directly to the action. + * The static params will be added to the request params map, unless "merge" is set to false. + * + *

      Parameters are typically defined with <param> elements within xwork.xml.

      + * + * + * + *

      Interceptor parameters:

      + * + * + * + *
        + * + *
      • None
      • + * + *
      + * + * + * + *

      Extending the interceptor:

      + * + * + * + *

      There are no extension points to this interceptor.

      + * + * + * + *

      Example code:

      + * + *
      + * 
      + * <action name="someAction" class="com.examples.SomeAction">
      + *     <interceptor-ref name="staticParams">
      + *          <param name="parse">true</param>
      + *          <param name="overwrite">false</param>
      + *     </interceptor-ref>
      + *     <result name="success">good_result.ftl</result>
      + * </action>
      + * 
      + * 
      + * + * @author Patrick Lightbody + */ +public class StaticParametersInterceptor extends AbstractInterceptor { + + private boolean parse; + private boolean overwrite; + private boolean merge = true; + private boolean devMode = false; + + private static final Logger LOG = LogManager.getLogger(StaticParametersInterceptor.class); + + private ValueStackFactory valueStackFactory; + private LocalizedTextProvider localizedTextProvider; + + @Inject + public void setValueStackFactory(ValueStackFactory valueStackFactory) { + this.valueStackFactory = valueStackFactory; + } + + @Inject(StrutsConstants.STRUTS_DEVMODE) + public void setDevMode(String mode) { + devMode = BooleanUtils.toBoolean(mode); + } + + @Inject + public void setLocalizedTextProvider(LocalizedTextProvider localizedTextProvider) { + this.localizedTextProvider = localizedTextProvider; + } + + public void setParse(String value) { + this.parse = BooleanUtils.toBoolean(value); + } + + public void setMerge(String value) { + this.merge = BooleanUtils.toBoolean(value); + } + + /** + * Overwrites already existing parameters from other sources. + * Static parameters are the successor over previously set parameters, if true. + * + * @param value enable overwrites of already existing parameters from other sources + */ + public void setOverwrite(String value) { + this.overwrite = BooleanUtils.toBoolean(value); + } + + @Override + public String intercept(ActionInvocation invocation) throws Exception { + ActionConfig config = invocation.getProxy().getConfig(); + Object action = invocation.getAction(); + + final Map parameters = config.getParams(); + + LOG.debug("Setting static parameters: {}", parameters); + + // for actions marked as Parameterizable, pass the static parameters directly + if (action instanceof Parameterizable) { + ((Parameterizable) action).setParams(parameters); + } + + if (parameters != null) { + ActionContext ac = ActionContext.getContext(); + Map contextMap = ac.getContextMap(); + try { + ReflectionContextState.setCreatingNullObjects(contextMap, true); + ReflectionContextState.setReportingConversionErrors(contextMap, true); + final ValueStack stack = ac.getValueStack(); + + ValueStack newStack = valueStackFactory.createValueStack(com.opensymphony.xwork2.util.ValueStack.adapt(stack)); + boolean clearableStack = newStack instanceof ClearableValueStack; + if (clearableStack) { + //if the stack's context can be cleared, do that to prevent OGNL + //from having access to objects in the stack, see XW-641 + ((ClearableValueStack)newStack).clearContextValues(); + Map context = newStack.getContext(); + ReflectionContextState.setCreatingNullObjects(context, true); + ReflectionContextState.setDenyMethodExecution(context, true); + ReflectionContextState.setReportingConversionErrors(context, true); + + //keep locale from original context + newStack.getActionContext().withLocale(stack.getActionContext().getLocale()); + } + + for (Map.Entry entry : parameters.entrySet()) { + Object val = entry.getValue(); + if (parse && val instanceof String) { + val = TextParseUtil.translateVariables(val.toString(), com.opensymphony.xwork2.util.ValueStack.adapt(stack)); + } + try { + newStack.setValue(entry.getKey(), val); + } catch (RuntimeException e) { + if (devMode) { + + String developerNotification = localizedTextProvider.findText(ParametersInterceptor.class, "devmode.notification", ActionContext.getContext().getLocale(), "Developer Notification:\n{0}", new Object[]{ + "Unexpected Exception caught setting '" + entry.getKey() + "' on '" + action.getClass() + ": " + e.getMessage() + }); + LOG.error(developerNotification); + if (action instanceof ValidationAware) { + ((ValidationAware) action).addActionMessage(developerNotification); + } + } + } + } + + if (clearableStack) { + stack.getActionContext().withConversionErrors(newStack.getActionContext().getConversionErrors()); + } + + if (merge) + addParametersToContext(ac, parameters); + } finally { + ReflectionContextState.setCreatingNullObjects(contextMap, false); + ReflectionContextState.setReportingConversionErrors(contextMap, false); + } + } + return invocation.invoke(); + } + + + /** + * @param ac The action context + * @return the parameters from the action mapping in the context. If none found, returns + * an empty map. + */ + protected Map retrieveParameters(ActionContext ac) { + ActionConfig config = ac.getActionInvocation().getProxy().getConfig(); + if (config != null) { + return config.getParams(); + } else { + return Collections.emptyMap(); + } + } + + /** + * Adds the parameters into context's ParameterMap. + * As default, static parameters will not overwrite existing parameters from other sources. + * If you want the static parameters as successor over already existing parameters, set overwrite to true. + * + * @param ac The action context + * @param newParams The parameter map to apply + */ + protected void addParametersToContext(ActionContext ac, Map newParams) { + HttpParameters previousParams = ac.getParameters(); + + HttpParameters.Builder combinedParams; + if (overwrite) { + combinedParams = HttpParameters.create().withParent( previousParams); + combinedParams = combinedParams.withExtraParams(newParams); + } else { + combinedParams = HttpParameters.create(newParams); + combinedParams = combinedParams.withExtraParams(previousParams); + } + ac.withParameters(combinedParams.build()); + } +} From 243244997590e0c1bcca8de3db82dfa1d7933ec7 Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Mon, 21 Oct 2024 18:51:15 +1100 Subject: [PATCH 29/33] WW-3714 Update StrutsResultSupport to allow overriding new signature --- .../struts2/result/StrutsResultSupport.java | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/apache/struts2/result/StrutsResultSupport.java b/core/src/main/java/org/apache/struts2/result/StrutsResultSupport.java index d5307d279..2ec5e987f 100644 --- a/core/src/main/java/org/apache/struts2/result/StrutsResultSupport.java +++ b/core/src/main/java/org/apache/struts2/result/StrutsResultSupport.java @@ -154,7 +154,7 @@ public abstract class StrutsResultSupport implements Result, StrutsStatics { public void setLocation(String location) { this.location = location; } - + /** * Gets the location it was created with, mainly for testing * @@ -201,9 +201,10 @@ public abstract class StrutsResultSupport implements Result, StrutsStatics { * @param invocation the execution state of the action. * @throws Exception if an error occurs while executing the result. */ + @Override public void execute(ActionInvocation invocation) throws Exception { lastFinalLocation = parseLocation ? conditionalParse(location, invocation) : location; - doExecute(lastFinalLocation, invocation); + doExecute(lastFinalLocation, (org.apache.struts2.ActionInvocation) invocation); } /** @@ -216,7 +217,7 @@ public abstract class StrutsResultSupport implements Result, StrutsStatics { protected String conditionalParse(String param, ActionInvocation invocation) { if (parse && param != null && invocation != null) { return TextParseUtil.translateVariables( - param, + param, invocation.getStack(), new EncodingParsedValueEvaluator()); } else { @@ -228,7 +229,7 @@ public abstract class StrutsResultSupport implements Result, StrutsStatics { * As {@link #conditionalParse(String, ActionInvocation)} but does not * convert found object into String. If found object is a collection it is * returned if found object is not a collection it is wrapped in one. - * + * * @param param parameter * @param invocation action invocation * @param excludeEmptyElements 'true' for excluding empty elements @@ -237,7 +238,7 @@ public abstract class StrutsResultSupport implements Result, StrutsStatics { protected Collection conditionalParseCollection(String param, ActionInvocation invocation, boolean excludeEmptyElements) { if (parse && param != null && invocation != null) { return TextParseUtil.translateVariablesCollection( - param, + param, invocation.getStack(), excludeEmptyElements, new EncodingParsedValueEvaluator()); @@ -251,9 +252,10 @@ public abstract class StrutsResultSupport implements Result, StrutsStatics { /** * {@link com.opensymphony.xwork2.util.TextParseUtil.ParsedValueEvaluator} to do URL encoding for found values. To be * used for single strings or collections. - * + * */ private final class EncodingParsedValueEvaluator implements TextParseUtil.ParsedValueEvaluator { + @Override public Object evaluate(String parsedValue) { if (encode) { if (parsedValue != null) { @@ -269,6 +271,13 @@ public abstract class StrutsResultSupport implements Result, StrutsStatics { } } + /** + * @deprecated since 6.7.0, override {@link #doExecute(String, org.apache.struts2.ActionInvocation)} instead. + */ + @Deprecated + protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception { + } + /** * Executes the result given a final location (jsp page, action, etc) and the action invocation * (the state in which the action was executed). Subclasses must implement this class to handle @@ -278,5 +287,7 @@ public abstract class StrutsResultSupport implements Result, StrutsStatics { * @param invocation the execution state of the action. * @throws Exception if an error occurs while executing the result. */ - protected abstract void doExecute(String finalLocation, ActionInvocation invocation) throws Exception; + protected void doExecute(String finalLocation, org.apache.struts2.ActionInvocation invocation) throws Exception { + doExecute(finalLocation, ActionInvocation.adapt(invocation)); + } } From 67e04779931f5fbb91a5390baae15a770923a1ca Mon Sep 17 00:00:00 2001 From: Lukasz Lenart Date: Fri, 25 Oct 2024 08:28:18 +0200 Subject: [PATCH 30/33] WW-5476 Deprecates tag's parameters as replaced with attributes --- .../struts2/components/ActionComponent.java | 4 +- .../apache/struts2/components/Component.java | 27 +++++++---- .../struts2/components/DoubleListUIBean.java | 4 +- .../struts2/components/DoubleSelect.java | 2 +- .../org/apache/struts2/components/File.java | 4 +- .../org/apache/struts2/components/Form.java | 10 ++-- .../apache/struts2/components/FormButton.java | 6 +-- .../apache/struts2/components/Include.java | 8 ++-- .../components/InputTransferSelect.java | 8 ++-- .../org/apache/struts2/components/Label.java | 2 +- .../apache/struts2/components/ListUIBean.java | 2 +- .../apache/struts2/components/OptGroup.java | 4 +- .../components/OptionTransferSelect.java | 16 +++---- .../components/ServletUrlRenderer.java | 2 +- .../org/apache/struts2/components/Token.java | 2 +- .../org/apache/struts2/components/UIBean.java | 20 ++++---- .../org/apache/struts2/components/URL.java | 2 +- .../struts2/components/UpDownSelect.java | 8 ++-- .../views/freemarker/ScopesHashModel.java | 27 ++++++++--- .../struts2/components/FormButtonTest.java | 22 ++++----- .../apache/struts2/components/FormTest.java | 6 +-- .../apache/struts2/components/UIBeanTest.java | 48 +++++++++---------- .../apache/struts2/views/jsp/URLTagTest.java | 12 ++--- .../struts2/views/jsp/ui/FormTagTest.java | 8 ++-- .../views/java/simple/SelectHandler.java | 8 ++-- .../simple/AbstractCommonAttributesTest.java | 6 +-- .../views/java/simple/ActionErrorTest.java | 6 +-- .../views/java/simple/ActionMessageTest.java | 6 +-- .../struts2/views/java/simple/AnchorTest.java | 8 ++-- .../views/java/simple/CheckboxTest.java | 6 +-- .../views/java/simple/DateTextFieldTest.java | 6 +-- .../views/java/simple/FieldErrorTest.java | 10 ++-- .../struts2/views/java/simple/FileTest.java | 2 +- .../struts2/views/java/simple/FormTest.java | 4 +- .../struts2/views/java/simple/HeadTest.java | 2 +- .../struts2/views/java/simple/HiddenTest.java | 2 +- .../struts2/views/java/simple/LabelTest.java | 2 +- .../struts2/views/java/simple/LinkTest.java | 4 +- .../views/java/simple/PasswordTest.java | 4 +- .../struts2/views/java/simple/ResetTest.java | 4 +- .../struts2/views/java/simple/ScriptTest.java | 2 +- .../struts2/views/java/simple/SelectTest.java | 10 ++-- .../struts2/views/java/simple/SubmitTest.java | 16 +++---- .../views/java/simple/TextAreaTest.java | 4 +- .../views/java/simple/TextFieldTest.java | 2 +- .../struts2/views/java/simple/TokenTest.java | 2 +- .../components/PortletUrlRenderer.java | 2 +- 47 files changed, 198 insertions(+), 174 deletions(-) diff --git a/core/src/main/java/org/apache/struts2/components/ActionComponent.java b/core/src/main/java/org/apache/struts2/components/ActionComponent.java index 521db09c0..d0c25404a 100644 --- a/core/src/main/java/org/apache/struts2/components/ActionComponent.java +++ b/core/src/main/java/org/apache/struts2/components/ActionComponent.java @@ -215,8 +215,8 @@ public class ActionComponent extends ContextBean { HttpParameters.Builder builder = HttpParameters.create().withParent(parentParams); - if (parameters != null) { - builder = builder.withExtraParams(parameters); + if (attributes != null) { + builder = builder.withExtraParams(attributes); } return builder.build(); } diff --git a/core/src/main/java/org/apache/struts2/components/Component.java b/core/src/main/java/org/apache/struts2/components/Component.java index ba0d672bf..74bd0f747 100644 --- a/core/src/main/java/org/apache/struts2/components/Component.java +++ b/core/src/main/java/org/apache/struts2/components/Component.java @@ -71,7 +71,7 @@ public class Component { protected boolean devMode = false; protected boolean escapeHtmlBody = false; protected ValueStack stack; - protected Map parameters; + protected Map attributes; protected ActionMapper actionMapper; protected boolean throwExceptionOnELFailure; protected boolean performClearTagStateForTagPoolingServers = false; @@ -86,7 +86,7 @@ public class Component { */ public Component(ValueStack stack) { this.stack = stack; - this.parameters = new LinkedHashMap<>(); + this.attributes = new LinkedHashMap<>(); getComponentStack().push(this); } @@ -279,7 +279,7 @@ public class Component { */ protected StrutsException fieldError(String field, String errorMsg, Exception e) { String msg = "tag '" + getComponentName() + "', field '" + field + - (parameters != null && parameters.containsKey("name") ? "', name '" + parameters.get("name") : "") + + (attributes != null && attributes.containsKey("name") ? "', name '" + attributes.get("name") : "") + "': " + errorMsg; throw new StrutsException(msg, e); } @@ -457,7 +457,7 @@ public class Component { * @param params the parameters to copy. */ public void copyParams(Map params) { - stack.push(parameters); + stack.push(attributes); stack.push(this); try { for (Map.Entry entry : params.entrySet()) { @@ -467,7 +467,7 @@ public class Component { // UI component attributes may contain hypens (e.g. data-ajax), but ognl // can't handle that, and there can't be a component property with a hypen // so into the parameters map it goes. See WW-4493 - parameters.put(key, entry.getValue()); + attributes.put(key, entry.getValue()); } else { stack.setValue(key, entry.getValue()); } @@ -496,9 +496,20 @@ public class Component { * Gets the parameters. * * @return the parameters. Is never null. + * @deprecated since 6.7.0, use {@link #getAttributes()} instead */ + @Deprecated public Map getParameters() { - return parameters; + return attributes; + } + + /** + * Gets the parameters. + * + * @return the parameters. Is never null. + */ + public Map getAttributes() { + return attributes; } /** @@ -507,7 +518,7 @@ public class Component { * @param params the parameters to add. */ public void addAllParameters(Map params) { - parameters.putAll(params); + attributes.putAll(params); } /** @@ -522,7 +533,7 @@ public class Component { */ public void addParameter(String key, Object value) { if (key != null) { - Map params = getParameters(); + Map params = getAttributes(); if (value == null) { params.remove(key); diff --git a/core/src/main/java/org/apache/struts2/components/DoubleListUIBean.java b/core/src/main/java/org/apache/struts2/components/DoubleListUIBean.java index 9c4e30a0c..e965b178f 100644 --- a/core/src/main/java/org/apache/struts2/components/DoubleListUIBean.java +++ b/core/src/main/java/org/apache/struts2/components/DoubleListUIBean.java @@ -164,7 +164,7 @@ public abstract class DoubleListUIBean extends ListUIBean { // ok, let's look it up Component form = findAncestor(Form.class); if (form != null) { - addParameter("formName", form.getParameters().get("name")); + addParameter("formName", form.getAttributes().get("name")); } } @@ -188,7 +188,7 @@ public abstract class DoubleListUIBean extends ListUIBean { if (doubleId != null) { addParameter("doubleId", findString(doubleId)); } else if (form != null) { - addParameter("doubleId", form.getParameters().get("id") + "_" + escape(doubleName != null ? findString(doubleName) : null)); + addParameter("doubleId", form.getAttributes().get("id") + "_" + escape(doubleName != null ? findString(doubleName) : null)); } else { addParameter("doubleId", escape(doubleName != null ? findString(doubleName) : null)); } diff --git a/core/src/main/java/org/apache/struts2/components/DoubleSelect.java b/core/src/main/java/org/apache/struts2/components/DoubleSelect.java index a6f96b114..ea574f6a7 100644 --- a/core/src/main/java/org/apache/struts2/components/DoubleSelect.java +++ b/core/src/main/java/org/apache/struts2/components/DoubleSelect.java @@ -57,7 +57,7 @@ public class DoubleSelect extends DoubleListUIBean { public void evaluateExtraParams() { super.evaluateExtraParams(); StringBuilder onchangeParam = new StringBuilder(); - onchangeParam.append(getParameters().get("id")).append("Redirect(this.selectedIndex)"); + onchangeParam.append(getAttributes().get("id")).append("Redirect(this.selectedIndex)"); if(StringUtils.isNotEmpty(this.onchange)) { onchangeParam.append(";").append(this.onchange); } 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 f93ac7742..2cb6719a6 100644 --- a/core/src/main/java/org/apache/struts2/components/File.java +++ b/core/src/main/java/org/apache/struts2/components/File.java @@ -68,13 +68,13 @@ public class File extends UIBean { Form form = (Form) findAncestor(Form.class); if (form != null) { - String encType = (String) form.getParameters().get("enctype"); + String encType = (String) form.getAttributes().get("enctype"); if (!"multipart/form-data".equals(encType)) { // uh oh, this isn't good! Let's warn the developer LOG.warn("Struts has detected a file upload UI tag (s:file) being used without a form set to enctype 'multipart/form-data'. This is probably an error!"); } - String method = (String) form.getParameters().get("method"); + String method = (String) form.getAttributes().get("method"); if (!"post".equalsIgnoreCase(method)) { // uh oh, this isn't good! Let's warn the developer LOG.warn("Struts has detected a file upload UI tag (s:file) being used without a form set to method 'POST'. This is probably an error!"); diff --git a/core/src/main/java/org/apache/struts2/components/Form.java b/core/src/main/java/org/apache/struts2/components/Form.java index 92758fbee..bb7493881 100644 --- a/core/src/main/java/org/apache/struts2/components/Form.java +++ b/core/src/main/java/org/apache/struts2/components/Form.java @@ -172,7 +172,7 @@ public class Form extends ClosingUIBean { if (name == null) { //make the name the same as the id - String id = (String) getParameters().get("id"); + String id = (String) getAttributes().get("id"); if (StringUtils.isNotEmpty(id)) { addParameter("name", id); } @@ -204,7 +204,7 @@ public class Form extends ClosingUIBean { // keep a collection of the tag names for anything special the templates might want to do (such as pure client // side validation) - if (!parameters.containsKey("tagNames")) { + if (!attributes.containsKey("tagNames")) { // we have this if check so we don't do this twice (on open and close of the template) addParameter("tagNames", new ArrayList()); } @@ -242,7 +242,7 @@ public class Form extends ClosingUIBean { protected void evaluateClientSideJsEnablement(String actionName, String namespace, String actionMethod) { // Only evaluate if Client-Side js is to be enable when validate=true - Boolean validate = (Boolean) getParameters().get("validate"); + Boolean validate = (Boolean) getAttributes().get("validate"); if (validate != null && validate) { addParameter("performValidation", Boolean.FALSE); @@ -270,7 +270,7 @@ public class Form extends ClosingUIBean { } public List getValidators(String name) { - Class actionClass = (Class) getParameters().get("actionClass"); + Class actionClass = (Class) getAttributes().get("actionClass"); if (actionClass == null) { return Collections.EMPTY_LIST; } @@ -279,7 +279,7 @@ public class Form extends ClosingUIBean { ActionMapping mapping = actionMapper.getMappingFromActionName(formActionValue); if (mapping == null) { - mapping = actionMapper.getMappingFromActionName((String) getParameters().get("actionName")); + mapping = actionMapper.getMappingFromActionName((String) getAttributes().get("actionName")); } if (mapping == null) { diff --git a/core/src/main/java/org/apache/struts2/components/FormButton.java b/core/src/main/java/org/apache/struts2/components/FormButton.java index 0ed08d47b..e028f546c 100644 --- a/core/src/main/java/org/apache/struts2/components/FormButton.java +++ b/core/src/main/java/org/apache/struts2/components/FormButton.java @@ -58,7 +58,7 @@ public abstract class FormButton extends ClosingUIBean { addParameter("type", submitType); if (!BUTTON_TYPE_INPUT.equals(submitType) && (label == null)) { - addParameter("label", getParameters().get("nameValue")); + addParameter("label", getAttributes().get("nameValue")); } if (action != null || method != null) { @@ -101,8 +101,8 @@ public abstract class FormButton extends ClosingUIBean { // this check is needed for backwards compatibility with 2.1.x tmpId = findString(id); } else { - if (form != null && form.getParameters().get("id") != null) { - tmpId = tmpId + form.getParameters().get("id").toString() + "_"; + if (form != null && form.getAttributes().get("id") != null) { + tmpId = tmpId + form.getAttributes().get("id").toString() + "_"; } if (name != null) { tmpId = tmpId + escape(findString(name)); diff --git a/core/src/main/java/org/apache/struts2/components/Include.java b/core/src/main/java/org/apache/struts2/components/Include.java index 2e1f862dd..83e4bd5ad 100644 --- a/core/src/main/java/org/apache/struts2/components/Include.java +++ b/core/src/main/java/org/apache/struts2/components/Include.java @@ -137,13 +137,13 @@ public class Include extends Component { urlBuf.append(page); // Add request parameters - if (parameters.size() > 0) { + if (attributes.size() > 0) { urlBuf.append('?'); String concat = ""; // Set parameters - for (Object next : parameters.entrySet()) { + for (Object next : attributes.entrySet()) { Map.Entry entry = (Map.Entry) next; Object name = entry.getKey(); List values = (List) entry.getValue(); @@ -234,11 +234,11 @@ public class Include extends Component { // instead, include tag requires that each parameter be a list of objects, // just like the HTTP servlet interfaces are (String[]) if (value != null) { - List currentValues = (List) parameters.get(key); + List currentValues = (List) attributes.get(key); if (currentValues == null) { currentValues = new ArrayList(); - parameters.put(key, currentValues); + attributes.put(key, currentValues); } currentValues.add(value); diff --git a/core/src/main/java/org/apache/struts2/components/InputTransferSelect.java b/core/src/main/java/org/apache/struts2/components/InputTransferSelect.java index 762bafc5b..cb6111e00 100644 --- a/core/src/main/java/org/apache/struts2/components/InputTransferSelect.java +++ b/core/src/main/java/org/apache/struts2/components/InputTransferSelect.java @@ -174,7 +174,7 @@ public class InputTransferSelect extends ListUIBean { // key -> select tag id, value -> headerKey (if exists) - Map formInputtransferselectIds = (Map) formAncestor.getParameters().get("inputtransferselectIds"); + Map formInputtransferselectIds = (Map) formAncestor.getAttributes().get("inputtransferselectIds"); // init lists if (formInputtransferselectIds == null) { @@ -182,13 +182,13 @@ public class InputTransferSelect extends ListUIBean { } // id - String tmpId = (String) getParameters().get("id"); - String tmpHeaderKey = (String) getParameters().get("headerKey"); + String tmpId = (String) getAttributes().get("id"); + String tmpHeaderKey = (String) getAttributes().get("headerKey"); if (tmpId != null && (! formInputtransferselectIds.containsKey(tmpId))) { formInputtransferselectIds.put(tmpId, tmpHeaderKey); } - formAncestor.getParameters().put("inputtransferselectIds", formInputtransferselectIds); + formAncestor.getAttributes().put("inputtransferselectIds", formInputtransferselectIds); } else { diff --git a/core/src/main/java/org/apache/struts2/components/Label.java b/core/src/main/java/org/apache/struts2/components/Label.java index c09b88c80..cf166f658 100644 --- a/core/src/main/java/org/apache/struts2/components/Label.java +++ b/core/src/main/java/org/apache/struts2/components/Label.java @@ -81,7 +81,7 @@ public class Label extends UIBean { if (value != null) { addParameter("nameValue", findString(value)); } else if (key != null) { - Object nameValue = parameters.get("nameValue"); + Object nameValue = attributes.get("nameValue"); if (nameValue == null || nameValue.toString().length() == 0) { // get the label from a TextProvider (default value is the key) String providedLabel = TextProviderHelper.getText(key, key, stack); diff --git a/core/src/main/java/org/apache/struts2/components/ListUIBean.java b/core/src/main/java/org/apache/struts2/components/ListUIBean.java index bfaffe6f1..b090fc674 100644 --- a/core/src/main/java/org/apache/struts2/components/ListUIBean.java +++ b/core/src/main/java/org/apache/struts2/components/ListUIBean.java @@ -67,7 +67,7 @@ public abstract class ListUIBean extends UIBean { Object value = null; if (list == null) { - list = parameters.get("list"); + list = attributes.get("list"); } if (list instanceof String) { diff --git a/core/src/main/java/org/apache/struts2/components/OptGroup.java b/core/src/main/java/org/apache/struts2/components/OptGroup.java index 5f2e2ace2..6916146d4 100644 --- a/core/src/main/java/org/apache/struts2/components/OptGroup.java +++ b/core/src/main/java/org/apache/struts2/components/OptGroup.java @@ -90,7 +90,7 @@ public class OptGroup extends Component { } }; } - + @Inject public void setContainer(Container container) { container.inject(internalUiBean); @@ -106,7 +106,7 @@ public class OptGroup extends Component { internalUiBean.start(writer); internalUiBean.end(writer, body); - List listUiBeans = (List) select.getParameters().get(INTERNAL_LIST_UI_BEAN_LIST_PARAMETER_KEY); + List listUiBeans = (List) select.getAttributes().get(INTERNAL_LIST_UI_BEAN_LIST_PARAMETER_KEY); if (listUiBeans == null) { listUiBeans = new ArrayList(); } diff --git a/core/src/main/java/org/apache/struts2/components/OptionTransferSelect.java b/core/src/main/java/org/apache/struts2/components/OptionTransferSelect.java index bdc4905df..a548ee76c 100644 --- a/core/src/main/java/org/apache/struts2/components/OptionTransferSelect.java +++ b/core/src/main/java/org/apache/struts2/components/OptionTransferSelect.java @@ -287,8 +287,8 @@ public class OptionTransferSelect extends DoubleListUIBean { // key -> select tag id, value -> headerKey (if exists) - Map formOptiontransferselectIds = (Map) formAncestor.getParameters().get("optiontransferselectIds"); - Map formOptiontransferselectDoubleIds = (Map) formAncestor.getParameters().get("optiontransferselectDoubleIds"); + Map formOptiontransferselectIds = (Map) formAncestor.getAttributes().get("optiontransferselectIds"); + Map formOptiontransferselectDoubleIds = (Map) formAncestor.getAttributes().get("optiontransferselectDoubleIds"); // init lists if (formOptiontransferselectIds == null) { @@ -300,21 +300,21 @@ public class OptionTransferSelect extends DoubleListUIBean { // id - String tmpId = (String) getParameters().get("id"); - String tmpHeaderKey = (String) getParameters().get("headerKey"); + String tmpId = (String) getAttributes().get("id"); + String tmpHeaderKey = (String) getAttributes().get("headerKey"); if (tmpId != null && (! formOptiontransferselectIds.containsKey(tmpId))) { formOptiontransferselectIds.put(tmpId, tmpHeaderKey); } // doubleId - String tmpDoubleId = (String) getParameters().get("doubleId"); - String tmpDoubleHeaderKey = (String) getParameters().get("doubleHeaderKey"); + String tmpDoubleId = (String) getAttributes().get("doubleId"); + String tmpDoubleHeaderKey = (String) getAttributes().get("doubleHeaderKey"); if (tmpDoubleId != null && (! formOptiontransferselectDoubleIds.containsKey(tmpDoubleId))) { formOptiontransferselectDoubleIds.put(tmpDoubleId, tmpDoubleHeaderKey); } - formAncestor.getParameters().put("optiontransferselectIds", formOptiontransferselectIds); - formAncestor.getParameters().put("optiontransferselectDoubleIds", formOptiontransferselectDoubleIds); + formAncestor.getAttributes().put("optiontransferselectIds", formOptiontransferselectIds); + formAncestor.getAttributes().put("optiontransferselectDoubleIds", formOptiontransferselectDoubleIds); } else { diff --git a/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java b/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java index 460aeebff..fb2cc85f2 100644 --- a/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java +++ b/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java @@ -174,7 +174,7 @@ public class ServletUrlRenderer implements UrlRenderer { namespace, actionName); if (actionConfig != null) { - ActionMapping mapping = new ActionMapping(actionName, namespace, actionMethod, formComponent.parameters); + ActionMapping mapping = new ActionMapping(actionName, namespace, actionMethod, formComponent.attributes); String result = urlHelper.buildUrl(formComponent.actionMapper.getUriFromActionMapping(mapping), formComponent.request, formComponent.response, queryStringResult.getQueryParams(), scheme, formComponent.includeContext, true, false, false); formComponent.addParameter("action", result); diff --git a/core/src/main/java/org/apache/struts2/components/Token.java b/core/src/main/java/org/apache/struts2/components/Token.java index 53a361f4f..c49a29cce 100644 --- a/core/src/main/java/org/apache/struts2/components/Token.java +++ b/core/src/main/java/org/apache/struts2/components/Token.java @@ -73,7 +73,7 @@ public class Token extends UIBean { super.evaluateExtraParams(); String tokenName; - Map parameters = getParameters(); + Map parameters = getAttributes(); if (parameters.containsKey("name")) { tokenName = (String) parameters.get("name"); 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 c787fd100..4d6897a4b 100644 --- a/core/src/main/java/org/apache/struts2/components/UIBean.java +++ b/core/src/main/java/org/apache/struts2/components/UIBean.java @@ -591,7 +591,7 @@ public abstract class UIBean extends Component { LOG.debug("Rendering template {}", template); - final TemplateRenderingContext context = new TemplateRenderingContext(template, writer, getStack(), getParameters(), this); + final TemplateRenderingContext context = new TemplateRenderingContext(template, writer, getStack(), getAttributes(), this); engine.renderTemplate(context); } @@ -797,11 +797,11 @@ public abstract class UIBean extends Component { populateComponentHtmlId(form); if (form != null ) { - addParameter("form", form.getParameters()); + addParameter("form", form.getAttributes()); if ( translatedName != null ) { // list should have been created by the form component - List tags = (List) form.getParameters().get("tagNames"); + List tags = (List) form.getAttributes().get("tagNames"); tags.add(translatedName); } } @@ -833,19 +833,19 @@ public abstract class UIBean extends Component { } //TODO: this is to keep backward compatibility, remove once when tooltipConfig is dropped - String jsTooltipEnabled = (String) getParameters().get("jsTooltipEnabled"); + String jsTooltipEnabled = (String) getAttributes().get("jsTooltipEnabled"); if (jsTooltipEnabled != null) this.javascriptTooltip = jsTooltipEnabled; //TODO: this is to keep backward compatibility, remove once when tooltipConfig is dropped - String tooltipIcon = (String) getParameters().get("tooltipIcon"); + String tooltipIcon = (String) getAttributes().get("tooltipIcon"); if (tooltipIcon != null) this.addParameter("tooltipIconPath", tooltipIcon); if (this.tooltipIconPath != null) this.addParameter("tooltipIconPath", findString(this.tooltipIconPath)); //TODO: this is to keep backward compatibility, remove once when tooltipConfig is dropped - String tooltipDelayParam = (String) getParameters().get("tooltipDelay"); + String tooltipDelayParam = (String) getAttributes().get("tooltipDelay"); if (tooltipDelayParam != null) this.addParameter("tooltipDelay", tooltipDelayParam); if (this.tooltipDelay != null) @@ -882,8 +882,8 @@ public abstract class UIBean extends Component { */ protected void applyValueParameter(String translatedName) { // see if the value has been specified as a parameter already - if (parameters.containsKey(ATTR_VALUE)) { - parameters.put(ATTR_NAME_VALUE, parameters.get(ATTR_VALUE)); + if (attributes.containsKey(ATTR_VALUE)) { + attributes.put(ATTR_NAME_VALUE, attributes.get(ATTR_VALUE)); } else { if (evaluateNameValue()) { final Class valueClazz = getValueClassType(); @@ -969,7 +969,7 @@ public abstract class UIBean extends Component { } protected Map getTooltipConfig(UIBean component) { - Object tooltipConfigObj = component.getParameters().get("tooltipConfig"); + Object tooltipConfigObj = component.getAttributes().get("tooltipConfig"); Map result = new LinkedHashMap<>(); if (tooltipConfigObj instanceof Map) { @@ -1030,7 +1030,7 @@ public abstract class UIBean extends Component { LOG.debug("Cannot determine id attribute for [{}], consider defining id, name or key attribute!", this); tryId = null; } else if (form != null) { - tryId = form.getParameters().get("id") + "_" + generatedId; + tryId = form.getAttributes().get("id") + "_" + generatedId; } else { tryId = generatedId; } diff --git a/core/src/main/java/org/apache/struts2/components/URL.java b/core/src/main/java/org/apache/struts2/components/URL.java index 0656340d4..e98d41cf9 100644 --- a/core/src/main/java/org/apache/struts2/components/URL.java +++ b/core/src/main/java/org/apache/struts2/components/URL.java @@ -111,7 +111,7 @@ public class URL extends ContextBean { public URL(ValueStack stack, HttpServletRequest req, HttpServletResponse res) { super(stack); - urlProvider = new ComponentUrlProvider(this, this.parameters); + urlProvider = new ComponentUrlProvider(this, this.attributes); urlProvider.setHttpServletRequest(req); urlProvider.setHttpServletResponse(res); } diff --git a/core/src/main/java/org/apache/struts2/components/UpDownSelect.java b/core/src/main/java/org/apache/struts2/components/UpDownSelect.java index 77dd5d67d..171ac65b9 100644 --- a/core/src/main/java/org/apache/struts2/components/UpDownSelect.java +++ b/core/src/main/java/org/apache/struts2/components/UpDownSelect.java @@ -70,7 +70,7 @@ import java.util.Map; * {@literal @}s.tag name="updownselect" tld-body-content="JSP" tld-tag-class="org.apache.struts2.views.jsp.ui.UpDownSelectTag" * description="Render a up down select element" */ -@StrutsTag(name="updownselect", tldTagClass="org.apache.struts2.views.jsp.ui.UpDownSelectTag", +@StrutsTag(name="updownselect", tldTagClass="org.apache.struts2.views.jsp.ui.UpDownSelectTag", description="Create a Select component with buttons to move the elements in the select component up and down") public class UpDownSelect extends Select { @@ -136,13 +136,13 @@ public class UpDownSelect extends Select { // inform form ancestor that we are using a custom onSubmit enableAncestorFormCustomOnsubmit(); - Map m = (Map) ancestorForm.getParameters().get("updownselectIds"); + Map m = (Map) ancestorForm.getAttributes().get("updownselectIds"); if (m == null) { // map with key -> id , value -> headerKey m = new LinkedHashMap(); } - m.put(getParameters().get("id"), getParameters().get("headerKey")); - ancestorForm.getParameters().put("updownselectIds", m); + m.put(getAttributes().get("id"), getAttributes().get("headerKey")); + ancestorForm.getAttributes().put("updownselectIds", m); } else { if (LOG.isWarnEnabled()) { diff --git a/core/src/main/java/org/apache/struts2/views/freemarker/ScopesHashModel.java b/core/src/main/java/org/apache/struts2/views/freemarker/ScopesHashModel.java index 441566670..33be31466 100644 --- a/core/src/main/java/org/apache/struts2/views/freemarker/ScopesHashModel.java +++ b/core/src/main/java/org/apache/struts2/views/freemarker/ScopesHashModel.java @@ -23,6 +23,8 @@ import freemarker.template.ObjectWrapper; import freemarker.template.SimpleHash; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; @@ -49,11 +51,19 @@ public class ScopesHashModel extends SimpleHash implements TemplateModel { private static final long serialVersionUID = 5551686380141886764L; + private static final Logger LOG = LogManager.getLogger(ScopesHashModel.class); + private static final String TAG_ATTRIBUTES = "attributes"; + /** + * @deprecated since 6.7.0, use {@link #TAG_ATTRIBUTES} instead + */ + @Deprecated + private static final String TAG_PARAMETERS = "parameters"; + private HttpServletRequest request; private ServletContext servletContext; private ValueStack stack; private final Map unlistedModels = new HashMap<>(); - private volatile Object parametersCache; + private volatile Object attributesCache; public ScopesHashModel(ObjectWrapper objectWrapper, ServletContext context, HttpServletRequest request, ValueStack stack) { super(objectWrapper); @@ -94,6 +104,9 @@ public class ScopesHashModel extends SimpleHash implements TemplateModel { if (obj != null) { return wrap(obj); + } else if (TAG_ATTRIBUTES.equals(key) || TAG_PARAMETERS.equals(key)) { + LOG.warn("[{}] cannot be resolved against stack, short-circuiting!", key); + return null; } // ok, then try the context @@ -143,13 +156,13 @@ public class ScopesHashModel extends SimpleHash implements TemplateModel { } private Object findValueOnStack(final String key) { - if ("parameters".equals(key)) { - if (parametersCache != null) { - return parametersCache; + if (TAG_ATTRIBUTES.equals(key) || TAG_PARAMETERS.equals(key)) { + if (attributesCache != null) { + return attributesCache; } - Object parametersLocal = stack.findValue(key); - parametersCache = parametersLocal; - return parametersLocal; + Object attributesLocal = stack.findValue(key); + attributesCache = attributesLocal; + return attributesLocal; } return stack.findValue(key); } diff --git a/core/src/test/java/org/apache/struts2/components/FormButtonTest.java b/core/src/test/java/org/apache/struts2/components/FormButtonTest.java index 429ecfd6c..ad6b3f764 100644 --- a/core/src/test/java/org/apache/struts2/components/FormButtonTest.java +++ b/core/src/test/java/org/apache/struts2/components/FormButtonTest.java @@ -38,14 +38,14 @@ public class FormButtonTest extends StrutsInternalTestCase { ValueStack stack = ActionContext.getContext().getValueStack(); Form form = new Form(stack, req, res); - form.getParameters().put("id", "formId"); + form.getAttributes().put("id", "formId"); Submit submit = new Submit(stack, req, res); submit.setId("submitId"); submit.populateComponentHtmlId(form); - assertEquals("submitId", submit.getParameters().get("id")); + assertEquals("submitId", submit.getAttributes().get("id")); } public void testPopulateComponentHtmlId2() { @@ -54,14 +54,14 @@ public class FormButtonTest extends StrutsInternalTestCase { ValueStack stack = ActionContext.getContext().getValueStack(); Form form = new Form(stack, req, res); - form.getParameters().put("id", "formId"); + form.getAttributes().put("id", "formId"); Submit submit = new Submit(stack, req, res); submit.setName("submitName"); submit.populateComponentHtmlId(form); - assertEquals("formId_submitName", submit.getParameters().get("id")); + assertEquals("formId_submitName", submit.getAttributes().get("id")); } public void testPopulateComponentHtmlId3() { @@ -70,7 +70,7 @@ public class FormButtonTest extends StrutsInternalTestCase { ValueStack stack = ActionContext.getContext().getValueStack(); Form form = new Form(stack, req, res); - form.getParameters().put("id", "formId"); + form.getAttributes().put("id", "formId"); Submit submit = new Submit(stack, req, res); submit.setAction("submitAction"); @@ -78,7 +78,7 @@ public class FormButtonTest extends StrutsInternalTestCase { submit.populateComponentHtmlId(form); - assertEquals("formId_submitAction_submitMethod", submit.getParameters().get("id")); + assertEquals("formId_submitAction_submitMethod", submit.getAttributes().get("id")); } public void testPopulateComponentHtmlId4() { @@ -91,7 +91,7 @@ public class FormButtonTest extends StrutsInternalTestCase { submit.populateComponentHtmlId(null); - assertEquals("submitId", submit.getParameters().get("id")); + assertEquals("submitId", submit.getAttributes().get("id")); } public void testPopulateComponentHtmlId5() { @@ -104,7 +104,7 @@ public class FormButtonTest extends StrutsInternalTestCase { submit.populateComponentHtmlId(null); - assertEquals("submitName", submit.getParameters().get("id")); + assertEquals("submitName", submit.getAttributes().get("id")); } public void testPopulateComponentHtmlId6() { @@ -118,7 +118,7 @@ public class FormButtonTest extends StrutsInternalTestCase { submit.populateComponentHtmlId(null); - assertEquals("submitAction_submitMethod", submit.getParameters().get("id")); + assertEquals("submitAction_submitMethod", submit.getAttributes().get("id")); } public void testPopulateComponentHtmlId7() { @@ -134,7 +134,7 @@ public class FormButtonTest extends StrutsInternalTestCase { submit.populateComponentHtmlId(null); - assertEquals("secondAction", submit.getParameters().get("id")); + assertEquals("secondAction", submit.getAttributes().get("id")); } public void testPopulateComponentHtmlId8() { @@ -152,6 +152,6 @@ public class FormButtonTest extends StrutsInternalTestCase { submit.populateComponentHtmlId(null); - assertEquals("boo_foo", submit.getParameters().get("id")); + assertEquals("boo_foo", submit.getAttributes().get("id")); } } diff --git a/core/src/test/java/org/apache/struts2/components/FormTest.java b/core/src/test/java/org/apache/struts2/components/FormTest.java index 649747a41..4f3c188f5 100644 --- a/core/src/test/java/org/apache/struts2/components/FormTest.java +++ b/core/src/test/java/org/apache/struts2/components/FormTest.java @@ -60,7 +60,7 @@ public class FormTest extends AbstractUITagTest { int expectedFooValidators, int expectedStatusValidators, int expectedResultValidators) { Form form = new Form(stack, request, response); container.inject(form); - form.getParameters().put("actionClass", TestAction.class); + form.getAttributes().put("actionClass", TestAction.class); form.setAction("actionName" + (methodName != null ? "!" + methodName : "")); validationInterceptor.setValidateAnnotatedMethodOnly(validateAnnotatedMethodOnly); @@ -101,7 +101,7 @@ public class FormTest extends AbstractUITagTest { EasyMock.expect(invocation.invoke()).andReturn(Action.SUCCESS).anyTimes(); EasyMock.expect(proxy.getMethod()).andReturn("execute").anyTimes(); EasyMock.expect(proxy.getConfig()).andReturn(config).anyTimes(); - + EasyMock.replay(invocation); EasyMock.replay(proxy); @@ -109,7 +109,7 @@ public class FormTest extends AbstractUITagTest { defaultNamespace.put("actionName", config); ((DefaultActionMapper) container.getInstance(ActionMapper.class)).setAllowDynamicMethodCalls("true"); - + ActionContext.getContext().withActionInvocation(invocation); } } diff --git a/core/src/test/java/org/apache/struts2/components/UIBeanTest.java b/core/src/test/java/org/apache/struts2/components/UIBeanTest.java index 1bff06889..7893e2232 100644 --- a/core/src/test/java/org/apache/struts2/components/UIBeanTest.java +++ b/core/src/test/java/org/apache/struts2/components/UIBeanTest.java @@ -44,14 +44,14 @@ public class UIBeanTest extends StrutsInternalTestCase { MockHttpServletResponse res = new MockHttpServletResponse(); Form form = new Form(stack, req, res); - form.getParameters().put("id", "formId"); + form.getAttributes().put("id", "formId"); TextField txtFld = new TextField(stack, req, res); txtFld.setId("txtFldId"); txtFld.populateComponentHtmlId(form); - assertEquals("txtFldId", txtFld.getParameters().get("id")); + assertEquals("txtFldId", txtFld.getAttributes().get("id")); } public void testPopulateComponentHtmlIdWithOgnl() { @@ -60,14 +60,14 @@ public class UIBeanTest extends StrutsInternalTestCase { MockHttpServletResponse res = new MockHttpServletResponse(); Form form = new Form(stack, req, res); - form.getParameters().put("id", "formId"); + form.getAttributes().put("id", "formId"); TextField txtFld = new TextField(stack, req, res); txtFld.setName("txtFldName%{'1'}"); txtFld.populateComponentHtmlId(form); - assertEquals("formId_txtFldName1", txtFld.getParameters().get("id")); + assertEquals("formId_txtFldName1", txtFld.getAttributes().get("id")); } public void testPopulateComponentHtmlId2() { @@ -76,14 +76,14 @@ public class UIBeanTest extends StrutsInternalTestCase { MockHttpServletResponse res = new MockHttpServletResponse(); Form form = new Form(stack, req, res); - form.getParameters().put("id", "formId"); + form.getAttributes().put("id", "formId"); TextField txtFld = new TextField(stack, req, res); txtFld.setName("txtFldName"); txtFld.populateComponentHtmlId(form); - assertEquals("formId_txtFldName", txtFld.getParameters().get("id")); + assertEquals("formId_txtFldName", txtFld.getAttributes().get("id")); } public void testPopulateComponentHtmlWithoutNameAndId() { @@ -92,13 +92,13 @@ public class UIBeanTest extends StrutsInternalTestCase { MockHttpServletResponse res = new MockHttpServletResponse(); Form form = new Form(stack, req, res); - form.getParameters().put("id", "formId"); + form.getAttributes().put("id", "formId"); TextField txtFld = new TextField(stack, req, res); txtFld.populateComponentHtmlId(form); - assertNull(txtFld.getParameters().get("id")); + assertNull(txtFld.getAttributes().get("id")); } public void testEscape() { @@ -124,12 +124,12 @@ public class UIBeanTest extends StrutsInternalTestCase { MockHttpServletResponse res = new MockHttpServletResponse(); Form form = new Form(stack, req, res); - form.getParameters().put("id", "formId"); + form.getAttributes().put("id", "formId"); TextField txtFld = new TextField(stack, req, res); txtFld.setName("foo/bar"); txtFld.populateComponentHtmlId(form); - assertEquals("formId_foo_bar", txtFld.getParameters().get("id")); + assertEquals("formId_foo_bar", txtFld.getAttributes().get("id")); } public void testGetThemeFromForm() { @@ -232,7 +232,7 @@ public class UIBeanTest extends StrutsInternalTestCase { txtFld.setAccesskey(accesskeyValue); txtFld.evaluateParams(); - assertEquals(accesskeyValue, txtFld.getParameters().get("accesskey")); + assertEquals(accesskeyValue, txtFld.getAttributes().get("accesskey")); } public void testValueParameterEvaluation() { @@ -246,7 +246,7 @@ public class UIBeanTest extends StrutsInternalTestCase { txtFld.addParameter("value", value); txtFld.evaluateParams(); - assertEquals(value, txtFld.getParameters().get("nameValue")); + assertEquals(value, txtFld.getAttributes().get("nameValue")); } public void testValueParameterRecursion() { @@ -270,8 +270,8 @@ public class UIBeanTest extends StrutsInternalTestCase { txtFld.setName("%{myValue}"); txtFld.evaluateParams(); - assertEquals("%{myBad}", txtFld.getParameters().get("nameValue")); - assertEquals("%{myBad}", txtFld.getParameters().get("name")); + assertEquals("%{myBad}", txtFld.getAttributes().get("nameValue")); + assertEquals("%{myBad}", txtFld.getAttributes().get("name")); } public void testValueNameParameterNotAccepted() { @@ -294,13 +294,13 @@ public class UIBeanTest extends StrutsInternalTestCase { container.inject(txtFld); txtFld.setName("%{myValueName}"); txtFld.evaluateParams(); - assertEquals("getMyValue()", txtFld.getParameters().get("name")); - assertEquals("getMyValue()", txtFld.getParameters().get("nameValue")); + assertEquals("getMyValue()", txtFld.getAttributes().get("name")); + assertEquals("getMyValue()", txtFld.getAttributes().get("nameValue")); txtFld.setNotExcludedAcceptedPatterns(NO_EXCLUSION_ACCEPT_ALL_PATTERNS_CHECKER); txtFld.evaluateParams(); - assertEquals("getMyValue()", txtFld.getParameters().get("name")); - assertEquals("value", txtFld.getParameters().get("nameValue")); + assertEquals("getMyValue()", txtFld.getAttributes().get("name")); + assertEquals("value", txtFld.getAttributes().get("nameValue")); } public void testValueNameParameterGetterAccepted() { @@ -319,8 +319,8 @@ public class UIBeanTest extends StrutsInternalTestCase { container.inject(txtFld); txtFld.setName("getMyValue()"); txtFld.evaluateParams(); - assertEquals("getMyValue()", txtFld.getParameters().get("name")); - assertEquals("value", txtFld.getParameters().get("nameValue")); + assertEquals("getMyValue()", txtFld.getAttributes().get("name")); + assertEquals("value", txtFld.getAttributes().get("nameValue")); } public void testSetClass() { @@ -334,7 +334,7 @@ public class UIBeanTest extends StrutsInternalTestCase { txtFld.setCssClass(cssClass); txtFld.evaluateParams(); - assertEquals(cssClass, txtFld.getParameters().get("cssClass")); + assertEquals(cssClass, txtFld.getAttributes().get("cssClass")); } public void testSetStyle() { @@ -348,7 +348,7 @@ public class UIBeanTest extends StrutsInternalTestCase { txtFld.setStyle(cssStyle); txtFld.evaluateParams(); - assertEquals(cssStyle, txtFld.getParameters().get("cssStyle")); + assertEquals(cssStyle, txtFld.getAttributes().get("cssStyle")); } public void testNonce() { @@ -367,7 +367,7 @@ public class UIBeanTest extends StrutsInternalTestCase { DoubleSelect dblSelect = new DoubleSelect(stack, req, res); dblSelect.evaluateParams(); - assertEquals(nonceVal, dblSelect.getParameters().get("nonce")); + assertEquals(nonceVal, dblSelect.getAttributes().get("nonce")); } public void testNonceOfInvalidSession() { @@ -387,7 +387,7 @@ public class UIBeanTest extends StrutsInternalTestCase { DoubleSelect dblSelect = new DoubleSelect(stack, req, res); dblSelect.evaluateParams(); - assertNull(dblSelect.getParameters().get("nonce")); + assertNull(dblSelect.getAttributes().get("nonce")); } public void testSetNullUiStaticContentPath() { diff --git a/core/src/test/java/org/apache/struts2/views/jsp/URLTagTest.java b/core/src/test/java/org/apache/struts2/views/jsp/URLTagTest.java index 237e78d18..86f83dcf7 100644 --- a/core/src/test/java/org/apache/struts2/views/jsp/URLTagTest.java +++ b/core/src/test/java/org/apache/struts2/views/jsp/URLTagTest.java @@ -128,7 +128,7 @@ public class URLTagTest extends AbstractUITagTest { param3.doEndTag(); URL url = (URL) tag.getComponent(); - Map parameters = url.getParameters(); + Map parameters = url.getAttributes(); assertNotNull(parameters); @@ -247,7 +247,7 @@ public class URLTagTest extends AbstractUITagTest { param3.doEndTag(); URL url = (URL) tag.getComponent(); - Map parameters = url.getParameters(); + Map parameters = url.getAttributes(); assertNotNull(parameters); @@ -393,7 +393,7 @@ public class URLTagTest extends AbstractUITagTest { param3.doEndTag(); URL url = (URL) tag.getComponent(); - Map parameters = url.getParameters(); + Map parameters = url.getAttributes(); assertEquals(parameters.size(), 5); assertEquals(parameters.get("id1"), "paramId1"); @@ -476,7 +476,7 @@ public class URLTagTest extends AbstractUITagTest { param3.doEndTag(); URL url = (URL) tag.getComponent(); - Map parameters = url.getParameters(); + Map parameters = url.getAttributes(); assertEquals(parameters.size(), 5); assertEquals(parameters.get("id1"), "paramId1"); @@ -526,7 +526,7 @@ public class URLTagTest extends AbstractUITagTest { tag.doStartTag(); URL url = (URL) tag.getComponent(); - Map parameters = url.getParameters(); + Map parameters = url.getAttributes(); tag.doEndTag(); @@ -560,7 +560,7 @@ public class URLTagTest extends AbstractUITagTest { setComponentTagClearTagState(tag, true); // Ensure component tag state clearing is set true (to match tag). URL url = (URL) tag.getComponent(); - Map parameters = url.getParameters(); + Map parameters = url.getAttributes(); tag.doEndTag(); diff --git a/core/src/test/java/org/apache/struts2/views/jsp/ui/FormTagTest.java b/core/src/test/java/org/apache/struts2/views/jsp/ui/FormTagTest.java index 0b0576272..9eb8f63c0 100644 --- a/core/src/test/java/org/apache/struts2/views/jsp/ui/FormTagTest.java +++ b/core/src/test/java/org/apache/struts2/views/jsp/ui/FormTagTest.java @@ -798,7 +798,7 @@ public class FormTagTest extends AbstractUITagTest { t.setList("{}"); tag.doStartTag(); - tag.getComponent().getParameters().put("actionClass", IntValidationAction.class); + tag.getComponent().getAttributes().put("actionClass", IntValidationAction.class); t.doStartTag(); t.doEndTag(); tag.doEndTag(); @@ -847,7 +847,7 @@ public class FormTagTest extends AbstractUITagTest { tag.doStartTag(); setComponentTagClearTagState(tag, true); // Ensure component tag state clearing is set true (to match tag). - tag.getComponent().getParameters().put("actionClass", IntValidationAction.class); + tag.getComponent().getAttributes().put("actionClass", IntValidationAction.class); t.doStartTag(); setComponentTagClearTagState(t, true); // Ensure component tag state clearing is set true (to match tag). t.doEndTag(); @@ -896,7 +896,7 @@ public class FormTagTest extends AbstractUITagTest { t.setList("{}"); tag.doStartTag(); - tag.getComponent().getParameters().put("actionClass", DoubleValidationAction.class); + tag.getComponent().getAttributes().put("actionClass", DoubleValidationAction.class); t.doStartTag(); t.doEndTag(); tag.doEndTag(); @@ -945,7 +945,7 @@ public class FormTagTest extends AbstractUITagTest { tag.doStartTag(); setComponentTagClearTagState(tag, true); // Ensure component tag state clearing is set true (to match tag). - tag.getComponent().getParameters().put("actionClass", DoubleValidationAction.class); + tag.getComponent().getAttributes().put("actionClass", DoubleValidationAction.class); t.doStartTag(); setComponentTagClearTagState(t, true); // Ensure component tag state clearing is set true (to match tag). t.doEndTag(); diff --git a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/SelectHandler.java b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/SelectHandler.java index f53a3d2a3..9bb9ded18 100644 --- a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/SelectHandler.java +++ b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/SelectHandler.java @@ -61,7 +61,7 @@ public class SelectHandler extends AbstractTagHandler implements TagGenerator { boolean selected = ContainUtil.contains(value, params.get("headerKey")); writeOption(headerKey, headerValue, selected); } - + //emptyoption Object emptyOption = params.get("emptyOption"); if (emptyOption != null && emptyOption.toString().equals(Boolean.toString(true))) { @@ -81,10 +81,10 @@ public class SelectHandler extends AbstractTagHandler implements TagGenerator { //key Object itemKey = findValue(listKey != null ? listKey : "top"); - String itemKeyStr = StringUtils.defaultString(itemKey == null ? null : itemKey.toString()); + String itemKeyStr = StringUtils.defaultString(itemKey == null ? null : itemKey.toString()); //value Object itemValue = findValue(listValue != null ? listValue : "top"); - String itemValueStr = StringUtils.defaultString(itemValue == null ? null : itemValue.toString()); + String itemValueStr = StringUtils.defaultString(itemValue == null ? null : itemValue.toString()); boolean selected = ContainUtil.contains(value, itemKey); writeOption(itemKeyStr, itemValueStr, selected); @@ -115,7 +115,7 @@ public class SelectHandler extends AbstractTagHandler implements TagGenerator { } private void writeOptionGroup(ListUIBean listUIBean, Object value) throws IOException { - Map params = listUIBean.getParameters(); + Map params = listUIBean.getAttributes(); Attributes attrs = new Attributes(); attrs.addIfExists("label", params.get("label")) .addIfTrue("disabled", params.get("disabled")); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractCommonAttributesTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractCommonAttributesTest.java index 0b60759e0..885acd4ea 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractCommonAttributesTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractCommonAttributesTest.java @@ -30,7 +30,7 @@ public abstract class AbstractCommonAttributesTest extends AbstractTest { applyScriptingAttrs(tag); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); @@ -44,7 +44,7 @@ public abstract class AbstractCommonAttributesTest extends AbstractTest { applyCommonAttrs(tag); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); @@ -57,7 +57,7 @@ public abstract class AbstractCommonAttributesTest extends AbstractTest { applyDynamicAttrs(tag); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionErrorTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionErrorTest.java index 18de37478..192e5a481 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionErrorTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionErrorTest.java @@ -36,7 +36,7 @@ public class ActionErrorTest extends AbstractTest { tag.setCssStyle("style"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s("
      • this clas is bad
      • baaaaad
      "); @@ -47,7 +47,7 @@ public class ActionErrorTest extends AbstractTest { tag.setCssStyle("style"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s("
      • this clas is bad
      • baaaaad
      "); @@ -57,7 +57,7 @@ public class ActionErrorTest extends AbstractTest { public void testRenderActionErrorNoErrors() { this.errors.clear(); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); assertEquals("", output); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionMessageTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionMessageTest.java index 3d635a13c..bd550819f 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionMessageTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionMessageTest.java @@ -36,7 +36,7 @@ public class ActionMessageTest extends AbstractTest { tag.setCssStyle("style"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s("
      • this clas is bad
      • baaaaad
      "); @@ -47,7 +47,7 @@ public class ActionMessageTest extends AbstractTest { tag.setCssStyle("style"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s("
      • this clas is bad
      • baaaaad
      "); @@ -57,7 +57,7 @@ public class ActionMessageTest extends AbstractTest { public void testRenderActionErrorNoErrors() { this.errors.clear(); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); assertEquals("", output); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AnchorTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AnchorTest.java index 595713547..2ac3b38d6 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AnchorTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AnchorTest.java @@ -39,7 +39,7 @@ public class AnchorTest extends AbstractTest { tag.setHref("http://sometest.com?ab=10"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); theme.renderTag(getTagName() + "-close", context); String output = writer.getBuffer().toString(); @@ -59,7 +59,7 @@ public class AnchorTest extends AbstractTest { tag.setHref("http://sometest.com?ab=10"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); theme.renderTag(getTagName() + "-close", context); String output = writer.getBuffer().toString(); @@ -75,7 +75,7 @@ public class AnchorTest extends AbstractTest { tag.setEscapeHtmlBody(true); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); context.getParameters().put("body", s("")); theme.renderTag(getTagName(), context); @@ -93,7 +93,7 @@ public class AnchorTest extends AbstractTest { //tag.setEscapeHtmlBody(true); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); context.getParameters().put("body", s("")); theme.renderTag(getTagName(), context); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/CheckboxTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/CheckboxTest.java index d7d56ec0a..a7060130f 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/CheckboxTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/CheckboxTest.java @@ -38,7 +38,7 @@ public class CheckboxTest extends AbstractCommonAttributesTest { tag.setFieldValue("xyz"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); @@ -57,7 +57,7 @@ public class CheckboxTest extends AbstractCommonAttributesTest { tag.setSubmitUnchecked("true"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); @@ -69,7 +69,7 @@ public class CheckboxTest extends AbstractCommonAttributesTest { tag.setValue("%{someValue}"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/DateTextFieldTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/DateTextFieldTest.java index fb37eebce..67d9dc5a5 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/DateTextFieldTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/DateTextFieldTest.java @@ -33,7 +33,7 @@ public class DateTextFieldTest extends AbstractCommonAttributesTest { tag.setFormat("yyyy-MM-dd"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s("
      " + @@ -42,10 +42,10 @@ public class DateTextFieldTest extends AbstractCommonAttributesTest { "-
      "); assertEquals(expected, output); } - + @Override public void testRenderTextFieldScriptingAttrs() throws Exception { } - + @Override public void testRenderTextFieldCommonAttrs() throws Exception { } diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FieldErrorTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FieldErrorTest.java index e5a39d7bc..fe35a58a0 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FieldErrorTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FieldErrorTest.java @@ -35,7 +35,7 @@ public class FieldErrorTest extends AbstractTest { tag.setCssStyle("style"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s("
      • not good
      • bad
      • bad to the bone
      "); @@ -46,7 +46,7 @@ public class FieldErrorTest extends AbstractTest { tag.setCssStyle("style"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s("
      • not good
      • bad
      • bad to the bone
      "); @@ -57,7 +57,7 @@ public class FieldErrorTest extends AbstractTest { this.fieldNames.clear(); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s("
      • not good
      • bad
      • bad to the bone
      "); @@ -67,7 +67,7 @@ public class FieldErrorTest extends AbstractTest { public void testRenderFieldErrorWithoutOneFieldName() { tag.setFieldName("field1"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s("
      • not good
      • bad
      "); @@ -79,7 +79,7 @@ public class FieldErrorTest extends AbstractTest { this.fieldNames.clear(); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); assertEquals("", output); 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 16ce86b65..bf9786f3a 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 @@ -39,7 +39,7 @@ public class FileTest extends AbstractCommonAttributesTest { tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FormTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FormTest.java index af8f303c9..34d176962 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FormTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FormTest.java @@ -45,7 +45,7 @@ public class FormTest extends AbstractCommonAttributesTest { tag.setMethod("post"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); theme.renderTag(getTagName() + "-close", context); String output = writer.getBuffer().toString(); @@ -55,7 +55,7 @@ public class FormTest extends AbstractCommonAttributesTest { public void testDefaultMethod() { tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); theme.renderTag(getTagName() + "-close", context); String output = writer.getBuffer().toString(); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HeadTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HeadTest.java index e116b3df4..a1c276280 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HeadTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HeadTest.java @@ -28,7 +28,7 @@ public class HeadTest extends AbstractTest { public void testRenderTextField() { tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HiddenTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HiddenTest.java index 497ea88f1..8884aaca0 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HiddenTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HiddenTest.java @@ -38,7 +38,7 @@ public class HiddenTest extends AbstractTest { tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LabelTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LabelTest.java index 39adea597..0dfbb81ad 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LabelTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LabelTest.java @@ -37,7 +37,7 @@ public class LabelTest extends AbstractCommonAttributesTest { tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LinkTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LinkTest.java index c8c9c414a..1fe7f0106 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LinkTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LinkTest.java @@ -39,7 +39,7 @@ public class LinkTest extends AbstractTest { tag.setTitle("test"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); @@ -71,7 +71,7 @@ public class LinkTest extends AbstractTest { tag.setTitle("test"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/PasswordTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/PasswordTest.java index 84f48ce92..a17e0fdce 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/PasswordTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/PasswordTest.java @@ -43,7 +43,7 @@ public class PasswordTest extends AbstractCommonAttributesTest { tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); @@ -66,7 +66,7 @@ public class PasswordTest extends AbstractCommonAttributesTest { tag.setShowPassword("%{'true'}"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ResetTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ResetTest.java index 3e78fcf78..9695e884f 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ResetTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ResetTest.java @@ -39,7 +39,7 @@ public class ResetTest extends AbstractCommonAttributesTest { tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s("some label"); @@ -58,7 +58,7 @@ public class ResetTest extends AbstractCommonAttributesTest { tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ScriptTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ScriptTest.java index b37c76ec8..c0d93a629 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ScriptTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ScriptTest.java @@ -40,7 +40,7 @@ public class ScriptTest extends AbstractTest { tag.setCrossorigin("test"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SelectTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SelectTest.java index 28d601fb6..4fa2a6ed7 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SelectTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SelectTest.java @@ -42,7 +42,7 @@ public class SelectTest extends AbstractCommonAttributesTest { tag.setTitle("title"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); @@ -55,7 +55,7 @@ public class SelectTest extends AbstractCommonAttributesTest { tag.setHeaderValue("%{'val'}"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); @@ -68,7 +68,7 @@ public class SelectTest extends AbstractCommonAttributesTest { tag.setListValue("stringField"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); @@ -79,7 +79,7 @@ public class SelectTest extends AbstractCommonAttributesTest { tag.setList("%{#{'key0' : 'val'}}"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); @@ -93,7 +93,7 @@ public class SelectTest extends AbstractCommonAttributesTest { tag.setValue("%{'1'}"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SubmitTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SubmitTest.java index cbb7f6c5f..84f45c2d8 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SubmitTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SubmitTest.java @@ -39,12 +39,12 @@ public class SubmitTest extends AbstractCommonAttributesTest { tag.setType("button"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); tag.addParameter("body", "hey hey hey, here I go now"); map.clear(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName() + "-close", context); String output = writer.getBuffer().toString(); String expected = s(""); @@ -65,7 +65,7 @@ public class SubmitTest extends AbstractCommonAttributesTest { tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); theme.renderTag(getTagName() + "-close", context); String output = writer.getBuffer().toString(); @@ -87,7 +87,7 @@ public class SubmitTest extends AbstractCommonAttributesTest { tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); theme.renderTag(getTagName() + "-close", context); String output = writer.getBuffer().toString(); @@ -108,7 +108,7 @@ public class SubmitTest extends AbstractCommonAttributesTest { tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); theme.renderTag(getTagName() + "-close", context); String output = writer.getBuffer().toString(); @@ -123,7 +123,7 @@ public class SubmitTest extends AbstractCommonAttributesTest { tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); theme.renderTag(getTagName() + "-close", context); String output = writer.getBuffer().toString(); @@ -138,12 +138,12 @@ public class SubmitTest extends AbstractCommonAttributesTest { tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); map.clear(); tag.setType("image"); tag.addParameter("body", "hey hey hey, here I go now"); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName() + "-close", context); String output = writer.getBuffer().toString(); String expected = s("hey hey hey, here I go now"); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextAreaTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextAreaTest.java index fb5d8e071..d72f42bcb 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextAreaTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextAreaTest.java @@ -41,7 +41,7 @@ public class TextAreaTest extends AbstractCommonAttributesTest { tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); @@ -60,7 +60,7 @@ public class TextAreaTest extends AbstractCommonAttributesTest { tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextFieldTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextFieldTest.java index 5973ea5ff..212a991cc 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextFieldTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextFieldTest.java @@ -41,7 +41,7 @@ public class TextFieldTest extends AbstractCommonAttributesTest { tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); String expected = s(""); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TokenTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TokenTest.java index e1ad3f907..7f7b3fbef 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TokenTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TokenTest.java @@ -35,7 +35,7 @@ public class TokenTest extends AbstractTest { tag.setValue("val1"); tag.evaluateParams(); - map.putAll(tag.getParameters()); + map.putAll(tag.getAttributes()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); diff --git a/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java b/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java index 754389f83..55ee07b39 100644 --- a/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java +++ b/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java @@ -180,7 +180,7 @@ public class PortletUrlRenderer implements UrlRenderer { } if (action != null) { String result = portletUrlHelper.buildUrl(action, namespace, null, - formComponent.getParameters(), type, formComponent.portletMode, formComponent.windowState); + formComponent.getAttributes(), type, formComponent.portletMode, formComponent.windowState); formComponent.addParameter("action", result); From 5b2f63fa7e917733f03658d5bf1f84775951725a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 01:50:03 +0000 Subject: [PATCH 31/33] Bump asm.version from 9.7 to 9.7.1 Bumps `asm.version` from 9.7 to 9.7.1. Updates `org.ow2.asm:asm` from 9.7 to 9.7.1 Updates `org.ow2.asm:asm-commons` from 9.7 to 9.7.1 --- updated-dependencies: - dependency-name: org.ow2.asm:asm dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.ow2.asm:asm-commons dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3b5e297e7..be5a692f0 100644 --- a/pom.xml +++ b/pom.xml @@ -109,7 +109,7 @@ 1.8 - 9.7 + 9.7.1 2.18.0 2.24.1 3.3.5 From 3f74923099b4ba9b05702a4d1b1ff97e1cdb11de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 01:54:27 +0000 Subject: [PATCH 32/33] Bump github/codeql-action from 3.26.13 to 3.27.0 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.26.13 to 3.27.0. - [Release notes](https://github.com/github/codeql-action/releases) - [Commits](https://github.com/github/codeql-action/compare/v3.26.13...v3.27.0) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql.yml | 6 +++--- .github/workflows/scorecards-analysis.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 5e616eab6..0846bfe9f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -44,12 +44,12 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - name: Initialize CodeQL - uses: github/codeql-action/init@v3.26.13 + uses: github/codeql-action/init@v3.27.0 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@v3.26.13 + uses: github/codeql-action/autobuild@v3.27.0 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3.26.13 + uses: github/codeql-action/analyze@v3.27.0 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecards-analysis.yaml b/.github/workflows/scorecards-analysis.yaml index 44c6ac646..0bd0c466e 100644 --- a/.github/workflows/scorecards-analysis.yaml +++ b/.github/workflows/scorecards-analysis.yaml @@ -64,6 +64,6 @@ jobs: retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@af56b044b5d41c317aef5d19920b3183cb4fbbec # 2.22.11 + uses: github/codeql-action/upload-sarif@3aa71356c75a8edd8430d54dff2982203a28be45 # 2.22.11 with: sarif_file: results.sarif From eab6d9ef89e9f522e9b6c290fbd103c870d8db73 Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Fri, 1 Nov 2024 16:01:19 +1100 Subject: [PATCH 33/33] Fix merge errors --- .../org/apache/struts2/ActionContext.java | 8 ++-- .../struts2/interceptor/AliasInterceptor.java | 2 +- .../StaticParametersInterceptor.java | 2 +- .../ActionFileUploadInterceptorTest.java | 46 ++++++++----------- 4 files changed, 26 insertions(+), 32 deletions(-) diff --git a/core/src/main/java/org/apache/struts2/ActionContext.java b/core/src/main/java/org/apache/struts2/ActionContext.java index 79f7552d5..c17ff43e4 100644 --- a/core/src/main/java/org/apache/struts2/ActionContext.java +++ b/core/src/main/java/org/apache/struts2/ActionContext.java @@ -20,14 +20,14 @@ package org.apache.struts2; import com.opensymphony.xwork2.conversion.impl.ConversionData; import com.opensymphony.xwork2.inject.Container; +import jakarta.servlet.ServletContext; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.jsp.PageContext; import org.apache.struts2.dispatcher.HttpParameters; import org.apache.struts2.dispatcher.mapper.ActionMapping; import org.apache.struts2.util.ValueStack; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.jsp.PageContext; import java.io.Serializable; import java.util.HashMap; import java.util.Locale; diff --git a/core/src/main/java/org/apache/struts2/interceptor/AliasInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/AliasInterceptor.java index c5aa9fb3c..58c50e404 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/AliasInterceptor.java +++ b/core/src/main/java/org/apache/struts2/interceptor/AliasInterceptor.java @@ -21,7 +21,6 @@ package org.apache.struts2.interceptor; import com.opensymphony.xwork2.LocalizedTextProvider; import com.opensymphony.xwork2.config.entities.ActionConfig; import com.opensymphony.xwork2.inject.Inject; -import com.opensymphony.xwork2.interceptor.ParametersInterceptor; import com.opensymphony.xwork2.security.AcceptedPatternsChecker; import com.opensymphony.xwork2.security.ExcludedPatternsChecker; import com.opensymphony.xwork2.util.ClearableValueStack; @@ -35,6 +34,7 @@ import org.apache.struts2.ActionInvocation; import org.apache.struts2.StrutsConstants; import org.apache.struts2.dispatcher.HttpParameters; import org.apache.struts2.dispatcher.Parameter; +import org.apache.struts2.interceptor.parameter.ParametersInterceptor; import org.apache.struts2.util.ValueStack; import java.util.Map; diff --git a/core/src/main/java/org/apache/struts2/interceptor/StaticParametersInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/StaticParametersInterceptor.java index 5b00ffca6..2f7ccac37 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/StaticParametersInterceptor.java +++ b/core/src/main/java/org/apache/struts2/interceptor/StaticParametersInterceptor.java @@ -22,7 +22,6 @@ import com.opensymphony.xwork2.LocalizedTextProvider; import com.opensymphony.xwork2.config.entities.ActionConfig; import com.opensymphony.xwork2.config.entities.Parameterizable; import com.opensymphony.xwork2.inject.Inject; -import com.opensymphony.xwork2.interceptor.ParametersInterceptor; import com.opensymphony.xwork2.util.ClearableValueStack; import com.opensymphony.xwork2.util.TextParseUtil; import com.opensymphony.xwork2.util.ValueStackFactory; @@ -34,6 +33,7 @@ import org.apache.struts2.ActionContext; import org.apache.struts2.ActionInvocation; import org.apache.struts2.StrutsConstants; import org.apache.struts2.dispatcher.HttpParameters; +import org.apache.struts2.interceptor.parameter.ParametersInterceptor; import org.apache.struts2.util.ValueStack; import java.util.Collections; diff --git a/core/src/test/java/org/apache/struts2/interceptor/ActionFileUploadInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/ActionFileUploadInterceptorTest.java index 876aec960..8e9e7bd4d 100644 --- a/core/src/test/java/org/apache/struts2/interceptor/ActionFileUploadInterceptorTest.java +++ b/core/src/test/java/org/apache/struts2/interceptor/ActionFileUploadInterceptorTest.java @@ -269,12 +269,10 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase { } public void testNoContentMultipartRequest() throws Exception { - MockHttpServletRequest req = new MockHttpServletRequest(); - - req.setCharacterEncoding(StandardCharsets.UTF_8.name()); - req.setMethod("post"); - req.addHeader("Content-type", "multipart/form-data"); - req.setContent(null); // there is no content + request.setCharacterEncoding(StandardCharsets.UTF_8.name()); + request.setMethod("post"); + request.addHeader("Content-type", "multipart/form-data"); + request.setContent(null); // there is no content MyFileUploadAction action = container.inject(MyFileUploadAction.class); MockActionInvocation mai = new MockActionInvocation(); @@ -326,10 +324,9 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase { } public void testSuccessUploadOfATextFileMultipartRequestNoMaxParamsSet() throws Exception { - MockHttpServletRequest req = new MockHttpServletRequest(); - req.setCharacterEncoding(StandardCharsets.UTF_8.name()); - req.setMethod("post"); - req.addHeader("Content-type", "multipart/form-data; boundary=---1234"); + request.setCharacterEncoding(StandardCharsets.UTF_8.name()); + request.setMethod("post"); + request.addHeader("Content-type", "multipart/form-data; boundary=---1234"); // inspired by the unit tests for jakarta commons fileupload String content = ("-----1234\r\n" + @@ -339,7 +336,7 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase { "Unit test of ActionFileUploadInterceptor" + "\r\n" + "-----1234--\r\n"); - req.setContent(content.getBytes(StandardCharsets.US_ASCII)); + request.setContent(content.getBytes(StandardCharsets.US_ASCII)); MyFileUploadAction action = new MyFileUploadAction(); @@ -347,7 +344,7 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase { mai.setAction(action); mai.setResultCode("success"); mai.setInvocationContext(ActionContext.getContext()); - ActionContext.getContext().withServletRequest(createMultipartRequestNoMaxParamsSet(req)); + ActionContext.getContext().withServletRequest(createMultipartRequestNoMaxParamsSet()); interceptor.intercept(mai); @@ -362,10 +359,9 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase { } public void testSuccessUploadOfATextFileMultipartRequestWithNormalFieldsMaxParamsSet() throws Exception { - MockHttpServletRequest req = new MockHttpServletRequest(); - req.setCharacterEncoding(StandardCharsets.UTF_8.name()); - req.setMethod("post"); - req.addHeader("Content-type", "multipart/form-data; boundary=---1234"); + request.setCharacterEncoding(StandardCharsets.UTF_8.name()); + request.setMethod("post"); + request.addHeader("Content-type", "multipart/form-data; boundary=---1234"); // inspired by the unit tests for jakarta commons fileupload String content = ("-----1234\r\n" + @@ -385,7 +381,7 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase { "normal field 2" + "\r\n" + "-----1234--\r\n"); - req.setContent(content.getBytes(StandardCharsets.US_ASCII)); + request.setContent(content.getBytes(StandardCharsets.US_ASCII)); MyFileUploadAction action = new MyFileUploadAction(); @@ -415,10 +411,9 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase { } public void testSuccessUploadOfATextFileMultipartRequestWithNormalFieldsNoMaxParamsSet() throws Exception { - MockHttpServletRequest req = new MockHttpServletRequest(); - req.setCharacterEncoding(StandardCharsets.UTF_8.name()); - req.setMethod("post"); - req.addHeader("Content-type", "multipart/form-data; boundary=---1234"); + request.setCharacterEncoding(StandardCharsets.UTF_8.name()); + request.setMethod("post"); + request.addHeader("Content-type", "multipart/form-data; boundary=---1234"); // inspired by the unit tests for jakarta commons fileupload String content = ("-----1234\r\n" + @@ -438,7 +433,7 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase { "normal field 2" + "\r\n" + "-----1234--\r\n"); - req.setContent(content.getBytes(StandardCharsets.US_ASCII)); + request.setContent(content.getBytes(StandardCharsets.US_ASCII)); MyFileUploadAction action = new MyFileUploadAction(); @@ -446,7 +441,7 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase { mai.setAction(action); mai.setResultCode("success"); mai.setInvocationContext(ActionContext.getContext()); - ActionContext.getContext().withServletRequest(createMultipartRequestNoMaxParamsSet(req)); + ActionContext.getContext().withServletRequest(createMultipartRequestNoMaxParamsSet()); interceptor.intercept(mai); @@ -757,10 +752,9 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase { return new MultiPartRequestWrapper(jak, request, tempDir.getAbsolutePath(), new DefaultLocaleProvider()); } - private MultiPartRequestWrapper createMultipartRequestNoMaxParamsSet(HttpServletRequest req) { - + private MultiPartRequestWrapper createMultipartRequestNoMaxParamsSet() { JakartaMultiPartRequest jak = new JakartaMultiPartRequest(); - return new MultiPartRequestWrapper(jak, req, tempDir.getAbsolutePath(), new DefaultLocaleProvider()); + return new MultiPartRequestWrapper(jak, request, tempDir.getAbsolutePath(), new DefaultLocaleProvider()); } protected void setUp() throws Exception {