On Aug 16, 2013, at 12:32 PM, Mark Thomas <ma...@apache.org> wrote: > On 16/08/2013 17:08, Daniel Mikusa wrote: >> I have a simple echo servlet which uses the Servlet 3.1 Non-Blocking IO API. >> It creates a ReadListener, that reads the request's input, buffers it, >> creates a WriteListener that takes the buffered input and echoes it back to >> the response. >> >> Most of the time this works OK, but when I send a request with no input data >> I get the following error. >> >> 6-Aug-2013 11:18:09.523 INFO [main] >> org.apache.catalina.startup.Catalina.start Server startup in 1452 ms >> java.lang.IllegalStateException: The non-blocking write listener has already >> been set >> at org.apache.coyote.Response.setWriteListener(Response.java:583) >> at >> org.apache.catalina.connector.OutputBuffer.setWriteListener(OutputBuffer.java:665) >> at >> org.apache.catalina.connector.CoyoteOutputStream.setWriteListener(CoyoteOutputStream.java:162) >> at >> com.pivotal.demos.nbio.EchoNbioServlet$1.onAllDataRead(EchoNbioServlet.java:77) >> at >> org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:384) >> at >> org.apache.coyote.http11.AbstractHttp11Processor.asyncDispatch(AbstractHttp11Processor.java:1607) >> at >> org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:622) >> at >> org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223) >> at >> org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1592) >> at >> org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1550) >> at >> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) >> at >> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) >> at java.lang.Thread.run(Thread.java:724) >> 16-Aug-2013 11:20:13.205 SEVERE [http-nio-8080-exec-7] >> org.apache.catalina.connector.CoyoteAdapter.asyncDispatch Exception while >> processing an asynchronous request >> java.lang.NullPointerException >> at >> org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:429) >> at >> org.apache.coyote.http11.AbstractHttp11Processor.asyncDispatch(AbstractHttp11Processor.java:1607) >> at >> org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:622) >> at >> org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223) >> at >> org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1592) >> at >> org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1550) >> at >> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) >> at >> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) >> at java.lang.Thread.run(Thread.java:724) >> >> Looking into it, what appears to be happening is that the >> "ReadListener.onAllDataRead()" method is being called twice. Because I'm >> setting the WriteListener in the "onAllDataRead" method, the second >> invocation of "onAllDataRead" causes the IllegalStateException. I was >> assuming that "onAllDataRead" should only be called once and so it would be >> OK to set the WriteListener in that method. Can "onAllDataRead" be >> legitimately called multiple times? > > No. Any chance you could convert the code below into a Tomcat unit test?
Sure. I've opened a bug report and attached it there. Here's the link. https://issues.apache.org/bugzilla/show_bug.cgi?id=55438 Dan > > Mark > >> >> Thanks >> >> Dan >> >> Code below… >> >> Servlet >> ---------- >> >> protected void doPost(HttpServletRequest req, HttpServletResponse resp) >> throws ServletException, IOException { >> // 1. Start Async >> final AsyncContext asyncContext = req.startAsync(); >> final ServletInputStream servletInputStream = >> asyncContext.getRequest().getInputStream(); >> >> // 2. Add Read Listener to get user's input >> ReadListener listener = new ReadListener() { >> >> private StringBuilder sb = new StringBuilder(); // >> buffer user's request >> >> public void onDataAvailable() throws IOException { >> // 4. Read all the data that is available, may >> be called multiple times >> try { >> byte[] b = new byte[8192]; >> int read = 0; >> do { >> read = servletInputStream.read(b); >> if (read == -1) { >> break; >> } >> sb.append(new String(b, 0, read)); >> System.out.println("Buffer is now [" + >> sb.length() + "] characters"); >> } while (servletInputStream.isReady()); >> } catch (Exception ex) { >> ex.printStackTrace(System.err); >> asyncContext.complete(); >> } >> } >> >> // 5. Called when all data has been read >> >> public void onAllDataRead() throws IOException { >> final ServletOutputStream outputStream = >> asyncContext.getResponse().getOutputStream(); >> >> final String output = sb.toString(); >> >> // 6. Configure a write listener to echo the >> response >> WriteListener listener = new WriteListener() { >> public void onWritePossible() throws >> IOException { >> // 7. Write output >> if (outputStream.isReady()) { >> >> outputStream.print(output); >> } >> >> // 8. Call complete, to signal >> we are done >> asyncContext.complete(); >> } >> >> public void onError(Throwable >> throwable) { >> >> throwable.printStackTrace(System.err); >> asyncContext.complete(); >> } >> }; >> outputStream.setWriteListener(listener); >> } >> >> public void onError(Throwable throwable) { >> throwable.printStackTrace(System.err); >> asyncContext.complete(); >> } >> }; >> >> // 3. Add listener, starts Non-blocking IO support >> servletInputStream.setReadListener(listener); >> } >> >> Client >> -------- >> >> public static void main(String[] args) throws Exception { >> URL url = new >> URL("http://localhost:8080/tomcat-8-demos/non-blocking-io/EchoNbioServlet"); >> HttpURLConnection connection = >> (HttpURLConnection) url.openConnection(); >> connection.setDoOutput(true); >> connection.setReadTimeout(1000000); >> connection.connect(); >> OutputStream os = null; >> try { >> os = connection.getOutputStream(); >> // do nothing >> } finally { >> if (os != null) { >> try { >> os.close(); >> } catch (IOException ioe) { >> // Ignore >> } >> } >> } >> >> int rc = connection.getResponseCode(); >> InputStream is; >> if (rc < 400) { >> is = connection.getInputStream(); >> } else { >> is = connection.getErrorStream(); >> } >> >> StringBuilder sb = new StringBuilder(); >> BufferedInputStream bis = null; >> try { >> bis = new BufferedInputStream(is); >> byte[] buf = new byte[2048]; >> int rd = 0; >> while((rd = bis.read(buf)) > 0) { >> sb.append(new String(buf, "utf-8")); >> } >> } finally { >> if (bis != null) { >> try { >> bis.close(); >> } catch (IOException e) { >> // Ignore >> } >> } >> } >> System.out.println("Resp: [" + sb.toString() + "]"); >> } >> >> >> >> --------------------------------------------------------------------- >> To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org >> For additional commands, e-mail: users-h...@tomcat.apache.org >> > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org > For additional commands, e-mail: users-h...@tomcat.apache.org > --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org