Thursday, December 20, 2012

OmniFaces 1.3 is released!

OmniFaces 1.3 has just been released! It's hopefully on time before end of world ;)

Sorry

Fist of all, OmniFaces 1.2 had some specific problems with processing ajax requests when RichFaces or MyFaces is been used. We just wanted to say "sorry" for any inconvenience caused by that, because this part should better have been tested, although it's after all not exactly our fault.

RichFaces' ExtendedPartialViewContext does (unexpectedly) not extend from PartialViewContextWrapper and hence it was never possible to obtain the wrapped OmniPartialViewContext from it. A reflection hack had to be used to fix that. MyFaces' PartialResponseWriterImpl does (unexpectedly) not use the getWrapped() method to delegate to the wrapped instance, instead it uses the local variable directly. OmniFaces' OmniPartialResponseWriter needs therefore to be changed to override all inherited methods to delegate to the wrapped instance, even though no additional tasks needs to be done (which actually defeats the whole point of the wrapper pattern). This was all fixed in the 1.3 snapshot of 21 November.

Restorable View

Now the Good News: next to a lot of relatively minor functions, a new select items index converter, a new bean validator, a "unique column" validator, a command script (the "standard JSF" variant of the well known PrimeFaces <p:remoteCommand>) and making the combined resource handler compatible with RichFaces resources, there's a completely new addition to the JSF world: the <o:enableRestorableView>.

The <o:enableRestorableView> is particularly useful for JSF web applications where server side state saving is been used. It basically instructs the view handler to recreate the entire view whenever the view has been expired. This effectively prevents ViewExpiredException on the view. This may be very useful on for example a registration or login page which is tied to a request scoped bean. This is also demonstrated as such on the showcase.

There are however (understandable!) technical design limitations: the recreated view is exactly the same as during the initial request, so any modifications which are made thereafter, either by taghandlers or conditionally rendered components based on some view or even session scoped variables, are completely lost. In order to recreate exactly the desired view, you would need to make sure that those modifications are made based on request scoped variables (read: request parameters) instead of view or session scoped variables. In other words, the state of the restorable view should not depend on view or session scoped managed beans, but purely on request scoped managed beans.

Thanks to Mimacom AG

Mimacom AG developers Adrian Gygax and Patrick Dobler have contributed to the biggest part of two new features of OmniFaces: <o:validateBean> and SelectItemsIndexConverter (which are further improved by yours truly). Thank you for your contributions, Adrian and Patrick!

New stuff

Here's a complete overview of all additions, changes and bugfixes in OmniFaces 1.3, see also What's new in OmniFaces 1.3? on the showcase application for links to live demos:


Added in OmniFaces 1.3

  • New Ajax#updateRow() and Ajax#updateColumn() (#82)
  • New <o:enableRestorableView> (#75)
  • New validationFailed attribute for <o:validateXxx> multiple field validators (#91)
  • New <o:validateBean> (#83)
  • New of:formatNumberDefault() (#90)
  • New <o:validateUniqueColumn> (#94)
  • New SelectItemsIndexConverter (#96)
  • New of:joinArray(), of:joinCollection() and of:joinMap() (#104)
  • New message attribute for <o:validator> (#109)
  • New <o:commandScript> (#108)
  • New of:addXxx() functions for date manipulation (#111)
  • New of:xxxBetween() functions for date calculation (#112)
  • New of:getDaysOfWeek() and of:getShortDaysOfWeek() functions for days of week (#58)

Changed in OmniFaces 1.3

  • Changed Html5RenderKit to support autofocus on HtmlCommandButton (#114)
  • Changed CombinedResourceHandler to recognize RichFaces specific resource libraries (#107)

Bugfixed in OmniFaces 1.3

  • Bugfix broken RichFaces PartialViewContext (#89)
  • Bugfix MyFaces issue with OmniPartialResponseWriter#getWrapped() (#99)
  • Bugfix o:tree initial state and tree visit (#105 and #106)

Maven download statistics

For the statsfreaks, here are the download stats from Maven:

  • October 2012: 831 (higher than expected during 1.2 release)
  • November 2012: 1024 (that's a nice geeky count!)

Container independent authentication

Arjan Tijms took for OmniFaces the effort to investigate the feasibility of a container independent JSF authentication module using the relatively unknown JASPIC API. After all, unfortunately, due to some container-specific bugs, JASPIC is not ready yet for inclusion in OmniFaces. Read more at his blog: Implementing container authentication in Java EE with JASPIC.

Wednesday, November 7, 2012

Got some t-shirts

I just got some post from Germany.

That's a nice surprise!

It's from Markus Eisele, who also ever interviewed me.

That's no problem! It's a pretty nice GlassFish t-shirt!

This is the back side.

There was also another shirt inside, an Oracle Open World t-shirt.

Thank you, Markus! :)

Saturday, October 20, 2012

OmniFaces 1.2 is released!

Finally, OmniFaces 1.2 is released! Due to job, holiday and personal circumstances it took one month longer than initially planned. There are relatively a lot of minor but very useful additions, among others the ability to capture <h:outputFormat> result into an EL variable, so that it can be used in a component attribute such as title. The only real major addition is a new PartialViewContext, the OmniPartialViewContext.

This custom PartialViewContext adds the following enhancements to your JSF web application:

  1. Support for programmatically executing callback scripts in ajax response.
  2. Support for programmatically adding arguments to JavaScript scope in ajax response.
  3. Buffers the ajax response fully until buffer size regardless of flush calls and gently closes the XML tags in ajax response in case of exception during ajax render response.
  4. Fixes the no-feedback problem when a ViewExpiredException occurs during an ajax request on a page which is restricted by web.xml <security-constraint>.

Points 1 and 2 are to be achieved by the new Ajax utility class. Note that PrimeFaces indeed offers similar functionality in flavor of RequestContext, but that's thus not available when you are not using PrimeFaces.

Point 3 has the advantage that the entire ajax response can be resetted and replaced by the error page by FullAjaxExceptionHandler and that exceptions during rendering of ajax response can now be properly handled, in both Mojarra and MyFaces.

Point 4 has the advantage that the enduser will now really be redirected to the login page instead of getting no form of feedback at all. More detailed description of the problem and solution can be found in this stackoverflow.com question: ViewExpiredException not thrown on ajax request if JSF page is protected by j_security_check.

Here's a complete overview of all additions, changes and bugfixes in OmniFaces 1.2, see also What's new in OmniFaces 1.2? on the showcase application:

Added in OmniFaces 1.2

  • Character encoding filter
  • Resource handler which replaces resource URLs by CDN URLs
  • Ignore validation failures on submit
  • Store h:outputFormat result in a variable
  • Several of:format() shortcut EL functions to format strings in EL
  • New Ajax utility class to ease programmatically updating components, executing callback scripts and injecting variables in JS scope
  • New OmniPartialViewContext for the Ajax utility class, better exception handling during rendering of ajax response by FullAjaxExceptionHandler and the fix of no-feedback problem when the view is expired during ajax request on a restricted page
  • New multi field validators which validates if "ONLY ONE" or "ONE or NONE" of the given inputs has been filled out
  • New of:formatCurrency() and of:formatNumber() EL functions
  • New generic enum converter for use in UISelectMany components with List<Enum>
  • Some new utility methods in Faces and Components

Changed in OmniFaces 1.2

  • Support to render JS/CSS inline by CombinedResourceHandler
  • Changed generation of combined resource IDs by CombinedResourceHandler so that it's now reversible
  • Improved rendered attribute of o:treeNodeItem so that it can now also see o:tree var/varNode
  • Improved components attribute of multi field validators so that it's resolved relative to parent UINamingContainer instead of to parent UIForm
  • Improved multi field validators to recognize UISelectBoolean components as well
  • Improved FullAjaxExceptionHandler to better handle exceptions during ajax render response phase
  • Improved o:highlight to apply style class on associated labels as well

Bugfixed in OmniFaces 1.2

  • Serialization and state saving issues in o:cache
  • Broken behaviour in MyFaces when using null values in SelectItemsConverter
  • Removed accidently introduced Servlet 3.0 dependency in GzipResponseFilter and improved recognition of non-gzippable responses (content range, etc)
  • Broken behavior of ResetInputAjaxActionListener when both PrimeFaces and RichFaces is used in same webapp

Download statistics

We just wanted to add, OmniFaces 1.1 was far more often been downloaded through Maven than through the Google project page. On the Google project page, OmniFaces 1.1 was been downloaded 557 times since the release. However, through Maven, where the stats are unfortunately not publicly available, OmniFaces 1.1 was been downloaded 418 times in July, 496 times in August and 528 times in September. We don't have statistics for October yet (we guess 400~500 until today), but the total is already 1999 downloads. That's not bad, after all :)

Tuesday, July 10, 2012

OmniFaces 1.1 is released!

Next to some bugfixes and improvements, there are of course several new very useful components and utilities! To name a few toppers which are completely new in the JSF library world: <o:cache>, <o:importConstants> and Html5RenderKit.

Here's a complete overview:

Added in OmniFaces 1.1

  • Rendering specific components by a GET request parameter
  • Form with support to include view parameters in action URL
  • Caching for page fragments with support for scopes, time to live and LRU eviction
  • f:event hook for pre and post invoke action phase
  • GZIP compression filter for HTTP responses
  • of:capitalize() function to capitalize a string
  • HTML5 render kit which adds support for several HTML5 specific attributes to UIForm and UIInput components
  • Importing constant values into EL scope
  • New Messages builder
  • A whole bunch of new utility methods in Faces
  • A new builder in Messages which also allows you to set the message detail
  • New validator which validates if ALL of the given inputs have been filled out
  • Maven integration

Changed in OmniFaces 1.1

  • Support for action components inside o:tree and new TreeModel#remove() and TreeModel#addChildNode() methods
  • Support for web-fragment.xml in FullAjaxExceptionHandler
  • Support to exclude or suppress specific resources in CombinedResourceHandler
  • Support for specific ordering type inside o:validateOrder

Bugfixed in OmniFaces 1.1

  • Broken behaviour inside UIData components in ResetInputAjaxActionListener
  • Incorrect behaviour on synchronous postbacks and NPE on inline scripts in CombinedResourceHandler

New showcase

You can check them all out in the showcase! Note that the showcase web application itself has also retrieved some minor layout improvements, such as a navigation menu hidden behind the header. On for example the <o:cache> page, you can click the "components" header to navigate to other groups and you can click the "cache" header to navigate to other pages in the same group.

Saturday, June 16, 2012

Adding HTML5 attributes to standard JSF components

For OmniFaces I've recently looked for the least intrusive way (i.e. no custom component/tag/renderer boilerplate necessary) to add HTML5 specific <form>, <input>, <textarea> and <select> attributes like placeholder, autofocus, type="range", etcetera. You can learn about all of those new HTML5 attributes in html5tutorial.info under the section "Web Form 2.0". The JSF renderers by default ignores all attributes which are not officially supported by the components.

After some thinking, this appears the best to achieve using a custom RenderKit which returns a custom ResponseWriter wherein the startElement() and writeAttribute() methods are been overridden to check for the current component and if the developer has specified any custom HTML5-related attributes. This way the developer can just add them to standard JSF <h:form>, <h:inputText>, <h:inputTextarea> and <h:selectXxx> components.

Html5RenderKit

The result was a new OmniFaces feature: Html5RenderKit (source code here). This will be available as per OmniFaces 1.1.

To get it to run, register its factory as follows in faces-config.xml:



<factory>
    <render-kit-factory>org.omnifaces.renderkit.Html5RenderKitFactory</render-kit-factory>
</factory>

Here's a demonstration how all those new HTML5 attributes can be used (note that the <h:form> now also supports the autocomplete attribute, in standard JSF 2.0/2.1 this was so far only supported on input components):

<h:form autocomplete="off">
    <h:panelGrid columns="3">
        <h:outputLabel for="text" value="Normal text" />
        <h:inputText id="text" value="#{bean.text1}" />
        <h:outputText value="Supported in all browsers" />
    
        <h:outputLabel for="placeholder" value="With placeholder" />
        <h:inputText id="placeholder" value="#{bean.text2}" placeholder="type here" />
        <h:outputText value="Since Firefox 4, Safari 4, Chrome 10, Opera 11.10 and IE 10" />
    
        <h:outputLabel for="autofocus" value="With autofocus" />
        <h:inputText id="autofocus" value="#{bean.text3}" autofocus="true" />
        <h:outputText value="Since Firefox 4, Safari 5, Chrome 6, Opera 11 and IE 10" />

        <h:outputLabel for="search" value="Search" />
        <h:inputText id="search" type="search" value="#{bean.search}" />
        <h:outputText value="Since Firefox 4, Safari 5, Chrome 6, Opera 10.6 and IE 9" />
    
        <h:outputLabel for="email" value="Email" />
        <h:inputText id="email" type="email" value="#{bean.email}" />
        <h:outputText value="Since Firefox 4, Chrome 6, Opera 10.6 and IE 10" />
    
        <h:outputLabel for="url" value="URL" />
        <h:inputText id="url" type="url" value="#{bean.url}" />
        <h:outputText value="Since Firefox 4, Safari 5, Chrome 6, Opera 10.6 and IE 10" />
    
        <h:outputLabel for="phone" value="Phone" />
        <h:inputText id="phone" type="tel" value="#{bean.phone}" />
        <h:outputText value="Since Firefox 4, Safari 5, Chrome 6, Opera 10.6 and IE 10" />
    
        <h:outputLabel for="range" value="Range (between 1 and 10)" />
        <h:inputText id="range" type="range" value="#{bean.range}" min="1" max="10" />
        <h:outputText value="Since Safari 4, Chrome 6, Opera 11 and IE 10" />
    
        <h:outputLabel for="number" value="Number (between 7 and 13)" />
        <h:inputText id="number" type="number" value="#{bean.number}" min="7" max="13" />
        <h:outputText value="Since Safari 4, Chrome 9 and Opera 11" />
    
        <h:outputLabel for="date" value="Date" />
        <h:inputText id="date" type="date" value="#{bean.date}"
            converterMessage="Format must be yyyy-MM-dd">
            <f:convertDateTime pattern="yyyy-MM-dd" />
        </h:inputText>
        <h:panelGroup>
            <h:outputText value="Since Opera 10.6" 
                rendered="#{not facesContext.validationFailed}" />
            <h:message for="date" />
        </h:panelGroup>
    
        <h:outputLabel for="textarea1" value="Textarea with maxlength of 20" />
        <h:inputTextarea id="textarea1" value="#{bean.text4}" cols="16" maxlength="20" />
        <h:outputText value="Since Firefox 4, Safari 5, Chrome 6, Opera 11 and IE 10" />
    
        <h:outputLabel for="textarea2" value="Textarea with placeholder" />
        <h:inputTextarea id="textarea2" value="#{bean.text5}" cols="16" placeholder="some text" />
        <h:outputText value="Since Firefox 4, Safari 5, Chrome 10, Opera 11.50 and IE 10" />
    
        <h:panelGroup />
        <h:commandButton value="submit">
            <f:ajax execute="@form" render="@form" />
        </h:commandButton>
        <h:panelGroup>
            <h:outputText value="OK!"
                rendered="#{facesContext.postback and not facesContext.validationFailed}" />
        </h:panelGroup>
    </h:panelGrid>
</h:form>

With this backing bean:

@ManagedBean
@ViewScoped
public class Bean implements Serializable {

    private String text1;
    private String text2;
    private String text3;
    private String search;
    private String email;
    private String url;
    private String phone;
    private Integer range;
    private Integer number;
    private Date date;
    private String text4;
    private String text5;

    // Add/generate getters/setters.
}

Here's a screenshot of how it look like in Chrome 19:

Friday, June 1, 2012

OmniFaces 1.0 is released!

After a long time of collecting and developing helpful utility methods and components, taking benefit of lessons learnt during ages of professional JSF development, reading stackoverflow.com for frequently recurring peculiar JSF problems, finding reuseable solutions for those problems, testing everything on both Mojarra and MyFaces, working through reported issues, we, me and Arjan Tijms, can now proudly announce that OmniFaces 1.0 is ready for release!

omnifaces-1.0.jar

The last major addition is the FacesViews feature, an idea of Arjan Tijms, which allows using extensionless URLs. Long story short, here's a link to the FacesViews guide and the showcase demo.

OmniFaces 1.0 Initial features

Here's an overview of what's all available in OmniFaces 1.0:

  • Conditional comment rendering for IE
  • Highlighting fields that failed validation
  • Executing scripts on load of every (ajax) response
  • OutputLabel automatically setting label of associated input component
  • Include Servlets and JSP pages in Facelets
  • Tree with full custom markup per level (useable for various recursive use cases)
  • Stateless view parameter
  • Automatic conversion of model objects in drop-downs and other select components.
  • Simplified PhaseListener requiring less boiler plate
  • Reset for input fields making them always updateable via ajax
  • Ajax aware exception handler
  • Extensionless URLs without need to register individual pages
  • Proper 404 for FacesFileNotFoundException
  • HttpFilter convenience class as analogy to HttpServlet
  • Collections of EL functions for dealing with arrays, conversion, dates and strings
  • Convenience managed beans for the current time and server startup time
  • Combining separate scripts and stylesheets to reduce HTTP requests
  • Render-time evaluation for f:converter and f:validator attributes
  • Passing a method expression into Facelets tag
  • Collection of Java methods for dealing with components, events, exceptions, messages and JSF in general
  • Checkbox with required attribute that works intuitively
  • Multi-field validators, for "all or none", "all equal", "one or more", "all in order" and "unique" validations

You can find demonstrations of practically everything on the showcase site.

This is not the end. We still have more ideas on our list, which we would like to implement in future versions. However, none of them are really trivial. For example, client+server side double submit prevention which handles responses properly, some sort of a session timeout checker, a component which makes it possible to invoke a bean action before unload, a component which caches the generated HTML output in the specified scope for a specified time, a component which simplifies usage of HTML5 localstorage feature from JSF on, some components which should simplify container managed login/logout in JSF, etcetera.

Friday, March 16, 2012

Reset non-processed input components on ajax update

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:


<style>.error { background-color: #fee; }</style>
<h:form id="form1">
    <p>input1: Enter something (but don't enter "Updated!").</p>
    <p>
        <h:inputText id="input1" value="#{bean.input1}" required="true"
                     styleClass="#{component.valid ? '' : 'error'}" />
        <h:message for="input1" errorClass="error" />
    </p>
    <p>input2: Leave this field empty or enter a non-numeric value to cause a validation failure.</p>
    <p>
        <h:inputText id="input2" value="#{bean.input2}" required="true"
                     styleClass="#{component.valid ? '' : 'error'}" />
        <h:message for="input2" errorClass="error" />
    </p>
    <p>Press "submit" and then "update". The "update" simulates changing model values externally.</p>
    <p>
        <h:commandButton value="Submit" action="#{bean.submit}">
            <f:ajax execute="@form" render="@form" />
        </h:commandButton>
        <h:commandButton value="Update" action="#{bean.update}">
            <f:ajax execute="@this" render="@form" />
        </h:commandButton>
    </p>
</h:form>

With this bean:


@ManagedBean
@ViewScoped
public class Bean {

    private String input1;
    private Integer input2;

    public void submit() {
        //
    }

    public void update() {
        input1 = "Updated!";
        input2 = 42;
    }

    // Getters/setters.
}

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.

OmniFaces to the rescue

OmniFaces has recently got a ResetInputAjaxActionListener which solves exactly this problem (source code here).

If you register it as <action-listener> in faces-config.xml, or add it as <f:actionListener> to the update command button as follows,


    <h:commandButton value="Update" action="#{bean.update}">
        <f:ajax execute="@this" render="@form" />
        <f:actionListener type="org.omnifaces.eventlistener.ResetInputAjaxActionListener" />
    </h:commandButton>

Then this problem will completely disappear. The principle is rather simple, here's a (simplified) extract of relevance from its source code:


FacesContext context = FacesContext.getCurrentInstance();
PartialViewContext partialViewContext = context.getPartialViewContext();

if (!partialViewContext.isAjaxRequest()) {
    return; // Ignore synchronous requests. All executed and rendered inputs are the same anyway.
}

Collection<String> renderIds = partialViewContext.getRenderIds();

if (renderIds.isEmpty()) {
    return; // Nothing to render, thus also nothing to reset.
}

UIViewRoot viewRoot = context.getViewRoot();
Set<EditableValueHolder> inputs = new HashSet<EditableValueHolder>();

// First find all to be rendered inputs and add them to the set.
for (String renderId : renderIds) {
    findAndAddEditableValueHolders(viewRoot.findComponent(renderId), inputs);
}

// Then find all executed inputs and remove them from the set.
for (String executeId : partialViewContext.getExecuteIds()) {
    findAndRemoveEditableValueHolders(viewRoot.findComponent(executeId), inputs);
}

// The set now contains inputs which are to be rendered, but which are not been executed. Reset them.
for (EditableValueHolder input : inputs) {
    input.resetValue();
}

Friday, March 9, 2012

Vdldoc - The Facelets .taglib.xml generator

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 :)

Monday, March 5, 2012

Stateless view parameter

The JSF 2.0 <f:viewParam> tag is a very useful tag which allows you to set GET request parameters as model values of a managed bean. You can even convert and validate them before it get set in the model. See also Communication in JSF 2.0 - Processing GET request parameters.

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


    <f:metadata>
        <f:viewParam name="id" value="#{users.user}"
            converter="#{userConverter}" converterMessage="Bad request. Unknown user."
            required="true" requiredMessage="Bad request. Please use a link from within the system."
        />
    </f:metadata>

use


    <f:metadata>
        <o:viewParam name="id" value="#{users.user}"
            converter="#{userConverter}" converterMessage="Bad request. Unknown user."
            required="true" requiredMessage="Bad request. Please use a link from within the system."
        />
    </f:metadata>

As a bonus, the label attribute will also default to the name attribute instead of the client ID whenever the label attribute is not specified. The name attribute is a more sane default for this.

Saturday, March 3, 2012

Full ajax exception handler

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:

<error-page>
    <error-code>500</error-code>
    <location>/errors/500.xhtml</location>
</error-page>
<error-page>
    <exception-type>javax.faces.application.ViewExpiredException</exception-type>
    <location>/errors/expired.xhtml</location>
</error-page>

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.

OmniFaces to the rescue

Ideally, JSF should just show the error page in its entirety. This is possible with a custom ExceptionHandler. The OmniFaces project has recently got such an exception handler, written by yours truly, the FullAjaxExceptionHandler (source code here). All you need to do is to register the FullAjaxExceptionHandlerFactory (source code here) in faces-config.xml as follows:

<factory>
    <exception-handler-factory>
        org.omnifaces.exceptionhandler.FullAjaxExceptionHandlerFactory
    </exception-handler-factory>
</factory>

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:

// Set the necessary servlet request attributes which a bit decent error page may expect.
final HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
request.setAttribute(ATTRIBUTE_ERROR_EXCEPTION, exception);
request.setAttribute(ATTRIBUTE_ERROR_EXCEPTION_TYPE, exception.getClass());
request.setAttribute(ATTRIBUTE_ERROR_MESSAGE, exception.getMessage());
request.setAttribute(ATTRIBUTE_ERROR_REQUEST_URI, request.getRequestURI());
request.setAttribute(ATTRIBUTE_ERROR_STATUS_CODE, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);

// Force JSF to render the error page in its entirety to the ajax response.
context.setViewRoot(context.getApplication().getViewHandler().createView(context, errorPageLocation));
context.getPartialViewContext().setRenderAll(true);
context.renderResponse();

// Prevent some servlet containers from handling the error page itself afterwards. So far Tomcat/JBoss
// are known to do that. It would only result in IllegalStateException "response already committed".
Events.addAfterPhaseListener(PhaseId.RENDER_RESPONSE, new Runnable() {
    @Override
    public void run() {
        request.removeAttribute(ATTRIBUTE_ERROR_EXCEPTION);
    }
});

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:

<ul>
    <li>Date/time: #{of:formatDate(now, 'yyyy-MM-dd HH:mm:ss')}</li>
    <li>HTTP user agent: #{header['user-agent']}</li>
    <li>Request URI: #{requestScope['javax.servlet.error.request_uri']}</li>
    <li>Status code: #{requestScope['javax.servlet.error.status_code']}</li>
    <li>Exception type: #{requestScope['javax.servlet.error.exception_type']}</li>
    <li>Exception message: #{requestScope['javax.servlet.error.message']}</li>
    <li>Exception stack trace: 
        <pre>#{of:printStackTrace(requestScope['javax.servlet.error.exception'])}</pre>
    </li>
</ul>

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}.

Update: the FullAjaxExceptionHandler can be tried live on the new showcase site!

But it does not work with PrimeFaces actions! (update: from 3.2 on, it will!)

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):

var originalPrimeFacesAjaxResponseFunction = PrimeFaces.ajax.AjaxResponse;
PrimeFaces.ajax.AjaxResponse = function(responseXML) {
  var newView = $(responseXML.documentElement).find("update[id='javax.faces.ViewRoot']").text();

  if (newView) {
    $('head').html(newView.substring(newView.indexOf("<head>") + 6, newView.indexOf("</head>")));
    $('body').html(newView.substring(newView.indexOf("<body>") + 6, newView.indexOf("</body>")));
  }
  else {
    originalPrimeFacesAjaxResponseFunction.apply(this, arguments);
  }
};

Update: the PrimeFaces support for update="@all" will be available with 3.2, great job, Optimus Prime!

Thursday, March 1, 2012

The OmniFaces project has started

Together with my colleague Arjan Tijms, who you shall probably also know from stackoverflow.com and from the majority of the JSF related blogs at jdevelopment.nl, the project OmniFaces has been started.

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:

Tree

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>.


<o:tree value="#{treeDemo.menu}" var="page">
    <o:treeNode level="0">
        <o:treeNodeItem>
            <h3><a href="#{page.url}">#{page.title}</a></h3>
            <o:treeInsertChildren />
        </o:treeNodeItem>
    </o:treeNode>
    <o:treeNode>
        <ul>
            <o:treeNodeItem>
                <li>
                    <a href="#{page.url}">#{page.title}</a>
                    <o:treeInsertChildren />
                </li>
            </o:treeNodeItem>
        </ul>
    </o:treeNode>      
</o:tree>

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.

Here's what the Page bean look like:

public class Page {

    private String url;
    private String title;

    public Page(String url, String title) {
        this.url = url;
        this.title = title;
    }

    // Getters/setters.
}

Here's what the backing bean look like:

public class TreeDemo {

    private TreeModel<Page> menu;

    @PostConstruct
    public void init() {
        menu = new ListTreeModel<Page>();
        TreeModel<Page> general = menu.addChild(new Page("general.xhtml", "General"));
        TreeModel<Page> components = menu.addChild(new Page("components.xhtml", "Components"));
        TreeModel<Page> help = menu.addChild(new Page("help.xhtml", "Help"));

        TreeModel<Page> aboutUs = general.addChild(new Page("aboutus.xhtml", "About us"));
        TreeModel<Page> location = general.addChild(new Page("location.xhtml", "Location"));
        TreeModel<Page> contact = general.addChild(new Page("contact.xhtml", "Contact"));

        TreeModel<Page> tree = components.addChild(new Page("tree.xhtml", "Tree"));
        TreeModel<Page> validators = components.addChild(new Page("validators.xhtml", "Validators"));

        TreeModel<Page> allOrNone = validators.addChild(new Page("allOrNone.xhtml", "All or None"));
        TreeModel<Page> oneOrMore = validators.addChild(new Page("oneOrMore.xhtml", "All or None"));
        TreeModel<Page> allEqual = validators.addChild(new Page("allEqual.xhtml", "All equal"));
        TreeModel<Page> allUnique = validators.addChild(new Page("allUnique.xhtml", "All unique"));
    }

    public TreeModel<Page> getMenu() {
        return menu;
    }

}

Here's what the generated HTML output look like:


<h3><a href="general.xhtml">General</a></h3>
<ul>
    <li>
        <a href="aboutus.xhtml">About us</a>
    </li>
    <li>
        <a href="location.xhtml">Location</a>
    </li>
    <li>
        <a href="contact.xhtml">Contact</a>
    </li>
</ul>

<h3><a href="components.xhtml">Components</a></h3>
<ul>
    <li>
        <a href="tree.xhtml">Tree</a>
    </li>
    <li>
        <a href="validators.xhtml">Validators</a>
        <ul>
            <li>
                <a href="allOrNone.xhtml">All or None</a>
            </li>
            <li>
                <a href="oneOrMore.xhtml">All or None</a>
            </li>
            <li>
                <a href="allEqual.xhtml">All equal</a>
            </li>
            <li>
                <a href="allUnique.xhtml">All unique</a>
            </li>
        </ul>
    </li>
</ul>

<h3><a href="help.xhtml">Help</a></h3>

For the fans of chaining, it's also possible to create the tree model by chaining:


@PostConstruct
public void init() {
    menu = new ListTreeModel<Page>();
    menu.addChild(new Page("general.xhtml", "General"))
            .addChild(new Page("aboutus.xhtml", "About us")).getParent()
            .addChild(new Page("location.xhtml", "Location")).getParent()
            .addChild(new Page("contact.xhtml", "Contact")).getParent().getParent()
        .addChild(new Page("components.xhtml", "Components"))
            .addChild(new Page("tree.xhtml", "Tree")).getParent()
            .addChild(new Page("validators.xhtml", "Validators"))
                .addChild(new Page("allOrNone.xhtml", "All or None")).getParent()
                .addChild(new Page("oneOrMore.xhtml", "All or None")).getParent()
                .addChild(new Page("allEqual.xhtml", "All equal")).getParent()
                .addChild(new Page("allUnique.xhtml", "All unique")).getParent().getParent().getParent()
        .addChild(new Page("help.xhtml", "Help"));
}

Multi field validators

There are five special validators for multiple input fields:

Here is an extract of relevance from the ValidateMultipleFields javadoc:

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.

<o:validateMultipleFields id="myId" components="foo bar baz" />
<h:message for="myId" />
<h:inputText id="foo" />
<h:inputText id="bar" />
<h:inputText id="baz" />

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.

<o:validateMultipleFields components="foo bar baz" message="{0} are wrong!" />

The faces message can also be shown for all of the referenced components using showMessageFor="@all".

<o:validateMultipleFields components="foo bar baz" message="This is wrong!" showMessageFor="@all" />
<h:inputText id="foo" />
<h:message for="foo" />
<h:inputText id="bar" />
<h:message for="bar" />
<h:inputText id="baz" />
<h:message for="baz" />

The showMessageFor attribute defaults to @this. Other values than @this or @all are not allowed.

Let's look how <o:validateEqual> is useful for password confirmation validation, for example:


<h:panelGrid columns="3">
    ...

    <h:outputLabel for="password" value="Enter password" />
    <h:inputSecret id="password" value"#{register.user.password}" redisplay="true" required="true"
        requiredMessage="Please enter password" />
    <h:panelGroup>
        <h:message for="password" />
        <h:message for="equal" />
    </h:panelGroup>
    
    <h:outputLabel for="confirm" value="Confirm password" />
    <h:inputSecret id="confirm" redisplay="true" required="true"
        requiredMessage="Please confirm password" />
    <h:panelGroup>
        <h:message for="confirm" />
        <o:validateEqual id="equal" components="password confirm" 
            message="Passwords are not equal" />
    </h:panelGroup>

    ...
</h:panelGrid>

<h:commandButton value="submit" action="#{register.submit}">
    <f:ajax execute="@form" render="@form" />
</h:commandButton>

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:


<h:panelGrid columns="3">
    ...

    <h:outputLabel for="startDate" value="Start date" />
    <h:inputText id="startDate" value"#{booking.reservation.startDate}" required="true"
        requiredMessage="Please enter start date"
        converterMessage="Please enter format yyyy-MM-dd">
        <f:convertDateTime pattern="yyyy-MM-dd" />
    </h:inputText>
    <h:message for="startDate" />
    
    <h:outputLabel for="endDate" value="End date" />
    <h:inputText id="endDate" value"#{booking.reservation.endDate}" required="true"
        requiredMessage="Please enter end date"
        converterMessage="Please enter format yyyy-MM-dd">
        <f:convertDateTime pattern="yyyy-MM-dd" />
    </h:inputText>
    <h:panelGroup>
        <h:message for="endDate" />
        <h:message for="order" />
        <o:validateOrder id="order" components="startDate endDate" 
            message="End date must be after start date" />
    </h:panelGroup>

    ...
</h:panelGrid>

<h:commandButton value="submit" action="#{booking.submit}">
    <f:ajax execute="@form" render="@form" />
</h:commandButton>

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.

Select items converter

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".


<h:selectOneMenu value="#{bean.selectedEntity}" converter="omnifaces.SelectItemsConverter">
    <f:selectItems value="#{bean.availableEntities}" var="entity" 
        itemValue="#{entity}" itemLabel="#{entity.someProperty}" />
</h:selectOneMenu>

Where the bean can look like this:


private Entity selectedEntity;
private List<Entity> availableEntities;

// Getters+setter.

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.

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.FacesConverter;

import org.omnifaces.converter.SelectItemsConverter;

@FacesConverter("entitySelectItemsConverter")
public class EntitySelectItemsConverter extends SelectItemsConverter {

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        Long id = ((Entity) value).getId();
        return (id != null) ? String.valueOf(id) : null;
    }

}

Note that you do not need to override getAsObject()!

To get it to work, just change the converter attribute in the above example to point to your custom converter in question.


<h:selectOneMenu value="#{bean.selectedEntity}" converter="entitySelectItemsConverter">
    <f:selectItems value="#{bean.availableEntities}" var="entity" 
        itemValue="#{entity}" itemLabel="#{entity.someProperty}" />
</h:selectOneMenu>

Notice

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.