|
|
JSF introduction | jsf webapp basics | jsf webapp features | practicalities
Last updated: August 2009
Java Server Faces (JSF) is a component-oriented web application framework.
Being a JEE standard backed by Sun, it has been steadily been growing in
popularity and is overtaking Struts. JSF allows third parties to create
components and offers the promise of RAD (GUI-oriented) development.
Furthermore, if you use it in conjunction with Seam you have an end-to-end
solution to enterprise development.
|
||||
|
|
introduction For the JSF version of WebOfContacts these technologies were used:
contactsdb
database set up . Then
download the EAR from this site
(make sure to retain the .ear extension)
into your JBoss's webapps directory, explode it using jar -xvf,
and view the application in your browser at
http://localhost:8080/WebOfContactsJSF/index.faces (log in as admin/admin).
The full source is available for download as an
Eclipse project.
There are two implementations for the JSF API: the Sun Reference Implementation
(used by WebOfContacts) and the Apache MyFaces implementation. Both Seam and
the Facelets extension (see Page Composition) can be used with either
implementation.
Special deployment note: in order for file upload to work the .ear must be
deployed in exploded form. This can be buggy in some versions of JBoss AS 5.0.2.
If you run into this problem, in the file
${JBOSS}/server/default/deployers/seam.deployer/META-INF/seam-deployers-jboss-beans.xml
remove this line:
<bean name="SeamMTMatcher" class="org.jboss.seam.integration.microcontainer.deployers.SeamTempModificationTypeMatcher"/> |
||||
|
jsf webapp basics In regard to basic flow control a link in a JSF page to another page may look like this: <h:outputLink value="contactForm.seam"><h:outputText value="CREATE CONTACT"/></h:outputLink> When the user clicks on the text CREATE CONTACT,
contactForm.xhtml is brought up. There is no file called
contactForm.seam -- the .seam extension (or .faces extension
for standard JSF) is mapped to
whatever real extension has been defined in web.xml for the
property javax.faces.DEFAULT_SUFFIX. By default this extension
is .jspx but when using the Facelets extension, .xhtml is used.
A link doesn't have to go to another page directly; it could call a method
in Java code like this:
<h:form><h:commandLink action="#{contactList.list}"><h:outputText
value="LIST CONTACTS" /></h:commandLink></h:form>
The word contactList in this code refers to the class
ContactListAction. Where is this mapping done? In standard JSF,
you would use the main JSF configuration file, faces-config.xml, to
declare a managed bean like this.
<managed-bean>
...
<managed-bean-name>contactList</managed-bean-name>
<managed-bean-class>
com.oranda.webofcontacts.jsf.action.ejb.ContactListActionBean
</managed-bean-class>
</managed-bean>
However, WebOfContactsJSF uses a helper technology called Seam which allows
you to do some things more concisely with annotations, including naming the bean at the
top of the class itself, i.e. @Name("contactAction").
After the list method in ContactActionBean is called,
the framework needs to know what the next page is for the browser. We need to
define it as listContacts.xhtml. Again there is a difference between traditional
JSF and Seam. In traditional JSF, navigational rules go in faces-config.xml and
look like this:
<navigation-rule>
<from-view-id>/*</from-view-id>
<navigation-case>
<from-action>#{ContactBean.list}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/listContacts.xhtml</to-view-id>
</navigation-case>
...
</navigation-rule>
This assumes that the list method is returning the outcome String
"success".
With Seam there is a different approach: navigational rules go in pages.xml (or more-specific-pages.xml files). Here is a typical group of rules which assumes that methods are returning outcomes that are the same as the page names that are desired.
<page view-id="/index.xhtml" login-required="true">
<navigation>
<rule if-outcome="listContacts">
<redirect view-id="/listContacts.xhtml"/>
</rule>
<rule if-outcome="listUsers">
<redirect view-id="/listUsers.xhtml"/>
</rule>
<rule if-outcome="contactForm">
<redirect view-id="/contactForm.xhtml"/>
</rule>
</navigation>
</page>
A typical page in JSF does not use any scriptlets at all, but relies entirely on the tag libraries provided by the framework and declared at the head of the Web page like this:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
It is also possible to specify libraries within the Facelets
ui:composition tag.
The html library provides form tags. The last section already
illustrated the use. Here is another example, showing a complete form for
searching:
<h:form><h:inputText id="searchTerm"
size="6" value="#{contactListAction.searchTerm}" required="true"/>
<h:commandButton id="search" action="#{contactListAction.search}"
value="Search" /></h:form>
As if to wean the developer off including logic in the view,
the JSF tags do not include logic tags (iteration, conditions, etc).
For iteration you would use the dataTable tag.
For conditions you can either use the rendered attribute for
elements, or mix in JSTL tags (but this requires a bit
of extra care because the two sets of tags evaluate at different
times in the lifecycle).
WebOfContacts uses the Facelets extension which has many features for
the view. For example, one feature not illustrated in the application is
the ability to use ordinary HTML tags along with a jsfc attribute to
convert it to the appropriate JSF tag:
<input type="text" jsfc="h:inputText" value="#{hello.world}" />
However, the most important feature provided by Facelets is the ability to
compose pages with headers, footers, navigation, etc.
For WebOfContacts there is a general template called layout.xhtml. Note the
include calls in the following fragment:
<td colspan="2" id="header">
<ui:insert name="header">
<ui:include src="header.xhtml"/>
</ui:insert>
</td>
...
<td id="body" valign="top">
<ui:insert name="body">
<ui:include src="body.xhtml"/>
</ui:insert>
</td>
Now an actual page like listUsers.xhtml specifies the
template layout.xhtml in the ui:composition tag and then
gives values for header and body in this way:
<ui:composition template="/WEB-INF/layout/layout.xhtml">
<ui:define name="title">List of Users</ui:define>
<ui:define name="body"><h3>List of Users</h3>
...
</ui:define>
</ui:composition>
Next let's consider the application tiers.
JSF has a clean separation between Model, View, and Controller
(MVC). Web pages (the View) make calls to backing beans
(the Controller) which manipulate the domain object (the
Model). In WebOfContacts the main backing beans are
ContactActionBean, ContactListActionBean,
and UserActionBean which use the model objects
Contact and User. It is possible for them
to use them directly, but I've chosen a layered approach (consistent
with other versions of WebOfContacts) where calls
go through a service layer and a DAO layer.
JSF can work with many different enterprise-level technologies, but
Seam is a good choice. One of the motivations behind Seam was to "stitch JSF and EJBs together".
Secondly, Seam came from the Hibernate team, so another big idea was to make
Hibernate play better with the Web tier by making "application transactions" easier
(avoiding the dreaded LazyInitializationExceptions caused by
parts of the data model becoming unbound over multiple web requests). Thirdly,
Seam provides application features like dependency injection and AOP
that in some ways compete with (though can also cooperate with) Spring.
With Seam we can use the solid transactional model of EJBs and maintain
conversational state
from request to request at the web tier. The action/controller beans in WebOfContactsJSF
are actually stateful session beans, while the domain objects are entity beans
annotated with integrity constraints and typical one-to-many relationships. The DAO
classes contain the EJB-QL logic for queries, e.g.
public ListNotice the instance of EntityManager (a very standard
EJB3 interface) above. Apart from EJB-QL this is useful for its
persist method (to save a new contact or any other
type of entity) and merge method (to update the entity).
The entity manager is injected into the entity's class by Seam using the
@PersistenceManager annotation. In fact, with a bit more
configuration work (in persistence.xml), it could also be injected
using Seam's generic @In annotation, which is used
freely in WebOfContacts to connect classes to each other via their bean names as
defined in the @Name annotation.
In terms of deployment, neither JSF nor Seam are bound to any specific server product. However, for Seam you are generally working with EJBs so you need more than Tomcat. Since Seam comes from the same team as JBoss, JBoss Application Server is a good choice.
|
|
jsf webapp features
With standard JSF, form validation can be handled
in the Java of the backing bean. For example, here is code
for a text field in the Web page for entering in phone number(s):
|
|
practicalities If you make good use of dependency injection, it is easy to isolate and unit test individual classes with tools like JUnit and JMock. For system-wide testing, a good tool is JSFUnit (it also works well with Seam). Originally based on Cactus, JSFUnit runs inside the container, so it can access FacesContext,
the main UI object in JSF.
What about the usability of the
framework? The framework has steadily been maturing with standard
add-ons like Facelets and Seam making life easier for the developer.
One key issue is hot deployment: exactly what can be updated in Seam
without restarting the server depends on what Seam version you are using,
which application server you are using, etc. It always takes effort to make
it work "seamlessly". This, of course, is the case with most webapp
frameworks.
JSF is component-oriented by design, so third-parties can extend it.
Consequently UI components for JSF are getting easier and easier to find.
RichFaces
from Exadel and JBoss is probably the most popular collection. There is
also Seam's own library and
Oracle ADF Faces. These modern component libraries are Ajax-enabled,
meaning developers can aim for desktop-like functionality in their
web applications.
Annother advantage of being component-oriented is that JSF is more suited
to RAD tools than other frameworks. The idea is that applications can be
prototyped (at least) in a graphical drag-and-drop environment. However,
tools like Sun Java Studio Creator and Exadel Studio do not seem to have
caught on in the way that was originally hoped for.
|