Creator and AJAX: The Demo

I did a demo at JavaOne during Monday's keynote on Creator 2 and AJAX. Being a keynote demo, it was obviously stripped down to the bare minimum with a three minute timeslot. Therefore, I didn't have time to motivate the example, or build up the demo in gradual steps. But in three minutes, starting from an empty project and using no code clips, I built a web page that does a google-suggest like thing where as you're typing in a textfield, you get autocompletion on words from a 180,000 word dictionary. I've received a number of questions about it, and so have the people who were working in the Creator booth at the conference, so I'm hoping a blog entry will clear some things up.

First, let's talk about AJAX. One of my favorite uses of AJAX is providing auto completion in text fields. You've probably used address forms where the State or Country fields use dropdowns with 50 or more items. You typically KNOW which state or country you want to select, so being able to type three or four characters to limit your visible choices is a lot more usable than scrolling through large popups.

However, doing autocompletion smoothly as a partial page refresh (e.g. no page submission) is somewhat tricky. It takes lots of JavaScript plumbing to do that - and to get it working correctly on lots of browsers.

This is an ideal domain for a JSF component. The JSF component can encapsulate all the hard work in its renderer, meaning that your JSP files contain no JavaScript code whatsoever. You get the benefits of AJAX without its usual high development cost.

So let's jump right into it. One of the points that was made in the keynote, but people have confused in their JavaOne summaries that I've read, is that the AJAX component I demonstrated is not part of Creator 2; it's developed in open source on java.net. Thus, you can get all the source code for this and enhance the component (or create similar components) to your heart's desire.

In fact, it gets even better than that. There's a whole write-up on this component which explains exactly how it works. It comes with a working sample application - a JSF address form providing city completion for all 25,000 U.S. cities. And if you want a more generic overview on how to create JSF and AJAX components, check out this paper written by Greg Murray, Ed Burns and me, which covers some different approaches and trade-offs for this technology.

One of the things you'll find in there is code to wrap the component up as a Creator component library that you can import right into the IDE. Once you've downloaded it, you can install it by right clicking on a palette category, bringing up Manage Component Libraries..., select Import, and drill to the component library jar. Ok your way out. You should now find a new "Ajax Component Library" palette category at the bottom containing the completion text field.

(What, only one AJAX component? Yes, we'll add more components there. If you look at the blueprints page I pointed to earlier, you'll see several additional JSF components written by Greg Murray, Ed Burns, and more are on the way. These will be packaged up as Creator importable components as well.)

Now, drop the text field on the page. Then double click on it. Notice how it will warp to the source code and show you a new event handler. This event handler has already been bound to the text field when you double clicked on the text field. (If you study the JSP you'll see that it has a completionMethod attribute set to a method binding expression pointing to the method you're currently editing.)

Take a look at the screenshot. That's what it looks like in my editor - and what it looked like at JavaOne. But it's not what you're seeing in Creator 2 Early Access. Here you have a component-specific event handler, with properly named method parameters, and a default event body that gives you some suggestions for what to do. This was added right after Early Access froze so your bits don't include this functionality, but needless to say it will be in the shipping release. This will make it easier to write editor validation event handlers or even button action handlers too, since the default bodies will guide you in the right direction.

Study the trivial sample code in the comment:

    public void ajaxTextField1_complete(FacesContext context, String prefix, CompletionResult result) {
        // TODO: Return your own list of items here based on the prefix
        //result.addItem("Hello");
        //result.addItem(prefix.toUpperCase());
    }

If you simply uncomment the last two lines, and hit Run, you'll get an editor which contains two items in the popup: "Hello", and whatever the user has typed in the browser - but uppercased:

That's a big deal. Notice that we've written simple Java code which runs on the server, yet as the user is typing in the browser, results are dynamically shown without any kind of page submit. The user gets nearly instant feedback. All the plumbing is taken care of by the component. So while writing one of these components is tricky (see the documents referenced above), using an AJAX component is downright trivial.

Ok, I know what you're thinking. "What, every keystroke in every client's browser is hitting the server? You're crazy!!". I addressed this point in the AJAX full hour session at JavaOne. AJAX functionality does have a price. Your users are getting a better user experience. It doesn't come for free. You need to have good server resources to support this type of interaction. (I know a company which will sell you a good server! :-) Think of Google Suggest for example. Every time one of their users types a character\*, it hits their servers and returns a portion of their index. (Yes, I'm aware that if users are typing fast multiple keystrokes get coalesced into a single request). This is clearly not free - they're using additional servers to be able to handle this load. But to them, and perhaps to you, the added user benefit justifies the additional cost.

Anyway, back to the AJAX demo. The previous step (where I simply do a trivial computation to show server computation reflected in the browser) was eliminated from the keynote demo due to time constraints. I jumped right to the part where I do something more complicated on the server with the prefix we're getting from the user's text field. I call a web service, which returns a small set of words that start with the given prefix. Calling a web service is easy. First I have to import the web service (by pointing to the relevant WSDL file), then drag the web service onto the canvas (to get a local proxy object I can make calls on), and finally I change the autocompletion event method to simply call the web service to get a String array of words, and then I add those words to the completion result object. (It has an addItem(String[]) method as well). Thus, after dragging the dictionary web service onto the page (which gives me a local field dictionaryServiceClient1), I replace the code in the event body with:

    public void ajaxTextField1_complete(FacesContext context, String prefix, CompletionResult result) {
       try {
           String[] items = dictionaryServiceClient1.matchPrefix(prefix);
           result.addItems(items);
       } catch (Exception ex) {
           log("Error Description", ex);
       }
    }
The try/catch skeleton here came from me typing "trc ", and I just typed dict followed by Ctrl-K to type in the full name of the service client object.

During the keynote demo, I had a typo - I wrote

   result.addItems(result);
rather than the correct code above. When I hit Deploy the compiler rightly complained. Somebody asked afterwards if that was intentional, since having errors in my code has happened a couple of times during keynote demos in the past. For example during James Gosling's keynote last year:
In another coding process, Norbye skipped a step, which Gosling noticed. Norbye quipped, "It's really great to have your very own James Gosling to help you code," which drew a big audience laugh.
Let me assure you that the step last year was accidentally missed, not skipped, and again this year it was definitely not intentional. You try to code in front of ten thousand people and see if you can do it flawlessly :) I'm only glad the mistake was trivial and easy to spot. It sure would have been annoying if I hadn't been able to catch it before getting chased off the stage. I gave a full-hour Creator 2 demo at NetBeans day the day before JavaOne, and towards the end I was going to build a nice demo utilizing the new file upload component. But each time I tried to submit, the file upload component threw an exception. We spent 5-10 minutes debugging it with the audience's help but to no avail. Annoyingly, shortly after the demo, Craig McClanahan (who was in the audience, and also works on Creator) discovered that the problem had been that I was doing the demo on Internet Explorer (which neither Craig nor I normally use). I hadn't noticed that on the demo box I was using it was the default. And it turns out that there is a bug in the EA version of the upload component where it doesn't work correctly with IE in a couple of cases. Oh well.

Anyway. Back to the scheduled programming. With the above code change, and deployment, you run and get the screen shown below. As you type, dictionary completions from a dictionary of 180,000+ words are instantly updated:

In the AJAX session I also went on to hook it up so that there's a lookup button which looks up the definition for the selected word and displays it below. I'll leave that simple exercise to the reader (hint: it took less than a minute in the session demo.)

One of the things I wished I would have thought of before the keynote, is a better "sample word" to type to show the application working. I typed "Java", but it would have been a lot more fun if I had typed "Brazil" !! (For those who don't know, many keynote speakers make a point of mentioning the word "Brazil" in their speeches because it invariably draws cheer and applause from the Brazillian delegation, each and every time.)

So that's the spiel. At this point you may wonder where the dictionary web service came from. I had really wanted to motivate the AJAX example with the simple deployment step first, such that it gets the "look how easy" point across. The web service call makes everything more "magical", especially when it happens so quickly during a 3 minue demo - but it's important to understand that it's just a method call which returns some good matches for a string.

The web service was deployed locally. It was extremely easy to create. I did it in one evening - and that includes the learning curve, since I had never created a web service before. However, I found this tutorial which shows how trivial it is to build one with NetBeans 4.1. So I went on the internet, found a free dictionary file, wrote a small program to take all those html files, extract all the words and definitions from them, and then sorted those and wrote them into two files: and index file, and a definition file.

The web service is very trivial. It has an interface with two methods: a method for looking up the definition of a word, and a method for returning the 10 closest matches to a prefix. The second method simply does a binary search in the word index, but rather than returning the matched word or null it returns the index of the closest match, so that the web service can return the 10 closest words in the sorted word array. Trivial, eh? You can download the web service project yourself, as a .zip file. Unzip it and open it in NetBeans 4.1.

It might complain about a missing server. Use the Server Navigator in the Tools menu to point to your Creator App Server 8.1 installation; it's running on port 28080 with username admin and password adminadmin.

You can now first run the project to deploy it, and then register the web service by going to the Web Service node in the project manager, right click and select Add To Registry... (or something like that). It will show you the WSDL URL for the deployed web service. In my case it was

  http://localhost:28080/DictionaryService/DictionaryService?WSDL
In Creator, you now go to the Web Services node, select Add, point to the above WSDL file, hit OK, and you've imported the web service into your Server Navigator. (You can test it too - look at the context menus for the web service method nodes.) Now you can simply drag the web service onto pages to get a local client object like dictionaryServiceClient1 in the code above.

Hopefully the use of a web service doesn't confuse the AJAX component issue too much. One of the nice things about separating the dictionary code into a web service (rather than having it included locally) is that the dictionary is only deployed once, not each time you deploy your Creator project. Thus, the 10 megabyte dictionary file doesn't get reparsed each time you start the project. (It takes a couple of seconds the first time it's called to "warm up", e.g. read its dictionary list into memory) but once it's up and running there's no delay at all.

....and that's all I have to say about that...
F. Gump

Comments:

[Trackback] Writing javascript seems to be a scary prospect for a lot of folk. This is understandable given the tangled mess of code that can easily accumulate if you treat it as a toy language, and slap the code together in a hurry without thinking of an overall...

Posted by classical geek on July 11, 2005 at 10:23 PM PDT #

The AJAX components is rendered wrong in Safari on Mac OS 10.4. I dont know why, but the autocomp. box is shown a couple of cm below the textfield. It is rendered correctly in Firefox on Mac OS X :-) Creator 2 looks nice!

Posted by Niels Peter on July 24, 2005 at 06:41 AM PDT #

I really want to get this JSF/AJAX/Web Service example running... and I'm close. When I type in the text field, my NetBeans output window shows an error like: [#|2005-08-30T15:01:24.852-0500|WARNING|sun-appserver-pe8.1_02|com.sun.faces.el.impl.Coercions|_ThreadID=22;|Attempt to apply operator "-" to null value|#] [#|2005-08-30T15:01:24.902-0500|SEVERE|sun-appserver-pe8.1_02|javax.enterprise.system.container.web|_ThreadID=22;|WebModule[/ajax-auto-complete-w-web-service-1a]Error Description java.rmi.RemoteException: HTTP transport error: java.net.MalformedURLException: no protocol: REPLACE_WITH_ACTUAL_URL; nested exception is: I've posted my problem in detail on experts-exchange but haven't had any luck. http://www.experts-exchange.com/Programming/Programming_Languages/Java/Q_21544943.html Any ideas? Thank you. Greg

Posted by Greg Pintar on August 30, 2005 at 06:03 AM PDT #

Following the link for "Where is AJAX?!" in AjaxFaces Forum , you will find a brief introduction about creating Google-Suggest with AjaxFaces.

Posted by AjaxFaces on August 31, 2005 at 06:56 AM PDT #

Greg, sorry, I can't tell... One idea is to try some things individually first. Make sure that you can access the web service directly (not from within the separate ajax web app) - use the "Test" facility in the runtime tab once you've deployed the web service. The blog entry points to a simple tutorial for building a web service - try going through it, it's very fast - that might uncover some problem in the configuration of the tool or the app server or perhaps there's a necessary step somewhere you missed. Good luck!

Posted by Tor Norbye on August 31, 2005 at 02:57 PM PDT #

Somehow REPLACE_WITH_ACTUAL_URL is inserted by wscompile into wsdl and .java files. It should be replaced by actual web service location.

Posted by Michał on September 26, 2005 at 02:47 AM PDT #

Hai experts can anyone guide me in creating a ajax enabled tabbed pane(apache,myfaces-tomahak component) in my jsfcomponent.Help needed...

Posted by Aniesh on September 26, 2005 at 07:59 PM PDT #

Nice blog and nice script!

Posted by Rick.M on October 22, 2005 at 08:38 AM PDT #

Note that this has been turned into a tutorial now: http://developers.sun.com/prodtech/javatools/jscreator/ea/jsc2/learning/tutorials/textcompletion.html.

The tutorial includes a simple .war to deploy for the web service, which should help those of you who had trouble getting the NetBeans web project I had included above to deploy correctly.

Posted by Tor Norbye on November 03, 2005 at 02:35 PM PST #

Hi, the demo and code is great, thanks. Does anyone know if it is possible to link the results of one Ajax completion field with another. If you try to access the value of the ajax text component in the 'complete' method of another ajax text component using .getText() then the returned value is null. Also, I can't get the component to call a method on the server when selecting an item from the dropdown. Keypresses are handled, but selecting from the dropdown is not. 24 hrs and still stuck. Please help.

Posted by Jacobus on December 02, 2005 at 06:54 AM PST #

I want to include an open source ajax library into my creator project that will put a dhtml text editor on my jsf page. I am experimenting with tinymce_2_0_2 http://tinymce.moxiecode.com/. I saw a tutorial on how to use component libraries in creator (http://developers.sun.com/prodtech/javatools/jscreator/learning/tutorials/2/textcompletion.html). How do I make my own component libraries to import into creator 2?

Posted by Peter Boivin on February 02, 2006 at 11:11 PM PST #

Hi, very powerful stuff. I'm new to Creator, and interested in more complex applications of the Ajax JSF components. For example, how would I redirect the results of the auto-complete component to a table component, tree, or other basic component on the same page? Would I have to write a specialized component? Is there any info on how to write "new" Ajax JSF components?

Posted by Mark Koch on February 03, 2006 at 06:17 AM PST #

Peter, to find out more about complibs etc. see this: http://wiki.java.net/bin/view/Javatools/CustomComponentLibraries

Mark, to find out more about this go look at the writeup over on the bpcatalog regarding this component. In particular, the sample application I've placed around the auto completion component there shows you how the result from the auto completion can be used to populate other fields too (in that case, picking a city from an autocompletion text field also populates the state and zip fields.)

Posted by Tor Norbye on February 03, 2006 at 07:25 AM PST #

Hi I am Naresh Cheedella.I am a software Enginner in Codec Communications Pvt Ltd Pune. I am very much exciting with the uess of Ajax. Thank U Very Much..........................

Posted by Naresh on March 23, 2006 at 03:27 PM PST #

Tor this is a great post. Just did a netbean AJAX screencast. I have built a custom JSF AJAX combobox component using the JSF phaselistener. The component I built also improves address entry. http://blogs.ebusiness-apps.com/godfrey/?p=15 Screencast: http://labs.ebusiness-apps.com/download/NetBeansJSFComboBoxDemo/NetBeansJSFComboBoxDemo.html If you have any advice please let me know. Cheers, Godfrey Hobbs

Posted by godfrey on May 05, 2006 at 03:55 AM PDT #

Post a Comment:
Comments are closed for this entry.
About

Tor Norbye

Search

Archives
« July 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
       
Today