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.
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() };
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
// 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