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.

Tuesday, April 16, 2013

"Alway in view" paradigm in web

I was thinking about writing the next post in my blog and remembered one well-known paradigm I used in my completed web projects. The paradigm is to show current element(s) to be navigated always in view, that means visible. You know, a classic web application can have a long content causing scrollbars in browser. For instance, a vertical scrollbar means there is a hidden content - above or below the current viewport. Not only the browser, a div element can have scrollbars and a viewport as well (as long as the style overflow:hidden is not set). Keeping important element(s) always in view increases the usability. If an element, which is expected to be shown, doesn't stay visible, the user is often confused and forced to navigate the element manually. Just two examples with screenshots and jQuery based solutions.

Assume we have two tables. The first table on the left side shows users in a system. Rows are clickable. User's details for a clicked row are shown in the second table on the right side.


The left table is big and when we're scrolling down, at certain point we can not see the right table at all. Now, a row click in the left table updates the right table, but it might be hidden due to its small length.


Is it user friendly? No. To overcome this problem we will implement a jQuery function which checks if a specified element is beyond the visible area.
$.fn.showTopInView = function () {
    var winTop = $(window).scrollTop();
    var bounds = this.offset();

    if (winTop > bounds.top) {
        $('html, body').animate({scrollTop: 0}, 'fast');
    }
};
The .offset() method allows us to retrieve the current position of an element relative to the document. We compare element's top position with the amount we have scrolled from the topmost part of the page (calculated by $(window).scrollTop()). If the element (referenced with this) is located in the hidden area, its top position is less than this scrolled amount. In this case, we simple scroll to topmost part of the page with an animation. Using is simple. In our example, we should force execution of the following script when row clicking:
 
$('#IdOfTheRightTableContainer').showTopInView();
 
This can happen in onclick callback directly or streamed down as an JS script in response to the browser (if clicks cause AJAX requests). IdOfTheRightTableContainer is an Id of the div element the right table is placed in.

Another example is more complicated. As I said, scrollbars can also appear in div and hide inner elements. Assume again, we have a table included in such div container. The table displays some search results. e.g. documents and folders. Furthermore, assume we have thumbnails for every entry in this result table. User clicks on a thumbnail and want to see the related table's entry. The requirement thus - the table's entry of the selected thumbnail should be selected (highlighted) as well and should scroll to the div's viewport in order to always stay visible. The picture below demonstrates this behavior.


The script for solving this task uses the jQuery's method .position(). Other as .offset(), .position() retrieves the current position relative to the offset parent. The offset parent should be positioned (position: absolute or relative). In our example the offset parent is a relative positioned div element with the style class ui-layout-content (note: the web app used the jQuery Layout plugin). First, we need to write a function which will find the table's entry by some given identifier (here pid argument). This function gets invoked when user clicks on a thumbnail.
function selectResultEntryOnCurrentPage (pid) {
    var $resultTable = $("#searchResultTable");
    var $resultEntry = $resultTable.find(".resultEntry[data-pid='" + pid + "']");
    $resultTable.find(".resultEntry").removeClass("selected");
    $resultEntry.addClass("selected");
    
    scrollToResultEntry ($resultTable, $resultEntry);
}
What we did here, was only a row selection. The table and the found table's entry are passed as parameters into the next function scrollToResultEntry. This function is responsible for keeping the selected entry visible.
function scrollToResultEntry ($resultTable, $resultEntry) {
    // scroll to the entry with animation if it's not completely visible
    var $scrollPane = $resultTable.closest(".ui-layout-content");
    var entryPos = $resultEntry.position();
    if (entryPos.top < 0) {
        // element has parts in the hidden top area of the scrollable layout pane ==> scroll up
        $scrollPane.animate({scrollTop: $scrollPane.scrollTop() + entryPos.top - 5}, "fast");
    } else if ($scrollPane.height() < entryPos.top + $resultEntry.outerHeight()) {
        // element has parts in the hidden bottom area of the scrollable layout pane ==> scroll down
        $scrollPane.animate({
            scrollTop: $scrollPane.scrollTop() + $resultEntry.outerHeight() + (entryPos.top - $scrollPane.height()) + 5}, "fast");
    }    
}
We measure the top position of the selected table's entry. Negative value means the entry is not completely visible and has some parts in the top area of the scrollable div (the mentioned offset parent). The second condition $scrollPane.height() < entryPos.top + $resultEntry.outerHeight() means the entry is not completely visible and has some parts in the bottom area of the scrollable div. In both cases, the entry is scrolled to the div's viewport with an animation. The new vertical scroll position is calculated (a little bit tricky) and set in the scrollTop option.

Thursday, March 14, 2013

Passing complex objects in URL parameters

Imagine you would like to pass primitive data types, complex Java objects like java.util.Data, java.lang.List, generic classes, arrays and everything what you want via URL parameters in order to preset default values on any web page after the page was loaded. Common task? Yeah, but available solutions are mostly restricted to encoding / decoding of java.lang.String. The approach I will show doesn't have any limits on the data types. Only one limit is the limit of the URL size. URLs longer than 2083 characters may not work properly in old IE versions. Modern Firefox, Opera, and Safari can handle at least 80000 characters in URL.

Passing any type of objects via URL parameters is possible if we serialize objects to JSON and deserialize them on the server-side. An encoded JSON string has a valid format and this is a way to go! Well, but there is a problem. A serialization / deserialization to / from the JSON format works fine if the object is a non-generic type. However, if the object is of a generic type, then the Generic type information gets lost because of Java Type Erasure. What to do in this case? The solution I want to demonstrate is not restricted to JSF, but as I'm developing Java / Web front-ends, I'm rotating in this circle... So, let's start. First, we need a proper converter to receive URL parameters in JSON format and converts them back to Java. PrimeFaces Extensions provides one - JsonConverter.java. How it works? The following example shows how the JsonConverter can be applied to f:viewParam to convert a list of Strings in the JSON format to a List in Java.
<f:metadata>
    <f:viewParam name="subscriptions" value="#{subscriptionController.subscriptions}">
        <pe:convertJson type="java.util.List<java.lang.String>" />
    </f:viewParam>
</f:metadata>

<h:selectManyCheckbox value="#{subscriptionController.subscriptions}">
    <f:selectItem id="item1" itemLabel="News" itemValue="1" />
    <f:selectItem id="item2" itemLabel="Sports" itemValue="2" />
    <f:selectItem id="item3" itemLabel="Music" itemValue="3" />
</h:selectManyCheckbox>
The JsonConverter has one optional attribute type. We don't need to provide a data type information for primitives such as boolean or int. But generally, the type information is a necessary attribute. It specifies a data type of the value object. Any primitive type, array, non generic or generic type is supported. The type consists of fully qualified class names (except primitives). Examples:
"long[]"
"java.lang.String"
"java.util.Date"
"java.util.Collection<java.lang.Integer>"
"java.util.Map<java.lang.String, com.prime.FooPair<java.lang.Integer, java.util.Date>>"
"com.prime.FooNonGenericClass"
"com.prime.FooGenericClass<java.lang.String, java.lang.Integer>"
"com.prime.FooGenericClass<int[], com.prime.FooGenericClass<com.prime.FooNonGenericClass, java.lang.Boolean>>"
The string in the type is parsed at runtime. The code for the JsonConverter is available here (for readers who are interested in details). The JsonConverter is based on three other classes: ParameterizedTypeImpl.java, GsonConverter.java and DateTypeAdapter.java. The last one is a special adapter for dates because java.util.Date should be converted to milliseconds as long and back to the java.util.Date. So far so good. But how to prepare the values as URL parameters on the Java side? I will show an utility class which can be used for that. Read comments please, they are self-explained.
import org.apache.log4j.Logger;
import org.primefaces.extensions.converter.JsonConverter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;

/**
 * Builder for request parameters.
 */
public class RequestParameterBuilder {

    private Logger LOG = Logger.getLogger(RequestParameterBuilder.class);

    private StringBuilder buffer;
    private String originalUrl;
    private JsonConverter jsonConverter;
    private String encoding;
    private boolean added;

    /**
     * Creates a builder instance by the current request URL.
     */
    public RequestParameterBuilder() {
        this(((HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest()).getRequestURL()
            .toString());
    }

    /**
     * Creates a builder instance by the given URL.
     *
     * @param url URL
     */
    public RequestParameterBuilder(String url) {
        buffer = new StringBuilder(url);
        originalUrl = url;
        jsonConverter = new JsonConverter();

        encoding = FacesContext.getCurrentInstance().getExternalContext().getRequestCharacterEncoding();
        if (encoding == null) {
            encoding = "UTF-8";
        }
    }

    /**
     * Adds a request parameter to the URL without specifying a data type of the given parameter value.
     * Parameter's value is converted to JSON notation when adding. Furthermore, it will be encoded
     * according to the acquired encoding.
     *
     * @param name name of the request parameter
     * @param value value of the request parameter
     * @return RequestParameterBuilder updated this instance which can be reused
     */
    public RequestParameterBuilder paramJson(String name, Object value) throws UnsupportedEncodingException {
        return paramJson(name, value, null);
    }

    /**
     * Adds a request parameter to the URL with specifying a data type of the given parameter value. Data type is sometimes
     * required, especially for Java generic types, because type information is erased at runtime and the conversion to JSON
     * will not work properly. Parameter's value is converted to JSON notation when adding. Furthermore, it will be encoded
     * according to the acquired encoding.
     *
     * @param name name of the request parameter
     * @param value value of the request parameter
     * @param type data type of the value object. Any primitive type, array, non generic or generic type is supported.
     *             Data type is sometimes required to convert a value to a JSON representation. All data types should be
     *             fully qualified.
     * @return RequestParameterBuilder updated this instance which can be reused
     */
    public RequestParameterBuilder paramJson(String name, Object value, String type)
        throws UnsupportedEncodingException {
        jsonConverter.setType(type);

        String jsonValue;
        if (value == null) {
            jsonValue = "null";
        } else {
            jsonValue = jsonConverter.getAsString(null, null, value);
        }

        if (added || originalUrl.contains("?")) {
            buffer.append("&");
        } else {
            buffer.append("?");
        }

        buffer.append(name);
        buffer.append("=");
        buffer.append(URLEncoder.encode(jsonValue, encoding));

        // set a flag that at least one request parameter was added
        added = true;

        return this;
    }

    /**
     * Adds a request parameter to the URL. This is a convenient method for primitive, plain data types.
     * Parameter's value will not be converted to JSON notation when adding. It will be only encoded
     * according to the acquired encoding. Note: null values will not be added.
     *
     * @param name name of the request parameter
     * @param value value of the request parameter
     * @return RequestParameterBuilder updated this instance which can be reused
     */
    public RequestParameterBuilder param(String name, Object value) throws UnsupportedEncodingException {
        if (value == null) {
            return this;
        }

        if (added || originalUrl.contains("?")) {
            buffer.append("&");
        } else {
            buffer.append("?");
        }

        buffer.append(name);
        buffer.append("=");
        buffer.append(URLEncoder.encode(value.toString(), encoding));

        // set a flag that at least one request parameter was added
        added = true;

        return this;
    }

    /**
     * Builds the end result.
     *
     * @return String end result
     */
    public String build() {
        String url = buffer.toString();

        if (url.length() > 2083) {
            LOG.error("URL " + url + " is longer than 2083 chars (" + buffer.length() +
                "). It may not work properly in old IE versions.");
        }

        return url;
    }

    /**
     * Resets the internal state in order to be reused.
     *
     * @return RequestParameterBuilder reseted builder
     */
    public RequestParameterBuilder reset() {
        buffer = new StringBuilder(originalUrl);
        jsonConverter.setType(null);
        added = false;

        return this;
    }
}
A typically bean using the RequestParameterBuilder provides a parametrized URL by calling either paramJson(...) or param(...).
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

/**
 * UrlParameterProvider bean.
 */
@ManagedBean
@SessionScoped
public class UrlParameterProvider implements Serializable {

    private String parametrizedUrl;

    @PostConstruct
    protected void initialize() {
        RequestParameterBuilder rpBuilder = new RequestParameterBuilder("/views/examples/params.jsf");
        try {
            List<String> subscriptions = new ArrayList<String>();
            tableBlockEntries.add("2");
            tableBlockEntries.add("3");

            // add the list to URL parameters with conversion to JSON
            rpBuilder.paramJson("subscriptions", subscriptions, "java.util.List<java.lang.String>");

            // add int values to URL parameters without conversion to JSON (just for example)
            rpBuilder.param("min", 20);
            rpBuilder.param("max", 80);   
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }

        parametrizedUrl = rpBuilder.build();
    }

    public String getParametrizedUrl() {
        return parametrizedUrl;
    }
}
Using in XHTML - example with h:outputLink
<h:outputLink value="#{urlParameterProvider.parametrizedUrl}">
    Parametrized URL
</h:outputLink>
Once the user clicks on the link and lands on the target page with the relative path /views/examples/params.jsf, he / she will see a pre-checked h:selectManyCheckbox.

The real world is more complicated. In the fact I've written a lot of custom converters having JsonConverter inside. So that instead of <pe:convertJson type="..." /> are custom converters attached. That subject is going beyond of this post.

Monday, February 18, 2013

Eager CDI beans

Everybody knows eager managed beans in JSF 2. @ManagedBean has an eager attribute. If eager="true" and the scope is application, then this bean must be created when the application starts and not during the first reference to the bean. This is a nice feature when you want to load application scoped data (e.g. some select items for menus) during application startup in order to increase the performance at runtime.
@ManagedBean(eager=true)
@ApplicationScoped
public class GlobalBean {
    ...
}
@ManagedBean annotation will be deprecated with JSF 2.2. It is highly recommended to use CDI (context dependency injection) beans in JEE environment. But what is the equivalent to the eager managed beans in CDI? Well, CDI is flexible, you can write portable CDI extensions. I asked Thomas Andraschko how to do this. Thomas is a CDI expert, co-owner of PrimeFaces Extensions and the committer in OpenWebBeans (OWB) project. His tip was to implement such extension as follows
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE})
public @interface Eager
{
}
package mydomain.mypackage;

import java.util.ArrayList;
import java.util.List;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterDeploymentValidation;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ProcessBean;

public class EagerExtension implements Extension {
    private List<Bean<?>> eagerBeansList = new ArrayList<Bean<?>>();

    public <T> void collect(@Observes ProcessBean<T> event) {
        if (event.getAnnotated().isAnnotationPresent(Eager.class)
            && event.getAnnotated().isAnnotationPresent(ApplicationScoped.class)) {
            eagerBeansList.add(event.getBean());
        }
    }

    public void load(@Observes AfterDeploymentValidation event, BeanManager beanManager) {
        for (Bean<?> bean : eagerBeansList) {
            // note: toString() is important to instantiate the bean
            beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean)).toString();
        }
    }
}
The extensions should be registered in a file META-INF/services/javax.enterprise.inject.spi.Extension. The file has only one line with a fully qualified path to the EagerExtension class, e.g. mydomain.mypackage.EagerExtension.

Using is simple. Assume, we have an application scoped LayoutController CDI bean which is responsible for the entire layout configration. We can annotate it with @Eager and speed up the layout creation.
@ApplicationScoped
@Eager
@Named
public class LayoutController implements Serializable {
    private LayoutOptions layoutOptions;

    @PostConstruct
    protected void initialize() {
        layoutOptions = new LayoutOptions();

        LayoutOptions panes = new LayoutOptions();
        panes.addOption("slidable", false);
        panes.addOption("spacing", 6);
        layoutOptions.setPanesOptions(panes);

        ...
    }

    public LayoutOptions getLayoutOptions() {
        return layoutOptions;
    }
}
Have fun with CDI!