J3 Limited
 
Google
WWW J3Ltd
 
User Registration JSF

Introduction

In the previous chapter, EJB's and supporting code were created. They allow a web application to create a new Person database record. In this section, the web application is updated to include a JSF page that allows a user to enter their details. The information entered is saved in the database using the EJB's created in the previous chapter.

The source code is available in a zip archive here.

Below is a screenshot of JSF page created in this section:

Create "register.jsp"

The file called register.jsp is created in the "src/web" folder. A previous chapter which dealt with the welcome page, explains the tag library, error page and internationalization bundles. It also explains the form, panelGrid and facet tags.

The contents of register.jsp are shown below.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ page errorPage="errorpage.jsp" %>  
<f:view>  
<f:loadBundle basename="com.j3ltd.web.messages.ApplicationMessages" var="msg"/>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title><h:outputText value="#{msg.pageTitle}"/></title>
<link href="styles.css" rel="stylesheet" type="text/css">
</head>
<body> 

<h:form id="registerForm">
<div class="pageTitle"><h:outputText value="#{msg.registration}"/></div>
<br/>
<div class="center">
<h:panelGrid columns="2"  
  styleClass="form" 
  headerClass="tableHeader"
  footerClass="tableFooter"
  rowClasses="tableRowOdd, tableRowEven">
  <f:facet name="header">
    <h:outputFormat value="#{msg.registrationBoxTitle}">
      <f:param value="*"/>
    </h:outputFormat>
  </f:facet>
  
  <f:facet name="footer">
    <h:panelGroup>
    <h:commandButton value="#{msg.submit}" 
      action="#{registrationBean.register}" />
    <h:commandButton value="#{msg.reset}" type="reset"/>
    </h:panelGroup>
  </f:facet>
    
  <h:outputLabel for="title" value="#{msg.registrationTitle}"/>
  <h:panelGroup>
  <h:inputText id="title" value="#{registrationBean.person.title}"
    maxlength="45" size="10"/><f:verbatim><br/></f:verbatim>
  <h:outputText value=" "/><h:message for="title" styleClass="formUserError"/>
  </h:panelGroup>
  
  <h:outputLabel for="firstName" value="#{msg.registrationName}"/>
  <h:panelGroup>
  <h:inputText id="firstName" value="#{registrationBean.person.firstName}"
    maxlength="255" size="30"/><f:verbatim><br/></f:verbatim>
  <h:outputText value=" "/><h:message for="firstName" styleClass="formUserError"/>
  </h:panelGroup>
  
  <h:outputLabel for="lastName" value="#{msg.registrationSurname}"/>
  <h:panelGroup>
  <h:inputText id="lastName" value="#{registrationBean.person.lastName}"
    maxlength="255" size="30"/><f:verbatim><br/></f:verbatim>
  <h:outputText value=" "/><h:message for="lastName" styleClass="formUserError"/>
  </h:panelGroup>
  
  <h:outputLabel for="suffix" value="#{msg.registrationSuffix}"/>
  <h:panelGroup>
  <h:inputText id="suffix" value="#{registrationBean.person.suffix}"
    maxlength="45" size="15"/><f:verbatim><br/></f:verbatim>
  <h:outputText value=" "/><h:message for="suffix" styleClass="formUserError"/>
  </h:panelGroup>
  
  <h:outputLabel for="dateOfBirth" value="#{msg.registrationDateOfBirth}"/>
  <h:panelGroup>
  <h:inputText id="dateOfBirth" value="#{registrationBean.person.dateOfBirth}">
    <f:convertDateTime pattern="dd/MM/yyyy"/>
  </h:inputText>  <f:verbatim><br/></f:verbatim>
  <h:outputText value=" "/><h:message for="dateOfBirth" styleClass="formUserError"/>
  </h:panelGroup>
  
  <h:outputLabel for="gender" value="#{msg.registrationGender}"/>
  <h:selectOneRadio id="gender" value="#{registrationBean.person.gender}">  
    <f:selectItems value="#{registrationBean.genders}"/>  
  </h:selectOneRadio>
  
  <h:outputLabel for="maritalStatus" value="#{msg.registrationMaritalStatus}"/>
  <h:selectOneRadio id="maritalStatus" value="#{registrationBean.person.maritalStatus}">  
    <f:selectItems value="#{registrationBean.maritalStati}"/>  
  </h:selectOneRadio>
  
  <h:outputLabel for="line1" value="#{msg.registrationAddress1}"/>
  <h:panelGroup>
  <h:inputText id="line1" value="#{registrationBean.person.address.line1}"
    maxlength="255" size="50"/>  <f:verbatim><br/></f:verbatim>
  <h:outputText value=" "/><h:message for="line1" styleClass="formUserError"/>
  </h:panelGroup>
  
  <h:outputLabel for="line2" value="#{msg.registrationAddress2}"/>
  <h:panelGroup>
  <h:inputText id="line2" value="#{registrationBean.person.address.line2}"
    maxlength="255" size="50"/>  <f:verbatim><br/></f:verbatim>
  <h:outputText value=" "/><h:message for="line2" styleClass="formUserError"/>
  </h:panelGroup>
  
  <h:outputLabel for="line3" value="#{msg.registrationAddress3}"/>
  <h:panelGroup>
  <h:inputText id="line3" value="#{registrationBean.person.address.line3}"
    maxlength="255" size="50"/>  <f:verbatim><br/></f:verbatim>
  <h:outputText value=" "/><h:message for="line3" styleClass="formUserError"/>
  </h:panelGroup>
  
  <h:outputLabel for="line4" value="#{msg.registrationAddress4}"/>
  <h:panelGroup>
  <h:inputText id="line4" value="#{registrationBean.person.address.line4}"
    maxlength="255" size="50"/><f:verbatim><br/></f:verbatim>
  <h:outputText value=" "/><h:message for="line4" styleClass="formUserError"/>
  </h:panelGroup>
  
  <h:outputLabel for="postcode" value="#{msg.registrationPostcode}"/>
  <h:panelGroup>
  <h:inputText id="postcode" value="#{registrationBean.person.address.postcode}"
    maxlength="50" size="20"/><f:verbatim><br/></f:verbatim>
  <h:outputText value=" "/><h:message for="postcode" styleClass="formUserError"/>  
  </h:panelGroup>
  
  <h:outputLabel for="country" value="#{msg.registrationCountry}"/>
  <h:panelGroup>
  <h:inputText id="country" value="#{registrationBean.person.address.country}"
    maxlength="150" size="40"/><f:verbatim><br/></f:verbatim>
  <h:outputText value=" "/><h:message for="country" styleClass="formUserError"/>
  </h:panelGroup>
  
  <h:outputLabel for="daytimePhone" value="#{msg.registrationPhoneDay}"/>
  <h:panelGroup>
  <h:inputText id="daytimePhone" value="#{registrationBean.person.daytimePhone}"
    maxlength="45" size="12"/><f:verbatim><br/></f:verbatim>
  <h:outputText value=" "/><h:message for="daytimePhone" styleClass="formUserError"/>
  </h:panelGroup>
  
  <h:outputLabel for="eveningPhone" value="#{msg.registrationPhoneEvening}"/>
  <h:panelGroup>
  <h:inputText id="eveningPhone" value="#{registrationBean.person.eveningPhone}"
    maxlength="45" size="12"/><f:verbatim><br/></f:verbatim>
  <h:outputText value=" "/><h:message for="eveningPhone" styleClass="formUserError"/>
  </h:panelGroup>
  
  <h:outputLabel for="email" value="*#{msg.registrationEmail}"/>
  <h:panelGroup>
  <h:inputText id="email" value="#{registrationBean.person.email}" 
    maxlength="255" size="50" 
    required="true">
      <f:validator validatorId="EmailValidator"/>
  </h:inputText><f:verbatim><br/></f:verbatim>
  <h:outputText value=" "/><h:message for="email" styleClass="formUserError"/>
  </h:panelGroup>
  
  <h:outputLabel for="emailConfirm" value="*#{msg.registrationEmailConfirm}"/>
  <h:panelGroup>
  <h:inputText id="emailConfirm" value="#{registrationBean.emailConfirm}" 
    maxlength="255" size="50" 
    required="true"/><f:verbatim><br/></f:verbatim>
  <h:outputText value=" "/><h:message for="emailConfirm" styleClass="formUserError"/>
  </h:panelGroup>
  
  <h:outputLabel for="password" value="*#{msg.registrationPassword}"/>
  <h:panelGroup>
  <h:inputSecret id="password" value="#{registrationBean.person.password}" 
    maxlength="64" size="20" 
    required="true" redisplay="true">
      <f:validateLength minimum="6"/>
  </h:inputSecret><f:verbatim><br/></f:verbatim>
  <h:outputText value=" "/><h:message for="password" styleClass="formUserError"/>
  </h:panelGroup>
  
  <h:outputLabel for="passwordConfirm" value="*#{msg.registrationPasswordConfirm}"/>
  <h:panelGroup>
  <h:inputSecret id="passwordConfirm" value="#{registrationBean.passwordConfirm}" 
    maxlength="64" size="20" 
    required="true" redisplay="true"/><f:verbatim><br/></f:verbatim>
  <h:outputText value=" "/><h:message for="passwordConfirm" styleClass="formUserError"/>
  </h:panelGroup>
  
  <h:outputLabel for="webSite" value="#{msg.registrationWeb}"/>
  <h:panelGroup>
  <h:inputText id="webSite" value="#{registrationBean.person.webSite}"
    maxlength="255" size="50"/><f:verbatim><br/></f:verbatim>
    <h:outputText value=" "/><h:message for="webSite" styleClass="formUserError"/>
  </h:panelGroup>
    
</h:panelGrid>
</div>
</h:form>
</body>
</html>
</f:view>

The page uses a panelGrid to hold the form with the input fields. The header facet holds the table's title, and the footer facet holds the Save and Reset command buttons.

Every cell which has an input field is wrapped in a panelGroup. This allows more than one tag to fit into the cell (column), as should be recalled, the panelGrid tag expects one child tag per column. Using panelGroup tags allows the field error message to appear below the input field to which it refers, as shown in the screenshot below:

The submit command button calls the register method on the managed bean (described in the next section). The register method returns the outcome, either success or failure, or throws an exception in an unlikely event that something unexpected happened.

The Date Of Birth field uses a converter that is supplied in the core JSF taglib. It allows JSF to validate and convert the user input into a java.util.Date.

A custom validator is used on the email field, it performs simple checks to ensure that the email entered has a valid syntax.

The password field uses a length validator that is supplied as part of the core JSF tag library.

The Register Managed Bean

The JSF page, described in the previous section, uses the Register managed bean to get and update data. Below is the code:

package com.j3ltd.web;


import com.j3ltd.common.*;
import com.j3ltd.server.sessionremote.*;
import com.j3ltd.server.entities.*;
import com.j3ltd.server.exceptions.*;
import com.j3ltd.web.messages.*;
import java.util.*;

import javax.faces.context.*;
import javax.faces.application.*;
import javax.faces.model.SelectItem;
import javax.naming.Context;
import javax.naming.InitialContext;


public class Register {

  Person person;
  private String passwordConfirm;
  private String emailConfirm;


  public Person getPerson() {
    return person;
  }

  public void setPerson(Person person) {
    this.person = person;
  }

  public List getGenders() {
    ArrayListgenders = new ArrayList();
    MessageFactory msg = new MessageFactory();
      
    SelectItem item = new SelectItem();    
    item.setLabel(msg.getMessage("male"));
    item.setValue(Gender.Male.toString());
    genders.add(item);
    item = new SelectItem();
    item.setLabel(msg.getMessage("female"));
    item.setValue(Gender.Female.toString());
    genders.add(item);
    item = new SelectItem();
    item.setLabel(msg.getMessage("undisclosed"));
    item.setValue(Gender.Undisclosed.toString());
    genders.add(item);
    return genders;
  }
  
  public List getMaritalStati() {
    ArrayList maritalStati = new ArrayList();
    MessageFactory msg = new MessageFactory();
    
    SelectItem item = new SelectItem();    
    item.setLabel(msg.getMessage("married"));
    item.setValue(MaritalStatus.Married.toString());
    maritalStati.add(item);
    item = new SelectItem();
    item.setLabel(msg.getMessage("single"));
    item.setValue(MaritalStatus.Single.toString());
    maritalStati.add(item);
    item = new SelectItem();
    item.setLabel(msg.getMessage("undisclosed"));
    item.setValue(MaritalStatus.Undisclosed.toString());
    maritalStati.add(item);
    return maritalStati; 
  }
  
  public String register() throws Exception {
    String toReturn = "failure";
       
    if (validateData()) {
      try {
        // save locale information, in case the user chose a language on the welcome page
Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
person.setLocaleCountry(locale.getCountry());
person.setLocaleLanguage(locale.getLanguage());
Context context = new InitialContext(); EntityFacade entities = (EntityFacade) context.lookup("EntityFacadeBean/remote"); person = entities.createPerson(person); toReturn = "success"; } catch (EntityExistsException exist) { MessageFactory msg = new MessageFactory(); FacesContext ctx = FacesContext.getCurrentInstance(); ctx.addMessage("registerForm:email", new FacesMessage(FacesMessage.SEVERITY_ERROR, msg.getMessage("errorEmailExists"), null)); } } return toReturn; } /** * Perform validation that can only be done once * all the field data is present * in the person member. Ie: to validate one field * other field(s) values are needed. * * Note that this method creates error messages for the * faces context, if errors are found. * @return true if data is OK, false if not OK */ private boolean validateData() { boolean toReturn = true; MessageFactory msg = new MessageFactory(); FacesContext ctx = FacesContext.getCurrentInstance(); // check emailConfirm is same as email if (!emailConfirm.equals(person.getEmail())) { ctx.addMessage("registerForm:emailConfirm", new FacesMessage(FacesMessage.SEVERITY_ERROR, msg.getMessage("errorEmailConfirm"), null)); toReturn = false; } // check passwordConfirm is same as password if (!passwordConfirm.equals(person.getPassword())) { ctx.addMessage("registerForm:passwordConfirm", new FacesMessage(FacesMessage.SEVERITY_ERROR, msg.getMessage("errorPasswordConfirm"), null)); toReturn = false; } return toReturn; } public String getEmailConfirm() { return emailConfirm; } public void setEmailConfirm(String emailConfirm) { this.emailConfirm = emailConfirm; } public String getPasswordConfirm() { return passwordConfirm; } public void setPasswordConfirm(String passwordConfirm) { this.passwordConfirm = passwordConfirm; } }

The managed bean Register has the members required to display the JSF page's field data. The Person entity bean class is used, along with two other members which are not part of the entity: the email and password confirmation fields. This illustrates a new feature in the EJB 3.0 persistence specification: entity classes passed from an EJB server to a Web application server are "detached" from the server. So it is perfectly acceptable to pass entity beans around as data beans.

The methods getGenders() and getMaritalStati() return a list that the selectOneRadio tags in the register.jsp use to display all the options available.

The method register() is called when the user submits the page. The method performs last minute validation, then saves the data using the stateless EJB defined previously. The register() method returns the String "success" if the details were saved, "failure" if the details could not be saved.

The validateData() method checks that the email and the email confirmation fields hold the same value. The same check is made on the password fields.

Support Classes

The managed bean, described in the previous section, uses a few support classes, these are now described.

An enumeration is used to describe the possible marital status of a person, and another enumeration is used to list the possible genders of a person. These enumerations are placed in a "com.j3ltd.common" package, as they may be useful in EJB's and web applications.

Gender enumeration:

package com.j3ltd.common;


public enum Gender {
  Male, Female, Undisclosed
}

Marital status enumeration:


package com.j3ltd.common;

public enum MaritalStatus {
  Single, Married, Undisclosed
}

A custom validator class is defined to validate an email string, it implements the javax.faces.validator.Validator interface :

package com.j3ltd.web.utilities;


import javax.faces.validator.*;
import javax.faces.*;
import javax.faces.context.*;
import javax.faces.component.*;
import com.j3ltd.web.messages.*;
import javax.faces.application.*;


public class EmailValidator implements Validator {
  
  public void validate(FacesContext context, UIComponent
      component, Object toValidate) {
    boolean isValid = true;
    String value = null;
    
    if ((context == null) || (component == null)) {
      throw new NullPointerException();
    }
    if (!(component instanceof UIInput)) {
      return;
    }
    if (null == toValidate) {
      return;
    }
    value = toValidate.toString();
    int atIndex = value.indexOf('@');
    if (atIndex < 0) {
      isValid = false;
    }
    else if (value.lastIndexOf('.') < atIndex) {
      isValid = false;
    }
    if ( !isValid ) {
      MessageFactory msg = new MessageFactory();
      FacesMessage errMsg = new FacesMessage(msg.getMessage("errorEmailFormat"));
      throw new ValidatorException(errMsg);
    }
  }
}

A message factory class is defined to get a localised message from the resource bundles. This is used by the managed bean:

package com.j3ltd.web.messages;


import java.util.*;
import javax.faces.context.*;
import java.text.*;


public class MessageFactory {
  ResourceBundle bundle;
  Locale locale;
  
  public MessageFactory() {
    locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
      bundle = ResourceBundle.getBundle("com.j3ltd.web.messages.ApplicationMessages", locale);
  }
  
  public String getMessage(String key) {
    return bundle.getString(key);
  }
  public String getMessage(String key, Object arg1) {
    return getMessage(key, new Object[] {arg1});
  }
  public String getMessage(String key, Object arg1, Object arg2) {
    return getMessage(key, new Object[] {arg1, arg2});
  }
  public String getMessage(String key, Object[] args) {
    if (args == null || args.length == 0) {
      return bundle.getString(key);
    }
    MessageFormat fmt = new MessageFormat(bundle.getString(key));
    fmt.setLocale(locale);
    return fmt.format(args).toString();
  }
}

Several getMessage() methods are defined. some just take the key to find the message in the properties file. Others take arguments, these are for messages of the form "this is a message with an argument {0}". Where the "{0}" denotes where to put the argument. Internationalization message bundles were described here.

JSF Error Messages

JSF provides validation for input fields: whether the field is mandatory, the length, data type, format and many other checks, can all be specified in the JSF page. JSF is installed with default error messages, it is possible to override the default messages with our own. This is done in the message files. Below is the english message file:

###################
#
# MyCV Application localised text, English
#
###################
pageTitle=MyCV, anytime, anywhere, always there


# Welcome Page
welcome=Welcome To MyCV
welcomeBoxTitle=Please select an option from those listed below
register=Register
login=Login
forgotPassword=Forgot Password


# Registration Page
registration=Register With MyCV
registrationBoxTitle=Fields marked {0} are mandatory.
registrationTitle=Title
registrationName=Name
registrationSurname=Surname
registrationSuffix=Suffix
registrationDateOfBirth=DOB (dd/mm/yyyy)
registrationGender=Gender
registrationAddress1=Address
registrationAddress2=
registrationAddress3=
registrationAddress4=
registrationPostcode=Postcode/Zip
registrationCountry=Country
registrationPhoneDay=Daytime Phone
registrationPhoneEvening=Evening
registrationEmail=Email
registrationEmailConfirm=Confirm Email
registrationPassword=Password
registrationPasswordConfirm=Confirm Password
registrationWeb=Website URL
registrationMaritalStatus=Marital Status
errorGenderString=String value {0} is not a com.j3ltd.common.Gender
errorMaritalStatusString=String value {0} is not a com.j3ltd.common.MaritalStatus
errorGenderObject=Object value {0} is not a com.j3ltd.common.Gender
errorMaritalStatusObject=Object value {0} is not a com.j3ltd.common.MaritalStatus
errorBlankEmail=Please enter a valid email address.
errorEmailConfirm=The email addresses are not the same

errorPasswordConfirm=The passwords are not the same
errorEmailFormat=The email address is not valid

errorEmailExists=The email address is already registered



#Common Page Navigation Labels
submit=Save
reset=Reset


#General Values
english=English
french=Français
married=Married
single=Single
undisclosed=Undisclosed
male=Male
female=Female

# Java conversion and validation error messages, as defined in
# Messages.properties file of JSF
javax.faces.component.UIInput.CONVERSION=the value is incorrect
javax.faces.component.UIInput.REQUIRED=cannot be blank
javax.faces.component.UISelectOne.INVALID=please select a valid option
javax.faces.component.UISelectMany.INVALID=please ensure the option(s) selected are valid
javax.faces.validator.NOT_IN_RANGE=please enter a value between {0} and {1}
javax.faces.validator.DoubleRangeValidator.MAXIMUM=please enter a value less than {0}
javax.faces.validator.DoubleRangeValidator.MINIMUM=please enter a value greater than {0}
javax.faces.validator.DoubleRangeValidator.TYPE=please enter a number
javax.faces.validator.LengthValidator.MAXIMUM=please enter a value shorter than {0} characters
javax.faces.validator.LengthValidator.MINIMUM=please enter a value longer than {0} characters
javax.faces.validator.LongRangeValidator.MAXIMUM=please enter a value less than {0}
javax.faces.validator.LongRangeValidator.MINIMUM=please enter a value greater than {0}
javax.faces.validator.LongRangeValidator.TYPE=please enter a whole number
javax.faces.convert.DateTimeConverter.CONVERSION = Please enter a valid date

The highlighted messages are those used to override JSF's default messages. A full list of messages can be found in the JSF jar file: server\default\deploy\jbossweb-tomcat55.sar\jsf-libs\myfaces-impl.jar, the file is Messages.properties.

Update The Welcome Page

The original welcome page does not have any hyperlinks to the registration page. The file welcome.jsp is updated to have hyperlinks to the registration page:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ page errorPage="errorpage.jsp" %>  
<f:view>  
<f:loadBundle basename="com.j3ltd.web.messages.ApplicationMessages" var="msg"/>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title><h:outputText value="#{msg.pageTitle}"/></title>
<link href="styles.css" rel="stylesheet" type="text/css">
</head>
<body>
<h:form >
<div class="pageTitle"><h:outputText value="#{msg.welcome}"/></div>
<br/>
<div class="center">
<h:panelGrid columns="3" 
  styleClass="form"
  headerClass="tableHeader">
  <f:facet name="header">
    <h:outputText value="#{msg.welcomeBoxTitle}"/>
  </f:facet>
    <h:outputText value="#{msg.login}"/>
    
    <h:commandLink action="register" id="register">
      <h:outputText value="#{msg.register}"/>
    </h:commandLink>
    
    <h:outputText value="#{msg.forgotPassword}"/>
    
    <h:outputText value=" "/><h:outputText value=" "/><h:outputText value=" "/>
    
    <h:commandLink id="english" action="chooseLocale"
       actionListener="#{welcomeBean.onChooseLocale}">
      <h:outputText value="#{msg.english}" />
    </h:commandLink>
    <h:outputText value=" "/>
    <h:commandLink id="french" action="chooseLocale"
       actionListener="#{welcomeBean.onChooseLocale}">
      <h:outputText value="#{msg.french}" />
    </h:commandLink>
</h:panelGrid>
</div>
</h:form>
</body>
</html>
</f:view>

Update The JSF Configuration File

The faces-config.xml file, originally created in a previous section, is updated with new navigation rules for the registration page, and also to specify the custom validator that has been defined.

<?xml version='1.0' encoding='UTF-8'?>

<!--
 Copyright 2004 Sun Microsystems, Inc. All rights reserved.
 SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
-->

<!DOCTYPE faces-config 
PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
                            "http://java.sun.com/dtd/web-facesconfig_1_0.dtd">
<faces-config>
  <application>
    <message-bundle>com.j3ltd.web.messages.ApplicationMessages</message-bundle>
    <locale-config>
       <default-locale>en</default-locale>
       <supported-locale>fr</supported-locale>
    </locale-config>
  </application>
  
  <!--............................ Managed Beans ..........................--> 
  
  <managed-bean>
    <managed-bean-name>welcomeBean</managed-bean-name>
    <managed-bean-class>com.j3ltd.web.Welcome</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
  </managed-bean>
  
  <managed-bean>
    <managed-bean-name>registrationBean</managed-bean-name>
    <managed-bean-class>com.j3ltd.web.Register</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
    <managed-property>
      <property-name>person</property-name>
      <value>#{registeringPersonBean}</value>
    </managed-property>
  </managed-bean>  
  
  <managed-bean>
    <managed-bean-name>registeringPersonBean</managed-bean-name>
    <managed-bean-class>com.j3ltd.server.entities.Person</managed-bean-class>
    <managed-bean-scope>none</managed-bean-scope>
    <managed-property>
      <property-name>address</property-name>
      <value>#{addressBean}</value>
    </managed-property>
    <managed-property>
      <property-name>gender</property-name>
      <value>Undisclosed</value>
    </managed-property>
     <managed-property>
      <property-name>maritalStatus</property-name>
      <value>Undisclosed</value>
    </managed-property>      
  </managed-bean>
  
  <managed-bean>
    <managed-bean-name>addressBean</managed-bean-name>
    <managed-bean-class>com.j3ltd.server.entities.Address</managed-bean-class>
    <managed-bean-scope>none</managed-bean-scope>
  </managed-bean>   
    
 <!--.......................... Navigation Rules ...................-->
 
 <!-- Welcome Page -->
 <navigation-rule>
    <from-view-id>/welcome.jsp</from-view-id>
    <navigation-case>
      <description>
        Choose locale changes locale then returns to welcome page
      </description>
      <from-outcome>chooseLocale</from-outcome>
      <to-view-id>/welcome.jsp</to-view-id>
    </navigation-case> 
    <navigation-case>
      <description>
        Navigate to register.jsp
      </description>
      <from-outcome>register</from-outcome>
      <to-view-id>/register.jsp</to-view-id>
    </navigation-case>    
 </navigation-rule> 
 
 <!-- Registration Page -->
  <navigation-rule>
    <from-view-id>/register.jsp</from-view-id>
    <navigation-case>
      <description>
        create new user succeeded
      </description>
      <from-outcome>success</from-outcome>
      <to-view-id>/login.jsp</to-view-id>
    </navigation-case>  
       
    <navigation-case>
      <description>
        create new user failed
      </description>
      <from-outcome>failure</from-outcome>
      <to-view-id>/register.jsp</to-view-id>
    </navigation-case>     
 </navigation-rule> 
 
 <!--........................... Custom Validators .....................-->
   <validator>
     <validator-id>EmailValidator</validator-id>
     <validator-class>com.j3ltd.web.utilities.EmailValidator</validator-class>
   </validator>
</faces-config>

Create A Login.jsp

A new file called login.jsp is created in the src/web folder. At the moment it is used solely to inform us that the register page saved the details successfully.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ page errorPage="errorpage.jsp" %>  
<f:view>  
<f:loadBundle basename="com.j3ltd.web.messages.ApplicationMessages" var="msg"/>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title><h:outputText value="#{msg.pageTitle}"/></title>
<link href="styles.css" rel="stylesheet" type="text/css">
</head>
<body>
<h:form >
Registration complete!
</h:form>
</body>
</html>
</f:view>

Package The Web Application

Several files have been added to the web application, the Eclipse packaging configuration for the project's web application needs to be updated, as described in this section.

The web application packaging configuration defined in a previous chapter was basic. The packaging needs to be updated to exclude the files that only sit in the EJB server. The packaging also needs to include files created in this chapter.

Below is a screenshot of the packaging configuration as it stands:

The entry highlighted above (/MyCV/bin) is removed.

MyCV.war is right clicked and "Add Folder" is selected. The project folder MyCV/bin/com/j3ltd/web is selected, the prefix given is WEB-INF/classes/com/j3ltd/web. the includes field is set to **/*.class. This includes the utilities and messages folders, as well as the content in the web folder.

The packaging configuration should look like the one below:

The project packaging is run to generate the war file.

Deploy And Test

JBoss is launched in debug mode from eclipse.

Once JBoss has started, the ejb archive MyCV.ejb3 is deployed to JBoss, by right clicking the file in the project explorer and selecting deployment. The web application archive MyCV.war is also deployed to JBoss.

A browser is opened, with the url http://localhost:8080/MyCV. This brings up the welcome page:

The register hyperlink is clicked, and the registration page is displayed. An invalid date, email and password are entered, then "Save" is clicked, this tests the date converter, and validators used in the page:

Test values are entered, as shown below:

The save button is clicked, which navigates to the rudimentary "login" page:

MySQL query browser is launched to check the values that have been inserted into the database.

The Person table in the shoestring catalog has been added successfully:

'firstname', 'surname', 1, 'title', 'Male', '1980-12-02 00:00:00', 'suffix', 'dayphone', 'eveningphone', 'http://www.j3ltd.com', 'Married', 1, 'password', 'memail@mail.com', 'en', ''

An address has also been added:

1, 'line1', 'line2', 'line3', 'line4', 'country', 'postcode'

This concludes the registration process, in this chapter a complete JSF page has been implemented, it uses a custom validator, JSF error messages have been overridden and the EJB 3 entity beans have been implemented to successfully save data into the database tables, using an EJB relationship and generated keys.

 

  Copyright © 2006 J3 Ltd Permission is granted to reproduce material on this page, on the condition that a reference to "WWW.J3Ltd.com" is given as the source of the material.