jakarta.faces.application.ViewHandler Maven / Gradle / Ivy
Show all versions of jakarta.faces Show documentation
/*
* Copyright (c) 1997, 2020 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 jakarta.faces.application;
import static java.util.Collections.emptySet;
import static java.util.Collections.unmodifiableSet;
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 jakarta.faces.FacesException;
import jakarta.faces.component.UIComponent;
import jakarta.faces.component.UIViewRoot;
import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext;
import jakarta.faces.push.PushContext;
import jakarta.faces.view.ViewDeclarationLanguage;
/**
*
*
* ViewHandler is the pluggablity mechanism for allowing implementations of or applications using the
* Jakarta 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 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("jakarta.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 = "jakarta.faces.request.charset";
/**
*
* This is not anymore used since removal of support for Jakarta Pages.
*
* @deprecated Use {@link #FACELETS_SUFFIX_PARAM_NAME} instead.
*/
@Deprecated(since = "4.0", forRemoval = true)
public static final String DEFAULT_SUFFIX_PARAM_NAME = "jakarta.faces.DEFAULT_SUFFIX";
/**
*
* This is not anymore used since removal of support for Jakarta Pages.
*
* @deprecated Use {@link #DEFAULT_FACELETS_SUFFIX} instead.
*/
@Deprecated(since = "4.0", forRemoval = true)
public static final String DEFAULT_SUFFIX = ".xhtml";
/**
*
* 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.
*
*
* @since 2.0
*/
public static final String FACELETS_SKIP_COMMENTS_PARAM_NAME = "jakarta.faces.FACELETS_SKIP_COMMENTS";
/**
*
* Allow the web application to define a list of alternate suffixes for Facelet based XHTML pages containing Jakarta 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_FACELETS_SUFFIX}
*
*
* @since 2.0
*/
public static final String FACELETS_SUFFIX_PARAM_NAME = "jakarta.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.xhtml*
.
*
*
* @since 2.0
*/
public static final String FACELETS_VIEW_MAPPINGS_PARAM_NAME = "jakarta.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.
*
*
* @since 2.0
*/
public static final String FACELETS_BUFFER_SIZE_PARAM_NAME = "jakarta.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.
* If this value
* is not specified, then the default depends on {@link jakarta.faces.application.ProjectStage}. If it is {@code Production},
* then runtime must act as if it is set to -1, else the runtime must act as if it is
* set to 0.
*
*
* @since 2.0
*/
public static final String FACELETS_REFRESH_PERIOD_PARAM_NAME = "jakarta.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".
*
*
*
* @since 2.0
*/
public static final String FACELETS_LIBRARIES_PARAM_NAME = "jakarta.faces.FACELETS_LIBRARIES";
/**
*
* A semicolon (;) delimitted list of class names of type jakarta.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.
*
*
* @since 2.0
*/
public static final String FACELETS_DECORATORS_PARAM_NAME = "jakarta.faces.FACELETS_DECORATORS";
// ---------------------------------------------------------- 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 originalEncoding = context.getExternalContext().getRequestCharacterEncoding();
String encoding = (originalEncoding != null) ? originalEncoding : calculateCharacterEncoding(context);
if (encoding != null && context.getExternalContext().getSession(false) != null) {
context.getExternalContext().getSessionMap().put(CHARACTER_ENCODING_KEY, encoding);
}
if (originalEncoding != null) {
return;
}
if (encoding != null) {
try {
context.getExternalContext().setRequestCharacterEncoding(encoding);
} catch (UnsupportedEncodingException e) {
String message = "Can't set encoding to: " + encoding + " Exception:" + e.getMessage();
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 jakarta.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
* section 7.6.2 "Default ViewHandler Implementation" of the Jakarta Faces Specification Document.
*
*
*
* 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
* section 7.6.2 "Default ViewHandler Implementation" of the Jakarta Faces Specification Document.
* 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 Faces lifecycle. Please see
* section 7.6.2 "Default ViewHandler Implementation" of the Jakarta Faces Specification Document
* for the complete specification, especially for details related to view
* protection using the {@link jakarta.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 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 7.6.2 "Default ViewHandler Implementation" of the Jakarta Faces Specification Document.
* 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 Faces action URL derived from the viewId argument that is suitable to be used as the target
* of a link in a Jakarta Faces response. Compliant implementations must implement this method as specified in
* section 7.6.2 "Default ViewHandler Implementation" of the Jakarta Faces Specification Document.
* 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 jakarta.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 jakarta.faces.context.PartialViewContext#processPartial(jakarta.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;
}