/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2016 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
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;
/**
* <p>
* <strong><span class="changed_modified_2_0 changed_modified_2_1 changed_modified_2_2
* changed_modified_2_3"> ViewHandler</span></strong> 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 <em>Render Response</em> and <em>Restore View</em> 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.
*
* <span class="changed_added_2_0">An implementation of this class must be thread-safe.</span>
* </p>
*
* <p>
* Please see {@link StateManager} for information on how the <code>ViewHandler</code> interacts the
* {@link StateManager}.
* </p>
*
* <p class="changed_added_2_0">
* Version 2 of the specification formally introduced the concept of <em>View Declaration
* Language</em>. 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
* <code>ViewHandler</code> 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 <code>ViewHandler</code> provides {@link #getViewDeclarationLanguage} as a convenience
* method to access the VDL implementation given a <code>viewId</code>.
* </p>
*
*/
public abstract class ViewHandler {
private static final Logger log = Logger.getLogger("javax.faces.application");
// ------------------------------------------------------ Manifest Constants
/**
* <p>
* The key, in the session's attribute set, under which the response character encoding may be
* stored and retrieved.
* </p>
*
*/
public static final String CHARACTER_ENCODING_KEY = "javax.faces.request.charset";
/**
* <p>
* <span class="changed_modified_2_0">Allow</span> the web application to define a
* <span class="changed_modified_2_0">list of alternate suffixes</span> for pages containing JSF
* content. <span class="changed_modified_2_0">This list is a space separated list of values of
* the form <i><code>.<extension></code></i>. The first physical resource whose extension
* matches one of the configured extensions will be the suffix used to create the view
* ID.</span> If this init parameter is not specified, the default value is taken from the value
* of the constant {@link #DEFAULT_SUFFIX}.
* </p>
*/
public static final String DEFAULT_SUFFIX_PARAM_NAME = "javax.faces.DEFAULT_SUFFIX";
/**
* <p class="changed_modified_2_1">
* The value to use for the default extension if the webapp is using url extension mapping.
* </p>
*/
public static final String DEFAULT_SUFFIX = ".xhtml .view.xml .jsp";
/**
* <p class="changed_added_2_2">
* 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.
* </p>
*
* @since 2.0
*/
public static final String FACELETS_SKIP_COMMENTS_PARAM_NAME = "javax.faces.FACELETS_SKIP_COMMENTS";
/**
* <p class="changed_added_2_0">
* 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}
* </p>
*
* @since 2.0
*/
public static final String FACELETS_SUFFIX_PARAM_NAME = "javax.faces.FACELETS_SUFFIX";
/**
* <p class="changed_added_2_0">
* The value to use for the default extension for Facelet based XHTML pages if the webapp is
* using url extension mapping.
* </p>
*
* @since 2.0
*/
public static final String DEFAULT_FACELETS_SUFFIX = ".xhtml";
/**
* <p class="changed_added_2_0">
* 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 <code>*.xhtml</code>, or a resource prefix (starting with '/'
* and interpreted as relative to the web application root), as in <code>/user/*</code>. The
* latter class of entry can also take the form of
* <code>/<filename>.<extension>*</code> such as <code>/login.jsp*</code>. The
* runtime must also consider the <code>facelets.VIEW_MAPPINGS</code> param name as an alias to
* this param name for backwards compatibility with existing Facelets applications.
* </p>
*
* @since 2.0
*/
public static final String FACELETS_VIEW_MAPPINGS_PARAM_NAME = "javax.faces.FACELETS_VIEW_MAPPINGS";
/**
* <p class="changed_added_2_2">
* 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.
* </p>
*
* @since 2.0
*/
public static final String FACELETS_BUFFER_SIZE_PARAM_NAME = "javax.faces.FACELETS_BUFFER_SIZE";
/**
* <p class="changed_added_2_2">
* <span class="changed_modified_2_3">When</span> 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. <span class="changed_added_2_3">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.</span>
* </p>
*
* @since 2.0
*/
public static final String FACELETS_REFRESH_PERIOD_PARAM_NAME = "javax.faces.FACELETS_REFRESH_PERIOD";
/**
* <p class="changed_added_2_2">
* 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.
* </p>
*
*
* @since 2.0
*/
public static final String FACELETS_LIBRARIES_PARAM_NAME = "javax.faces.FACELETS_LIBRARIES";
/**
* <p class="changed_added_2_2">
* 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.
* </p>
*
* @since 2.0
*/
public static final String FACELETS_DECORATORS_PARAM_NAME = "javax.faces.FACELETS_DECORATORS";
/**
* <p class="changed_added_2_2">
* 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.
* </p>
*
* @since 2.0
*/
public static final String DISABLE_FACELET_JSF_VIEWHANDLER_PARAM_NAME = "javax.faces.DISABLE_FACELET_JSF_VIEWHANDLER";
// ---------------------------------------------------------- Public Methods
/**
*
* <p>
* <span class="changed_modified_2_0">Initialize</span> the view for the request processing
* lifecycle.
* </p>
*
* <p>
* This method must be called at the beginning of the <em>Restore View Phase</em> of the Request
* Processing Lifecycle. It is responsible for performing any per-request initialization
* necessary to the operation of the lifycecle.
* </p>
*
* <p class="changed_modified_2_0">
* The default implementation must perform the following actions. If
* {@link ExternalContext#getRequestCharacterEncoding} returns <code>null</code>, call
* {@link #calculateCharacterEncoding} and pass the result, if non-<code>null</code>, into the
* {@link ExternalContext#setRequestCharacterEncoding} method. If
* {@link ExternalContext#getRequestCharacterEncoding} returns non-<code>null</code> take no
* action.
* </p>
*
* @param context the Faces context.
* @throws FacesException if a problem occurs setting the encoding, such as the
* <code>UnsupportedEncodingException</code> 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);
}
}
}
/**
* <p>
* <span class="changed_modified_2_0">Perform</span> whatever actions are required to restore
* the view associated with the specified {@link FacesContext} and <code>viewId</code>. It may
* delegate to the <code>restoreView</code> of the associated {@link StateManager} to do the
* actual work of restoring the view. If there is no available state for the specified
* <code>viewId</code>, return <code>null</code>.
* </p>
*
* <p class="changed_added_2_0">
* Otherwise, the default implementation must obtain a reference to the
* {@link ViewDeclarationLanguage} for this <code>viewId</code> and call its
* {@link ViewDeclarationLanguage#restoreView} method, returning the result and not swallowing
* any exceptions thrown by that method.
* </p>
*
* @param context {@link FacesContext} for the current request
* @param viewId the view identifier for the current request
* @return the restored view root, or <b>null</b>.
* @throws NullPointerException if <code>context</code> is <code>null</code>
* @throws FacesException if a servlet error occurs
*/
public abstract UIViewRoot restoreView(FacesContext context, String viewId);
/**
* <p>
* <strong class="changed_modified_2_0">Create</strong> and return a new {@link UIViewRoot}
* instance initialized with information from the argument <code>FacesContext</code> and
* <code>viewId</code>. <span class="changed_modified_2_0">Locate the
* {@link ViewDeclarationLanguage} implementation for the VDL used in the view. The argument
* <code>viewId</code> must be converted to a physical <code>viewId</code> that can refer to an
* actual resource suitable for use by the <code>ViewDeclarationLanguage</code>
* {@link ViewDeclarationLanguage#createView}, which must be called by this method.</span>
*
* @param context the Faces context.
* @param viewId the view id.
* @throws NullPointerException if <code>context</code> is <code>null</code>
*
* @return the viewroot.
*/
public abstract UIViewRoot createView(FacesContext context, String viewId);
/**
* <p>
* <span class="changed_modified_2_0">Perform</span> whatever actions are required to render the
* response view to the response object associated with the current {@link FacesContext}.
* </p>
*
* <p class="changed_added_2_0">
* Otherwise, the default implementation must obtain a reference to the
* {@link ViewDeclarationLanguage} for the <code>viewId</code> of the argument
* <code>viewToRender</code> and call its {@link ViewDeclarationLanguage#renderView} method,
* returning the result and not swallowing any exceptions thrown by that method.
* </p>
*
* @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 <code>context</code> or <code>viewToRender</code> is
* <code>null</code>
* @throws FacesException if a servlet error occurs
*/
public abstract void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException, FacesException;
/**
* <p>
* Returns an appropriate {@link Locale} to use for this and subsequent requests for the current
* client.
* </p>
*
* @param context {@link FacesContext} for the current request
* @return the locale.
* @throws NullPointerException if <code>context</code> is <code>null</code>
*/
public abstract Locale calculateLocale(FacesContext context);
/**
* <p>
* Returns the correct character encoding to be used for this request.
* </p>
*
* <p>
* The following algorithm is employed.
* </p>
*
* <ul>
*
* <li>
* <p>
* Examine the <code>Content-Type</code> request header. If it has a <code>charset</code>
* parameter, extract it and return that as the encoding.
* </p>
* </li>
*
* <li>
* <p>
* If no <code>charset</code> parameter was found, check for the existence of a session by
* calling {@link ExternalContext#getSession(boolean)} passing <code>false</code> as the
* argument. If that method returns <code>true</code>, 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.
* </p>
* </li>
*
* <li>
* <p>
* Otherwise, return <code>null</code>
* </p>
* </li>
*
* </ul>
*
* @param context the Faces context.
* @return the character encoding, or <code>null</code>
* @since 1.2
*/
public String calculateCharacterEncoding(FacesContext context) {
ExternalContext extContext = context.getExternalContext();
Map<String, String> 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;
}
/**
* <p>
* Return an appropriate <code>renderKitId</code> for this and subsequent requests from the
* current client. It is an error for this method to return <code>null</code>.
* </p>
*
* <p>
* The default return value is
* {@link javax.faces.render.RenderKitFactory#HTML_BASIC_RENDER_KIT}.
* </p>
*
* @param context {@link FacesContext} for the current request
* @return the render kit id.
* @throws NullPointerException if <code>context</code> is <code>null</code>
*/
public abstract String calculateRenderKitId(FacesContext context);
/**
* <p class="changed_added_2_0">
* 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.
* </p>
*
* <p class="changed_added_2_3">
* This method should work correctly when the FacesServlet is invoked via either a
* <code>path mapping</code>, <code>extension mapping</code> or an <code>exact match</code>
* (mapping) as defined by Servlet.12.2. Note that <code>path mapping</code> is also commonly
* known as prefix mapping (e.g. "/faces/*") and <code>extension mapping</code> as suffix
* mapping (e.g. "*.xhtml"). An <code>exact match</code> is possible where there's a servlet
* mapping with an exact URL pattern such as "/foo".
* </p>
*
* <p>
* The default implementation of this method simply returns requestViewId unchanged.
* </p>
*
* @param context the <code>FacesContext</code> for this request
*
* @param requestViewId the <code>viewId</code> to derive,
* @return the derived view id.
* @since 2.0
*/
public String deriveViewId(FacesContext context, String requestViewId) {
return requestViewId;
}
/**
* <p class="changed_added_2_1">
* 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
* <code>deriveViewId()</code>, this method does not require that a physical view be present.
* </p>
*
* <p class="changed_added_2_3">
* This method should work correctly when the FacesServlet is invoked via either a
* <code>path mapping</code>, <code>extension mapping</code> or an <code>exact match</code>
* (mapping) as defined by Servlet.12.2. Note that <code>path mapping</code> is also commonly
* known as prefix mapping (e.g. "/faces/*") and <code>extension mapping</code> as suffix
* mapping (e.g. "*.xhtml"). An <code>exact match</code> is possible where there's a servlet
* mapping with an exact URL pattern such as "/foo".
* </p>
*
* <p>
* The default implementation of this method simply returns requestViewId unchanged.
* </p>
*
* @param context the <code>FacesContext</code> for this request
*
* @param requestViewId the <code>viewId</code> to derive,
* @return the derived logical view id.
* @since 2.1
*/
public String deriveLogicalViewId(FacesContext context, String requestViewId) {
return requestViewId;
}
/**
* <p class="changed_modified_2_0">
* <span class="changed_modified_2_2">If</span> the value returned from this method is used as
* the <code>file</code> argument to the four-argument constructor for <code>java.net.URL</code>
* (assuming appropriate values are used for the first three arguments), then a client making a
* request to the <code>toExternalForm()</code> of that <code>URL</code> will select the
* argument <code>viewId</code> for traversing the JSF lifecycle. Please see section JSF.7.6.2
* for the complete specification, <span class="changed_added_2_2">especially for details
* related to view protection using the
* {@link javax.faces.render.ResponseStateManager#NON_POSTBACK_VIEW_TOKEN_PARAM}
* </span><span class="changed_added_2_3"> 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</span>.
* </p>
*
*
* @param context {@link FacesContext} for this request
* @param viewId View identifier of the desired view
*
* @throws IllegalArgumentException if <code>viewId</code> is not valid for this
* <code>ViewHandler</code>, or does not start with "/".
* @throws NullPointerException if <code>context</code> or <code>viewId</code> is
* <code>null</code>.
*
* @return the action url.
*/
public abstract String getActionURL(FacesContext context, String viewId);
/**
* <p class="changed_added_2_0">
* Return a JSF action URL derived from the <code>viewId</code> 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 <code>context</code> and <code>viewId</code>.
* </p>
*
* @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<String, List<String>> parameters, boolean includeViewParams) {
return getActionURL(context, viewId);
}
/**
* <p class="changed_added_2_0">
* 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 <code>context</code> and <code>viewId</code>.
* </p>
*
* @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<String, List<String>> parameters, boolean includeViewParams) {
return getActionURL(context, viewId);
}
/**
* <p class="changed_modified_2_0">
* If the value returned from this method is used as the <code>file</code> argument to the
* four-argument constructor for <code>java.net.URL</code> (assuming appropriate values are used
* for the first three arguments), then a client making a request to the
* <code>toExternalForm()</code> of that <code>URL</code> will select the argument
* <code>path</code> 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.
* </p>
*
* @param context {@link FacesContext} for the current request
* @param path Resource path to convert to a URL
*
* @throws IllegalArgumentException if <code>viewId</code> is not valid for this
* <code>ViewHandler</code>.
* @throws NullPointerException if <code>context</code> or <code>path</code> is
* <code>null</code>.
*
* @return the resource URL.
*/
public abstract String getResourceURL(FacesContext context, String path);
/**
* <p class="changed_added_2_3">
* If the value returned from this method is used as the <code>file</code> argument to the
* four-argument constructor for <code>java.net.URL</code> (assuming appropriate values are used
* for the first three arguments), then a client making a push handshake request to the
* <code>toExternalForm()</code> of that <code>URL</code> will select the argument
* <code>channel</code> for connecting the websocket push channel in the current view. It must
* match the {@link PushContext#URI_PREFIX} of the endpoint.
* </p>
*
* @param context {@link FacesContext} for the current request.
* @param channel The channel name of the websocket.
*
* @throws NullPointerException if <code>context</code> or <code>channel</code> is
* <code>null</code>.
*
* @return the websocket URL.
* @see PushContext#URI_PREFIX
*/
public abstract String getWebsocketURL(FacesContext context, String channel);
/**
* <p class="changed_added_2_2">
* Return an unmodifiable <code>Set</code> of the protected views currently known to this
* <code>ViewHandler</code> instance. Compliant implementations must return a <code>Set</code>
* that is the concatenation of the contents of all the <code><url-pattern></code>
* elements within all the <code><protected-views></code> 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 <code>Set</code>.
* </p>
*
* @return the unmodifiable set of protected views.
* @since 2.2
*/
public Set<String> getProtectedViewsUnmodifiable() {
return unmodifiableSet(emptySet());
}
/**
* <p class="changed_added_2_2">
* Add the argument <code>urlPattern</code> to the thread safe <code>Set</code> 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.
* </p>
*
* @param urlPattern the url-pattern to add.
*
* @since 2.2
*/
public void addProtectedView(String urlPattern) {
}
/**
* <p class="changed_added_2_2">
* Remove the argument <code>urlPattern</code> from the thread safe <code>Set</code> of
* protected views for this application, if present in the <code>Set</code>. If the argument
* <code>urlPattern</code> is not present in the <code>Set</code>, 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 <code>true</code>
* if this <code>Set</code> contained the argument. The default implementation takes no action
* and returns <code>false</code>.
* </p>
*
* @param urlPattern the url-pattern to remove.
* @return <code>true</code> if in the <code>Set</code>, <code>false</code> otherwise.
* @since 2.2
*/
public boolean removeProtectedView(String urlPattern) {
return false;
}
/**
* <p class="changed_added_2_0">
* <span class="changed_modified_2_1">Return</span> the {@link ViewDeclarationLanguage} instance
* used for this <code>ViewHandler</code> instance.
* </p>
*
* <div class="changed_added_2_0">
*
* <p>
* The default implementation must use
* {@link javax.faces.view.ViewDeclarationLanguageFactory#getViewDeclarationLanguage} to obtain
* the appropriate <code>ViewDeclarationLanguage</code> implementation for the argument
* <code>viewId</code>. Any exceptions thrown as a result of invoking that method must not be
* swallowed.
* </p>
*
* <p>
* The default implementation of this method returns null.
* </p>
*
* </div>
*
* @param context the <code>FacesContext</code> for this request.
*
* @param viewId <span class="changed_modified_2_1">the logical view id, as returned from
* {@link #deriveLogicalViewId} for which the <code>ViewDeclarationLanguage</code>
* should be returned.</span>
* @return the ViewDeclarationLanguage, or <b>null</b>.
* @since 2.0
*/
public ViewDeclarationLanguage getViewDeclarationLanguage(FacesContext context, String viewId) {
return null;
}
/**
* <p class="changed_added_2_3">
* 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 <em>breadth-first</em> as per the
* contract of
* {@link ViewDeclarationLanguage#getViews(FacesContext, String, int, ViewVisitOption...)}. The
* elements in the stream are <em>logical</em> view ids.
* </p>
*
* <p>
* The {@code maxDepth} parameter is the maximum depth of directory levels to visit for each
* {@code ViewDeclarationLanguage} <em>beyond the initial path</em>, 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.
*
* <p>
* 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
* <em>breadth-first</em>.
*
* @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<String> getViews(FacesContext facesContext, String path, int maxDepth, ViewVisitOption... options) {
return Stream.empty();
}
/**
* <p class="changed_added_2_3">
* 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 <em>breadth-first</em> as per the
* contract of
* {@link ViewDeclarationLanguage#getViews(FacesContext, String, int, ViewVisitOption...)}. The
* elements in the stream are <em>logical</em> view ids.
* </p>
*
* <p>
* This method works as if invoking it were equivalent to evaluating the expression:
* <blockquote>
*
* <pre>
* getViews(facesContext, start, Integer.MAX_VALUE, options)
* </pre>
*
* </blockquote> Put differently, it visits all levels of the view tree.
*
* <p>
* 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
* <em>breadth-first</em>.
*
* @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<String> getViews(FacesContext facesContext, String path, ViewVisitOption... options) {
return Stream.empty();
}
/**
* <p>
* 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.
* </p>
*
* <p class="changed_added_2_0">
* This method must do nothing if the current request is an <code>Ajax</code> request. When
* responding to <code>Ajax</code> requests, the state is obtained by calling
* {@link StateManager#getViewState} and then written into the <code>Ajax</code> response during
* final encoding <span class="changed_modified_2_3">
* ({@link javax.faces.context.PartialViewContext#processPartial(javax.faces.event.PhaseId)})
* </span>.
* </p>
*
* @param context {@link FacesContext} for the current request
*
* @throws IOException if an input/output error occurs
* @throws NullPointerException if <code>context</code> is <code>null</code>
*/
public abstract void writeState(FacesContext context) throws IOException;
}