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? 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