Friday, March 16, 2012

Introduction

When JSF validation has failed for a particular form submit and you happen to need to update the values of invalidated input fields later by a different ajax action or even a different ajax form (e.g. populating a field depending on a dropdown selection or the result of some modal dialog form, or clearing out all values with some clear action, etc), then you basically need to reset the target input components in order to get JSF to display the model value which was edited during invoke action. Otherwise JSF will still display its local value as it was during the validation failure and keep them in an invalidated state.

This problem is the easiest to understand if you see it yourself. Use this simple testcase view:

Problem: input1 is not updated with text "Updated!" and input2 is still marked invalid! The problem can be understood by the following JSF facts:

When JSF validation succeeds for a particular input component during the validations phase, then the submitted value is set to null and the validated value is set as local value of the input component.

When JSF validation fails for a particular input component during the validations phase, then the submitted value is kept in the input component.

When at least one input component is invalid after the validations phase, then JSF will not update the model values for any of the input components. JSF will directly proceed to render response phase.

When JSF renders input components, then it will first test if the submitted value is not null and then display it, else if the local value is not null and then display it, else it will display the model value.

As long as you're interacting with the same JSF view, you're dealing with the same component state.

Ideally, when JSF needs to update/re-render an input component by an ajax request, and that input component is not included in the process/execute of the ajax request, then JSF should reset the input component's value. This has been requested as JSF spec issue 1060.

Friday, March 9, 2012

VDL documentation

For the new OmniFaces project we would of course also like to generate VDL documentation so that at least the developers have a good reference about all available tags and functions. The API javadocs were no problem, just the existing Java 7 javadoc tool was sufficient. It generated nice documentation in Java 7 javadoc look'n'feel.

But there was no documentation generator for Facelets .taglib.xml files.

I looked at how JSF guys did it. They just used old style JSP .tld files and have not yet migrated to .taglib.xml files. They used the old JSP TLDDoc generator which was previously available at http://taglibdoc.dev.java.net, but is now nowhere available anymore (the JARs are of course still available at online code repositories). I looked at how RichFaces guys did it. They have .taglib.xml files only, but managed to have TLDDoc-generated tag documentation. I think they were using modified XSL templates for TLDDoc. I looked at how PrimeFaces did it, but it has only a PDF file which is at its own very nice but pretty a lot of work.

As to existing projects, there seems to be only a facelet-doc project on java.net, but it was not obvious how to use it and the project seems to be still unfinished and have bleeded to death.

Vdldoc!

So I decided to fork TLDDoc and rewrite the source code and XSL templates to be able to parse Facelets .taglib.xml files and generate real VDL documentation in nice Java 7 look'n'feel. And Vdldoc was born!

Hopefully it was worth the effort. I have also tested it on PrimeFaces and RichFaces .taglib.xml files and it has generated very nice docs for them :)

However, in combination with view scoped beans, it has one disadvantage. When you perform a postback on the same view, then the initial GET request parameter get converted and validated again based on the submitted value which was saved in the view state (the initial GET request parameter is namely not available anymore in the postback request). When the conversion is performed through a service/DAO method based on some entity ID as request parameter, then that service/DAO method would be invoked again during the postback, which is completely unnecessary in case of a view scoped bean.

The solution is simple: just make the <f:viewParam> tag stateless as to the submitted value! If it becomes null, then it won't be set in the model anyway. On jdevelopment.nl you can find a more in depth explanation about this. Arjan Tijms has extended the UIViewParameter component to achieve this functionality into a new OmniFaces<o:viewParam> tag (source code here).

The usage is simple, just replace f: tag prefix by o: tag prefix. So, instead of

Saturday, March 3, 2012

Whenever some business code throws an unhandled exception, due to some unexpected environmental situation (e.g. DB down), or due to session expiration (ViewExpiredException), or due to some overseen bug (fix it asap!), it usually ends up in a HTTP 500 error page or some exception-specific error page, which you can in any way customize according the standard Servlet API rules by a <error-page> in web.xml as follows:

However, the error page does not show up at all whenever the exception occurs during a JSF ajax request. In Mojarra, only when the javax.faces.PROJECT_STAGE is set to Development, a bare JavaScript alert dialogue will show up, with only the exception type and message. This may be helpful for developers and testers during development stage, but this alert does thus not show up in Production project stage. The enduser would not get any feedback if the action was successfully performed or not. This is quite frustrating. Also for the developer.

This exception handler factory will register the FullAjaxExceptionHandler which will handle exceptions on ajax requests.

The exception handler will parse the web.xml to find the error page locations of the HTTP error code 500 and all exception types. You only need to make sure that those locations point each to a Facelets file. The location of the HTTP error code 500 or the exception type java.lang.Throwable is required to have at least a fallback error page if none of the specific exception types are matched.

The exception handler will set all error details in the request scope by the standard servlet error request attributes like as in a normal synchronous HTTP 500 error page response. This way the error pages are fully reuseable for both normal and ajax requests. Finally it will create a new UIViewRoot on the error page location and force a partial render of @all. Here's an extract of relevance from the source code:

Note the last part. Tomcat and JBoss seem to automatically trigger the default HTTP 500 error page mechanism after JSF has done its job. It turns out that it was triggered by the presence of the javax.servlet.error.exception request attribute, regardless of if it was been set by response.sendError(). Although that would not harm, the response is namely already committed by JSF, but it would clutter your server logs with an IllegalStateException: response already committed every time when the exception handler does its job. Hence the piece of code which removes the request attribute after the render response phase.

Finally, you could show all error details in the error page the usual way as follows:

When using OmniFaces, the #{of:xxx} functions are available by the http://omnifaces.org/functions namespace. Also, when using OmniFaces the java.util.Date representing the current timestamp is implicitly available by #{now}.

Indeed, PrimeFaces does not support a render/update of @all. Here's a cite of Optimus Prime himself:

PrimeFaces does not support update="@all" because update="@all" is fundamentally wrong.

I agree with him to a certain degree. In case of successful requests, it does indeed not make any sense. You would as good just send a normal/synchronous request instead of an ajax/asynchronous request. But in case of failed requests it would have been very useful. Of course, you could send a redirect instead by ExternalContext#redirect(), that would work perfectly fine, but you would lose all request attributes, including the error details. It is really not preferable to fiddle with the session scope or maybe even the flash scope to get them to show up in the error page.

Fortunately, there's a simple way to get PrimeFaces to support @all. Just add the following piece of JavaScript code to your global JavaScript file which should be loaded after PrimeFaces' own scripts (just referencing it by <h:outputScript> ought to be sufficient):

OmniFaces is a library for JSF 2.x that focusses on utilities that ease everyday tasks. An important design goal will be to have as few dependencies as possible (so far, it only requires JSF 2.0, EL 2.1 and Servlet 2.5 APIs which is already minimally available in a bit modern container serving a JSF 2.0 web application) and to be minimally invasive. As such, OmniFaces should principally integrate perfectly well with most other JSF libraries. Characteristic of OmniFaces will be that it will not just be about components, but instead will have an equally strong focus on providing utility classes for working with the JSF API from Java code.

OmniFaces is still under development, but so far among others the following components are available:

The <o:tree> allows you to render a markup-less tree wherein you have the freedom to declare markup, such as <ul><li>. You can give every individual node level its own markup. Here's an example of a menu wherein the first level (with a value of 0) is been rendered as a <h3> and all of its children are rendered as nested <ul><li>.

The <o:treeNode> gives you the space to write markup around a single tree node. The level attribute specifies for which level the tree node should be rendered. In the above example, the content of <o:treeNode level="0"> will only be rendered for all tree nodes of the first level and the content of the level-less <o:treeNode> will be rendered for tree nodes of all other levels. The <o:treeNodeItem> gives you the space to write markup around every single child of the current tree node. The <o:treeInsertChildren> indicates the insertion point where the <o:treeNode> associated with the child's level must be rendered.

General usage of all multiple field validators

This validator must be placed inside the same UIForm as the UIInput components in question.
The UIInput components must be referenced by a space separated collection of their client IDs in the
components attribute. This validator can be placed anywhere in the form, but keep in mind that the
components will be validated in the order as they appear in the form. So if this validator is been placed before all
of the components, then it will be executed before any of the component's own validators. If this validator fails,
then the component's own validators will not be fired. If this validator is been placed after all of the components,
then it will be executed after any of the component's own validators. If any of them fails, then this validator
will not be exeucted. It is not recommended to put this validator somewhere in between the referenced components as
the resulting behaviour may be confusing. Put this validator either before or after all of the components, depending
on how you would like to prioritize the validation.

In an invalidating case, all of the referenced components will be marked invalid and a faces message will be added
on the client ID of this validator component. The default message can be changed by the message
attribute. Any "{0}" placeholder in the message will be substituted with a comma separated string of labels of the
referenced input components.

If none of the fields are filled out, the component's own required validators will fire and the equal validator will not fire. If both fields are filled out and not equal, then the equal validator will fire and show the message on the <h:message> associated with its own ID.

Here's another example how the <o:validateOrder> is useful for start date - end date validation, for example:

If none of the fields are filled out or filled out with invalid date format, then the component's own converter and required validators will fire and the order validator will not fire. If both fields are filled out with valid date formats but not in order, then the equal validator will fire and show the message on the <h:message> associated with its own ID.

The SelectItemsConverter, written by Arjan Tijms, allows the developer to use complex objects like entities as the value of <f:selectItems>without the need to implement a custom converter which calls some DAO/service method to obtain the associated entity by for example its ID as submitted string value. The converter converts the submitted value based on the already-available values in the <f:selectItems>. The conversion is by default based on the toString() representation of the entity which is supposed to already return an unique enough representation.

All you need to do is to specify the converter as converter="omnifaces.selectItemsConverter".

You can always extend the SelectItemsConverter class to offer a custom getAsString() implementation which returns for example entity.getId() instead of the default entity.toString() which may in case of some entities be unnecessarily long.

The OmniFaces component library is still in early development! Although we strive to full backwards compatibility, there will until the first stable 1.0 release be no guarantee that no changes will be made to the class names, tag names, attibute names, EL function names, the general behaviour and so forth.

This blog is purely informal so that you can check/try them out and/or leave feedback. Important issues can be reported to the OmniFaces issue list.

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.