Monday, October 27, 2008

Dynamic Size Arrays in javascript

Recently I needed to create a dynamic array in javascript. I didn't want to have two complete arrays defined and choose based off an if statement. So to do this I used the push() command. It easily allowed me to tailor the contents of the array based on various boolean flags. The array I was creating was for the tools param of a new Ext.Panel object. As you can see in the sample code below, the publish button is only added to the tool array if the isShareable flag is true.

var tools = [];

tools.push({
id:'toggle',
handler: this.onToggle.createDelegate(this),
qtip: "toggle"
});
tools.push({
id:'help',
handler: this.onHelp.createDelegate(this),
qtip: "help"
});
tools.push({
id:'gear',
handler: this.onConfigure.createDelegate(this),
qtip: "configure"
});
tools.push({
id:'refresh',
handler: this.onRefresh.createDelegate(this),
qtip: "refresh"
});
if (this.isShareable) {
tools.push({
id:'save',
handler: this.onPublish.createDelegate(this),
qtip: "publish"
});
}
tools.push({
id:'close',
handler: this.onClose.createDelegate(this),
qtip: "close"
});

Monday, September 22, 2008

NoClassDefFound Exceptions tied to PermGen Space

Today I spent a good deal of time trying to figure out why I was getting a bunch of NoClassDefFoundErrors. The changes I made were not significant, but I did make one configuration change to JBoss. It seems the default is to compile the JSP pages with Java 1.4, so I changed it to 1.5, as a new JSP page used some Java 1.5 generics.

When I tried to bring the application back up, I got the following different errors each time I restarted JBoss.

javax.servlet.ServletException: java.lang.NoClassDefFoundError: org/eclipse/jdt/internal/compiler/problem/DefaultProblem

java.lang.NoClassDefFoundError: org/eclipse/jdt/internal/compiler/ast/Argument

NoClassDefFoundError: org/eclipse/jdt/internal/compiler/ast/SingleTypeReference

Finally, I got a PermGen space error.

A friend suggested increasing my PermGen memory in JBoss, which I did by adding the following line to the run.bat file in the JBoss bin directory:
set JAVA_OPTS=%JAVA_OPTS% -XX:PermSize=512m -XX:MaxPermSize=512m

This fixed the problem. So when having weird org/eclipse NoClassDefFoundErrors being thrown, try increasing your PermSize.

Thursday, September 4, 2008

Custom Events in ExtJS

I was kind of new to the idea of event driven applications, but after reading a little about it fell in love with it. I immediately had some applications in my work where it would solve particular problems I was having. Having never implemented this before, I didn't know where to start. Searching the ExtJS forum I uncovered some good information, but not enough to just jump right into it.

I thought I would blog about it while it was still fresh in my mind.

First you need to extend the Observable class for the class that you want to add a new custom event to. Then in a method called when the class is constructed, you need to add the new custom event. I needed to throw a custom event whenever the tab changed. As you can see from the code below, that a 'tabchange' event triggered a call to onTabChange function. This function then fires the 'myCustomEvent' event. That is all it takes to create a custom event. Of course, nothing will happen if there are not any listeners registered for that event.

Example.Events = function(config) {
this.initialize(config);
};
Ext.extend(Example.Events, Ext.util.Observable, {
initialize: function(config) {
this.addEvents('myCustomEvent');
this.panel = new Ext.TabPanel({
.....
};
this.panel.on('tabchange', this.onTabChange.createDelegate(this));

}
onTabChange : function(tabPanel, tab) {
var index = -1;
if (tab.getIndex) {
index = tab.getIndex();
}
this.fireEvent('myCustomEvent', index);
},
}

In my case, I had widgets that existed on tabs and they need to know when their tab was activated. So inside those widgets they needed to obtain a reference to the Example.Events object for our application, and then register as a listener and tell it which function to call back on. I did this in the widget constructor, as shown below.

in constructor:

var event= Example.Parent.getEvent();
event.on('myCustomEvent', this.tabSelected.createDelegate(this));
this.myTabIndex = event.getMyIndex();

The call back function:
tabSelected : function(index) {
if (index == myTabIndex) {
// Do something if your tab is activated
}
},


That's it. There is nothing more to it. And it works like a charm.

JavaScript handling of time zones

On the project I am currently working on, we had a problem to solve regarding time zones with our application. From the web interface the user was entering time for some of the fields. The time was being sent to the server and stored in a database. The problem we ran into was the client time zone was different than the server timezone. The database on the server was converting all times that were saved to the server time zone. When the data was retrieved, it was displaying the server time values and presenting it to the user as if it were client local time. Obviously we were not taking time zones into account.

Like most problems, there is usually more than one way to solve it. The way we solved it, was to make sure that all of the times that were being passed back and forth through the REST web service calls were in GMT (Zulu) time. The database can convert to local time, but before it is sent to the client, it is converted back to GMT. Likewise, in the browser, the user can enter time in local time, but before it is sent to the server it is converted to GMT time.

The rub came in finding the right java script date functions to allow for conversion to and from GMT. The GMT string representations that were being passed back and forth, needed converted to the clients local time. This was easily accomplished by using the java script Date constructor.

var localTimeZoneDate = new Date(gmtTimeZoneDateStr);

The date components the UI implemented, needed to be initialized with milliseconds from epoch time. To get that information we simply called Date.parse(localTimeZoneDate);

On the server it was equally easy to convert the value retrieved from the database to GMT.
String dateFormatStr = "EEE, dd MMM yyyy HH:mm:ss z";
SimpleDateFormat dateFormat = new SimpleDateFormat(dateFormatStr );
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
Date date = dateFormat.parse(timeStr);

In reviewing what we did, there may have been an easier solution. Both the Java Date object and the JavaScript Date object, are able to return milliseconds from epoch. It would have been much simpler to just send that value back and forth, and not worry about the string format.

Tuesday, April 29, 2008

How to add new events types to ExtJS components

I needed to be able to click on an Ext.Panel and have a window popup. The 'click' event is not a supported event for Ext.Panel. It turns out it is pretty easy to do in ExtJS. Almost every component has a getEl() method.

var myPanel = new Ext.Panel({
html: '<> Click Me < / h2>',
autoHeight: true
});

Once the panel has been rendered you simply, need to do the following.
var element = myPanel.getEl();
element.on('click', this.handleClick.createDelegate(this));

Now when ever a mouse clicks on the panel, the handleClick method will be called. The trick is that you have to wait until the panel has been rendered, to be able to add the event to it.

You may be tempted to use
myPanel.on({'click':this.handleClick.createDelegate(this), scope: this});

This method works great for events that the ExtJS Component supports by default, but doesn't work for other events.

How to add a keymap to an existing FormPanel in ExtJS

Recently I needed to add a key map to an existing FormPanel in our ExtJS project. This sounded like a simple thing to do and in the end the code was simple, but it wasn't obvious how to do it. So I thought I would try to save you the pain I went through to figure it out.

In the JavaScript, you might have something like the following.

this.myForm = new Ext.form.FormPanel({ ...your parameters....});
this.myWindow = new Ext.Window({ ...your parameters....
items: this.myForm,
buttons: [{
text: 'Save',
handler: this.onSave.createDelegate(this)
},{
text: 'Cancel',
handler: this.onCancel.createDelegate(this)
}]
});

Now how do you go back and add a KeyMap after the fact.

The panel has to be rendered before you can add the KeyMap to it. To do that simple call the following.

this.myWindow.show();
this.myWindow.doLayout();

Now you can create the KeyMap.
new Ext.KeyMap(this.myForm.body, [{
key: Ext.EventObject.ESC,
fn: this.onCancel.createDelegate(this),
scope: this
},{
key: Ext.EventObject.ENTER,
fn: this.onSave.createDelegate(this),
scope: this
}]);

Now, the user can either click the cancel button or hit 'esc' to cancel what he was doing and to save what he was doing he can either press the save button or press the 'enter' key on the keyboard. I hope you find this helpful.

Friday, April 25, 2008

Debugging JavaScript in IE

Firebug is so powerful and easy to use, I almost never need to debug JavaScript in IE. However, every once in a while I will come across a bug that only occurs in IE. A co-worker of mine told me about the best free IE JavaScript debugger he was aware of. It has been a real life saver at times. I thought I would share the information here so that you too can debug JavaScript in IE, if you must.

It does take a while to download and install the Mircosoft Visual Web Developer 2008 Express Edition, http://msdn.microsoft.com/vstudio/express/vwd/

This blog entry has steps on how to set up and use the tool the first time.
http://www.berniecode.com/blog/2007/03/08/how-to-debug-javascript-with-visual-web-developer-express/

There some special instructions in that blog for getting it to work, if IE is not your default browser.

Hope you find this helpful



Friday, April 11, 2008

Configuration Management: Bugs and Branches

Most software when the time comes to make a release will establish a branch. As the branch is tested bugs will be found that must be fixed. A very common dilemma is do we fix it on the main branch then merge the fix to the release branch, or do we fix it in the release branch and merge it back to the main branch. Either way, the changes must be in both locations.

This is a very old debate, and developers will usually be adamant about which side they support. I have been involved in projects that have practiced both methods. I would simply like to share my experiences from both sides.

Branch to Main:
Pros
  • One of the main rationals for this method is that the release is on a time line to get out. The fixes need to be put into the branch first to be able to maintain schedule and insure that the problems are fixed to support the customer.
  • Mainline code will continue to be enhanced for future releases so it will diverge from the branch code and the fix for the main branch may not be valid for the branch, so you should fix the branch first.
Cons
  • The biggest risk is that the fix never makes it back to the main branch so the next release you risk breaking the customer. Or even worse, an enhancement that was requested at the last minute by the customer, never makes it back to the main line.
Main to Branch:
Pros
  • It guarantees that the main branch always has all the fixes and enhancements, so that future releases are not at risk of missing critical bug fixes or minor customer enhancements.
Cons
  • It takes longer to update the branch with fixes, potentially causing a delay in the software release.
  • Risk that the fixes from the main branch don't get merged to the release branch.
  • The longer the branch lives the more difficult the merges to the branch become. You only want the bug fixes, not the new development.
Experiences:
My experiences have shown me that the testing involved on the release branch is much more rigorous than the testing on the main branch. No one wants the software to fail for the customer so must of the testing is focused on the release. Due to new development, the main branch is "broken" more frequently and while that is not desired, it is not entirely unexpected. It is more difficult to test reliably the main branch because the development my not be finished, and bugs would be written against code that wasn't ready to be tested. The release branch is usually much more stable with only critical defects being fixed, which makes it easier to test.

I have been involved in releases of software that went out to the customer only to have bugs reported back, that were fixed in a previous version and are broken again in the version they just received. Customers are not very understanding of this situation, especially on government contracts. They will call into question the processes you use, the reliability of your release process, even your ability to write bug free code. Some very uncomfortable meetings to have to go through.

One project I was on, the branch lived for a year and a half. The mainline code had diverged so much that bug fixes were completely different in both places. In fact we branched 3 times from the original branch without ever going back to the main. It was truly a nightmare to maintain. Which ever method you choose, the longer the branch lives, the more difficult the merges become, either direction.

There are pros and cons to both sides. From my experience, release branches should be short lived, and bug fixes should be merged in as quickly as possible after you branch. This negates a lot of the code divergence cons used as arguments for both sides. Due to the heavy testing on the release branch, it is not very likely that a required bug fix will be missed on the branch.

For the reasons stated above I am a proponent of fixing in the main branch then merging to the release branch. That said both methods can work. Going from the branch to the main requires a well defined process that everyone must follow to guarantee that changes are merged into main once they are verified on the branch.

Thursday, April 10, 2008

Getting Internationalization to work on Windows

Recently, I wasted several days trying to resolve an internationalization issue within our web application. Now I would like to share my experience and the solution I found in order to save others time.

Our web application has a requirement to support multiple languages, English and Hangul(Korean). Our application uses ExtJS for the front end and Jersey for the REST services, and we had difficulties getting i18n working in the javascript.

Initially all the Korean characters would appear as ??? in our ExtJS widgets. After some research we added a call to get the UTF-8 bytes, new String(bundle.getValue(key).getBytes(“UTF-8”)). and setting the content type charset to UTF-8 on the Jersey StringRepresentation. The issue with this approach was that certain Korean characters would appear in our ExtJS widgets as ?? and others would appear fine, so it was only a partial solution.

The solution ended up being pretty simple. Based on some information here, you basically have to set the default charset for the JVM to UTF-8. The default charset on Windows is windows-1252. To do this set the system property file.encoding=UTF-8 in the JVM, for JBoss you can do this by modifying the run.bat and adding -Dfile.encoding=UTF-8 to the JAVA_OPTS variable. Please note this is a Windows specific issue, since UTF-8 is the default charset for both Linux and Macs.

The following is the code before and after the changes to the JVM default charset , that will allow you to properly visualize Hangul(Korean) in your application.

The following displayed ?? for certain Korean characters.
ResourceBundle bundle = ResourceBundle.getBundle(bundleName, locale);

Enumeration keys = bundle.getKeys();

String key = keys.nextElement();

String value = bundle.getValue(key);
byte[] bytes = value.getBytes("UTF-8");
String newValue = new String(bytes);
StringRepresentation representaiton = new StringRepresentation(newValue);
representaiton.setLanguage("ko");
representaiton.setMediaType("text/plain; charset=UTF-8");
return representation;

After configuring the JVM to set the default charset to UTF-8
ResourceBundle bundle = ResourceBundle.getBundle(bundleName, locale);
Enumeration keys = bundle.getKeys();

String key = keys.nextElement();

String value = bundle.getValue(key);
StringRepresentation representaiton = new StringRepresentation(value);
representaiton.setLanguage("ko");

representaiton.setMediaType("text/plain; charset=UTF-8");

return representation;


For those that want some additional details as to why it wasn't working, read on.
bundle.getValue(key) always returns a UTF-8 String, even if the default charset is windows-1252.

The Jersey REST Service is returning a JSON StringRepresentation back to the client code. But the StringRepresentation class expects the string you construct it with to be in the default charset . Setting the media type on the StringRepresentation to "text/plain; charset=UTF-8" will cause it to try to convert the string it was provided from the default charset to UTF-8.

The first case it was trying to convert a UTF-8 String(thinking it was windows-1252) to a UTF-8 String. This produces all ?????? on the client for the Hangul(Korean) characters.

The second case, we get take the UTF-8 string returned from the bundle and convert it to an array of UTF-8 byte codes. We then take those byte codes and create a new windows-1252 string. The string representation class basically takes that windows-1252 string and converts it back to a UTF-8 string. So why didn't this work? Some byte codes can't be represented in windows-1252, specifically(129, 141, 143, 144, and 157). So any Korean characters that had one of those specific byte codes, would show up as a '?'.

The final solution, eliminates all the extra conversions. Bundle returns a UTF-8 string, StringRepresentation sees that the default charset is UTF-8, and it is sending UTF-8 so it doesn't need to convert anything and the result is the client correctly displays all the Korean characters.

In summary, just set the default charset on the JVM to UTF-8.

To find out what default charset your system is set to you can execute the following Java command:
System.out.println(java.nio.charset.Charset.defaultCharset().name());