Java EE 7 SDK |
This sample application that simulates a Weather Station demonstrates (a) how to use the non-blocking I/O functionality in servlets (b) how to parse the arguments of the URL (c) how to do a curl query and how to parse and analyze the respond.
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.
The server executes the reverse operation, in a non blocking manner. This means that the server is not blocked until the end of the conversation with the client.
Then, we proceed with the execution of a code that examine the parameters on the URL line. The client prints the name and values of the parameters. This is a concrete example demonstrating the analysis of parameters i.e. how to communicate from the external world with the client's program.
At last, the client executes the curl
query in order
to download the information about the city, given in a parameter (city
code), on the URL line.
Notice that all the useful work is accomplished in the client. We could also balance the work by making the server executing the Internet query. This is just a choice!
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".
Then the servlet executes the code to analyse the URL parameters:
@WebServlet(name = "ClientTest", urlPatterns = {"/*"}) public class ClientTest extends HttpServlet { protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); ... // Start parsing of parameters Enumeration paramNames = request.getParameterNames(); out.print("Parameter Analysis...
"); out.println("
Parameter Name | " + "Parameter Value |
---|---|
" + paramName + "\n | ");
String[] paramValues = request.getParameterValues(paramName);
if (paramValues.length == 1)
{
String paramValue = paramValues[0];
if (paramValue.length() == 0)
out.println("No Value");
else
out.println(paramValue);
}
else
{
out.println("
|
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/weather-station-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. ../glassfish5)
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>/weather-station-war/?City=132&Second_param=Bonjour&Tird_param=Hangzhou
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 weather-station-war
, and click Open Project.weather-station-war
and select Run to build, deploy, and run the project.If you have problems when running the application, refer the troubleshooting document.
Copyright © 2017 Oracle and/or its affiliates. All rights reserved.