Preface
JavaServer Faces, aka JSF, is a client-server framework for building Java-based web applications -
a framework for developing web applications, and wiring their client-side user interface with the server-side.
Although there are many tutorials about JSF, many developers and architects disqualify the JSF framework.
We give in here some common complaints and then argue them:
-
How does JSF co-exist with the popular MVC design-pattern?
-
JSF represents only one part of the MVC design-pattern - the View.
The view part of MVC is a complex issue by itself and is built from both client-side code and server-side code
and the interaction between them.
-
I had a bad experience with JSF. It did not give me an adequate solution to client-server interaction. I
needed to use several third-party libraries and still I did not get a qualified solution to the
client-server challenge as I expected.
-
It is true that older versions of JSF lack many aspects of an adequate client-server framework.
There was a
massive use of several third-parties libraries and building an infrastructure with many libraries that
co-exist with each other and use their matching versions in order to work together was a very hard
thing to do. But still, this was the best choice for the java community for several years.
We are glad to announce that since JSF 2.0 there is an amazing and continuance improvement on the JSF
framework. It is a much more reacher framework than before and supports up-to-date aspects of client-server
challenges, such as AJAX, JSONP, File-Upload, HTML5, CSS3 and more.
A JSF framework does not need anymore third-party libraries, because it is comprehensive enough.
-
While JSF tries to introduce a framework for HTML client-server interaction, it displays a poor HTML solution.
It has only basic HTML components that does not compete with evolving market and HTML challenges.
-
The JSF framework comes with a default render-kit for rendering HTML markup,
that is tightly bound to server-side Java-Beans. While it gives a great solution for simple HTML
components, like radio buttons, input text, forms and selectors, you still need to use HTML libraries
in order to make your site amazing.
This does not reduce from its ability to ease the clent-server interaction. You can still use the default
render-kit components effectively with another HTML widget library that can wrap the JSF
components. Notice that there is a separation of activities here. The rendering of the JSF components
happens on the server side, and the wrapping of the JSF components with an happens on the client side,
and to be more specific, on the web browser.
We recommend to use Kendo UI HTML5 Widget Library.
It gives a very rich controls for the browser and works seamlessly with JSF.
-
It is lacking the separation of responsibilities between client-side developement and server-side developement.
-
Although JSF is written both in the client-side and in the server-side, it represents only one part of the
MVC deign-pattern - the View.
It is up to the organization if to refer to JSF technology as a server-side
framework or client-side framework. In most cases it is developed by client-side developers that also write
java code, while yje latter also interacts with other layers of the application such as the Model layer
and Controller layer.
Terminology
-
JSF Component - is a JSF code idiom, which is built of a collection of server-side code and client-side
code that works together in order to perform or represent a specified functionality. The JSF framework manages
the life-cycle of this code and is also responsible for the rendering of the client-side code. Examples are:
-
A client-side form controller that sends its elements to the server and automatically populates
a java bean on the server side
-
A client-side table / grid controller that is automatically synchronized with its server-side representation
Main Features
The main features of JavaServer Faces are:
-
A GUI Component Framework - the browser's HTML tags are tightly coupled with the server code,
as a set of Java classes
-
Different markup languages - a flexible model for rendering components in different markup languages, such as
HTML, SVG, XUL, or even create your own custom render kit
-
a
javax.faces.render.Renderer
class that translates JSF components into browser's markup code and delegates HTTP requests and
responses between the server and the web browser. E.g.:
-
JSF form components (
h:form
) to HTML "form
" tags
-
JSF table components (
h:datatable
) to HTML "table
" tags
-
JSF drop-down / select-box components (such as
h:selectOneMenu
) to HTML "select
"
tags
-
JSF checkbox components to HTML
input type="checkbox"
tags
-
JSF Container components (such as
h:panelGroup
) to HTML "div
" tags
- etc...
-
A standard
javax.faces.render.RenderKit
for generating HTML markup.
Complementary GUI Components features
The following features support the GUI components:
-
Input validation - validation of input fields received by an HTTP request from the browser
-
Event handling - attaching listeners to different browser events, like changing input field,
change in a drop-down and so forth
-
Data conversion - The framework automatically casts from strings received from the HTTP request
and their corresponding type on the server-side. E.g. "
1
" may be cast
to int, 1.5
to float.
-
Managed object-model life-cycle - The JSF object life-cycle are managed by the framework. It supplies an
API for:
- Representing components and managing their state
- Handling events, server-side validation, and data conversion
- Defining page navigation
- Supporting internationalization and accessibility
- Providing extensibility for all these features
-
Page navigation configuration - The navigation to application screens may be configured and controlled easily
-
Expression Language (aka EL) - using expressions that map directly to server objects
-
Tag libraries - Using JSF tag and EL tags on web pages to represent JSF components
Benefits of JSF Infrastructure
- Drop components onto a web page by adding component tags.
- Bind components on a page to server-side data.
- Wire component-generated events to server-side application code.
- Save and restore application state beyond the life of server requests.
- Reuse and extend components through customization.
New JSF Features
The Java EE 6 platform contains implementations of JavaServer Faces version 2.0 and
Expression Language version 2.2. These implementations adds a lot of functionality and makes the
developement of JSF applications much easier. The new features are:
-
JSF annotations - The ability to use JSF annotations instead of a configuration file in order
to specify managed beans and other components
-
Facelets - a display technology that uses templates and analyzes XHTML syntax files instead of
JavaServer Pages (aka JSP) files. By using XHTML the JSF render kit engine can better
analyze the files and support more features.
- Ajax support
-
Composite components - the ability to write your own components using the same template engine
and render kit
-
Implicit navigation - Using navigation results with the page navigation feature directly inside the
JSF markup
JSF Version History (for Infrastructure Development and Architects)
When you download the JEE developement kit it comes with all the implementations and their correct versions that
JSF and other resources need. While this is a very simple task to do, in most cases you will not want all the JEE
SDK to be included in your distribution and run on your server, therefore, you usually prefer to get just what you
need. In order to do so you need to work what are the pieces that work together. Here is a short summary of some
of the JSF building blocks:
J2EE 1.4
Java Servlet |
2.4 |
JSR154 |
JavaServer Pages (JSP) |
2.0 |
JSR152 |
JavaServer Pages Standard Tag Library (JSTL) |
1.1 |
JSR52 |
JavaServer Faces (JSF) |
1.1 |
JSR127 |
Java EE 5
Java Servlet | 2.5 | JSR154 |
JavaServer Faces (JSF) | 1.2 | JSR252 |
JavaServer Pages (JSP) | 2.1 | JSR245 |
JavaServer Pages Standard Tag Library (JSTL) | 1.2 | JSR52 |
Debugging Support for Other Languages | 1.0 | JSR45 |
Java EE 6
Java Servlet | 3.0 | JSR315 |
JavaServer Faces (JSF) | 2.0 | JSR314 |
JavaServer Pages (JSP) | 2.2 | JSR245 |
Expression Language (EL) | 2.2 | JSR245 |
JavaServer Pages Standard Tag Library (JSTL) | 1.2 | JSR52 |
Debugging Support for Other Languages | 1.0 | JSR45 |
Java EE 7
Java API for WebSocket | | JSR356 |
Java API for JSON Processing | | JSR353 |
Java Servlet | 3.1 | JSR340 |
JavaServer Faces (JSF) | 2.2 | JSR344 |
Expression Language (EL) | 3.0 | JSR341 |
JavaServer Pages (JSP) | 2.3 | JSR245 |
JavaServer Pages Standard Tag Library (JSTL) | 1.2 | JSR52 |
JSF-2 Scopes
JSF2 offers six predefined @ManagedBean
scopes. Their lifetime and use are described
in detail below:
@RequestScoped
-
Lives – between the browser's submission of a request to the server and until the response was delivered back
to the browser.
-
Storing and Retrieval
-
JSF stores the bean as an attribute of
HttpServletRequest
with the managed bean name as key
- It is also available by
ExternalContext#getRequestMap()
- Usage - Use this scope for pure request-scoped data.
@ViewScoped
-
Lives - From an HTTP request for the specified view. It stays alive as long as you're interacting with the same
JSF view ("
f:view
") and until there is a request to a different view.
-
Storing and Retrieval
-
JSF stores the bean in the
UIViewRoot#getViewMap()
. The map itself is stored in the session.
- It is also available by invoking
ExternalContext#getRequestMap()
-
Usage - Use this scope for complex forms that their state needs to be retained in subsequent requests.
-
This also answers the multiple browser's tab issue. While the session scope is shared between multiple
browser tabs, the view scope is not shared.
FlashScoped
- there is no annotation for the flash scope.
-
Lives - the flash scope lives between views. In other words, it is a way for JSF views to make conversations
with each other.
-
Storing and Retrieval
-
You can retrieve the Flash Scope by invoking the following:
(FacesContext.getCurrentInstance().getExternalContext().getFlash())
-
Then, you can populate the flash by invoking:
flashRetrieved.put("bean", this);
-
To read the flash from the next view you can write:
#{flash.bean.text}
or
#{flash['bean'].text}
-
Usage - Use this scope for HTML forms (on different views) that need to interact with each other.
@SessionScoped
-
Lives - It is created upon the first HTTP request involving this bean in the session,
and lives as long as the HTTP session lives. This means that if the session is invalidated or the bean is
manually removed from the session, the bean will not live any more.
-
Storing and Retrieval - It is stored on the HttpSession. It can be retrieved by invoking
ExternalContext#getSessionMap()
.
-
Usage - For session-scoped data which can safely be shared among windows and tabs (views) from the same session.
@ApplicationScoped
-
Lives - It is created upon the first HTTP request involving this bean in the application,
or when the web application starts with the "eager=true" attribute on the managed-bean.
It lives as long as the web application lives, or while it was not manually removed from application map.
-
Storing and Retrieval - on the ServletContext
-
Usage - For pure application-scoped data which can safely be shared among all sessions.
@NoneScoped
-
Lives - It is created on each and every EL evaluation and destroyed right after the end of the
EL evaluation.
-
Storing and Retrieval - JSF does not store the bean anywhere.
-
Usage - Use this scope on beans that shhould behave only as data beans and need to be injected in another
scoped-bean (AcceptorBean). The injected bean will then live as long as the acceptor bean. The
advantage of using @noneScope is that you can use it as a @ManagedProperty in any bean of any scope.
@CustomScoped
-
Lives - Custom implemented.
-
Usage - if no one of the other scopes suits your requirements.
Processing GET request parameters
JSF 2.x you can use the "f:viewParam
" tag, inside "f:metadata
", to add functionality
to GET request parameters. You can attach to them Converters, Validators, Messages
and Events:
Eg-1
<f:metadata>
<f:viewParam name="id" value="#{bean.userId}"/>
<f:event type="preRenderView" listener="#{bean.init}"/>
</f:metadata>
Eg-2
<f:metadata>
<f:viewParam name="id" value="#{bean.user}"
converter="#{userConverter}"
converterMessage="Bad request. Unknown user."
required="true"
requiredMessage="Bad request. Unsupported link."
/>
</f:metadata>
Eg-3
<f:metadata>
<f:viewParam name="id" value="#{bean.user}"
converterMessage="Bad request. Unknown user."
required="true"
requiredMessage="Bad request. Unsupported link."
/>
</f:metadata>
Eg-4
<f:metadata>
<f:viewParam name="id" value="#{users.user}"
converter="#{userConverter}"
converterMessage="Bad request. Unknown user."
required="true"
requiredMessage="Bad request. Unsupported link."
/>
</f:metadata>
Managing Bean Lifecycle
You can react to the creation and the destruction of a
managed bean, as follows:
public class MyBean {
@PostConstruct
public void postCreate(){
...
}
@PreDestroy
public void preDestroy(){
...
}
To make things simpler, you can create an abstract class with these methods and extend it on managed-beans.
Implicit EL objects
JSF2 EL comes with several implicit EL objects:
-
#{component}
: the current javax.faces.component.UIComponent
-
#{facesContext}
: the current javax.faces.context.FacesContext
-
#{view}
: the current javax.faces.component.UIViewRoot
-
#{request}
: the current javax.servlet.http.HttpServletRequest
-
#{session}
: the current javax.servlet.http.HttpSession
-
#{application}
: the javax.servlet.ServletContext
-
#{flash}
: the current javax.faces.context.Flash
-
#{cc}
: the current Composite Component
-
#{requestScope}
: the current request attribute map
-
#{viewScope}
: the current view attribute map
-
#{sessionScope}
: the current session attribute map
-
#{applicationScope}
: the application attribute map
-
#{initParam}
: the current context parameter map
-
#{param}
: the current request parameter map
-
#{paramValues}
: the current request parameter values map
-
#{header}
: the current request header map
-
#{headerValues}
: the current request header values map
-
#{cookie}
: the current request cookie map
-
#{resource}
: converts a JSF resource identifier to a concrete resource URL.
Referring to the current component with EL
You can use the #{component}
EL object to reference the current component,
like the keyword of this
is used in Java classes:
<h:inputText value="#{bean.value}"
styleClass="#{component.valid ? '' : 'error'}"/>
Adding Ajax Capabilities
The f:ajax
tag
The f:ajax
tag adds Ajax capabilities to one or more JSF components.
It can be nested within a single UI component to enable Ajax for that component,
or it can wrap around multiple components to enable Ajax for many components.
Resolving render
(Re-render) IDs
Render IDs are resolved relative to the parent UINamingContainer
(javax.faces.component.UINamingContainer
) component. Examples of such components are
h:form
, h:dataTable
, ui:repeat
, etc. These components prepends
their own IDs to the client ID of their children.
The following idiom will not work:
<h:form id="form">
<h:commandButton value="Submit">
<f:ajax render="result" />
</h:commandButton>
</h:form>
<h:outputText id="result" value="#{bean.result}" />
Since the "result" ID is not in the UINamingContainer
where the ajax command resides, it will not be found by it.
If you prefix the ID to render with a colon (":
") it will be resolved relative to the view root.
So to fix the previous idiom we should write:
<h:form id="form">
<h:commandButton value="Submit">
<f:ajax render=":result" />
</h:commandButton>
</h:form>
<h:outputText id="result" value="#{bean.result}" />
Adding a colon tells the ajax tag to search for an absolute render ID, so if the id to be rendered resides in another UINamingContainer
,
we need to include its ID as well:
<h:form id="form">
<h:commandButton value="Submit">
<f:ajax render=":otherform:result" />
</h:commandButton>
</h:form>
<h:form id="otherform">
<h:outputText id="result" value="#{bean.result}" />
</h:form>
Ajax rendering of content outside form
See "Resolving render (Re-render) IDs"
Ajax rendering of content which contains another form
When you ajax render a content which contains another form, then the other form will render but it will loose some
of the information that it needs in order to communicate with the JSF framework.
The following idiom will not work:
<h:panelGroup id="firstPanel">
<h:form id="firstForm">
<h:outputLabel for="input" value="First form input" />
<h:inputText id="input" value="#{bean1.input}" required="true" />
<h:commandButton value="Submit form" action="#{bean1.submit}">
<f:ajax execute="@form" render="@form :secondPanel :messages" />
</h:commandButton>
<h:message for="input" />
</h:form>
</h:panelGroup>
<h:panelGroup id="secondPanel">
<h:form id="secondForm">
<h:outputLabel for="input" value="Second form input" />
<h:inputText id="input" value="#{bean2.input}" required="true" />
<h:commandButton value="Submit other form" action="#{bean2.submit}">
<f:ajax execute="@form" render="@form :firstPanel :messages" />
</h:commandButton>
<h:message for="input" />
</h:form>
</h:panelGroup>
To get it to work you need to Explicitly add the client ID of the other form in the f:ajax
render
:
<h:panelGroup id="firstPanel">
<h:form id="firstForm">
<h:outputLabel for="input" value="First form input" />
<h:inputText id="input" value="#{bean1.input}" required="true" />
<h:commandButton value="Submit form" action="#{bean1.submit}">
<f:ajax execute="@form"
render="@form :secondPanel :secondForm :messages" />
</h:commandButton>
<h:message for="input" />
</h:form>
</h:panelGroup>
<h:panelGroup id="secondPanel">
<h:form id="secondForm">
<h:outputLabel for="input" value="Second form input" />
<h:inputText id="input" value="#{bean2.input}" required="true" />
<h:commandButton value="Submit other form" action="#{bean2.submit}">
<f:ajax execute="@form"
render="@form :firstPanel :firstForm :messages" />
</h:commandButton>
<h:message for="input" />
</h:form>
</h:panelGroup>
Ajax rendering of content which is by itself conditionally rendered
Elements that are conditionally rendered, may not be available to the f:ajax
component,
because the element to be rendered on the Ajax request may not be available on the page.
For example, in the following idiom, if "renderResult
" is false
while the page
is rendered, the "result
" component, which is conditionally rendered, will not be available
on the page, and thus will not be available to the "f:ajax
" component:
The following idiom will not work when #{bean.renderResult}
defaults to false
:
<h:form id="form">
<h:commandButton value="Submit">
<f:ajax render=":result" />
</h:commandButton>
</h:form>
<h:outputText id="result" rendered="#{bean.renderResult}" />
For this to work you need to ensure that you give the "render
" attribute
of the "ajax
" component an ID that points to a component which is already present in the output.
So we wrap the component to be rendered in a panel:
<h:form id="form">
<h:commandButton value="Submit" action="#{bean.toggleRenderResult}">
<f:ajax render=":result" />
</h:commandButton>
</h:form>
<h:panelGroup id="result">
<h:outputText value="#{bean.result}" rendered="#{bean.renderResult}" />
</h:panelGroup>
Common problems
- Merge JSF screens with new design from a designer
-
It is a common problem for JSF developers, when their site need to be upgraded with a new design.
They receive an HTML from a designer and need to integrate it in their existing,
fully-functional JSF application.
There are several ways to do that. As we experienced this problem we came to the following conclusions:
-
One may choose to take the code from the designer and then change the JSF code to match the markup code
from the designer. We found that it is a critical mistake. JSF deals with both design and
functionality
while the designer's code deals only with design. To match a fully-functional existing code with a
third-party code that deals only with the design is a very hard task. We don't want to change the
functionality of our application for this.
-
A better way may be to match the new design to the existing JSF code, which is already functional.
Changing code that deals with design issues only is a much simpler task than changing code that deals
with functionality.
No comments:
Post a Comment