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

Reply via email to