Monday, June 2, 2014

OmniFaces 1.8.3 released!

Also this release had some unscheduled delay for various reasons. Great programmers are also just humans with a "life" next to all the development work. I personally had after all a lot more time needed to acclimatize myself to the Netherlands after having lived in Curaçao for almost 6 years (still don't really feel home here outside the working hours, still want to go back once the kids grow out the house). Arjan had among others also some unforeseen issues with his new home.

Defer loading and parsing of JavaScript files

If you've ever analyzed the performance of your website using a tool like Google PageSpeed, then you'll probably recognize the recommendation to defer loading and parsing of JavaScript files. Basically, the recommendation is to load JavaScript files only when the browser is finished with rendering of the page. This is to be achieved by dynamically creating a <script> element via document.createElement() during window.onload. Please note that this is not the same as just moving the scripts to the bottom of the page using <h:outputScript target="body">! That would speed up downloading of other resources, but still block the rendering of the HTML in most browsers (read: everything expect IE).

OmniFaces now comes with a <o:deferredScript> component for this very purpose which works just like <h:outputScript> with a library and name attribute.

You can also use it on for example PrimeFaces scripts, but some additional work needs to be done. For detail, refer this Stack Overflow Question and Answer: Defer loading and parsing of PrimeFaces JavaScript files. This approach has been in production at zeef.com since March 20 (more than 2 months already thus) and has decreased the time to "DOM content loaded" from ~3s to ~1s on a modern client machine.

Set a common attribute on multiple components

The new <o:massAttribute> taghandler allows you to set a common attribute on multiple components. So, instead of for example:

Eagerly instantiate a CDI managed bean

When using the standard JSF managed bean facility via @ManagedBean which is since JSF 2.2 semi-official deprecated (not documented as such, but the JSF team is clearly pushing toward it given the total absence of new features around JSF managed bean facility, instead they are all in CDI managed bean facility), it was possible to declare an application scoped JSF managed bean to be eagerly instantiated during application's startup like so:

However, this isn't possible with standard CDI, not even with the one as available in Java EE 7. So OmniFaces has added the @Eager and @Startup annotations for the very purpose. The @Startup is just a stereotype for @Eager @ApplicationScoped.

An additional bonus of OmniFaces @Eager is that it not only works on application scoped CDI managed beans, but also on request and session scoped CDI managed beans and on beans annotated with OmniFaces @ViewScoped (thus not the JSF 2.2 one yet, that will come in the upcoming OmniFaces 2.0 which will target JSF 2.2, OmniFaces 1.x is namely JSF 2.0 targeted).

Having @Eager on a request scoped bean may look somewhat strange, but this makes an interesting use case possible: eagerly and asynchronously fetch some data from a DB in the very beginning of the request, long before the FacesServlet is invoked, it runs even before the servlet filters are hit (it's initiated via a ServletRequestListener). Depending on the server hardware used, the available server resources, all code running between the invocation of the first servlet filter and entering the JSF render response, this may give you a time space of 10ms ~ 500ms (or perhaps more if you've some inefficient code in the pipeline ;) ) to fetch some data from DB in a different thread parallel with the HTTP request and thus a speed improvement equivalent to the time the DB needs to fetch the data. Below is an example of how such an approach can look like:

The asynchronous service (this silly example fetches the entire table; just do whatever DB or any other relatively long-lasting service task you want to do as long as the method is annotated with @Asynchronous and you return an AsyncResult as Future; the container will all by itself worry about managing the threads):

The @Eager request scoped bean (note the requestURI attribute, this must exactly match the context-relative request URI without any path fragments and query strings, this example assumes a /test.xhtml page (with a FacesServlet mapping of *.xhtml); wildcards like * are not supported yet, this may come in the future if there's demand)

... then the above bean will be constructed and initialized far before the FacesServlet is invoked. Note that this thus also means that the FacesContext is not available inside the @PostConstruct! From that point on, both JSF and JPA will do their jobs simultaneously in separate threads until JSF calls the getter for the first time. The JSF thread (the HTTP request thread) will then block until JPA has returned the result, or perhaps it's already returned at that moment and then JSF can just advance immediately without waiting for JPA.

Maven download stats

Here are the Maven download stats:

January 2014: 3537

February 2014: 3580

March 2014: 3892

April 2014: 3572

May 2014: 3971

Below is the version pie of May 2014:

Last but not least

For the case you missed it: OmniFaces repo, wiki and issue tracking (basically: everything) has moved from Google Code to GitHub, along with a "brand new" homepage in GitHub style at omnifaces.org. The downloads will from now just point directly to Maven via links at the homepage.

No comments:

About

Donate

For the ones who want to express their excessive thanks for my work, I used to have an Amazon wishlist with a list of books, but right now I don't have any interesting books on the list anymore (to anyone who've sent books before: thank you very much, I got 6 books in 6 months). You can always donate something so that I can use it for other stuff, such as Nespresso coffee.