You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2020/06/30 05:35:00 UTC

[struts] branch WW-5080-plain-result updated: WW-5080 Adds some docs and logging, and option to skip committed response

This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5080-plain-result
in repository https://gitbox.apache.org/repos/asf/struts.git


The following commit(s) were added to refs/heads/WW-5080-plain-result by this push:
     new f2d73ee  WW-5080 Adds some docs and logging, and option to skip committed response
f2d73ee is described below

commit f2d73ee4f1a71ba03703a6abdb8eeffbcc1a75b2
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Tue Jun 30 07:34:52 2020 +0200

    WW-5080 Adds some docs and logging, and option to skip committed response
---
 .../org/apache/struts2/result/PlainResult.java     | 42 +++++++++++++++++++++-
 .../org/apache/struts2/result/PlainResultTest.java | 39 ++++++++++++++++++++
 2 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/core/src/main/java/org/apache/struts2/result/PlainResult.java b/core/src/main/java/org/apache/struts2/result/PlainResult.java
index 3cbeb09..b398b93 100644
--- a/core/src/main/java/org/apache/struts2/result/PlainResult.java
+++ b/core/src/main/java/org/apache/struts2/result/PlainResult.java
@@ -20,6 +20,9 @@ package org.apache.struts2.result;
 
 import com.opensymphony.xwork2.ActionInvocation;
 import com.opensymphony.xwork2.Result;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.message.ParameterizedMessage;
 import org.apache.struts2.StrutsException;
 import org.apache.struts2.result.plain.HttpHeader;
 import org.apache.struts2.result.plain.ResponseBuilder;
@@ -27,30 +30,51 @@ import org.apache.struts2.result.plain.ResponseBuilder;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletResponse;
 
+/**
+ * This result can only be used in code, as a result of action's method, eg.:
+ * <p>
+ * public PlainResult execute() {
+ * return response -> response.write("");
+ * }
+ * <p>
+ * Please notice the result type of the method is a PlainResult not a String.
+ */
 public interface PlainResult extends Result {
 
+    Logger LOG = LogManager.getLogger(PlainResult.class);
+
     @Override
     default void execute(ActionInvocation invocation) throws Exception {
+        LOG.debug("Executing plain result");
         ResponseBuilder builder = new ResponseBuilder();
         write(builder);
 
         HttpServletResponse response = invocation.getInvocationContext().getServletResponse();
 
         if (response.isCommitted()) {
-            throw new StrutsException("Http response already committed, cannot modify it!");
+            if (ignoreCommitted()) {
+                LOG.warn("Http response already committed, ignoring & skipping!");
+                return;
+            } else {
+                throw new StrutsException("Http response already committed, cannot modify it!");
+            }
         }
 
         for (HttpHeader<String> header : builder.getStringHeaders()) {
+            LOG.debug(new ParameterizedMessage("A string header: {} = {}", header.getName(), header.getValue()));
             response.addHeader(header.getName(), header.getValue());
         }
         for (HttpHeader<Long> header : builder.getDateHeaders()) {
+            LOG.debug(new ParameterizedMessage("A date header: {} = {}", header.getName(), header.getValue()));
             response.addDateHeader(header.getName(), header.getValue());
         }
         for (HttpHeader<Integer> header : builder.getIntHeaders()) {
+            LOG.debug(new ParameterizedMessage("An int header: {} = {}", header.getName(), header.getValue()));
             response.addIntHeader(header.getName(), header.getValue());
         }
 
         for (Cookie cookie : builder.getCookies()) {
+            LOG.debug(new ParameterizedMessage("A cookie: {} = {}", cookie.getName(), cookie.getValue()));
             response.addCookie(cookie);
         }
 
@@ -58,7 +82,23 @@ public interface PlainResult extends Result {
         response.flushBuffer();
     }
 
+    /**
+     * Implement this method in action using lambdas
+     *
+     * @param response a response builder used to build a Http response
+     */
     void write(ResponseBuilder response);
 
+    /**
+     * Controls if result should ignore already committed Http response
+     * If set to true only a warning will be issued and the rest of the result
+     * will be skipped
+     *
+     * @return boolean false by default which means an exception will be thrown
+     */
+    default boolean ignoreCommitted() {
+        return false;
+    }
+
 }
 
diff --git a/core/src/test/java/org/apache/struts2/result/PlainResultTest.java b/core/src/test/java/org/apache/struts2/result/PlainResultTest.java
index 9e53cee..4cd193c 100644
--- a/core/src/test/java/org/apache/struts2/result/PlainResultTest.java
+++ b/core/src/test/java/org/apache/struts2/result/PlainResultTest.java
@@ -20,7 +20,9 @@ package org.apache.struts2.result;
 
 import com.opensymphony.xwork2.ActionContext;
 import com.opensymphony.xwork2.mock.MockActionInvocation;
+import org.apache.struts2.StrutsException;
 import org.apache.struts2.StrutsInternalTestCase;
+import org.apache.struts2.result.plain.ResponseBuilder;
 import org.springframework.mock.web.MockHttpServletResponse;
 
 public class PlainResultTest extends StrutsInternalTestCase {
@@ -88,6 +90,43 @@ public class PlainResultTest extends StrutsInternalTestCase {
         assertEquals("100", response.getHeader("X-NUmber"));
     }
 
+    public void testExceptionOnCommitted() throws Exception {
+        response.setCommitted(true);
+
+        PlainResult result = (PlainResult) response ->
+            response.write("");
+
+        try {
+            result.execute(invocation);
+            fail("Exception was expected!");
+        } catch (StrutsException e) {
+            assertEquals("Http response already committed, cannot modify it!", e.getMessage());
+        }
+    }
+
+    public void testNoExceptionOnCommitted() throws Exception {
+        response.setCommitted(true);
+
+        PlainResult result = new PlainResult() {
+            @Override
+            public void write(ResponseBuilder response) {
+                response.write("");
+            }
+
+            @Override
+            public boolean ignoreCommitted() {
+                return true;
+            }
+        };
+
+        try {
+            result.execute(invocation);
+            assertTrue(true);
+        } catch (StrutsException e) {
+            fail(e.getMessage());
+        }
+    }
+
     public void setUp() throws Exception {
         super.setUp();
         invocation = new MockActionInvocation();