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:
  • Java 6 (a.k.a. 1.6)
  • JSF 1.2_03-b09
  • Facelets 1.1.13
  • Hibernate 3.2
  • JBoss AS 5.0.1
  • MySQL 5.0.45
  • JUnit 3
  • Ant 1.7
  • Eclipse 3.4
  • Seam 2.2
If you want to download the .war and run this application on your own machine, then you can as JSF, Facelets 1.1, and Hibernate are included as jars in the webapp. However you will already need to have a version of Java at 5 or greater, a recent version of JBoss, Seam installed, and the 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 List getAllContacts() {
	    contacts = entityManager.createQuery(
	    		"select c from Contact c order by priority desc").getResultList();
		return contacts;
	}
Notice 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):

<h:inputText id="phoneNums" size="12"
value="#{contactAction.contact.phoneNums}"
validator="#{contactAction.validatePhoneNums}" />
Then in the ContactAction class, the code to validate would be:
	public void validatePhoneNums(FacesContext context, 
	        UIComponent toValidate, Object value) {
		String phoneNums = (String) value;
		
		// ... validation code ...
		// if the validation code fails
		FacesMessage message = new FacesMessage(
		        "Invalid Phone numbers");
		context.addMessage(toValidate.getClientId(context), 
		        message);
	}					

However, the same functionality can be provided more concisely using Hibernate validation annotations. Within the entity class itself, you can specify it with a regular expression above the getter:

	@Column (name="phone_nums")
	@Length(max=255)
	@Pattern(regex="(^$)|(^[0-9 \\-]+$)", message="Invalid phone number")
	public String getPhoneNums() {
		return phoneNums;
	}					
(Hibernate has some standard annotations for things like emails, so you don't always have to supply your own regular expression.)

Because Hibernate and Seam work well together, that error message ("Invalid phone number") can be displayed in the view. The technique is to "decorate" each form field with a facet that displays a message:

      ...
      <f:facet name="afterInvalidField">
        <s:message value="Invalid entry"/>
      </f:facet>
      <s:validateAll>
        ... form components ....
        <h:outputLabel value="Phone Numbers:" for="phoneNums" />
		<s:decorate>		  
		  <h:inputText id="phoneNums" size="12" value="#{contact.phoneNums}" />
		</s:decorate> 
	    ... more form components ....
	  </s:validateAll>	  
File upload is not included out-of-the-box with JSF unfortunately. With standard JSF you need to download the Tomahawk JARs and use the inputFileUpload component. With Seam there is fileUpload component used like this:
<s:fileUpload id="photoFile"
              data="#{contactAction.photoFile}"
              fileName="#{contactAction.fileName}"/>

Now in the ContactActionBean backing bean, the photoFile is made available via dependency injection as an object of type InputStream. The form is set up to call ContactActionBean.save() on submission, and that method, apart from calling through to the main entityManager.persist() call, accesses this photo input stream and persists it to the local filesystem.

JSF does not provide a single standard solution for authentication: you could use a servlet filter, Acegi, form-based authentication, or any custom scheme. WebOfContacts uses Seam's Authenticator mechanism, which is based on a solid Sun standard: JAAS. The basic procedure is to implement the method boolean Authenticator.authenticate() in a session bean, and declare the bean in Seam's main configuration file, components.xml:

<security:identity authenticate-method="#{authenticator.authenticate}" remember-me="true"/>
The usual login form is created with fields set to bind #{identity.username} and #{identity.password}. This input is injected into the Authenticator bean via an Identity object. Then the developer returns true or false depending on whether those details match the database entry. To control access to resources, it is possible to set roles on the Identity object. The other major step in the authenticate() method is to store the user object in a context where it can retrieved at any time during the session:
Contexts.getSessionContext().set("authenticatedUser", user);



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.