Monday, December 18, 2006

How to consume UrbanDictionary service with Java Script

From my last entry, I had wrote that my instructor assign a project on mashing-up three web services together. Today I had to help my friend who need to consume a service from UrbanDictionary, a slang dictionary, using SOAP and JavaScript.

Actually there is an example of how to consume a service with JavaScript on their website too. However, it is still hard for a complete JavaScript newbies to understand and use.

So I had to code the skeleton part for my friend. Here is the code

function lookup(key, word) {
req = new XMLHttpRequest();
req.open("POST", "http://api.urbandictionary.com/soap", true);
req.onreadystatechange = function() {
if (req.readyState == 4) {
var results = req.responseXML.getElementsByTagName("item");
var len = results.length;
var resp = "";
for(var i = 0 ; i < len ; i++)
{
var item = results[i];
for(var j = 0 ; j < item.childNodes.length ; j++)
{
var node = item.childNodes[j];
resp+="<br />";
if(node.nodeName == "word")
resp+= "คำว่า : " + node.firstChild.data;
else if(node.nodeName == "definition")
resp+= "คำจำกัดความ : " + node.firstChild.data;
else if(node.nodeName == "author")
resp += "ผู้แต่ง : " + node.firstChild.data;
else if(node.nodeName == "url")
resp += "URL : " + node.firstChild.data;


}
resp += "<hr />";
}
spanResp.innerHTML = resp;
}
}

var post = '<?xml version="1.0" encoding="UTF-8"?>' +
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' +
'<soapenv:Body>' +
'<ns1:lookup soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="urn:UrbanSearch">' +
'<key xsi:type="xsd:string">' + escape(key) + '</key>' +
'<term xsi:type="xsd:string">' + escape(word) + '</term>' +
'</ns1:lookup>' +
'</soapenv:Body>' +
'</soapenv:Envelope>';

req.setRequestHeader('Content-Type', 'text/xml');
req.send(post);
}

function doLookUp()
{
var oTxt = document.getElementById('txtWord');
lookup('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', oTxt.value);
}

You have to replace "xxxxxxxxxxxxxx" with your UrbanDictionary passkey to get this code working.

One of the problem I encountered during coding this example is the "getElementsByTagName" method. I first use the "getElementByTagName" (no 's' in 'Element') method which does not exist. It takes me a while to figure this out.

Thursday, December 14, 2006

Windows username problem

Today, I have to install Netbeans 5.5, a very popular IDE for Java, on my friend's notebook. At first, the installer said that there is no JDK on this computer. So we find another Netbeans installer pack which included JDK 6. But the situation is almost the same. The installer asked to locate the "java.exe" file but after I select the correct file it said file is corrupted.

We try restarting Windows, reinstalling the JDK, but none of them worked. After a while, I noticed that my friend's Windows user name is a little weird (It contain "@" and "!"). So I try create a new Windows user account. And try install Netbeans again from there. Bang! It worked!

I realized that this is not the first time I experienced this problem. So, do not name your next Windows account with those weird characters :)

Wednesday, December 13, 2006

Handling exceptions in asynchronous web service call in Visual Studio 2005


I had just finish developing my application for ISO (Information System Organization - one of the subject teached at my university). The requirements are to consume 3 of the services available at http://www.programmableweb.com/matrix and the students can develop their applications for any available platforms. I choose to develop my project, MashOpedia, on the .NET Framework 2.0 using Visual C# Express Edition as my IDE.

Consuming web services with Visual Studio is sure an easy job for those services which provide WSDLs. In Visual Studio .NET 2003, any method exposed from a generated proxy classes have their asynchronous versions whose names are "BeginXXX" and "EndXXX" where "XXX" is original method's name. These methods allow the developers to call web services in asynchronous style easily!

However, when you generated a proxy classes with Visual Studio 2005 there are no these "BeginXXX" and "EndXXX" methods anymore. You will find "XXXAsync" method and "XXXCompleted"event instead. These provide an easier way to invoke a web service in asynchronous style. You first call "XXXAsync" and when the call is completed it will raise "XXXCompleted" event.

I had used the "XXXAsync" method to call web serice in my project. But one problem arises. How do I handle those exceptions generated in another thread ?. In Visual Studio .NET 2003 I can wrap the try..catch block over the "EndXXX" method call. Any exception, such as SocketException caused by internet connectivity problem, would be caught by this block.

But in Visual Studio 2005,


void serv_doGoogleSearchCompleted(object sender, doGoogleSearchCompletedEventArgs e)
{
if (e.Error != null)
MessageBox.Show(e.Error.Message);
...
}

I can detect if there is an error occurred in asynchronous call but I could not handle it. When I intentionally unplug my LAN connection. The program stop working and push me back to the IDE with the mysterious "TargetInvocationException" at line "Application.Run(...)". I dont know how should I handle such case. I try wrap the try..catch block around "Application.Run(...)" too. That works but the form instantly close itself after the exception is catched which is not what I want.

One workaround I used to solve this problem is to wrap a synchronous call within the BackgroundWorker. This allows me to call the web service in asynchronous style (The GUI is not freezed) and allows me to handle exceptions raise by the call too.

private void backgroundSearch_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = null;
try
{
GoogleSearchService googleSearch = new GoogleSearchService();
GoogleSearchResult googleRes = googleSearch.doGoogleSearch(ApplicationSettings.GoogleLicenseKey,
txtKeywords.Text, 0, 10, true, "", false, "", "", "");
...
}
catch (Exception ex)
{
e.Result = ex;
}

}

private void backgroundSearch_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Result == null)
{
/* Means operation completed successfully */
...
}
else
{
/* Failed */
...
}

If there is more simple way to solve this problem, feel free to tell me :)

Sunday, December 10, 2006

Running Java SE Application in Windows Vista


Running Java SE Application in Windows Vista with Aero will cause Windows to automatically change its theme to Vista Basic (without Aero). This is really annoying especially when debugging Java application in the IDE.

A workaround to this problem is to install Java Runtime Environment (JRE) 6 Release Candidate (download page). Java applications (made with JFrame) would support Aero after JRE 6.0 RC is installed.

Just installed Windows Vista RC1



Just installed Windows Vista RC1.