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.
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
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 | ✘ | ✘ |
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.
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:
Fig. 2 : invalid user input, the "More..." link shown here is for optional data (not required data, c.f. table above)
Fig. 3 : Registration canceled
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
- Get the source code of the application from the github repository below.
- Once downloaded, open a command line prompt and navigate to the application directory. Once there, type the maven command 'mvn package'
- 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
Comments