Thursday, March 06, 2008

Java Remoting – Calling Java APIs from Javascript via AJAX

Current Strategy:
In the real-world Web Application Development, to make a Java API call from any Javascript event (Clicking on Submit/Go button) requires the Page to be submitted and request will be sent to the server and response will be returned back to the Browser and page will be reloaded with the results.

Issues with this approach is that
- Requires round-trip to the server.
- Page will have to be reloaded to refresh the content.
- Cannot call Java APIs in the client side javascript.
- Not rich user experience.

A little background on AJAX:

In the AJAX world, making a call to the server side APIs via XMLHttpRequest and polling results in the background and loading the results in the UI without reloading the page gives rich user experience.
For example, Google Suggest - Google pulls the list of suggested search key words as soon as user keys in the data in the search bar. It executes the poll the key words via background.

Our Strategy:
This programming approach uses AJAX to make a call to the Java API via Java Servlet and displays the results in the UI. This simple architecture works as follows:

1. In the Javascript, using XMLHttpRequest object, submit the POST request to the Java Servlet with the input parameters to be passed on the Java API.

Parameters contain
a) Class Name,
b) Method Name to be invoked.
c) Method input parameters.

2. Java Servlet uses Java Reflection API to invoke the method on the
given class name and executes the method and returns the results
in doPost method.

3. In the Javascript callback function, process the results and display
it in the UI.

Example and Files:

1. JSP Application (JavaAjaxTest.jsp)

<pre>
<script language="Javascript">
function xmlhttpPost(strURL) {
var xmlHttpReq = false;
var self = this;
// Mozilla/Safari
if (window.XMLHttpRequest) {
self.xmlHttpReq = new XMLHttpRequest();
}
// IE
else if (window.ActiveXObject) {
self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
}
self.xmlHttpReq.open('POST', strURL, true);
self.xmlHttpReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
self.xmlHttpReq.onreadystatechange = function() {
if (self.xmlHttpReq.readyState == 4) {
updatepage(self.xmlHttpReq.responseText);
}
}
self.xmlHttpReq.send("class=ajaxproj.HelloWorld&method=sayHello&username='"+ document.JavaAJAXForm.username.value+"'");
}
function updatepage(str){
document.getElementById("result").innerHTML = str;
}
</script>

<form name="JavaAJAXForm">
<input name="username">
<input onclick="'JavaScript:xmlhttpPost(" type="button" value="Go"></input>
<div id="result"></div>
</form>

</pre>

2. HelloWorld.java
package ajaxproj;

public class HelloWorld {
public HelloWorld() {
}
public String sayHello(String name) {
return "Hello "+ name;
}

3. Java Servlet (JavaMethodServlet.java)
package ajaxproj;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.*;

import java.net.URL;

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

public class JavaMethodServlet extends HttpServlet {
private static final String CONTENT_TYPE = "text/html; charset=windows-1252";

public void init(ServletConfig config) throws ServletException {
super.init(config);
}

public void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}

public void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {response.setContentType(CONTENT_TYPE);

System.out.println("JavaMethodServlet.doPost");

PrintWriter out = response.getWriter();
//Parse the Query String and Call Java Method with Parameters.
String className = (String) request.getParameter("class");
String methodName = (String) request.getParameter("method");
String userName = (String) request.getParameter("username");

//Call Java Method.
Class c;
Method method;
String value = null;

try {
c = Class.forName(className);
Object obj;
obj = c.newInstance();
method = c.getDeclaredMethod(methodName, new Class[]{String.class});
method.setAccessible(true);
value = (String) method.invoke(obj , new String[]{userName});

System.out.println(value);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}

out.write(value);
out.close();
}
}

How does it works:
Invoke JavaAjaxTest.jsp, enter the username and click on Go.
The message Hello <username>will be displayed without refreshing the page.

Here is how it works:
1. When user clicks on the Go button, we make a call to the java servlet with the appropriate classname, methodname and the username input values in the AJAX way using XMLHttpRequest object.
2. Javaservlet parses the request parameters, and invokes method on the given class and returns the result.
3. In the Javascript classback function, we process responseText and set the value of "result" div element to display the return value.

This is the initial approach, it can be further enhanced to return and handle objects from Java APIs, and to handle Security (CSRF - Cross Site Request Forgery), etc to give a complete framework which can be used in the web applications to make a call to Java APIs.

Frameworks:
- There are few open source frameworks available such as DWR
http://getahead.org/dwr/) and Reverse AJAX(using/manipulating
Javascript content in Java) , but still the security is a open issue to be
enhanced further. Please look at http://getahead.org/dwr/overview/dwr

Thanks
Ananthalakshmi