Showing posts with label Validator. Show all posts
Showing posts with label Validator. Show all posts

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.

Monday, January 31, 2011

JSF 2.0 tutorial with Eclipse and Glassfish

WARNING - OUTDATED CONTENT!

There is a newer JSF 2.3 tutorial out with Eclipse / Maven / WildFly / H2.

Introduction

In this tutorial you will learn how to setup a JSF 2.0 (Mojarra) playground with Eclipse 3.6 SR1 (Helios) and Oracle Application Server v3 (Glassfish).

There are also another IDE's 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 enough 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 Oracle Glassfish, e.g. JBoss Application Server, Apache Tomcat, etcetera. The choice for Glassfish is made because it ships as being a full fledged Java EE 6 application server already with JSF builtin and offers builtin support for lot of other handy Java EE aspects like JPA for database connectivity, EJB for business services, JSR303 for bean validation, CDI for dependency injection, etcetera. Also, in combination with the current Eclipse plugin, it allows for extremely fast development. Not only Glassfish starts up relatively quick, but it is able to hotdeploy code changes in a subsecond. It's certainly an improvement as compared to its predecesor, Glassfish v2. In the 3-year old JSF 1.2 tutorial, Apache Tomcat was been used. One of the reasons to prefer Tomcat over Glassfish v2 was the lack of a good Eclipse plugin for Glassfish back then in 2008.

Back to top

Preparing

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.

Back to top

Download and install Java SE 6 JDK

The Java SE 6 JDK contains both the runtime (JRE, java.exe) and the compiler (JDK, javac.exe) for the standard Java API.

You can skip this part if you already have downloaded/installed Java SE 6 JDK.

  1. Surf to the Java SE 6 download page.
  2. You'll see four big buttons next to each other, press the leftmost one, which says just 'Java'.
  3. Accept the License Agreement and choose the right file for your platform. For Windows x64 for example you will get the file jdk-6u23-windows-x64.exe (naming may differ per version), save it to disk.
  4. Install the JDK and JRE in C:\Java\jdk1.6.0_23 and C:\Java\jre1.6.0_23 respectively (or in their default paths, if you want).
Back to top

Download and install Java EE 6 Web Profile SDK

The Java EE 6 covers the enterprise Java API. This is basically an abstract API for which Glassfish is one of the concrete implementations. Actually, Glassfish is the reference implementation. The Java EE 6 Web Profile is a specified part of the huge Java EE 6 API which includes the minimum necessary API's required for Java web development: the Servlet 3.0 API, JSF 2.0 API, JPA 2.0 API and EJB 3.1 Lite. Note that Apache Tomcat 7.0 only includes Servlet 3.0 API.

You can also consider to pick the standard (full) profile. It's only too heavy-weight since it contains API components which are (possibly) not of your interest like EJB (full), JAX-WS, JAXB, JMS, JACC, JAX-RPC, JAXR, etcetera. It causes Glassfish to start slower as compared to the lightweight web profile, sometimes very noticeably slower. The web profile starts in only a few seconds. You can find an overview of differences halfway the download page of the Glassfish development site.

You can skip this part if you already have downloaded/installed Glassfish, even though you did it by their development site.

  1. Surf to the Java EE 6 download page.
  2. You'll see four big buttons next to each other, press the rightmost one, which says 'Java EE 6 Web Profile SDK'.
  3. Choose Platform/Language, accept the License Agreement and press the Continue button.
  4. In the section 'Available Files', click at the link below 'Java EE 6 Web Profile SDK Update 1', you will get the file java_ee_sdk-6u1-web-windows.exe (naming may differ per version), save it to disk.
  5. Install Glassfish in C:\Java\glassfishv3 and walk through the remnant of the wizard. Just with default settings is fine. You may possibly get a firewall warning whenever you go to the next step after setting the ports (the installer is just testing them). Just let the firewall allow access. Don't forget to remember the admin username and password for the case that you've changed them!


Note that you may possibly get the error 'This application needs version 1.6 or higher of the Java 2 Runtime Environment.' when executing the installer. In this case, your best bet is to try reinstalling the JRE (not the JDK!) which you can download from java.com. In the latest Java 1.6 releases, there's apparently a little difference in how the JDK/JRE installers configures the necessary registry keys and DLL's in Windows. Just reinstall JRE from java.com in the same folder. During auto-uninstalling the original JRE, you'll possibly get warnings that msvcr71.dll is missing, just ignore it and go ahead (it's may namely be exactly that file which was broken in the original JRE install!).

Back to top

Download and install Eclipse Helios 3.6 SR1

The Eclipse IDE is available in several tastes. 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 Helios 3.6 SR1.

  1. Surf to the Eclipse download page.
  2. Click at the Eclipse IDE for Java EE Developers link.
  3. On the right hand menu, pick the platform version.
  4. Click the default mirror or pick a mirror and you will get the file eclipse-jee-helios-SR1-win32-x86_64.zip (naming may differ per version), save it to disk.
  5. Extract the zip and move the child directory \eclipse to C:\Java\eclipse.
Back to top

Run and configure Eclipse

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.

  1. Run C:\Java\eclipse\eclipse.exe. You will be asked to select a workspace. Point it to C:\Java\workspace.
  2. On the welcome screen, click at the icon with the curved arrow at the right top: Go to the workbench.
  3. In the top menu, go to Window » Preferences. This is the preferences dialogue.
  4. You want world domination, so enter 'encoding' in the 'type filter text' input field on the left top. On every section, change the encoding from default (often cp1252 or ISO 8859-1) to UTF-8.
  5. In the Preferences dialogue, clear if necessary first the entered filter text, then go to General » Editors » Text Editors » Spelling and disable it. Really. It will save you from a big annoyment, because it also unnecessarily spellchecks XML documents like web.xml, faces-config.xml and on.
  6. In the Preferences dialogue, go to Web » JavaServer Faces Tools » Validation and in the section Type Assignment Problems set Method expression signature incompatibility to Warning or Ignore if you want to allow JSF action methods return void. I also recommend to set the Unary operation number (and boolean) coercion problems in the section Type Coercion Problems to Warning or Ignore, because it would unnecessarily give an error when you're using for example UIComponent#getValue() -which has Object type outcome- in EL but you treated it as number or boolean.
  7. In the Preferences dialogue, go to Web » HTML Files » Editor » Templates and click New. Enter name New Facelet Page, select context New HTML, enter description Creates a new Facelet page, copypaste the following snippet in the pattern field and click OK:
    <!DOCTYPE html>
    <html lang="en"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:ui="http://java.sun.com/jsf/facelets">
        <h:head>
            <title>Insert title here</title>
        </h:head>
        <h:body>
            ${cursor}
        </h:body>
    </html>
    
  8. Here are some more screenshots of how I configured some other preferences (Text Editors, HTML Editor and Errors/Warnings), you may find it useful as well (indent using spaces, set line width and print margin, finetune errors/warnings, etc):
  9. Click OK to close the Preferences dialogue.
Back to top

Integrate Glassfish in Eclipse

We need to familarize Eclipse with any installed application servers so that Eclipse can seamlessly link their 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 applications server is namely the concrete Java EE implementation).

  1. At the bottom box click at the Servers tab to open the servers view. Rightclick at the box and choose New » Server. In the wizard, click the link 'Download additional server adapters'. Wait until it has finished gathering all available adapters. Finally choose 'Oracle Glassfish Server Tools' from the list and click Next. Accept the license terms and click Finish. In the end you need to restart Eclipse, do it.
  2. After restarting and going to workbench, open the servers view once again to add a new server. In the wizard, select GlassFish » GlassFish Server Open Source Edition 3 (Java EE 6) and click Next. In the next page, click at Browse, point to C:\Java\glassfishv3\glassfish and click Next. In the next page, change if necessary the admin ID (username) and password, which is the same as the ones specified during Glassfish installation. Finally click Finish. Now Glassfish is integrated in Eclipse.
  3. Doubleclick the Glassfish server entry in the Servers tab, you'll get the server configuration. You can there if necessary change the admin name/password and configure the degree of publishing (hotdeploying). You may possibly get a firewall warning when you open the server configuration for the first time, just let it allow access. Glassfish is able to publish extremely fast on just a Ctrl+S. In the Publishing section, set Automatically publish when resources change and set the interval to 0.
  4. Rightclick the Glassfish server entry in the Servers tab and choose Start. You can also start it by clicking at the green arrow at the toolbar of the box. Again, you may possibly get a firewall warning here as well, just let it allow access (this should be the last time now ;) ). Once it is started, go to http://localhost:8080 (where 8080 is the HTTP port as in Glassfish config). You should get the default Glassfish home page. Also checkout the admin console on http://localhost:4848 (where 4848 is the admin port as in Glassfish config).

    If you get a timeout or kind of an unknown host error message, then doublecheck it is started properly and you're using the right port number. In Eclipse you can find the Glassfish logs at the Console tab of the bottom dialogue box (you can doubleclick the tab to maximize it and bring it back). Glassfish actually shows two consoles, one of the JVM and one of the server.log logfile. The last one is of your interest. Click the blue monitor icon on the right top to switch between consoles.
  5. You can stop the server by rightclicking at the Glassfish server entry in the Servers tab and choose Stop. You can also stop it by clicking at the red square at the toolbar of the box.
Back to top

Prepare JSF web project in Eclipse

Now we can finally create a JSF web project in Eclipse.

  1. 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 name Playground, verify if Target Runtime is set to 'GlassFish Server Open Source Edition 3 (Java EE 6)' and Dynamic Web Module version is set to '3.0' (this is actually the Servlet API version). Under Configuration select 'JavaServer Faces v2.0 project' and click Next.
  2. In the next page, you can configure the source folder and build folder (there where compiled classes will end up in). Just keep it default and click Next.
  3. In the next page, you may change the module settings to your taste. Personally I like to have URL's always in lowercase, so I change the default Context Root from Playground to playground. Also, check the checkbox Generate web.xml deployment descriptor to have Eclipse auto-generate the web.xml. Click Next.
  4. In the next page, you need to define JSF Capabilities. At JSF Implementation Library, select 'Disable Library Configuration'. Glassfish already ships with JSF 2.0 builtin, so we don't need to specify anything. At URL Mapping Patterns, select the default /faces/* and click Remove to remove it. Prefix patterns end up to be less maintainable. Better use postfix patterns like *.jsf or even *.xhtml (unless you have XHTML files which you'd like not to have JSF's FacesServlet to kick in). We'll pick *.xhtml here, a major advantage 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.

    Click Add... to add a new pattern with the value *.xhtml. Finally click Finish.
  5. After creation of the web project, you should get a directory structure similar to the screenshot below.
  6. Due to a combination of constraints in the HTTP/HTML/EL specifications, empty HTML input fields are by default treated as empty String. The average (Java) web developer usually dislikes this (so do I). We can instruct 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:
    <context-param>
        <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
        <param-value>true</param-value>
    </context-param>
    
    If necessary hit Ctrl+Shift+F to format the xml file nicely.
  7. Save and close the file.
Back to top

Create JSF hello world in Eclipse - The model

As a hello world project, we'll create a simple ajax-flavored form which treats the use case of "Register User". We first need to create a data model. That's a class which represents a real world entitiy, in this case the User. It holds all the information about the user. It should be written as a Javabean. A Javabean is a class which holds properties as private fields which are exposed by public getters and setters.

  1. Open the newly created Playground project, rightclick at Java Resources folder and choose New » Class. In the wizard, enter the package name com.example, enter the class name User, keep the other fields default and click Finish. The package and the class will be created and the editor box will show the class source.
  2. Let the class implement Serializable. This is not mandatory per se, but this is useful in order to let the HTTP session survive server restarts. Also, as we're going to use a JSF view scoped bean, which will be stored in the component tree (the `UIViewRoot`) in the HTTP session, the view scoped bean itself and all of its properties should be Serializable as well.
    package com.example;
    
    import java.io.Serializable;
    
    public class User implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
    }
    Note that when you add implements Serializable, Eclipse will show a warning that the class needs to have a serialVersionUID field. You can if necessary just let Eclipse include it with a default or autogenerated ID. Click the yellow bullet on the left hand side and choose it.
  3. Add five fields to the class (note that Date is to be imported as java.util.Date, not as java.sql.Date):
    
        private Long id;
        private String username;
        private String password;
        private String email;
        private Date birthdate;
     
    
  4. Let Eclipse auto-generate the necessary getters and setters. Rightclick somewhere in blank space of the source code inside the source editor, choose Source » Generate Getters and Setters, or hit Alt+Shift+S, then R. In the wizard, click Select All and then untick the serialVersionUID one, if necessary choose the insertion point (I like to have getters and setters at the whole bottom of the class, thus Last member) and the sorting (it defaults to getter/setter pairs, which is okay) and then click at OK. If necessary, hit Ctrl+Shift+F to format the code again so that methods get separated by a blank line. You can configure formatting preferences in Window » Preferences » Java » Code Style » Formatter.
  5. Save the class by choosing File » Save in the top menu or by pressing Ctrl+S.

Create JSF hello world in Eclipse - The controller

The backing bean is in turn the glue between the view (the JSF page) and the data model (the entity). The backing bean is linked to the view and all properties of the model are by the backing bean exposed in the view. The backing bean can contain action methods which are linked in the view. The backing bean is basically a mini-controller at its own (in the bigger picture of JSF, the FacesServlet is actually the real web MVC controller).

  1. Rightclick at com.example package and choose New » Class. In the wizard, enter the class name Register, keep the other fields default (if you rightclicked on the package to create a new class, the package name should already be com.example) and click Finish. The class will be created and the editor box will show the class source.
  2. First let the class implement Serializable. Then add a new line above the class declaration, enter @ManagedBean, press Ctrl+Space and ensure that you choose the javax.faces one to import. Do the same for @ViewScoped annotation as well. Note that we can also use @RequestScoped here as well since the bean doesn't do any significantly expensive operations during the construction such as obtaining some data from a database, but if it did and you declared it @RequestScoped, then the bean will be constructed and thus the DB will be hit on every ajax request, keep this in mind!
    package com.example;
    
    import java.io.Serializable;
    
    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.ViewScoped;
    
    @ManagedBean
    @ViewScoped
    public class Register implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
    }
  3. Add a property for the User model, along with a getter and (optionally) a setter, add a @PostConstruct method with which initializes a new User and finally add an action method which just adds a success message (in real world, we would save the newly registered user in the DB as well, but that's beyond the scope of this tutorial):
    
        private User user;
    
        @PostConstruct
        public void init() {
            user = new User();
        }
        
        public void submit() {
            FacesMessage message = new FacesMessage("Registration succesful!");
            FacesContext.getCurrentInstance().addMessage(null, message);
        }
        
        public User getUser() {
            return user;
        }
    
    
  4. Save the class.
Back to top

Create JSF hello world in Eclipse - The view

blah

  1. Rightclick at WebContent folder and choose New » XHTML page. In the wizard, enter the File name register, click Next (the .xhtml extension will be appended automatically anyway), select the template New Facelet Page (which we have definied in the preferences) and click Finish.

  2. Change the <title> to Register user and add the following ajax-flavored form to the body of the view:
    <h:form>
        <h:panelGrid columns="3">
            <h:outputLabel for="username">Username</h:outputLabel>
            <h:inputText id="username" value="#{register.user.username}" required="true">
                <f:ajax event="blur" render="usernameMessage" />
            </h:inputText>
            <h:message id="usernameMessage" for="username" />
    
            <h:outputLabel for="password">Password</h:outputLabel>
            <h:inputSecret id="password" value="#{register.user.password}" required="true" redisplay="true">
                <f:ajax event="blur" render="passwordMessage" />
            </h:inputSecret>
            <h:message id="passwordMessage" for="password" />
    
            <h:outputLabel for="email">Email</h:outputLabel>
            <h:inputText id="email" value="#{register.user.email}" required="true">
                <f:ajax event="blur" render="emailMessage" />
            </h:inputText>
            <h:message id="emailMessage" for="email" />
    
            <h:outputLabel for="birthdate">Birthdate (yyyy-MM-dd)</h:outputLabel>
            <h:inputText id="birthdate" value="#{register.user.birthdate}">
                <f:convertDateTime pattern="yyyy-MM-dd" />
                <f:ajax event="blur" render="birthdateMessage" />
            </h:inputText>
            <h:message id="birthdateMessage" for="birthdate" />
    
            <h:panelGroup />
            <h:commandButton value="Register" action="#{register.submit}">
                <f:ajax execute="@form" render="@form" />
            </h:commandButton>
            <h:messages globalOnly="true" layout="table" />
        </h:panelGrid>
    </h:form>
    You see, it creates a form with a 3-column table (however, a tableless form with a flood of CSS would semantically have been more correct, but that's beyond the scope of this tutorial, we teach JSF, not CSS). The 1st column contains the labels for input fields, the 2nd column contains the input fields and the submit button, the 3rd column contains the messages. The <f:ajax> tags in the input fields will submit (and validate!) only the current field and trigger a re-render of the associated message field when the JavaScript/HTML DOM blur event is triggered (when the field loses focus, i.e. when you tab out the field or click somewhere else on the page). The <f:ajax> tag in the command button will do a pure ajax submit instead of a normal submit. The globalOnly="true" in the messages field will only display messages whose client ID is null (as we've created in the managed bean's submit() method).
  3. Save the view.
Back to top

Run JSF web project in Glassfish

Now it's time to deploy the project to Glassfish and run it!

  1. Rightclick the Glassfish server entry in the Servers tab and choose Add and Remove Projects. In the wizard, select the Playground project under Available Projects and click Add to add it to Configured Projects. Click Finish.
  2. Rightclick the Glassfish server entry in the Servers tab and choose Start. You can also start it by clicking at the green arrow at the toolbar of the box. Glassfish is started successfully if the server.log in the Console tab (click the blue monitor icon on the right top to switch between consoles if necessary) displays at least the following line:
    INFO: Playground was successfully deployed in 3,770 milliseconds.
    
    Note that it may take longer or shorter, depending on whether the server has already started for the first time before or not.
  3. Once it is started, go to http://localhost:8080/playground/register.xhtml in your favourite webbrowser. Note that the .xhtml extension must match the URL pattern of the FacesServlet mapping as we have definied in step 4 of chapter Prepare JSF web project in Eclipse. Such a request URL will then trigger the FacesServlet and it will create the FacesContext and do all the JSF works.

    If you get a timeout or kind of an unknown host error message, then doublecheck if Glassfish is started properly and if the port is correct. If you get an internal server error, then an exception was been thrown and is available in the server log. Also try to interpret and understand the exception message and the trace, if necessary with help of Google, and then fix the code accordingly.
  4. Play around it in your browser! Tab through the fields, enter values, remove values, press the submit button, etcetera. You'll note that it's running smoothly thanks to all the new JSF 2.0 ajax works.
Back to top

Extra! Finetuning validation

You'll probably have noticed that the default validation error messages are scary and you would probably also like to add a bit more strong password and email validation. Now, you can finetune the validation messages in several ways.

  1. Those j_idt6:username, j_idt6:password, etc are actually client ID's of the input elements (that is, the generated id of the HTML input element which you can see when you do rightclick and View Source of the opened page in the webbrowser). The j_idt6 part (which can differ) is controllable by giving the <h:form> a fixed id.
    <h:form id="form">
    
    Edit it accordingly in the register.xhtml, save it and refresh the page (no server restart is required! Glassfish hotdeploys extremely fast, you don't need to wait for anything, just refresh the page in browser). Trigger the validation and you'll see form:username, form:password, etc instead.
  2. That's already less scary. However, we can make the labels more human friendly by defining them in the label attribute of the input components.
    <h:inputText id="username" label="Username" ... >
    ...
    <h:inputSecret id="password" label="Password" ... >
    ...
    <h:inputText id="email" label="Email" ... >
    ...
    <h:inputText id="birthdate" label="Birthdate" ... >
    Edit accordingly, save source, refresh page in browser, play around it. No pain!
  3. Better, but still too "mechanic". However, there's a way to replace the entire default required and conversion message in the view side by defining them as requiredMessage and converterMessage accordingly.
    <h:inputText id="username" requiredMessage="Please enter username" ... >
    ...
    <h:inputSecret id="password" requiredMessage="Please enter password" ... >
    ...
    <h:inputText id="email" requiredMessage="Please enter email" ... >
    ...
    <h:inputText id="birthdate" converterMessage="Please enter date in yyyy-MM-dd format" ... >
    Rinse and repeat.

    There are other ways as well, for example defining them as <message-bundle> in the faces-config.xml, but that's beyond the scope of this tutorial.
  4. We can also do the validation straight in the model instead of the view. This can be more useful if the model is a JPA entity. Glassfish ships with builtin bean validation (also known as JSR 303) which is anticipated seamlessly by JSF 2.0. It ships with several validation constraint annotations such as @NotNull.

    First remove the required and requiredMessage attributes from the three input fields username, password and email. Then add the @NotNull annotation on exactly those properties of the model (note that this only works when you've added the javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL context parameter as described in step 6 of chapter Prepare JSF web project in Eclipse, otherwise you need the Hibernate validation specific @NotEmpty annotation instead!).
    
        private Long id;
        @NotNull
        private String username;
        @NotNull
        private String password;
        @NotNull
        private String email;
        private Date birthdate;
    
    
    Save and refresh browser (no, still no server restart needed here as well!)
  5. Again, the messages are too generic: "may not be null". We can however customize them straight in the model by the message field of the annotation.
    
        private Long id;
        @NotNull(message = "Please enter username")
        private String username;
        @NotNull(message = "Please enter password")
        private String password;
        @NotNull(message = "Please enter email")
        private String email;
        private Date birthdate;
    
    
    Save, refresh, play.

    Now we're back at the same state as with view-level validation finetuning.

    Which one you should be using in your projects really depends on the requirements. For example, if you want to be able to run this on a random Tomcat machine or non-Java EE 6-container (JSF 2.0 is by itself backwards compatible with Java EE 5 / Servlet 2.5), then forget bean validation.
  6. We can even use regex to validate the strengthness of the password and correctness of the email. For this the JSR 303 @Pattern annotation is useful. We want the password to be at least 8 chars in length, contain at least one digit, at least one lowercase alphabet letter and at least one uppercase alphabet letter. We also want the email to be syntactically valid with regard to the @ and the .. We shouldn't care about the actual characters in the email address.
    
        private Long id;
        @NotNull(message = "Please enter username")
        private String username;
        @NotNull(message = "Please enter password")
        @Pattern(regexp = ".*(?=.{8,})(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).*", message = "Password is not strong enough")
        private String password;
        @NotNull(message = "Please enter email")
        @Pattern(regexp = "([^.@]+)(\\.[^.@]+)*@([^.@]+\\.)+([^.@]+)", message = "Email is not in valid format")
        private String email;
        private Date birthdate;
    
    
    Rinse and repeat.
Back to top

And now?

Play with it! Head if necessary to Communication in JSF 2.0 article to learn about some tips and tricks.

Here are the most important JSF 2.0 related links to be bookmarked and read thoroughly:

  • JSF 2.0 specification (pick the 1st download link), it explains why JSF is there, how it works and what it all provides.
  • JSF 2.0 API documentation, it contains detailed javadocs of the JSF API classes, it explains where the classes are for, how to use them and what all fields/methods do.
  • JSF 2.0 tag documentation, it shows which JSF tags are all available, what they all do and which attributes they supports.
  • Java EE 6 tutorial, chapter 4 and on contains Sun's Oracle's own JSF 2.0 tutorial.
  • If you want to get a book, I highly recommend the JSF 2.0: The Complete Reference, one of its authors, Ed Burns, is the lead of the JSF specification. If you want to get a step further with Glassfish, then Java EE 6 platform with GlassFish 3 is also an excellent choice.
  • Another excellent online resource is the Mkyong.com JSF 2.0 Tutorials. It contains lot of high quality JSF 2.0 examples (although there are unfortunately a bit too much advertisements, it's sometimes demotivating). There are other sites as well, but please don't even take a look at Roseindia.net.

Finally you can check the Favorites section at the right column of this blog site for more interesting links (of which the majority of the older ones are still targeted on JSF 1.2, the future articles will cover JSF 2.0 anyway).

Back to top

Copyright - None of this article may be taken over without explicit authorisation.

(C) January 2011, BalusC