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