0

sometimes my Servlet ends with this exception:

    WARNING: StandardWrapperValve[HeartBeatServlet]: PWC1406: Servlet.service() for servlet HeartBeatServlet threw exception
java.lang.IllegalStateException: Not Suspended
    at com.sun.grizzly.tcp.Response.resume(Response.java:768)
    at org.apache.catalina.connector.Request.asyncComplete(Request.java:3993)
    at org.apache.catalina.connector.AsyncContextImpl.complete(AsyncContextImpl.java:242)
    at com.northcane.talkeen.HeartBeatServlet.doPost(HeartBeatServlet.java:47)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:688)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:722)

and here's my Servlet's source. The only thing it does is to handle long-polling requests from javascript client and sends message received on POST to all of them:

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import javax.servlet.AsyncContext;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@WebServlet(name = "HeartBeatServlet", urlPatterns = {"/HeartBeatServlet"}, asyncSupported = true)
public class HeartBeatServlet extends HttpServlet {

    private List<AsyncContext> asyncContextList = new LinkedList<>();

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) {
        AsyncContext asyncContext = request.startAsync(request, response);
        asyncContext.setTimeout(30000);
        asyncContextList.add(asyncContext);
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) {
        String test = request.getParameter("message");
        List<AsyncContext> asyncContexts = new ArrayList<>(asyncContextList);
        asyncContextList.clear();
        for (AsyncContext asyncContext : asyncContexts) {
            ServletResponse res = asyncContext.getResponse();
            res.setContentType("text/html");
            try {
                PrintWriter out = asyncContext.getResponse().getWriter();
                out.println(test + " <br />");
                out.flush();
                asyncContext.complete();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

is there something wrong I do? Thanks

xwinus
  • 886
  • 3
  • 12
  • 28

1 Answers1

0

(The code has Multi-threading issues. Pls see this SO answer for how to resolve them.)

The code is storing the AsyncContext for a GET request in a List and on a POST completes the GET response. But because of the timeout, the GET response may have completed implicitly (triggered by the servlet container) and the stored AsyncContext will not reflect this. So, when you retrieve this stored AsyncContext and try to complete the GET request, the servlet container does not find a pending GET request that needs to be resumed. Hence the IllegalStateException.

Pls also refer this other answer which indirectly answers this.

Community
  • 1
  • 1
2020
  • 2,821
  • 2
  • 23
  • 40