Reputation: 447
Sometimes the method req.startAsync()
from HttpServletRequest
throws an IllegalStateException
(Response has been closed already).
How can I check the request state in order to avoid IllegalStateException
?
req.isAsyncSupported()
returns true always.
Relevant code:
final HttpSession httpSession = req.getSession(false);
if (httpSession == null) {
resp.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
return;
}
final AsyncContext asynContext = req.startAsync(); //exception here`
Exception:
12:28:12,735 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/esus].[LongPollServlet]] (http-/0.0.0.0:8080-2) JBWEB000236: Servlet.service() for servlet LongPollServlet threw exception: java.lang.IllegalStateException: JBWEB000049: Response has been closed already at org.apache.catalina.connector.Request.startAsync(Request.java:3180) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.catalina.connector.Request.startAsync(Request.java:3170) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.catalina.connector.RequestFacade.startAsync(RequestFacade.java:925) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at com.performer.framework.server.LongPollServlet.continueDoPost(LongPollServlet.java:75) [st10.framework.webserver.jar:] at com.performer.framework.server.LongPollServlet.doPost(LongPollServlet.java:62) [st10.framework.webserver.jar:] at javax.servlet.http.HttpServlet.service(HttpServlet.java:754) [jboss-servlet-api_3.0_spec-1.0.2.Final-redhat-1.jar:1.0.2.Final-redhat-1] at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [jboss-servlet-api_3.0_spec-1.0.2.Final-redhat-1.jar:1.0.2.Final-redhat-1] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:295) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:149) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8] at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8] at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:169) [jboss-as-web-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:145) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:97) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:102) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:336) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:856) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:653) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:915) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at java.lang.Thread.run(Unknown Source) [rt.jar:1.6.0_34]
Upvotes: 0
Views: 3119
Reputation: 2735
You want to check the response, not the request state, as startAsync()
cannot be called when the original response is closed.
You should be able to see from your code where is closes the response (e.g. if it calls response.close();
somewhere). You should call startAsync()
before this point, or set a flag once it has been called and check that before calling startAsync()
.
If you do not handle the response at all you can try to test The HttpServletResponse
to see if it's been closed, but there is no definite way to do that:
if (!isClosed(response.getOutputStream())) {
startAsync();
// ...
For discussion of implementation of isClosed()
, see this answer. There is no easy or recommended way, but if you're desparate this may work (untested) but it does write to the response output stream, which is dangerous:
boolean isClosed(ServletOutputStream sos) {
try {
os.println(""); // This will append extra line feed to the HTTP response!
return false;
} catch(IOException e) {
return true; // assume due to stream being closed
}
}
Alternatively, you can possibly rely on response.isCommitted()
(see doc) as a committed response would typically be closed, however this isn't definite - it could be closed but not committed.
Upvotes: 1
Reputation: 10707
Acording to documentation for startAsync():
Throws: IllegalStateException - if this request is within the scope of a filter or servlet that does not support asynchronous operations (that is, isAsyncSupported() returns false), or if this method is called again without any asynchronous dispatch (resulting from one of the AsyncContext#dispatch methods), is called outside the scope of any such dispatch, or is called again within the scope of the same dispatch, or if the response has already been closed.
It seems that Tomcat has isAsyncSupported()
set to true
.
You can set the async attribute in the HttpServletRequest
object to true
by:
req.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
or
((org.apache.catalina.connector.Request)req).setAsyncSupported(true);
You also have to add in front of your servlet:
@WebServlet(... , asyncSupported = true)
Upvotes: 2