JSF/RF Register Portlet

    Overview

    The idea is to implement a JSF alternative to the existing portlet where a new user can register. The problem to solve is that the current portlet is WebUI based and requires WebUI knowledge to be modified. The new solution should be flexible enough so that it doesn’t require to be recompiled to do most standard customizations (adding/removing captcha support, adding/removing fields...)
    Also the new application should be smooth and be a 2010 application (Ajax) , not a 1990 old-style.

     

    Authors

    • Nabil Benothman

     

    Dependencies

     

    • GateIn 3.1 (JBoss AS 5)
    • PortletBridge-2.1.0.FINAL
    • Richfaces-3.3.3.Final
    • Portlet API 2.0
    • JSF 1.2
    • Facelet 1.1.15
    • SimpleCaptcha 1.1.1

     

    This implementation should work also with Tomcat 6, with some more configurations (dependencies scope).

    Features

     

    • Ability to add/remove captcha support
    • Ability to add/remove fields (phone, birthday, etc.) without modifying source code (java classes)
    • Ability to add/remove email validation
    • Ability to add custom fields and map them to user properties
    • Ability to validate custom fields (using JSF validators and/or Hibernate validators)
    • Password generator should be customizable to accept a list of characters to choose from when generating a password
    • Ability to create an account for another person (managed by admin)

     

    portlet.xml

     

    To create a portlet, we have to create the portlet.xml descriptor and declare the portlet class and initialize parameters, in this case the view id.

     

    <?xml version="1.0" encoding="UTF-8"?>
    <portlet-app version="1.0" xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"> 
        <portlet>
            <description>
                JSF/RF Register Portlet.
            </description>
            <portlet-name>JSFRegisterPortlet</portlet-name>
            <display-name>JSF/RF Register Portlet</display-name>
            <portlet-class>org.jboss.gatein.portlet.RegisterPortlet</portlet-class>
            <init-param>
                <name>javax.portlet.faces.preserveActionParams</name>
                <value>true</value>
            </init-param>
            <init-param>
                <name>javax.portlet.faces.defaultViewId.view</name>
                <value>/faces/index.xhtml</value>
            </init-param>
            <expiration-cache>0</expiration-cache>
            <supports>
                <mime-type>text/html</mime-type>
                <portlet-mode>view</portlet-mode>
            </supports>
            <portlet-info>
                <title>JSF/RF Register Portlet</title>
            </portlet-info>
        </portlet>
    </portlet-app>
    

    Portlet class

    As a new feature of the portlet 2.0 specification, the new method called "doHeaders" allows to add some headers needed by the portlet such as stylesheet sources and/or javascript. In this portlet we need to override only this method since we have the view is defined in the portlet.xml.

    N.B.:

    • The edit mode and help mode are not enabled for this portlet (c.f. portlet.xml).
    • This file normally should not be modified except if the admin prefers to use additional stylesheet files.

     

    package org.jboss.gatein.portlet;
    import javax.portlet.MimeResponse;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;
    import javax.portlet.faces.GenericFacesPortlet;
    import org.w3c.dom.Element;
    
    public class RegisterPortlet extends GenericFacesPortlet {
    
    
        @Override
        public void doHeaders(RenderRequest request, RenderResponse response) {
    
            // adding different stylesheets
            Element default_css = response.createElement("link");
            default_css.setAttribute("id", "defaultccs");
            default_css.setAttribute("type", "text/css");
            default_css.setAttribute("rel", "stylesheet");
            default_css.setAttribute("media", "screen");
            default_css.setAttribute("href", request.getContextPath() + "/css/default.css");
            response.addProperty(MimeResponse.MARKUP_HEAD_ELEMENT, default_css);
    
            Element layout_css = response.createElement("link");
            layout_css.setAttribute("id", "ccs_layout");
            layout_css.setAttribute("type", "text/css");
            layout_css.setAttribute("rel", "stylesheet");
            default_css.setAttribute("media", "screen");
            layout_css.setAttribute("href", request.getContextPath() + "/css/cssLayout.css");
            response.addProperty(MimeResponse.MARKUP_HEAD_ELEMENT, layout_css);
    
            Element bubble_css = response.createElement("link");
            bubble_css.setAttribute("id", "bubble_css");
            bubble_css.setAttribute("type", "text/css");
            bubble_css.setAttribute("rel", "stylesheet");
            default_css.setAttribute("media", "screen");
            bubble_css.setAttribute("href", request.getContextPath() + "/css/bubble.css");
            response.addProperty(MimeResponse.MARKUP_HEAD_ELEMENT, bubble_css);
        }
    }
    

     

     

     

     

    Default implementation

     

    In this implementation, we provide a default interface which can be easily extended according to the administrator needs. The used fields respects the JSR-286 excepts some custom ones that are not defined in the JSR. The fields are described in the table below:

     

     

    Field

    Key

    JSR-286

    Required

    First name

    user.name.given

    Last name

    user.name.family

    Email address

    user.home-info.online.email

    User name

    user.login.id

    Password

    gatein.user.password

    Confirm password

    gatein.user.confirmPassword

    Title

    gatein.user.title

    Gender

    user.gender

    Birthday

    user.bdate

    Physical address street

    user.home-info.postal.street

    Physical address postal code

    user.home-info.postal.postalcode

    Physical address city

    user.home-info.postal.city

    Physical address state

    user.home-info.postal.stateprov

    Physical address country

    user.home-info.postal.country

    Home phone number

    user.home-info.telecom.telephone.number

    Home mobile phone number

    user.home-info.telecom.mobile.number

    Twitter account

    gatein.user.twitter

    Skype account

    gatein.user.skype

    LinkedIn

    gatein.user.linkedIn

    MSN

    gatein.user.msn

    ICQ

    gatein.user.icq

     

     

    For more details about user attributes provided by the JSR-286, see the JSR web site ("User Information Attribute Names" section)

     

     

    Custom components

    To have a smooth 2010 application, all requests are sent using Ajax (A4J). Ajax is used essentially for input validation, submit and page navigation as JSF allow to do such features. For more interactive application we create some custom components to improve the look and feel. These components are described below:

     

    • GateInHtmlInputText: A simple HtmlInputText that allow to display a label as default value. When the input gain the focus, the value becomes empty to allow user edit the field. The default value will be redisplayed again if the user leaves it empty. If the submitted value is the default one, the method « getSubmittedValue() » will return the empty value.
    • GateInHtmlInputSecret: same as GateInHtmlInputText but for password input.
    • GateInBubbleHtmlInputText: A sub-class of GateInHtmlInputText that display a bubble info message when the input gain the focus (see screenshot below: Fig. 1). When the input loose the focus, the bubble info message still displayed for one second (configurable). If some validation are required, the info message will be replaced by the validation message.
    • GateInBubbleHtmlInputSecret: A sub-class of GateInHtmlInputSecret and works same as GateInBubbleHtmlInputText.

     

    Screen shot 2010-12-21 at 10.52.34 AM.png

    Fig. 1: screenshot of the GateInBubbleHtmlInputText.

     

     

     

     

    Screenshots

    Below some screenshots of the portlet showing the it's behavior in case of invalid inputs, the normal case (all inputs are vaild) and when the user (admin) cancel the registration:

     

     

    invalid-inputs.pngFig. 2 : invalid user input, the "More..." link shown here is for optional data (not required data, c.f. table above)

     

    cancel-action.png

    Fig. 3 : Registration canceled

     

    process-success.png

    Fig. 4: Registration finish successfully.

     

     

     

    The current state of the application uses a JQuery script for these components (you don't need to download JQuery since it is provided with Richfaces). For more details about this script, check the source code.

     

     

    Testing

    To test the application, we used JSFUnit. Note that JSFUnit does not work yet in a portal environment and these tests were done in a normal web container.


    Download & install

     

    1. Get the source code of the application from the github repository below.
    2. Once downloaded, open a command line prompt and navigate to the application directory. Once there, type the maven command 'mvn package'
    3. copy the war archive (target/RegisterPortlet.war) into the deploy directory of GateIn (GateIn-JBoss AS 5.x)

     

    Build system: Maven (http://maven.apache.org/)

    Github repository : https://github.com/benothman/Register-Portlet