Java EE 7: Using Non-blocking I/O in the
Servlet 3.1 API
Overview
Purpose
This tutorial covers how to use the non-blocking I/O
functionality with GlassFish and NetBeans. Non-blocking I/O was
introduced in Servlet 3.1, a new API in Java Platform, Enterprise
Edition 7 (Java EE 7) .
Time to Complete
Approximately 45 minutes
Introduction
Non-blocking I/O was introduced in Servlet 3.1(JSR
340) to develop scalable applications. Servlet 3.0 allowed
asynchronous request processing, but the API allowed only
traditional I/O, which can restrict scalability of your
applications. In a typical application, ServletInputStream
is read in a while loop. However, if the incoming
data is blocked or is streamed slower, the server thread must wait
for the data. The same situation can happen if the data is written
to ServletOutputStream.
Servlet 3.1 resolves the problem by adding event listeners: ReadListener
and WriteListener interfaces. You register these
event listeners by using ServletInputStream.setReadListener
and ServletOutputStream.setWriteListener. The
listeners have callback methods that are invoked when the content
is available to be read or that can be written without blocking.
In this tutorial, you learn how to use the new non-blocking I/O
API with an example of non-blocking read and then non-blocking
write.
Create a Java EE 7 web application.
Modify index.html to include an HTML5 file
upload control to enable the user to select a file.
Develop two Java classes that implement
ReadListener and WriteListener
interfaces.
Develop a servlet that performs a non-blocking I/O. The
servlet reads the contents of the file selected by the user and
writes the contents of the file as a response by using
non-blocking I/O.
Deploy the project to the GlassFish Server.
Test the project.
Hardware and Software Requirements
The following is a list of hardware and software requirements:
Download and install the latest JDK from this link (Java Platform, Standard Edition 7u21
recommended).
Download and install NetBeans 7.3.1 with Java EE, which
includes GlassFish 4 (Java EE download bundle), from this link. During installation, be sure to
select the check box to install GlassFish. JUnit is an optional
installation and is not required for this tutorial.
Download and unzip SampleFiles.zip,
which contains two sample input files to upload.
Prerequisites
Before starting this tutorial, you should:
Have installed the required software.
Ensure that NetBeans is running.
Creating a Web Application
In this section, you create a Java EE 7 web application in the
NetBeans IDE.
The onchange event of the <input
type="file"> element is assigned to the fileSelected()
JavaScript method. Each time you browse and select a file
on your local system, this event is raised.
Add the following lines of code to display the attributes of
the file to be uploaded:
The submit button is attached to the onsubmit
event. When you click submit, it makes an HTTP POST
request to the UploadServlet, as specified
in the action attribute of the form.
Add the fileSelected()
JavaScript function to the <head> section.
The <input type="file"/> element
provides access to the FileList object,
which is new in HTML5 and is part of the File API
specifications. A FileList object is a
collection of file objects and has the following
properties:
name: Name of the file (excluding any path)
type: MIME type of the file (in lowercase)
size: Size of the file in bytes
Because <input type="file"/>
provides access to this information on the client side,
the fileSelected() JavaScript method
accesses the FileList object and provides
information about the file that the user selected.
Note: <meta http-equiv="Content-Type"
content="text/html; charset=UTF-8">, this
NetBeans generated code can be optionally added to the <head>
section.
Developing the WriteListenerImpl Class
In this section, you develop the WriteListenerImpl
class, which performs write operations in a non-blocking mode. WriteListenerImpl
implements the WriteListener interface. This
implementation has two callback methods:
onWritePossible() is invoked when data is
available to be written.
onError() is invoked if the request generates an
error.
Perform the following steps to implement the WriteListenerImpl
class:
On the Projects tab, right-click Html5andServlet3.1
and select New > Other.
public void onError(final Throwable t) {
context.complete();
t.printStackTrace();
}View Image
Developing the ReadListenerImpl Class
In this section, you develop the ReadListenerImpl
class, which performs the read operation in a non-blocking mode. ReadListenerImpl
implements the ReadListener interface. This
implementation has three callback methods:
onDataAvailable is called when data can be read
without blocking.
onAllDataRead is invoked when data for the
current request is completely read.
onError is invoked if the request generates an
error.
Perform the following steps to implement the ReadListenerImpl
class:
On the Projects tab, right-click Html5andServlet3.1
and select New > Other.
Modify the class to implement the ReadListener
interface.
public class ReadListenerImpl implements
ReadListener
Declare the following variables:
private ServletInputStream input = null;
private HttpServletResponse res = null;
private AsyncContext ac = null;
private Queue queue = new LinkedBlockingQueue(); View Image
Add a constructor to the class.
ReadListenerImpl(ServletInputStream in,
HttpServletResponse r, AsyncContext c) {
input = in;
res = r;
ac = c;
} View Image
Add the onDataAvailable()
method.
public void onDataAvailable() throws IOException {
System.out.println("Data is available");
StringBuilder sb =
new StringBuilder();
int len = -1;
byte b[] = new
byte[1024];
while
(input.isReady() && (len = input.read(b)) != -1) {
String data = new String(b, 0, len);
sb.append(data);
}
queue.add(sb.toString());
} View Image
Add the onAllDataRead()method.
public void onAllDataRead() throws IOException {
System.out.println("Data is all read");
// now all data are
read, set up a WriteListener to write
ServletOutputStream
output = res.getOutputStream();
WriteListener
writeListener = new WriteListenerImpl(output, queue, ac);
output.setWriteListener(writeListener);
}View Image
After ServletInputStream.setReadListener is
called, ReadListener#onDataAvailable is
invoked immediately if there is data to read. Otherwise,
it is invoked when the data is ready. When all data is
read, ReadListenerImpl#onAllDataRead sets up
a WriteListenerImpl for writing data in a
non-blocking mode.
Developing the UploadServlet Servlet
In this section, you develop a servlet, UploadServlet,
which reads and writes the contents of a file with the
non-blocking I/O Servlet 3.1 API. The servlet processes the HTTP
POST request made by the client asynchronously.
The servlet performs the following to implement non-blocking I/O:
Obtains an input stream and/or an output stream from the
request and response objects.
Assigns a read listener to the input stream and a write
listener to the output stream.
Processes the request and the response inside the listener's
callback methods.
On the Projects tab, right-click Html5andServlet3.1
and select New > Other.