Monday, January 13, 2014

OmniFaces 1.7 released!

Happy New Year! OmniFaces 1.7 has yesterday been released!

Again, this release had some unscheduled delay for various reasons. Among others, I migrated back from CuraƧao to the Netherlands and Arjan Tijms moved into a new home, resulting in both having much less free time during the same period. This also explains why there are relatively small additions and changes in this release. The three most useful additions are the fixviewstate.js, CacheControlFilter and <o:validateMultiple>.

Fix JSF view state after ajax-rendering content which contains another form

You'll probably recognize the Mojarra-related problem described in an earlier blog Communication in JSF 2.0 - Ajax rendering of content which contains another form. In short, when you ajax-render some component which in turn contains another form, then this form would lose its JSF view state hidden field which in turn causes that the 1st submit always misses hit and only the 2nd submit works. This problem was almost 4 years ago reported as JSF spec issue 790 and for a long time scheduled to be fixed for JSF 2.2, however for some unclear reason it has been postponed to JSF 2.3. Note: early MyFaces 2.0.x/2.1.x versions also exposed this problem, but they internally fixed it rather quickly irrespective of the spec issue being targeted at 2.2/2.3.

Even though this problem could be fixed by a custom jsf.ajax.addOnEvent script, the script is relatively large and sensitive to minor browser-specific bugs and thus not really worth copypasting plain into every single new JSF project. We couldn't wait any longer for JSF 2.3, so it has been added to OmniFaces 1.7! Long story short, you can see it in action at the showcase. It's basically a matter of adding the following line inside the <h:body> (not head!) of your master template:


<h:outputScript library="omnifaces" name="fixviewstate.js" target="head" />

Note for PrimeFaces users: this script also silently fixes a minor PrimeFaces-related bug in versions older than 3.5.23 and 4.0.7: its internal fix for this problem namely incorrectly appends the JSF view state hidden field to GET forms as well! The fixviewstate.js removes the hidden field from those forms afterwards. By the way, speaking about PrimeFaces, the showcase application has for this release been upgraded from PrimeFaces 3.5 to 4.0. No single change was necessary in the UI side (XHTML/CSS/JS). Kudos! In the Java side (backing beans, etc) only the Constants#VERSION was removed, but that's not really relevant for the average PrimeFaces based webapp.

Control cache-related response headers

One of the more common homegrown servlet filters is one which sets the Cache-Control, Expires and Pragma headers related to browser caching. With the new CacheControlFilter there's now finally one more "standard" OmniFaces solution to minimize repeatedly homegrown code in your JSF project. Its configuration is relatively simple, in order to disable caching on all dynamic JSF pages, just add the following to the project's web.xml, assuming that your FacesServlet is mapped with a <servlet-name> of facesServlet:


<filter>
    <filter-name>noCache</filter-name>
    <filter-class>org.omnifaces.filter.CacheControlFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>noCache</filter-name>
    <servlet-name>facesServlet</servlet-name>
</filter-mapping>

If you want to cache resources matching an example URL pattern of /foo/* for 2 days, then map it so, with an expires initialization parameter which can take a value of a number with a "w", "d", "h", "m" or "s" suffix indicating respectively weeks, days, hours, minutes or seconds:


<filter>
    <filter-name>cache2days</filter-name>
    <filter-class>org.omnifaces.filter.CacheControlFilter</filter-class>
    <init-param>
        <param-name>expires</param-name>
        <param-value>2d</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>cache2days</filter-name>
    <url-pattern>/foo/*</url-pattern>
</filter-mapping>

Note that you can easily specify multiple <url-pattern> entries in a single <filter-mapping>. See also the showcase.

Validate multiple input fields in a single method

If no one of the existing multi field validators <o:validateAll>, <o:validateAllOrNone>, <o:validateEqual>, <o:validateOne>, <o:validateOneOrMore>, <o:validateOneOrNone>, <o:validateOrder> or <o:validateUnique> is sufficient for your concrete functional requirement, then you have now the opportunity to easily implement your custom multi field validation method via the new <o:validateMultiple> tag. Here's an example referencing a bean method:


<o:validateMultiple id="myId" components="foo bar baz" validator="#{bean.someMethod}" />
<h:message for="myId" />
<h:inputText id="foo" />
<h:inputText id="bar" />
<h:inputText id="baz" />

Whereby the method has the following signature (method name is free to your choice):


    public boolean someMethod(FacesContext context, List<UIInput> components, List<Object> values) {
        // ...
    }

You've all input values at your hands in a single place whereby you just return true when the specific combination of those values is considered valid based on your own business requirements. See also the showcase which shows a slight different example referencing a backing bean implementing MultiFieldValidator interface. Thanks goes to OmniFaces user Juliano Marques for the kickoff implementation of the component and taghandler for this.

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

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

Added in OmniFaces 1.7

  • New omnifaces:fixviewstate.js script which should automatically fix JSF issue 790
  • Added invalidateAll attribute to disable invalidating valid fields, and add support for showMessageFor="@invalid" to show message for invalidated fields only
  • New ValueChangeValidator which runs only when the submitted and converted value is really changed as compared to the model value
  • Added Faces#getBookmarkableURL() methods taking ParamHolder instances as value
  • Added Beans#getInstance() and Beans#getActiveInstances() methods returning concrete (non-proxied) instances
  • New CacheControlFilter which can control cache-related headers of the response
  • New <o:validateMultiple> tag which allows validating multiple fields via a custom validator method or implementation
  • Added WebXml#getSessionTimeout() to get web.xml configured session timeout
  • Added SortedTreeModel which holds the <o:tree> children in a TreeSet

Changed in OmniFaces 1.7

  • FullAjaxExceptionHandler is now able to handle error in error page itself

Fixed in OmniFaces 1.7

  • Store constants of <o:importConstants> in an ordered map instead of an unordered map
  • WebXml initialization failed in Weblogic because it attempts to load it as CDI managed bean
  • Broken 404 "not found" error handling of CombinedResourceHandler (it threw IllegalArgumentException instead)
  • GenericEnumConverter failed in composites which are reused more than once in same view and on enums with custom bodies
  • <o:validateOrder> threw NPE on non-required fields

Maven download stats

Here are the Maven download stats:

  • September 2013: 1779
  • October 2013: 3202
  • November 2013: 2091
  • December 2013: 2344