Saturday, November 18, 2006

Is JSF made for AJAX or does it just "play along"?

My blog has moved, please update your links. You can find this article here

Before I begin, this post is meant as a discussion point, not a flame war. I decided to publish this as a blog instead of an email on one of the JSF mailing lists so that I could get comments and feedback from others.

I have been using JSF for almost two years now, one year as my full time job. It is by far, better than any other server side framework that I have used (C CGI, Perl CGI, PHP, ASP, ASP.NET, JSP and servlets)

Background

With this in mind, it doesn't mean there aren't issue in the JSF space. One of which is it's compatibility with AJAX. Several competitors are available to use AJAX with JSF:

  • AjaxAnywhere
  • Ajax4Jsf
  • G4Jsf
  • Trinidad
  • jsf-extensions/Avatar
  • ICEFaces
  • JBoss-Seam (in the works)
  • etc.

Each of them handle AJAX in their own way unfortunately for the learning user. The one large problem with them, is that they are all on top of JSF. Before you post your comment, here me out. JSF is a "hack" to bring a new technology on top of JSP. It was developed when Sun and Java developers realized that JSP was not succeeding and had fundemental flaws in the design that made ASP.NET, RoR and other languages more appealing. Many went the way of Struts with Java to gain so of that functionality. The problem with struts is that it never provided a good component framework.

The reason that JSF is a "hack" is that it is built from JSP pages. Although nice to those wishing to convert their projects from plain JSP to JSF with a JSP view handler, the combination is useless for large business applications. "The reason for this?" you ask, well it is the component tree. The single worst design of JSF is the saved component state of the UIViewRoot object. The component tree is made to be built once and then saved on the client or in the user's HttpSession object. This is more than just a serialized set of objects. It has methods for saving state and restoring state that custom components may override. Every time a view is restored, then entire component tree must be recursed and each of these methods are invoked. All the EL expressions (a.k.a. value bindings), component properties, attributes, etc. are all serialized into this component state. The overhead is gigantic.

To illustrate this point, let me bring up my companies application. It is just that an application, having dockabe frames, complex dialog box, complex layouts, etc. It actually makes Gmail and Google calendar look simplistic. Now I am not trying to pat myself or my company on the back, but let you know of the complexity of each view. There are hundreds if not thousands of components in this component tree. Each time I POST back to the view, the time it takes to restore this component tree is getting slower and slower as we add more functionality.

Luckily we use Facelets for our view handler not JSP (which I would never recommend as a long term solution). JSP should be though of only as a stepping stone until you convert your legacy application from JSP to JSF. Once you are completely in JSF, use facelets. It is the only way to achieve adequate performance for anything besides a Hello World application.

Enter AJAX

We are using AjaxAnywhere right now. It is very stable in 1.1.0.6 and does the job nicely. If I were to do it all again, I would probably use Ajax4Jsf due to its tight integration with JSF and the fact that it is the closest in design to Avatar (the future of AJAX in JSF from Sun).

The problem

For each AJAX request, the "JSF integrated" technologies must post back to JSF. They then execute the standard JSF lifecycle. This includes the restoring of the component tree. Yes, this is the single worst part of JSF for AJAX. If I simply want to update 2 components on the page, I have to restore the entire tree, counting possibly into the 1000s of components. Sound like a bottleneck? It is!

I can witness this problem when I use JBoss-Seam remoting. Remoting is independent of JSF and therefore does not restore the component tree or the view. I have extended it in my use to integrate with the FacesContext so that I can access & update my backing beans as well. The performance? -- instant. That is right, it doesn't even appear to go back to the server it is so fast. The difference between this and the page POST of AjaxAnywhere back to JSF is huge. Unfortunately, using Java methods on the server to generate HTML feels like the days of pre-JSP servlet development, so while it is good for sending & getting data, it is not a good fit for generating HTML (unless you love JavaScript and you build the entire page via document.createElement() calls -- see my discussion on GWT below).

What can be done? Well many of these technologies "hack and slash" their way into the JSF APIs to try to speed performance. They skip phases such as validation, updating of the model, etc. for components that do not need to change, but the component tree is still always restored. The one solution is that the component tree must go! That is right, in order for JSF to have adequate performance the JSF specifications must be completely changed to mostly remove the component tree. If I want to update 2 components using AJAX, only those two components should be reloaded from the view, no more. This is problematic as the API is not built for this.

Jacob Hookom has had some really good insights on this issue:

Is the grass greener?

I was looking at GWT the other day as it came up when I was looking for some good JavaScript libraries for layouts. In doing so, I started to read more and more, liking it quite a bit. Wondering if this is better for business applications than JSF, I found G4Jsf, an attempt at integration of JSF and GWT. The problem is that I could not find any documentation and the demo is extremely simplistic (no forms, no validation or updating of the JSF model, no JSF navigation, and almost no Views, just GWT code). I will be quite anxious to see where this project goes.

From what I understand in my initial look, GWT is interesting in that it stores the component state in the DOM of the browser using HTML + JavaScript. This means that when calls are made to the server, there is no component tree to update, no view to restore. The client is almost a thick client (and almost getting the performance of one). It's "magic" is to convert Java code into JavaScript, hiding the complexity of writing JavaScript DOM manipulation code by hand.

On the other hand GWT doesn't look like a good tool to create web pages though. There is no HTML for developers, only Java code. WYSIWYG is next to impossible from what I see for complex applications. The ease of using the JSF view and the Facelets templates, just doesn't seem to be there.

What Now?

As I mentioned, the whole point of this blog is simply to start a discussion. I would love to hear what the JSF experts have to say and if they know if future releases beyond 1.2 will start to address these issues (I even wonder if 1.2 will ever take off as ppl. aren't even fully embracing 1.1 yet).

Is there something I missed with these JSF AJAX libraries to get around the component tree performance issue?

Please keep the comments to Java based technologies as they apply to JSF, this is not meant to be language war.

Update: 2007-04-22

Since I created this post, I have had the opportunity to convert my company's software over from AjaxAnywhere to Ajax4Jsf and I wanted to report my findings so far. After some initial issues on converting some very large (and nested) templates over and converting some complex in-house components to A4J, we are now running on A4J with only some minor patching.

Even with a very large component tree, I am seeing ~300-600ms per AJAX request (calculated using FireBug in Firefox). I am using ajaxSingle="true", limitToList="true" and a4j:region tags where possible to enhance performance (it make a significant performance impact). With time permitting, I think I can get performance better by working on our in-house JavaScript code that runs per-AJAX request that is part of the issue.

So even though JSF needs some large improvements to the specification to make AJAX fit better, the performance is definitely dependent on the AJAX tools used. Hopefully we see JSF more stream-lined and less JSP dependent (or hopefully completely separate from JSP) in JSF 2.0 with some improvements to component creation and state saving (letting the view handler take more of the burden on and less on the component develeper).