8 Replies Latest reply: Nov 11, 2010 11:45 AM by Martin Frey RSS

JSF 2.0 and rendered attribute improvements

Arbi Sookazian Master

http://seamframework.org/Documentation/JSF21#H-RenderedIsRidiculousP2


This is a long and interesting wiki written up by DAllen that I just stumbled upon (how come you guys write these helpful articles and never seem to announce them in the forum - I found this months later????)  It's related to Seam because if you're using JSF 1.x with Seam, then you may be experiencing some performance degradation as a direct result of the getter methods (associated with the rendered attribute) in your backing beans being executed too many times during the JSF life cycle.


Here is the enhancement in JSF issues list: https://javaserverfaces.dev.java.net/issues/show_bug.cgi?id=1253 due to be fixed in JSF 2.0.


  • 1. Re: JSF 2.0 and rendered attribute improvements
    Jonathan Fields Novice

    I definitely agree that this needs to be fixed. I just spent about half a day trying to understand why a DB query was being executed TWICE. Using the rendered attribute was the culprit. I have a very simple CRUD search page using Seam EntityQuery. The rendered expressions which call EntityQuery.getResultList() (to see if it is empty, or not) are being evaluated in Apply Request Values, which fires the DB query. Then, during Invoke Application, EntityQuery.first() is being called, as a result of a button click, which refreshes the query. Finally in Render Response, EntityQuery.getResultList() is called again, and since first() was just called, fires the DB query a second time.


    One workaround I can see is using c:if instead of rendered. I don't like that, and am not even sure if it's completely safe to do.... The other possibility is to eliminate the use of dataTable, since one of the rendered attributes is determining whether there are any rows to display.


    I've read some fairly arrogant posts on other forums about how there's no problem with rendered being evaluated so much. They say bad application design and all that.


    To me, it's not so much the frequency, but when its called. Being called before Invoke Application is the issue to me, and doesn't make sense, since what's truly going to be rendered will likely depend upon the outcome of whats done in Invoke Application. (For example, an action in Invoke Application might update the DB which changes the values of the rendered expressions from Apply Request Values to Render Response.

  • 2. Re: JSF 2.0 and rendered attribute improvements
    Hui Onn Tan Newbie

    I encounter the exactly same problem today. To prevent calling EntityQuery.getResultList() before INVOKE APPLICATION phase, the workaround I use is to exclude datatable from server side processing with <a4j:region>


    However, this is not a good general solution. I wonder whether there is recommended way of providing consistent rendered expression in JSF 1.2. The expression should be re-evaluated during INVOKE APPLICATION phase.

  • 3. Re: JSF 2.0 and rendered attribute improvements
    Tim Evers Master

    Some of the reasons why it is evaluated multiple times were fairly valid reasons. Not necessarily good design but they at least had reasons.


    I was going to write a bit more but, I'm really no where near as experienced as a lot of people that have written fairly good explanations out there on the web already.


    JSF 2.0 will make a difference yes, but it's not going to be the silver bullet. If you are writing things where a getter goes back to the database after the original list call has been made or anything like that then your code is wrong. It can get out of sync and ultimately we should be writing code that goes off to the database as little as possible. Many small transactions is going to take a lot longer then grabbing your data up front.


    I say all this but I know there are special circumstances where this may not be applicable.


    Tan, your solution is much more complicated then you need to make it.
    Just don't put an EL expression in your JSF that causes that method to be called. A getter should not be the method to do the query. Your buttons (or events if you are using fancy ajaxy stuff :P) should fire off methods that do the query, or your initialisation into the page should do the query, not a getter. Keep your getters simple, it will be worth it later.

  • 4. Re: JSF 2.0 and rendered attribute improvements
    Hui Onn Tan Newbie

    Thanks for your advice. I fully agree with your opinion.
    However that is seam-gen design. I just customize my application from seam-gen template.


    I thought it was troublesome to change all ajax calls (sort, paging, search) to invoke the method that do database query, but it appears that it is easier than I think.



    it will be worth it later

    So true... Now, I can pre-process and post-process the result list easily (for multi-page selection).

  • 5. Re: JSF 2.0 and rendered attribute improvements
    Roger Mori Newbie

    Following this article's advice, I was trying to to count how many times the DB is efectively being hit by a query.


    Based on a view (list) generated by seam-gen, I found that the getResultList method is being called several times, but the query itself is performed only once per JSF request.


    Following the EntityQuery's source code, I placed a counter in an overriden version the method createQuery, which is the only stop in the chaing just before performing the query. 


    How can I replicate the above behavior?


    Please advise






  • 6. Re: JSF 2.0 and rendered attribute improvements
    Tim Evers Master

    Well, just look at where the createQuery method get's called from and you'll see how they do this.


    The way this is done is to check if the resultList or singleResult variables are null. If the are null then they query is created and executed. If they are not null then it just uses the value it has.


    So essentially, you can write all your getters to only query the DB if the result var is null. This is an OK solution but still not the best.


    First. You'll still execute the query many times if you are doing a singleResult query where it returns no values because the result will always be null. Thus the query will execute many times.


    Second. You have to make sure you null out these vars when you want the query to re execute. This doesn't sound bad, but it makes your code hard to read and follow. Because instead of making a call to a method like refreshResultsFromDB() you'll just go results = null; I mean you could put the results = null; line in a nicely named method but then you still are left with the problem of when exactly will the query get executed. What phase? Do I need the results before that? etc.


    Following on from my second point, I just want to say the reason why I like to keep my getters and setters simple. When writing code try to remember that you may not always be the one maintaining it. Ideally when someone else comes along and takes your place as the maintenance programmer they should be able to follow your code logically and work out how things happen and when. If getters contain logic then there is no way to follow the execution path of your app as you can never really be sure (without running the app) exactly what order things are happening. If you follow a nice pattern of an init() method when navigating to a page. a reset() method (if applicable) for a reset button. saveButtonClicked() method or appropriate action methods for other command buttons. And ensure that all db queries and logic are in these action or actionListener methods. This will make other developers love you when they have to come in and make changes :)

  • 7. Re: JSF 2.0 and rendered attribute improvements
    Roger Mori Newbie

    Tim:


    Thank you for your feedback.


    I have finished extending EntityQuery to trigger the query only if a parameter has been to true. As a result, the query hits the database only once per JSF request.


    package com.dpn.action.sf;
    import java.util.List;
    import org.jboss.seam.framework.EntityQuery;
    public class HerlindaQuery<E> extends EntityQuery<E> {
            private Boolean openFire;
    
            @Override
            public List<E> getResultList()
            {
               if (getOpenFire()) {
                    return super.getResultList();
               } else {
                    return null;
               }
            }
            
            @Override
            public E getSingleResult()
            {
                if (getOpenFire()) {
                     return super.getSingleResult();
                } else {
                     return null;
                }
            }
            
            @Override
            public Long getResultCount()
            {
              if (getOpenFire()) {
                   return super.getResultCount();
              } else {
                   return null;
              }
            }
         public Boolean getOpenFire() {
              return openFire == null ? false : openFire;
         }
         public void setOpenFire(Boolean openFire) {
              this.openFire = openFire;
         }
    }
    
    


  • 8. Re: JSF 2.0 and rendered attribute improvements
    Martin Frey Newbie

    Sorry to crosspost but i think what i did today for my issues with the rendered attribute seems like it applies for this here too:


    http://seamframework.org/Community/WhatAboutANewScopeType