Thursday 17 July, 2008

Caching DWR interface java script files

DWR provides a convenient mechanism to execute server side java classes from javascript running in the browser. We use it extensively while developing Dekoh applications. Recently I noticed that when we use DWR, there are many requests to java-script files from the browser. It appeared that some DWR scripts are not being cached by the browser. I fired up firefox live http headers and noticed that inded some scripts were being downloaded with every page. We use DWR version 1.1.4. The headers for the repeat downloads looked like:

GET /dekohportal/dwr/interface/locationchooser.js HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en,as;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cache-Control: max-age=0

HTTP/1.x 200 OK
Server: Pramati Server/5.0SP3 [Servlet/2.4 JSP/2.0]
Date: Tue, 24 Jul 2007 05:29:20 GMT
Transfer-Encoding: chunked
Connection: Keep-Alive

Notice that in the response headers, there is no Last-Modified header. This is the reason why the browser is reloading the script on every page load. This script is a DWR interface script. When you expose java methods using DWR (through a create tag in the dwr-*.xml), DWR creates an interface javascript. This file implements javascript methods which invoke the remote java methods (using DWREngine._execute). The interface script does not change unless the methods exposed in the dwr-*.xml are changed and the application is restarted. Hence the script should have been cacheable. These scripts are generated by DefaultInterfaceProcessor in DWR. To enable caching, we need to change the InterfaceProcessor to add the Last-Modified header in the response and read the If-Modified-Since header in the request. DWR provides a nice mechanism to plugin custom implementation of processors. So instead of chaging the DefaultInterfaceProcessor (which is shipped with DWR), I subclassed the default implementation to support these new headers and plugged it in to our runtime. The code for custom interface processor looks like:

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import uk.ltd.getahead.dwr.impl.DefaultInterfaceProcessor;
import uk.ltd.getahead.dwr.impl.HtmlConstants;

/**
* This class is the InterfaceProcessor for DWRHandler which
* will add the functionality to add las modified header and
* check if modified since header.
* @author Venkat Gunnu
* @since Jul 19, 2007
*/

public class HttpCachingInterfaceProcessor
extends DefaultInterfaceProcessor

{
//Store the application startup time. This will be the time we will set
//as the Last-Modified time for all the interface scripts
private final long lastUpdatedTime = (System.currentTimeMillis() / 1000) * 1000;

public void handle(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
long ifModifiedSince = req.getDateHeader(HtmlConstants.HEADER_IF_MODIFIED);
if (ifModifiedSince < lastUpdatedTime) {
//If the browser does not have the script in the cache or the cached copy is stale
//set the Last-Modified date header and send the new script file
//Note: If the browser does not have the script in its cache ifModifiedSince will be -1

resp.setDateHeader(HtmlConstants.HEADER_LAST_MODIFIED, lastUpdatedTime);
super.handle(req, resp);
} else {
//If the browser has current version of the file, dont send the script. Just say it has not changed
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
}

To plugin this new Interface Processor, we need to add init parameter for DWRServlet in web.xml. The snippet from web.xml would look like:

dwr-invoker
uk.ltd.getahead.dwr.DWRServlet

interface
util.dwr.HttpCachingInterfaceProcessor

...


After adding the custom inerface processor following are the headers for the dwr interface request.

GET /dekohportal/dwr/interface/locationchooser.js HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en,as;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-aliveHTTP/1.x 200 OK
Server: Pramati Server/5.0SP3 [Servlet/2.4 JSP/2.0]
Date: Tue, 24 Jul 2007 05:49:43 GMT

Last-Modified: Tue, 24 Jul 2007 05:49:33 GMT
Transfer-Encoding: chunked
Connection: Keep-Alive

Notice that now for the first request, DWR is sending the Last-Modfied header. When we make the second request, the browser sends an “If-Modified-Since” header and DWR now sends a 304 NOT_MODIFIED response.

GET /dekohportal/dwr/interface/locationchooser.js HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en,as;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
If-Modified-Since: Tue, 24 Jul 2007 05:49:33 GMT

HTTP/1.x 304 NOT_MODIFIED
Server: Pramati Server/5.0SP3 [Servlet/2.4 JSP/2.0]
Date: Tue, 24 Jul 2007 05:50:42 GMT
Content-Length: 0
Connection: Keep-Alive

Thus, by plugging in a custom interface processor, we can enable caching of interface java-scripts in DWR.

Thursday 15 May, 2008

Debugging in IE

When I first started using JavaScript, I used to code and debug using Firebug and then test the same on IE. Obviously sometimes this used to fail due to some porting issues and I would be left with no means to know where and why the code is failing. I am writing this article to share something which will make life easier with debugging on IE for someone who is struggling like me.

I found a world-class free debugger for IE. Visual studio is known for the best debugger out there which can directly attach to any process running on windows, but that doesn't come for free. Microsoft started giving out express editions for free, which has a debugger but that cannot attach to already running processes. Follow the steps below to make express editions help debugging our web-pages on IE.

  • Install Visual Web Developer Express which is free and can be downloaded from
    http://msdn.microsoft.com/en-us/express/aa975050.aspx

  • Enable script debug on IE - go to Tools > Internet Options > Advanced, and make sure "Disable Script Debugging (Internet Explorer)" is unchecked and "Display a notification about every script error" is checked.

  • Start a dummy project with some name.

  • Start IE in debug mode with the created dummy project - Debug->start debugging.

  • The above will start IE with debug enabled and you can open your web-page and enjoy free ultimate debugger.


 

Tuesday 13 May, 2008

"Deep Copy" in JavaScript

Some of you might have come across this issue. When you make a copy of an object and try to change the values of the new instance, it reflects in the original one too. Well I heard this not only applies to JavaScript, but also to most other object oriented languages; not sure though.

Here is a case:



Problem


//original object definition
var oOriginal = {
memNum: 1, // number
memStr: "I am a string", // string
memObj: {
test1: "Old value" // we'll test
},
memArr: [ // array with object members
"a string", // simple string element
{ // an object
test2: "Try changing me" // we'll test
}
]
};

//test 1
var oCopy = oOriginal; // normal copy

oCopy.memObj.test1 = "New value"; // Problem
// - will reflect in oOriginal


alert(oOriginal.memObj.test1); // will show "New value"

//test 2
oCopy.memArr[1].test2 = "I am changed"; // Problem
// - will reflect in oOriginal


alert(oOriginal.memArr[1].test2); // will show "I am changed"


Here the problem is, the objects are never copied, only their references are. So what's the solution? Iterate through all members of the original object, create the same members for target object and then assign corresponding values. And while doing so, we can't forget array of objects.

(Referring to Sunil's comment to this post, we'll add this simple line at the very top to help us detect Array objects. It basically adds our own custom extension to the Array class.)



To recognize Array type objects


<html>
<head>
<title>Deep Copy in JavaScript</title>
<script language="javascript" type="text/javascript">
Array.prototype.__isArray = true;
</script>
.
.


Now, here is the generic method that will help in iterating through all (type of) members of our original object and copy them one-by-one regardless of the depth of the object structure:



Solution


var ObjectHandler = {
//public method
getCloneOfObject: function(oldObject) {
var tempClone = {};

if (typeof(oldObject) == "object")
for (prop in oldObject)
// for array use private method getCloneOfArray
if ((typeof(oldObject[prop]) == "object") && (oldObject[prop]).__isArray)
tempClone[prop] = this.getCloneOfArray(oldObject[prop]);
// for object make recursive call to getCloneOfObject
else if (typeof(oldObject[prop]) == "object")
tempClone[prop] = this.getCloneOfObject(oldObject[prop]);
// normal (non-object type) members
else
tempClone[prop] = oldObject[prop];

return tempClone;
},

//private method (to copy array of objects) - getCloneOfObject will use this internally
getCloneOfArray: function(oldArray) {
var tempClone = [];

for (var arrIndex = 0; arrIndex <= oldArray.length; arrIndex++)
if (typeof(oldArray[arrIndex]) == "object")
tempClone.push(this.getCloneOfObject(oldArray[arrIndex]));
else
tempClone.push(oldArray[arrIndex]);

return tempClone;
}
};


Now we'll perform the same two tests mentioned in the 'Problem' block using this new helper - ObjectHandler



Test


//test 1
var oCopy = ObjectHandler.getCloneOfObject(oOriginal);

oCopy.memObj.test1 = "New value";

alert(oOriginal.memObj.test1); // will show "Old value"

//test 2
oCopy.memArr[1].test2 = "I am changed";

alert(oOriginal.memArr[1].test2); // will show "Try changing me"


In general, this solution is often referred to as "Deep Copy".

Cheers!

Kumar
UI Architect


 

Javascript - Did you get a taste of it yet!?

Javascript is the most under rated language the world has ever seen. Yeah, there might be many more, but the way Javascript had been labeled as an entry level programmer's language for over a decade, nothing can get worse!

Thanks to Google, people suddenly woke up to realize the true potential of Javascript. Before that a million others tried to convince the world that this language has got more than they can imagine, but that hardly helped! I remember this one instance when GMail was launched, and a popular web browser had to come out out with a quick patch in order to make it GMail compatible. Now, if you and I had a similar issue and approached the same people we would be given a hand book on browser standards and compatibilities and asked to learn to live in the 'real world'. Well, this world works on 'brand' capitalization - nothing can replace the power of a brand (except money of course)!

I have always enjoyed coding in Javascript for the last ten odd years. Of course, it took me a long time to realize the true potential of object oriented javascript! My professional work was more in the Java world for a long time. After doing a bit of freelancing using MS Visual Studio, Perl and a few other technologies, I started my regular career on a Java based proprietary framework called WebObjects (this, for those of you who don't know, was at least 5 years ahead of it's time - was more like a combination of Tapestry and Hibernate). After that I went on to work on developing a C library, and later on worked on Tapestry, Hibernate and Spring too. I really enjoy working on a wide variety of technologies, and always prefer to be a jack of all, rather than an expert in something. I believe that being involved in diverse technologies makes you a lot more creative while dealing with tricky situations.

Hmm, now this post is supposed to deal with Javascript, so why am I talking about what I did! Well, now, didn't I mention branding :p! Well, I just want to set the context right guys - I have been there, seen that, and I really know where Javascript stands in terms of churning out amazing code that brings out amazing results. So, if you are a programmer, and if you ever get a chance to deal with raw Javascript, don't think twice - accept it straight away! By the way I didn't use the word 'raw' just like that. Sometime soon I will elaborate on this.

Javascript is basically a 'prototype' based object oriented language. What this means is that you don't describe an object (as in, you don't write a class), but rather use a sample object to define a type. It's a loosely typed language and does not need you to declare types for variables. It can also implicitly convert types as needed. As in Java, Javascript has primitive types and objects. String, number and boolean constitute the primitive types.

Every object in Javascript behaves like a hashmap, and you can determine which property of an object needs to be accessed at runtime. This is a very cool feature, and the last I had dealt with something close to that in Java was while programming using one of the WebObjects frameworks called Enterprise Objects Framework (EOF, please sit up and take note, is like a great ancestor of Hibernate and many other contemporary ORM frameworks). EOF had this base class that enabled a similar functionality using Java's reflection API, and programmers in general wouldn't have to deal with all the complexity of reflection. It definitely helped in trimming down the number of lines while implementing complex business functionality.

Now lets discuss a bit about functions in Javascript. One amazing thing is that every function declared in Javascript is treated like any other object. This means you can actually throw your functions around your code, pass them to other functions, and hold references to them using variables! Hmm, if you ever worked on C, you should be drooling by now - yep, function pointers on steroids, that's what this is!! All those guys from the Java World - sorry guys we have nothing like that in Java (you can try it with reflection, but not really, not enough) - so just make sure you have enough strength to imagine beyond the ordinary to understand the power of function pointers.

Any function in Javascript can be used as a constructor. Now this might confuse beginners, but it's a very simple concept - whenever you call a function preceded by the new keyword, a new object is created and that function is executed in the new object's context (on the lines of a constructor).

Well, now for some not so great news. Javascript does not support function overloading. But I guess there's a valid reason. Javascript allows variable number of arguments to be passed to a function, which means you can pass more arguments than what's been declared for the function! So, then how can those other arguments be accessed? Well, simple, every function has an internal variable called 'arguments' which is like an array of arguments, and all arguments passed to a function can be accessed using 'arguments'.

Well, that kind of wraps up some key features. I will get back with more on Javascript pretty soon!

Kartik Reddy Thum
Senior Dev Engineer

 

Friday 25 April, 2008

Separating JavaScript from HTML

This article addresses the difficulty and a possible solution to completely separate JavaScript from HTML e.g. event assigning attribute like onclick and more importantly onload.

Suppose your HTML page - myPage.html, looks something like this



myPage.html


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head><title>Separating JavaScript from HTML</title>
</head>

<body>

<p>Type your name here: <input id="userName" type="text" />
<button id="btnProceed">Proceed</button></p>

</body>
</html>


Now, here is the specific task description:

  • Assign an onclick event handler for the 'Proceed' button

  • This handler method should read the 'userName' input field and display a greeting message to welcome the user. If blank, inform user accordingly.

  • Do not use HTML attributes to assign events e.g. onclick, onload etc. The whole idea is to follow a more methodical approach while dealing with events and thereby obtain a clean HTML; just what we have been doing for 'look and feel' aka CSS.

Ok, we will first include the external JS file:



myPage.html


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head><title>Separating JavaScript from HTML</title>
<script language="JavaScript" type="text/javascript" src="myPage.js"></script>
</head>

<body>

<p>Type your name here: <input id="userName" type="text" />
<button id="btnProceed">Proceed</button></p>

</body>
</html>


Now, the real action. Let's start writing the JavaScript code; but here are some tips:

  • Have a single JavaScript Object, say oMyPage, to represent one HTML page. This should help you avoide any global variable declarations; you can have them as properties of this object.

  • Remember, ALL functionality you need for your HTML page should be comprised either as method or as property of the oMyPage object.

  • Define an initializer method which will take care of all event assigning task for necessary HTML elements. (Later on we'll set this method to be invoked automatically when our HTML page is completely loaded and ready.)

  • Always describe your method and property declarations with the help of comments. This will make the code maintenance easier.

  • Do not overlook the importance of proper indentation and self-explanatory but brief names (necessarily in the same order of priority) for your object members. Believe me, it doesn't take more than 1% of the total coding efforts.




myPage.js


//object to represent myPage.html
var oMyPage = {
//default initialize method
init: function(){
//get the button element
this.btnProceed = document.getElementById("btnProceed");

if (this.btnProceed) { //avoid exception
if (this.btnProceed.addEventListener) { //non-IE
this.btnProceed.addEventListener("click",this.greetUser,false);
}else if (this.btnProceed.attachEvent){ //IE
this.btnProceed.attachEvent("onclick",this.greetUser);
}
}
},

//method to read username inputbox and display greeting message
greetUser: function(){
//collect userName inputbox
var ibUserName = document.getElementById("userName");
var sUserName = '';

if (ibUserName) { //avoid exception
sUserName = ibUserName.value; //read

if (sUserName == '') { //check for blank entry
alert("Please enter your name");
} else { //greet user
alert("Welcome '" + sUserName + "'");
}
}
}
}

//set oMyPage object's initialize method to get invoked automatically when HTML page is ready
window.onload = function() {
window.setTimeout(function() { //especially for IE, setTimeout will make sure the page is ready. Later on we will have another post which will provide a better solution to check the document ready state.
oMyPage.init();
}, 10);
}


Of course, with the help of a wrapper like prototype.js, we can get rid of browser conscious code. But the point here was to handle this task with core JavaScript.

Please have a look at the member names. Prefixes can be used to describe types e.g. o for object, s for string etc. Definitely, one can think of his/her own naming convention rules. Also, defining these conventions somewhere in the file, preferably at the bottom, would be a great idea.

Concluding, this might not be a perfect solution. So, kindly leave your comments to improve this snippet further.

Cheers!

Kumar
UI Architect


 

Friday 14 December, 2007

Welcome to Pramati UIT Blog

Hi friends,

Welcome to Pramati UIT Blog! Let's make this place a good 'UI Technology and Trends' reference for our team and other Pramatians.

Here, we will post articles on Web Standards, New Trends in UI technology, JavaScript, AJAX, Usability, Accessibility and anything else that can prove as a good reference for UI Development.

Please make it a habit to read, add and comment.

Cheers!

Kumar
UI Architect