public class AsyncContextImpl implements AsyncContext {
public static enum AsyncState {
- NOT_STARTED, STARTED, DISPATCHING, DISPATCHING_INTERNAL, DISPATCHED,
- COMPLETING, TIMING_OUT, ERROR_DISPATCHING
+ NOT_STARTED, STARTED, DISPATCHING, DISPATCHING_RUNNABLE, DISPATCHED,
+ COMPLETING, COMPLETING_RUNNABLE, TIMING_OUT, ERROR_DISPATCHING
}
private static final Log log = LogFactory.getLog(AsyncContextImpl.class);
AtomicBoolean dispatched = new AtomicBoolean(false);
request.getCoyoteRequest().action(ActionCode.ACTION_ASYNC_COMPLETE,dispatched);
if (!dispatched.get()) doInternalComplete(false);
+ } else if (state.compareAndSet(AsyncState.DISPATCHING_RUNNABLE,
+ AsyncState.COMPLETING_RUNNABLE)) {
+ // do nothing
} else {
throw new IllegalStateException("Complete not allowed. Invalid state:"+state.get());
}
log.debug("AsyncContext Start Called["+state.get()+"; "+request.getRequestURI()+"?"+request.getQueryString()+"]", new DebugException());
}
- if (state.compareAndSet(AsyncState.STARTED, AsyncState.DISPATCHING_INTERNAL) ||
- state.compareAndSet(AsyncState.DISPATCHED, AsyncState.DISPATCHING_INTERNAL)) {
+ if (state.compareAndSet(AsyncState.STARTED, AsyncState.DISPATCHING_RUNNABLE) ||
+ state.compareAndSet(AsyncState.DISPATCHED, AsyncState.DISPATCHING_RUNNABLE)) {
// TODO SERVLET3 - async
final ServletContext sctx = getServletRequest().getServletContext();
Runnable r = new Runnable() {
}
public boolean isStarted() {
- return (state.get() == AsyncState.STARTED || state.get() == AsyncState.DISPATCHING);
+ return (state.get() == AsyncState.STARTED ||
+ state.get() == AsyncState.DISPATCHING ||
+ state.get() == AsyncState.DISPATCHING_RUNNABLE);
}
public void setStarted(Context context) {
dispatch = null;
}
}
- } else if (this.state.get() == AsyncState.DISPATCHING_INTERNAL) {
+ } else if (this.state.get() == AsyncState.DISPATCHING_RUNNABLE) {
if (this.dispatch!=null) {
try {
dispatch.run();
else throw new ServletException(x);
} finally {
dispatch = null;
- this.state.set(AsyncState.DISPATCHED);
+ }
+ if (this.state.compareAndSet(AsyncState.COMPLETING_RUNNABLE,
+ AsyncState.COMPLETING)) {
+ doInternalComplete(false);
+ } else if (this.state.get() == AsyncState.DISPATCHING_RUNNABLE) {
+ doInternalComplete(true);
+ throw new IllegalStateException(
+ "Failed to call dispatch() or complete() after start()");
}
}
} else if (this.state.get()==AsyncState.COMPLETING) {
// Call the servlet once
getUrl("http://localhost:" + getPort() + "/");
- assertEquals("", servlet.getErrors());
+ assertEquals("1false2true3true4true5false", servlet.getResult());
}
private static class Bug49528Servlet extends HttpServlet {
private static final long serialVersionUID = 1L;
- private StringBuilder errors = new StringBuilder();
+ private StringBuilder result = new StringBuilder();
- public String getErrors() {
- return errors.toString();
+ public String getResult() {
+ return result.toString();
}
@Override
final HttpServletResponse resp)
throws ServletException, IOException {
- confirmFalse("1", req);
+ result.append('1');
+ result.append(req.isAsyncStarted());
req.startAsync();
- confirmTrue("2", req);
+ result.append('2');
+ result.append(req.isAsyncStarted());
req.getAsyncContext().start(new Runnable() {
@Override
public void run() {
try {
- confirmTrue("3", req);
+ result.append('3');
+ result.append(req.isAsyncStarted());
Thread.sleep(1000);
- confirmTrue("4", req);
+ result.append('4');
+ result.append(req.isAsyncStarted());
req.getAsyncContext().complete();
- confirmFalse("5", req);
+ result.append('5');
+ result.append(req.isAsyncStarted());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// when debugging
req.getMethod();
}
-
- private void confirmFalse(String stage, HttpServletRequest req) {
- if (req.isAsyncStarted()) {
- errors.append("Stage " + stage +
- ": Async started when not expected\n");
- }
- }
-
- private void confirmTrue(String stage, HttpServletRequest req) {
- if (!req.isAsyncStarted()) {
- errors.append("Stage " + stage +
- ": Async not started when expected\n");
- }
- }
-
}
}