package net.sourceforge.stripes.controller; import net.sourceforge.stripes.action.ActionBean; import net.sourceforge.stripes.action.Resolution; import net.sourceforge.stripes.util.Log; import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.reflect.Method; /** * Concrete implementation for AsyncResponse in Servlet3 containers. * Handles cleanup on completion, and delegates to servlet's AsyncContext methods. * This class is loaded via reflection and should not be linked to, for compat reasons. */ public class AsyncResponseServlet3 extends AsyncResponse { private final static Log log = Log.getInstance(AsyncResponseServlet3.class); private final AsyncContext asyncContext; public AsyncResponseServlet3(HttpServletRequest request, HttpServletResponse response, ActionBean bean, Method handler) { super(request, response, bean, handler); this.asyncContext = request.startAsync(request, response); // remove currentContext ThreadLocal ExecutionContext.clearContextThreadLocal(); // start async processing log.debug("Starting async processing from action ", bean); // register listener for finalizing the async processing asyncContext.addListener(new AsyncListener() { private boolean completed = false; private void doComplete() { if (!completed) { completed = true; cleanup(); } } public void onComplete(AsyncEvent event) throws IOException { log.debug("Async context completed=", event.getAsyncContext()); notifyListenersComplete(); doComplete(); } public void onTimeout(AsyncEvent event) throws IOException { log.warn("Async context timeout after ", event.getAsyncContext().getTimeout(), "ms, ctx=", event.getAsyncContext()); HttpServletResponse response = (HttpServletResponse) event.getSuppliedResponse(); notifyListenersTimeout(); response.sendError(500, "Operation timed out"); getAsyncContext().complete(); doComplete(); } public void onError(AsyncEvent event) throws IOException { log.error("Async context error=", event.getAsyncContext()); Throwable err = event.getThrowable(); notifyListenersError(err); HttpServletResponse response = (HttpServletResponse) event.getSuppliedResponse(); String msg = err != null ? err.getMessage() : ""; response.sendError(500, msg); doComplete(); } // this one is not called because we register the listener after starting the async context... public void onStartAsync(AsyncEvent event) throws IOException { log.debug("Async context started=", event.getAsyncContext(), "request=", event.getSuppliedRequest(), "response=", event.getSuppliedResponse()); } }); } public AsyncContext getAsyncContext() { return asyncContext; } public void complete() { log.debug("Completing AsyncResponse ", this); getAsyncContext().complete(); } public void complete(Resolution resolution) { log.debug("Completing AsyncResponse ", this, " with Resolution ", resolution); try { resolution.execute(getRequest(), getResponse()); } catch (Exception e) { throw new RuntimeException(e); } } @Override public void dispatch(String path) { log.debug("Dispatching AsyncResponse ", this, " to path ", path); getAsyncContext().dispatch(path); } @Override public long getTimeout() { return getAsyncContext().getTimeout(); } @Override public void setTimeout(long timeout) { getAsyncContext().setTimeout(timeout); } }