What is ExternalContext ?
Well, ExternalContext class "allows the Faces API to be unaware of the nature of its containing application environment. In particular, this class allows JavaServer Faces based applications to run in either a Servlet or a Portlet environment" - official documentation.
You can easily intuit the role of ExternalContext if you check the methods it offers in contrast with FacesContext. Basically, FacesContext provides methods specific to JSF and needed for accessing the JSF specific artifacts (e.g. converters, validators, components, EL expressions, view root, resource handlers, exception handlers, supported locales, phase listeners, view handlers, system event listeners, etc). Practically everything is present in JSF API is exposed via FacesContext.
By the other hand, JavaServer Faces based applications run in either a Servlet or a Portlet environment and take advantage of the environment artifacts. For example, if your JSF application run in a Servlet environment (most probably) then you may need to access the HTTP servlet request, response, HTTP sessions, Servlet context and so on. These are available via ExternalContext, NOT via FacesContext!
So, FacesContext provides methods for accessing the JSF API, while ExternalContext provides methods for accessing the Servlet/Portlet environment in which your JSF application run.
The FacesContext is accessible via:
FacesContext fc = FacesContext.getCurrentInstance();
! OmniFaces provides a shortcut for the above code as: FacesContext fc = Faces.getContext();. Moreover, in JSF 2.3 FacesContext is injectable as: @Inject private FacesContext fc;.
The ExternalContext is available via FacesContext as below:
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
! OmniFaces provides a shortcut for the above code as: ExternalContext ec = Faces.getExternalContext();. Moreover, in JSF 2.3 ExternalContext is injectable as: @Inject private ExternalContext ec;.
Notice that these two contexts doesn't provide any common artifact!
What is FacesContext ?
As you probably know, a JSF request typically passes through six phases
as in the below sketch:
As I said above, FacesContext
is responsible to the entire JSF API access. Via FacesContext, you can access (access =
create, destroy, init, modify, etc):
·
lifecycle
·
converters
·
validators
·
components
·
EL expressions
·
view root
·
contexts
·
render kits
·
renderers
·
event listeners
·
resource handlers
·
exception handlers
·
supported locales
·
phase listeners
·
view handlers
·
system event listeners
·
tag handlers
·
etc ...
FacesContext is created per request (a single instance per request).
The initialization of FacesContext
take place at each request in FacesServlet
(see javax.faces.webapp.FacesServlet
source code). The relevant code is listed below:
// Mojarra
2.2.9 source code, FacesServlet class
public final class
FacesServlet implements Servlet {
// factory of FacesContext instances
private FacesContextFactory
facesContextFactory = null;
// JSF lifecycle
private Lifecycle lifecycle =
null;
public void init(ServletConfig servletConfig)
throws ServletException {
...
// init
the FacesContextFactory which is capable to provide FacesContext instances
facesContextFactory = (FacesContextFactory) FactoryFinder.getFactory
(FactoryFinder.FACES_CONTEXT_FACTORY);
...
//init JSF lifecycle
...
}
...
@Override
public void service(ServletRequest req,
ServletResponse resp)
throws IOException, ServletException {
HttpServletRequest request =
(HttpServletRequest) req;
HttpServletResponse response =
(HttpServletResponse) resp;
...
// Acquire
the FacesContext instance for this request
FacesContext context = facesContextFactory.getFacesContext
(servletConfig.getServletContext(), request, response, lifecycle);
...
}
}
After FacesContext
is created it will be used by the JSF Lifecycle to successfully accomplish the
JSF six phases. During this process, you can obtain the FacesContext of the current JSF request
via FacesContext#getCurrentInstance()
from different places (e.g. from a custom component, a phase listener, even a
custom FacesContext).
The JSF lifecycle is triggered from FacesServlet as below (this is happening in the FacesServlet#service()
method):
lifecycle.execute(context);
// first 5 JSF phases
lifecycle.render(context); // Render Response phase
After
the current request was processed the FacesContext should be released (it will be created again
at the next request). This take place in the same FacesServlet#service() method in a in a
finally clause (this ensures that the FacesContext will be always released, even when an error
occurred during JSF lifecycle).
So, the JSF FacesContext
lifespan spreads over a JSF request-response cycle.
finally {
// Release the FacesContext instance for this
request
context.release();
}
The
below image expose the FacesContext
lifespan:
Finally,
all resources are released (among others FacesContextFactory and Lifecycle):
public void destroy() {
facesContextFactory = null;
lifecycle =
null;
...
}
The FacesContext#getCurrentIntance()
returns the FacesContext
instance of the current request created as you saw above.
The view (or current view) is associated in JSF API with the current view root
(UIViewRoot
instance). The current view (or view root) can be obtained in page via the
implicit object #{view}
or programmatically as below:
UIViewRoot viewRoot =
FacesContext.getCurrentInstance().getViewRoot();
! OmniFaces provides a shortcut for the above code as: UIViewRoot viewRoot = Faces.getViewRoot();.
Moreover, in JSF 2.3 UIViewRoot
is injectable as: @Inject
private UIViewRoot uiViewRoot;.
From
the same view (page/browser tab) you can trigger as many requests as you want.
Each of these requests will have associate an FacesContext initialized and released in FacesServlet. So, FacesContext#getCurrentIntance()
returns the FacesContext
associated with the current request fired from the current view, not the view itself.
The view is just an JSF API artifact (is true, one of the most important) that FacesContext manages.
Niciun comentariu :
Trimiteți un comentariu