Category Archives: Seam Framework

Performance tuning of Seam, JSF, Richfaces for webapps

Apart from following best practices while coding an application, we often come across the need to tune it up just a bit further to get that peek performance going.
On a recent project we faced some challenges in trying to increase the performance of our web application. We finally ended up optimizing the app and got very promising results. Here I put together some of the information used by us in one location, which is scattered over the web.

The frameworks used were, Seam 2.2 and JSF 1.2 with Richfaces 3.2 and also Spring 2.5. Now without further delay here you go..

Some pointers on using JSF beans mapped in your view layer (JSP/XHTML when using facelets).

  1. Don’t put code in a getter (accessor method) of a managed bean
    The getters are invoked frequently to get the data. You could use some other method to fetch data and simply update the property.
    But if you did end up with few getters which hit the database for data loading, then consider putting a condition around that code to load data only if required.
    Example: Change code like the below;

    private List aList;
    public List getList() {
    aList = getServiceObject().loadListFromDB();
    return aList;
    }
    

    To load data conditionally as given below;

    private List aList;
    public List getList() {
    if( null == aList || aList.isEmpty() ) {
    //Load from DB only if list is empty
    aList = getServiceObject().loadListFromDB();
    }
    return aList;
    }
    
  2. Check scope of your beans. Seam provides a Conversation Scope use it instead of Session Scope if practical enough for your requirement.
  3. Richfaces does provide a huge set of components which are Ajax based.
    But many of those components also add to the processing overhead. Use them judiciously or it can affect your page load time pretty badly.
    Consider these points when trying to optimize a JSF/Richfaces application.

    • Avoid using rich:dataGrid or rich:dataTable whenever you can. The h:dataTable of JSF usually provides good enough options.
    • Do not use rich:tooltip inside a data table or grid. It’s very expensive and can lead to very slow rendering especially on IE.
      Also avoid nesting too many rich:xxx components inside a dataTable.
    • Use ajaxSingle=true attribute and a4j:region tag whenever possible. Also consider using limitToList attribute when reRendering.
    • Do not use multiple rich:modalPanel components for each view consider using one single rich:modalPanel with dynamic view.You could use a4j:include or ui:include (facelets) to change the view inside a modal panel.

Apart from following the above practices here are some goodies which will speed up your JSF with Richfaces webapp.
Add the below snippets to your web.xml

  • Use a global queue. (This is not strictly required if you are already using queuing of ajax requests)
    <context-param>
    <param-name>
     org.richfaces.queue.global.enabled
    </param-name>
    <param-value>true</param-value>
    </context-param>
    
  • Use NEKO parser instead of the default. This will speed up things.
    <context-param>
     <param-name>
      org.ajax4jsf.xmlparser.ORDER
     </param-name>
     <param-value>
      NONE,NEKO,TIDY
     </param-value>
    </context-param>
    
    <context-param>
    <param-name>org.ajax4jsf.xmlparser.NEKO</param-name>
    <param-value>.*\..*</param-value>
    </context-param>
    
  • Change the way css and java script files are loaded.
    If you view the source of your page you will notice that by default richfaces will add some includes of css and scripts which lead to multiple calls to load.
    For example with our web app we had like 8 css files and 23 js scripts getting loaded separately.
    and with the below setting our pages had just 1 css include and 2 script includes.

    <context-param>
    <param-name>
    org.richfaces.LoadStyleStrategy
    </param-name>
    <param-value>ALL</param-value>
    </context-param>
    
    <context-param>
    <param-name>
    org.richfaces.LoadScriptStrategy
    </param-name>
    <param-value>ALL</param-value>
    </context-param>
    
    <!--  If you use LoadScriptStrategy ALL, turn the compression off  -->
    <context-param>
    <param-name>
    org.ajax4jsf.COMPRESS_SCRIPT
    </param-name>
    <param-value>false</param-value>
    </context-param>
    

    Using the above settings we had reduced the css and js files to be loaded:

    <link rel='stylesheet' class='component' type='text/css'
            href='/excel/a4j_3_2_1-SNAPSHOTorg/richfaces/skin-ext-classes.xcss/DATB/eAELXT5DOhSIAQ.sA18_'
    />
    <script type='text/javascript'
            src='/excel/a4j_3_2_1-SNAPSHOT/org/ajax4jsf/framework.pack.js'></script>
    <script type='text/javascript'
            src='/excel/a4j_3_2_1-SNAPSHOT/org/richfaces/ui.pack.js'></script>
    
  • For Facelets and JSF RI from Sun you can use the below settings:
    <!--  Facelets tuning -->
    <context-param>
    <param-name>
    facelets.RECREATE_VALUE_EXPRESSION_ON_BUILD_BEFORE_RESTORE
    </param-name>
    <param-value>false</param-value>
    </context-param>
    
    <context-param>
    <param-name>
    facelets.BUILD_BEFORE_RESTORE
    </param-name>
    <param-value>false</param-value>
    </context-param>
    
    <context-param>
    <param-name>facelets.DEVELOPMENT</param-name>
    <param-value>false</param-value>
    </context-param>
    
    <context-param>
    <param-name>facelets.REFRESH_PERIOD</param-name>
    <param-value>-1</param-value>
    </context-param>
    
    <!--  JSF RI Performance tuning -->
    <context-param>
    <param-name>com.sun.faces.responseBufferSize</param-name>
    <param-value>500000</param-value>
    </context-param>
    
    <context-param>
    <param-name>com.sun.faces.verifyObjects</param-name>
    <param-value>false</param-value>
    </context-param>
    
    <!-- Allows the JavaScript to be cached -->
    <context-param>
    <param-name>
    com.sun.faces.externalizeJavaScript
    </param-name>
    <param-value>true</param-value>
    </context-param>
    

    Only if you are running under JBoss AS

    <context-param>
    <param-name>
    com.sun.faces.serializationProvider
    </param-name>
    <param-value>
    org.jboss.web.jsf.integration.serialization.JBossSerializationProvider
    </param-value>
    </context-param>
    

When tuning your seam application you can use the components.xml file to tweak some settings.

  • Cache images and style globally.
    <web:cache-control-filter name="imageCacheControlFilter"
    regex-url-pattern=".*(\.gif|\.png|\.jpg|\.jpeg)"
    value="max-age=86400"/>
    
    <web:cache-control-filter name="textCacheControlFilter"
    regex-url-pattern=".*(\.css|\.js)"
    value="max-age=1400"/>
    
  • Also if you are using richfaces with Seam you could configure the richfaces filter  in components.xml itself
    without needing to declare the filter in web.xml
    Disable the forceparser and turn on caching.

    <web:ajax4jsf-filter force-parser="false"
    enable-cache="true"
    url-pattern="*.jsf"/>
    

So in the end after optimizing the webapp by using framework provided settings, you can expect a lot better performance from your app. In the end you get happy visitors. Hope this bit of information helps you guys.

Advertisements

Jboss 5.1 and Seam 2 Redeployment issue workaround

When trying to work with Seam 2.2 applications in JBoss 5.1 you might have come across a very annoying redeploy cycle of your application. I will document the issue and workaround here.
Beginning with Seam 2.2 and JBoss 5.1 is pretty straight forward. But you could soon run into issues if you don’t pay attention to the details.

The Journey

  1. I had decided to give Seam a try after having dig into some seam docs. The first thing was to try out the examples that come bundled with seam.
  2. Seam is pretty easy to start off with. You just need to get a copy of JBoss 5.1 and Seam 2.2 (the latest during this post). Then as mentioned in the Running Seam in Jboss Just do the below two steps:
    1. Edit build.properties in your Seam directory and configure the jboss.home property to be your JBoss AS installation directory.
    2. In the jboss-seam/examples/booking directory, type ant deploy. (Here booking is one example you can do it with any other)
  3. ant deploy command will generate the (War/Ear/Ejb) artifacts and dump it into the deploy folder of JBoss AS.
  4. If JBoss is running you should see the console output showing the deployment taking place.
  5. Just point your browser to the deployed apps URL and voila.

When you start building your own application using either the seam commands or Jboss Tools plugin for Eclipse, you will notice quite a few artifacts getting generated (Not all are needed).

When you deploy your project and find that none of the @Name annotated classes are getting found. Check for seam.properties file this must be in your classpath. It’s an empty file but acts like a marker which triggers the scanning of your seam components. Without that file you will need to register each component in your components.xml file.

This should solve your problem, but under JBoss 5.1 you might run into another issue of constant undeploy/deploy of your project without any details as to why in the logs. If you look in the Seam documentation WhatHappensWhenYouDeploySeamAppInJBoss5 and couple of other JBoss JIRA pages you will find that mostly this happens due to IDE generated files getting placed under WEB-INF check for these and delete them. The files get generated when you open the pages.xml or web.xml kind of files in Visual Editor.

Even after following the simple & complex advice the problem sometimes just won’t go. What i noticed was that the presence of seam.properties file under WEB-INF/classes will also trigger the dreadful redeployment of your application. If you look in the seam reference docs for possible locations of seam.properties, you will find that it needs to be in your classes/ root or META-INF directory of a JAR. So an easier solutions is to just “move the seam.properties from WEB-INF/classes to WEB-INF/classes/META-INF” and voila the problem should be solved without any fancy modification to your JBoss AS.

I hope this helps you to get on with building your Seam applications.