5) Sample Application
5.1) Introduction
In this section, let us walk through a Sample Application that makes use of the Ajax4Jsf Libraries. Let the keep the functionalities of this Sample Application to a simpler extent. This is a kind of Auto Complete Application in which whenever the User gives the Bank Account Number, the corresponding details like the name of the Bank, its Branch Name, Customer Name, Balance Details, Contact Details etc will be fetched from the Server. The more important thing to note that is the Request that is sent to the Server is not a normal Jsf Request but instead it is a Ajax Request.
5.2) Web Application Descriptor File
As seen previously, the Ajax4Jsf provides a Filter Servlet for adding Ajax capability for the Jsf Components. So, the web.xml should include a 'filter' tag about the various information about the Filter Servlet.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<display-name>Ajax4jsf Filter</display-name>
<filter-name>ajax4jsf</filter-name>
<filter-class>org.ajax4jsf.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>ajax4jsf</filter-name>
<servlet-name>Faces Servlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<!-- Welcome files -->
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
As we can see from the above Xml File, apart from the normal Faces Servlet information, a Filter Servlet has been embedded to add Ajax capabilities for the Client Requests.
5.3) Faces Configuration File
The Faces Configuration file (faces-config.xml) contains only one entry that represents a Managed Bean object. As we will see in the later sections, this Managed Bean will contain the logic for creating some Dummy Account Information as well as contains the logic for fetching the appropriate Account Information. Following is the code for faces-config.xml file.
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
<managed-bean>
<managed-bean-name>accountSearcher</managed-bean-name>
<managed-bean-class>
net.javabeat.articles.ajax4jsf.introduction.AccountSearcher
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>
5.4) Jsp File containing Jsf and Ajax4Jsf Tags
The following Jsp page presents an Interface to the user, when the User is given a Text-Field prompting to enter the Account Information. If the Account Number entered in valid, which is done by comparing the list of Account Objects, then the corresponding related Information of the Account will be populated in the View.
index.jsp
<html>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="https://ajax4jsf.dev.java.net/ajax" prefix="a4j" %>
<f:view locale="en">
<head>
<title>Account Details</title>
</head>
<body>
<h:form id="form">
<h3>Enter the Account number and tab out for getting further information</h3>
<h:panelGrid columns="2">
<h:outputLabel for = "AccountNo" value = "Account Number:"/>
<h:inputText id = "AccountNo"
binding = "#{accountSearcher.accountTextField}"
size = "6" required="true">
<f:validateLength minimum="6" maximum="6"/>
<f:convertNumber type = "number" />
<a4j:support event = "onblur" immediate="true"
actionListener = "#{accountSearcher.search}"
reRender = "BankName, CustName, BranchName, OpenDate,
ClosingBalance, Address, EmailId, PhoneNumber"/>
</h:inputText>
</h:panelGrid>
<hr>
<p>Bank Details:</p>
<h:panelGrid columns="2">
<h:outputLabel for = "BankName" value = "Bank Name:"/>
<h:inputText id = "BankName" size="25"
binding = "#{accountSearcher.bankNameTextField}"
value = "#{accountSearcher.account.bankName}"/>
<h:outputLabel for = "CustName" value = "Customer Name"/>
<h:inputText id = "CustName" size="15"
binding = "#{accountSearcher.customerNameTextField}"
value = "#{accountSearcher.account.customerName}"/>
<h:outputLabel for = "BranchName" value = "Branch Name"/>
<h:inputText id = "BranchName" size="15"
binding = "#{accountSearcher.branchNameTextField}"
value = "#{accountSearcher.account.branchName}"/>
<h:outputLabel for = "OpenDate" value = "Open Date"/>
<h:inputText id = "OpenDate" size="15"
binding = "#{accountSearcher.openDateTextField}"
value = "#{accountSearcher.account.openDate}"/>
<h:outputLabel for = "ClosingBalance" value = "Closing Balance"/>
<h:inputText id = "ClosingBalance" size="15"
binding = "#{accountSearcher.closingBalanceTextField}"
value = "#{accountSearcher.account.closingBalance}"/>
</h:panelGrid>
<hr>
<p>Contact Details:</p>
<h:panelGrid columns="2">
<h:outputLabel for = "Address" value = "Address"/>
<h:inputTextarea id = "Address"
binding = "#{accountSearcher.addressTextArea}"
value = "#{accountSearcher.account.address}"/>
<h:outputLabel for = "EmailId" value = "EMail Id"/>
<h:inputText id = "EmailId" size="15"
binding = "#{accountSearcher.emailIdTextField}"
value = "#{accountSearcher.account.emailId}"/>
<h:outputLabel for = "PhoneNumber" value = "Phone Number"/>
<h:inputText id = "PhoneNumber" size="15"
binding = "#{accountSearcher.phoneNumberTextField}"
value = "#{accountSearcher.account.phoneNumber}"/>
</h:panelGrid>
</h:form>
</body>
</f:view>
</html>
The main thing to observe in the Jsp Page is for the <a4j:support> tag which is embedded within the <h:inputText> tag representing the Account Number. Since we want support for the Account Number Text-Field we have done like this. That's all, just by adding this support Tag within the Jsf UI Components, automatically Ajax Support will be applicable to the JSF UI Components. The attribute 'event' is set to 'onblur' which means that the corresponding listener method as represented by the 'actionListener' attribute (search() defined inside the AccountSearcher class) will be called when the focus is lost from the Text Field control (which means after tabbing out from the Control). The most significant attribute is the support tag is the 'reRender' attribute which takes a comma separated list of Component Identifiers that want to be re-rendered once the control returns back from the Server.
The 'binding' attribute evaluates to a Jsf EL Expression, if specified will map to the corresponding UI Component in the Backing Bean Class. For example, consider the following code snippet,
<h:inputText id = "AccountNo" binding = "#{accountSearcher.accountTextField}">
</h:inputText>
The binding expression is given as "#{accountSearcher.accountTextField}, which means that the Input Control directly maps to a property by name accountTextField in the AccountSearcher class which is of type javax.faces.component.UIInput. Following is the Java Code for the same,
AccountSearcher.java
public class AccountSearcher {
private UIInput accountTextField;
// Getters and Setters for the same.
}
5.5) Account.java
Following is the class that encapsulates pieces of information like Account Number, Bank Name, Customer Name, Branch Name, Account Opening Date, Contact Information inside the Account class. Following is the complete Listing for the Account.java class.
Account.java
package net.javabeat.articles.ajax4jsf.introduction;
import java.util.Date;
public class Account {
private long accountNo;
private String bankName;
private String customerName;
private String branchName;
private String openDate;
private double closingBalance;
private String address;
private String emailId;
private String phoneNumber;
public Account() {
}
public long getAccountNo() {
return accountNo;
}
public void setAccountNo(long accountNo) {
this.accountNo = accountNo;
}
public String getBankName() {
return bankName;
}
public void setBankName(String bankName) {
this.bankName = bankName;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getEmailId() {
return emailId;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
public String getBranchName() {
return branchName;
}
public void setBranchName(String branchName) {
this.branchName = branchName;
}
public String getOpenDate() {
return openDate;
}
public void setOpenDate(String openDate) {
this.openDate = openDate;
}
public double getClosingBalance() {
return closingBalance;
}
public void setClosingBalance(double closingBalance) {
this.closingBalance = closingBalance;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
5.6) AccountCreator.java
This Utility Class is used to create Dummy Account Information Objects and acts as Storage for those Account Objects. When looked-up for an Account object by giving the Account Number as a Key, the appropriate Object is returned. The Managed Bean references this Class heavily for creating and retrieving Account Objects. Following listing is the complete code for AccountCreator.java
AccountCreator.java
package net.javabeat.articles.ajax4jsf.introduction;
import java.util.HashMap;
import java.util.Map;
public class AccountCreator {
private static Map<Long, Account> accounts;
public static void createTestAccounts(){
if (accounts == null || accounts.isEmpty()){
accounts = new HashMap<Long, Account>();
}
Account account = null;
account = createAccountInfo(123456, "Hdfc Bank",
"Jenny", "Shastri Nagar, Chennai",
"10/05/2003", 100033.53, "Address1",
"jenny@gmail.com", "99123456789");
accounts.put(account.getAccountNo(), account);
account = createAccountInfo(234567, "Icici Bank",
"Joseph", "Besant Nagar, Chennai",
"121/09/2001", 3200033.53, "Address2",
"joseph@gmail.com", "99987654321");
accounts.put(account.getAccountNo(), account);
}
private static Account createAccountInfo(long accountNo, String bankName,
String customerName, String branchName, String openDate,
double closingBalance, String address, String emailId, String phoneNumber){
Account account = new Account();
account.setAccountNo(accountNo);
account.setBankName(bankName);
account.setCustomerName(customerName);
account.setBranchName(branchName);
account.setOpenDate(openDate);
account.setClosingBalance(closingBalance);
account.setAddress(address);
account.setEmailId(emailId);
account.setPhoneNumber(phoneNumber);
return account;
}
public static Account getAccountInfo(Long accountNo){
return accounts.get(accountNo);
}
}
5.7) Account Searcher.java
This Managed Bean takes care of creating Dummy Account Objects and it returns the appropriate Account Information back to the Client upon Request. Most of the code in this class represents the getters and the setters for the various UI Components in the Jsp Page. The search logic is implemented in the search() method which takes ActionEvent as its only parameter. Following is the code for the same.
AccountSearcher.java
package net.javabeat.articles.ajax4jsf.introduction;
import javax.faces.component.UICommand;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
public class AccountSearcher {
private Account account;
private UIInput accountTextField;
private UIInput bankNameTextField;
private UIInput customerNameTextField;
private UIInput branchNameTextField;
private UIInput openDateTextField;
private UIInput closingBalanceTextField;
private UIInput addressTextArea;
private UIInput emailIdTextField;
private UIInput phoneNumberTextField;
public AccountSearcher() {
AccountCreator.createTestAccounts();
}
public void search(ActionEvent actionEvent){
String strAccountNo = (String)getAccountTextField().getSubmittedValue();
long accountNo = 0L;
try{
accountNo = Long.parseLong(strAccountNo);
account = AccountCreator.getAccountInfo(accountNo);
if (account != null){
setComponentsValueToNull();
}else{
// Error Message.
}
}catch(Exception exception){
exception.printStackTrace();
}
}
private void setComponentsValueToNull(){
bankNameTextField.setSubmittedValue(null);
customerNameTextField.setSubmittedValue(null);
branchNameTextField.setSubmittedValue(null);
openDateTextField.setSubmittedValue(null);
closingBalanceTextField.setSubmittedValue(null);
addressTextArea.setSubmittedValue(null);
emailIdTextField.setSubmittedValue(null);
phoneNumberTextField.setSubmittedValue(null);
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public UIInput getAccountTextField() {
return accountTextField;
}
public void setAccountTextField(UIInput accountTextField) {
this.accountTextField = accountTextField;
}
public UIInput getBankNameTextField() {
return bankNameTextField;
}
public void setBankNameTextField(UIInput bankNameTextField) {
this.bankNameTextField = bankNameTextField;
}
public UIInput getCustomerNameTextField() {
return customerNameTextField;
}
public void setCustomerNameTextField(UIInput customerNameTextField) {
this.customerNameTextField = customerNameTextField;
}
public UIInput getBranchNameTextField() {
return branchNameTextField;
}
public void setBranchNameTextField(UIInput branchNameTextField) {
this.branchNameTextField = branchNameTextField;
}
public UIInput getOpenDateTextField() {
return openDateTextField;
}
public void setOpenDateTextField(UIInput openDateTextField) {
this.openDateTextField = openDateTextField;
}
public UIInput getClosingBalanceTextField() {
return closingBalanceTextField;
}
public void setClosingBalanceTextField(UIInput closingBalanceTextField) {
this.closingBalanceTextField = closingBalanceTextField;
}
public UIInput getAddressTextArea() {
return addressTextArea;
}
public void setAddressTextArea(UIInput addressTextArea) {
this.addressTextArea = addressTextArea;
}
public UIInput getEmailIdTextField() {
return emailIdTextField;
}
public void setEmailIdTextField(UIInput emailIdTextField) {
this.emailIdTextField = emailIdTextField;
}
public UIInput getPhoneNumberTextField() {
return phoneNumberTextField;
}
public void setPhoneNumberTextField(UIInput phoneNumberTextField) {
this.phoneNumberTextField = phoneNumberTextField;
}
}
Take a careful look at the implementation of the Search Logic. After getting the submitted value of the Account Text Field by calling UIInput. getSubmittedValue(), the code tries to perform a lookup operation in the Account Storage. If an Account object is obtained, then the code explicitly sets all the submitted information of the UI Components to Null. This is necessary because by setting all the Submitted Value of the Input Components to null, we are ensuring that the Component's Value will be taken from the appropriate Model Objects.
6) Conclusion
Many of the Vendors have started using Ajax4Jsf Framework in their Web Applications due to its simplicity. No need to depend on JavaScript code to make use of Ajax Functionality. This article initially focused on explaining the need to have another Framework for the Web Tier. Then it provided a Brief Information about the Workflow that happens in an Ajax4Jsf enabled Web Application. Then the most commonly used Ajax4Jsf Tags are explained in detail. Finally the article concluded by giving a Sample AutoComplete Application for populating the User Account Information when given the Account Number.
|