eXo Java Server Faces Bridge

The support of JSF 1.0 within a Portlet is a new feature in the eXo platform. We solved many intriguing tasks that occurred in the process of establishing a faces portlet able to adopt the exisiting JSF based projects

There are two well known implementations of JSF : Sun JSF-RI and the OSS project MyFaces. The eXo platform supports both of them. You may choose to compile the platform to work on the one you prefer. Most of our code are independent from the JSF implementation, but there are some differences between Sun Reference Implementation and MyFaces implementation.

Portlet/Servlet : Similarities and Differences

The Servlet and Portlet interfaces have a lot of similarities. Both set of interfaces define Request , Response , Session, Config, Context objects. In each case, you can use the request interface to retrieve the request parameters, to set an attribute and to use the respone interface to send back the response to the client. You can also use the config interface to read the application configuration and use the context interface to access the container...

However Servlet and Portlet are not the same. The biggest modification has been made to introduce an MVC design directly into the portlet. The portlet defines 2 phases of execution, processAction(..) and render(..). Also the Request and Response interfaces are well defined for each execution phase : ActionRequest and ActionResponse for the process action phase, and RenderRequest and RenderResponse for the render phase. Therefore the current JSF implementation will not support the portlet out of box. However, JSF technology has a very flexible and well thought design

The JSF implementation

As you know, JSF has 7 phases of execution controlled by the FacesServlet. The FacesContext contains all of the per-request state information related to the processing of a single JavaServer Faces request, and the rendering of the corresponding response. It is given to, and potentially modified by, each phase of the request processing lifecycle. The ExternalContext contains the context, request, and response objects of the request life cycle; those objects can be either of Portlet or Servlet types. We will list a pseudo code here to illustrate how FacesServlet work and the faces context is created

class FacesServlet extends HttpServlet {
  [..]

  public void init(ServletConfig servletConfig) throws ServletException {
    //do ?ome initialization here such create FacesContext and Lifecycle factory object
  }

  public void service(HttpServletRequest request, HttpServletResponse response) {
    //create face context instance base on the servlet context, request and response.
    //The faces context will create the ExternalContext object and pass the servletContext
    //request and response to the new ExternalContext. You can access those objects at any place
    //in 7 phases of execution by calling:
    // HttpServletRequest=(HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest()
    // HttpServletResponse=(HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getResponse()
    FaceContext facesContext = facesContextFactoy.getFacesContext(servletContext, request, response) ;
    //get lifecyle object
    Lifecycle lifecycle = lifecycleFactory.getLifeCycle() ;
    //the lifecycle execute 7 phases:
    // 1) Reconstitute Request tree
    // 2) Apply Request Values (decode)
    // 3) Handle Request Event
    // 4) Process Validations
    // 5) Update Model Values
    // 6) Invoke Application
    // 7) Render Request
    lifecyle.execute(facesContext) ;
    //release the resource such request , response and the current context that associate
    //with the current thread
    facesContext.release() ;
  }
}
        

You can access the context, request and response objects at any place by obtaining the current faces context object. You just need to get the external context, and then extract the request or response objects out of it. However when you write a JSF application or component, you don't know that the application/component will be deployed into a servlet environment or a portlet environement so you should not call the getRequest() and getResponse() and cast the returned object.

The ExternalContext interface comes with a set of method that can help you to abstract the current environment. For example, to obtain the request parameter, you can use : externalContext.getRequestParameterMap().get(key) instead of ((HttpServletRequest)externalContext.getRequest()).getParameter(key). PLease check ExternalContext API for more detail and the available set of methods

Our modifications

Now that you have an overview how JSF works in the servlet environment. You should see that in order to make a JSF support within the portlet technology, we only need to replace the FacesContext, ExternalContext and FacesContext factory implementations by a custom portlet implementation

As we mention above, the portal controller delegates (1) the request to the portletcontainer where the faces portlet is located. The portlet replaces (2) the FacesContext instance by a new one and obtains the lifecycle object before executing (3) it. Wehen the new JSF lifecycle has finished its work (4), the portlet restores the previous state (5) and returns (6) an Output object to the portal WAR.

The next JSP page shows hw simple it is to introduce JSF code inside a portlet :

          
<%@ taglib uri="http://exoplatform.org/jsf/custom" prefix="x" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>

<%@ page import="framework.bean.HelloBean"%>

<f:use_faces>
  <div>Faces, Welcome to eXo Platform, this is a test</div>
  <div>
    <x:form id="facesForm" formName="facesForm" method="POST">
      <h:input_hidden id="actionName" value="HelloFacesAction" />
      <h:output_text id="label_name" value="Please enter your name:<br>" />
      <h:input_text id="input_name" valueRef="hello.name" />
      <h:command_button id="submit" type="submit" commandName="submit" label="Submit" actionRef="hello.submit"/>
    </x:form>
  </div>
</f:use_faces>
        

Do not focus on the eXo custom taglib,we have just added several usefull reusable tags. The HelloBean is a JSF Managed Bean defined in the faces-config.xml file :

         
[...]
  <managed-bean>
    <description>Hello Bean</description>
    <managed-bean-name>hello</managed-bean-name>
    <managed-bean-class>framework.bean.HelloBean</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
    <managed-property>
      <property-name>name</property-name>
      <value>Enter your name here</value>
    </managed-property>
  </managed-bean>
  [...] 
        

Here is the result :