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

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

There is a newer version: 3.1.0.SP02
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 JJakarta Server 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 Jakarta Server Faces {@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 Jakarta Server Faces * 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 Jakarta Server Faces 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 Jakarta Server 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 Jakarta 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 Jakarta 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 Jakarta 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 Jakarta Server Faces 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 Jakarta Server Faces 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 Jakarta Server Faces action URL derived from the viewId argument that is suitable to be used as the * target of a link in a Jakarta Server Faces response. 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 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