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

Reply via email to