Friday, April 21, 2006

STAX:The new Streaming API for XML

I was reading up something on JAXB which was pretty long winded, when i came accross this "STAX" or "Streaming API for XML".

It is a bit unique in it's design from both SAX and DOM, but it still is closer to SAX.

It is a parser and hence can be used to read up xml documents but additionally like DOM can also be used to write up XML.

It is a streaming parser like SAX and like SAX it works from start to finish, and can not work backwards from a certain point in an xml file.

SAX uses push style of streaming i.e. it reads up the entire xml file from start to finish and logs events which the user can use.

STAX uses pull style of streaming i.e like an iterator which checks for hasNext() and the uses next() to get the next Object, STAX also checks for hasNext() and the uses next() to get the next Element.

Why do we need a new style of parser ?

I guess the main reason is performance.

1) Threads
With sax style parsers the application thread control is with the sax parser and thus one application thread can read one document at a time.

With stax style parsers that the application thread control is with the application code that calls the parser and thus one application thread can multiple document at a time.

2) Smaller libraries
Sun tutorial claims that pull parsing libraries, can be much smaller than push libraies

3) Filters
StAX supports building of filters and thus xml content not needed, can be ignored by the parser.

Here is a quote from the Sun Tutorial:-

"Why StAX?

The StAX project was spearheaded by BEA with support from Sun Microsystems, and the JSR 173 specification passed the Java Community Process final approval ballot in March, 2004 (http://jcp.org/en/jsr/detail?id=173). The primary goal of the StAX API is to give “parsing control to the programmer by exposing a simple iterator based API. This allows the programmer to ask for the next event (pull the event) and allows state to be stored in procedural fashion.”

StAX was created to address limitations in the two most prevalent parsing APIs, SAX and DOM."

Note that BEA and Sun are both involved in this. So I guess for the future of java xml in general and java web services in particular STAX parsers are here to stay.

There are two kinds of STAX api

Cursor API
This is a light weight and fast api, used for projects like J2ME and projects where performance is essential.

It is implemented by XMLStreamReader and XMLStreamWriter interfaces.

Iterator API
In this api the Events generated can be used by the application even after the parser has moved on to subsequent Events. It is much more flexible when you want to add or remove Events, extend Events, etc..

It is implemented by XMLEventReader and XMLEventWriter interfaces.

Please see these links for more information:-

http://www.oracle.com/technology/oramag/oracle/03-sep/o53devxml.html
http://java.sun.com/webservices/docs/2.0/tutorial/doc/StAX.html#wp69937

Now back to JAXB.....

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.

Java DateFormat is not threadsafe

Java DateFormat and SimpleDate classes are not threadsafe.

When an application has a few common date formats it seems natural to have them in some common place like static variables or in some kind of singleton.

However as per this bug report last updated in 2001, date format is not thread safe :-

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4228335

Also the sun java doc for 1.4 and 1.5 confirms the same :-

http://java.sun.com/j2se/1.4.2/docs/api/java/text/DateFormat.html
http://java.sun.com/j2se/1.5.0/docs/api/java/text/DateFormat.html

Synchronization

Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.

What does that impact ?

Well if the methods of dateformat do not use instance variables like most servlets, i guess we should be ok, even if multiple threads access the dateformat, just like servlets.

However since the javadoc "recommends to create separate format instances for each thread" we might use thread local variables to store the DateFormats. That way instead of creating a new DateFormat each time it is needed, we will get only as many DateFormats as there are threads using them.

Java Timezone class

I was looking at java.util.TimeZone class. I guessed this could be important in places like the USA where there are three or more timezones.

However in addition to being usefull for places with different timezones it also seems to cater to places with daylight savings time. For the uninformed, especially from places like india where there is no daylight savings this link gives a lot of information :-

http://en.wikipedia.org/wiki/Daylight_saving_time

The javadoc is at :-

http://java.sun.com/j2se/1.4.2/docs/api/java/util/TimeZone.html

The interesting methods to use are the getOffset Methods :-

public abstract int getOffset(int era,int year,int month,int day,int dayOfWeek,int milliseconds)

Gets the time zone offset, for current date, modified in case of daylight savings. This is the offset to add to UTC to get local time.
This method returns a historically correct offset if an underlying TimeZone implementation subclass supports historical Daylight Saving Time schedule and GMT offset changes.

One can use this method in this fashion :-

TimeZone tz = timeZone.getTimeZone("America/Los_Angeles");
long actualDate = (new Date().getTime() ) + timeZone.getOffset(new Date().getTime() )