8 Replies Latest reply: Jun 19, 2009 10:54 PM by Jean Luc RSS

too many Seam component executions from JSF

Arbi Sookazian Master

This is a general problem with JSF but I am trying to use Seam factory component pattern to solve it.


xhtml:


<a4j:outputPanel ajaxRendered="true">
                <!--  <a4j:outputPanel id="undefinedItemNumbersOutputPanel">  -->
                     <h:panelGrid columns="2"
                                     rendered="#{recoveredEquipmentManagement.totalUndefined > 0 and recoveredEquipmentManagementList.getRowCount() > 0}">
                              <s:graphicImage value="/img/warning_red_lg.jpg"/>
                                <h:outputText value="There are #{recoveredEquipmentManagement.totalUndefined} undefined item number(s)."/>
                     </h:panelGrid>
              </a4j:outputPanel>



SFSB:


//ScopeType.EVENT does not make totalUndefined display/refresh in time when we submit a change in modal edit screen...
     //@Factory(value="totalUndefined", scope=ScopeType.EVENT)
     //NOTE: see this thread regarding order of events and @Factory pattern:  http://www.seamframework.org/Community/FactoryAnnotationAndOrderOfEventsInSFSB
     //NOTE: this method is being executed multiple times in one HTTP req/resp. cycle!!!
     public Long getTotalUndefined(){
          Long totalUndefined = (Long)entityManager.createQuery("select count(*) "+
                                        " from RecoveredEquipmentManagement rem "+
                                        " where rem.recoveryType = ( SELECT lv.listValueId "+
                                   " FROM ListValue lv, List l "+
                                   " WHERE l.listId = lv.list.listId "+
                                   " and l.listName = :recoveryType"+
                                   " and lv.listValue = :undefined)")
                                   .setParameter("recoveryType", RECOVERY_TYPE)                                                  
                                   .setParameter("undefined", UNDEFINED)
                                   .getSingleResult();
return totalUndefined;
}



The getTotalUndefined() method is being executed approx. 8 - 12 times depending on what other a4j: activities (form submissions) are occurring. 


I want the getTotalUndefined() method to be executed after the first form/search submission (after Hibernate Criteria API query executes and returns resultset to populate the dataTable).  I then want it to re-exec after the user edits one of the values in one of the rows of the dataTable in a modalPanel embedded h:form.


The problem is that the only way the totalUndefined number is updated and reRendered properly is when I do not use the @Factory(value="totalUndefined", scope=ScopeType.EVENT).  The idea behind using the @Factory(value="totalUndefined", scope=ScopeType.EVENT) is to prevent the method from being executed too many times during the JSF life cycle and various a4j:/rich: (I'm using a rich:suggestionBox in one of the form search fields) activities.


Anybody know best way to solve this?  It's a very annoying characteristic of JSF...  I wonder if they addressed this problem at all in JSF 2.0...


I'm not sure if @Factory(value="totalUndefined", scope=ScopeType.PAGE) would work because the method would only be executed once per xhtml main page (unless manually set to null) and that is not appropriate either. 


I can't even pass a param to the method, that's too complicated and won't work with JSF binding events...

  • 1. Re: too many Seam component executions from JSF
    Arbi Sookazian Master

    I added a log.info() in getTotalUndefined() and here's what I see in the console after executing a search (form submission):


    10:15:19,855 INFO  [RecoveredEquipmentManagementAction] totalTimesTotalUndefinedCalled = 13



    and after the modalPanel edit row form submission:


    10:18:10,203 INFO  [RecoveredEquipmentManagementAction] totalTimesTotalUndefinedCalled = 43



    wow.  what a party.


    this is the xhtml snippet from the modalPanel h:form:


    <a4j:commandButton value="Apply Data" 
                  action="#{recoveredEquipmentManagement.applyData}" 
                 oncomplete="Richfaces.hideModalPanel('mpanelRecoveredEquipmentManagement');"
                 reRender="requiredEquipmentManagementDataTable, undefinedItemNumbersOutputPanel"/>



    So now I'm thinking that I can call the getTotalUndefined() from action events (like the Apply Data cmdBtn's method) and make the getTotalUndefined() method private.  Add context variable to the Seam component for the totalUndefined int value and read that from the JSF rather than binding the h:panelGrid rendered and h:outputText value to the getTotalUndefined() method.


    Obviously, the getTotalUndefined() mehtod will need to be called from the search action event for the primary form.


    Anybody else have comments or better ideas?  The getter methods for the context variable will still be called 43 times I guess, but that's better than n + y database queries, no???  Thank God these are not remote method calls from one process (JVM) to another!  The network latency and marshalling will kill the performance potentially.


  • 2. Re: too many Seam component executions from JSF
    Binesh Gummadi Novice

    As we know getter methods are called multiple times during Jsf lifecyle.


    I would approach this problem like this.





    1. Move the logic from getter method to something like calculateTotalUndefined. Outject totalUndefined variable.

    2. Call this method from pages.xml

    3. Use the outjected variable in your xhtml file.

    4. In your edit page(from modal panel). Call calculateTotalUndefined method which would ouject the new value.



    Good Luck.

  • 3. Re: too many Seam component executions from JSF
    Arbi Sookazian Master

    Binesh Gummadi wrote on Jun 19, 2009 19:30:


    As we know getter methods are called multiple times during Jsf lifecyle.

    I would approach this problem like this.




    1. Move the logic from getter method to something like calculateTotalUndefined. Outject totalUndefined variable.

    2. Call this method from pages.xml

    3. Use the outjected variable in your xhtml file.

    4. In your edit page(from modal panel). Call calculateTotalUndefined method which would ouject the new value.



    Good Luck.


    thanks I basically did that and here's what I'm seeing now:


    10:43:54,578 INFO  [RecoveredEquipmentManagementAction] totalTimesTotalUndefinedCalled = 1



    10:43:54,578 INFO  [RecoveredEquipmentManagementAction] totalTimesTotalUndefinedCalled = 2



    Much better in terms of reduction of unnecessary DB hits. 


    Is there a wiki or sticky on this??

  • 4. Re: too many Seam component executions from JSF
    Arbi Sookazian Master

    btw, anybody done (or read) some analysis on which phases exactly of the JSF lifecycle are contributing to the excessive (extra?) calls to the getter methods?


    and would this problem go away if we used wicket instead??  or must you still use JSF with wicket?

  • 5. Re: too many Seam component executions from JSF
    Francisco Jose Peredo Noguez Master

    If you ever wondered why some people think JSF over complicates stuff, I have got a good part of the answer.

  • 6. Re: too many Seam component executions from JSF
    Francisco Jose Peredo Noguez Master

    Arbi Sookazian wrote on Jun 19, 2009 19:45:


    Is there a wiki or sticky on this??



    This is common knowledge if you use JSF for anythin non-trivial... so I do not think a wiki or sticky is necesary... this feature is (AFAIK) part of the reason outjection (and particularly @Factory) was invented...


    And I guess developers using other presentation frameworks (Wicket, Tapesty and AribaWeb, etc) find it very funny that we JSF users have to suffer with this behavior... I have always wondered why this is not fixed by using some kind of caching interceptor:


    
    @PhaseCache(RefreshMode.ONLY_ONCE)
    public string getSomething(){
    
    }
    
    



    With different refresh modes depending on the phase where the getter is called by JSF... I think that would be a lot more intuitive than @Out or @Factory because the path to the property would be preserved... but I guess there should be some kind of architectural limitation in JSF that prevents anyone from developing such an apparently simple solution...

  • 7. Re: too many Seam component executions from JSF
    Francisco Jose Peredo Noguez Master

    Arbi Sookazian wrote on Jun 19, 2009 19:54:


    btw, anybody done (or read) some analysis on which phases exactly of the JSF lifecycle are contributing to the excessive (extra?) calls to the getter methods?


    No, but hava always wondered why there is no mechanism to say read this getter only once or re-read this getter from phase X to phase Y and then cache its return value



    and would this problem go away if we used wicket instead??  or must you still use JSF with wicket?


    Of course it would go way, Wicket has absolutely nothing to do with JSF, and this is a problem of JSF.

  • 8. Re: too many Seam component executions from JSF
    Jean Luc Apprentice

    Francisco Peredo wrote on Jun 19, 2009 21:28:


    I have always wondered why this is not fixed by using some kind of caching interceptor:
    @PhaseCache(RefreshMode.ONLY_ONCE)
    public string getSomething(){
    }
    



    (...) but I guess there should be some kind of architectural limitation in JSF that prevents anyone from developing such an apparently simple solution...


    Hmmm.. is there such a limitation indeed? This is an excellent suggestion and it might be implementable through Seam since it (Seam) intercepts the JSF events. At the very least for the Render Response phase since page views are typically a lot more frequent than updates.