Books Store application:

Imagine a web page in which a user can search for information about Books. The page includes a field where the user can enter the name of the book. In the example application, the entry field has an auto-complete feature. In other words, the user can type in part of the book’s title, and the web application attempts to complete the title by listing all books whose name begins with the characters entered. The auto-complete feature saves the user from having to remember the complete title of the Book and can provide a more intuitive and direct path to the sought-after information.

Implementing auto-completion in a search field is something that can be performed using Ajax. Ajax works by employing an XMLHttpRequest object to pass requests and responses asynchronously between the client and server

The process goes as follows

1.  You first create the client-side files for the presentation and functionality needed to generate the XMLHttpRequest object.

2.  you set up the server-side by creating the data store and business logic using Java-based technology.

3.  you return to the client-side and implement callback(), and other JavaScript functionality to update the HTML DOM.

Programming the Client-Side

1.  Choose File > New Project. Under Categories, select javaWeb. Under Projects, select Web Application and click Next.

2.  In the Name and Location panel, enter MyAjaxApp for Project Name. The Project Location field enables you to specify the location of the project on your computer. Leave other options at their defaults and click Next.

3  In the Server and Settings panel, select the server you want to deploy your application to. Only servers that are registered with the IDE are listed.

4 Click Finish. The IDE creates the project folder in your file system and the project opens in

the IDE.

5 Now run the Index.jsp page which appears on the screen so as to make sure the

Project runs good with the server

Using the HTML Editor

6 Replace the content for the <title> tags to read: Auto-Completion using AJAX. Also, Between <h1> tags, type in the same text as you did <title> tags. The index page requires no server-side scripting code, so you can safely delete any remnants that were created by default.

8  Add some explanatory text to describe the purpose of the text field. You can copy and paste in the following text at a point just beneath the <h1> tags:

<p>This example shows how you can do real time auto-completion using Asynchronous

JavaScript and XML (Ajax) interactions.</p>

<p>In the form below enter a name. Possible names that will be completed are displayed

below the form. For example, try typing in "Javascripts basics, " "Java web development," or "Java EE Tutorial,"

then click on one of the selections to see book details.</p>

9  Add an HTML form to the page. You can do this by making use of the elements listed in the IDE's Palette. If the Palette is not open, choose Window > Palette from the main menu. Then, under HTML Forms, click on and drag a Form element into the page to a point beneath the <p> tags that you just added. The Insert Form dialog box opens. Specify the following:

Action: autocomplete

Method: GET

Name: autofillform

Click OK. The HTML <form> tags are inserted into the page containing the attributes you specified. (GET is applied by default, and so is not explicitly declared.)

10  Add an HTML table to the page. Under the HTML category in the Palette, click on a Table element and drag it to a point between the <form> tags. The Insert Table dialog box opens. Specify the following:

Rows: 2

Columns: 2

Border Size: 0

cell Padding: 5

11  Right-click inside the Source Editor and choose Format. This tidies up the code.

12  Within the first row of the table, type the following text into the first column (changes in bold):

<td><strong>Book Title:</strong></td>

13  Within the second column of the first row, instead of dragging a Text Input field from the Palette, type in the code below manually:

<th

<input type="text"

size="40"

id="complete-field"

onkeyup="doCompletion();">

</th

Using the JavaScript Editor

Note: When using the JavaScript Editor, the IDE provides you with browser-compatibility information, depending on the browser types and versions you specify in the JavaScript Options panel. Open the JavaScript Options panel by choosing Tools > Options (NetBeans > Preferences on Mac), then Miscellaneous > JavaScript.

Add a JavaScript file to the application and begin implementing doCompletion().

14  In the Projects window, right-click on the project node and choose New > JavaScript file. (If JavaScript file is not listed, choose Other. Then choose JavaScript file from the Web category in the New File wizard.)

15  Name the file javascript, and type in web in the Folder text field to place it in the web subfolder.

16  Click Finish and note that the new JavaScript file appears in the Projects window within the Web Pages folder.

Note: If you are wondering why the web folder is not displayed, click on the Files window (Window > Files). The Projects window provides a logical view of important project contents, whereas the Files window offers a representation of the entire project contents in a directory-based view.

17  Type the code below into javascript.js.

var req;

var isIE;

function init() {

completeField = document.getElementById("complete-field");

}

function doCompletion() {

var url = "autocomplete?action=complete&id=" + escape(completeField.value);

req = initRequest(url);

req.open("GET", url, true);

req.onreadystatechange = callback;

req.send(null);

}

function initRequest(url) {

if (window.XMLHttpRequest) {

return new XMLHttpRequest();

} else if (window.ActiveXObject) {

isIE = true;

return new ActiveXObject("Microsoft.XMLHTTP");

}

}

18  Switch back to index.jsp and add a reference to the JavaScript file between the <head> tags.

<script type="text/javascript" src="javascript.js"</script>

19  Insert a call to init() in the opening <body> tag.

<body onload="init()"

  1. This ensures that init() is called each time the page is loaded.

The role of doCompletion() is to:

·  create a URL that contains data that can be utilized by the server-side,

·  initialize an XMLHttpRequest object, and

·  prompt the XMLHttpRequest object to send an asynchronous request to the server.

The XMLHttpRequest object is at the heart of Ajax and has become the de facto standard for enabling XML data to be passed asynchronously over HTTP. Asynchronous interaction implies that the browser can continue to process events in the page after the request is sent. Data is passed in the background, and can be automatically loaded into the page without requiring a page refresh.

Notice that the XMLHttpRequest object is actually created by initRequest(), which is called by doCompletion(). The function checks whether XMLHttpRequest can be understood by the browser, and if so it creates an XMLHttpRequest object. Otherwise, it performs a check on ActiveXObject (the XMLHttpRequest equivalent for Internet Explorer), and creates an ActiveXObject if identified.

Three parameters are specified when you create an XMLHttpRequest object: a URL, the HTTP method (GET or POST), and whether or not the interaction is asynchronous. In the above example, the parameters are:

·  The URL autocomplete, and the text entered into the complete-field by the user:

var url = "autocomplete?action=complete&id=" + escape(completeField.value);

·  GET, signifying that HTTP interactions use the GET method, and

·  true, signifying that the interaction is asynchronous:

req.open("GET", url, true);

If the interaction is set as asynchronous, a callback function must be specified. The callback function for this interaction is set with the statement:

req.onreadystatechange = callback;

and a callback() function must later be defined. The HTTP interaction begins when XMLHttpRequest.send() is called. This action maps to the HTTP request that is sent to the web server in the above flow diagram.

Programming the Server-Side

Creating the Data Store

20  Right-click on the project node in the Projects window and choose New > Java Class.

21  Name the class BookData, and enter com.ajax in the Package field. This creates a new package to contain the class, as well as other classes that will later be created.

22  Click Finish. The class is created and opens in the Source

Add this code to the newly created class

package com.ajax;

import java.util.HashMap;

public class BookData {

private HashMap Books = new HashMap();

public HashMap getBooks() {

return Books;

}

public BookData() {

Books.put("1", new Book("1", "Javascripts basics"));

Books.put("2", new Book("2", "Java web development"));

Books.put("3", new Book("3", "Java EE Tutorial"));

}

}

Create the Book class:

  1. Right-click on the project node in the Projects window and choose New > Java Class.
  2. Name the class Book, and choose com.ajax from the drop-down list in the Package field. Click Next.
  3. Click Finish. The class is created and opens in the Source Editor.
  4. In the Source Editor, paste in the following code:

package com.ajax;

public class Book {

private String id;

// the First name is changed to BookTitle

private String bookTitle;

public Book (String id, String bookTitle)

{

this.id = id;

this.bookTitle = bookTitle;

}

public String getId() {

return id;

}

public String getBookTitle() {

return bookTitle;

}

}

Creating a Servlet

Create a servlet to handle the autocomplete URL that is received by the incoming request.

  1. Right-click on the project node in the Projects window and choose New > Servlet. (If Servlet is not displayed, choose Other, then select Servlet from the Web category.)
  2. Name the servlet AutoCompleteServlet, and choose com.ajax from the drop-down list in the Package field. Click Next.
  1. In the Configure Servlet Deployment panel, note that the servlet name is AutoCompleteServlet and the fully-qualified path to the class is com.ajax.AutoCompleteServlet. Change the URL pattern to /autocomplete so that it matches the URL that you previously set in the XMLHttpRequest object. This panel saves you the step of needing to manually add these details to the deployment descriptor.
  1. Click Finish. The servlet is created and opens in the Source Editor. The web.xml deployment descriptor is also updated to indicate that the servlet is registered with the application.

The only methods you need to override are doGet(), to define how the servlet handles the autocomplete GET request, and init(), which needs to initiate a ServletContext so the servlet can access other classes in the application once it is put into service.

You can override methods from superclasses using the IDE's Insert Code popup menu. Implement init() by doing this.

1.  Place your cursor beneath the AutoCompleteServlet class declaration in the Source Editor. Press Alt-Insert (Ctrl-I on Mac) to open the Insert Code popup menu.

  1. Choose Override Method. In the dialog that displays, all classes that AutoCompleteServlet inherits from are displayed. Expand the GenericServlet node and select init(Servlet Config arg0).
  1. Click Generate. The init() method is added in the Source Editor.
  2. Add a variable for a ServletContext object and modify init() (changes in bold):

private ServletContext context;

@Override

public void init(ServletConfig config) throws ServletException {

this.context = config.getServletContext();

}

  1. Add an import statement for ServletContext. You can do this by clicking on the lightbulb icon that displays in the left margin of the Source Editor

The doGet() method needs to parse the URL of the request, retrieve data from the data store, and prepare a response in XML format. Note that the method declaration was generated when you created the class. To view it, you may need to expand the HttpServlet methods by clicking on the expand icon () in the left margin.

Add the following variable declarations beneath the AutocompleteServlet class declaration.

private BookData bookData = new BookData();

private HashMap Books = bookData.getBooks();

This creates a HashMap of all Book data, which is then employed by doGet().

Scroll down to doGet() and implement the method as follows:

@Override

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws IOException, ServletException {

String action = request.getParameter("action");

String targetId = request.getParameter("id");

StringBuffer sb = new StringBuffer();

if (targetId != null) {

targetId = targetId.trim().toLowerCase();

}

boolean namesAdded = false;

if (action.equals("complete")) {

Iterator it = Books.keySet().iterator();

while (it.hasNext()) {

String id = (String) it.next();

Book book = (Book) Books.get(id);

// simple matching for start of first or last name, or both

if ((targetId != null) &

// if targetId matches first name

(book.getBookTitle().toLowerCase().startsWith(targetId)))

{

sb.append("<book>");

sb.append("<id>" + book.getId() + "</id>");

sb.append("<BookTitle>" + book.getBookTitle() + "</BookTitle>");

sb.append("</book>");

namesAdded = true;

}

}

if (namesAdded) {

response.setContentType("text/xml");

response.setHeader("Cache-Control", "no-cache");

response.getWriter().write("<Books>" + sb.toString() + "</Books>");

} else {

//nothing to show

response.setStatus(HttpServletResponse.SC_NO_CONTENT);

}

}

}

As you can see in this servlet, there is nothing really new you need to learn to write server-side code for Ajax processing. The response content type needs to be set to text/xml for cases where you want to exchange XML documents. With Ajax, you can also exchange plain text or even snippets of JavaScript which may be evaluated or executed by the callback function on the client. Note too that some browsers might cache the results, and so it may be necessary to set the Cache-Control HTTP header to no-cache.

In this example, the servlet generates an XML document that contains all booktitles with a titlesbeginning with the characters typed in by the user. This document maps to the XML Data depicted in the flow diagram above. Here is an example of an XML document that is returned to the XMLHttpRequest object:

Programming the Client-Side: Part 2

Adding Callback Functionality

  1. The callback function is called asynchronously at specific points during HTTP interaction when the readyState property of the XMLHttpRequest object changes. In the application you are building, the callback function is callback(). You recall that in doCompletion(), callback was set as the XMLHttpRequest.onreadystatechange property to a function. Now, implement the callback function as follows.
  1. Open javascript.js in the Source Editor and type in the code below.

function callback() {

if (req.readyState == 4) {

if (req.status == 200) {

parseMessages(req.responseXML);

} else if (req.status == 204){

clearTable();

}

}

}

  1. readyState of "4" signifies the completion of the HTTP interaction. The API for XMLHttpRequest.readState indicates that there are 5 possible values that can be set.

Updating the HTML DOM

  1. Open index.jsp in the Source Editor and type in the below code for the second row of the HTML table you previously created.

<tr>