13 Replies Latest reply on Sep 12, 2007 6:48 PM by mgrouch

    Dynamic columns howto, my solution is to slow

    mail.micke

      Hi all

      I'm wondering about your solutions of using dynamic columns with richfaces datatable, my implementation is to slow.
      From my experience tomahawk columns isn't that great to work with, what do you think.


      This is what I did.
      - Cookie with info about if a column should be rendered or not, data accessed via the ColumnManager
      - Using Seam enhanced EL on the rendered attribute of rich:column

      I think this way of doing this is quite neat, if only it wasn't so slow.

      All that usage of EL seems to take way to much CPU resources to process, when displaying a table with about 100 rows it takes about 6 seconds in the render response phase, while an exact copy without the conditional column rendering renders immediately.
      The code inside the columnManager.doRenderColumn(..) looks up information in a cached Map (parsed from a cookie string), so it should be quick.

      If you have time please have a look and see if what I did makes sense; is it crazy, can it be optimized or are there alternative better solutions.

      <rich:dataTable id="posListingTable"
       value="#{sdb.positions}"
       var="item">
       <f:facet name="header">
       <rich:columnGroup>
       <rich:column rendered="#{columnManager.doRenderColumn(sdb.expType,'cpb')}">
       CP Branch
       <a4j:commandLink reRender="posListingTable,reEnableColumnForm" value="x" action="#{columnManager.toggleRendering(sdb.expType,'cpb')}"/>
       </rich:column>
       <rich:column rendered="#{columnManager.doRenderColumn(sdb.expType,'cpty')}">
       Cpty Code
       <h:commandLink value="x" action="#{columnManager.toggleRendering(sdb.expType,'cpty')}"/>
       </rich:column>
       <rich:column rendered="#{columnManager.doRenderColumn(sdb.expType,'cagrid')}">
       Coll agr. id
       <h:commandLink value="x" action="#{columnManager.toggleRendering(sdb.expType,'cagrid')}"/>
       </rich:column>
       <rich:column rendered="#{columnManager.doRenderColumn(sdb.expType,'lpc')}">
       Limex Pos Code
       <h:commandLink value="x" action="#{columnManager.toggleRendering(sdb.expType,'lpc')}"/>
       </rich:column>
       <rich:column rendered="#{columnManager.doRenderColumn(sdb.expType,'ihi')}">
       IHI Key
       <h:commandLink value="x" action="#{columnManager.toggleRendering(sdb.expType,'ihi')}"/>
       </rich:column>
       <rich:column rendered="#{columnManager.doRenderColumn(sdb.expType,'md')}">
       Maturity Date
       <h:commandLink value="x" action="#{columnManager.toggleRendering(sdb.expType,'md')}"/>
       </rich:column>
       <rich:column rendered="#{columnManager.doRenderColumn(sdb.expType,'pt')}">
       Product Type
       <h:commandLink value="x" action="#{columnManager.toggleRendering(sdb.expType,'pt')}"/>
       </rich:column>
       <rich:column rendered="#{columnManager.doRenderColumn(sdb.expType,'pgi')}">
       Position Group Id
       <h:commandLink value="x" action="#{columnManager.toggleRendering(sdb.expType,'pgi')}"/>
       </rich:column>
      
      
       <ui:include src="#{sdb.additionalHeadersViewId}"/>
      
       </rich:columnGroup>
       </f:facet>
      
       <rich:column rendered="#{columnManager.doRenderColumn(sdb.expType,'cpb')}">
       #{item.positionData.placeCodeBookingCpty}
       </rich:column>
       <rich:column rendered="#{columnManager.doRenderColumn(sdb.expType,'cpty')}">
       #{item.positionData.codeCpty}
       </rich:column>
       <rich:column rendered="#{columnManager.doRenderColumn(sdb.expType,'cagrid')}">
       #{item.positionData.collateralAgreementId}
       </rich:column>
       <rich:column rendered="#{columnManager.doRenderColumn(sdb.expType,'lpc')}">
       #{item.positionData.positionCodeLimex}
       </rich:column>
       <rich:column rendered="#{columnManager.doRenderColumn(sdb.expType,'ihi')}">
       #{item.positionData.internalHierarchyKey}
       </rich:column>
       <rich:column rendered="#{columnManager.doRenderColumn(sdb.expType,'md')}">
       <h:outputText value="#{item.positionData.maturityDate}">
       <f:convertDateTime pattern="dd/MM/yyyy"/>
       </h:outputText>
       </rich:column>
       <rich:column rendered="#{columnManager.doRenderColumn(sdb.expType,'pt')}">
       #{item.positionData.productTypeCode}
       </rich:column>
       <rich:column rendered="#{columnManager.doRenderColumn(sdb.expType,'pgi')}">
       #{item.positionData.positionGroupId}
       </rich:column>
      
       <ui:include src="#{sdb.additionalColumnValuesViewId}"/>
      
      </rich:dataTable>
      
      


      Cheers,
      Mike

        • 1. Re: Dynamic columns howto, my solution is to slow

          Did you try to define EL function for you rendered contition.
          It can be static method and you can skip all injection/outjection
          which happens when you cann bean Method if you use Seam.

          • 2. Re: Dynamic columns howto, my solution is to slow

            YOu can also avoid callign getter of sdb.expType repetitively
            if you put table code into separate xhtml and pass
            sdb.expType into it using <ui:param> in <ui:include>

            • 3. Re: Dynamic columns howto, my solution is to slow
              mail.micke

              Hi

              - EL function
              I'll try this.
              Actuall started off implementing it this way but changed my mind and figured I'd put all the logic in one bean.
              Had issues with this since the el func got the value from the cookie and the columnManager kept the values in a cache
              and the cookie value seemd to lag one request. Perhaps I can try getting the columnManager via the appCtx, hmm.

              - separate xhtml file
              Didn't think about this, I'll try this as well.

              Many thanks,
              Mike

              • 4. Re: Dynamic columns howto, my solution is to slow
                mail.micke

                Tried to put it in a separate xhtml file and pass the expType via ui:param , didn't make any noticable differance.

                Quickly tried a dumb facelets function implementation, but it didn't give any performance gains either.
                Guess looking up the backing bean isn't a cheap operation.

                
                public static boolean doRenderColumn(final String expType, final String colName){
                
                 ELContext elCtx = FacesContext.getCurrentInstance().getELContext();
                
                 ValueExpression ve = FacesContext.getCurrentInstance().getApplication().
                 getExpressionFactory().
                 createValueExpression(elCtx,"#{columnManager}", ColumnManager.class);
                 ColumnManager cm = (ColumnManager) ve.getValue( elCtx);
                
                 return cm.doRenderColumn(expType, colName);
                }
                
                




                • 5. Re: Dynamic columns howto, my solution is to slow
                  tjakopec

                  I have the same problem, but I decided not to implement dynamic columns... so problem was gone :)
                  BUT
                  My approach was the same as mail.micke@gmail.com and that seem so complicated.
                  What will be best practice to accomplish dynamic columns (with mechanize off adding and removing columns in view)

                  • 6. Re: Dynamic columns howto, my solution is to slow
                    mail.micke

                    Hi all

                    just for the sake of testing I just tested with this facelets function:

                    public static boolean doRenderColumn(final String expType, final String colName){
                    
                     return true;
                    }
                    


                    But still rendering is to slow, takes about 4-5 seconds in render response phase to render a table with 100-140 rows.

                    I would also be really grateful for some information about how to accomplish what I'm trying to do with reasonable performance.

                    Regards,
                    Mike

                    • 7. Re: Dynamic columns howto, my solution is to slow
                      mail.micke

                      Just tried this on jboss 4.0.3SP1 and it is even slower??

                      Before I ran it on jboss 4.2 bundled with RHDS. Here it was only Phase 6 which a lot of time.

                      Now I get this:

                      15:54:23,590 INFO [TimerPhaseListener] RESTORE_VIEW 1 Time spent = 0 seconds
                      15:54:23,606 INFO [STDOUT] dkib.demo.sdb2.backing.SdbBacking: To display115 items
                      15:54:28,649 INFO [TimerPhaseListener] APPLY_REQUEST_VALUES 2 Time spent = 5 seconds
                      15:54:32,747 INFO [TimerPhaseListener] PROCESS_VALIDATIONS 3 Time spent = 4 seconds
                      15:54:37,097 INFO [TimerPhaseListener] UPDATE_MODEL_VALUES 4 Time spent = 4 seconds
                      15:54:37,207 INFO [STDOUT] dkib.demo.sdb2.backing.ColumnManager expType=default, colName=cpty
                      15:54:37,286 INFO [TimerPhaseListener] INVOKE_APPLICATION 5 Time spent = 0 seconds
                      15:54:37,727 INFO [STDOUT] dkib.demo.sdb2.backing.SdbBacking: To display115 items
                      15:54:45,797 INFO [STDOUT] dkib.demo.sdb2.backing.SdbBacking: To display115 items
                      15:54:45,939 INFO [TimerPhaseListener] RENDER_RESPONSE 6 Time spent = 8 seconds
                      15:54:45,939 INFO [TimerPhaseListener] RENDER_RESPONSE 6 Total Time spent = 22 seconds
                      


                      Does anyone know the reason for the drastic performance difference between jboss 4.0.3 and jbosss 4.2 ?

                      Cheers,
                      Mike

                      • 8. Re: Dynamic columns howto, my solution is to slow
                        dhalupa

                         

                        "tjakopec" wrote:
                        I have the same problem, but I decided not to implement dynamic columns... so problem was gone :)
                        BUT
                        My approach was the same as mail.micke@gmail.com and that seem so complicated.
                        What will be best practice to accomplish dynamic columns (with mechanize off adding and removing columns in view)


                        My approach was to extend datatable component class, override encodeBegin method, iterate through columns collection and switch rendering on and off according to some condition set. In the code snippet bellow configuredColumns is a List of id's of columns which should be rendered.
                        @Override
                         public void encodeBegin(FacesContext context) throws IOException {
                         for (Object child : getChildren()) {
                         if (child instanceof HtmlColumn) {
                         boolean rendered = configuredColums
                         .contains(((UIComponent) child).getId());
                         ((UIComponent) child).setRendered(rendered);
                         }
                         }
                         super.encodeBegin(context);
                         }


                        • 9. Re: Dynamic columns howto, my solution is to slow

                          I'm using the following solution (with facelets):

                          Have 2 loops with t:dataList (tomahawk repeater)
                          Outer one loops by rows, inner by columns.
                          Have a backing bean for list of columns where
                          column bean object has property which contains name of the
                          property of a data bean in this column.

                          In EL to access property of a data bean where
                          property name comes as a string from a column bean you use this
                          syntax

                          dataBean[columnBean.propertyName]

                          This worked fastest way for me (out of all other methods I tried).

                          With this approach you have full control over how you render table, order of columns, you write no java code except beans.

                          --MG

                          • 10. Re: Dynamic columns howto, my solution is to slow

                            You have long
                            APPLY_REQUEST_VALUES,
                            PROCESS_VALIDATIONS,
                            UPDATE_MODEL_VALUES

                            because you have many input controls on the form you are submitting.
                            (I guess in your table each row has a number of input controls)

                            With approach I described before you can render those inputs
                            regular HTML style (I assume you are using facelets which you should)
                            (not JSF).
                            I.e. instead of h:inputText you just use input type="text".

                            When your form is submitted you would have to read those
                            values regular servlet API way into your bean.
                            I know this is not true JSF way, but this way you can make it work faster :(.

                            You can also try reducing the length of your ids you are setting on JSF elements (Although I didn't notice much benefit from it)

                            Are you using server side state saving?
                            Did you check this:

                            http://wiki.jboss.org/wiki/Wiki.jsp?page=JSFPerformanceTipsInSeamApplications

                            --MG

                            • 11. Re: Dynamic columns howto, my solution is to slow

                              And one more idea:

                              using ui:remove

                              try to find out which column(s) gives you most performance loss.

                              It is usually some component, EL expression or getter which performs much worse.
                              Do you have any dropdowns in a table? Menu selections?
                              Check boxes? Complicated EL expressions in some columns?

                              --MG

                              • 12. Re: Dynamic columns howto, my solution is to slow
                                mail.micke

                                Hi MG,
                                I was thinking about doing it that way but I want to use things like the rich datascroller for paging :( and also want the nice look&feel of the rich:dataTable.
                                But there might be no avoiding this solution, then I'd have to figure out how to use the skin CSS to make it look right... hmm.

                                Keep em hints coming

                                Thanks,
                                Mike

                                • 13. Re: Dynamic columns howto, my solution is to slow

                                  I have similar use case to yours. With my approach we also
                                  implemented pager. It is not that hard. facelet tag. paginator bean
                                  utilize first and rows attributes on t:dataList (they will take values
                                  from paginator bean) (or JBoss Gravel has paginator tag)
                                  and ajax4jsf for pagination actions. Minimal coding in Java (just
                                  usual beans/actions).
                                  We also implemented grouping with collapsible sections in table
                                  by using multiple tbody in HTML table (couldn't make this with any of existing components otherwise). Only Woodstock JSF lib had something similar.

                                  You can also try quipukit table (if that is an option for you).
                                  It has customizable columns order (It has its share of performance
                                  issues usually with client side javascript though).