Monday, November 24, 2014

The minimum requirements have been upgraded from Java 1.6, JSF 2.0, EL 2.1 and Servlet 2.5 to Java 1.7, JSF 2.2, EL 2.2, Servlet 3.0 and CDI 1.1. An important change is thus that the optional CDI dependency is now required. OmniFaces 2.0 won't deploy on an environment without CDI. This way we can keep things simple and move forward.

As of now, OmniFaces 2.0 is still fully backwards compatible with JSF 2.1, but not with JSF 2.0 anymore. OmniFaces 2.0 is also backwards compatible with CDI 1.0, as long as you don't use the Beans#destroy() utility method which works only in CDI 1.1. Noted should be that future 2.x versions may not be backwards compatible with either JSF 2.1 or CDI 1.0 anymore, so don't take the backwards compatibility of 2.0 as a guarantee for the same in future 2.x versions.

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 2.0. The top three additions which will likely become popular are the <o:viewParamValidationFailed> taghandler, <o:graphicImage> component and @Param annotation. Do however check out the What's new page for more, with among others the NoAutoGeneratedIdViewHandler and the <o:validateBean> which Arjan Tijms blogged about.

Installation

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

Generally, the answer was to fiddle around in @PostConstruct, <f:viewAction>, or preRenderView and explicitly check for FacesContext#isPostback() and/or #isValidationFailed() and then deal with it using ExternalContext#redirect() or #sendError(). And then you've perhaps also take messaging into account and/or ignore the "Faces message has been enqueued but is not displayed" warnings over all place in logs.

OmniFaces now comes with a <o:viewParamValidationFailed> taghandler for this very purpose which can be applied per <f|o:viewParam>, or for them all. Here's an example which sends a HTTP 400 error when the foo parameter is absent.

Note that the <o:viewParam> is being used instead of <f:viewParam> to bypass a design mistake in <f:viewParam required="true">. Namely, it works only exactly like as <h:inputText required="true"> when an empty string is supplied as request parameter instead of null. So, when the request parameter is totally absent, i.e. it is null, then the <f:viewParam required="true"> behaves internally differently, causing among others postValidateEvent listeners and even JSR303 bean validation annotations such as @NotNull to be entirely skipped.

Stream images directly from backing bean, optionally as data URI

The <h:graphicImage> is relatively limited in usage. In JSF 1.x it only generates a HTML <img> element without any true JSF advantages. It didn't support e.g. directly referencing a byte[] or InputStream property representing the raw image content. You could just as well use plain HTML <img> directly. In JSF 2.x, it got additional support for referencing JSF resources via new name and library attributes. However, it still didn't support directly referencing the image's content as bean property.

PrimeFaces came with <p:graphicImage> which supported referencing a special wrapper class StreamedContent which in turn should contain among others the image via an InputStream. However, this caused much trouble and confusion among starters because the majority created and assigned it as a property of a request or view scoped bean during some postback bean action. This won't work because the webbrowser requests the image in a different and independent HTTP GET request, during which the initial request scoped bean won't exist anymore, and the JSF view state of the initial view (and thus also the view scoped bean) isn't available anywhere. Basically, you'd need to create the StreamedContentonly in the getter method. This is fleshed out in the answer of among others the following questions:

Whilst the getter method approach worked, this ultimately ended up in ugly and confusing backing bean code, because the getter method is called twice and you only needed to populate the StreamedContent with the image's content in the second (stateless) call. You'd be tempted to just switch to a plain vanilla @WebServlet for the sole purpose of serving images, or to use the data URI scheme to immediately render the image content directly embedded in the HTML output.

OmniFaces now comes with a <o:graphicImage> component which solves all of those problems. It supports directly referencing a byte[] or InputStream property representing the raw image content. It also immediately validates if the managed bean holding the property is @ApplicationScoped, so that the developer is automatically forced to "do things the right way" (i.e. don't accidentally deal with request/view scoped state by declaring the byte[] or InputStream as an instance variable). And, it supports a new dataURI="true" attribute which will immediately embed the image in the HTML output, and hereby thus supporting the image as property of a request or view scoped bean which is set during some postback bean action (hereby providing a perfect solution for a "preview uploaded image" case without polluting the data store).

Here's an example which shows images from a DB in a loop. Note that the getter method basically immediately invokes the service call and that it's also really only invoked when the browser actually requests the image, and thus not during rendering the HTML output. The application scoped bean is basically acting like an image servlet/service, but then with less boilerplate code than e.g. the @WebServlet approach.

See the showcase for live examples, with among others an upload-preview example.

Inject, convert and validate HTTP request parameters via CDI and have them ready in @PostConstruct

The @Param has been improved to support directly injecting the desired target type. So instead of

@Inject @Paramprivate ParamValue<String> paramName;

you can now finally use

@Inject @Paramprivate String paramName;

, lowering the burden to actually use it. It even supports injecting (auto)converted values like so

@Inject @Paramprivate Product product;

with a @FacesConverter(forClass=Product.class).

The major advantage as compared to <f:viewParam> is that the injected value is readily available in @PostConstruct and you don't need an additional <f:viewAction> (or the JSF 2.0/2.1 <f:event type="preRenderView"> workaround) to perform the desired bean initialization based on those params. The disadvantage is that it's fully decoupled from the JSF lifecycle. I.e. conversion and validation is performed immediately during bean's construction, which is not necessarily during validations phase. Also, you would still need an additional Faces#isValidationFailed() check inside the @PostConstruct if you'd like to conditionally perform bean initialization depending on the validation outcome.

It doesn't make <f:viewParam> entirely superfluous, but depending on the business requirements it's a pretty good alternative as it makes the model (the backing bean) more declarative and the view (the XHTML) more clean. For example, one of the disadvantages of <f:viewParam> is that you can't declare it in a common template file and thus you'd have to copypaste it over all template clients. This can be solved by replacing it by using @Param on the common backing bean.

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

NoAutoGeneratedIdViewHandler which throws a runtime exception when an autogenerated JSF client ID is being rendered

<o:viewParamValidationFailed> which enables sending either a redirect or error status on validation failure of view parameters

<o:graphicImage> which is capable of referencing a byte[] or InputStream property with optional support for data URI format

@Param now supports directly injecting the (auto-converted) value

<o:moveComponent> via which components, facets and behaviors can be moved at runtime to a target component in various ways

<o:resolveComponent> via which a component can be looked up by its ID and a reference to it put in various scopes

<o:validateBean> now supports validating beans at the class level

Servlets utility class got a bunch of new methods related to cookies and JSF

New BeansLocal utility class next to Beans class with the same philosophy as Faces/FacesLocal

Changed in OmniFaces 2.0 (also applies to 1.10)

Default validation message of ValidateMultipleFields components can now be supplied via <message-bundle>

<o:viewParam> enables support for @NotNull and Pre/PostValidateEvent even when parameter is not specified, on contrary to <f:viewParam>

Html5RenderKit is now not forgiving anymore on broken renderers that don't pass the current component to the write methods (fixes "plain HTML" messup)

Skip null/empty values in <o:validateOrder> as that's actually the responsibility of required="true"

CDNResourceHandler and CombinedResourceHandler can now be disabled via a web.xml context param supporting a request based EL expression

Fixed in OmniFaces 2.0 (also applies to 1.10)

Set system default timezone in CDI @FacesConverter when web.xml context param says so

Components#hasInvokedSubmit() failed in iterating components such as UIData and UIRepeat

Fixed <o:massAttribute> to only consider own children instead of those of parent

GzipResponseFilter is made better compatible with Servlet 3.1 containers

Maven download stats

Here are the Maven download stats:

June 2014: 4429

July 2014: 4243

August 2014: 4169

September 2014: 4531

October 2014: 3651

Below is the version pie of October 2014:

But ... I don't want / can't use CDI at all!

Don't panic! OmniFaces 1.10 is the new release from the 1.x branch and is the same as 1.8.1, but with the bugfixes from 2.0 (but no additions!) and without any CDI dependency. This still depends on Java 1.6, JSF 2.0, EL 2.1 and Servlet 2.5 like the previous 1.x releases. The CDI part, which was optional since 1.6, has completely been removed (except for the org.omnifaces.config.BeanManager singleton enum, which uses reflection anyway). The reason for this is that some 1.x users were unable to upgrade to OmniFaces 1.6 or newer in an outdated environment due to bugs or conflicts in the ancient CDI library used.

I can't say if this will be the last OmniFaces 1.x release. If there's a bug report which applies to both 1.x and 2.x, then it will be fixed for both versions. The 1.x release won't contain any new features. This is not only to push users towards CDI, but also because any newer features will most likely also depend on the existence of new APIs. For example, the <o:viewParamValidationFailed> depends on JSF 2.1 and <o:graphicImage> depends on EL 2.2.

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

Vdldoc 2.0

Vdldoc, our Facelets .taglib.xml documentation generator, has also had its 2.0 release. The Java 7 javadoc look'n'feel has been upgraded to Java 8 javadoc look'n'feel. It now also supports Java EE 7's http://xmlns.jcp.org/* XML namespace. There are no other technical/functional changes.

Thursday, October 16, 2014

In this tutorial you will learn how to setup a JSF 2.2 (Mojarra) playground with Eclipse 4.4 (Luna) and WildFly 8.1. This tutorial assumes that you're starting from scratch and thus covers every single step necessary towards a working JSF web page. This tutorial is targeted on Windows users and screenshots are also Windows based. Only the steps to install the JDK is different on other operating systems, but the remainder not. In local disk file system path examples, just replace "C:\...\..." by "~/.../..." to make it Unix friendly.

There are also another IDEs available next to Eclipse, e.g. Oracle Netbeans, IntelliJ IDEA, etcetera. The choice for Eclipse is made because it's highly configureable, customizeable, has lots of helpful wizards and .. it's free! True, it may eat memory and it may sometimes crash. Just make sure that your environment has suffuciently free RAM memory for Java EE development. I recommend at least 2GB of free RAM of which 1GB is reserved to Eclipse. Also at least a dual/quad core CPU around 2GHz is recommended to be able to work fluently. Also make sure that you install trusted Eclipse plugins the right and clean way, because the well-known Eclipse-instability is almost always caused by bad plugins.

There are also another application servers available next to JBoss WildFly, e.g. Apache TomEE, Oracle GlassFish, etcetera. The choice for WildFly is made because it ships as being a full fledged Java EE 7 application server already with JSF 2.2 builtin and a lot of other handy Java EE aspects like CDI for bean management and dependency injection, JPA for database connectivity, EJB for database transaction management, JSR303 for bean validation, etcetera. In the 3-year old JSF 2.0 tutorial, GlassFish was been used. The main reason to prefer WildFly over GlassFish is that Oracle stopped with commercial support for GlassFish and thus it essentially isn't ever going to be "production ready". WildFly will be "production ready" once the commercially supported JBoss EAP 7 version will be released. Also, the current Eclipse GlassFish plugin has some terrible bugs causing the server to never finish its startup cycle or causing duplicate deployments.

Create a working directory where you install and store all related files. In this tutorial we'll use C:\Java as working directory. If you want to store it somewhere else, then you'll have to replace every occurence of "C:\Java" throughout the tutorial by the desired directory.

You'll see several "download" buttons. Press the one which also says "JDK".

Currently, this will lead you to Java SE Development Kit 8 Downloads page. Accept the License Agreement and choose the right file for your platform. For Windows x64 for example you will get the file jdk-8u20-windows-x64.exe (naming may differ per version, specifically this one is thus JDK 8 update 20), save it to disk. This is the installer.

Execute it and install the JDK in C:\Java\jdk1.8.0_20 and JRE in C:\Java\jre1.8.0_20 respectively (or in their default paths, if you want).

WildFly 8 is JBoss' implementation of the Java EE 7 API. Note that you do not need to download the Java EE 7 SDK! It basically contains GlassFish 4 along with a bunch of documentation. You do not need it. We're using WildFly instead of GlassFish as the Java EE implementation.

You can skip this part if you already have downloaded/installed WildFly.

WildFly uses Mojarra as JSF reference implementation. WildFly 8.1 ships with Mojarra version 2.2.6 (newer WildFly versions will of course ship with a newer Mojarra version). Sometimes you'd like to upgrade Mojarra in WildFly, because you need a bugfix which is only available in a newer version.

You can skip this chapter if you don't need to upgrade (yet).

Download the Mojarra version to your choice. You need 2 separate JAR files, one with the JSF API (the javax.faces.* classes) and another with the JSF impl (the com.sun.faces.* classes). Scroll to the bottom of the page to pick the newest 2.2.x version. Currently, it's 2.2.8 in flavor of jsf-api-2.2.8.jar and jsf-impl-2.2.8.jar. The following instructions will assume 2.2.8, but you can of course substitute them for newer versions.

The Eclipse IDE is available in several flavors. As we're going to develop Java EE web applications, we need the Java EE variant. It contains among others the invaluable WTP (Web Tools Platform) which eases the development of Java EE web applications. The currently latest version is Eclipse Luna 4.4. This is the first Eclipse version to natively support Java 8 (including the lambda awesomeness).

Click the default mirror or pick a mirror and you will get the file eclipse-jee-luna-R-win32-x86_64.zip (naming may differ per version), save it to disk.

Just unzip it and move the eclipse folder to C:\Java\eclipse.

Open the C:\Java\eclipse\eclipse.ini file for editing. At the bottom you'll see those two lines:

-Xms40m
-Xmx512m

This sets the initial and maximum memory size pool which Eclipse may use (note that this also implicitly applies to any virtual machine which is internally started by Eclipse, such as application servers). This is really way too low when you want to develop an enterprise application. Better set it to 1GB or maybe 2GB if you've plenty of memory. On my laptop with 6GB of RAM, I've personally set it to 1.5GB:

-Xms512m
-Xmx1536m

This way I should be able to run Eclipse with 2 servers simultaneously (thus, three JVMs with together a max of 4.5GB). Watch out that you don't declare more than the available physical memory. When the memory usage exceeds the available physical memory, then it will continue into virtual memory/swapdisk, which will greatly decrease performance and result in major hiccups and slowups.

After starting Eclipse for the first time, we would like to finetune Eclipse a bit so that we don't after all end in trouble and/or annoyances. Eclipse has enormously a lot of settings of which some default values should after all not have been the default values. Here I'll describe only the most useful/important ones.

Run C:\Java\eclipse\eclipse.exe. You will be asked to select a workspace. Point it to C:\Java\workspace. Check if necessary the checkbox to use it as default.

On the welcome screen, click at the icon with the curved arrow at the right top: Go to the workbench.

In the top menu, go to Window » Preferences. This is the preferences dialogue. Configure it as follows:

General

Editors

Text editors: the option Show print margin should be enabled and set to 120 (helpful indicator to not go beyond 120 chars width in code).

Spelling: the option Enable spell checking should be unchecked! This will save you from a big annoyment, because it unnecessarily also spellchecks XML documents like web.xml, faces-config.xml and so on, causing confusing and annoying red underlines over all place.

Workspace: the setting Text file encodingmust be set to UTF-8. This basically enables world domination. Optionally, set New text file line delimiter to Unix. That's prettier when you work regularly on different operating systems (e.g. home/work) via a version control system. Don't do this if you want to be able to edit source code files in Windows Notepad or whatever tool which isn't designed for that ;)

Java

Compiler: the setting Compiler compliance levelmust be set to a minimum of 1.6 in order to use JSF 2.2. Higher is always better. I've just kept it at 1.8.

Errors/warnings: it should be configured as follows (and you should strive to keep your code free of those errors/warnings to achieve high quality code).

Editor

Save actions: it should be configured as follows
With the following Additional actions on top of the defaults, via Configure...:

Code Organizing: Remove trailing whitespace

Code Style: Use blocks in if/while/for/do statements

Member Accesses: Use declaring class as qualifier

Unnecessary code: Remove unused imports

Installed JREs: Add and select the JDK instead of the JRE. This is required by WildFly.

Web

CSS files: the setting Encodingmust be set to UTF-8 (it's the top option)

HTML files: the setting Encodingmust be set to UTF-8 (it's the top option)

Otherwise value expressions which evaluate to java.lang.Object instead of java.lang.Number or java.lang.Boolean would incorrectly show an error in number/boolean comparisons, for example <h:selectBooleanCheckbox binding="#{checkbox}"> and then elsewhere else in the same view <h:someComponent rendered="#{checkbox.value}">. See also this Stack Overflow answer.

We need to familarize Eclipse with any installed application servers so that Eclipse can seamlessly link their Java EE API libraries in the build path (read: the compiletime classpath) of the project. This is mandatory in order to be able to import classes from the Java EE API in your project (you know, the application server is namely the concrete Java EE implementation).

At the bottom box click at the Servers tab to open the servers view.

Click the link which says "No servers are available. Click this link to create a new server...".

Select WildFly 8.x in the list, click Next, Next, and then browse and set the WildFly installation folder C:\Java\wildfly-8.1.0.Final, and make sure that the Runtime JRE is being set to the JDK instead of JRE.

You can start the server by selecting the server entry in the Servers tab and clicking at the green arrow in the toolbar of the box. The Console tab should automatically open and get focus (you can doubleclick the tab to maximize it and bring it back). The server log is shown in there.

Once it is started, go to http://localhost:8080 (where 8080 is the HTTP port as in WildFly config). You should get the default WildFly home page.

You can stop the server by selecting the server entry in the Servers tab and clicking at the red square in the toolbar of the box (note: the Console tab has also such a button, but it doesn't gracefully shutdown the server, instead it immediately terminates the entire JVM/server!).

After stopping, when you're really using JDK8, then you'll see the following line in the log:

Although this warning is harmless, we'd like to get rid of it. Go back to Servers tab and doubleclick the WildFly entry. You'll get the server configuration. Close if necessary the Outline and Task View tabs on the right hand side to get more space. Now, click the Open launch configuration link.

Remove the VM argument -XX:MaxPermSize=256m. That should fix the warning.

Now we can create a "dynamic web project" (basically, a servlet based Java EE project) in Eclipse. We'll in this tutorial not use only JSF, but also take CDI, EJB and JPA along.

At the left box open the Project Explorer tab if not already opened. Rightclick at the box and choose New » Dynamic Web Project.

In the wizard, give it the Project nameplayground, verify if Target Runtime is set to 'WildFly 8.x Runtime' we just created and Dynamic Web Module version is set to '3.1' (this is actually the Servlet API version, Servlet 3.1 is together with JSF 2.2 part of Java EE 7). Under Configuration select '<custom>' and click Modify... Make sure that you select CDI, JSF and JPA and that Java version is set to 1.8 (it defaults namely to 1.7, which actually doesn't harm, but newer is always better and more fun). Now click Next.

In the next page, 'Java', you can configure the source folder and build folder (there where compiled classes will end up in. Just keep it default and click Next.

In the next page, 'JPA Facet', you can configure the JPA provider and DB connection. As WildFly already ships with Hibernate ORM out the box, just keep it default 'Library provided by Target Runtime'. As we're going to use WildFly's embedded H2 database for now, we don't need an external DB connection, so just keep it default '<none>'. Now click Next.

In the next page, 'Web Module', you may change the Context Root to your insight. This becomes the folder after the domain in URL like so 'http://localhost:8080/playground'. This defaults the project name, which is in this case okay. Further, check the checkbox Generate web.xml deployment descriptor to have Eclipse auto-generate the web.xml. Since Servlet 3.0 it is namely optional, but we'd like to have it anyway so that we can configure some more specific JSF settings and the proper welcome file. Now click Next.

In the next page, 'CDI', you can choose to generate beans.xml file or not. Previously, in Java EE 6, CDI was by default disabled if you didn't have that file. However, in Java EE 7, CDI is now by default enabled even when you don't have that file. That file is now only useful for additional and extended configuration for CDI API, such as the web.xml is for Servlet API. Just keep it default and click Next.

In the next page, 'JSF Capabilities', you can configure the JSF implementation. As WildFly already ships with Mojarra out the box as concrete JSF implementation, just keep it default 'Library provided by Target Runtime'. First rename the JSF Servlet Name from Faces Servlet to facesServlet, fully conform Java variable naming conventions. Then, at URL Mapping Patterns, remove the /faces/* and add *.xhtml. Prefix patterns will namely cause lot of maintenance pain. It's best to use suffix patterns like *.jsf or even better *.xhtml. If you have "plain vanilla" XHTML files for which you'd like not to have JSF's FacesServlet to kick in (which is in turn very weird ... shouldn't those be just HTML files?), then you'd better choose *.jsf so that you can still serve XHTML files without that FacesServlet runs on it. In any case, a major advantage of using *.xhtml as mapping pattern is that this is an easy way to avoid that the enduser can see the JSF source code whenever s/he (accidently) opens the page with *.xhtml in the URL while the FacesServlet is mapped on *.jsf. Finally click Finish.

After creation of the web project, you should get a directory structure similar to the screenshot below.

Due to a combination of constraints in the HTTP/HTML/EL specifications, empty HTML input fields are by default treated as empty String. So, when an empty form is submitted, all String properties will be littered with empty strings instead of being kept null. The average (Java) web developer usually dislikes this (so do I). We can fortunately tell JSF to interpret them as null. Open WebContent/WEB-INF/web.xml file, click if necessary the Source tab at the bottom of the editor, and add the following context parameter:

While we're at it, replace all plain JSP/HTML <welcome-file> entries by a single JSF-compatible entry index.xhtml. The "welcome file" must represent the sole filename of the file which the server should lookup in the folder and serve back when the enduser requests an arbitrary folder (including the root folder). Note that this is quite different from "landing page" or "home page" which is what most starters seem to think.

As a quick Hello World test, we'll first create a simple form which also tests the new JSF 2.2 feature of "passthrough attributes", also in more overgeneralized form known as "HTML5 in JSF". Before JSF 2.2, JSF didn't support specifying custom attributes on UI components, which was preventing JSF developers from using new HTML5 attributes like placeholder, autofocus and data-* attributes.

Rightclick on the newly created playground project and choose new » XHTML Page.

Specify the file name index.xhtml and click Next.

Check the checkbox Use XHTML template and select Blank Facelet Page which we just improved in preferences and click Finish.

The index.xhtml file shows up with the JBoss Tools Visual Page Editor which we don't need here. It's not only experimental, but generally visual page editors just doesn't work when you want to end up with quality code. Just click the red cross at the right bottom corner and then click the Source tab and finally close the Palette tab. This is fortunately an one-time thing.

Change the title to Hello World and add the following test form to the body:

Open the Servers tab, rightclick the WildFly entry and choose Add and remove.... Here you can add and remove projects from deployments. Add the playground project right here.

Start the server. Once started, go to http://localhost:8080/playground in your favourite webbrowser (and thus not the Eclipse builtin one!). You should see an input field with a HTML5 placholder and a submit button. When you fill the field and press the button, then you should see Hello, [input field value] on the screen.

Okay, everything works now as to JSF. Now we can advance to the serious work! As an example project, covering most important Java EE aspects, we'll create a CRUD form with a database.

We first need to create the model. In the architectural perspective of a full fledged Java EE application, the "model" is usually represented by JPA entity classes. Those classes usually represent real world data which is often 1:1 mapped to a data store, such as a SQL database. Think of classes like User, Role, Address, Product, Order, Invoice, etcetera. Such a class should be created as a true Javabean. A Javabean is a class which holds properties as private fields which are exposed by public getters and setters. The average IDE such as Eclipse can autogenerate such classes via a wizard. You can of course also create those classes from scratch just "by hand".

...

Sorry, I stumbled upon a writer's block. I'm posting the above anyway so that you have at least a proper basic hello world. It's been unfinished for more than a month already. The advanced one will come later :)

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.