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?

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

Reply via email to