|
2) Java Server Faces - An UI Framework
In Fact, JSF is nothing but an abstraction over the existing Web Framework.
JSF is implemented as a Servlet which is called the
Faces Servlet. Before the advent of JSF, Servlets and
JSP are the predominant ones that form the core components in the development of a
Web Application. Let us see the traditional interaction that takes place in a Web Application
is developed only with the Servlet and the JSP components that follows
the MVC-2 Architecture. A client who is normally a HTML Browser sends a request to the server. The Web Server
receives the request, encapsulates the request and then populates this request object with
the various parameter values from the client and will send it to the
Servlet. The Servlet which acts as a Controller, analyses the request,
then will interact with the Model (Java Beans) that executes the various
application business logic and then chooses which View to be shown to the User.
Java Server Faces which provides a Component-Based Architecture for developing
reusable User Interface Components hides most of the complex stuffs that are happening in the
View portion of the MVC-2 Architecture. The framework is not only
limited to developing customized User Interface Components but also provides support for various
Advanced Features like Event handling Mechanism, Validating User Inputs
that are sent by the clients, Easy Page Navigation Mechanism etc. The good thing
about Java Server Faces is that the degree of coupling between the
UI Components that represent the various behaviour/properties and its
Rendering is very low. In fact it is almost nill. So, HTML browsers are not the
only target client applications. JSF Applications works even well with WML Browsers.
3) Basic Elements of JSF
Let us examine the various core basic elements in a JSF application. The most significant
components in a JSF application are explained as follows.
- User Interface Components
- Managed Beans
- Validators
- Convertors
- Events and Listeners
- Page Navigation
- Renderers
All the above-mentioned components can be found in separated packages in the API. For example,
the User Interface Components are available in
javax.faces.component package,
Validation API is available in
javax.faces.validator package and so on.
3.1) User Interface Components
If Java Swings represent the UI components for a
Desktop Java Application, then JSF UI Components are meant for the
Web Applications. The JSF User Interface Components are developed with
Java Beans Specifications and Standards in mind. It means that
JSF Components have properties, methods and
events as they are normally found for a traditional
Java Bean. One of the peculiar
features of the JSF UI Components is that they can manage the state
of the component. So many built-in UI components are bundled with the JSF API, the most commonly
used ones are Label, Text-Field, Form,
Check-Box, Drop-Down Box etc. JSF also provides a framework for
creating Customized UI Components.
It is very important to note that JSF UI Components only represent the
attributes, behaviors and events for a
component and not the actual display. For example in a
Text-Field Control, the attributes may be the value of the
text-field, the maximum number of characters that can be entered etc.
Modifying the existing value and setting the maximum number of characters forms the
behaviour for the Text-Field. Change in the value of
the Text-Field may cause the Text-Field to cause some kind of Event to be emitted.
The manner is which text-field is displayed in the client is
separated from the UI Data Representation itself.
It means that there are separate components called Renderers which will take care of
displaying the UI components in Different Client Surfaces, one client may be the
HTML Browser running in a PC and the other may be the
WML Browser running within a mobile phone. Each and every JSF component
is uniquely identified by a Component Identifier.
3.2) Managed Beans
Managed Beans are standard Java classes that follow the Java Beans
Specification.Generally, Managed Beans are used to represent the
user inputs. They may even act as Listeners and can handle the appropriate
Actions. Assume that there is an Encryption Application, which is presented with a
Text-Field, wherein which user can enter a string that is to be encrypted. Below that is a Encrypt
Button, which when clicked calls the server code that does the actual job of Encryption.
The following code snippet shows how to represent the Text-Field and the command button,
<html:inputText
id = "strToBeEncryptedTextField"
value = "#{EncryptionBean.strToBeEncrypted}">
</html:inputText>
<html:commandButton
id = "encryptButton"
actionListener = "#{EncryptionBean.doEncryption}">
</html:commandButton>
|
Don't worry about the declaration of the Text-Field and the Command Button here. The syntax for
their declaration in covered in the later sections.
The first noticeable thing is that the Text-Field has two attributes namely
id and value.
The id attribute uniquely identifies the Text-Field component from other Components in the View.
The value for the attribute value is
#{EncryptionBean.strToBeEncrypted}.
This expression is a JSF EL Expression. The EL expression can be
interpreted as follows, Take the value of the string to be encrypted from the UI Component
and map it to the property called
strToBeEncrypted which is inside the class
called EncryptionBean.
It means that the declaration of the Managed Java Bean class may look something
like the following,
class EncryptionBean{
private String strToBeEncrypted;
public String getStrToBeEncrypted(){
return strToBeencrypted;
}
public void setStrToBeEncrypted(String strToBeEncrypted){
this.strToBeEncrypted = strToBeEncrypted;
}
// Other things goes here
}
|
From the declaration of the command button object, we can interpret that, 'encryptButton' is
uniquely used to identify the command button object, the attribute
actionListener is used to
provide the listener method that will get invoked as a result of someone clicking the button.
So, actionListener = "#{EncryptionBean.doEncryption}"
essentially says that there is a method called
doEncryption() within the
EncryptionBean class. Following code
snippet may prove this,
class EncryptionBean{
…
public void doEncryption(javax.faces.event.ActionEvent event){
}
…
}
|
3.3) Validator
Validation is a must for almost any application. Data entered by the clients have to
be validated before being sent to the Server for processing. JSF already have the
Common Validation API being implemented for almost all controls in the
javax.faces.validator package and also
through various Custom Tags. The Validator Framework that is
available with JSF is pluggable, i.e it also allows the developers
to provide their own Custom Validation Classes through the help of
Configuration Files.
Suppose say, there is a Text-Field Component in the form which inputs the age from the user to
get some benefit from the organization. We can have a Simple Validation Rule
telling that only Employees who are above 35 and below 45 are eligible for such a benefit.
This can easily achieved through the use of Custom Validation Tags like the
following one,
<html:inputText identifier = "employeeAgeTextField">
<f:validateLongRange minimum = "25" maximum = "35">
</f:validateLongRange>
</html:inputText>
|
JSF will immediately report a Default Error Message whenever the value of the age
entered by the user crosses the boundary range of 25-35.
Two types of Validation are possible in JSF. They are,
- Direct Validation
- Delegated Validation
i). Direct Validation:
Assume that there is a Customized UI component called E-Mail Text Field which allows
the user to enter only email-ids in the appropriate format. Whenever a user enters some email-id, the UI component has to
validate whether the given email-id is in the right format, something like
username@someDomain.com. It is wise to embed the Validation Logic within the
component itself. Such Validation Code which is found within the UI component and can be used
only by that Component is called
Direct Validation.
ii). Delegated Validation:
Delegation Validation comes into picture when the Validation Logic is about to
be re-used across so many Components. Common Validation stuffs are ideal candidates
for Delegated Validation. For example, consider in a form where we have a Text-Field representing the
name of a customer and a Radio-Button for Marital Status with values 'Married' and 'Single'. If both
are required fields, then before the submission of the form, both the input fields
(text-field and the radio-button) have to be validated for empty (or null) values. So, in such
a case we can have a Validator called
NullCheckValidator and then bind both
the input components to this Validator.
3.4) Convertors
Every piece of request that is passed from the client to the server is interpreted as a String value
only. Manual conversion of the String object to the appropriate Data-type has to be done in the
Application Code before carrying on with the application logic. Suppose in a form, there are fields
like name, age and date. Corresponding to this form, we would have constructed a
Managed Bean representing name, age and date as properties
with String, integer and Date respectively. Certain amount of code has to be written for the
conversion of the age and date values to their corresponding int and Date types.
But because of the availability of JSF Convertors functionality, this becomes easy.
In the declaration of the UI Component itself within the form, we can mention
which data-type the value for this control has to be converted. The Conversion API
is available in javax.faces.convert.
For example, consider the following piece of code,
<html:inputText identifier = "numberTextField">
<f:convertNumber pattern = "###,###">
</f:convertNumber>
</html:inputText>
|
In the above, we have a Number Converter which converts the number given by the user
to the specified format. For example, if the original value entered by the user is 123456, then the
after the conversion process the value becomes '123,456'.
3.5) Events and Listeners
JSF UI Event Mechanism is very similar to the one found in
Swing UI Components. The Architecture remains the same in both the cases. In JSF,
all the UI Components can emit any number of events. For example, a
Button Component, when clicked by the user can emit an
ActionEvent.
Those which take appropriate actions after a component has emitted some kind of Events
are called Event Listeners. In JSF, Java Managed Beans also acts as
Listeners for the Events emitted by the components.
For example, consider the following code snippet,
<html:inputText
identifier = "submitButton"
value = "Click Me"
actionListener = "#{SomeBean.submitButtonClicked}"
</html:inputText>
|
In the above code, we can see that how a UI Component can be associated with an
Event-Handler with the help of actionListener attribute. The code essentially says
that whenever an ActionEvent is emitted by
the button (which will happen usually when the user clicks the button or presses the Enter key over
the button) call the Event Listener's method
submitButtonClicked inside the
SomeBean class.
3.6) Navigation
An user of a Web Application doesn't restrict himself in viewing one single Web Page. He/She will
navigate from one page to another page. Technically the navigation of a user from
one page to another page results in the generation of request and response for that page. Most
of the boiler-plate work that is related to navigation stuffs in a web-application is handled by the
Default JSF Navigation Handler itself. The Navigation Handler provides a simple yet
a powerful framework for controlling the navigation.
For any single request page, there may be a number of response pages. Assuming that in a
data-entry application, if the request page, say 'enterdata.jsp', is a view showing all the input
controls to get data from the user, then the following responses may be available.
-
The user has entered all the data and the result is a 'success' so that a page called
'success.jsp' page is displayed
-
The user has entered a mix of correct and incorrect data in which case, the result or the
response is a 'partialsuccess' and some jsp page called 'partialsuccess.jsp' is displayed.
-
The user hasn't entered any correct values which means that result is a 'failure' which
results in the display of a page called 'failure.jsp'.
If we look at a very high-level, almost all of the pages will have this kind of
Navigation Rule which will have N number of Navigational Cases. As such,
we can define the Navigational Rules along with Navigational Cases for handling the navigational
logic for the entire JSF application in the JSF Configuration File.
For example, the following is a simple navigation rule for the above sample scenario,
<navigation-rule>
<from-view-id>/dataentry/enterdata.jsp</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/dataentry/success.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>partialsuccess</from-outcome>
<to-view-id>/dataentry/partialsuccess.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>failure</from-outcome>
<to-view-id>/dataentry/failure.jsp</to-view-id>
</navigation-case>
</navigation-rule>
|
The above code within the Configuration File states for the jsp file 'enterdata.jsp' (where
'/dataentry/' is the context path), if the outcome is 'success', navigate to 'success.jsp,
if the outcome is 'partialsuccess', then navigate to 'partialsuccess.jsp', else if the outcome
is 'failure', then take the user to 'failure.jsp'.
|