Tutorial of J2S in Eclipse (6): How to Use ajax.* -- A Simple RSS Reader

Zhou Renjian
Feb 16, 2006

This article demostrates the ways of developing AJAX web application through Java and J2S Pacemaker. The concept of AJAX from Java perspective is also introduced in this article.

Prerequisite

Please read previous tutorials:

Setup AJAX environment

First create a Java project with source folder "src". Then configure that project as Java2Script project by enable Java2Script compiler. For AJAX-supported, you should add project "net.sf.j2s.ajax" as required. And you should aslo add the "j2s-ajax-core.jz" in the Java2Script Builder property page.

Import the project "net.sf.j2s.ajax" into the workspace. You can find the project "net.sf.j2s.ajax" in the folder "src" in the version 0.5.0, or you can download the project from the AJAX-related resources before you can continue this tutorial. And after imported, add the "net.sf.j2s.ajax" project to the build path of your project (by Properties -> "Java Build Path" Property Page -> "Projects" Tab -> "Add" Button).

And as this tutorial is to provider an SWT-based RSS Reader, you should also configure the project as SWT-supported project. For more configuration details, please visit Setup SWT Environment of Tutorial of J2S in Eclipse (5): Tutorial of J2S in Eclipse (5): How to Use org.eclipse.swt.* -- Tour to UI.

First AJAX in Java

Synchronous request in Java codes:

HttpRequest request = new HttpRequest();
request.open("GET", "http://idwhiz.vicp.net/whizznotes/rss/all.xml", false);
request.send();
System.out.println(request.getResponseText());

Asynchronous request in Java codes:

final HttpRequest request = new HttpRequest();
request.open("GET", "http://idwhiz.vicp.net/whizznotes/rss/all.xml", true);
request.registerOnReadyStateChange(new HttpRequestCallBackAdapter() {
	public void onComplete() {
		System.out.println(request.getResponseText());
	}
});
request.send();
System.out.println("continue!");

Let me take some seconds explaining the above codes. HttpRequest is a wrapper that call java.net.HttpURLConnection to do what XMLHttpRequest do in JavaScript. And HttpRequest provides the following APIs:

getReadyState()
getResponseCode()
getResponseHeader(String)
getResponseText()
getResponseXML()
open(String, String)
open(String, String, boolean)
registerOnReadyStateChange(IHttpRequestCallBack)
run()
send()
send(String)
setRequestHeader(String, String)
in which, the method "run" is implementing java.lang.Runnable.
And in JavaScript, there is a relative HttpRequest.js that wraps XMLHttpRequest in the same style APIs.

And IHttpRequestCallBack and HttpRequestCallBackAdapter is simple as following:

public interface IHttpRequestCallBack {
	public void onUninitialized();
	public void onLoading();
	public void onLoaded();
	public void onInteractive();
	public void onComplete();
}

public class HttpRequestCallBackAdapter implements IHttpRequestCallBack {
	public void onComplete() {
	}
	public void onInteractive() {
	}
	public void onLoaded() {
	}
	public void onLoading() {
	}
	public void onUninitialized() {
	}
}

SWT RSS Reader

Following, I will show you the example that native SWT RSS Reader running as standalone desktop application, which can be converted into Java2Script application running inside browser.

First, I choose my old blog wHizz Notes as my testing RSS sources, because the outputed RSS can be easily constructed into a Tree.

Here is the main codes:

package net.sf.j2s.examples;

import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import ajax.HttpRequest;

public class RSSReader {

	public static void main(String[] args) {
		final Display display = new Display();
		Shell shell = new Shell(display);
		shell.setMaximized(true);
		shell.setText("wHizzNotes RSS Reader (J2S AJAX)");
		shell.setLayout(new FillLayout());

		SashForm form = new SashForm(shell, SWT.HORIZONTAL);
		form.setLayout(new FillLayout());

		Composite outlinePanel = new Composite(form, SWT.NONE);
		outlinePanel.setLayout(new FillLayout());
		final Tree outline = new Tree(outlinePanel, SWT.BORDER);
		final String RSS_PREFIX = "http://idwhiz.vicp.net/whizznotes/rss/";
		final String HTML_PREFIX = "http://idwhiz.vicp.net/whizznotes/xhtml/";
		String[] roots = new String[] {
//				"http://idwhiz.vicp.net/whizznotes/rss/all.xml",
				RSS_PREFIX + "1.xml"//,
		};
		for (int i=0; i < roots.length; i++) {
			TreeItem root = new TreeItem (outline, 0);
			root.setText ("wHizzNotes");
			root.setData (roots [i]);
			new TreeItem (root, 0);
		}

		final Composite contentPanel = new Composite(form, SWT.NONE);
		contentPanel.setLayout(new FillLayout());
		final Browser browser = new Browser(contentPanel, SWT.BORDER);

		outline.addListener (SWT.Expand, new Listener () {
			public void handleEvent (final Event event) {
				final TreeItem root = (TreeItem) event.item;
				TreeItem [] items = root.getItems ();
				for (int i= 0; i < items.length; i++) {
					if (items [i].getData () != null) {
						return;
					}
					items [i].dispose ();
				}
				String url = (String) root.getData();
				final HttpRequest request = new HttpRequest();
				request.open("GET", url, true);
				request.registerOnReadyStateChange(new HttpRequestCallBackSWTAdapter() {
					public void swtOnComplete() {
						//System.out.println(request.getResponseText());
						NodeList xitems = request.getResponseXML().getElementsByTagName("item");
						for (int i = 0; i < xitems.getLength(); i++) {
							Element item = (Element) xitems.item(i);
							NodeList titles = item.getElementsByTagName("title");
							Element title = (Element) titles.item(0);
							String titleLabel = title.getFirstChild().getNodeValue();
							
							NodeList htmlURL = item.getElementsByTagName("link");
							Element link = (Element) htmlURL.item(0);
							String url = link.getFirstChild().getNodeValue();
							url = RSS_PREFIX + url.substring(url.lastIndexOf("/") + 1, url.lastIndexOf(".")) + ".xml";

							TreeItem treeItem = new TreeItem (root, 0);
							treeItem.setText (titleLabel);
							treeItem.setData (url);
							new TreeItem (treeItem, 0);
						}
						root.setExpanded(true);
					}
				});
				request.send();
			}
		});

		outline.addSelectionListener(new SelectionAdapter() {
		
			public void widgetSelected(SelectionEvent e) {
				String url = (String) outline.getSelection()[0].getData();
				url = HTML_PREFIX + url.substring(url.lastIndexOf("/") + 1, url.lastIndexOf(".")) + ".html";
				browser.setUrl(url);
			}
		
		});
		
		form.setWeights(new int[] { 32, 68 });
		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
		display.dispose();
	}

}
And the HttpRequestCallBackSWTAdapter is an implementation of IHttpRequestCallBack that bridge callbacks from Thread gulf of SWT.
public class HttpRequestCallBackSWTAdapter implements IHttpRequestCallBack {
	public void swtOnComplete() {
	}
	public void swtOnInteractive() {
	}
	public void swtOnLoaded() {
	}
	public void swtOnLoading() {
	}
	public void swtOnUninitialized() {
	}
	public void onComplete() {
		Display.getDefault().syncExec(new Runnable() {
			public void run() {
				swtOnComplete();
			}
		});
	}
	public void onInteractive() {
		Display.getDefault().syncExec(new Runnable() {
			public void run() {
				swtOnInteractive();
			}
		});
	}
	public void onLoaded() {
		Display.getDefault().syncExec(new Runnable() {
			public void run() {
				swtOnLoaded();
			}
		});
	}
	public void onLoading() {
		Display.getDefault().syncExec(new Runnable() {
			public void run() {
				swtOnLoading();
			}
		});
	}
	public void onUninitialized() {
		Display.getDefault().syncExec(new Runnable() {
			public void run() {
				swtOnUninitialized();
			}
		});
	}
}

Running the RSSReader as "SWT Application", you will get:
Desktop SWT RSS Reader

And running the RSSReader as "Java2Script Application", then deploy, and launching it in browser, you will get:
Browser SWT RSS Reader
You can test the online SWT RSS Reader here in wHizzNotes (The server may be slow and unstable. Enjoy it).

For Safari user, you will fail on the above online demo, please read the comments on section "First SWT snippets" of "Tutorial of J2S in Eclipse (5): How to Use org.eclipse.swt.* -- Tour to UI" for more details.

About XML and W3CDOM

In the HttpRequestCallBackSWTAdapter's swtOnComplete(), some lines using the standard W3C DOM APIs to read titles and links from the response RSS2.0 XML.

NodeList xitems = request.getResponseXML().getElementsByTagName("item");
for (int i = 0; i < xitems.getLength(); i++) {
	Element item = (Element) xitems.item(i);
	NodeList titles = item.getElementsByTagName("title");
	Element title = (Element) titles.item(0);
	String titleLabel = title.getFirstChild().getNodeValue();
	
	NodeList htmlURL = item.getElementsByTagName("link");
	Element link = (Element) htmlURL.item(0);
	String url = link.getFirstChild().getNodeValue();
	url = RSS_PREFIX + url.substring(url.lastIndexOf("/") + 1, url.lastIndexOf(".")) + ".xml";
	
	...
}
These Java codes will be converted into compatiable JavaScript in the way of W3C DOM recommendation. The generated JavaScript will use field-access properties rather than those get* methods:
for (var i = 0; i < xitems.length; i++) {
var item = xitems.item (i);
var titles = item.getElementsByTagName ("title");
var title = titles.item (0);
var titleLabel = title.firstChild.nodeValue;
var htmlURL = item.getElementsByTagName ("link");
var link = htmlURL.item (0);
var url = link.firstChild.nodeValue;
url = this.$finals.RSS_PREFIX + url.substring (url.lastIndexOf ("/") + 1, url.lastIndexOf (".")) + ".xml";
...
}

Thought deep under reusing

In the last tutorial article's Thought deep under reusing, I said integrated developing environment or tools are important factors for web UI libraries. And now I will say something about web application. Once user can use both desktop client application or browser web application in similar UI, user will feel familiar and happy. And for programmers, codes are only needed to write once, and then codes can be run elsewhere. If there are modification needed, it will be small and it will save the programmer's efforts of maintaining codes. And besides, desktop application may be developed much faster, as there are lots of efficient tools for Java Gurus.

Resources

Down the net.sf.j2s.swt.ajax/examples project files (zip) (121k)

Blog discussion

Have problems while reading through these articles? Or find some errors between the words? Or have some ideas on the Java2Script technology? Please make comments or discussions here in the blog.

About the author

Zhou Renjian: Initial contributor of Java2Script.