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 <lukaszlen...@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();