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: [email protected]
> For additional commands, e-mail: [email protected]
>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]