Java EE 7 SDK 

Samples Main Page

The Non-blocking I/O Write Servlet Sample Application

This is a simple servlet application that uses the non-blocking I/O API to demonstrate how to write to a response in a non-blocking manner.

Description

This sample application demonstrates how to use the WriteListener interface in servlets. The application consists of three elements: the client (ClientTest), the server (ServerTest), and the implementation of the WriteListener interface (WriteListenerImpl). The server registers the write listener, and when data is available to write to the response, it sends chunks of bytes to the client. The chunk size is pre-configured to simulate blocking (the maximum write buffer size). The client receives the data from the server and displays it on the page.

Client

In ClientTest.java, the client initiates an HTTP connection to server and waits for the response to show it on the page.

@WebServlet(name = "ClientTest", urlPatterns = {"/"})
public class ClientTest extends HttpServlet {

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
                                  throws ServletException, IOException {
        ...
        String urlPath = "http://"
            + request.getServerName()
            + ":" + request.getLocalPort() //8080
            + request.getContextPath()
            + "/ServerTest";

        URL url = new URL(urlPath);

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        ...
        conn.connect();
        ...
        BufferedReader input = new BufferedReader(new InputStreamReader(conn.getInputStream()));
		
        for (String line; input != null && (line = input.readLine()) != null;) {
            if (line.length() > 20) {
                out.println(line.substring(0, 20) + "</br>");
                out.flush();
            } else if (line.equals("---> Time out")) {
                out.println(line + "</br>");
                out.flush();
            }
        }
    }
    ...
}

Since the server sends several chunks of bytes, the length of the byte array is larger than the width of most browser windows, so some browsers would not display this correctly. In this sample, the length of the line is truncated to 20 characters.

Server

In ServerTest.java, after receiving a request the servlet starts the asynchronous request processing and registers the write listener.

@WebServlet(name="ServerTest", urlPatterns={"/ServerTest"}, asyncSupported = true)
public class ServerTest extends HttpServlet {

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
                                  throws ServletException, IOException {
        ... 
        final AsyncContext context = request.startAsync();
        final ServletOutputStream output = response.getOutputStream();
        output.setWriteListener(new ServerWriteListenerImpl(output, context));
    }
...
}

WebServlet(..., asyncSupported = true) is an annotation that specifies the servlet name, URL, and asynchronous processing support. The method setWriteListener() registers the write listener for the input stream.

Note: Non-blocking I/O only works with asynchronous request processing in servlets and filters.

Write Listener Implementation

WriteListenerImpl.java is the implementation of the WriteListener interface.

public class WriteListenerImpl implements WriteListener {
    public WriteListenerImpl() {
        ...
    }
	
    @Override
    public void onWritePossible() throws IOException {
	    ...
        while (output.isReady()) {
            if (System.currentTimeMillis() - startTime > 10000 || count > 10) {
                output.println("---> Time out");
                throw new Exception("Time out");
            }
            System.out.println("Writing data...... ");
            writeBytes(output, 'a');
            count++;
        }
        ...
    }

@Override public void onError(Throwable t) { ... System.out.println("--> onError"); } protected void writeBytes(ServletOutputStream output, char data) throws IOException { byte[] b = new byte[LENGTH]; Arrays.fill(b, 0, LENGTH, (byte) data); output.write(b); ... } }

The method onWritePossible() is invoked when data is available to write to the response stream. The container subsequently invokes the writeBytes() method if and only if isReady() returns true. The onError(Throwable t) method is invoked if any error or exceptions occur while writing to the response. The isReady() method returns true if the underlying data stream is not blocked. At this point, the container invokes the writeBytes() method.

You can customize the constructor to handle different parameters. The parameters can be ServletInputStream, ServletOutputStream, or AsyncContext. This sample uses ServletOutputStream and AsyncContext to implement the write listener.

Key Features

This sample application demonstrates the following key features:

Building, Deploying, and Running the Application

Follow these instructions for building, deploying, and running this sample application:

  1. Set up your build environment and configure the application server with which the build system has to work by following the common build instructions.
  2. app_dir is the sample application base directory: samples_install_dir/servlet/non-blocking-io-write-war.
  3. Change directory to app_dir.
  4. Build and deploy the sample application using the mvn target:
  5. Use the command below to run this sample using the Cargo framework:

    app_dir> mvn clean verify cargo:run

    You can point Cargo to an already installed and running Glassfish server:

    app_dir> mvn clean verify cargo:run -Dglassfish.home=$<glassfish_dir> (e.g. ../glassfish4)

    You can also build, deploy the sample application without Cargo:

    app_dir> mvn install

    app_dir> asadmin deploy ./target/<app_name>.war

  6. Run the sample as follows:

  7. Use the glassfish command line to undeploy the application.

    app_dir> asadmin undeploy <app_name>

  8. Use the target clean to remove the temporary directories like /target.

    app_dir> mvn clean

Building, Deploying, and Running the Application in NetBeans IDE

Perform the following steps to build, deploy, and run the application using NetBeans IDE:

  1. Refer to the common build instructions for setting up NetBeans IDE and Java EE 7 SDK.
  2. In the NetBeans IDE, choose File → Open Project (Ctrl-Shift-O), navigate to the samples_install_dir/servlet/ directory, select non-blocking-io-write-war, and click Open Project.
  3. In the Projects tab, right click non-blocking-io-write-war and select Run to build, deploy, and run the project.

Troubleshooting

If you have problems when running the application, refer the troubleshooting document.

 

Copyright © 1997-2013 Oracle and/or its affiliates. All rights reserved.