Java EE 7 SDK 

Samples Main Page

The Non-blocking I/O Read Servlet Sample Application

This sample application demonstrates how to use the non-blocking I/O functionality in servlets.

Description

In this sample application, the client (ClientTest) sends two parts of data to the server (ServerTest). The server registers a ReadListener, whose methods are called when events related to the input stream occur. The implementation of ReadListener in this application collects data and echoes it back in reverse order.

Client

In ClientTest, the client initiates an HTTP connection to the server and writes two parts of data with a two second pause between them, which simulates blocking from the client side.

@WebServlet(name = "ClientTest", urlPatterns = {"/"})
public class ClientTest extends HttpServlet {
    OutputStream output = null;
    InputStream input = null;

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

        URL url = new URL(urlPath);

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        ...
        conn.connect();
        ...
        output = conn.getOutputStream();
		String firstPart = "Hello";
        writeData(output, firstPart);
        Thread.sleep(2000);
        ...
		// Sending the second part
        input = conn.getInputStream();
        printEchoData(out, input);
    }
	
    protected void writeData(OutputStream output, String data) throws IOException {
        if (data != null && !data.equals("") && output != null) {
            output.write(data.getBytes());
            output.flush();
        }
    }
	
    protected void printEchoData(PrintWriter out, InputStream input) throws IOException {
        while (input.available() > 0 && input != null && out != null) {
            out.print((char) input.read());
        }
        out.println("</br>");
    }
}

The servlet uses OutputStream and InputStream to write and read data, and Thread.sleep() to pause the thread for two seconds to simulate I/O blocking. You can send larger blocks of data instead of "Hello World".

Server

In ServerTest, the server receives the request, starts the asynchronous processing of the request, and registers a ReadListener

@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 ServletInputStream input = request.getInputStream();
        final ServletOutputStream output = response.getOutputStream();
        input.setReadListener(new ServerReadListenerImpl(input, output, context));
    }
    ...
}

@WebServlet(..., asyncSupported = true) is an annotation that specifies the servlet name, its URL, and enables asynchronous processing. The setReadListener() method registers a read listener for the input stream.

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

Implementation of the Read Listener

ReadListenerImpl.java is the implementation of the ReadListener interface:

public class ReadListenerImpl implements ReadListener {

    public ServerReadListenerImpl() {
        ...
    }
	
    @Override
    public void onDataAvailable() {
        ...
        while (input.isReady() && !input.isFinished()) {
            sb.append((char) input.read()); // Use StringBuilder to append chars together
        }
    }

    @Override
    public void onAllDataRead() {
        ...
        output.print("Echo the reverse String from server: " + sb.reverse().toString() + "<br>");
        output.flush();
        ...
    }
    
    @Override
    public void onError(Throwable t) {
        ...
        System.out.println("--> onError");
    }

The onDataAvailable() method is invoked when data is available to be read from the input request stream. The container subsequently invokes the read() method if and only if isReady() returns true. The onAllDataRead() method is invoked when all the data from the request has been read. The onError(Throwable t) method is invoked if there is any error or exceptions occurs while processing the request. The isReady() method returns true if the underlying data stream is not blocked. At this point, the container invokes the onDataAvailable() method.

You can customize the constructor to handle different parameters. Usually, the parameters are ServletInputStream, ServletOutputStream, or AsyncContext. This sample uses all of them to implement the ReadListener interface.

Key Features

This sample application demonstrates the following key features:

Building, Deploying, and Running the Application

Following 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-read-war.
  3. Change directory to app_dir.
  4. Build, 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-read-war, and click Open Project.
  3. In the Projects tab, right click non-blocking-io-read-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.