Approaches to Web Development for Bioinformatics

Previous  Contents  Next
References

A Simple AJAX Example with Java

I will demonstrate AJAX with an example that gets gene information from a Servlet.  This example is lengthy but there are a number of AJAX libraries available to simplify this.  It demonstrates a the entire round trip of collecting user input from a HTML form, using JavaScript to post to a Servlet in the background and updating the HTML page as the data is streamed to it without requesting an entirely new page.  Here is the HTML page that the user starts with (code is here: index.html).


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <script type="text/javascript" src="ajax.js"></script>
    <script type="text/javascript" src="example.js"></script>
  </head>
  <body>
    <h3>Simple AJAX Example</h3>
    <form id="getDataForm" action="javascript:getData()" method="post">
      <input type="text" name="geneSymbolInput" id="geneSymbolInput" value="HD"/><br/>
      <input type="submit" name="submit" value="Get Data"/>
    </form>
    <!--  Place holder for search results -->
    <div id="results">
    </div>
  </body>
</html>

The page has an input field where the user is supposed to type in a gene symbol. When the user clicks on the button the JavaScript function getData() is called. This function in the file example.js:


// Collects the user's input criteria (gene symbol) and gets search results from the server
function getData() {
    var geneSymbol = document.getElementById("geneSymbolInput").value;
    fetchData("AJAXServlet", geneSymbol, updateSearchResults);
}

/*
 * Update the search results table after the data has completed loading from the XMLHttpRequest
 */
function updateSearchResults() {

    // parse data
    if (httpRequest.readyState == 4) {

        if (httpRequest.status == 200) {
            var id = extractTagValue(httpRequest.responseText, "id");
            var symbol = extractTagValue(httpRequest.responseText, "symbol");
            var name = extractTagValue(httpRequest.responseText, "name");

            var oldSearchResultsDiv = document.getElementById("results");
            var searchResultsParent = oldSearchResultsDiv.parentNode;
            var searchResultsDiv = document.createElement("div");
   
            // populate table
            var p = document.createElement("p");
            var textNode = document.createTextNode("Search Results:");
            p.appendChild(textNode);
            searchResultsDiv.appendChild(p);

            // table header
            var table = document.createElement("table");
            var tbody = document.createElement("tbody");
            table.appendChild(tbody);
            var tr = document.createElement("tr");
            tr.appendChild(createTableHeader("ID"));
            tr.appendChild(createTableHeader("Symbol"));
            tr.appendChild(createTableHeader("Name"));
            tbody.appendChild(tr);

            // table data
            var tr2 = document.createElement("tr");
            tr2.appendChild(createTableCell(id));
            tr2.appendChild(createTableCell(symbol));
            tr2.appendChild(createTableCell(name));
            tbody.appendChild(tr2);

            searchResultsDiv.appendChild(table);
            searchResultsParent.replaceChild(searchResultsDiv, oldSearchResultsDiv);
 
        } else {
            alert("Error retreiving data.");
        }
    }
}

/*
 * Extracts the tag value from the XML string
 * @param xml the xml string to parse
 * @param tag the tag to extract the value for
 * @return the value found in the string or null if not found
 */
function extractTagValue(xml, tag) {
    var start = xml.indexOf("<" + tag + ">") + tag.length + 2;  // starting position of the value
    if (start < 0) {
        return null;
    }
    var end = xml.indexOf("</" + tag + ">");  // ending position of the value (+1)
    return xml.substring(start, end);
}

function createTableHeader(headerText) {
    var th = document.createElement("th");
    var a = document.createElement("a");
    a.setAttribute("href", "#");
    textNode = document.createTextNode(headerText);
    a.appendChild(textNode);
    th.appendChild(a);
    return th;
}

function createTableCell(cellText) {
    var td = document.createElement("td");
    textNode = document.createTextNode(cellText);
    td.appendChild(textNode);
    return td;
}

This page calls a generic JavaScript AJAX function called fetchData() in file ajax.js.  The URL of the Servlet is passed in as a parameter.  This function calls the server with a POST request that includes the parameter the user entered in the form.  This is one of the keys to AJAX: either the IE ActiveX XMLHTTP object or the Firefox XMLHttpRequest object.  It also assigns an event handler (callback) to handle the data as it is streamed back from the server (hence the Asynchronous in AJAX).  The event handler is back in example.js (updateSearchResults()).  It dynamically manipulates the DOM to add the data to the page.  By the way, my implementation of this function is only smart enough to parse one record of from the XML document.

I have used XML to send data from server to browser but an easier way is JSON. XML has the advantage of better separating client and server code but JSON is probably a better choice overall.


// HTTP Request object
var httpRequest

/*
 * Fetch the given data from the server
 * @param dataSource the url of the data source
 * @param postData the parameters to post to the server
 * @param callback the callback to invoke when the data has loaded
 */
function fetchData(dataSource, postData, callback) {
    httpRequest = false;
    if (window.XMLHttpRequest) {
        httpRequest = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        try {
            httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
        } catch(e) {
            try{
                httpRequest = new ActiveXObject("Microsoft.XMLHTTP")
            } catch (e){
                alert("fetchData, e: " + e);
            }
        }
    } else {
        return false;
    }
    httpRequest.onreadystatechange = callback;
    httpRequest.open("POST", dataSource, true);
    httpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    if (postData == null) {
        httpRequest.send(null);
    } else {
        var params = "postData=" + postData;
        httpRequest.send(params);
    }

}

Finally, here is the Servlet that responds to the request. This need not be Java. The same thing can be any server side framework. Of course, in reality you would be getting the output results from a file or a database rather than generating from fixed strings as done here.  The source is in AJAXServlet.java.


package net.medicalComputing;

import java.io.*;

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

 public class AJAXServlet extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
    
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String symbol = request.getParameter("postData");
        PrintWriter writer = response.getWriter();
        writer.print("<geneInfo><id>3064</id><symbol>" + symbol + "</symbol><name>" +
                "huntingtin (Huntington disease)</name></geneInfo>");
    }                
}

The files to deploy the project on Tomcat are in AJAXServlet.zip.  This is what you will see if you are successful in deploying it.

AJAX Example Input Form

AJAX Example Input Form.  Notice the URL of the page (index.html)

And the result sent to the user after clicking the button looks like

AJAX Example Output

AJAX Example Output.  Notice that the URL of the page has not changed.

As you can see developing AJAX is heavy on the JavaScript and needs relatively less in the way of Server side generation of HTML with the like of Java Server Pages or PHP.  The code can be simplified some by using AJAX libraries from one of a number of open source projects, such as Direct Web Remoting (DWR)58.


Previous  Contents  Next
References

Contributed Comments and NotesAdd a comment.

There are no user comments.

Google

Please send ideas and opinions by email at alexamies@gmail.com.

© 2006-2007 Alex Amies