+ All Categories
Home > Documents > AJAX Tutorial for Java Programmers

AJAX Tutorial for Java Programmers

Date post: 27-Nov-2014
Category:
Upload: shubham-sai-soti
View: 52 times
Download: 3 times
Share this document with a friend
17
AJAX Tutorial for Java Programmers Getting Started Installing the Tutorial Server In this tutorial, we want to focus on the AJAX details rather than installation and setup issues. There are various different setup scenarios available for Jaxcent, and discussing them will take the focus away from the actual programing. Therefore, a small server is provided here, that is very easy to install, has Jaxcent pre-bundled, and gets the setup issues out of the way so you can concentrate on the concepts. This server is not very fast, but it is very convenient and easy to set up. It is meant for learning rather than production usage. The first step is to download the zip file below, and extract its contents. jaxtut.zip In this tutorial, we will assume you have created a folder C:\Jaxtut and have extracted the zip file to this folder, so you should have the following on your hard drive: C:\Jaxtut\jaxtut.jar C:\Jaxtut\JaxcentConfig.jar C:\Jaxtut\license.html C:\Jaxtut\html (directory) C:\Jaxtut\java (directory) C:\Jaxtut\api (directory) (If you are on a non-windows systems, or if you need to use a different path, please adjust the names accordingly.) Note that you will also get a "solutions" folder -- it is meant to be used after you have finished the exercises on your own! The given solution is just one way of doing the task, and may be interesting to compare with your own solution. Now double-click the jaxtut.jar file. (If nothing happens, you do not have an association for the ".jar" extension. In this case, bring up a command prompt window, change directory to C:\Jaxtut, and run the command java -jar jaxtut.jar instead.) You should see the tutorial server comes up. The first time, it will ask you to confirm its setup before starting. The defaults should be ok, make sure they are as follows: Port number should be 80. (If you are already running a server on port 80, you can shut it down while doing the tutorial, or you can change the port number to something else, e.g. 8080. If you are using port 80, the URLs are of the form http://localhost/, but if you are using a port number other than 80, e.g. 8080, the URLs will be of the form http://localhost:8080/) HTML Folder should be C:\jaxtut\html Java classpath should be C:\jaxtut\java Config file should be C:\jaxtut\JaxcentConfig.xml or as appropriate, if you are on a non-Windows system or have installed in a location different from C:\jaxtut. Click OK to accept the settings, and minimize the tutorial server. In the future, you will need to start the tutorial server by double-clicking the JAR file (or by issuing a java - jar command) before running any of the tutorial steps. After the first time, the tutorial server will not ask for any settings. It can be minimized and put out of the way. To see output from your System.out.println statements, or exception stack traces, un-minimize the tutorial server and look at its output window. To make sure the tutorial server is installed and running correctly, visit the following location in your browser: http://localhost/ You should see a message saying the tutorial server is working. You should see two links, both should work.
Transcript

AJAX Tutorial for Java Programmers

Getting Started

Installing the Tutorial Server

In this tutorial, we want to focus on the AJAX details rather than installation and setup issues. There are

various different setup scenarios available for Jaxcent, and discussing them will take the focus away from the

actual programing.

Therefore, a small server is provided here, that is very easy to install, has Jaxcent pre-bundled, and gets the

setup issues out of the way so you can concentrate on the concepts. This server is not very fast, but it is very

convenient and easy to set up. It is meant for learning rather than production usage.

The first step is to download the zip file below, and extract its contents.

jaxtut.zip

In this tutorial, we will assume you have created a folder C:\Jaxtut and have extracted the zip file to this folder,

so you should have the following on your hard drive:

C:\Jaxtut\jaxtut.jar

C:\Jaxtut\JaxcentConfig.jar

C:\Jaxtut\license.html

C:\Jaxtut\html (directory)

C:\Jaxtut\java (directory)

C:\Jaxtut\api (directory) (If you are on a non-windows systems, or if you need to use a different path, please adjust the names

accordingly.)

Note that you will also get a "solutions" folder -- it is meant to be used after you have finished the exercises on

your own! The given solution is just one way of doing the task, and may be interesting to compare with your

own solution.

Now double-click the jaxtut.jar file. (If nothing happens, you do not have an association for

the ".jar" extension. In this case, bring up a command prompt window, change directory to C:\Jaxtut, and run

the command java -jar jaxtut.jar instead.)

You should see the tutorial server comes up. The first time, it will ask you to confirm its setup before starting.

The defaults should be ok, make sure they are as follows:

Port number should be 80. (If you are already running a server on port 80, you can shut it down while

doing the tutorial, or you can change the port number to something else, e.g. 8080. If you are using

port 80, the URLs are of the form http://localhost/, but if you are using a port number other than 80,

e.g. 8080, the URLs will be of the form http://localhost:8080/)

HTML Folder should be C:\jaxtut\html

Java classpath should be C:\jaxtut\java

Config file should be C:\jaxtut\JaxcentConfig.xml

or as appropriate, if you are on a non-Windows system or have installed in a location different from C:\jaxtut.

Click OK to accept the settings, and minimize the tutorial server.

In the future, you will need to start the tutorial server by double-clicking the JAR file (or by issuing a java -

jar command) before running any of the tutorial steps. After the first time, the tutorial server will not ask for

any settings. It can be minimized and put out of the way.

To see output from your System.out.println statements, or exception stack traces, un-minimize the tutorial

server and look at its output window.

To make sure the tutorial server is installed and running correctly, visit the following location in your browser:

http://localhost/

You should see a message saying the tutorial server is working.

You should see two links, both should work.

Hello, World The tutorial server is already set up with two files:

A HelloWorld.html file

A HelloWorld.java file

In addition, the default JaxcentConfig.xml file already map these two -- in other words, it tells Jaxcent to

connect the HelloWorld.html file with the HelloWorld.java code.

The first task is, therefore, very simple: Modify the HelloWorld.java so that it puts the words "Hello, World!"

in the browser instead of the text already there. It has to be done dynamically, instead of modifying the

HelloWorld.html file. The HelloWorld.html file has to stay unchanged, but the browser text should change!

To accomplish this, first examine the HelloWorld.html file in a text viewer such as notepad. You will notice

the P tag has an "id" attribute. The P tag is also closed with a matching /P tag.

Both of these are important. Your Java code needs a way to identify the text to change. There are various ways

to do this, but the best approach is to put an "id" attribute with a unique tag.

Secondly, if you don't close the P tag with a matching /P, in some browser versions the paragraph will not be

closed, and the subsequent HTML will be treated as a child of that paragraph! In AJAX programming, this can

lead to occasional surprises. So if you write a paragraph with the intention of changing it dynamically, it is a

good idea to have the habit of closing the tag.

Now let us examine the HelloWorld.java file. You will see it contains just a framework, but doesn't actually

do anything.

First change we need to make is to declare a variable that references our paragraph, as follows: HtmlPara para = new HtmlPara( this, "text" );

The second argument here identifies the text used for the "id" attribute of the para, so the framework can match

it up with actual HTML on the page.

Now add a constructor (public, no args) in the Java code, and in the constructor, put in the code para.setInnerHTML( "Hello, World!" );

That's it! (Well, almost. In these tutorial pages, you are expected to find the final issues yourselves by actually

doing it.)

Compile the HelloWorld.java code (the resulting .class file must go in

C:\Jaxtut\java\tutorial\HelloWorld.class. If you specify the "-d C:\Jaxtut\java" option to javac, it will place

it there.)

After a successful compilation, revisit or refresh the HelloWorld page in your browser (you do not need to

restart the tutorial server, but it must be running.) If everything is done correctly, you should see your output!

Exercise: Get this to work, then add a para following the first para, and dynamically change its text to say

"Goodbye, World!".

A Dancing Hello, World Changing HTML dynamically is a very useful ability, but we could have done this just by editing the HTML

file, so you may wonder what is the advantage.

We can do much more than just change HTML elements. In this case, we are going to change the style of the

HTML on the fly. But we are going to do this continuously, in a Java Thread.

Here is the thread definition, which can be added to the Java file. private class HelloThread extends Thread {

public void run()

{

// Thread processing.

}

}

HelloThread helloThread = new HelloThread();

and in the constructor, we just need to add helloThread.start();

to start the thread.

In the thread, we are going to change the "style" of the HtmlPara element. But instead of doing it once, we are

going to change it continuously.

The style is "font-size", and its values are given in various units, e.g. "px" for "pixel". Here is a Java statement

to set the font-size to 10 pixels. para.setStyle( "font-size", "10px" );

Given all this, the assignment in this tutorial is to add code in the thread that runs continuously. The tasks are:

Add a

for (;;) {

}

or "while (true)" loop to the code.

Add

Thread.sleep( 10 );

at the beginning or end of each iteration.

Maintain a direction variable, which can be "increasing" or "decreasing". (You can use a boolean

"increasing", set to true for increasing, false for decreasing.)

In each Iteration, If the direction is increasing:

o Increment the font size by 1 pixel.

o If the font size has reached 100, reverse the direction.

else if the direction is decreasing:

o Decrement the font size by 1 pixel.

o If the font size has reached 8, reverse the direction.

Set the para to the new font-size (add "px" after the size.)

Start the direction as increasing at start, and the size at 10.

We are still using the HelloWorld page so you can just modify and compile the existing HelloWorld.java file.

Exercise: Get the font-size changes to work. Then at each direction change, change the "color" style to one of

"red", "black", "green" and "blue", cycling through the colors at each change.

Listening to Hello, World Events What about input and interactive programming in AJAX?

You may be familiar with HTML forms and processing input at the server upon the click of a button. Using

AJAX, you can do much more than that. You don't have to depend upon form submissions. You can listen to a

whole selection of events. This includes events on the familiar FORM elements, but is not restricted to them.

In this exercise, we will be listening to mouse clicks that occur on our good old "Hello, World" text itself.

To do this, we just need to override a method named "onClick" that's provided for HtmlPara objects. This can

be done right at the declaration of "para". HtmlPara para = new HtmlPara( this, "text" ) {

protected void onClick() {

System.out.println( "Click!" );

}

};

That's it, make this change, and give it a try (Note: When you change and recompile a Java class, just

refreshing the page in the browser will load your new version.)

If everything is fine, then everytime you click on the para, you should see an output in the Tutorial Server's

output window. (Of course, if you have done the previous exercise, you would have to make sure to catch the

Hello, World text first!)

All event handling in Jaxcent is like this, by overriding methods. Mouse and button clicks are important for

various user interactions. Also important are page load and unload events. We have been doing output in the

constructor, but in the constructor, we cannot receive the value or attributes of a tag. For that, we must wait

until the page has been loaded in the browser and connected to Jaxcent. Such things can be done in the page

load handler.

Page unload handler is important for cleanups.

You may have noticed that the output window in your Jaxcent Tutorial Server shows exception stack traces

like this one whenever you close your browser window or point it to some other location:

Exception in thread "Thread-1040" jaxcent.PageUnloadedError: Page has already unloaded

at jaxcent.JaxcentPage.sendPageQuery(JaxcentPage.java:1753)

at jaxcent.JaxcentHtmlElement.setStyle(JaxcentHtmlElement.java:198)

at tutorial.HelloWorld$HelloThread.run(HelloWorld.java:32)

It is now time to get rid of these stack traces!

What is happening is that you have a thread that starts in the page constructor. When the user closes the

browser window, or navigates away from the HelloWorld url, the page unloads. After the page has unloaded,

Jaxcent throws a PageUnloadedError This has the effect of terminating your thread. This works, but is

obviously not very graceful!

For a controlled graceful termination of the thread, we can take advantage of the page unload handler. This

handler is provided by the jaxcent.JaxcentPage class, so we can override it in our HelloWorld class. protected void onUnload()

{

}

We need to have some boolean variable which is initially set to true. The page unload handler sets it to false.

The thread checks this variable, and when it is set to false, stops its main loop.

In addition, we can interrupt the thread by calling Thread.interrupt after setting the boolean variable. This

will wakeup the thread from a sleep state.

This makes for a nice tidy shutdown of our thread. In some cases there may be windows where the Error may

still be raised, but we don't need to worry too much about such situations because in the worst case, the thread

will still be terminated by the error being thrown!

Exercise: Add the click handler and the page unload handler and verify these are working. Then add a handle

for page loading. In this handler, get the inner HTML for the para and print out the inner HTML. (If you try

doing this in the constructor, you will get an exception.)

Adding a New Page We have been able to do a lot just with a "Hello, World" program. Now it's time to add in another page.

Adding a page in Jaxcent has three components:

The HTML page itself.

The Java source code.

The XML mapping.

The HTML Page

The HTML page is like any normal HTML page, except that the HEAD section must contain the following: <SCRIPT TYPE="text/javascript" SRC="/jaxcent21.js"></SCRIPT>

This is very important. If you are doing Jaxcent programming, and you visit a new page and nothing happens,

check if you are missing the JavaScript include! Other errors may cause some sort of alarm, but this error will

silently fail. But if this include statement is missing, the page will not be connected to Jaxcent, and nothing

will happen.

The Java Source Code Typically, there will be a Java class connected to every HTML page, for doing all AJAX handling. (Though

there does not have to be a class and sometimes you can just use the base class jaxcent.JaxcentPage.)

This Java class must derive from the jaxcent.JaxcentPage class. In most cases, there will be one or more

variables declared that refer to tags on the HTML page. These variables are of type Html<Tag> where <Tag>

refers to the HTML tag those variables match on the page.

E.g. HtmlPara, HtmlInputText, HtmlInputButton, HtmlForm etc.

When you initialize these variables, the constructor tells Jaxcent how to find the matching HTML element on

the HTML page.

We have already seen initializations of the form HtmlPara p = new HtmlPara( this, "text" );

where "text" matches the "id" attribute of the HTML tag on the HTML page.

There are other search methods available, e.g. HtmlPara p = new HtmlPara( this, SearchType.SearchByTag, "P", 2 );

This refers to the 3rd element on the page with a "P" tag. The searching index is 0-based, so the "2" actually is

the third by count. You can omit the last argument, in which case it defaults to 0, i.e. the first such tag. For

INPUT elements, there are more search types, e.g. HtmlInputText text = new HtmlInputText( this, SearchType.SearchByName, "FirstName" );

or HtmlInputText text = new HtmlInputText( this, SearchType.SearchInputByType, "TEXT", 1 );

which will find the second INPUT TEXT on the page. You can even search by input value, HtmlInputText text = new HtmlInputText( this, SearchType.SearchInputByValue, "ok" );

which may be useful in searching for checkboxes or radio buttons.

Each variable initialization can also be followed by event over-rides.

Finally, in the Java code, there can be a constructor and over-rides of form load, unload methods.

Processing can start in the constructor or in one of the over-ridden methods.

The XML Mapping

The HTML page must be connected to the Java class.

This is done by adding a Page node in the Jaxcent XML configuration file. There are two sub-nodes,

a PagePath that specifies the URL path (starting with a "/" and usually ending in ".html") of the HTML file,

and a PageClass that specifies the fully qualified name of the class. In addition to PagePath and PageClass, an AutoSessionData node with the value true can be added. This tells Jaxcent to provide automatic forms data

management.

The Jaxcent XML configuration file in C:\Jaxtut already contains a sample mapping. Other mappings follow

the similar format.

If there is no Java source required (this can be the case if AutoSessionData is set, and you are using Jaxcent on

that HTML page just for managing forms data), the PageClass node must still be present, but it just contains

jaxcent.JaxcentPage which is the base class.

Exercise:

i. Write a new HTML page MyPage.html.

o Add the JavaScript INCLUDE to the HEAD section.

o Add a SELECT tag with with id "mySelect" and nothing inside the tag (we will be fillng the

SELECT from Java.) o <SELECT id="mySelect">

o </SELECT>

o Add a BUTTON tag with id "myButton". o <BUTTON id="myButton">My Button</BUTTON>

o Add a P tag, then add a TABLE tag with border set to 2 and id "myTable", but nothing inside

the tag (we will also be filling the table from Java.) o <TABLE id="myTable" border=2>

o </TABLE>

ii. Write a Java class MyPage.java. The package name is "tutorial". Declare and initialize a

variable myTable of type HtmlTable that connects to the table, a variable mySelect of

type HtmlSelect that connects to the SELECT, and a variable myButton of type HtmlButton that

connects to the button. Add a click handler to myButton that calls iii. showMessageDialog( "Button Clicked" );

iv. Modify the Jaxcent configuration file, adding a new Page node that connects the HTML

page /MyPage.html to the tutorial.MyPage Java class.

v. Compile the Java class and make sure the class file is in C:\Jaxtut\java\tutorial\MyPage.class.

vi. Make sure the Tutorial Server is running and visit your page http://localhost/MyPage.html in the

browser. If there are any error messages, fix them. If everything is working, you should see the

message from your button when you click it. You won't see your TABLE and the SELECT will look

strange because they are both empty -- that's ok.

Working with Tables and Lists We are now ready to populate and work with our TABLE and SELECT list. Often, the material to populate tables and lists will be coming from a database. But for the purposes of this

tutorial, we will just be keeping it in Java static variables! We have three categories of books to populate, as

given below (book names are for example only, and are not meant to represent any actual books/curriculi!): static String[] scienceBooks = {

"Light", "Magnetism", "Electricity", "Heat", "Sound", "Motion", "Plants"

};

static String[] mathBooks = {

"Arithmetic", "Geometry", "Algebra", "Dynamics"

};

static String[] geographyBooks = {

"North America", "South America", "Asia", "Europe", "Africa", "Australia"

};

In the constructor, we are going to fill the SELECT list with these three categories. We will also attach a

handler on the SELECT, so that when someone selects one of the categories, we will fill the table with books

of that category. Initialize the SELECT

The code in the constructor will be as follows: mySelect.insertOption( 0, "Science Books" );

mySelect.insertOption( 1, "Math Books" );

mySelect.insertOption( 2, "Geography Books" );

mySelect.sizeToOptions();

mySelect.setSelectedIndex( -1 );

The "sizeToOptions" will resize the SELECT to have as many displayed rows as options, so that it will show up as a list instead of the normal combo-box (making it slightly more convenient to pick a category.) And finally, the setting of selected index to -1 makes nothing selected in the list, initiallly. Otherwise, the first index would have shown up selected. Try this out to see the new SELECT. Adding action on SELECT change

Now add an "onChange" handler to mySelect. But instead of the "onClick" handlers we have added so far, add

an int parameter to the handler: protected void onChange( int selectedIndex )

{

showMessageDialog( "Selected Index = " + selectedIndex );

}

Once this is working, the next step is to populate our table in the "onChange" handler, instead of just showing a message dialog. Populating the Table

In populating the table, first we remove any existing element. Then we just have to keep adding rows matching the selection. The new version of "onChange" is: myTable.deleteAllRows();

String[] books;

String header;

switch ( selectedIndex ) {

case 0:

books = scienceBooks;

header = "Science Books";

break;

case 1:

header = "Math Books";

books = mathBooks;

break;

default:

header = "Geography Books";

books = geographyBooks;

}

// Add a header, using B tags

myTable.insertRow( -1, new String[]{ "<B>" + header + "</B>" } );

// Fill up the table with the books.

for ( int i = 0; i < books.length; i++ ) {

myTable.insertRow( -1, new String[]{ books[i] } );

}

The -1 in the insertRow is to insert rows at the end of the table. We just have one cell in each row, so we are supplying an array of String's, containing just one element. Exercise: Get all this to work at http://localhost/MyPage.html in the browser. Clicking any choice in the

SELECT list should populate the table with that type of items.

Receiving Input from the Page The idea now is to add a checkbox to the table rows, and to change the text on the button to say "Order"

instead of "MyButton". This is shaping up to be a very rudimentary shopping cart.

But checkboxes can only be inside FORM tags. The new BUTTON tag allows buttons outside forms, but all other

input elements are still required to be inside FORMs, because they are designed for the page submit protocol.

With AJAX, the page submit protocol is not really required, but still we have to put the checkboxes inside

forms.

So the first task is to put the TABLE inside a FORM tag (open and close.) The FORM tag does not need any

attributes, e.g. ACTION, METHOD etc.

Now we can change the contents of the table so that in addition to the name of the book, there is also a

checkbox next to it. The user can select books, click the button, and we will display the results in a shopping

cart table.

The onChange handler needs to be modified, to supply String arrays of 2 elements to the insertRow method. // Add a header, using B tags

myTable.insertRow( -1,

new String[]{ "<B>" + header + "</B>",

"<B>Order</B>" } );

// Fill up the table with the books.

for ( int i = 0; i < books.length; i++ ) {

myTable.insertRow( -1,

new String[]{ books[i],

"<INPUT TYPE=CHECKBOX NAME=checkbox_" + i + ">" } );

}

Notice that we are supplying a unique NAME to each checkbox. Supplying a unique name or id lets us identify

the checkbox, either to attach an object (of class HtmlInputCheckbox in the case of checkboxes) to it, or to

identify whether it has been checked or not.

In this sample, we will simply be checking which checkboxes have been checked, and putting the

corresponding books in the shopping cart. Change the button text to "Order" and add another empty TABLE

with ID "shoppingCart" to the page. Also add and initialize a variable "shoppingCart" of class "HtmlTable"

connected to the new TABLE.

The button should already have a click handler, now change the click handler so it has a single parameter

of java.util.Map class.

In the handler,check for all names that start with "checkbox_" and add the corresponding books in the

"shoppingCart" tables. protected void onClick( java.util.Map pageData )

{

try {

int selectedIndex = getSelectedIndex( pageData.get( "mySelect" ));

String[] books;

switch ( selectedIndex ) {

case 0: books = scienceBooks; break;

case 1: books = mathBooks; break;

default: books = geographyBooks;

}

java.util.Iterator names = pageData.keySet().iterator();

while ( names.hasNext()) {

String name = (String) names.next();

String value = (String) pageData.get( name );

if ( name.startsWith( "checkbox_" ) && ! value.equals( "" )) {

// Checkbox, selected

int index = Integer.parseInt( name.substring( "checkbox_".length()));

String book = books[ index ];

shoppingCart.insertRow( -1, new String[]{ book } );

}

}

} catch (Jaxception jax) {

jax.printStackTrace();

}

}

Exercise: Get all this to work at http://localhost/MyPage.html in the browser. Clicking the "Order" button

should fill the shopping cart table with any checked books. Also add a variable that is initialized to false, and

that keeps track of whether anything has been added to the shopping cart yet. Use it to add a header to the

shopping cart, the first time something is added to the shopping cart.

The Session Web Programming uses the concept of a "session" to keep track of user data.

When a user visits your website, he/she may visit more than one page. Usually for user interface reasons, it is a

good idea to separate data entry into several pages. But we would like to be able to connect all these pieces of

data with the same user. While he/she is visiting some pages, other users may be visiting other pages using the

save web server. So the problem is, how to keep track of the data for each user.

The "session" concept is useful for this. A "session" is an object that is associated with a visitor. Each visitor

gets his/her own session object. We can store all data related to the visitor in that session object. But that we

don't know if the visitor is going to visit more pages, or has gone away to another site or has closed the

browser. So sessions have a "timeout". If the user has not visited any pages within, say, 10 minutes, we assume

the user has gone away and delete the session object.

Sessions are provided by web-server back ends, such as Java Application Servers.

Jaxcent uses the session object to provide a java.util.Map that is stored in the session.

Jaxcent can automatically save and restore data from forms in this Map. This data is saved by using the id or

name as keys. The data stored consists of INPUT, SELECT and TEXTAREA items. You can also save your

own items in this Map, as long as your keys do not collide with the form names/id.

To enable this automatic saving/restoring, the <Page> node in the config XML file needs to have one more

entry: <AutoSessionData>true</AutoSessionData>

This tells Jaxcent to load form items with session data when the page is loaded, and to save any changes in the

session when the page is unloaded.

To try this out, we will create some HTML pages with input elements on them:

1. An HTML page Name.html with a FORM with INPUT TEXT fields for user first name and user last

name (use values firstName and lastName for the NAME attribute.)

2. An HTML page Address.html with a FORM with INPUT TEXT fields for user street address

("address"), city ("city") and a SELECT for state ("state") containing a few state names.

3. An HTML page Message.html with a FORM containing a TEXTAREA with NAME "message" for

entering a message.

4. A summary page Summary.html with an empty TABLE with ID "summary".

5. An index page Contents.html that has A HREF links to all these pages.

6. Also put in links from Name.html to Address.html, from Address.html to Message.html, and from

Message.html to Summary.html, and from all of them to the Contents.html.

7. Add the JavaScript include statement in the header of all the html files except Contents.html.

Also write an empty Java framework for the Summary.html, using the package "tutorial" and class

"Summary". Add a constructor and write some output to System.out, to verify that the page is connected.

Now add entries for all of these except Contents.html, in the config XML file. Note that we only have one Java

class. Use jaxcent.JaxcentPage directly for all other HTML pages. In all the new Page node entries in the

XML file, also add

<AutoSessionData>true</AutoSessionData>

Now visit all of these, entering data in the forms. Any data you enter in the forms, should be staying in those

forms when you visit the form again. Even if you refresh the page or visit the URL without going back, the

data will stay on the page. However, if you leave the browser for more than 10 minutes and then come back,

any pages you revisit will have lost their data, because the session would have been lost. (Except that if you

have left your browser on one of these pages during those 10 minutes, that page's existing data would get

loaded again.)

If you start another browser (not "New Window" from the same browser, but a new instance or a new type of

browser, e.g. IE and Mozilla), you will not see your changes. You could enter a fresh set of data using that

browser, and it will be kept track of. (Here are you acting as a second user.)

This is happening because of the AutoSession setting.

Exercise: Get all this to work and verify that it is working by visiting http://localhost/Contents.html in the

browser. Verify that all the data sticks.

Retrieving Session Data It takes no additional work beyond specifying AutoSessionData to true, to get all the user's input into session.

Of course, in a real-life situation, we may want to add more code to each page to verify data etc. But the

saving/restoring into forms itself is free.

To get the data from the session, the method getAllSessionData provided in JaxcentPage class is used. It takes

a single parameter, which we will specify as false. If the parameter is true, it tells Jaxcent that we also want to

get the most recent information from the current page. But our summary page has no form input, so we don't

need that.

The method returns a map, so all we have to do is retrieve values from the map.

Note that there is a distinction between the values stored in the map: if the user has never visited a page, the

values for that page are not in the map. So retrieving any data from that page will return a null. But if the user

has visited a page and has just not entered data in a field, retrieving data from that field will return an empty

string instead of a null.

We can now build a small utiltiy to write out a row to our output table. void writeValue( HtmlTable table, // Table to output to

String description, // Description of key (to output)

Object value // Value of the key

) throws Jaxception

{

if ( value == null ) // Page containing the item was never visited.

value = "<I>Not Visited</I>";

table.insertRow( -1, new String[]{ description, (String) value } );

}

Using this utility, we can modify the constructor of Summary.java to write out all items. public Summary()

{

try {

HtmlTable table = new HtmlTable( this, "summary" );

java.util.Map data = getAllSessionData( false );

// Add a header.

table.insertRow( -1, new String[]{ "<B>Item</B>", "<B>Value</B>" } );

// Add items.

writeValue( table, "First Name", data.get( "firstName" ));

writeValue( table, "Last Name", data.get( "lastName" ));

writeValue( table, "Address", data.get( "address" ));

writeValue( table, "City", data.get( "city" ));

writeValue( table, "State", JaxcentObject.getSelectedValue( data.get( "state"

)));

writeValue( table, "User Message", data.get( "message" ));

} catch (Exception ex) {

ex.printStackTrace();

}

}

Exercise: Get all this to work. Starting from http://localhost/Contents.html in the browser, verify that the

summary page shows all data entered, and that every time you visit it, it changes to reflect any changes you

made on the pages.

Navigation in Web Applications You may have noticed that in the previous application, all navigation between pages was done using normal A HREF links. Using Ajax, this is quite sufficient to save and load data. In fact, the data will be saved even if the user

navigates away somewhere else using the browser buttons or the browser address bar, or even just closes the

browser. But this behavior is different from the traditional behaviors of forms with buttons called Reset and

Submit. As such, this behavior may be unsettling to users who expect that nothing is saved anywhere until they

click a nice solid-looking button.

The Reset button is useful in any case, as users may want to undo the changes they have made on the page. Adding a RESET Button

The old-style RESET feature available with FORM tags, is likely to only conflict with Ajax. Therefore a RESET button needs to be added and handled in Java. To implement a RESET feature, do not use the INPUT TYPE=RESET, simply create a BUTTON (can be

outside FORM) or INPUT TYPE=BUTTON (has to be inside FORM) element, label it "Reset", and add a

variable and handler for it on the Java side. HtmlButton /* or HtmlInputButton */

resetButton = new HtmlButton( this, "reset" ) {

protected void onClick() {

resetFromSession();

}

};

That's enough, this will reset the items on the page from session, getting rid of any changes the user has made. Navigating using a button

To navigate using a button instead of using A HREF links, there are several approaches: Make the button a SUBMIT button, and specify the new URL as the ACTION of the FORM. (This will

cause form data to show up in the browser address bar, unless the METHOD is POST.) Of course, the new URL will just ignore the form data if it is the URL is an HTML file, so there will be no harm from the data.

Add JavaScript code on the button to do the navigation. Add a handler on the Java side, and do the navigation in this handler.

SUBMIT button behavior

The contract of the old-style SUBMIT button is -- any changes the user makes are not sent to the website until the user clicks the SUBMIT button. If instead of clicking SUBMIT, the user navigates away from the form, the data will never been seen. This behavior can also be enabled in Jaxcent. To duplicate this behavior:

1. Add a button with the desired label, but it must not be an INPUT TYPE=SUBMIT button. It can be a BUTTON or INPUT TYPE=BUTTON element.

2. In the page constructor, call 3. setFormSaveEnabled( false );

4. In the button click handler, call 5. setFormSaveEnabled( true );

6. navigate( "/NewUrl.html" );

This will stop Jaxcent from saving the form data in the session, until the user clicks the button.

Before calling the setFormSaveEnabled and the navigation, the button handler can also check if any required

form data is missing/wrong etc.

Exercise: Add Reset and Submit (for old-style submit) buttons to the http://localhost/Name.html page. This

will require changing the XML map for Name.html, and adding a Java class.

Data Verification Often, it is desirable to verify the data on a page on a "Submit" button, before allowing the user to move to the

next page.

This is very straightforward if there is a Java button click handler for the "Submit" button. The click handlers

can be defined to have a single argument of type "java.util.Map" and they will receive all the page data along

with the click notification. The page data can then be checked. E.g. protected void onClick( java.util.Map pageData )

{

String firstName = (String) pageData.get( "firstName" );

if ( firstName.equals( "" )) {

showMessageDialog( "Please enter first name" );

return;

}

// ... Other checks

// .. If everythihng ok, navigate

}

If there is no Java server-side button handler, the verification needs to be handled using JavaScript

mechanisms.

There is a third situation -- where there is indeed a click handler on the button, but the verification can be done

on the client-side in JavaScript, and does not need any server information.

In such cases, a client-server round trip can be saved by only invoking the server-side handler if the client-side

verification succeeded. This is desirable, because it increases responsiveness, and decreases server load. The

trade-off is that it requires some JavaScript coding.

In Jaxcent, button click handlers (as well as any other event handlers) can have a JavaScript "verifier" attached

to them. If the verifier fails, the button handler is never called by the client side.

The verifier can be a chunk of JavaScript code, though it will usually be more convenient to write a JavaScript

function on the client, and just give Jaxcent the name of the verifier function.

An example of adding such a verifier is: myButton.addJavaScriptVerification(

"click", // Name of event

"verify()", // Javascript code

null // Optional args. If specifying args, do

// do not include "()" in the code.

);

Now when "myButton" is clicked, the client-side JavaScript function "verify()" will be called first, all without

involving the server. If this function returns false, no further processing will occur, and there will be no client-

server communication. If this function returns true, only then server-side Java will be called.

An example of a verify function is: <SCRIPT LANGUAGE="JavaScript">

<!--

function verify()

{

var form = document.getElementsByTagName( "FORM" )[0];

if ( form.firstName.value == "" ) {

alert( '"First Name" is required.' );

return false;

}

if ( form.lastName.value == "" ) {

alert( '"Last Name" is required.' );

return false;

}

return true; // Proceed to server-side click handler.

}

-->

</SCRIPT>

Exercise:

1. Add first name field verification from the server-side to http://localhost/Name.html page.

2. Add last name field verification from the client-side to http://localhost/Name.html page,

using addJavaScriptVerifiation.

Working with JavaScript We have already seen how to add JavaScript verifiers to click handlers in order to reduce client-server round trips and server load. Jaxcent also allows other mechanisms for working with JavaScript.

The method execJavaScriptCode in JaxcentPage class executes JavaScript code. It can either be given just

some chunk of code, or a function name that takes 1 or more arguments. For example: execJavaScriptCode( "alert( \"Hello\" );", false, null );

or execJavaScriptCode( "alert", false, new Object[]{ "Hello" } );

The arguments are specified as an Object-array, and besides the primitive type-wrappers (Integer, Boolean etc) and String, can also include Jaxcent HTML element objects e.g. HtmlInputText, HtmlPara etc. The second parameter is false in these examples. If it is specified as true, the arguments are passed as a single

parameter to the JavaScript function. The single parameter is a JavaScript array containing the actual list of

arguments.

In addition to execJavaScriptCode, there is an evalJavaScriptCode method, which is similar but waits for the

result from the JavaScript evaluation, and returns the result. Client-driven Jaxcent Framework

In Jaxcent, normally the program logic is driven from the server side. But parts of, or the entire framework, can be client-side driven as well. Jaxcent provides the JavaScript function JaxcentServerRequest to the client side. This function can be called

with 0 or more parameters by JavaScript code on the client side.

Jaxcent provides the corresponding Java method onJavaScriptRequest in the JaxcentPage class. This method

can be over-ridden to process messages coming from JaxcentServerRequest. It will be called with two null

parameters, or a command and optionally an array of arguments.

Exercise: Create an HTML file Jstest.html, with the Jaxcent JavaScript include statement in it. Also add the

following JavaScript code in the HEAD section.

<SCRIPT LANGUAGE="JavaScript">

<!--

function identify( element )

{

oldColor = element.style.backgroundColor;

elementToReset = element;

element.style.backgroundColor = "red";

setTimeout( "resetIdentified()", 1000 );

}

function factorial( n )

{

if ( n < 2 ) {

return 1;

}

return n * factorial( n-1 );

}

var oldColor;

var elementToReset;

function resetIdentified()

{

elementToReset.style.backgroundColor = oldColor;

}

var iter = 1;

function callServer()

{

JaxcentServerRequest( "Test", "Calling", "Server", iter++ );

setTimeout( "callServer()", 10000 );

}

setTimeout( "callServer()", 10000 );

-->

</SCRIPT>

Add a FORM, add an INPUT TEXT field to the form, and two BUTTONs with an id each. The text for the first button is "Identify Text Field", the text for the second button is "Compute Factorial 5".

1. The JavaScript function "identify" can be called with an HTML element as argument. It will identify the element on the page by briefly turning it red. Add a Java handler to the first button. In the handler, call the JavaScript "identify" function to identify the INPUT TEXT field.

2. Add a handler to the second button. In the handler, call the JavaScript function "factorial" with the argument "5" and print out the result in the output window.

3. The JavaScript code given above, calls "JaxcentServerRequest" every 10 seconds. Retrieve the command and its arguments from the Java side, and print them out to System.out.

Hiding and Showing Page Elements A powerful UI technique is to hide and show elements to the user as needed.

Any individual elements can be hidden or shown by calling the "hide()" or "show()" methods.

But instead of hiding and showing various blocks of elements individually, in many cases it is much simpler to

put them inside DIV tags, and then to hide/show entire DIVs.

Using this technique, even an entire web application can be placed on a single HTML page without requiring

any navigation -- instead of navigation, just show the DIV containing the next block of input!

We have a very rudimentary application involving Name, Address, a Message and a Summary page.

The exercise in this page is to pack them in a single page MyApplication.html. Though one may not want to pack an entire application in one page for aesthetics and/or manageability

reasons, the choice is there! And this exercise will show you the capabilities available.

Note that the AutoSessionData continues to work.

Exercise:

1. Create an HTML file MyApplication.html, with the Jaxcent JavaScript include statement in it. Add

four DIV elements in it, with ids "nameDiv", "addrDiv", "messageDiv" and "summaryDiv". In these

DIVs, copy the HTML forms and tables from the earlier Name.html, Address.html, Message.html and

Summary.html files, but not the "Reset" or "Next" buttons.

2. On all the DIVs, set the attribute style="display: none;" to start them off hidden at first.

3. After all the DIVs, add a single Reset and a single Next button.

4. Write the Java file for the HTML. In the constructor, show the "nameDiv" DIV. When connecting to

the HTML file, don't forget to set the AutoSessionData!

5. Add a Reset handler as earlier.

6. Maintain a "currentPage" variable. Add a handler for the Next button. Because the user is not leaving

the page, session data will not be automatically saved on the Next button. The saving must be done

manually. In the handler, call the method "getAllSessionData( true )" to save the form data into the

session (you can ignore the result of the method.) Then hide the current DIV being shown, and show

the next DIV. If the next DIV is the summary DIV, also populate the summary table, and hide the

Reset and Next buttons.

7. Similarly, add a Back button. Use the "setEnabled" method in the constructor to start it off disabled.

Enable it in the Next button's handler. Hide it when the user gets to the summary. Add code to show

the previous DIV, and if on the first DIV, to disable itself.

Creating New Elements and Moving Existing Elements Sometimes just hiding and showing page elements is appropriate. At other times, it is more appropriate to

create new elements and insert them in the page. Sometimes, elements just need to be moved around!

In AJAX programming, great effects can be achieved using all these techniques.

The hierarchy of elements on the HTML page is known as the "Document Object Model" or "DOM" for short.

The DOM is a nicely organized tree structure. Elements are arranged as child and parent nodes.

If you want to create a new HTML node (say, a new <IMG> element), you need to decide where to insert it in

the tree structure. There are some convenient options:

Insert in as the first or last child of a known node. The BODY node (corresponding to

the HtmlBody class) is a convenient node for this, because many times it is convenient to add a new

element at the top or bottom of the page.

Insert it right before or right after some other known node. For instance, you could create a new image

element, and insert it right after a para node.

Same consideration apply if you want to move an element -- you need to decide where to move it to!

In Jaxcent, new elements are created using the same constructors we have been using, e.g. HtmlPara, HtmlDiv

and so on. But the constructors take a SearchType parameter -- to create new elements, this parameter is

specified as SearchType.createNew to tell Jaxcent that instead of searching for an existing element, it should

create a new element on the page.

The new element must then be inserted in the page. Element insertion is same for new or existing elements,

with the difference that when you create a new element, it will not be visible on the page until the first time

you have inserted it somewhere in the DOM hierarchy.

These concepts should become clear with an example: HtmlBody body = new HtmlBody(); // The BODY of the page

HtmlPara p = new HtmlPara( this, "myPara" ); // A P tag with id "myPara"

// Insert the new para at the end, move the old para

// the new para (from wherever it was)

void newPara() throws Jaxception

{

// Make a new para some text.

HtmlPara newp = new HtmlPara( this, SearchType.createNew,

"P", "My New Para, created at " + new java.util.Date());

newPara.insertAtEnd( body ); // New para goes at end of BODY

p.insertBefore( newPara ); // "myPara" goes jsut before new para

}

The methods insertAtEnd and insertAtBeginning insert (or move) a child node in another node, such as the

body. The methods insertBefore and insertAfter insert (or move) a node immediately before or after a

sibling node.

Exercise: Write an HTML file DOM.html that has a para containing some text, and after that a form with id

"form". In the form, add a checkbox with name "insertAtEnd" followed by a label "Insert at End". After this,

put a button with id "insertTime" and text "Insert Time".

When the button is clicked, if the checkbox has not been checked, insert a new para at the beginning of the

BODY giving the current time. If the checkbox has been checked, insert a new para giving the current time at

the end of the body. Sleep 2 seconds, then move the new para just before the form. (Note: in the data map, the

value for the checkbox will be an empty string if the checkbox has not been checked.)

Saving Your Own Data in the Session Earlier we learned about the session, and how to use it for form elements.

The session is a useful concept, and in addition to form elements, it can also be helpful to save your own data

for a user.

The Jaxcent "session" matches the "session" of a Java Application Server if Jaxcent is running in a Java

Application Server. Therefore if you have a legacy web application using a Java Application Server, you can

use the session from both Jaxcent pages and the Application Server servlets/JSPs, and they can co-operate.

In general, however, it is not guaranteed that you are running inside a Java Application Server. Jaxcent could

be directly connected to an IIS or Apache web server, or there may be some other configuration.

You will still have some kind of a session available, but it may not be an Application Server's session.

Therefore, to save any data for your own use, it's best to store it in the java.util.Map that Jaxcent makes

available. If you enable AutoSessionData this Map will be available to you. The Map just stores the values of

all form field using names/ids as keys (keys are lowercased, retrieval is case independent) in this map. So as

long as you don't collide with these names, you can store your own values in the same Map, and it will be

available to you for the duration of the user's session.

The Map is available by calling getAllSessionData( false ); from any page with AutoSessionData enabled.

If the parameter is true, the session will first be updated with any data on the current page.

Exercise: Earlier we made a small shopping-cart type application. Modify the MyPage.java as follows:

1. Add AutoSessionData in the mapping for MyPage.html.

2. Add a "bookList" field of class Vector (can't be ArrayList without adding synchronization, therefore

Vector is convenient.)

3. In the constructor, retrieve the data Map (parameter must be false, there is no page connected in the

constructor) and get the element bookList from this map at key "MyPage.shoppingCart". If the

element is null, create the Vector bookList, and store it at that key. If the element is not null, it must be

the Vector you have saved earlier. Populate the table from it.

4. As you save data in the table, also store the book names in the "bookList" Vector.

5. Now everytime you visit the page again (without having timed out the session), you should see the

shopping cart populated from any earlier choices.

6. You will notice a slight problem -- the AutoSessionData will keep the previous SELECT selection

highlighted even though in this case we don't want this data to be saved! This can be fixed by putting

the mySelect.setSelectedIndex( -1 ); in an onLoad override instead of the constructor, so this can

be reset at page load.

Dragging and Dropping Using AJAX, user interfaces such as dragging and dropping become possible. We will briefly cover that here.

Dragging and dropping involves two items

1. A dragging source, and

2. A drop target.

The source is something that you click on, and drag around. The target is where you release the source, and

which potentially does something useful with it!

In Jaxcent, you set an element draggable just by calling setDraggable on it.

To make something a drop-target, you just override the OnDragDrop method. This method takes on argument,

which is the source that has been dragged.

The OnDragDrop takes the specific actions related to the drag and drop action. For instance, if the drop target is

an icon of a trash-can, it would make sense for it to delete the dragged item, and to record in the session that

the dragged item has been removed.

Drag and drop will typically change your underlying data structure, and therefore will often involve working

with the session. For this example, we are not going to save anything in the session, because we just want to

see how drag and drop can be made to work.

We will have two paragraphs, both of which serve as both a source as well as a target. They can be dragged

and dropped on each other. The dropped one gets moved before the other one!

Exercise: Write an HTML file with two paras and a matching Java file. Each of the two paras overrides

the OnDragDrop method, and inserts the dropped source before it. In the constructor, make both paras

draggable.

Optimization Issues The Jaxcent documentation has some pointers on optimization. These should be reviewed by serious

programmers.

We won't get into the technical details of those here. Instead, this tutorial will point out some practical issues.

In practical programming, there are various levels of optimization.

We have already covered JavaScript and how to improve response and decrease server load by doing things in

JavaScript.

But given today's servers' power and network speeds, if you are developing an intranet application for a

thousand users on a local area network, such optimization would be a waste of time. You may as well not

spend any time and effort with JavaScript. JavaScript, as of now, is much harder and clumsier to write,

organize and debug than Java. Therefore any development you do in Java instead of JavaScript, improves the

application reliability, reduces development time, and so on.

On the other hand, if you are developing an application that could be potentially used by hundreds of

thousands of users, some of whom may be located half way around the world at fifty network hops, you should

put as much the of the work in JavaScipt as possible, so the application does not have any client-server trips

that are not absolutely necessary, and so that the clients are distributing as much workload as possible.

If you don't know ahead of time how much the application needs to scale, a good stragety is to start with an all

Java version. As the application grows in clientele, you can start moving selected pieces to JavaScript if/when

needed.

There are other optimization issues as well, but in Java AJAX programming at the time, Java/JavaScript

balancing is the big optimization issue. Servers hava become very fast and powerful. The network can still be a

bottleneck.

Of course, optimization trade-offs change every few years with advances in technology and hardware. It is

possible that a few years later, entirely other issues may dominate optimization instead!

Further Learning This tutorial uses a special server that makes learning very easy. Because it is designed for making learning

easy, the Tutorial Server is not a very efficient server. In actual usage, Jaxcent works with servers known as

Java Application Servers, or web servers known as IIS and Apache.

Depending upon your environment, you will need to learn how to configure Jaxcent for the type of server you

have.

The Jaxcent download package includes documentation on getting started, as well as the Jaxcent API.

In addition to the API and environment, AJAX programmers using Jaxcent should focus on learning the

various types of HTML tags and styles. HTML styles are often called "CSS" (Cascading Style Sheets) by

HTML programmers, because historically, many HTML styles and separate style sheets were introduced

together. However, for an AJAX programmer, an HTML style is an HTML style, whether it comes from a CSS

or not. Some HTML tutorials are:

W3 Schools HTML Tutorial

Quackit

HTML Help

HTML Code Tutorial

Some JavaScript learning can also help. Though JavaScript is not required in Jaxcent programming, a

knowledge of JavaScript can be useful, and in particular, can help in advanced programming using Jaxcent (for

instance, in integrating a third party JavaScript solution.)

Some JavaScript tutorials are:

W3 Schools JavaScript Tutorial

WebDeveloper.com

JavaScript Kit

Web-Source.net

Jaxcent can be downloaded from http://www.jaxcent.com/


Recommended