Monday, June 2, 2014

OmniFaces 1.8.3 released!

OmniFaces 1.8.3 has finally been 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.

As usual, in the What's new page of the showcase site you can find an overview of all what's been added/changed/fixed for 1.8. The three most useful additions are the <o:deferredScript>, <o:massAttribute> and @Eager.

Installation

Non-Maven users: download OmniFaces 1.8.3 JAR and drop it in /WEB-INF/lib the usual way, replacing the older version if any.

Maven users: use <version>1.8.3</version>.

<dependency>
    <groupId>org.omnifaces</groupId>
    <artifactId>omnifaces</artifactId>
    <version>1.8.3</version>
</dependency>

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.

<h:head>
    ...
    <o:deferredScript library="libraryname" name="resourcename.js" />
</h:head>

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. At a production site, this approach has proven to decrease the average time until "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:

<h:inputText ... disabled="#{someBean.disabled}" />
<h:inputText ... disabled="#{someBean.disabled}" />
<h:inputText ... disabled="#{someBean.disabled}" />
<h:inputText ... disabled="#{someBean.disabled}" />
<h:inputText ... disabled="#{someBean.disabled}" />

You can just do:

<o:massAttribute name="disabled" value="#{someBean.disabled}">
    <h:inputText ... />
    <h:inputText ... />
    <h:inputText ... />
    <h:inputText ... />
    <h:inputText ... />
</o:massAttribute>

The advantage speaks for itself.

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:

import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;

@ManagedBean(eager=true)
@ApplicationScoped
public class Bean {
    // ...
}

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.

So, both beans below are equivalent:

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
import org.omnifaces.cdi.Eager;

@Named
@Eager
@ApplicationScoped
public class Bean {
    // ...
}
import javax.inject.Named;
import org.omnifaces.cdi.Startup;

@Named
@Startup
public class Bean {
    // ...
}

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):

package com.example;

import java.util.List;
import java.util.concurrent.Future;
import javax.ejb.AsyncResult;
import javax.ejb.Asynchronous;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class MyEntityService {

    @PersistenceContext
    private EntityManager em;

    @Asynchronous
    public Future<List<MyEntity>> asyncList() {
        List<MyEntity> entities = em
            .createQuery("SELECT e FROM MyEntity e", MyEntity.class)
            .getResultList();
        return new AsyncResult<>(entities);
    }

}

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)

package com.example;

import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.omnifaces.cdi.Eager;

@Named
@Eager(requestURI="/test.xhtml")
@RequestScoped
public class MyEagerRequestBean {

    private Future<List<MyEntity>> entities;

    @Inject
    private MyEntityService service;

    @PostConstruct
    public void init() {
        entities = service.asyncList();
    }

    public List<MyEntity> getEntities() {
        try {
            return entities.get();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new FacesException(e);
        } catch (ExecutionException e) {
            throw new FacesException(e);
        }
    }

}

This way, when you request /test.xhtml with something like this:

<h:dataTable value="#{myEagerRequestBean.entities}" var="entity">
    <h:column>#{entity.property}</h:column>
</h:dataTable>

... 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.

An overview of all additions/changes/bugfixes in OmniFaces 1.8

Taken over from the What's new? page on showcase:

Added in OmniFaces 1.8

  • WebXml#getFormErrorPage() to get web.xml configured location of the FORM authentication error page
  • <o:deferredScript> which is capable of deferring JavaScript resources to window.onload
  • Faces#addResponseCookie() got 2 new overloaded methods whereby domain and path defaults to current request domain and current path
  • Components#isRendered() which also checks the rendered attribute of all parents of the given component
  • <o:massAttribute> which sets the given attribute on all nested components
  • FacesMessageExceptionHandler which sets any caught exception as a global FATAL faces message
  • <o:cache> has new disabled attribute to temporarily disable the cache and pass-through children directly
  • @Eager annotation to eagerly instantiate request-, view-, session- and application scoped beans
  • <o:viewParam> skips converter for null model values so that query string doesn't get polluted with an empty string
  • Small amount of utility methods and classes, e.g. method to check CDI annotations recursively in stereotypes, shortcut method to obtain VDL, etc

Changed in OmniFaces 1.8

  • CombinedResourceHandler now also recognizes and combines <o:deferredScript>
  • UnmappedResourceHandler now also recognizes PrimeFaces dynamic resources using StreamedContent

Fixed in OmniFaces 1.8

  • Assume RuntimeException in BeanManager#init() as CDI not available (fixes deployment error on WAS 8.5 without CDI enabled)
  • Use "-" (hyphen) instead of null as default option value to workaround noSelectionOption fail with GenericEnumConverter
  • <o:param> shouldn't silently convert the value to String (fixes e.g. java.util.Date formatting fail in <o:outputFormat>)
  • Fixed javax.enterprise.inject.AmbiguousResolutionException in subclassed @FacesConverter and @FacesValidator
  • <o:messages> failed to find the for component when it's not in the same parent
  • <o:conditionalComment> shouldn't XML-escape the if value, enabling usage of & character
  • UnmappedResourceHandler broke state saving when partial state saving is turned off
  • CombinedResourceHandler didn't properly deal with MyFaces-managed resources

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.