Author: markt Date: Sat Aug 28 11:07:39 2010 New Revision: 990342 URL: http://svn.apache.org/viewvc?rev=990342&view=rev Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=49698 Allow listeners to call complete when a async request times out Add a test case based on pero's previous timeout test case
Modified: tomcat/trunk/java/org/apache/catalina/core/AsyncContextImpl.java tomcat/trunk/test/org/apache/catalina/core/TestAsyncContextImpl.java tomcat/trunk/webapps/docs/changelog.xml Modified: tomcat/trunk/java/org/apache/catalina/core/AsyncContextImpl.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/AsyncContextImpl.java?rev=990342&r1=990341&r2=990342&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/core/AsyncContextImpl.java (original) +++ tomcat/trunk/java/org/apache/catalina/core/AsyncContextImpl.java Sat Aug 28 11:07:39 2010 @@ -51,7 +51,7 @@ public class AsyncContextImpl implements public static enum AsyncState { NOT_STARTED, STARTED, DISPATCHING, DISPATCHED, COMPLETING, TIMING_OUT, - ERROR_DISPATCHING + TIMING_OUT_NEED_COMPLETE, ERROR_DISPATCHING } private static final Log log = LogFactory.getLog(AsyncContextImpl.class); @@ -82,13 +82,19 @@ public class AsyncContextImpl implements } if (state.get()==AsyncState.COMPLETING) { //do nothing - } else if (state.compareAndSet(AsyncState.DISPATCHED, AsyncState.COMPLETING) || - state.compareAndSet(AsyncState.STARTED, AsyncState.COMPLETING)) { + } else if (state.compareAndSet(AsyncState.DISPATCHED, + AsyncState.COMPLETING) || + state.compareAndSet(AsyncState.STARTED, + AsyncState.COMPLETING) || + state.compareAndSet(AsyncState.TIMING_OUT_NEED_COMPLETE, + AsyncState.COMPLETING)) { AtomicBoolean dispatched = new AtomicBoolean(false); - request.getCoyoteRequest().action(ActionCode.ACTION_ASYNC_COMPLETE,dispatched); + request.getCoyoteRequest().action(ActionCode.ACTION_ASYNC_COMPLETE, + dispatched); if (!dispatched.get()) doInternalComplete(false); } else { - throw new IllegalStateException("Complete not allowed. Invalid state:"+state.get()); + throw new IllegalStateException( + "Complete not allowed. Invalid state:"+state.get()); } } @@ -296,10 +302,14 @@ public class AsyncContextImpl implements } public void doInternalDispatch() throws ServletException, IOException { - if (this.state.compareAndSet(AsyncState.TIMING_OUT, AsyncState.COMPLETING)) { + if (this.state.compareAndSet(AsyncState.TIMING_OUT, + AsyncState.TIMING_OUT_NEED_COMPLETE)) { log.debug("TIMING OUT!"); boolean listenerInvoked = false; - for (AsyncListenerWrapper listener : listeners) { + List<AsyncListenerWrapper> listenersCopy = + new ArrayList<AsyncListenerWrapper>(); + listenersCopy.addAll(listeners); + for (AsyncListenerWrapper listener : listenersCopy) { listener.fireOnTimeout(event); listenerInvoked = true; } Modified: tomcat/trunk/test/org/apache/catalina/core/TestAsyncContextImpl.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/core/TestAsyncContextImpl.java?rev=990342&r1=990341&r2=990342&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/catalina/core/TestAsyncContextImpl.java (original) +++ tomcat/trunk/test/org/apache/catalina/core/TestAsyncContextImpl.java Sat Aug 28 11:07:39 2010 @@ -17,9 +17,12 @@ package org.apache.catalina.core; +import java.io.File; import java.io.IOException; import javax.servlet.AsyncContext; +import javax.servlet.AsyncEvent; +import javax.servlet.AsyncListener; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -308,4 +311,70 @@ public class TestAsyncContextImpl extend } } + public void testTimeout() throws Exception { + // Setup Tomcat instance + Tomcat tomcat = getTomcatInstance(); + + // Must have a real docBase - just use temp + File docBase = new File(System.getProperty("java.io.tmpdir")); + + // Create the folder that will trigger the redirect + File foo = new File(docBase, "async"); + if (!foo.exists() && !foo.mkdirs()) { + fail("Unable to create async directory in docBase"); + } + + Context ctx = tomcat.addContext("/", docBase.getAbsolutePath()); + + TimeoutServlet timeout = new TimeoutServlet(); + + Wrapper wrapper = Tomcat.addServlet(ctx, "time", timeout); + wrapper.setAsyncSupported(true); + ctx.addServletMapping("/async", "time"); + + tomcat.start(); + ByteChunk res = getUrl("http://localhost:" + getPort() + "/async"); + assertEquals("OK", res.toString()); + } + + private static class TimeoutServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + if (req.isAsyncSupported()) { + resp.getWriter().print("OK"); + final AsyncContext ac = req.startAsync(); + ac.setTimeout(2000); + + ac.addListener(new TimeoutListener()); + } else + resp.getWriter().print("FAIL: Async unsupported"); + } + } + + private static class TimeoutListener implements AsyncListener { + + @Override + public void onComplete(AsyncEvent event) throws IOException { + // NO-OP + } + + @Override + public void onTimeout(AsyncEvent event) throws IOException { + event.getAsyncContext().complete(); + } + + @Override + public void onError(AsyncEvent event) throws IOException { + // NOOP + } + + @Override + public void onStartAsync(AsyncEvent event) throws IOException { + // NOOP + } + + } } Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=990342&r1=990341&r2=990342&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Sat Aug 28 11:07:39 2010 @@ -52,6 +52,10 @@ refactoring. (markt) </fix> <fix> + <bug>49698</bug>: Allow a listener to complete an asynchronous request + if it times out. (markt) + </fix> + <fix> <bug>49714</bug>: The annotation process of Jar doesn't influence distributable element of web.xml. (kfujino) </fix> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org