From 95fdf5164038e40946789d705e2b64522254fa86 Mon Sep 17 00:00:00 2001 From: Remi Vankeisbelck Date: Mon, 18 Jan 2016 18:34:49 +0100 Subject: [PATCH] #37 : added AsyncResolution.complete(Resolution) method that allows for reuse of Resolution classes. As the name says, completes the async processing. You cannot use several Resolutions when async processing. --- .../stripes/action/AsyncResolution.java | 12 ++++++++++ .../stripes/action/ForwardResolution.java | 24 ++++++++++++------- .../stripes/action/JsonResolution.java | 3 +++ .../stripes/action/RedirectResolution.java | 4 ++++ .../stripes/action/StreamingResolution.java | 4 ++++ .../ValidationErrorReportResolution.java | 4 ++++ .../stripes/ajax/JavaScriptResolution.java | 3 +++ .../stripes/mock/MockAsyncContext.java | 15 ++++++++++-- .../stripes/mock/TestMockAsync.java | 21 ++++++++++++++++ 9 files changed, 80 insertions(+), 10 deletions(-) diff --git a/stripes/src/main/java/net/sourceforge/stripes/action/AsyncResolution.java b/stripes/src/main/java/net/sourceforge/stripes/action/AsyncResolution.java index c050b9aaf..c836e4e39 100644 --- a/stripes/src/main/java/net/sourceforge/stripes/action/AsyncResolution.java +++ b/stripes/src/main/java/net/sourceforge/stripes/action/AsyncResolution.java @@ -3,6 +3,8 @@ import javax.servlet.AsyncContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.util.function.Consumer; +import java.util.function.Supplier; public abstract class AsyncResolution implements Resolution { @@ -53,4 +55,14 @@ protected void dispatch(String path) { protected void complete() { getAsyncContext().complete(); } + + protected void complete(Resolution resolution) { + try { + resolution.execute(getRequest(), getResponse()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + } diff --git a/stripes/src/main/java/net/sourceforge/stripes/action/ForwardResolution.java b/stripes/src/main/java/net/sourceforge/stripes/action/ForwardResolution.java index 28cf1d101..305729c43 100644 --- a/stripes/src/main/java/net/sourceforge/stripes/action/ForwardResolution.java +++ b/stripes/src/main/java/net/sourceforge/stripes/action/ForwardResolution.java @@ -144,16 +144,24 @@ public void execute(HttpServletRequest request, HttpServletResponse response) String oldEvent = (String) request.getAttribute(StripesConstants.REQ_ATTR_EVENT_NAME); request.setAttribute(StripesConstants.REQ_ATTR_EVENT_NAME, event); - // Figure out if we're inside an include, and use an include instead of a forward - if (autoInclude && request.getAttribute(StripesConstants.REQ_ATTR_INCLUDE_PATH) != null) { - log.trace("Including URL: ", path); - request.getRequestDispatcher(path).include(request, response); + // are we asynchronous ? + if (request.isAsyncStarted()) { + // async started, dispatch... + log.trace("Async mode, dispatching to URL: ", path); + request.getAsyncContext().dispatch(path); } else { - log.trace("Forwarding to URL: ", path); - request.getRequestDispatcher(path).forward(request, response); + // Figure out if we're inside an include, and use an include instead of a forward + if (autoInclude && request.getAttribute(StripesConstants.REQ_ATTR_INCLUDE_PATH) != null) { + log.trace("Including URL: ", path); + request.getRequestDispatcher(path).include(request, response); + } else { + log.trace("Forwarding to URL: ", path); + request.getRequestDispatcher(path).forward(request, response); + } + + // Revert event name to its original value + request.setAttribute(StripesConstants.REQ_ATTR_EVENT_NAME, oldEvent); } - // Revert event name to its original value - request.setAttribute(StripesConstants.REQ_ATTR_EVENT_NAME, oldEvent); } } diff --git a/stripes/src/main/java/net/sourceforge/stripes/action/JsonResolution.java b/stripes/src/main/java/net/sourceforge/stripes/action/JsonResolution.java index 55f37269d..2ff59413a 100644 --- a/stripes/src/main/java/net/sourceforge/stripes/action/JsonResolution.java +++ b/stripes/src/main/java/net/sourceforge/stripes/action/JsonResolution.java @@ -46,5 +46,8 @@ public void execute(HttpServletRequest request, HttpServletResponse response) th response.setContentType("application/json"); builder.build(response.getWriter()); response.flushBuffer(); + if (request.isAsyncStarted()) { + request.getAsyncContext().complete(); + } } } diff --git a/stripes/src/main/java/net/sourceforge/stripes/action/RedirectResolution.java b/stripes/src/main/java/net/sourceforge/stripes/action/RedirectResolution.java index c361123f9..b90182282 100644 --- a/stripes/src/main/java/net/sourceforge/stripes/action/RedirectResolution.java +++ b/stripes/src/main/java/net/sourceforge/stripes/action/RedirectResolution.java @@ -222,6 +222,10 @@ public void sendRedirect(String location) throws IOException { log.trace("Redirecting ", this.beans == null ? "" : "(w/flashed bean) ", "to URL: ", url); response.sendRedirect(url); + + if (request.isAsyncStarted()) { + request.getAsyncContext().complete(); + } } /** diff --git a/stripes/src/main/java/net/sourceforge/stripes/action/StreamingResolution.java b/stripes/src/main/java/net/sourceforge/stripes/action/StreamingResolution.java index 27a0ffe14..994cc0c23 100644 --- a/stripes/src/main/java/net/sourceforge/stripes/action/StreamingResolution.java +++ b/stripes/src/main/java/net/sourceforge/stripes/action/StreamingResolution.java @@ -238,6 +238,10 @@ final public void execute(HttpServletRequest request, HttpServletResponse respon applyHeaders(response); stream(response); + + if (request.isAsyncStarted()) { + request.getAsyncContext().complete(); + } } /** diff --git a/stripes/src/main/java/net/sourceforge/stripes/action/ValidationErrorReportResolution.java b/stripes/src/main/java/net/sourceforge/stripes/action/ValidationErrorReportResolution.java index 37c0144f6..5f5a6f8c9 100644 --- a/stripes/src/main/java/net/sourceforge/stripes/action/ValidationErrorReportResolution.java +++ b/stripes/src/main/java/net/sourceforge/stripes/action/ValidationErrorReportResolution.java @@ -65,6 +65,10 @@ public void execute(HttpServletRequest request, HttpServletResponse response) th writer.println("

Validation errors

"); sendErrors(request, response); writer.println("

"); + + if (request.isAsyncStarted()) { + request.getAsyncContext().complete(); + } } /** diff --git a/stripes/src/main/java/net/sourceforge/stripes/ajax/JavaScriptResolution.java b/stripes/src/main/java/net/sourceforge/stripes/ajax/JavaScriptResolution.java index aeded5223..422ea151c 100644 --- a/stripes/src/main/java/net/sourceforge/stripes/ajax/JavaScriptResolution.java +++ b/stripes/src/main/java/net/sourceforge/stripes/ajax/JavaScriptResolution.java @@ -74,5 +74,8 @@ public void execute(HttpServletRequest request, HttpServletResponse response) th response.setContentType("text/javascript"); this.builder.build(response.getWriter()); response.flushBuffer(); + if (request.isAsyncStarted()) { + request.getAsyncContext().complete(); + } } } diff --git a/stripes/src/main/java/net/sourceforge/stripes/mock/MockAsyncContext.java b/stripes/src/main/java/net/sourceforge/stripes/mock/MockAsyncContext.java index 747d1ae4d..7a4bbdf5b 100644 --- a/stripes/src/main/java/net/sourceforge/stripes/mock/MockAsyncContext.java +++ b/stripes/src/main/java/net/sourceforge/stripes/mock/MockAsyncContext.java @@ -6,7 +6,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ExecutorService; public class MockAsyncContext implements AsyncContext { @@ -18,7 +17,7 @@ public class MockAsyncContext implements AsyncContext { private boolean completed = false; private boolean timedOut = false; - private long timeout = 30000; + private long timeout = 5000; private long startedOn; public MockAsyncContext(ServletRequest request, ServletResponse response) { @@ -136,4 +135,16 @@ public void waitForCompletion() throws Exception { Thread.sleep(200); } } + + public long getStartedOn() { + return startedOn; + } + + public boolean isTimedOut() { + return timedOut; + } + + public boolean isCompleted() { + return completed; + } } diff --git a/stripes/src/test/java/net/sourceforge/stripes/mock/TestMockAsync.java b/stripes/src/test/java/net/sourceforge/stripes/mock/TestMockAsync.java index 5339b011e..3920b1d9e 100644 --- a/stripes/src/test/java/net/sourceforge/stripes/mock/TestMockAsync.java +++ b/stripes/src/test/java/net/sourceforge/stripes/mock/TestMockAsync.java @@ -73,10 +73,19 @@ public void testAsyncException() throws Exception { assertTrue(caught); } + @Test + public void testCompleteWithForwardResolution() throws Exception { + MockRoundtrip trip = new MockRoundtrip(getMockServletContext(), AsyncActionBean.class); + trip.execute("doAsyncAndCompleteWithForwardResolution"); + AsyncActionBean bean = trip.getActionBean(AsyncActionBean.class); + assertNotNull(bean); + } + @UrlBinding("/async") public static class AsyncActionBean implements ActionBean { private boolean completed = false; + private boolean executedForwardResolution; private ActionBeanContext context; public ActionBeanContext getContext() { @@ -142,9 +151,21 @@ protected void executeAsync() throws Exception { }; } + public Resolution doAsyncAndCompleteWithForwardResolution() { + return new AsyncResolution() { + @Override + protected void executeAsync() throws Exception { + System.out.println("hiya, I'm forwarding..."); + complete(new ForwardResolution("/foo/bar.jsp")); + } + }; + } + + public boolean isCompleted() { return completed; } + }