Skip to main content

JSF Avatar vs. MS Atlas (Updated)

Posted by jhook on September 18, 2005 at 8:51 AM PDT

In my last blog entry, I 'kind of' complained about how JSF's component model was maintained and all the overhead involved. Really, I can't think of it as overhead, because it is tremendously richer in what it can do than other component frameworks.

With JSF, each component has control over each step in the request cycle. But this is only half true. When I started to look at ways to efficiently handle partial component tree requests, there really isn't any way for components to also have control over other component's lifecycles. Example, an autocomplete component that wants to be refreshed, but not require the rest of the tree to be processed.

Current Solutions

Currently, the JEE blueprints suggest alternate servlets or phaselisteners that deliver 'xml model' data back to the page over AJAX for further processing before rendering. MS's Atlas does the same kind of processing and the only thing I can say is, "Why??"

What if there was a way to simply 'refresh' components without requiring any translation or behavioral injection outside of the component itself? So JSF would be able to selectively update and re-draw the one autocomplete component instead of the whole tree. No phaselisteners, no alternate response renderers, no need to have knowledge of AJAX-- just redraw yourself. Sounds very swing-ish?

Black-box Components

Well, I originally started development on a solution under Facelets called, "Avatar" that would do this. But this ran into problems. As I stated before, JSF's components are so rich (that they are essentially black-boxes) and it's hard for a framework to externally dictate component processing (UIData for example). What JSF does right now is just walks the whole tree to allow each black-box component to do its thing. Again, this isn't very efficient for AJAX requests-- hence all of the solutions in JEE blueprints and online that require extra, unique cases.

In Practice

Anyways, back to 'Avatar'-- the idea is to carry JSF's event handling over into the concept of ProcessingContexts. A ProcessingContext acts as a pointer to a branch or leaf in the component tree and exposes the same processXXXX methods as the UIComponent has.

Just like events are gained and broadcast through the component tree, a ViewHandler could ask the component tree for one or more ProcessingContexts by client id. So take that autocomplete component's ID, pass it up in an AJAX request, ask the component tree for a ProcessingContext for that single ID and just operate on that one. So basically, Everything in JSF operates as normal, just that the Root Component (UIViewRoot) now only operates on these ProcessingContext pointers instead of the whole tree (by default, the whole tree though). The end result is that UIComponents are request-type agnostic, allowing everything in JSF to suddenly be 'AJAX' capable with only a few small API changes (UIComponent, UIComponentBase, UIViewRoot).

// custom viewhandler
List pcs = ...;
for(String clientId : clientIdList) {
  pcs.add(viewRoot.getProcessingContext(clientId);
}
CompositeProcessingContext cpc = new .... (pcs);
viewRoot.setProcessingContext(cpc);

// UIViewRoot
public void processDecodes(FacesContext faces) {
  this.processingContext.processDecodes(faces);
}

// AutoCompleteComponent
public void encodeBegin(FacesContext faces) {
  // no changes :-)
}

Because this processing is delegated within UIViewRoot, everything else in JSF stays intact. You could even have components or Actions add additional components to render during the lifecycle to say, "When action X is fired, re-render components A and B on the screen." Again, the best part is that components wouldn't need to know/care about AJAX and they should all be able to continue to work in this alternate processing method. The whole component tree is still there, referenceable, just that we are selectively processing events.

How to Get There?

More discussion would have to come up as to how we could standardize this secondary communication over AJAX, but this would could also work for things like XUL too! You could have a rich UI that is defined in a single page (or with Facelet templates) that never needs to be fully refreshed. Now the overhead from JSF's component model doesn't sound bad at all, and actually quite useful! I was wrong, JSF is [near] perfect :-)

I would like to get a mod-ed version of JSF 1.2 prototype working, but again, this requires an official spec enhancement-- how about it? JSF 1.2a for Avatar?

Updated!

I setup some initial unit tests for a medium sized page with lots of static text and a couple data tables, displaying 40 developers in two, separate spots. My example is automatically updating the DB when a single field in the column loses focus, so rendering one component back in the AJAX response. Some of my initial results where:

Full Request
Total Render Time: 12.51 ms
Total Output: 17 KB
Partial Request (Single Component)
Total Render Time: 0.17 ms
Total Output: 89 bytes

Now, was it fair for me to use such a large document? Nope, but it helps to emphasize my point! The same document was processed in both cases, but since we only wanted one part of it actually updated back to the client (or visa versa), there was a much smaller request to be processed under the SAME lifecycle. No special phaselisteners, or separate documents or servlets-- again, there's only one document being used with the same components as everyone uses from the JSF API (h:dataTable, h:inputText, h:panelGrid, etc).

In relation to Facelets, this isn't a Facelets specific solution. In my own tests, tree building requirements are nothing (<< 1 ms) compared to the rendering time. I don't see this cost being any different with JSF 1.2 and JSP 2.1.

Related Topics >>