Tuesday, May 7, 2013

JSF: choice between legacy components and fashionable performance killers

This blog post was originated due to performance issues in one big web application. Everybody optimizes Java code, but it seems nobody try to optimize the JavaScript code. Strange, because on the client-side there is much room for improvements. I would state, even more than on the server-side. We will analyse the perfomance of editable JSF standard components, sometimes called "legacy", and modern PrimeFaces components with rich JavaScript widgets. This is a neutral analyse, without to blame any library or any person. Only facts.

Well. What do we want to test? The goal is to measure the client-side perfomance (without backend logic) of JS script block executions for PrimeFaces p:inputText / p:selectOneMenu. We want to test an editable p:dataTable with inputs / selects components in table cells. The table has 25 rows and 16 columns, that means 25 * 16 = 400 cells. Every cell contains either an input or a select component. There are 6 test cases. Standard h:inputText and h:selectOneMenu don't have JS script blocks, so it is interesting to see what for impact JS widgets have.


The entire test project is available on GitHub. Simple clone or download it and run with built-in Maven Jetty plugin. The page load speed is measured with the new Navigation Timing JavaScript API for accurately measuring performance on the web. The API provides a simple way to get accurate and detailed timing statistics. It's more precise than using JS Date object. The Navigation Timing JavaScript API is available in Internet Explorer 9 and higher, last versions of Google Chrome and Firefox. The code to measure the time after the current response has been arrived until the window onload event is fired is shown on the GitHub.

JavaScript is single-threaded, so let's see how sequential script block executions can slow down displaying a web page. If we only test h:inputText and p:inputText, the difference is marginal. The page load time is almost the same. Running on Windows 7 and Firefox 20.0.1 I could only see that the table with p:inputText needs ca. 200-300 ms more than the table with h:inputText. This is a good result which means the JS script execution for one p:inputText takes less than 1 ms. Really good. Congrats to PrimeFaces. A mix test with inputs and selects shown that the page with PrimeFaces components takes approximately 1.5 sek. more than the page with standard components. Adding more PrimeFaces select components slows the page rendering time down. Extreme case is to have only p:selectOneMenu components. This is a perfomance killer and the reason why our web application was too slow. Internet Explorer shows the well-known error message "A script on this page is causing Internet Explorer to run slowly". Take a look at page load time self.

Running on Windows 7 and Firefox 20.0.1

h:selectOneMenu

 

p:selectOneMenu


If we assume that component renderers take approximately the same time to render HTML output, we can calculate the time for JS script block execution of a single p:selectOneMenu. This time is 11,3 ms. That's too much. The reason may be many inefficient jQuery selectors in widget's constructor. I don't know and it doesn't matter here. On my notebook with Ubuntu, I got a huge time difference ca. 10 sek. The browser with 400 p:selectOneMenu tags almost "freezes".

Running on Kubuntu 12.04 and Firefox 20.0

h:selectOneMenu


p:selectOneMenu


Conclusion

Some people say "JSF is slow, JSF is not a right technology". Wrong. JSF is fast enough. It depends on how to use this framework. Editing of everything at once is nice, but obviously it is not recommended to use a large editable DataTable with rich JSF components. What would be an alternative for editable DataTable? There are many ways, depending on individual preferences. I will try to propose some ones.
  1. Use standard JSF select components in large editable tables. But what is with theming? No problem. All modern browser, also IE8 and higher allow to style native HTML select elements. You can adjust colors for borders, background and let selects look more or less stylish according to applied theme. Presupposed is of course, you don't need advanced features such as custom content within select components (filter functionality or whatever).
  2. Cell editing feature in PrimeFaces renders native select elements and it is fast.
  3. Row editing feature in PrimeFaces renders native select elements and it seems to be also fast.
  4. Master-Detail approach in one view. You select a row and see details to edit. Details can be shown outside of the table - on the right side or at the top, depending on table's width / height.
  5. Master-Detail approach with separate views. You select a row and switch the views. Instead of table, you see details like in the MasterDetail component of PrimeFaces Extensions. From details you can go on to another levels to create / edit more details and then, at the end, jump to the overview table again.
I hope, you enjoyed this post :-). Comments and suggestions are welcome.

Sunday, May 5, 2013

PrimeFaces Extensions 0.7 released

We are glad to announce the new 0.7 release of PrimeFaces Extensions. This is a main release which contains a lot of improvements and bug fixes. The full list of closed issues is on the GitHub. I would like to pick up some highlights.
  • AjaxErrorHandler
There are many, many fixes for pe:ajaxErrorHandler. The reason: more users, incl. team members of the Extensions project started to use this component. We are thinking now to add a support for non AJAX requests too. Let's see where we will end up.
  • ImportEnum
Enum values can be accessed on pages directly by the new pe:importEnum tag. Usage is demonstrated in this use case.
  • InputNumber
Thousand and decimal separators are Locale aware now. You don't need to pass a Locale as attribute - default values for thousand and decimal separators are taken in this way now
Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();                
java.text.DecimalFormatSymbols decimalFormatSymbols = new java.text.DecimalFormatSymbols(locale);
String thousandSeparator =  Character.toString(decimalFormatSymbols.getGroupingSeparator());
String decimalSeparator = Character.toString(decimalFormatSymbols.getDecimalSeparator());
  • Exporter
This is a new component which provides many features such as export of multiple tables, sub-tables, tables with grouping, cell editing, dynamic columns, customized format, etc. It supports exporting of DataList and custom exporter via Java ServiceLoader mechanism. Demo is available here. This component is continuing to grow, more features are on TODO list.
  • DynaForm
DynaForm got some optimizations, e.g. new constructors without too much parameters and a new feature - varContainerId. varContainerId is a name of the variable which contains the prefix of the client Id within pe:dynaFormControl. This property allows to get the whole clientId of a component within pe:dynaFormControl. The whole client Id is sometimes required for JavaScript or RequestContext.update(...). Demo is available here. Users often asked how to update controls (cells) from another cells. We decided to implement a new use case to demonstrate this feature (I call it inter-control or inter-cell communication within pe:dynaForm). This nice use case demonstrates how to implement a class called ClearInputsExecutor for the PrimeFaces Extensions' ExecutableVisitCallback to clear all inputs / selects related to one row in pe:dynaForm.
  • Layout
Layout got the spacing_open and spacing_closed attributes which define spacing between adjacent layout panes. But the main improvement in this release is not this feature. Until now we only could use an instance of LayoutOptions in the options attributes of pe:layout tag. We thought, because LayoutOptions gets serialized to JSON to be able to be used in the underlying widget, it would be also nice to accept already serialized options as JSON string as well. This could increase the time of layout building when the layout is built during application startup in an application scoped bean. The options attribute accepts now a JSON string. Just call toJson() method on LayoutOptions and use it like this
<pe:layout options="#{layoutController.options}" ...>
@ManagedBean(eager=true)
@ApplicationScope
public class LayoutController implements Serializable {
    private String options;
 
    @PostConstruct
    protected void initialize() {
        LayoutOptions layoutOptions = new LayoutOptions(); 
        LayoutOptions panes = new LayoutOptions();
        panes.addOption("slidable", false);
        ...
        layoutOptions.setPanesOptions(panes);
         ...

        options = layoutOptions.toJson(); 
    }
 
    public String getOptions() {
        return options;
    }
}
This is a better choice in comparison to specifying options per attributes. Support of iframe acting as layout pane and updatable nested layouts were postponed to the next release.
  • TimePicker
TimePicker got a huge update. JS script was updated, fixed a collision with p:calendar and an issue in Chrome, but especially handy is a new attribute showOn. Similar to the PrimeFaces Calendar, this attribute defines the behavior when the timepicker is shown. focus (default): when the input gets focus, button: when the button trigger element is clicked, both: when the input gets focus and when the button is clicked. The online demo is available here.
  • Timeline
Timeline was reimplemented almost from scratch and this is the most interesting highlight of this release! First, thanks to the Applus IDIADA - company that sponsored the Timeline component. The new Timeline has features such as editable and read-only events, event's grouping, configurable zoom range, min. / max. dates for visible range, client-side and server-side API, i18n support, theming and more. We were excited to develop these interesting features. Explore various timeline features yourself, e.g. client-side API, server-side API or grouped events.


Timeline is highly interactive. The component provides a convenient server-side API to update its events smoothly. What does it mean? Approach for editing is similar to the PrimeFaces' Schedule, but the Schedule component provide a client-side widget's API method update() to update itself in oncomplete. The main goal is to avoid a DOM update of the component markup because is has a complex UI and can leads to flickers. The problem with update() is a separate AJAX request. So, we have two requests in the Schedule if we want to add or edit an event. The Timeline component provides a server-side API to update the component with only one request / response. So, you can update the UI on the server-side immediately when sending "update" request for a particular event. The main steps to do:
  1. Get thread-safe TimelineUpdater instance by timeline's Id (in terms of findComponent()).
  2. Invoke one or many (batch mode) CRUD operations, such as add, update, delete, deleteAll, clear, on the TimelineModel with the TimelineUpdater as parameter.
This is a paid component which has a quality. More features such as drag-and-drop from outside onto Timeline and connection arrows between dependent events are coming soon. As soon as the payment arrived, we will produce t-shirts for all team members and our friend Çağatay Çivici, the founder of PrimeFaces and PrimeTek. The first design looks like


Well, this was the first design, the word "PrimeFaces" is missing :-). It should be "PrimeFaces & Extensions". The back side doesn't show buildings as some readers may think. It shows the commit history on the GitHub :-).

What is the next? The project is stable. We have very small amount of open issues (around 20). This is a right time to grow. The next main release 1.0.0 will contain 3 new components! They will have the same quality as Timeline. The expected release date is tightly coupled with the upcoming PrimeFaces 4.0. Stay tuned.