Tuesday, June 25, 2013

JSF 2 tutorial. Part II: Spring integration and Prettyfaces usage

In the first part of this JSF 2 series, we prepared our development environment: Eclipse, Maven, Tomcat 7 and JSF 2. In this second part, we will walk through Spring integration with JSF 2. We will also see how to use the Prettyfaces library. And finally we will use Spring security to secure the access to our application.

1) Spring integration

First we need to add Spring dependencies to our application (POM file):
3.2.3.RELEASE



 javax.inject
 javax.inject
 1



  org.springframework
  spring-core
  ${org.springframework.version}



  org.springframework
  spring-expression
  ${org.springframework.version}

 


  org.springframework
  spring-beans
  ${org.springframework.version}



  org.springframework
  spring-aop
  ${org.springframework.version}

 


  org.springframework
  spring-context
  ${org.springframework.version}

 


  org.springframework
  spring-context-support
  ${org.springframework.version}



  org.springframework
  spring-tx
  ${org.springframework.version}



  org.springframework
  spring-web
  ${org.springframework.version}



 org.springframework
 spring-orm
 ${org.springframework.version}


You can refer to this blog entry from Spring source for detailed explanation about every dependency.
Next step is to create the famous Spring's applicationContext.xml file:


 
 
 
 
 

  
Now we need to register Spring listeners in the web deployment descriptor:




 org.springframework.web.context.ContextLoaderListener



 org.springframework.web.context.request.RequestContextListener

Last config to be done, is registering the SpringBeanFacesELResolver in the faces-config.xml file:

   
   
  
          org.springframework.web.jsf.el.SpringBeanFacesELResolver
  
   

The SpringBeanFacesELResolver is an ELResolver that delegates to the Spring root WebApplicationContext, resolving name references to Spring-defined beans.
Now we can use the Spring framework for dependency injection (DI) in our application. If you are not familiar with DI and Inversion of Control (IoC) please refer to this excellent article.
In the first part of this series, we annotated our user managed bean with:
@ManagedBean(name="userManagedBean")
@SessionScoped
to make JSF aware of it. Now we want Spring to be responsible for missions like this: registering all components and instantiating them when needed. For this, Spring offers multiple class annotations: @Component, @Service, @Repository.
So we change our UserManagedBean to be annotated with:
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("session")
public class UserManagedBean implements Serializable
By now you can start your server and see that the bean is instantiated.

2) JSF2 View scope with Spring

JSF 2 introduced a big enhancement by introducing new scopes to Managed beans. One of the most interesting scopes, is the View scope. In fact, if you used JSF 1.2 without Richfaces (or Seam), then you would have found yourself obliged to define most of your managed beans as Session beans, otherwise you would encounter plenty of problems with Ajax requests sent along with request scoped beans. In fact, with every Ajax call, request bean is re-instantiated again.
With the View scope, your bean will keep alive (this remembers me the a4j:keepAlive in Richfaces) until view is completely refreshed.
The problem here with Spring, is that you can not define a bean with @Scope("view") by default. An excellent workaround was proposed by Cagatay Civici (Founder of Primefaces) here.
The main idea, is to define the View scope our self and make Spring aware of it and add it to its list of scopes.
So first thing to do is to define the ViewScope class that implements the Scope interfaces:

package com.raissi.spring.customscope;

import java.util.Map;

import javax.faces.context.FacesContext;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;

/**
 * Implements the JSF View Scope for use by Spring. 
 * This class is registered as a Spring bean with the CustomScopeConfigurer.
*/
public class ViewScope implements Scope {

 public Object get(String name, ObjectFactory objectFactory) {
  if (FacesContext.getCurrentInstance().getViewRoot() != null) {
   Map viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
   if (viewMap.containsKey(name)) {
    return viewMap.get(name);
   } else {
    Object object = objectFactory.getObject();
    viewMap.put(name, object);
    return object;
   }
  } else {
   return null;
  }
 }

 public Object remove(String name) {
  if (FacesContext.getCurrentInstance().getViewRoot() != null) {
   return FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove(name);
  } else {
   return null;
  }
 }

 public void registerDestructionCallback(String name, Runnable callback) {
  // Do nothing
 }

 public Object resolveContextualObject(String key) {
  return null;
 }

 public String getConversationId() {
  return null;
 }

}
Once done, we need to register our newly defined scope to the Spring CustomScopeConfigurer in applicationContext.xml:


 
  
   
    
   
  
 

And that's all you need to make Spring aware of ViewScope. Notice that possible enhancements to this workaround can be found here for possible memory leaks. Et voilà!!! vous avez Spring et JSF 2 ready to go. Next step is to prettify our URLs.

3) Using Prettyfaces

Prettyfaces is an open source URL-rewriting library used essentially with JSF (1.1, 1.2 and 2). It's a very powerful library to re-write your JSF app URLs with many customization features. It's also very easy to configure and use. First thing, add Prettyfaces dependencies in your POM file: 

 com.ocpsoft
 prettyfaces-jsf2
 3.3.3

Next, configure your web.xml to use the Prettyfaces filter:

  Pretty Filter
  com.ocpsoft.pretty.PrettyFilter
  true


 
  Pretty Filter 
  /* 
  FORWARD 
  REQUEST 
  ERROR
  ASYNC

Last thing is to map your views with Prettyfaces. So under WEB-INF, create a file pretty-config.xml:


 
  
  
 
 
  
  
  #{userManagedBean.logout}
 
 
  
  
 


As you can see in this mapping file, to prettify your URLs you need to create a url-mapping for each JSF view. For example, if we want the URL to login page to be just: http://domainname.ex/login instead of http://domainname.ex/pages/login.jsf then we create a url-mapping, defining "/login" as pattern and /pages/login.jsf as correspondent view. So whenever there is a call to /login URL the "/login/login.jsf" view will be rendered. Now, we want that whenever the "/logout" URL is called by browser, user is a) redirected to login.jsf and b) also user session is destroyed. This can be easily achieved by defining the pattern /logout pointing to login.jsf view and also we define an action element. This action, is just a method of a defined managed bean that will get executed once the specified URL is called. And here is our method:
public void logout(){
     FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
}
Other beautiful features can be found in the Prettyfaces user guide.
In next part of the series, we will add some security to our application

4 comments:

  1. You know what, you rock!!!!!!!! You have just saved my day man!!!! Thanks a lotttttttttttttttttttttttttt

    ReplyDelete
    Replies
    1. You are very welcome, please post any questions and I will be very happy to help

      Delete
  2. prettyfaces does not works and any other filter???

    ReplyDelete
    Replies
    1. Would you please give more details about the error(s) you are encountering ?

      Delete