How does the FacesServlet know which facelet to render based on the URL?

1.6k Views Asked by At

I've been checking around and can't find an explanation of how the FacesServlet resolves a URL to a real file in the web app file structure. Within the context of servlets, my understanding is that a URL is just a made-up name that you want clients to use. In web.xml you then map specific servlets to URL patterns, but the real name/location of the servlet is hidden from the outside world...that's for servlets in general.

Specifically for JSF 2, we deal with the FacesServlet, which leads me to my first question: is the FacesServlet the only servlet I need to provide mapping details for in my app (and the only servlet I need, period)? It seems like the answer is "yes," but if there are situations where this wouldn't be the case, please give an example.

From reading other questions on SO, I understand that not all requests need to pass through the FacesServlet, so basically requests are divided into A) requests for static content that shouldn't be processed by the FacesServlet, and B) requests for dynamic content that need to be processed by the FacesServlet. So, how is the static content obtained? Just by having an incoming request in which the URL doesn't match the URL pattern for the FacesServlet, but does match a real file location in the app file structure?

Finally, my main question: when a request comes in that matches the URL pattern for the FacesServlet, how does the FacesServlet know which view file (.xhtml) to render? Is there a convention in working with JSF 2 that I need to follow to make it work? If not, then I don't get it, because, like I mentioned above in the case of a "general" servlet, the URL could include a name that nas nothing to do with the real file name, as long as it's mapped to the correct servlet in the web.xml file. I feel like I'm missing something obvious (and important) here. The only thing I can think of is that the URL should match a real file location or that there's another mapping table or something that associates URLs with view files.

By the way, I looked at this question, which is related but doesn't have any answers.

Thanks!

1

There are 1 best solutions below

2
On BEST ANSWER

The easiest way to serve static content is outlined in the servlet specification, section 10.5:

A Web application exists as a structured hierarchy of directories. The root of this hierarchy serves as the document root for files that are part of the application. For example, for a Web application with the context path /catalog in a Web container, the index.html file at the base of the Web application hierarchy or in a JAR file inside WEB-INF/lib that includes the index.html under META-INF/resources directory can be served to satisfy a request from /catalog/index.html. If an index.html is present both in the root context and in the META-INF/resources directory of a JAR file in the WEB-INF/lib directory of the application, then the file that is available in the root context MUST be used. The rules for matching URLs to context path are laid out in Chapter 12, “Mapping Requests to Servlets”.

and

A special directory exists within the application hierarchy named “WEB-INF”. This directory contains all things related to the application that aren’t in the document root of the application. Most of the WEB-INF node is not part of the public document tree of the application. Except for static resources and JSPs packaged in the META- INF/resources of a JAR file that resides in the WEB-INF/lib directory, no other files contained in the WEB-INF directory may be served directly to a client by the container.

That is, to serve static content, it is sufficient to save the content in the appropriate directory of your web application.

Servlet mappings are in addition to this "implicit" servlet. Most JSF applications therefore only declare the FacesServlet. IIRC, in recent JSF implementations that servlet will even declare itself if its declaration is omitted, so you don't even have to declare it explicitly.

How the FacesServlet locates the definition of the view to use is defined in the JSF specification, in particular section 7.6.2:

The terms view identifier and viewId are used interchangeably below and mean the context relative path to the web application resource that produces the view, such as a JSP page or a Facelets page. In the JSP case, this is a context relative path to the jsp page representing the view, such as /foo.jsp. In the Facelets case, this is a context relative path to the XHTML page representing the view, such as /foo.xhtml.

JSF implementations must provide a default ViewHandler implementation, along with a default ViewDeclarationLanguageFactory implementation that vends ViewDeclarationLanguage implementations designed to support the rendering of JSP pages containing JSF components and Facelets pages containing JSF components.

The default implementation is specified in the following section 7.6.2.1. I spare your the full quotation. The gist is that if the Faces Servlet is mapped with a prefix mapping (e.g. /faces/**), the viewId is the part of the URL following the prefix, and if the Faces Servlet is mapped with a suffix mapping (e.g. *.jsf), the viewId is the part of the URL following the context path, with replaced file extension. For instance, if the servlet is mapped to *.jsf, a request for the URL http://host/context/admin/userlist.jsf would read the view definition from the file admin/userlist.xhtml in the web application directory.