OmniFaces 2.5.1 released with o:inputFile, @GraphicImageBean and MultiViews

The major visible changes are the <o:inputFile> component which extends and improves <h:inputFile>, the @GraphicImageBean annotation which can be used to mark a bean as a public and dedicated image service, and adoption of "MultiViews" in FacesViews.

For CDI-less users, there will be no version 1.15. There are no major 2.x bugfixes anymore which should also end up in 1.1x. Therefore it isn't worth the effort to merge 2.x back to 1.1x again. And, due to major changes in 2.x project structure, merging 2.x branch back to 1.1x branch has become a tedious task which isn't worth the effort anymore. OmniFaces 1.1x is now in maintenance mode. The latest 1.1x version is still 1.14. Of course there may be bugfix releases in the future, but so far there are no major 2.4-2.5 bugs which also affect 1.14, so there's no 1.14.1 yet as of now.

Spring 3.x already supports javax.inject API from CDI, so Spring services (which are often used to substitute the lack of EJB support in Tomcat) can seamlessly be injected in CDI managed beans.

Multi file upload with builtin file type and size validation

The relatively new <h:inputFile> component, which was introduced only in JSF 2.2, has been extended and enhanced into new <o:inputFile> component with support for multiple file selection and folder selection via new HTML5 multiple and directory attributes.

Also, media type filtering via new HTML5 accept attribute has been added, along with built-in server side validation based on file extension. The below example will in modern browsers only show image files in file browse dialog.

<o:inputFile value="#{bean.file}" accept="image/*" />

And, file size validation via a custom maxsize attribute has been added which runs in both client and server side. The below example sets the file size limit to 10MiB.

<o:inputFile value="#{bean.file}" maxsize="#{10 * 1024 * 1024}" />

In client side JavaScript, the new HTML5 File API will be used to check the file size and a special ajax request will be sent to trigger a JSF faces message. This all will take place without that the whole file needs to be sent to the server side. Instant feedback thus. As fallback for older non-HTML5 clients and as safeguard against spoofed requests, the server side will validate the file size once again after the file is arrived over there.

Independent image service

The <o:graphicImage> component, which was added in OmniFaces 2.0, had a builtin security restriction to prevent users from being able to invoke arbitrary bean methods by manipulating the GET request URL path. One of the consequences of this security restriction is that images served by <o:graphicImage> component aren't consistently hotlinkable. It works only if the page referencing the <o:graphicImage> has been invoked at least once in application's lifetime.

Therefore a new managed bean annotation has been introduced which should mark a bean as a dedicated and public graphic image service. When putting @GraphicImageBean annotation on the bean, then all of bean's public methods which return either InputStream or byte[] will become accessible by a direct GET request URL.

This also allowed the creation of a bunch of new EL functions such as #{of:graphicImageURL(...)} which merely print the graphic image URL without the need for a whole <o:graphicImage> component, which finally makes the below case possible:

MultiViews

Ones who are familiar with Apache HTTPD+PHP world are probably aware of the age-old but very useful MultiViews feature of Apache HTTPD which allowed usage of clean URLs such as http://example.com/foo/bar/baz which searches for respectively /foo/bar/baz.php, /foo/bar.php and /foo.php until the first one is found, and then passes the rest of the URL as PATH_INFO variable.

The OmniFaces-builtin extensionless URL feature known as FacesViews has been enhanced to support exactly this MultiViews feature too. It's a matter of adding /* suffix to the org.omnifaces.FACES_VIEWS_SCAN_PATHS context parameter value. The below context parameter makes all files in the current webapp available via extensionless URLs with MultiViews support.

With above configuration, an URL such as http://example.com/contextpath/foo/bar/baz will search for /foo/bar/baz.xhtml, /foo/bar.xhtml and /foo.xhtml in this order until the first one is found and then invoke it. The existing @Param annotation has been enhanced to inject path parameters by their index. Assuming that you've a /foo.xhtml, then the path parameters bar and baz can be injected in the managed bean associated with /foo.xhtml as below: