The Source for Java Technology Collaboration
User: Password:



Jacob Hookom

Jacob Hookom's Blog

JSF Avatar vs. MS Atlas (Updated)

Posted by jhook on September 18, 2005 at 08:51 AM | Comments (14)

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.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Hmm, Avatar sounds useful... Good going!

    Posted by: tobega on September 20, 2005 at 04:21 AM

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

    Adam had the same reaction. The answer is simple, and it's not a
    technical one. We had a requirement to craft a solution that ran on an
    existing, unchanged, JSF 1.1 installation.

    This seems like a great idea to revolutionize and simplify how AJAX is
    done with JSF. Perhaps we can get it into 1.2, but we'll see what the
    EG says.

    Ed (JSR-252 spec co-lead)

    Posted by: edburns on October 05, 2005 at 08:07 AM

  • That's really good word, Jacob. I saw your post in MyFaces discussion list, and it really interested me because of the performance, and it's the logical thing in a component base framework like JSF. When will you post something like a demo or a working example with Avatar implemented?
    Can't wait this ;)

    Posted by: rafanami on October 07, 2005 at 10:42 AM

  • We cannot change the contract of what a ViewHandler has to do since that
    would break existing custom ViewHandlers. Therefore, I want to
    encapsulate the discovery of which ProcessingContexts to use on this
    request entirely inside the UIViewRoot, or its delegate. Now, since JSF
    keeps the rendering technology separate from components, components
    don't know how to pull things from the request parameter set.

    PROPOSAL

    Part 1: new renderer for UIViewRoot

    To solve this, let's add a new renderer to the standard HTML renderkit

    component-family

    javax.faces.ViewRoot

    renderer-type

    javax.faces.ViewRoot

    This is the renderer for the UIViewRoot.

    Encode behavior:

    None. No encode behavior.

    Decode beavior:

    Look at the UIViewRoot's ProcessingContext property. If it is
    non-null, return immediately. Otherwise, continue.

    Look in the request parameter set for the processing contexts to be
    use for this request. Create a new CompositeProcessingContext and
    populate with a ProcessingContext for each pc found in the request
    parameter set. If none are found, create a ProcessingContext that
    points to the UIViewRoot itself. Set the CompositeProcessingContext
    into the UIViewRoot.

    Part 2: changes to UIViewRoot

    In addition to having a renderer where it didn't before, UIViewRoot
    needs some other changes.

    We add a read/write JavaBeans property of type ProcessingContext. This
    property is transient and does not participate in state
    saving/restoring.

    To bootstrap the processing context we need to modify our overridden
    processDecodes(). After we notify our beforePhaseListener() we call
    super.decode(). This looks up the renderer, and calls its decode(),
    which behaves as above. When super.decode() returns, we know our
    ProcessingContext property has been initialized. Assert that it is
    non-null. We then proceed with our existing processDecodes
    implementation().

    override the getFacetsAndChildren() method such that it leverages the
    ProcessingContext to find the UIComponent sub-roots for the processing
    contexts found in the incoming request.

    This is just sketchy, but I think it's a start.

    Ed (JSR-252 co-spec-lead)

    Posted by: edburns on October 07, 2005 at 07:36 PM

  • That's a great idea! A framework could provide their own UIViewRoot/Behavior in combination with other API helpers to refresh different parts of the tree in later phases, such is in the invokeAction? I like the idea of invoking an action and just allow the action to say, "refresh the left column".

    Posted by: jhook on October 07, 2005 at 07:48 PM

  • a good start point for ajax support.

    web2.0 developer also need access to ejb in a firefox extension using js, so a javascript api open door to a wider world.

    Posted by: gnualber on November 14, 2005 at 04:24 AM

  • I have realised same idea 5 month ago. Worked sampe still at http://smirnov.org.ru/myfaces-ajax/ajax.jsf , code repository can be found at http://sourceforge.net/projects/telamon .
    Best realisation will be create subclass for UIVewRoot, but, since Sun RI directly instantiate UIViewRoot class ( xmm.. MyFaces create it by Application.createComponent ), I add my own UIAjaxView component.
    Some descriptions ( outdated ) You can see at http://smirnov.org.ru/en/ajax-jsf.html .

    Posted by: alexsmirnov on December 04, 2005 at 11:27 AM

  • Alexander-- actually it's a bit different than what you are talking about. I've looked at your proposal, along with similar ones that groups like IceFaces proposed last year, and what I'm trying to push with JSF is a whole different way of looking at View Management-- not just a solution for AJAX. To provide a clear example of this, Galen Dunkelberger took the time to implement a good majority of Ed's suggestion on this blog and, seriously, it's only about 4 new classes. This elegant simplicity is what will work for JSF long term as part of the spec, not a whole separate series of components and handlers-- you should theoretically be able to use everything you did before without modification or re-specifying the form controls.

    Posted by: jhook on December 04, 2005 at 11:35 AM

  • I've got the basics of the server side of this implemented on JSF 1.2. Details at http://blogs.sun.com/roller/page/edburns?entry=basic_jsf_avatar_server_side

    Ed (JSF Co-Spec Lead)

    Posted by: edburns on December 08, 2005 at 09:26 AM

  • I've got the basics of the server side of this implemented on JSF 1.2. Details at
    my sun.com blog.

    Ed Burns (JSF Co-Spec-Lead)

    Posted by: edburns on December 08, 2005 at 09:28 AM

  • This is great benefit for future development efforts. Has anyone done something similar to this in a 1.1 implementation environment though. I'm thinking that this would be perfect to access child components in UIData components for gathering up validation error details, something I'm trying to do on a 1.1_01RI project.

    Posted by: smccoole on March 10, 2006 at 01:30 PM

  • MyFaces folks have implemented a partial solution for the Tomahawk data table. In my later blogs, I describe a recent JSF 1.2 feature that accomodates the things described w/ Avatar.

    Posted by: jhook on March 10, 2006 at 01:51 PM

  • Sorry for my english!
    I am happy to see that jsf is looking for a transparent way to support ajax and partial rendering.
    Anyway is this really possible in every situation?
    For example my page has a form component, and inside it only a div component.

    Now in some ajax request I want to update div component, adding a commandLink or a commandButton inside it.
    If I render only the div component I will have the new commandLink in my html, but what about some input hidden field necessary to make the link work? MyFaces form component, for example, add the hidden input file useful for the button or link only if some of these component is present, inside it.
    So the solution here is to render also the form. But this is not a really transparent solution, and if the form has a lot of components inside it , we loose the advantage of partial rendering.

    Posted by: ivankov on March 12, 2006 at 05:30 AM

  • Looking good. One question/comment though, would this involve partial page navigation?

    One "limitation" I am facing with facelets and AJAX partial page rendering is the lack of support for the navigation handler. Instead of the navigation handler always creating a new view, it could create a new sub-view. This would allow for wizards, DIV-style implementation of dialogs to leverage the full abstraction framework of JSF navigation while being contained in an external constant view.

    So in a portal-esk style of development, I can child views that post back and refresh leaving the rest of the page unchanged.

    Also somehow getting around the JSF server state would be great too. If each "subview" had its own state that would be ideal as well (when I mean state here, I don't mean the bloated state we find in JSF, but a subset - like keeping expanded nodes of a tree for example - although one could definately argue for this being stored in managed beans).

    Also, a note, that it is also important to make sure the form is the entire page, not a sub-view. This way different child windows can receive data from other child windows. The difference would be that not all child windows would necessarily be refreshed.

    Too many worms for a Friday... Will be interesting to see where this goes.

    Posted by: arobinson74 on April 07, 2006 at 06:23 PM





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds