All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax.faces.application.ViewHandler Maven / Gradle / Ivy

Go to download

Jakarta Faces defines an MVC framework for building user interfaces for web applications, including UI components, state management, event handing, input validation, page navigation, and support for internationalization and accessibility.

There is a newer version: 4.1.0
Show newest version
/*
 * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package javax.faces.application;

import static java.util.Collections.emptySet;
import static java.util.Collections.unmodifiableSet;
import static java.util.logging.Level.WARNING;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import java.util.stream.Stream;

import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.push.PushContext;
import javax.faces.view.ViewDeclarationLanguage;

/**
 * 

* ViewHandler is the pluggablity mechanism for allowing * implementations of or applications using the JavaServer Faces specification to provide their own * handling of the activities in the Render Response and Restore View phases of * the request processing lifecycle. * * This allows for implementations to support different response * generation technologies, as well as alternative strategies for saving and restoring the state of * each view. * * An implementation of this class must be thread-safe. *

* *

* Please see {@link StateManager} for information on how the ViewHandler interacts the * {@link StateManager}. *

* *

* Version 2 of the specification formally introduced the concept of View Declaration * Language. A View Declaration Language (VDL) is a syntax used to declare user interfaces * comprised of instances of JSF {@link UIComponent}s. Any of the responsibilities of the * ViewHandler that specifically deal with the VDL sub-system are now the domain of the * VDL implementation. These responsibilities are defined on the {@link ViewDeclarationLanguage} * class. The ViewHandler provides {@link #getViewDeclarationLanguage} as a convenience * method to access the VDL implementation given a viewId. *

* */ public abstract class ViewHandler { private static final Logger log = Logger.getLogger("javax.faces.application"); // ------------------------------------------------------ Manifest Constants /** *

* The key, in the session's attribute set, under which the response character encoding may be * stored and retrieved. *

* */ public static final String CHARACTER_ENCODING_KEY = "javax.faces.request.charset"; /** *

* Allow the web application to define a * list of alternate suffixes for pages containing JSF * content. This list is a space separated list of values of * the form .<extension>. The first physical resource whose extension * matches one of the configured extensions will be the suffix used to create the view * ID. If this init parameter is not specified, the default value is taken from the value * of the constant {@link #DEFAULT_SUFFIX}. *

*/ public static final String DEFAULT_SUFFIX_PARAM_NAME = "javax.faces.DEFAULT_SUFFIX"; /** *

* The value to use for the default extension if the webapp is using url extension mapping. *

*/ public static final String DEFAULT_SUFFIX = ".xhtml .view.xml .jsp"; /** *

* If this param is set, and calling toLowerCase().equals("true") on a String representation of * its value returns true, the runtime must ensure that any XML comments in the Facelets source * page are not delivered to the client. The runtime must also consider the * facelets.SKIP_COMMENTS param name as an alias to this param name for backwards compatibility * with existing facelets tag libraries. *

* * @since 2.0 */ public static final String FACELETS_SKIP_COMMENTS_PARAM_NAME = "javax.faces.FACELETS_SKIP_COMMENTS"; /** *

* Allow the web application to define an alternate suffix for Facelet based XHTML pages * containing JSF content. If this init parameter is not specified, the default value is taken * from the value of the constant {@link #DEFAULT_FACELETS_SUFFIX} *

* * @since 2.0 */ public static final String FACELETS_SUFFIX_PARAM_NAME = "javax.faces.FACELETS_SUFFIX"; /** *

* The value to use for the default extension for Facelet based XHTML pages if the webapp is * using url extension mapping. *

* * @since 2.0 */ public static final String DEFAULT_FACELETS_SUFFIX = ".xhtml"; /** *

* Allow the web application to define a semicolon (;) separated list of strings that is used to * forcibly declare that certain pages in the application must be interpreted as using Facelets, * regardless of their extension. Each entry in the semicolon (;) separated list of strings is * either a file extension, as in *.xhtml, or a resource prefix (starting with '/' * and interpreted as relative to the web application root), as in /user/*. The * latter class of entry can also take the form of * /<filename>.<extension>* such as /login.jsp*. The * runtime must also consider the facelets.VIEW_MAPPINGS param name as an alias to * this param name for backwards compatibility with existing Facelets applications. *

* * @since 2.0 */ public static final String FACELETS_VIEW_MAPPINGS_PARAM_NAME = "javax.faces.FACELETS_VIEW_MAPPINGS"; /** *

* The buffer size to set on the response when the ResponseWriter is generated. By default the * value is 1024. A value of -1 will not assign a buffer size on the response. This should be * increased if you are using development mode in order to guarantee that the response isn't * partially rendered when an error is generated. The runtime must also consider the * facelets.BUFFER_SIZE param name as an alias to this param name for backwards compatibility * with existing facelets tag libraries. *

* * @since 2.0 */ public static final String FACELETS_BUFFER_SIZE_PARAM_NAME = "javax.faces.FACELETS_BUFFER_SIZE"; /** *

* When a page is requested, what interval in seconds * should the compiler check for changes. If you don't want the compiler to check for changes * once the page is compiled, then use a value of -1. Setting a low refresh period helps during * development to be able to edit pages in a running application.The runtime must also consider * the facelets.REFRESH_PERIOD param name as an alias to this param name for backwards * compatibility with existing facelets tag libraries. If * {@link javax.faces.application.ProjectStage} is set to {@code Production} and this value is * not otherwise specified, the runtime must act as if it is set to -1. *

* * @since 2.0 */ public static final String FACELETS_REFRESH_PERIOD_PARAM_NAME = "javax.faces.FACELETS_REFRESH_PERIOD"; /** *

* If this param is set, the runtime must interpret it as a semicolon (;) separated list of * paths, starting with "/" (without the quotes). The runtime must interpret each entry in the * list as a path relative to the web application root and interpret the file found at that path * as a facelet tag library, conforming to the facelet taglibrary schema and expose the tags * therein according to Section "Facelet Tag Library mechanism". The runtime must also consider * the facelets.LIBRARIES param name as an alias to this param name for backwards compatibility * with existing facelets tag libraries. *

* * * @since 2.0 */ public static final String FACELETS_LIBRARIES_PARAM_NAME = "javax.faces.FACELETS_LIBRARIES"; /** *

* A semicolon (;) delimitted list of class names of type * javax.faces.view.facelets.TagDecorator, with a no-argument constructor. These decorators will * be loaded when the first request for a Facelets VDL view hits the ViewHandler for page * compilation.The runtime must also consider the facelets.DECORATORS param name as an alias to * this param name for backwards compatibility with existing facelets tag libraries. *

* * @since 2.0 */ public static final String FACELETS_DECORATORS_PARAM_NAME = "javax.faces.FACELETS_DECORATORS"; /** *

* If this param is set, and calling toLowerCase().equals("true") on a String representation of * its value returns true, the default ViewHandler must behave as specified in the latest 1.2 * version of this specification. Any behavior specified in Section "Default * ViewDeclarationLanguage Implementation" of the spec prose document and implemented in the * default ViewHandler that pertains to handling requests for pages authored in the JavaServer * Faces View Declaration Language must not be executed by the runtime. *

* * @since 2.0 */ public static final String DISABLE_FACELET_JSF_VIEWHANDLER_PARAM_NAME = "javax.faces.DISABLE_FACELET_JSF_VIEWHANDLER"; // ---------------------------------------------------------- Public Methods /** * *

* Initialize the view for the request processing * lifecycle. *

* *

* This method must be called at the beginning of the Restore View Phase of the Request * Processing Lifecycle. It is responsible for performing any per-request initialization * necessary to the operation of the lifycecle. *

* *

* The default implementation must perform the following actions. If * {@link ExternalContext#getRequestCharacterEncoding} returns null, call * {@link #calculateCharacterEncoding} and pass the result, if non-null, into the * {@link ExternalContext#setRequestCharacterEncoding} method. If * {@link ExternalContext#getRequestCharacterEncoding} returns non-null take no * action. *

* * @param context the Faces context. * @throws FacesException if a problem occurs setting the encoding, such as the * UnsupportedEncodingException thrown by the underlying Servlet or * Portlet technology when the encoding is not supported. * */ public void initView(FacesContext context) throws FacesException { String encoding = context.getExternalContext().getRequestCharacterEncoding(); if (encoding != null) { return; } encoding = calculateCharacterEncoding(context); if (encoding != null) { try { context.getExternalContext().setRequestCharacterEncoding(encoding); } catch (UnsupportedEncodingException e) { String message = "Can't set encoding to: " + encoding + " Exception:" + e.getMessage(); if (log.isLoggable(WARNING)) { log.fine(message); } throw new FacesException(message, e); } } } /** *

* Perform whatever actions are required to restore * the view associated with the specified {@link FacesContext} and viewId. It may * delegate to the restoreView of the associated {@link StateManager} to do the * actual work of restoring the view. If there is no available state for the specified * viewId, return null. *

* *

* Otherwise, the default implementation must obtain a reference to the * {@link ViewDeclarationLanguage} for this viewId and call its * {@link ViewDeclarationLanguage#restoreView} method, returning the result and not swallowing * any exceptions thrown by that method. *

* * @param context {@link FacesContext} for the current request * @param viewId the view identifier for the current request * @return the restored view root, or null. * @throws NullPointerException if context is null * @throws FacesException if a servlet error occurs */ public abstract UIViewRoot restoreView(FacesContext context, String viewId); /** *

* Create and return a new {@link UIViewRoot} * instance initialized with information from the argument FacesContext and * viewId. Locate the * {@link ViewDeclarationLanguage} implementation for the VDL used in the view. The argument * viewId must be converted to a physical viewId that can refer to an * actual resource suitable for use by the ViewDeclarationLanguage * {@link ViewDeclarationLanguage#createView}, which must be called by this method. * * @param context the Faces context. * @param viewId the view id. * @throws NullPointerException if context is null * * @return the viewroot. */ public abstract UIViewRoot createView(FacesContext context, String viewId); /** *

* Perform whatever actions are required to render the * response view to the response object associated with the current {@link FacesContext}. *

* *

* Otherwise, the default implementation must obtain a reference to the * {@link ViewDeclarationLanguage} for the viewId of the argument * viewToRender and call its {@link ViewDeclarationLanguage#renderView} method, * returning the result and not swallowing any exceptions thrown by that method. *

* * @param context {@link FacesContext} for the current request * @param viewToRender the view to render * * @throws IOException if an input/output error occurs * @throws NullPointerException if context or viewToRender is * null * @throws FacesException if a servlet error occurs */ public abstract void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException, FacesException; /** *

* Returns an appropriate {@link Locale} to use for this and subsequent requests for the current * client. *

* * @param context {@link FacesContext} for the current request * @return the locale. * @throws NullPointerException if context is null */ public abstract Locale calculateLocale(FacesContext context); /** *

* Returns the correct character encoding to be used for this request. *

* *

* The following algorithm is employed. *

* *
    * *
  • *

    * Examine the Content-Type request header. If it has a charset * parameter, extract it and return that as the encoding. *

    *
  • * *
  • *

    * If no charset parameter was found, check for the existence of a session by * calling {@link ExternalContext#getSession(boolean)} passing false as the * argument. If that method returns true, get the session Map by calling * {@link ExternalContext#getSessionMap} and look for a value under the key given by the value * of the symbolic constant {@link ViewHandler#CHARACTER_ENCODING_KEY}. If present, return the * value, converted to String. *

    *
  • * *
  • *

    * Otherwise, return null *

    *
  • * *
* * @param context the Faces context. * @return the character encoding, or null * @since 1.2 */ public String calculateCharacterEncoding(FacesContext context) { ExternalContext extContext = context.getExternalContext(); Map headerMap = extContext.getRequestHeaderMap(); String contentType = headerMap.get("Content-Type"); String charEnc = null; // Look for a charset in the Content-Type header first. if (contentType != null) { // See if this header had a charset String charsetStr = "charset="; int len = charsetStr.length(); int idx = contentType.indexOf(charsetStr); // If we have a charset in this Content-Type header AND it // has a non-zero length. if (idx != -1 && idx + len < contentType.length()) { charEnc = contentType.substring(idx + len); } } // failing that, look in the session for a previously saved one if (charEnc == null) { if (extContext.getSession(false) != null) { charEnc = (String) extContext.getSessionMap().get(CHARACTER_ENCODING_KEY); } } return charEnc; } /** *

* Return an appropriate renderKitId for this and subsequent requests from the * current client. It is an error for this method to return null. *

* *

* The default return value is * {@link javax.faces.render.RenderKitFactory#HTML_BASIC_RENDER_KIT}. *

* * @param context {@link FacesContext} for the current request * @return the render kit id. * @throws NullPointerException if context is null */ public abstract String calculateRenderKitId(FacesContext context); /** *

* Derive and return the viewId from the current request, or the argument input by following the * algorithm defined in specification section JSF.7.6.2. *

* *

* This method should work correctly when the FacesServlet is invoked via either a * path mapping, extension mapping or an exact match * (mapping) as defined by Servlet.12.2. Note that path mapping is also commonly * known as prefix mapping (e.g. "/faces/*") and extension mapping as suffix * mapping (e.g. "*.xhtml"). An exact match is possible where there's a servlet * mapping with an exact URL pattern such as "/foo". *

* *

* The default implementation of this method simply returns requestViewId unchanged. *

* * @param context the FacesContext for this request * * @param requestViewId the viewId to derive, * @return the derived view id. * @since 2.0 */ public String deriveViewId(FacesContext context, String requestViewId) { return requestViewId; } /** *

* Derive and return the viewId from the current request, or the argument input by following the * algorithm defined in specification section JSF.7.6.2. Note that unlike * deriveViewId(), this method does not require that a physical view be present. *

* *

* This method should work correctly when the FacesServlet is invoked via either a * path mapping, extension mapping or an exact match * (mapping) as defined by Servlet.12.2. Note that path mapping is also commonly * known as prefix mapping (e.g. "/faces/*") and extension mapping as suffix * mapping (e.g. "*.xhtml"). An exact match is possible where there's a servlet * mapping with an exact URL pattern such as "/foo". *

* *

* The default implementation of this method simply returns requestViewId unchanged. *

* * @param context the FacesContext for this request * * @param requestViewId the viewId to derive, * @return the derived logical view id. * @since 2.1 */ public String deriveLogicalViewId(FacesContext context, String requestViewId) { return requestViewId; } /** *

* If the value returned from this method is used as * the file argument to the four-argument constructor for java.net.URL * (assuming appropriate values are used for the first three arguments), then a client making a * request to the toExternalForm() of that URL will select the * argument viewId for traversing the JSF lifecycle. Please see section JSF.7.6.2 * for the complete specification, especially for details * related to view protection using the * {@link javax.faces.render.ResponseStateManager#NON_POSTBACK_VIEW_TOKEN_PARAM} * and the behavior when the current request is to a URL * for which the FacesServlet has an exact mapping as defined by Servlet.12.2. *

* * * @param context {@link FacesContext} for this request * @param viewId View identifier of the desired view * * @throws IllegalArgumentException if viewId is not valid for this * ViewHandler, or does not start with "/". * @throws NullPointerException if context or viewId is * null. * * @return the action url. */ public abstract String getActionURL(FacesContext context, String viewId); /** *

* Return a JSF action URL derived from the viewId argument that is suitable to be * used by the {@link NavigationHandler} to issue a redirect request to the URL using a NonFaces * request. Compliant implementations must implement this method as specified in section * JSF.7.6.2. The default implementation simply calls through to {@link #getActionURL}, passing * the arguments context and viewId. *

* * @param context The FacesContext processing this request * @param viewId The view identifier of the target page * @param parameters A mapping of parameter names to one or more values * @param includeViewParams A flag indicating whether view parameters should be encoded into * this URL * @return the redirect URL. * @since 2.0 */ public String getRedirectURL(FacesContext context, String viewId, Map> parameters, boolean includeViewParams) { return getActionURL(context, viewId); } /** *

* Return a JSF action URL derived from the viewId argument that is suitable to be used as the * target of a link in a JSF response. Compiliant implementations must implement this method as * specified in section JSF.7.6.2. The default implementation simply calls through to * {@link #getActionURL}, passing the arguments context and viewId. *

* * @param context The FacesContext processing this request * @param viewId The view identifier of the target page * @param parameters A mapping of parameter names to one or more values * @param includeViewParams A flag indicating whether view parameters should be encoded into * this URL * * @return the bookmarkable URL. * * @since 2.0 */ public String getBookmarkableURL(FacesContext context, String viewId, Map> parameters, boolean includeViewParams) { return getActionURL(context, viewId); } /** *

* If the value returned from this method is used as the file argument to the * four-argument constructor for java.net.URL (assuming appropriate values are used * for the first three arguments), then a client making a request to the * toExternalForm() of that URL will select the argument * path for direct rendering. If the specified path starts with a slash, it must be * treated as context relative; otherwise, it must be treated as relative to the action URL of * the current view. *

* * @param context {@link FacesContext} for the current request * @param path Resource path to convert to a URL * * @throws IllegalArgumentException if viewId is not valid for this * ViewHandler. * @throws NullPointerException if context or path is * null. * * @return the resource URL. */ public abstract String getResourceURL(FacesContext context, String path); /** *

* If the value returned from this method is used as the file argument to the * four-argument constructor for java.net.URL (assuming appropriate values are used * for the first three arguments), then a client making a push handshake request to the * toExternalForm() of that URL will select the argument * channel for connecting the websocket push channel in the current view. It must * match the {@link PushContext#URI_PREFIX} of the endpoint. *

* * @param context {@link FacesContext} for the current request. * @param channel The channel name of the websocket. * * @throws NullPointerException if context or channel is * null. * * @return the websocket URL. * @see PushContext#URI_PREFIX */ public abstract String getWebsocketURL(FacesContext context, String channel); /** *

* Return an unmodifiable Set of the protected views currently known to this * ViewHandler instance. Compliant implementations must return a Set * that is the concatenation of the contents of all the <url-pattern> * elements within all the <protected-views> in all of the application * configuration resources in the current application. The runtime must support calling this * method at any time after application startup. The default implementation returns an * unmodifiable empty Set. *

* * @return the unmodifiable set of protected views. * @since 2.2 */ public Set getProtectedViewsUnmodifiable() { return unmodifiableSet(emptySet()); } /** *

* Add the argument urlPattern to the thread safe Set of protected * views for this application. Compliant implementations make it so a subsequent call to * {@link #getProtectedViewsUnmodifiable} contains the argument. The runtime must support * calling this method at any time after application startup. The default implementation takes * no action. *

* * @param urlPattern the url-pattern to add. * * @since 2.2 */ public void addProtectedView(String urlPattern) { } /** *

* Remove the argument urlPattern from the thread safe Set of * protected views for this application, if present in the Set. If the argument * urlPattern is not present in the Set, this method has no effect. * Compliant implementations must make it so a subsequent call to * {@link #getProtectedViewsUnmodifiable} does not contain the argument. The runtime must * support calling this method at any time after application startup. Returns true * if this Set contained the argument. The default implementation takes no action * and returns false. *

* * @param urlPattern the url-pattern to remove. * @return true if in the Set, false otherwise. * @since 2.2 */ public boolean removeProtectedView(String urlPattern) { return false; } /** *

* Return the {@link ViewDeclarationLanguage} instance * used for this ViewHandler instance. *

* *
* *

* The default implementation must use * {@link javax.faces.view.ViewDeclarationLanguageFactory#getViewDeclarationLanguage} to obtain * the appropriate ViewDeclarationLanguage implementation for the argument * viewId. Any exceptions thrown as a result of invoking that method must not be * swallowed. *

* *

* The default implementation of this method returns null. *

* *
* * @param context the FacesContext for this request. * * @param viewId the logical view id, as returned from * {@link #deriveLogicalViewId} for which the ViewDeclarationLanguage * should be returned. * @return the ViewDeclarationLanguage, or null. * @since 2.0 */ public ViewDeclarationLanguage getViewDeclarationLanguage(FacesContext context, String viewId) { return null; } /** *

* Return a {@code Stream} possibly lazily populated by walking the view trees of every active * {@link ViewDeclarationLanguage} rooted at a given initial path. The view tree of every * {@link ViewDeclarationLanguage} is individually traversed breadth-first as per the * contract of * {@link ViewDeclarationLanguage#getViews(FacesContext, String, int, ViewVisitOption...)}. The * elements in the stream are logical view ids. *

* *

* The {@code maxDepth} parameter is the maximum depth of directory levels to visit for each * {@code ViewDeclarationLanguage} beyond the initial path, which is always visited. * The value is relative to the root ({@code /}), not to the given initial path. E.g. given * {@code maxDepth} = {@code 3} and initial path {@code /foo/}, visiting will proceed up to * {@code /foo/bar/}, where {@code /} counts as depth {@code 1}, {@code /foo/} as depth * {@code 2} and {@code /foo/bar/} as depth {@code 3}. A value lower or equal to the depth of * the initial path means that only the initial path is visited. A value of * {@link Integer#MAX_VALUE MAX_VALUE} may be used to indicate that all levels should be * visited. * *

* In case more than one active {@code ViewDeclarationLanguage} is present, the order in which * view ids from each {@code ViewDeclarationLanguage} appear in the stream is undetermined, * except for the guarantee that every individual {@code ViewDeclarationLanguage} is traversed * breadth-first. * * @param facesContext The {@link FacesContext} for this request. * @param path The initial path from which to start looking for view ids. * @param maxDepth The absolute maximum depth of nested directories to visit counted from the * root ({@code /}). * @param options The options to influence the traversal. See {@link ViewVisitOption} for * details on those. * * @return the {@link Stream} of view ids * * @since 2.3 */ public Stream getViews(FacesContext facesContext, String path, int maxDepth, ViewVisitOption... options) { return Stream.empty(); } /** *

* Return a {@code Stream} possibly lazily populated by walking the view trees of every active * {@link ViewDeclarationLanguage} rooted at a given initial path. The view tree of every * {@link ViewDeclarationLanguage} is individually traversed breadth-first as per the * contract of * {@link ViewDeclarationLanguage#getViews(FacesContext, String, int, ViewVisitOption...)}. The * elements in the stream are logical view ids. *

* *

* This method works as if invoking it were equivalent to evaluating the expression: *

* *
     * getViews(facesContext, start, Integer.MAX_VALUE, options)
     * 
* *
Put differently, it visits all levels of the view tree. * *

* In case more than one active {@code ViewDeclarationLanguage} is present, the order in which * view ids from each {@code ViewDeclarationLanguage} appear in the stream is undetermined, * except for the guarantee that every individual {@code ViewDeclarationLanguage} is traversed * breadth-first. * * @param facesContext The {@link FacesContext} for this request. * @param path The initial path from which to start looking for view ids. * @param options The options to influence the traversal. See {@link ViewVisitOption} for * details on those. * * @return the {@link Stream} of view ids * * @since 2.3 */ public Stream getViews(FacesContext facesContext, String path, ViewVisitOption... options) { return Stream.empty(); } /** *

* Take any appropriate action to either immediately write out the current state information (by * calling {@link StateManager#writeState}, or noting where state information should later be * written. *

* *

* This method must do nothing if the current request is an Ajax request. When * responding to Ajax requests, the state is obtained by calling * {@link StateManager#getViewState} and then written into the Ajax response during * final encoding * ({@link javax.faces.context.PartialViewContext#processPartial(javax.faces.event.PhaseId)}) * . *

* * @param context {@link FacesContext} for the current request * * @throws IOException if an input/output error occurs * @throws NullPointerException if context is null */ public abstract void writeState(FacesContext context) throws IOException; }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy