My JSF Books/Videos My JSF Tutorials OmniFaces/JSF PPTs
JSF 2.3 Tutorial
JSF Caching Tutorial
JSF Navigation Tutorial
JSF Scopes Tutorial
JSF Page Author Beginner's Guide
OmniFaces 2.3 Tutorial Examples
OmniFaces 2.2 Tutorial Examples
JSF Events Tutorial
OmniFaces Callbacks Usages
JSF State Tutorial
JSF and Design Patterns
JSF 2.3 New Features (2.3-m04)
Introduction to OmniFaces
25+ Reasons to use OmniFaces in JSF
OmniFaces Validators
OmniFaces Converters
JSF Design Patterns
Mastering OmniFaces
Reusable and less-verbose JSF code

My JSF Resources ...

Java EE Guardian
Member of JCG Program
Member MVB DZone
Blog curated on ZEEF
OmniFaces is an utility library for JSF, including PrimeFaces, RichFaces, ICEfaces ...

[OmniFaces Utilities] - Find the right JSF OmniFaces 2 utilities methods/functions

Search on blog

Petition by Java EE Guardians

Twitter

joi, 17 septembrie 2015

JSF and State design pattern - part II

Read also:
JSF and State design pattern - part I

In the first part of this post we have combined JSF and CDI managed beans to shape an example based on the state design pattern. Further, we will discuss about how JSF uses internally this pattern, and we start by saying that we will focus on JSF lifecycle.

As you probably know, a JSF request typically passes through six phases as in the below sketch:
In flow terms, we can improve the above sketch with the FacesServlet and Lifecycle. The FacesServlet represents the "entry point" of a JSF request (faces request, see FacesServlet#service()), while the Lifecycle represents the "entry point" for processing the JSF request. FacesServlet triggers the Lifecycle via Lifecycle#execute() method, while Lifecycle "orchestrates" the phases executions in the order exposed above (except the Render Response phase). FacesServlet acquires the FacesContext instance for the current request and passes it to the Lifecycle#execute() method; afterwards, each phase or state changes the contextual information passed to it and then sets the correspondig flag in the FacesContext itself to point out the next possible phase (or step), so each phase can be responsible for the execution of the next phase. Lifecycle will inspect the FacesContext flags: renderResponse and responseComplete. If the responseComplete is true, lifecycle abandons the execution of the request altogether. If a renderResponse flag is set after some phase, JSF implementation skips remaining phases and goes directly to the Render Response phase. If neither flag is set, lifecycle executes the next step in the sequence.
Speaking in code lines, we identify the state design pattern in the following artifacts:
·         The abstract state is represented by the com.sun.faces.lifecycle.Phase in Mojarra, or org.apache.myfaces.lifecycle.PhaseExecutor in Apache MyFaces
·         The concrete states represents extensions of Phase/PhaseExecutor and they are located in com.sun.faces.lifecycle package for Mojarra, respectively in org.apache.myfaces.lifecycle for Apache MyFaces. In Mojarra they are: RestoreViewPhase, ApplyRequestValuesPhase, ProcessValidationsPhase, UpdateModelValuesPhase, InvokeApplicationPhase, RenderResponsePhase. In Apache MyFaces they are: RestoreViewExecutor, ApplyRequestValuesExecutor, ProcessValidationsExecutor, UpdateModelValuesExecutor, InvokeApplicationExecutor, RenderResponseExecutor.
·        The state context is Lifecycle defined as an abstract class in javax.faces.lifecycle and implemented in com.sun.faces.lifecycle.LifecycleImpl in Mojarra, respectively in org.apache.myfaces.lifecycle.LifecycleImpl in Apache MyFaces.

Below you can see the source code that chain the state design pattern implementation:

// JSF FacesServlet
package javax.faces.webapp;
...
@MultipartConfig
public final class FacesServlet implements Servlet {
 ...
 private Lifecycle lifecycle = null; // this is acquire in FacesServlet#init()
 ...
 @Override
 public void service(ServletRequest req, ServletResponse resp)
                                    throws IOException, ServletException {
  ...
  // Acquire the FacesContext instance for this request
  FacesContext context = facesContextFactory.getFacesContext
               (servletConfig.getServletContext(), request, response, lifecycle);

  // in state pattern terms, call here the state context
  lifecycle.execute(context);
  // execute the Render Response phase
  lifecycle.render(context);
  ...
  // Release the FacesContext instance for this request
  context.release();
 }
 ...
}

Now, in Mojarra the kernel of the state context is the execute() method:

// Mojarra 2.2.9 source code
package com.sun.faces.lifecycle;
...
public class LifecycleImpl extends Lifecycle {
 ...
 private Phase response = new RenderResponsePhase();

 // The set of Phase instances (concrete states) that are executed by the execute()  
 // method in order by the ordinal property of each phase
 private Phase[] phases = {
  null, // ANY_PHASE placeholder, not a real Phase
  new RestoreViewPhase(),
  new ApplyRequestValuesPhase(),
  new ProcessValidationsPhase(),
  new UpdateModelValuesPhase(),
  new InvokeApplicationPhase(),
  response
 };

 public void execute(FacesContext context) throws FacesException {
  ...
  for (int i = 1, len = phases.length -1 ; i < len; i++) {

       if (context.getRenderResponse() ||
           context.getResponseComplete()) {
           break;
       }

       phases[i].doPhase(context, this, listeners.listIterator());
  }
 }

 // Execute the Render Response phase
 public void render(FacesContext context) throws FacesException {
  ...
  if (!context.getResponseComplete()) {
      response.doPhase(context, this, listeners.listIterator());
  }
 }
}

In Apache MyFaces the kernel of the state context is the execute() method:

// Apache MyFaces 2.2.7 source code
package org.apache.myfaces.lifecycle;

public class LifecycleImpl extends Lifecycle {
 ...
 private final PhaseExecutor[] lifecycleExecutors;
 private final PhaseExecutor renderExecutor;

 lifecycleExecutors = new PhaseExecutor[] { new RestoreViewExecutor(), new ApplyRequestValuesExecutor(), 
           new ProcessValidationsExecutor(), new UpdateModelValuesExecutor(), new InvokeApplicationExecutor() };

 renderExecutor = new RenderResponseExecutor();
 ...
 @Override
 public void execute(FacesContext facesContext) throws FacesException {
  ...
  for (PhaseExecutor executor : lifecycleExecutors) {
       // executePhase() is a private method that inspect responseComplete and renderResponse, and executes the passed phase
       if (executePhase(facesContext, executor, phaseListenerMgr)) {
           return;
       }
  }
 }

 @Override
 public void render(FacesContext facesContext) throws FacesException {
  ...
  if (isResponseComplete(facesContext, renderExecutor.getPhase(), true)) {
      return;
  }
  renderExecutor.execute(facesContext);
  ...
 }
}

If the JSF lifecycle doesn't take advantage of the state design pattern then the implementation would be cluttered with a lot of conditionals (e.g. if/switch).

Niciun comentariu :

Trimiteți un comentariu

JSF BOOKS COLLECTION

Postări populare

OmniFaces/JSF Fans

Follow by Email

Visitors Starting 4 September 2015

Locations of Site Visitors