Java EE 7 SDK |
This sample application demonstrates how to use the non-blocking I/O functionality in servlets.
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.
This sample application demonstrates the following key features:
ReadListener
interface to avoid waiting for data inside a loop.Following these instructions for building, deploying, and running this sample application:
app_dir
is the sample application base
directory: samples_install_dir/servlet/non-blocking-io-read-war
.
Change directory to app_dir.
mvn
target: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
http://<javaee.server.name>:<javaee.server.port>/non-blocking-io-read-war
Sending to server: Hello
Sending to server: World
Echo data from server: dlroW olleH
Please check server log for details.
app_dir>
asadmin undeploy
<app_name>
clean
to remove the temporary directories
like /target.
app_dir> mvn
clean
Perform the following steps to build, deploy, and run the application using NetBeans IDE:
samples_install_dir/servlet/
directory, select non-blocking-io-read-war
, and click Open Project.non-blocking-io-read-war
and select Run to build, deploy, and run the project.If you have problems when running the application, refer the troubleshooting document.
Copyright © 1997-2013 Oracle and/or its affiliates. All rights reserved.