Package org.omnifaces.facesviews

This package contains the classes for the OmniFaces' FacesViews feature.

See: Description

Package org.omnifaces.facesviews Description

This package contains the classes for the OmniFaces' FacesViews feature.

Introduction

FacesViews is a feature where a special dedicated directory (/WEB-INF/faces-views), or optionally one or more user specified directories, can be used to store Facelets source files.

All files found in these directory are automatically mapped as Facelets files and made available using both their original extension as well as without an extension (extensionless). Optionally scanning can be restricted to include only certain extensions.

With FacesViews, there is thus no need to list all Facelets views that should be accessed without an extension in some configuration file. Additionally, it thus automatically maps Facelets files to their original file extension, which prevents exposing the source code of those Facelets that happens with the default JSF mapping.

In Servlet 3.0 containers, scanning is done automatically and no further configuration is needed. The feature is compatible with applications that don't have web.xml or faces-config.xml configuration files. As such, it can be used as an alternative to declaring the FacesServlet in web.xml for the .xhtml to .xhtml mapping.

Example 1:

Consider the following file structure and assume no further configuration has been done:

    /WEB-INF/faces-views/index.xhtml
    /WEB-INF/faces-views/users/add.xhtml
    /normal.xhtml
 

This will make the Facelets available via the following URLs (given a root deployment on domain example.com):

    example.com/index
    example.com/users/add
    example.com/index.xhtml (will direct to /index by default)
    example.com/users/add.xhtml (will direct to /users/add by default)
    example.com/normal.xhtml
 

Note that although the directory outside /WEB-INF/faces-views is not scanned, the FacesServlet is mapped on all extensions found in /WEB-INF/faces-views, so this will also affect files outside this directory. In the above example normal.xhtml is thus also available via the .xhtml extension, since the whole FacesServlet is mapped on this.

Also note that the extension variants of the scanned views will redirect to the extensionless variants. This behavior can be changed (see below), so that these views are either directly available (no redirect) or are not available at all.

Example 2:

Consider the following web.xml:

    <context-param>
        <param-name>org.omnifaces.FACES_VIEWS_SCAN_PATHS</param-name>
        <param-value>/*.xhtml</param-value>
    </context-param>
 

And this file structure:

    /page1.xhtml
    /foo/page2.xhtml
    /WEB-INF/resources/template.xhtml
    /script.js
 

This will make the Facelets available via the following URLs (given a root deployment on domain example.com):

    example.com/page1
    example.com/foo/page2
    example.com/page1.xhtml (will direct to /page1 by default)
    example.com/foo/page2.xhtml (will direct to /foo/page2 by default)
 

Note that in the above example, /WEB-INF was NOT scanned and thus template.xhtml is not made publicly available. Likewise /script.js was also not scanned since it doesn't have the configured extension (.xhtml). Finally, although a web.xml was used, there does not need to be a mapping for the FacesServlet in it when using a Servlet 3.0 container.

Welcome files

If a <welcome-file> is defined in web.xml that's scanned by FacesViews AND REDIRECT_TO_EXTENSIONLESS is used (which is the default, see below), it's necessary to define an extensionless welcome file to prevent a request to / being redirected to /[welcome file]. E.g. without this http://example.com will redirect to say http://example.com/index.

For example:

    <welcome-file-list>
        <welcome-file>index</welcome-file>
    </welcome-file-list>
 

Dispatch methods

JSF normally inspects the request URI to derive a logical view id from it. It assumes the FacesServlet is either mapped on a prefix path or an extension, and will get confused when an extensionless "exactly mapped" request is encountered. To counter this, FacesViews makes use of a filter that intercepts each request and makes it appear to JSF that the request was a normal extension mapped one.

In order to do this dispatching, two methods are provided; forwarding, and wrapping the request and continuing the filter chain. For the last method to work, the FacesServlet is programmatically mapped to every individual resource (page/view) that is encountered. By default the filter is automatically registered and is inserted after all filters that are declared in web.xml.

These internal details are important for users to be aware of, since they greatly influence how extensionless requests interact with other filter based functionality such as security filters, compression filters, file upload filters, etc.

With the forwarding method, filters typically have to be set to dispatch type FORWARD as well. If the FacesView filter is the first in the chain other filters that are set to dispatch type REQUEST will NOT be invoked at all (the chain is ended). If the FacesView filter is set to be the last, other filters will be invoked, but they should not modify the response (a forward clears the response buffer till so far if not committed).

No such problems appear to exist when the FacesView filter simply continues the filtering chain. However, since it wraps the requess there might be unforeseen problems with containers or other filters that get confused when the request URI changes in the middle of the chain. Continuing the chain has been tested with JBoss EAP 6.0.1, GlassFish 3.1.2.2, WebLogic 12.1.1 and TomEE 1.5.2-snapshot and thus with both Mojarra and MyFaces. However, since it's a new method for OmniFaces 1.4 we kept the existing forward as an alternative.

The configuration options below provide more details about the dispatch methods and the filter position which can be used for tweaking FacesViews for interoperability with other filters.

Configuration

The following context parameters are available.

"org.omnifaces.FACES_VIEWS_ENABLED" Used to completely switch scanning off.
Allowed values: {true,false}
Default value: true
(note that if no /WEB-INF/faces-views directory is present and no explicit paths have been configured, no scanning will be done either)
"org.omnifaces.FACES_VIEWS_SCAN_PATHS" A comma separated list of paths that are to be scanned in addition to /WEB-INF/faces-views.
Allowed values: any path relative to the web root, including the root path (/) and /WEB-INF. A wildcard can be added to the path, which will cause only files with the given extension te be scanned.
Examples:
- Scan all files in both folder1 and folder2: /folder1, /folder2
- Scan only .xhtml files in the root: /*.xhtml
Note that when the root path is given, all its sub paths are also scanned EXCEPT WEB-INF, META-INF and resources. If those have to be scanned as well, they can be added to the list of paths explicitly.
Default value: /WEB-INF/faces-views (note when this value is set, those paths will be in addition to the default /WEB-INF/faces-views)
"org.omnifaces.FACES_VIEWS_SCANNED_VIEWS_ALWAYS_EXTENSIONLESS" Used to set how scanned views should be rendered in JSF controlled links. With this setting set to false, it depends on whether the request URI uses an extension or not. If it doesn't, links are also rendered without one, otherwise they are rendered with an extension. When set to true links are always rendered without an extension.
Default value: true
"org.omnifaces.FACES_VIEWS_EXTENSION_ACTION" Determines the action that is performed whenever a resource is requested WITH extension that's also available without an extension.
Allowed values: {SEND_404,REDIRECT_TO_EXTENSIONLESS,PROCEED}, which have the following meaning:
- SEND_404: Send a 404 (not found), makes it look like e.g. /foo.xhtml never existed and there's only /foo.
- REDIRECT_TO_EXTENSIONLESS: Redirects to the same URL, but with the extension removed. E.g. /foo.xhtml is redirected to /foo.
- PROCEED: No special action is taken. Both /foo.xhtml and /foo are processed as-if they were separate views (with same content).
Default value: REDIRECT_TO_EXTENSIONLESS
"org.omnifaces.FACES_VIEWS_PATH_ACTION" Determines the action that is performed whenever a resource is requested in a public path that has been used for scanning views by faces views (e.g. the paths set by "org.omnifaces.FACES_VIEWS_SCAN_PATHS", but excluding the root path /).
Allowed values: {SEND_404,REDIRECT_TO_SCANNED_EXTENSIONLESS,PROCEED}, which have the following meaning:
- SEND_404: Send a 404 (not found), makes it look like e.g. /path/foo.xhtml never existed and there's only /foo and optionally /foo.xhtml.
- REDIRECT_TO_SCANNED_EXTENSIONLESS: Redirects to the resource corresponding with the one that was scanned. e.g. /path/foo.xml redirects to /foo.
- PROCEED: No special action is taken. /path/foo.xml and /foo (and optionally /foo.xhtml) will be accessible.
Default value: REDIRECT_TO_EXTENSIONLESS
"org.omnifaces.FACES_VIEWS_DISPATCH_METHOD" Determines the method used by FacesViews to invoke the FacesServlet.
Allowed values: {FORWARD,DO_FILTER}, which have the following meaning:
- FORWARD: Use a forward to invoke the FacesServlet. Using this method the FacesServlet does not have to be mapped to the (extensionless) requested resource or to everything (/*) when manually mapping.
- DO_FILTER: Use a plain FilterChain.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) to invoke the FacesServlet. Using this method necessitates the FacesServlet to be mapped to the (extensionless) requested resource or to everything (/*) when manually mapping.
Default value: DO_FILTER
"org.omnifaces.FACES_VIEWS_VIEW_HANDLER_MODE" Determines how the FacesViewsViewHandler should build the action URL that's used in e.g. forms and links.
Allowed values: {STRIP_EXTENSION_FROM_PARENT, BUILD_WITH_PARENT_QUERY_PARAMETERS}, which have the following meaning:
- STRIP_EXTENSION_FROM_PARENT: Strip the extension from the parent view handler's outcome using the at runtime determined extension mapping of the FacesServlet. Requires Servlet 3.0+.
- BUILD_WITH_PARENT_QUERY_PARAMETERS: The FacesViewsViewHandler constructs the action URL itself and only takes the query parameters (if any) from the parent view handler outcome. This is mode is automatically selected on Servlet 2.5.
Default value: STRIP_EXTENSION_FROM_PARENT on Servlet 3.0+, BUILD_WITH_PARENT_QUERY_PARAMETERS on Servlet 2.5.
"org.omnifaces.FACES_VIEWS_FILTER_AFTER_DECLARED_FILTERS" Used to set whether the FacesViewsForwardingFilter should match before declared filters (false) or after declared filters (true), when automatic scanning and mapping is used (as opposed to manually mapping the Servlet as explained in the Servlet 2.5 section below).
Default value: true (the FacesViews forwarding filter is the last in the filter chain)

Servlet 2.5 configuration

Servlet 2.5 users will have to install the FacesViewsForwardingFilter and FacesViewsViewHandler manually in web.xml:

    <filter>
        <filter-name>FacesViewsForwardingFilter</filter-name>
        <filter-class>org.omnifaces.facesviews.FacesViewsForwardingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>FacesViewsForwardingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <context-param>
        <param-name>org.omnifaces.FACES_VIEWS_DISPATCH_METHOD</param-name>
        <param-value>FORWARD</param-value>
    </context-param>
 

Note that the FORWARD method has been set. Without that, the FacesServlet has to be mapped manually (also in web.xml) to each and every view that is used. This is similar to how the welcome file (see below) has to be mapped to the FacesServlet for Servlet 2.5 users.

When an extensionless welcome file is defined in web.xml (see above), the FacesServlet has to be explicitly mapped to this welcome file for Servlet 2.5. E.g.

    <welcome-file-list>
        <welcome-file>index</welcome-file>
    </welcome-file-list>

    <servlet>
        <servlet-name>facesServlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>facesServlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
        <url-pattern>/welcome</url-pattern>
    </servlet-mapping>
 

And this in faces-config.xml

    <application>
        <view-handler>org.omnifaces.facesviews.FacesViewsViewHandler</view-handler>
    </application>
 

(at the moment Servlet 2.5 compatibility has not been tested thorougly)

OmniFaces 1.3 compatibility

In OmniFaces 1.4, a major overhaul was done for FacesViews and several things are done differently from how they were done in 1.3

Most notably is that the FacesServlet dispatch changed from forwarding to continuing the chain, the FacesView filter moved from being the first in the chain to being the last, links are always rendered as their extensionless variant independent of the request using an extension or not, and when a request with an extension is used anyway (e.g. by typing it directly into the address bar) it's now redirected to the extensionless variant.

By putting the following settings in web.xml a behavior that most closely resembles 1.3 can be obtained:

    <context-param>
        <param-name>org.omnifaces.FACES_VIEWS_DISPATCH_METHOD</param-name>
        <param-value>FORWARD</param-value>
    </context-param>
    <context-param>
        <param-name>org.omnifaces.FACES_VIEWS_FILTER_AFTER_DECLARED_FILTERS</param-name>
        <param-value>false</param-value>
    </context-param>
    <context-param>
        <param-name>org.omnifaces.FACES_VIEWS_SCANNED_VIEWS_ALWAYS_EXTENSIONLESS</param-name>
        <param-value>false</param-value>
    </context-param>
    <context-param>
        <param-name>org.omnifaces.FACES_VIEWS_EXTENSION_ACTION</param-name>
        <param-value>PROCEED</param-value>
    </context-param>
 
Author:
Arjan Tijms