Tuesday, April 18, 2006

AJAX JSP and Direct Web Remoting

I wanted to try out Ajax with Java for some time now. I was clueless as to where to start. I came across this tool called "Direct Web Remoting" at http://getahead.ltd.uk/dwr/index .

I decided to give it a try with the assumtions:-

1) I should have a simeple java jsp/servlet which does some simple validation.
2) This JSP/Servlet will invariable go back to the server and reload the jsp Page.
3) The AJAX code must be able to perform the same simple validation.
4) The AJAX code must go back to the server but must not reload the jsp Page.

So i went ahead and first wrote a simple JSP/Servlet with Weblogic 8.1 and JDK 1.4.

NOTE:- Blogger tries to render HTML tags in a blog. So where you see [] in tags read them as <>.

The traditional Servlet/JSP code:-

package suchak.ajax.test;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

public class SimpleTestServlet extends HttpServlet {

// Initialize th log4j logger
private Logger log = Logger.getLogger(SimpleTestServlet.class);

// The default String in the all jsp form action attributes.
private final static String COMMANDENDSTRING = ".cmd";

/* Using service method so that the servlet will work with a get as
* well as a port
*/
public void service(HttpServletRequest req, HttpServletResponse res)
throws IOException, ServletException{

log.debug("the command asked for is : " +
req.getRequestURI() );

if(isCommand("processFullForm",req)){
try{
processFullForm(req,res);
req.setAttribute("iSANumber","iSANumber");
}catch(NumberFormatException e){
req.setAttribute("NotANumber","NotANumber");
}
}
req.getRequestDispatcher("jsp/welcome.jsp").forward(req,res);
}


/* The process method does the does the full form processing test.
*
*
*/
private void processFullForm(HttpServletRequest req, HttpServletResponse res)
throws NumberFormatException, ServletException {
//Set the done attribute for the screen
String number = req.getParameter("number");
Double.parseDouble(number);
req.setAttribute("done","done");
}

/* This method tests the URI to see which command was asked for.
* The command is the same as the action attribute of the form tag in the
* jsp. This way multiple JSP's can use the same servlet.
*
* @param command the string value of the command i.e the action attribute
* of the form tag in the jsp.
* @param req the http request object
*
* @return boolean returns true if the command is same as the req uri or
* false otherwise
*/
private boolean isCommand(String command, HttpServletRequest req){
log.debug("URI will be compared with :: " +
req.getContextPath()+ "/" + command + COMMANDENDSTRING);
return req.getRequestURI().
equals(req.getContextPath()+ "/" + command + COMMANDENDSTRING);
}}


Traditional JSP

[html]
[head]
[title]Welcome[/title]
[/head]
[body]
[h1]
Welcome to the AJAX Test
[/h1]
[br /]
[br /]
[!-- Start : Section for full form processing --]

[hr]

[h4]Full JSP reload test[h4]

[FORM name="JSPReload" action="/ajaxtest/processFullForm.cmd" method="post"]
[h4]Please enter a number here : [/h4]

[INPUT type="text" name="number" value="
[%if(request.getAttribute("number") !=null){
out.println(request.getAttribute("number"));
}else{
out.println("");
}%]
"]

[%if(request.getAttribute("NotANumber") != null){%]
[h4]Please Enter a Valid Number ![/h4]
[%}else if(request.getAttribute("iSANumber") != null) {%]
[h4]That was a valid Number ![/h4]
[%}%]

[INPUT type="submit" name="submit" value="Click to get check whether the value entered is a number"]

[/FORM]

[!-- Start : Section for output values --]
[%if(request.getAttribute("done") != null){%]
[h4]Done[/h4]
[%}%]
[!-- END : Section for output values --]

[!-- End : Section for full form processing --]

[/body]
[/html]

Traditional Web.xml

[?xml version="1.0" encoding="UTF-8"?]
[!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"]

[web-app]
[servlet]
[servlet-name]SimpleTestServlet[/servlet-name]
[servlet-class]suchak.ajax.test.SimpleTestServlet[/servlet-class]
[/servlet]

[servlet-mapping]
[servlet-name]SimpleTestServlet[/servlet-name]
[url-pattern]*.cmd[/url-pattern]
[/servlet-mapping]

[/web-app]

The above code works in the traditional way, and outputs wether the user entered a number on the jsp or not. Also it does the traditional JSP reload as expected

The AJAX JSP code:-

The test bean code

package suchak.ajax.test;

public class TestAjx {

public boolean isNumber(String number){
System.out.println("In Server side Test Ajax");
try{
Double.parseDouble(number);
System.out.println("In Server side Test Ajax : Before return true");
return true;
}catch(NumberFormatException e){
System.out.println("In Server side Test Ajax NumberFormatException: " +
"Before return false");
return false;
}
}}


The Modified AJAX JSP

[html]
[head]
[title]Welcome[/title]
[script type='text/javascript' src='/ajaxtest/dwr/interface/TAjx.js'][/script]
[script type='text/javascript' src='/ajaxtest/dwr/engine.js'][/script]
[script type='text/javascript' src='/ajaxtest/dwr/util.js'][/script]
[/head]
[body]
[h1]
Welcome to the AJAX Test
[/h1]
[br /]
[br /]
[!-- Start : Section for full form processing --]

[hr]

[h4]Full JSP reload test[h4]

[FORM name="JSPReload" action="/ajaxtest/processFullForm.cmd" method="post"]
[h4]Please enter a number here : [/h4]

[INPUT type="text" name="number" value="
[%if(request.getAttribute("number") !=null){
out.println(request.getAttribute("number"));
}else{
out.println("");
}%]
"]

[%if(request.getAttribute("NotANumber") != null){%]
[h4]Please Enter a Valid Number ![/h4]
[%}else if(request.getAttribute("iSANumber") != null) {%]
[h4]That was a valid Number ![/h4]
[%}%]

[INPUT type="submit" name="submit" value="Click to get check whether the value entered is a number"]

[/FORM]

[!-- Start : Section for output values --]
[%if(request.getAttribute("done") != null){%]
[h4]Done[/h4]
[%}%]
[!-- END : Section for output values --]

[!-- End : Section for full form processing --]

[br][br][br][br][br]

[!-- Start : Section for ajax form processing --]

[hr]

[h4]Ajax test : Not full form Refresh[h4]

[h4]Please enter a number here : [/h4]

[FORM name="AJAXTest" onsubmit="showMessage()" method="post"]
[INPUT type="text" name="AjxNumber" value=""]
[INPUT type="submit" name="submit" value="Click to get check whether the value entered is a number"]
[/FORM]
[script language="javascript" type="text/javascript"]

var bool = false

var reply0 = function(data){
bool = data
}

function showMessage() {
TAjx.isNumber(document.AJAXTest.AjxNumber.value,reply0)

alert(bool)

if(
document.AJAXTest.AjxNumber.value != null
&& document.AJAXTest.AjxNumber.value != ''
&& bool
)
{
alert('That was a valid number!');
}
else{
alert('Please enter a Valid Number!');
}
}

[/script]

[!-- End : Section for ajax form processing --]

[/body]
[/html]


The Modified AJAX Web.xml

[?xml version="1.0" encoding="UTF-8"?]
[!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"]

[web-app]
[servlet]
[servlet-name]SimpleTestServlet[/servlet-name]
[servlet-class]suchak.ajax.test.SimpleTestServlet[/servlet-class]
[/servlet]

[servlet]
[servlet-name]dwr-invoker[/servlet-name]
[display-name]DWR Servlet[/display-name]
[servlet-class]uk.ltd.getahead.dwr.DWRServlet[/servlet-class]
[init-param]
[param-name]debug[/param-name]
[param-value]true[/param-value]
[/init-param]
[/servlet]

[servlet-mapping]
[servlet-name]SimpleTestServlet[/servlet-name]
[url-pattern]*.cmd[/url-pattern]
[/servlet-mapping]

[servlet-mapping]
[servlet-name]dwr-invoker[/servlet-name]
[url-pattern]/dwr/*[/url-pattern]
[/servlet-mapping]

[/web-app]

The new AJAX DWR.xml

[!DOCTYPE dwr PUBLIC
"-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
"http://www.getahead.ltd.uk/dwr/dwr10.dtd"]

[dwr]
[allow]
[create creator="new" javascript="TAjx" scope="session"]
[param name="class" value="suchak.ajax.test.TestAjx"/]
[/create]
[create creator="new" javascript="JDate" scope="session"]
[param name="class" value="java.util.Date"/]
[/create]
[/allow]
[/dwr]

This works as assumed above with the output :-

In Server side Test Ajax
In Server side Test Ajax NumberFormatException: Before return false
In Server side Test Ajax
In Server side Test Ajax : Before return true

The Problems i faced were :-

1) The dwr.jar (http://getahead.ltd.uk/dwr/download) is needed to be in the web-inf/lib dir, along with the bean class suchak.ajax.test.TestAjx. I had place everthing in APP-inf/lib dir which was not working. I found out that this was a known issue with DWR in weblogic 8.1.
2) The javascript was a bit difficult to figure out initially, but looking at the code in the example war it came out to be pretty straightforward.

The issues i think are :-

1) There is a dependency on DWR for this to work.
2) The Ajax page sends gives alerts instead of messages on the page like the JSP/Servlet solution, which i think is better than alerts. There is a javascript document.write but that can not write to a portion of the page.

But all said and done the HTML Java AJAX solution does work, with little effort using DWR. Also it does server side validations without page refresh.

0 Comments:

Post a Comment

<< Home