Using Asynchronous Servlets for Web Push Notifications
Overview
Purpose
This tutorial will show you how to implement Asynchronous
Servlets in a simple "shout-out" Web Application with real-time
updates.
Time to Complete
Approximately 45 minutes
- There is a long process to complete in order to calculate a response.
- There is a streaming response or one that is waiting for
some external data and in the meantime is in a waiting state.
Introduction
In Java EE 6, Asynchronous Servlets can be used to optimize resources in Web Applications. Asynchronous Servlets allow you to handle the request and write the response in a different thread to reduce idle time or processing on the server's thread pool. In a common Web Application, a thread is used per request. When a request comes to the Web Server, it assigns a thread to handle that request and return a response. When the Servlet ends processing the thread is freed and reused for another request.
There is a problem with this behavior; if a request takes long to complete then the thread may spend a long time to be freed. This is particularly problematic in two scenarios:
Asynchronous Servlets solve the two scenarios by deferring the
response and allowing another thread to write to it.
In this tutorial you will create a simple Web Application that uses Asyncrhonous Servlets and Long Polling for Web Push Notifications.
You can find more about the different Web Server Push
techniques as well as the different uses of Asynchronous
Servlets in the Summary of this
tutorial.
- Download and install Java JDK 7 from http://www.oracle.com/technetwork/java/javase/downloads/index.html
- Download and install NetBeans 7.2 from http://netbeans.org/downloads/index.html
- Download and install WebLogic Zip Distribution from http://www.oracle.com/technetwork/middleware/weblogic/downloads/index.html
- Screens and steps in this tutorial uses NetBeans IDE 7.2 and WebLogic 12.1.1 as the Web Server but you may use any other Java Servlet/JSP Container. A Java EE Web Profile compliant server is highly recommended. For more information on such servers refer to http://www.oracle.com/technetwork/java/javaee/overview/compatibility-jsp-136984.html
Software Requirements
The following is a list of software requirements:
- Have knowledge of the Java 7 Programming Language.
- Have basic knowledge of the Java EE 6 Platform, specifically Servlets and JSP.
- Have basic HTML and Javascript knowledge.
- This tutorial uses Java 7 syntax. In the code examples that requires change in code syntax if used with previous versions, refer to: http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html for changes in the Java 7 Platform.
Prerequisites
Before starting this tutorial, you should:
Creating a simple Java EE6 Web Application
For this tutorial you will create a simple Web Application
first.
Open NetBeans.
Go to: File > New Project

Select Java Web > Web Application and click Next.

Type a name for your Web Application and Click Next.

From the server list select Oracle WebLogic Server.
Select Java EE 6 Web from the Java EE Version dropdown list,
Click Next.

Leave all options unchecked in the Frameworks pane.
Click Finish and your application project will be
created and configured.

You have created a simple Web Application from NetBeans using Java EE 6.
Verify Web Application project configuration
To ensure you have the proper settings, verify the project
configuration.
Click File > Project Properties (Your project name).

In the Sources pane, select JDK 7 for the
Source/Binary Format.

Code samples in this tutorial uses Java 7 syntax
In the Run pane, verify the Java EE Version is Java EE 6 Web. The server dictates the Java EE Version setting. Selecting Oracle WebLogic Server sets the Java EE Version to Java EE 6 Web.
If you are running other Server
ensure that the Java EE Version is 6.
Make sure that Deploy on Save is checked. This
ensures that every change you make in the source code is
deployed to the Web Server, and you can see your changes in
real time.

Create the JSP view and Shout Servlet.
To begin you need a page that will invoke the Servlet services.
Open the project and open the index.jsp file
located under Web Pages if it's not already open.
Add the highlighted code.
index.jsp - Html layout.
<%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP Page</title> </head> <body> <h1>SHOUT-OUT!</h1> <form method="POST" action="shoutServlet"> <table> <tr> <td>Your name:</td> <td><input type="text" id="name" name="name"/></td> </tr> <tr> <td>Your shout:</td> <td><input type="text" id="message" name="message" /></td> </tr> <tr> <td><input type="submit" value="SHOUT" /></td> </tr> </table> </form> <h2> Current Shouts </h2> <div id="content"> <% if (application.getAttribute("messages") != null) {%> <%= application.getAttribute("messages")%> <% }%> </div> </body> </html>
To create the Servlet, right-click on Source Packages and select New > Java Class.

Name the class ShoutServlet and type com.example.shout in the Package field.

Start with a simple implementation of the Shout Servlet
that is synchronous and stores all the shouts in the Servlet
Context by adding the highlighted
code:
ShoutServlet.java - Simple Servlet implementation.
package com.example.shout; import java.io.IOException; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(urlPatterns = {"/shoutServlet"}) public class ShoutServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("name"); String message = request.getParameter("message"); String htmlMessage = "<p><b>" + name + "</b><br/>" + message + "</p>"; ServletContext sc = request.getServletContext(); if (sc.getAttribute("messages") == null) { sc.setAttribute("messages", htmlMessage); } else { String currentMessages = (String) sc.getAttribute("messages"); sc.setAttribute("messages", htmlMessage + currentMessages); } response.sendRedirect("index.jsp"); } }
To test the application, right-click on the project and
select Run.

A browser will open.
Fill the form with your name and type a message as Your shout. Click SHOUT.
You should see your shout posted in the browser.

Open another browser window and move it beside the first.
Post another shout by filling the form.
Notice only one browser updates.

In the next step you will learn how to use basic ajax code to
update the page using an Asynchronous Servlet.
Add the Asynchronous Servlet and JavaScript code.
You will create a simple implementation of Long Polling to
notify the browser of changes.
Open the index.jsp file.
Add the AJAX call to wait until a message is posted and print it on the page by adding the highlighted code.
index.jsp - Using AJAX for get method on ShoutServlet.
<%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP Page</title> </head> <body> <h1>SHOUT-OUT!</h1> <form method="POST" action="shoutServlet"> <table> <tr> <td>Your name:</td> <td><input type="text" id="name" name="name"/></td> </tr> <tr> <td>Your shout:</td> <td><input type="text" id="message" name="message" /></td> </tr> <tr> <td><input type="submit" value="SHOUT" /></td> </tr> </table> </form> <h2> Current Shouts </h2> <div id="content"> <% if (application.getAttribute("messages") != null) {%> <%= application.getAttribute("messages")%> <% }%> </div> <script> var messagesWaiting = false; function getMessages(){ if(!messagesWaiting){ messagesWaiting = true; var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange=function(){ if (xmlhttp.readyState==4 && xmlhttp.status==200) { messagesWaiting = false; var contentElement = document.getElementById("content"); contentElement.innerHTML = xmlhttp.responseText + contentElement.innerHTML; } } xmlhttp.open("GET", "shoutServlet?t="+new Date(), true); xmlhttp.send(); } } setInterval(getMessages, 1000); </script> </body> </html>
The code you added will continuously request the Shout
Servlet for a new message and append the response of
the Servlet to the content div.
You need to add the asynchronous support to the Servlet
and implement the message notification.
Open the ShoutServlet class
and add the highlighted code.
ShoutServlet.java - Asynchronous Servlet for notifications.
package com.example.shout; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import javax.servlet.AsyncContext; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(urlPatterns = {"/shoutServlet"}, asyncSupported=true) public class ShoutServlet extends HttpServlet { private List<AsyncContext> contexts = new LinkedList<>(); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { final AsyncContext asyncContext = request.startAsync(request, response); asyncContext.setTimeout(10 * 60 * 1000); contexts.add(asyncContext); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { List<AsyncContext> asyncContexts = new ArrayList<>(this.contexts); this.contexts.clear(); String name = request.getParameter("name"); String message = request.getParameter("message"); String htmlMessage = "<p><b>" + name + "</b><br/>" + message + "</p>"; ServletContext sc = request.getServletContext(); if (sc.getAttribute("messages") == null) { sc.setAttribute("messages", htmlMessage); } else { String currentMessages = (String) sc.getAttribute("messages"); sc.setAttribute("messages", htmlMessage + currentMessages); } for (AsyncContext asyncContext : asyncContexts) { try (PrintWriter writer = asyncContext.getResponse().getWriter()) { writer.println(htmlMessage); writer.flush(); asyncContext.complete(); } catch (Exception ex) { } } } }
When the Servlet receives a "get" Request, it starts an AsyncContext by calling: request.startAsync(request, response). This will notify the Web Container that at the end of the request call it should free the handling thread and leave the connection open so that other thread writes the response and end the connection.
The next thing you did in the code is adding the AsyncContext to a List so we can get all waiting contexts in the doPost method.
Then you modified the doPost
method to get a safe copy of the list of AsyncContext.Then
you cleared the common list to prevent a pending request to
be notified twice. Finally for all the AsyncContexts queued
you wrote the message to their responses and completed those
requests by calling asyncContext.complete()
Test your application by running it.
Right-click on your project name and Select Run.
A browser will open. Open another browser window and move
them side by side.
Fill the form with your name and type a message as Your shout. Click SHOUT.
You should see your shout posted on both browser windows.

The page still refreshes when you post a message. To make the page refresh partially when you submit a shout, add the highlighted code to the index.jsp file:
index.jsp - AJAX on get and post methods on ShoutServlet.
<%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP Page</title> </head> <body onload="getMessages();"> <h1>SHOUT-OUT!</h1> <form> <table> <tr> <td>Your name:</td> <td><input type="text" id="name" name="name"/></td> </tr> <tr> <td>Your shout:</td> <td><input type="text" id="message" name="message" /></td> </tr> <tr> <td><input type="button" onclick="postMessage();" value="SHOUT" /></td> </tr> </table> </form> <h2> Current Shouts </h2> <div id="content"> <% if (application.getAttribute("messages") != null) {%> <%= application.getAttribute("messages")%> <% }%> </div> <script> function postMessage() { var xmlhttp = new XMLHttpRequest(); xmlhttp.open("POST", "shoutServlet?t="+new Date(), false); xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); var nameText = escape(document.getElementById("name").value); var messageText = escape(document.getElementById("message").value); document.getElementById("message").value = ""; xmlhttp.send("name="+nameText+"&message="+messageText); } var messagesWaiting = false; function getMessages(){ if(!messagesWaiting){ messagesWaiting = true; var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange=function(){ if (xmlhttp.readyState==4 && xmlhttp.status==200) { messagesWaiting = false; var contentElement = document.getElementById("content"); contentElement.innerHTML = xmlhttp.responseText + contentElement.innerHTML; } } xmlhttp.open("GET", "shoutServlet?t="+new Date(), true); xmlhttp.send(); } } setInterval(getMessages, 1000); </script> </body> </html>
Your application is now complete. You can test it on your
browser and see how it updates automatically across
different browsers.
Summary / next steps
In this tutorial you learned the basics of Asynchronous
Servlets with a simple example that uses long polling for
notifications.
- Oracle Blog on: Asynchronous
Support in Servlet 3.0.
- Asynchronous
Servlets sample on the Java EE 6 code samples.
- API Pages: AsyncContext interface, WebServlet annotation, ServletRequest.startAsync method.
- The Servlet 3.0 specification.
- Oracle
courses and learning paths for Java EE 6.
- To learn more about Java EE 6 refer to additional OBEs in
the Oracle
Learning Library
- How does long polling works?
Long polling notifies the client by keeping the network connection open until there is a notification for the client at which point the response is written and the connection is closed. The client has to keep the connection open by opening a new connection every time the server responds or times out.
- Are there any other notification
mechanisms?
Yes there are a lot of notification mechanisms besides long polling, although arguably long polling is the easiest to implement from scratch in this tutorial. There is Comet (AJAX server push) Web Sockets (for persistent full duplex connections) Use of Java Applets for server communication, Flash XML Sockets, etc. - What are other uses of Asynchronous
Servlets?
Asynchronous Servlets are ideal in any scenario where the response cannot be completed when a request comes in a timely manner.
You can use Asynchronous Servlets in the following scenarios: - Server push (notifications) Since the response is delayed until a certain event happens.
- Calling external services that require an outbound connection, since the handling thread will wait on a external resource thus the response is delayed until another service responds.
- Waiting for resources like a database query result. Sometimes the application waits too long on such resources and that is iddle time of the request so you can implement asynchronous Servlets to reduce iddle time of the handling thread.
- What is the advantage of
Asynchronous Servlets.
Using Asynchronous Servlets frees the request handling thread allowing another connection to be opened and handled, greatly optimizing server load
- Lead Curriculum Developer: Eduardo Moranchel
Resources
For more information on the topics of this tutorial:
Questions and answers:
Credits
To help navigate this Oracle by Example, note the following:
- Hiding Header Buttons:
- Click the Title to hide the buttons in the header. To show the buttons again, simply click the Title again.
- Topic List Button:
- A list of all the topics. Click one of the topics to navigate to that section.
- Expand/Collapse All Topics:
- To show/hide all the detail for all the sections. By default, all topics are collapsed
- Show/Hide All Images:
- To show/hide all the screenshots. By default, all images are displayed.
- Print:
- To print the content. The content currently displayed or hidden will be printed.
To navigate to a particular section in this tutorial, select the topic from the list.