OmniFaces 1.8 1.8.1 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
,
and @Eager
.
Update: during fixing issue 35 for MyFaces, I accidentally removed a line necessary for deferred script from combined resource handler, causing it to combine those scripts twice (once in head and once in deferred script) :( OmniFaces 1.8.1 was quickly released with a fix. Reminder for the future: don't release on a Monday.
Installation
Non-Maven users: download OmniFaces 1.8.1 JAR and drop it in /WEB-INF/lib
the usual way, replacing the older version if any.
Maven users: use 1.8.1
.
org.omnifaces
omnifaces
1.8.1
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
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
! 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
component for this very purpose which works just like
with a library
and name
attribute.
...
library="libraryname" name="resourcename.js" />
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
taghandler allows you to set a common attribute on multiple components. So, instead of for example:
... disabled="#{someBean.disabled}" />
... disabled="#{someBean.disabled}" />
... disabled="#{someBean.disabled}" />
... disabled="#{someBean.disabled}" />
... disabled="#{someBean.disabled}" />
You can just do:
name="disabled" value="#{someBean.disabled}">
... />
... />
... />
... />
... />
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> asyncList() {
List 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> entities;
@Inject
private MyEntityService service;
@PostConstruct
public void init() {
entities = service.asyncList();
}
public List getEntities() throws InterruptedException, ExecutionException {
return entities.get();
}
}
This way, when you request /test.xhtml
with something like this:
value="#{myEagerRequestBean.entities}" var="entity">
#{entity.property}
... 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
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
which sets the given attribute on all nested components
FacesMessageExceptionHandler
which sets any caught exception as a global FATAL faces message
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
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
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
shouldn't silently convert the value to String
(fixes e.g. java.util.Date
formatting fail in
)
Fixed javax.enterprise.inject.AmbiguousResolutionException
in subclassed @FacesConverter
and @FacesValidator
failed to find the for
component when it's not in the same parent
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.
Source:http://balusc.blogspot.com/2014/06/omnifaces-18-released.html