Introduction to AJAX

In this section lets discuss about Ajax and how to use ajax in JSP in a simple way.

AJAX (Asynchronous JavaScript and XML ) is a technology combining java script with XML to send/receive request/response from server asynchronously.

Consider a scenario where you have two drop down list boxes say Countries and States in a jsp form. The States drop down list has to be populated based on the user selection from Countries drop down list. The usual way of achieving this functionality is, allowing the user to select a country from Countries drop down list and submit the form using a submit button. Now process the request in the server side by getting the list of states (from DB) for that country and then return the response back to the jsp. This will work fine and it is the traditional way of programming. But imagine if you have n pairs of such drop down list. It won't be a good idea to make the user select each drop down list and submit the button for each child drop down list to be populated.

This is were AJAX comes to the rescue. Without submitting the entire page to fill up a drop down list box, we can actually send an asynchronous request to the server side process it and send the list of states back to UI. Everything happens in the background without user intervention.

Lets see how to do the same with an example. To make things interesting lets try to simulate online Live cricket score card (which updates whenever there is a change in score) between India Vs South Africa. Have a look at the jsp file below.

JSP File

<%@ page language="java" pageEncoding="UTF-8" contentType="text/html;charset=UTF-8" %>
<html>

<head></head>

<script language = "javascript">
var req;

function initRequest()
{
    if (window.XMLHttpRequest)
    {
        req = new XMLHttpRequest();
    }
    else if (window.ActiveXObject)
    {
        isIE = true;
        req = new ActiveXObject("Microsoft.XMLHTTP");
    }
}

var sessionClockIntialTime = 1;
var sessionClockFinalTime = 5;

function startClock()
{
    sessionClockIntialTime = sessionClockIntialTime+1;

    if(sessionClockIntialTime == sessionClockFinalTime)
    {
        initRequest();
        req.onreadystatechange = processResponse;

        var IndRuns = document.getElementById("IndRuns").innerHTML;
        var IndWks = document.getElementById("IndWks").innerHTML;
        var IndOvers = document.getElementById("IndOvers").innerHTML;
        var SouthRuns = document.getElementById("SouthRuns").innerHTML;
        var SouthWks = document.getElementById("SouthWks").innerHTML;
        var SouthOvers = document.getElementById("SouthOvers").innerHTML;
       
        var urli = "cricket?IndRuns="+ IndRuns +"&IndWks="+ IndWks +"&IndOvers="+IndOvers;
        var urls = "&SouthRuns="+ SouthRuns +"&SouthWks="+ SouthWks+"&SouthOvers="+SouthOvers;
        var url = urli + urls;
       
        req.open("GET", url, true);
        req.send(null);
        sessionClockIntialTime = 1;
        sessionClockFinalTime = 5;
    }
    setTimeout("startClock()", 5000)
}

function update()
{
    document.getElementById("IndRuns").innerHTML = '0';
    document.getElementById("IndWks").innerHTML = '0';
    document.getElementById("IndOvers").innerHTML = '0';
    document.getElementById("SouthRuns").innerHTML = '0';
    document.getElementById("SouthWks").innerHTML = '0';
    document.getElementById("SouthOvers").innerHTML = '0';
}

function processResponse()
{
    if (req.readyState==4)
    {
        var xmlDoc = req.responseText;
        xmlDoc = (new DOMParser()).parseFromString(xmlDoc, "text/xml");
       
        var ind = xmlDoc.getElementsByTagName('selectTeam')[0];
        var saf = xmlDoc.getElementsByTagName('selectTeam')[1];
        var res = xmlDoc.getElementsByTagName('Result')[0];
       
        document.getElementById("IndRuns").innerHTML = ind.childNodes[1].firstChild.nodeValue;
        document.getElementById("IndWks").innerHTML = ind.childNodes[2].firstChild.nodeValue;
        document.getElementById("IndOvers").innerHTML = ind.childNodes[3].firstChild.nodeValue;
        document.getElementById("SouthRuns").innerHTML = saf.childNodes[1].firstChild.nodeValue;
        document.getElementById("SouthWks").innerHTML = saf.childNodes[2].firstChild.nodeValue;
        document.getElementById("SouthOvers").innerHTML = saf.childNodes[3].firstChild.nodeValue;
        document.getElementById("Result").innerHTML = res.childNodes[0].firstChild.nodeValue;
    }
}
</script>

<script>startClock();</script>

<BODY onload="update();">
        <FORM name="Form1" method="POST" action="<%=request.getContextPath()%>/cricket">
                <p>Cricket ScoreCard: <span id="txtHint"/>
                </p>
                <table>
                        <tr>
                                <td>
                                        <p>India: <span id="IndRuns"/>/<span id="IndWks"/>
                                                <span id="IndOvers"/>  Overs</p>
                                </td>
                        </tr>
                        <tr>
                                <td>
                                        <p>South Africa: <span id="SouthRuns"/>/<span id="SouthWks"/>
                                                <span id="SouthOvers"/>   Overs</p>
                                </td>
                        </tr>
                        <tr>
                                <td>
                                        <p>Result: <span id="Result"/>
                                        </p>
                                </td>
                        </tr>
                </table>
        </FORM>
</BODY>
</html>

First create an object of XMLHttpRequest(taken care by initRequest() method in the above code). Then form the URL for which the request is to be sent. Create post process method which will be called once the response is received from UI(taken care by processResponse() method). In this jsp the Live Cricket Scores are updated automatically within a time frame of 5000ms. In the sense every 5000 ms an ajax request will be made to get the latest score. Have a look at startClock() method, which is called once during the page loading process and then using the setTimeout("startClock()", 5000) in the same method. The javascript update() method is called once during body onLoad event to make the initial scores to zero.

In the startClock() method url is formed by using query parameters for runs, wickets, overs for each team and sent to the server using req.open("GET", url, true), req.send(null) methods. These parameters are processed at the server side to return the latest scores (actually we are generating random scores in server side! ) using AjaxServlet.java.

Take a look at the AjaxServlet class below.

AjaxServlet Class

/**
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package in.techdive.java.ajax;

import java.io.*;
import java.util.*;

import javax.servlet.*;
import javax.servlet.http.*;

public class AjaxServlet extends HttpServlet
{
    private static Random rn = new Random();

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        String scoreId = request.getParameter("IndRuns");
        if (scoreId != null)
        {
            System.out.println("Entered in to ajax call....");
            String xmlScore = CalculateScore(request, response);
            System.out.println("xmlScore... " + xmlScore);
           
            response.setContentType("text/xml");
            response.setHeader("Cache-Control", "no-cache");
            response.getWriter().write(xmlScore);
            System.out.println("going to exit.. ajax call....");
            return;
        }
    }

    public void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
    {
    }

    public String CalculateScore(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException
    {
        String s1 = "<?xml version=\"1.0\" ?>";
        StringBuffer sbf = new StringBuffer(s1);
        String result = new String("MATCH IN PROGRESS");

        try
        {
            String IndRuns = request.getParameter("IndRuns");
            String IndWks = request.getParameter("IndWks");
            String IndOvers = request.getParameter("IndOvers");
            String SouthRuns = request.getParameter("SouthRuns");
            String SouthWks = request.getParameter("SouthWks");
            String SouthOvers = request.getParameter("SouthOvers");

            String[] strArr = result.split(",");
            System.out.println(strArr[0]);
            int tempI = Integer.parseInt(IndOvers);
            int tempIW = Integer.parseInt(IndWks);
            int tempS = Integer.parseInt(SouthOvers);
            int tempW = Integer.parseInt(SouthWks);
            int rIndWks = 0;
            int rSafWks = 0;
            int rSafRuns = 0;
           
            if (tempI < 50 && tempIW < 10)
            {
                IndRuns = Integer.toString(Integer.parseInt(IndRuns) + rand(1, 100));
                rIndWks = Integer.parseInt(IndWks) + rand(0, 4);
                IndWks = Integer.toString(rIndWks <= 10 ? rIndWks : 10);
                IndOvers = Integer.toString(Integer.parseInt(IndOvers) + 10);
            }
            else if (tempS < 50 && tempW < 10 && !(Integer.parseInt(IndRuns) < Integer.parseInt(SouthRuns)))
            {
                rSafRuns = Integer.parseInt(SouthRuns) + rand(1, 100);
                SouthRuns = Integer.toString(rSafRuns <= (Integer.parseInt(IndRuns)) ? rSafRuns : (Integer.parseInt(IndRuns) + 1));
                rSafWks = Integer.parseInt(SouthWks) + rand(0, 4);
                SouthWks = Integer.toString(rSafWks <= 10 ? rSafWks : 10);
                SouthOvers = Integer.toString(Integer.parseInt(SouthOvers) + 10);
            }
            if (Integer.parseInt(SouthOvers) == 50 || tempW == 10 || Integer.parseInt(IndRuns) < Integer.parseInt(SouthRuns))
            {
                if (Integer.parseInt(IndRuns) > Integer.parseInt(SouthRuns))
                {
                    result = "INDIA WON BY ";
                    result = result+ Integer.toString(Integer.parseInt(IndRuns) - Integer.parseInt(SouthRuns));
                    result = result + " RUNS";
                }
                else
                {
                    result = "SOUTH AFRICA WON BY ";
                    result = result + Integer.toString(10 - Integer.parseInt(SouthWks));
                    result = result + " WICKETS";
                }
            }

            sbf.append("<selectScore>");
            sbf.append("<selectTeam>");
            sbf.append("<Country>India");
            sbf.append("</Country>");

            sbf.append("<Runs>" + IndRuns);
            sbf.append("</Runs>");
            sbf.append("<Wickets>" + IndWks);
            sbf.append("</Wickets>");

            sbf.append("<Overs>" + IndOvers);
            sbf.append("</Overs>");
            sbf.append("</selectTeam>");

            sbf.append("<selectTeam>");
            sbf.append("<Country>South Africa");
            sbf.append("</Country>");

            sbf.append("<Runs>" + SouthRuns);
            sbf.append("</Runs>");
            sbf.append("<Wickets>" + SouthWks);
            sbf.append("</Wickets>");

            sbf.append("<Overs>" + SouthOvers);
            sbf.append("</Overs>");
            sbf.append("</selectTeam>");
            sbf.append("<Result>");
            sbf.append("<Res>" + result);
            sbf.append("</Res>");
            sbf.append("</Result>");
            sbf.append("</selectScore>");
        }
        catch (Exception e)
        {
            System.out.println(e);
        }
        return sbf.toString();
    }

    public static int rand(int lo, int hi)
    {
        int n = hi - lo + 1;
        int i = rn.nextInt() % n;
        if (i < 0)
            i = -i;
        return lo + i;
    }
}

Since we are sending a http GET request, doGet() method will be called in the servlet. To differentiate from AJAX and normal request, We are checking the request parameter 'IndRuns'. Then we are calculating the latest scores using some random number generation and then we are forming an xml consisting of current scores for both the teams. Now the response (i.e the xml) is sent back to the UI using response.getWriter().write(xmlScore) method.

XML

<selectScore>
        <selectTeam>
                <Country>India</Country>
                <Runs>325</Runs>
                <Wickets>6</Wickets>
                <Overs>50</Overs>
        </selectTeam>
        <selectTeam>
                <Country>South Africa</Country>
                <Runs>200</Runs>
                <Wickets>4</Wickets>
                <Overs>30</Overs>
        </selectTeam>
</selectScore>

Now get back to the jsp to find the processResponse() method. After receiving the response this method will be called in the jsp.

It initially checks for the (req.readyState==4) condition, (i.e) whether the reponse was successful or not. Then it tries to retrieve the xml from the response using xmlDoc = (new DOMParser()).parseFromString(xmlDoc, "text/xml") method. Then we iterate through each xml element and update the scores changing 'innerHtml' attribute of each element( for runs, wickets and overs) in jsp.

Have a look at the final scorecard as it will be displayed in UI.

Score CardCricket Score Card:

India: 272/10 50 Overs

South Africa: 245/10 50 Overs

Result: INDIA WON BY 27 RUNS

For Further Study
Spring DWR
Spring DWR Validation

Technology: 

Search