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).
10 comments:
Really interesting comments and good article Andrew. One thing I just want to point out though...ICEfaces doesn't recreate the component tree on every AJAX request. It uses a modified JSF lifecyle for asynchronous updates, which bypasses recreating the tree. This gives you fairly instantaneous updates, like you see with Seam Remoting, and is fairly lightweight after the initial page creation.
Full disclosure: I work for ICEsoft.
Thanks,
Philip
Philip, thanks for the feedback and the correction. I have looked at bit into ICEFaces, and was quite happy with the solution. My problem (and my company's) was simply that it (the direct-to-DOM rendering style) isn't the way Sun was targeting AJAX support which made us hesitate. Since it is much different and not universal, 3rd party components would not benefit as much from the ICEFaces code and it is unfortunate that in such a space, companies don't tend to grow from one another unless one becomes the standard.
I'm just hoping in the holding out for "Sun's solution" that a good offering is made and not like the JDK logging APIs which fell flat on their faces compared to Log4J.
Hopefully your company's good work can influence the future of JSF.
Well, as a newbie, I would say that JSF doesn't seem to be made for AJAX at all. There doesn't seem to be any easy way to make it work with JSF. There are several frameworks out there and none are mature enough to offer a reliable solution. As soon as you plugin one thing, something else stops working. Both JSF and AJAX with JSF seem incredibly immature and difficult for a technology more than 2 years old (JSF).
To have AJAX support in JSF, it would be extremely useful to have some kind of functionality that does the following:
A JSF component can be set to another value on the server-side by calling a function of javascript from the client side. Then it is marked 'dirty' and automatically reloads. All the HTML for the new value is automatically generated, like it is generated the first time the component is loaded. No need for custom components that are AJAX-enabled.
Well, it's just a fantasy for AJAX-ability in JSF. I don't know how practical.
Every advanced technology has its own development paradigm. If you follow this paradigm you get its powers. Otherwise, you just will get its troubles.
JSF is a component-oriented technology. JSP is a page-oriented technology. To use JSF as "another syntax" on the top of JSP is the same that to use a microscope to hammer nails.
GWT is a technology that is good for one-page mashup rich applications. I have no idea why are you looking there for the navigation. Probably, you want to pull one paradigm on the technology that has another.
I disagree with Aneesha. JSF seems to be made for Ajax. Otherwise, I have no rational explanation why we were able to add Ajax on the top of JSF without changing the JSF's paradigm even a little bit and without single line of code modified in the JSF implementation itself.
There is big difference between "restoring" the tree and "decoding/processing" of user input.
Typical scenario usually include sending asynchronous request (with some user input), decoding, processing, re-rendering of sub-set (or many sub-sets), sending back result or rendering and applying changes on the client side.
In Ajax4jaf you have full control of what part(s) of the page will be decoded/processed and re-rendered/updated. That can be achieved by a combination of special a4j:region and a4j:outputPanel components and (or) some attributes on regular components, like "ajaxSingle", "ajaxRendered", "selfRendered" etc. Using that features you can minimize impact of "decoding/processing" to absolute necessity level.
Tree restoration itself is pure serialization/de-serialization operation and has relatively low impact to the final performance. It has nothing to do with EL expression evaluation, model interaction etc.
Hi Igor, I have already tried using ajax4jsf. But some of the components I was using stopped working as soon as ajax4jsf was plugged in. I could not get any support on the mailing list. The only choice was to remove it and move on. So far, the development has been plain JSF.
That is where the "maturity" comment arises from.
Hi,
I have not worked with ASP.NET. A few colleagues of mine have and they say it was far less problematic compared to JSF (MyFaces 1.1.x/Facelets).
Could you please write a post comparing JSF to ASP.NET and explain why do you prefer JSF to ASP.NET?
Frankly, so far, to me, the JSF experience has been frustrating. I think one reason is that I started working with JSF on real-world projects before understanding and studying JSF enough. So I have devoted the next year exclusively to JSF.
With best wishes
Sorry for the late reply, I've been hesitant to reply about ASP.NET as it has been over a year since using it and it wasn't my primary role (I was doing more Windows Forms over Web Forms). So I can't guarantee that this information is (still) correct.
With that disclaimer, let me talk about what I remember. ASP.NET is simplistic, like most Microsoft code which means that it is very easy and powerful as a basic developer and when you are learning it. And just like VB, it hits a ceiling very fast. It lacks a lot of the power that JSF comes delivered with out of the box.
My top 10 reasons not to use ASP.NET:
1) Post values aren't bound to the back-end. Unlike JSF, ASP.NET requires that you, by hand take the values from the UI and push them into your data bean values. JSF's EL binding works out of the box
2) There is no bind to a list of objects functionality (especially in .NET 1.1). You have to create a DataSet and bind that dataset to a table. .NET 2.0 introduced an object data provider but when I looked at it, it was a lot more cumbersome, less powerful and harder to use than the JSF data table
3) I don't recall any built in validation and conversion framework like that of JSF.
4) There was no acceptable templating technologies like facelets.
5) All third party providers are non-free, JSF has a large open source following (crucial if your company is stingy/frugal)
6) There is no active community for getting questions asked. The facelets and MyFaces user mailing lists are excellent.
7) It only runs on Windows (don't even mention Mono, it is behind the times and very unstable -- no where near production quality)
8) It caters to IE6, good luck in getting it to work well in firefox, opera and safari. You can (I have) get it to use the "advanced" browser rendering settings, but it requires some effort and some research and even then, since ASP.NET controls are written by MS, they don't try to make them W3C compatible, only IE compatible.
9) The debugger in VisualStudio 2003 was junk (often couldn't display values of variables) and I found VisualStudio 2005 unstable and extremely RAM intensive with big memory leak problems (and I am comparing it to Eclipse which has similar issues)
10) Its written by Microsoft -- need I say more?
Hi!
I have not worked with JSF (well I am starting to work with it) (only with ASP.NET), but I would like some clarifications
on the ASP.NET / JSF Comparison:
1) Completely agree.
2) Agree with 1.1, but I don't think the ObjectDatasource is equivalent to JSF datatable (the ObjectDataSource is a datasource "design time only" component, the GridView would be the component to compare with)
3) There are some validator controls in ASP.NET, but not exactly a framework
4) Agreed
5) but there is http://ajax.asp.net/, I have been looking for something like that for JSF (specially the update panel control, but I couldn't find anything)
6)http://forums.asp.net/default.aspx?GroupID=34
7)I agree
8)I agree
9) I haven't had any problems with the debugger (when debugging C# code... but debugging JScript code is problematic)
10) I don't believe that necessarily means it has to be bad... (of course sometimes is... but I think this is not the case)
Post a Comment