Context.java

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.catalina;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import jakarta.servlet.ServletContainerInitializer;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletRegistration;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletSecurityElement;
import jakarta.servlet.descriptor.JspConfigDescriptor;

import org.apache.catalina.deploy.NamingResourcesImpl;
import org.apache.tomcat.ContextBind;
import org.apache.tomcat.InstanceManager;
import org.apache.tomcat.JarScanner;
import org.apache.tomcat.util.descriptor.web.ApplicationParameter;
import org.apache.tomcat.util.descriptor.web.ErrorPage;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;
import org.apache.tomcat.util.descriptor.web.LoginConfig;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.apache.tomcat.util.file.ConfigFileLoader;
import org.apache.tomcat.util.file.ConfigurationSource.Resource;
import org.apache.tomcat.util.http.CookieProcessor;

/**
 * A <b>Context</b> is a Container that represents a servlet context, and therefore an individual web application, in
 * the Catalina servlet engine. It is therefore useful in almost every deployment of Catalina (even if a Connector
 * attached to a web server (such as Apache) uses the web server's facilities to identify the appropriate Wrapper to
 * handle this request. It also provides a convenient mechanism to use Interceptors that see every request processed by
 * this particular web application.
 * <p>
 * The parent Container attached to a Context is generally a Host, but may be some other implementation, or may be
 * omitted if it is not necessary.
 * <p>
 * The child containers attached to a Context are generally implementations of Wrapper (representing individual servlet
 * definitions).
 * <p>
 *
 * @author Craig R. McClanahan
 */
public interface Context extends Container, ContextBind {


    // ----------------------------------------------------- Manifest Constants

    /**
     * Container event for adding a welcome file.
     */
    String ADD_WELCOME_FILE_EVENT = "addWelcomeFile";

    /**
     * Container event for removing a wrapper.
     */
    String REMOVE_WELCOME_FILE_EVENT = "removeWelcomeFile";

    /**
     * Container event for clearing welcome files.
     */
    String CLEAR_WELCOME_FILES_EVENT = "clearWelcomeFiles";

    /**
     * Container event for changing the ID of a session.
     */
    String CHANGE_SESSION_ID_EVENT = "changeSessionId";

    /**
     * Prefix for resource lookup.
     */
    String WEBAPP_PROTOCOL = "webapp:";


    // ------------------------------------------------------------- Properties

    /**
     * Returns <code>true</code> if requests mapped to servlets without "multipart config" to parse multipart/form-data
     * requests anyway.
     *
     * @return <code>true</code> if requests mapped to servlets without "multipart config" to parse multipart/form-data
     *             requests, <code>false</code> otherwise.
     */
    boolean getAllowCasualMultipartParsing();


    /**
     * Set to <code>true</code> to allow requests mapped to servlets that do not explicitly declare @MultipartConfig or
     * have &lt;multipart-config&gt; specified in web.xml to parse multipart/form-data requests.
     *
     * @param allowCasualMultipartParsing <code>true</code> to allow such casual parsing, <code>false</code> otherwise.
     */
    void setAllowCasualMultipartParsing(boolean allowCasualMultipartParsing);


    /**
     * Obtain the registered application event listeners.
     *
     * @return An array containing the application event listener instances for this web application in the order they
     *             were specified in the web application deployment descriptor
     */
    Object[] getApplicationEventListeners();


    /**
     * Store the set of initialized application event listener objects, in the order they were specified in the web
     * application deployment descriptor, for this application.
     *
     * @param listeners The set of instantiated listener objects.
     */
    void setApplicationEventListeners(Object listeners[]);


    /**
     * Obtain the registered application lifecycle listeners.
     *
     * @return An array containing the application lifecycle listener instances for this web application in the order
     *             they were specified in the web application deployment descriptor
     */
    Object[] getApplicationLifecycleListeners();


    /**
     * Store the set of initialized application lifecycle listener objects, in the order they were specified in the web
     * application deployment descriptor, for this application.
     *
     * @param listeners The set of instantiated listener objects.
     */
    void setApplicationLifecycleListeners(Object listeners[]);


    /**
     * Obtain the character set name to use with the given Locale. Note that different Contexts may have different
     * mappings of Locale to character set.
     *
     * @param locale The locale for which the mapped character set should be returned
     *
     * @return The name of the character set to use with the given Locale
     */
    String getCharset(Locale locale);


    /**
     * Return the URL of the XML descriptor for this context.
     *
     * @return The URL of the XML descriptor for this context
     */
    URL getConfigFile();


    /**
     * Set the URL of the XML descriptor for this context.
     *
     * @param configFile The URL of the XML descriptor for this context.
     */
    void setConfigFile(URL configFile);


    /**
     * Return the "correctly configured" flag for this Context.
     *
     * @return <code>true</code> if the Context has been correctly configured, otherwise <code>false</code>
     */
    boolean getConfigured();


    /**
     * Set the "correctly configured" flag for this Context. This can be set to false by startup listeners that detect a
     * fatal configuration error to avoid the application from being made available.
     *
     * @param configured The new correctly configured flag
     */
    void setConfigured(boolean configured);


    /**
     * Return the "use cookies for session ids" flag.
     *
     * @return <code>true</code> if it is permitted to use cookies to track session IDs for this web application,
     *             otherwise <code>false</code>
     */
    boolean getCookies();


    /**
     * Set the "use cookies for session ids" flag.
     *
     * @param cookies The new flag
     */
    void setCookies(boolean cookies);


    /**
     * Gets the name to use for session cookies. Overrides any setting that may be specified by the application.
     *
     * @return The value of the default session cookie name or null if not specified
     */
    String getSessionCookieName();


    /**
     * Sets the name to use for session cookies. Overrides any setting that may be specified by the application.
     *
     * @param sessionCookieName The name to use
     */
    void setSessionCookieName(String sessionCookieName);


    /**
     * Gets the value of the use HttpOnly cookies for session cookies flag.
     *
     * @return <code>true</code> if the HttpOnly flag should be set on session cookies
     */
    boolean getUseHttpOnly();


    /**
     * Sets the use HttpOnly cookies for session cookies flag.
     *
     * @param useHttpOnly Set to <code>true</code> to use HttpOnly cookies for session cookies
     */
    void setUseHttpOnly(boolean useHttpOnly);


    /**
     * Should the {@code Partitioned} attribute be added to session cookies created for this web application.
     * <p>
     * The name of the attribute used to indicate a partitioned cookie as part of
     * <a href="https://developers.google.com/privacy-sandbox/3pcd#partitioned">CHIPS</a> is not defined by an RFC and
     * may change in a non-backwards compatible way once equivalent functionality is included in an RFC.
     *
     * @return {@code true} if the {@code Partitioned} attribute should be added to session cookies created for this web
     *             application, otherwise {@code false}
     */
    boolean getUsePartitioned();


    /**
     * Configure whether the {@code Partitioned} attribute should be added to session cookies created for this web
     * application.
     * <p>
     * The name of the attribute used to indicate a partitioned cookie as part of
     * <a href="https://developers.google.com/privacy-sandbox/3pcd#partitioned">CHIPS</a> is not defined by an RFC and
     * may change in a non-backwards compatible way once equivalent functionality is included in an RFC.
     *
     * @param usePartitioned {@code true} if the {@code Partitioned} attribute should be added to session cookies
     *                           created for this web application, otherwise {@code false}
     */
    void setUsePartitioned(boolean usePartitioned);


    /**
     * Gets the domain to use for session cookies. Overrides any setting that may be specified by the application.
     *
     * @return The value of the default session cookie domain or null if not specified
     */
    String getSessionCookieDomain();


    /**
     * Sets the domain to use for session cookies. Overrides any setting that may be specified by the application.
     *
     * @param sessionCookieDomain The domain to use
     */
    void setSessionCookieDomain(String sessionCookieDomain);


    /**
     * Gets the path to use for session cookies. Overrides any setting that may be specified by the application.
     *
     * @return The value of the default session cookie path or null if not specified
     */
    String getSessionCookiePath();


    /**
     * Sets the path to use for session cookies. Overrides any setting that may be specified by the application.
     *
     * @param sessionCookiePath The path to use
     */
    void setSessionCookiePath(String sessionCookiePath);


    /**
     * Is a / added to the end of the session cookie path to ensure browsers, particularly IE, don't send a session
     * cookie for context /foo with requests intended for context /foobar.
     *
     * @return <code>true</code> if the slash is added, otherwise <code>false</code>
     */
    boolean getSessionCookiePathUsesTrailingSlash();


    /**
     * Configures if a / is added to the end of the session cookie path to ensure browsers, particularly IE, don't send
     * a session cookie for context /foo with requests intended for context /foobar.
     *
     * @param sessionCookiePathUsesTrailingSlash <code>true</code> if the slash is should be added, otherwise
     *                                               <code>false</code>
     */
    void setSessionCookiePathUsesTrailingSlash(boolean sessionCookiePathUsesTrailingSlash);


    /**
     * Return the "allow crossing servlet contexts" flag.
     *
     * @return <code>true</code> if cross-contest requests are allowed from this web applications, otherwise
     *             <code>false</code>
     */
    boolean getCrossContext();


    /**
     * Return the alternate Deployment Descriptor name.
     *
     * @return the name
     */
    String getAltDDName();


    /**
     * Set an alternate Deployment Descriptor name.
     *
     * @param altDDName The new name
     */
    void setAltDDName(String altDDName);


    /**
     * Set the "allow crossing servlet contexts" flag.
     *
     * @param crossContext The new cross contexts flag
     */
    void setCrossContext(boolean crossContext);


    /**
     * Return the deny-uncovered-http-methods flag for this web application.
     *
     * @return The current value of the flag
     */
    boolean getDenyUncoveredHttpMethods();


    /**
     * Set the deny-uncovered-http-methods flag for this web application.
     *
     * @param denyUncoveredHttpMethods The new deny-uncovered-http-methods flag
     */
    void setDenyUncoveredHttpMethods(boolean denyUncoveredHttpMethods);


    /**
     * Return the display name of this web application.
     *
     * @return The display name
     */
    String getDisplayName();


    /**
     * Set the display name of this web application.
     *
     * @param displayName The new display name
     */
    void setDisplayName(String displayName);


    /**
     * Get the distributable flag for this web application.
     *
     * @return The value of the distributable flag for this web application.
     */
    boolean getDistributable();


    /**
     * Set the distributable flag for this web application.
     *
     * @param distributable The new distributable flag
     */
    void setDistributable(boolean distributable);


    /**
     * Obtain the document root for this Context.
     *
     * @return An absolute pathname or a relative (to the Host's appBase) pathname.
     */
    String getDocBase();


    /**
     * Set the document root for this Context. This can be either an absolute pathname or a relative pathname. Relative
     * pathnames are relative to the containing Host's appBase.
     *
     * @param docBase The new document root
     */
    void setDocBase(String docBase);


    /**
     * Return the URL encoded context path
     *
     * @return The URL encoded (with UTF-8) context path
     */
    String getEncodedPath();


    /**
     * Determine if annotations parsing is currently disabled
     *
     * @return {@code true} if annotation parsing is disabled for this web application
     */
    boolean getIgnoreAnnotations();


    /**
     * Set the boolean on the annotations parsing for this web application.
     *
     * @param ignoreAnnotations The boolean on the annotations parsing
     */
    void setIgnoreAnnotations(boolean ignoreAnnotations);


    /**
     * Determine if the metadata of the application is complete. This typically means annotations which add to the
     * application metadata will be ignored.
     *
     * @return {@code true} if metadata is complete for this web application
     */
    boolean getMetadataComplete();


    /**
     * Set the boolean on the metadata complete flag for this web application.
     *
     * @param metadataComplete The boolean on the metadata complete flag
     */
    void setMetadataComplete(boolean metadataComplete);


    /**
     * @return the login configuration descriptor for this web application.
     */
    LoginConfig getLoginConfig();


    /**
     * Set the login configuration descriptor for this web application.
     *
     * @param config The new login configuration
     */
    void setLoginConfig(LoginConfig config);


    /**
     * @return the naming resources associated with this web application.
     */
    NamingResourcesImpl getNamingResources();


    /**
     * Set the naming resources for this web application.
     *
     * @param namingResources The new naming resources
     */
    void setNamingResources(NamingResourcesImpl namingResources);


    /**
     * @return the context path for this web application.
     */
    String getPath();


    /**
     * Set the context path for this web application.
     *
     * @param path The new context path
     */
    void setPath(String path);


    /**
     * @return the public identifier of the deployment descriptor DTD that is currently being parsed.
     */
    String getPublicId();


    /**
     * Set the public identifier of the deployment descriptor DTD that is currently being parsed.
     *
     * @param publicId The public identifier
     */
    void setPublicId(String publicId);


    /**
     * @return the reloadable flag for this web application.
     */
    boolean getReloadable();


    /**
     * Set the reloadable flag for this web application.
     *
     * @param reloadable The new reloadable flag
     */
    void setReloadable(boolean reloadable);


    /**
     * @return the override flag for this web application.
     */
    boolean getOverride();


    /**
     * Set the override flag for this web application.
     *
     * @param override The new override flag
     */
    void setOverride(boolean override);


    /**
     * @return the privileged flag for this web application.
     */
    boolean getPrivileged();


    /**
     * Set the privileged flag for this web application.
     *
     * @param privileged The new privileged flag
     */
    void setPrivileged(boolean privileged);


    /**
     * @return the Servlet context for which this Context is a facade.
     */
    ServletContext getServletContext();


    /**
     * @return the default session timeout (in minutes) for this web application.
     */
    int getSessionTimeout();


    /**
     * Set the default session timeout (in minutes) for this web application.
     *
     * @param timeout The new default session timeout
     */
    void setSessionTimeout(int timeout);


    /**
     * Returns <code>true</code> if remaining request data will be read (swallowed) even the request violates a data
     * size constraint.
     *
     * @return <code>true</code> if data will be swallowed (default), <code>false</code> otherwise.
     */
    boolean getSwallowAbortedUploads();


    /**
     * Set to <code>false</code> to disable request data swallowing after an upload was aborted due to size constraints.
     *
     * @param swallowAbortedUploads <code>false</code> to disable swallowing, <code>true</code> otherwise (default).
     */
    void setSwallowAbortedUploads(boolean swallowAbortedUploads);

    /**
     * @return the value of the swallowOutput flag.
     */
    boolean getSwallowOutput();


    /**
     * Set the value of the swallowOutput flag. If set to true, the system.out and system.err will be redirected to the
     * logger during a servlet execution.
     *
     * @param swallowOutput The new value
     */
    void setSwallowOutput(boolean swallowOutput);


    /**
     * @return the Java class name of the Wrapper implementation used for servlets registered in this Context.
     */
    String getWrapperClass();


    /**
     * Set the Java class name of the Wrapper implementation used for servlets registered in this Context.
     *
     * @param wrapperClass The new wrapper class
     */
    void setWrapperClass(String wrapperClass);


    /**
     * Will the parsing of web.xml and web-fragment.xml files for this Context be performed by a namespace aware parser?
     *
     * @return true if namespace awareness is enabled.
     */
    boolean getXmlNamespaceAware();


    /**
     * Controls whether the parsing of web.xml and web-fragment.xml files for this Context will be performed by a
     * namespace aware parser.
     *
     * @param xmlNamespaceAware true to enable namespace awareness
     */
    void setXmlNamespaceAware(boolean xmlNamespaceAware);


    /**
     * Will the parsing of web.xml and web-fragment.xml files for this Context be performed by a validating parser?
     *
     * @return true if validation is enabled.
     */
    boolean getXmlValidation();


    /**
     * Controls whether the parsing of web.xml and web-fragment.xml files for this Context will be performed by a
     * validating parser.
     *
     * @param xmlValidation true to enable xml validation
     */
    void setXmlValidation(boolean xmlValidation);


    /**
     * Will the parsing of web.xml, web-fragment.xml, *.tld, *.jspx, *.tagx and tagplugin.xml files for this Context
     * block the use of external entities?
     *
     * @return true if access to external entities is blocked
     */
    boolean getXmlBlockExternal();


    /**
     * Controls whether the parsing of web.xml, web-fragment.xml, *.tld, *.jspx, *.tagx and tagplugin.xml files for this
     * Context will block the use of external entities.
     *
     * @param xmlBlockExternal true to block external entities
     */
    void setXmlBlockExternal(boolean xmlBlockExternal);


    /**
     * Will the parsing of *.tld files for this Context be performed by a validating parser?
     *
     * @return true if validation is enabled.
     */
    boolean getTldValidation();


    /**
     * Controls whether the parsing of *.tld files for this Context will be performed by a validating parser.
     *
     * @param tldValidation true to enable xml validation
     */
    void setTldValidation(boolean tldValidation);


    /**
     * Get the Jar Scanner to be used to scan for JAR resources for this context.
     *
     * @return The Jar Scanner configured for this context.
     */
    JarScanner getJarScanner();

    /**
     * Set the Jar Scanner to be used to scan for JAR resources for this context.
     *
     * @param jarScanner The Jar Scanner to be used for this context.
     */
    void setJarScanner(JarScanner jarScanner);

    /**
     * @return the {@link Authenticator} that is used by this context. This is always non-{@code null} for a started
     *             Context
     */
    Authenticator getAuthenticator();

    /**
     * Set whether or not the effective web.xml for this context should be logged on context start.
     *
     * @param logEffectiveWebXml set to <code>true</code> to log the complete web.xml that will be used for the webapp
     */
    void setLogEffectiveWebXml(boolean logEffectiveWebXml);

    /**
     * Should the effective web.xml for this context be logged on context start?
     *
     * @return true if the reconstructed web.xml that will be used for the webapp should be logged
     */
    boolean getLogEffectiveWebXml();

    /**
     * @return the instance manager associated with this context.
     */
    InstanceManager getInstanceManager();

    /**
     * Set the instance manager associated with this context.
     *
     * @param instanceManager the new instance manager instance
     */
    void setInstanceManager(InstanceManager instanceManager);

    /**
     * Sets the regular expression that specifies which container provided SCIs should be filtered out and not used for
     * this context. Matching uses {@link java.util.regex.Matcher#find()} so the regular expression only has to match a
     * sub-string of the fully qualified class name of the container provided SCI for it to be filtered out.
     *
     * @param containerSciFilter The regular expression against which the fully qualified class name of each container
     *                               provided SCI should be checked
     */
    void setContainerSciFilter(String containerSciFilter);

    /**
     * Obtains the regular expression that specifies which container provided SCIs should be filtered out and not used
     * for this context. Matching uses {@link java.util.regex.Matcher#find()} so the regular expression only has to
     * match a sub-string of the fully qualified class name of the container provided SCI for it to be filtered out.
     *
     * @return The regular expression against which the fully qualified class name of each container provided SCI will
     *             be checked
     */
    String getContainerSciFilter();


    /**
     * @return the value of the parallel annotation scanning flag. If true, it will dispatch scanning to the utility
     *             executor.
     */
    boolean getParallelAnnotationScanning();

    /**
     * Set the parallel annotation scanning value.
     *
     * @param parallelAnnotationScanning new parallel annotation scanning flag
     */
    void setParallelAnnotationScanning(boolean parallelAnnotationScanning);


    // --------------------------------------------------------- Public Methods

    /**
     * Add a new Listener class name to the set of Listeners configured for this application.
     *
     * @param listener Java class name of a listener class
     */
    void addApplicationListener(String listener);


    /**
     * Add a new application parameter for this application.
     *
     * @param parameter The new application parameter
     */
    void addApplicationParameter(ApplicationParameter parameter);


    /**
     * Add a security constraint to the set for this web application.
     *
     * @param constraint The security constraint that should be added
     */
    void addConstraint(SecurityConstraint constraint);


    /**
     * Add an error page for the specified error or Java exception.
     *
     * @param errorPage The error page definition to be added
     */
    void addErrorPage(ErrorPage errorPage);


    /**
     * Add a filter definition to this Context.
     *
     * @param filterDef The filter definition to be added
     */
    void addFilterDef(FilterDef filterDef);


    /**
     * Add a filter mapping to this Context.
     *
     * @param filterMap The filter mapping to be added
     */
    void addFilterMap(FilterMap filterMap);

    /**
     * Add a filter mapping to this Context before the mappings defined in the deployment descriptor but after any other
     * mappings added via this method.
     *
     * @param filterMap The filter mapping to be added
     *
     * @exception IllegalArgumentException if the specified filter name does not match an existing filter definition, or
     *                                         the filter mapping is malformed
     */
    void addFilterMapBefore(FilterMap filterMap);


    /**
     * Add a Locale Encoding Mapping (see Sec 5.4 of Servlet spec 2.4)
     *
     * @param locale   locale to map an encoding for
     * @param encoding encoding to be used for a give locale
     */
    void addLocaleEncodingMappingParameter(String locale, String encoding);


    /**
     * Add a new MIME mapping, replacing any existing mapping for the specified extension.
     *
     * @param extension Filename extension being mapped
     * @param mimeType  Corresponding MIME type
     */
    void addMimeMapping(String extension, String mimeType);


    /**
     * Add a new context initialization parameter, replacing any existing value for the specified name.
     *
     * @param name  Name of the new parameter
     * @param value Value of the new parameter
     */
    void addParameter(String name, String value);


    /**
     * Add a security role reference for this web application.
     *
     * @param role Security role used in the application
     * @param link Actual security role to check for
     */
    void addRoleMapping(String role, String link);


    /**
     * Add a new security role for this web application.
     *
     * @param role New security role
     */
    void addSecurityRole(String role);


    /**
     * Add a new servlet mapping, replacing any existing mapping for the specified pattern.
     *
     * @param pattern URL pattern to be mapped
     * @param name    Name of the corresponding servlet to execute
     */
    default void addServletMappingDecoded(String pattern, String name) {
        addServletMappingDecoded(pattern, name, false);
    }


    /**
     * Add a new servlet mapping, replacing any existing mapping for the specified pattern.
     *
     * @param pattern     URL pattern to be mapped
     * @param name        Name of the corresponding servlet to execute
     * @param jspWildcard true if name identifies the JspServlet and pattern contains a wildcard; false otherwise
     */
    void addServletMappingDecoded(String pattern, String name, boolean jspWildcard);


    /**
     * Add a resource which will be watched for reloading by the host auto deployer. Note: this will not be used in
     * embedded mode.
     *
     * @param name Path to the resource, relative to docBase
     */
    void addWatchedResource(String name);


    /**
     * Add a new welcome file to the set recognized by this Context.
     *
     * @param name New welcome file name
     */
    void addWelcomeFile(String name);


    /**
     * Add the classname of a LifecycleListener to be added to each Wrapper appended to this Context.
     *
     * @param listener Java class name of a LifecycleListener class
     */
    void addWrapperLifecycle(String listener);


    /**
     * Add the classname of a ContainerListener to be added to each Wrapper appended to this Context.
     *
     * @param listener Java class name of a ContainerListener class
     */
    void addWrapperListener(String listener);


    /**
     * Factory method to create and return a new InstanceManager instance. This can be used for framework integration or
     * easier configuration with custom Context implementations.
     *
     * @return the instance manager
     */
    InstanceManager createInstanceManager();

    /**
     * Factory method to create and return a new Wrapper instance, of the Java implementation class appropriate for this
     * Context implementation. The constructor of the instantiated Wrapper will have been called, but no properties will
     * have been set.
     *
     * @return a newly created wrapper instance that is used to wrap a Servlet
     */
    Wrapper createWrapper();


    /**
     * @return the set of application listener class names configured for this application.
     */
    String[] findApplicationListeners();


    /**
     * @return the set of application parameters for this application.
     */
    ApplicationParameter[] findApplicationParameters();


    /**
     * @return the set of security constraints for this web application. If there are none, a zero-length array is
     *             returned.
     */
    SecurityConstraint[] findConstraints();


    /**
     * @return the error page entry for the specified HTTP error code, if any; otherwise return <code>null</code>.
     *
     * @param errorCode Error code to look up
     */
    ErrorPage findErrorPage(int errorCode);


    /**
     * Find and return the ErrorPage instance for the specified exception's class, or an ErrorPage instance for the
     * closest superclass for which there is such a definition. If no associated ErrorPage instance is found, return
     * <code>null</code>.
     *
     * @param throwable The exception type for which to find an ErrorPage
     *
     * @return the error page entry for the specified Java exception type, if any; otherwise return {@code null}.
     */
    ErrorPage findErrorPage(Throwable throwable);


    /**
     * @return the set of defined error pages for all specified error codes and exception types.
     */
    ErrorPage[] findErrorPages();


    /**
     * @return the filter definition for the specified filter name, if any; otherwise return <code>null</code>.
     *
     * @param filterName Filter name to look up
     */
    FilterDef findFilterDef(String filterName);


    /**
     * @return the set of defined filters for this Context.
     */
    FilterDef[] findFilterDefs();


    /**
     * @return the set of filter mappings for this Context.
     */
    FilterMap[] findFilterMaps();


    /**
     * @return the MIME type to which the specified extension is mapped, if any; otherwise return <code>null</code>.
     *
     * @param extension Extension to map to a MIME type
     */
    String findMimeMapping(String extension);


    /**
     * @return the extensions for which MIME mappings are defined. If there are none, a zero-length array is returned.
     */
    String[] findMimeMappings();


    /**
     * @return the value for the specified context initialization parameter name, if any; otherwise return
     *             <code>null</code>.
     *
     * @param name Name of the parameter to return
     */
    String findParameter(String name);


    /**
     * @return the names of all defined context initialization parameters for this Context. If no parameters are
     *             defined, a zero-length array is returned.
     */
    String[] findParameters();


    /**
     * For the given security role (as used by an application), return the corresponding role name (as defined by the
     * underlying Realm) if there is one. Otherwise, return the specified role unchanged.
     *
     * @param role Security role to map
     *
     * @return The role name that was mapped to the specified role
     */
    String findRoleMapping(String role);


    /**
     * @return <code>true</code> if the specified security role is defined for this application; otherwise return
     *             <code>false</code>.
     *
     * @param role Security role to verify
     */
    boolean findSecurityRole(String role);


    /**
     * @return the security roles defined for this application. If none have been defined, a zero-length array is
     *             returned.
     */
    String[] findSecurityRoles();


    /**
     * @return the servlet name mapped by the specified pattern (if any); otherwise return <code>null</code>.
     *
     * @param pattern Pattern for which a mapping is requested
     */
    String findServletMapping(String pattern);


    /**
     * @return the patterns of all defined servlet mappings for this Context. If no mappings are defined, a zero-length
     *             array is returned.
     */
    String[] findServletMappings();


    /**
     * @return the associated ThreadBindingListener.
     */
    ThreadBindingListener getThreadBindingListener();


    /**
     * Get the associated ThreadBindingListener.
     *
     * @param threadBindingListener Set the listener that will receive notifications when entering and exiting the
     *                                  application scope
     */
    void setThreadBindingListener(ThreadBindingListener threadBindingListener);


    /**
     * @return the set of watched resources for this Context. If none are defined, a zero length array will be returned.
     */
    String[] findWatchedResources();


    /**
     * @return <code>true</code> if the specified welcome file is defined for this Context; otherwise return
     *             <code>false</code>.
     *
     * @param name Welcome file to verify
     */
    boolean findWelcomeFile(String name);


    /**
     * @return the set of welcome files defined for this Context. If none are defined, a zero-length array is returned.
     */
    String[] findWelcomeFiles();


    /**
     * @return the set of LifecycleListener classes that will be added to newly created Wrappers automatically.
     */
    String[] findWrapperLifecycles();


    /**
     * @return the set of ContainerListener classes that will be added to newly created Wrappers automatically.
     */
    String[] findWrapperListeners();


    /**
     * Notify all {@link jakarta.servlet.ServletRequestListener}s that a request has started.
     *
     * @param request The request object that will be passed to the listener
     *
     * @return <code>true</code> if the listeners fire successfully, else <code>false</code>
     */
    boolean fireRequestInitEvent(ServletRequest request);

    /**
     * Notify all {@link jakarta.servlet.ServletRequestListener}s that a request has ended.
     *
     * @param request The request object that will be passed to the listener
     *
     * @return <code>true</code> if the listeners fire successfully, else <code>false</code>
     */
    boolean fireRequestDestroyEvent(ServletRequest request);

    /**
     * Reload this web application, if reloading is supported.
     *
     * @exception IllegalStateException if the <code>reloadable</code> property is set to <code>false</code>.
     */
    void reload();


    /**
     * Remove the specified application listener class from the set of listeners for this application.
     *
     * @param listener Java class name of the listener to be removed
     */
    void removeApplicationListener(String listener);


    /**
     * Remove the application parameter with the specified name from the set for this application.
     *
     * @param name Name of the application parameter to remove
     */
    void removeApplicationParameter(String name);


    /**
     * Remove the specified security constraint from this web application.
     *
     * @param constraint Constraint to be removed
     */
    void removeConstraint(SecurityConstraint constraint);


    /**
     * Remove the error page for the specified error code or Java language exception, if it exists; otherwise, no action
     * is taken.
     *
     * @param errorPage The error page definition to be removed
     */
    void removeErrorPage(ErrorPage errorPage);


    /**
     * Remove the specified filter definition from this Context, if it exists; otherwise, no action is taken.
     *
     * @param filterDef Filter definition to be removed
     */
    void removeFilterDef(FilterDef filterDef);


    /**
     * Remove a filter mapping from this Context.
     *
     * @param filterMap The filter mapping to be removed
     */
    void removeFilterMap(FilterMap filterMap);


    /**
     * Remove the MIME mapping for the specified extension, if it exists; otherwise, no action is taken.
     *
     * @param extension Extension to remove the mapping for
     */
    void removeMimeMapping(String extension);


    /**
     * Remove the context initialization parameter with the specified name, if it exists; otherwise, no action is taken.
     *
     * @param name Name of the parameter to remove
     */
    void removeParameter(String name);


    /**
     * Remove any security role reference for the specified name
     *
     * @param role Security role (as used in the application) to remove
     */
    void removeRoleMapping(String role);


    /**
     * Remove any security role with the specified name.
     *
     * @param role Security role to remove
     */
    void removeSecurityRole(String role);


    /**
     * Remove any servlet mapping for the specified pattern, if it exists; otherwise, no action is taken.
     *
     * @param pattern URL pattern of the mapping to remove
     */
    void removeServletMapping(String pattern);


    /**
     * Remove the specified watched resource name from the list associated with this Context.
     *
     * @param name Name of the watched resource to be removed
     */
    void removeWatchedResource(String name);


    /**
     * Remove the specified welcome file name from the list recognized by this Context.
     *
     * @param name Name of the welcome file to be removed
     */
    void removeWelcomeFile(String name);


    /**
     * Remove a class name from the set of LifecycleListener classes that will be added to newly created Wrappers.
     *
     * @param listener Class name of a LifecycleListener class to be removed
     */
    void removeWrapperLifecycle(String listener);


    /**
     * Remove a class name from the set of ContainerListener classes that will be added to newly created Wrappers.
     *
     * @param listener Class name of a ContainerListener class to be removed
     */
    void removeWrapperListener(String listener);


    /**
     * @return the real path for a given virtual path, if possible; otherwise return <code>null</code>.
     *
     * @param path The path to the desired resource
     */
    String getRealPath(String path);


    /**
     * @return the effective major version of the Servlet spec used by this context.
     */
    int getEffectiveMajorVersion();


    /**
     * Set the effective major version of the Servlet spec used by this context.
     *
     * @param major Set the version number
     */
    void setEffectiveMajorVersion(int major);


    /**
     * @return the effective minor version of the Servlet spec used by this context.
     */
    int getEffectiveMinorVersion();


    /**
     * Set the effective minor version of the Servlet spec used by this context.
     *
     * @param minor Set the version number
     */
    void setEffectiveMinorVersion(int minor);


    /**
     * @return the JSP configuration for this context. Will be null if there is no JSP configuration.
     */
    JspConfigDescriptor getJspConfigDescriptor();


    /**
     * Set the JspConfigDescriptor for this context. A null value indicates there is not JSP configuration.
     *
     * @param descriptor the new JSP configuration
     */
    void setJspConfigDescriptor(JspConfigDescriptor descriptor);


    /**
     * Add a ServletContainerInitializer instance to this web application.
     *
     * @param sci     The instance to add
     * @param classes The classes in which the initializer expressed an interest
     */
    void addServletContainerInitializer(ServletContainerInitializer sci, Set<Class<?>> classes);


    /**
     * Is this Context paused whilst it is reloaded?
     *
     * @return <code>true</code> if the context has been paused
     */
    boolean getPaused();


    /**
     * Is this context using version 2.2 of the Servlet spec?
     *
     * @return <code>true</code> for a legacy Servlet 2.2 webapp
     */
    boolean isServlet22();


    /**
     * Notification that Servlet security has been dynamically set in a
     * {@link jakarta.servlet.ServletRegistration.Dynamic}
     *
     * @param registration           Servlet security was modified for
     * @param servletSecurityElement new security constraints for this Servlet
     *
     * @return urls currently mapped to this registration that are already present in web.xml
     */
    Set<String> addServletSecurity(ServletRegistration.Dynamic registration,
            ServletSecurityElement servletSecurityElement);

    /**
     * Sets the (comma separated) list of Servlets that expect a resource to be present. Used to ensure that welcome
     * files associated with Servlets that expect a resource to be present are not mapped when there is no resource.
     *
     * @param resourceOnlyServlets The Servlet names comma separated list
     */
    void setResourceOnlyServlets(String resourceOnlyServlets);

    /**
     * Obtains the list of Servlets that expect a resource to be present.
     *
     * @return A comma separated list of Servlet names as used in web.xml
     */
    String getResourceOnlyServlets();

    /**
     * Checks the named Servlet to see if it expects a resource to be present.
     *
     * @param servletName Name of the Servlet (as per web.xml) to check
     *
     * @return <code>true</code> if the Servlet expects a resource, otherwise <code>false</code>
     */
    boolean isResourceOnlyServlet(String servletName);

    /**
     * @return the base name to use for WARs, directories or context.xml files for this context.
     */
    String getBaseName();

    /**
     * Set the version of this web application - used to differentiate different versions of the same web application
     * when using parallel deployment.
     *
     * @param webappVersion The webapp version associated with the context, which should be unique
     */
    void setWebappVersion(String webappVersion);

    /**
     * @return The version of this web application, used to differentiate different versions of the same web application
     *             when using parallel deployment. If not specified, defaults to the empty string.
     */
    String getWebappVersion();

    /**
     * Configure whether or not requests listeners will be fired on forwards for this Context.
     *
     * @param enable <code>true</code> to fire request listeners when forwarding
     */
    void setFireRequestListenersOnForwards(boolean enable);

    /**
     * @return whether or not requests listeners will be fired on forwards for this Context.
     */
    boolean getFireRequestListenersOnForwards();

    /**
     * Configures if a user presents authentication credentials, whether the context will process them when the request
     * is for a non-protected resource.
     *
     * @param enable <code>true</code> to perform authentication even outside security constraints
     */
    void setPreemptiveAuthentication(boolean enable);

    /**
     * @return if a user presents authentication credentials, will the context will process them when the request is for
     *             a non-protected resource.
     */
    boolean getPreemptiveAuthentication();

    /**
     * Configures if a response body is included when a redirect response is sent to the client.
     *
     * @param enable <code>true</code> to send a response body for redirects
     */
    void setSendRedirectBody(boolean enable);

    /**
     * @return if the context is configured to include a response body as part of a redirect response.
     */
    boolean getSendRedirectBody();

    /**
     * @return the Loader with which this Context is associated.
     */
    Loader getLoader();

    /**
     * Set the Loader with which this Context is associated.
     *
     * @param loader The newly associated loader
     */
    void setLoader(Loader loader);

    /**
     * @return the Resources with which this Context is associated.
     */
    WebResourceRoot getResources();

    /**
     * Set the Resources object with which this Context is associated.
     *
     * @param resources The newly associated Resources
     */
    void setResources(WebResourceRoot resources);

    /**
     * @return the Manager with which this Context is associated. If there is no associated Manager, return
     *             <code>null</code>.
     */
    Manager getManager();


    /**
     * Set the Manager with which this Context is associated.
     *
     * @param manager The newly associated Manager
     */
    void setManager(Manager manager);

    /**
     * Sets the flag that indicates if /WEB-INF/classes should be treated like an exploded JAR and JAR resources made
     * available as if they were in a JAR.
     *
     * @param addWebinfClassesResources The new value for the flag
     */
    void setAddWebinfClassesResources(boolean addWebinfClassesResources);

    /**
     * @return the flag that indicates if /WEB-INF/classes should be treated like an exploded JAR and JAR resources made
     *             available as if they were in a JAR.
     */
    boolean getAddWebinfClassesResources();

    /**
     * Add a post construct method definition for the given class, if there is an existing definition for the specified
     * class - IllegalArgumentException will be thrown.
     *
     * @param clazz  Fully qualified class name
     * @param method Post construct method name
     *
     * @throws IllegalArgumentException if the fully qualified class name or method name are <code>NULL</code>; if there
     *                                      is already post construct method definition for the given class
     */
    void addPostConstructMethod(String clazz, String method);

    /**
     * Add a pre destroy method definition for the given class, if there is an existing definition for the specified
     * class - IllegalArgumentException will be thrown.
     *
     * @param clazz  Fully qualified class name
     * @param method Post construct method name
     *
     * @throws IllegalArgumentException if the fully qualified class name or method name are <code>NULL</code>; if there
     *                                      is already pre destroy method definition for the given class
     */
    void addPreDestroyMethod(String clazz, String method);

    /**
     * Removes the post construct method definition for the given class, if it exists; otherwise, no action is taken.
     *
     * @param clazz Fully qualified class name
     */
    void removePostConstructMethod(String clazz);

    /**
     * Removes the pre destroy method definition for the given class, if it exists; otherwise, no action is taken.
     *
     * @param clazz Fully qualified class name
     */
    void removePreDestroyMethod(String clazz);

    /**
     * Returns the method name that is specified as post construct method for the given class, if it exists; otherwise
     * <code>NULL</code> will be returned.
     *
     * @param clazz Fully qualified class name
     *
     * @return the method name that is specified as post construct method for the given class, if it exists; otherwise
     *             <code>NULL</code> will be returned.
     */
    String findPostConstructMethod(String clazz);

    /**
     * Returns the method name that is specified as pre destroy method for the given class, if it exists; otherwise
     * <code>NULL</code> will be returned.
     *
     * @param clazz Fully qualified class name
     *
     * @return the method name that is specified as pre destroy method for the given class, if it exists; otherwise
     *             <code>NULL</code> will be returned.
     */
    String findPreDestroyMethod(String clazz);

    /**
     * Returns a map with keys - fully qualified class names of the classes that have post construct methods and the
     * values are the corresponding method names. If there are no such classes an empty map will be returned.
     *
     * @return a map with keys - fully qualified class names of the classes that have post construct methods and the
     *             values are the corresponding method names.
     */
    Map<String,String> findPostConstructMethods();

    /**
     * Returns a map with keys - fully qualified class names of the classes that have pre destroy methods and the values
     * are the corresponding method names. If there are no such classes an empty map will be returned.
     *
     * @return a map with keys - fully qualified class names of the classes that have pre destroy methods and the values
     *             are the corresponding method names.
     */
    Map<String,String> findPreDestroyMethods();

    /**
     * @return the token necessary for operations on the associated JNDI naming context.
     */
    Object getNamingToken();

    /**
     * Sets the {@link CookieProcessor} that will be used to process cookies for this Context.
     *
     * @param cookieProcessor The new cookie processor
     *
     * @throws IllegalArgumentException If a {@code null} CookieProcessor is specified
     */
    void setCookieProcessor(CookieProcessor cookieProcessor);

    /**
     * @return the {@link CookieProcessor} that will be used to process cookies for this Context.
     */
    CookieProcessor getCookieProcessor();

    /**
     * When a client provides the ID for a new session, should that ID be validated? The only use case for using a
     * client provided session ID is to have a common session ID across multiple web applications. Therefore, any client
     * provided session ID should already exist in another web application. If this check is enabled, the client
     * provided session ID will only be used if the session ID exists in at least one other web application for the
     * current host. Note that the following additional tests are always applied, irrespective of this setting:
     * <ul>
     * <li>The session ID is provided by a cookie</li>
     * <li>The session cookie has a path of {@code /}</li>
     * </ul>
     *
     * @param validateClientProvidedNewSessionId {@code true} if validation should be applied
     */
    void setValidateClientProvidedNewSessionId(boolean validateClientProvidedNewSessionId);

    /**
     * Will client provided session IDs be validated (see {@link #setValidateClientProvidedNewSessionId(boolean)})
     * before use?
     *
     * @return {@code true} if validation will be applied. Otherwise, {@code
     *         false}
     */
    boolean getValidateClientProvidedNewSessionId();

    /**
     * If enabled, requests for a web application context root will be redirected (adding a trailing slash) by the
     * Mapper. This is more efficient but has the side effect of confirming that the context path is valid.
     *
     * @param mapperContextRootRedirectEnabled Should the redirects be enabled?
     */
    void setMapperContextRootRedirectEnabled(boolean mapperContextRootRedirectEnabled);

    /**
     * Determines if requests for a web application context root will be redirected (adding a trailing slash) by the
     * Mapper. This is more efficient but has the side effect of confirming that the context path is valid.
     *
     * @return {@code true} if the Mapper level redirect is enabled for this Context.
     */
    boolean getMapperContextRootRedirectEnabled();

    /**
     * If enabled, requests for a directory will be redirected (adding a trailing slash) by the Mapper. This is more
     * efficient but has the side effect of confirming that the directory is valid.
     *
     * @param mapperDirectoryRedirectEnabled Should the redirects be enabled?
     */
    void setMapperDirectoryRedirectEnabled(boolean mapperDirectoryRedirectEnabled);

    /**
     * Determines if requests for a directory will be redirected (adding a trailing slash) by the Mapper. This is more
     * efficient but has the side effect of confirming that the directory is valid.
     *
     * @return {@code true} if the Mapper level redirect is enabled for this Context.
     */
    boolean getMapperDirectoryRedirectEnabled();

    /**
     * Controls whether HTTP 1.1 and later location headers generated by a call to
     * {@link jakarta.servlet.http.HttpServletResponse#sendRedirect(String)} will use relative or absolute redirects.
     * <p>
     * Relative redirects are more efficient but may not work with reverse proxies that change the context path. It
     * should be noted that it is not recommended to use a reverse proxy to change the context path because of the
     * multiple issues it creates.
     * <p>
     * Absolute redirects should work with reverse proxies that change the context path but may cause issues with the
     * {@link org.apache.catalina.filters.RemoteIpFilter} if the filter is changing the scheme and/or port.
     *
     * @param useRelativeRedirects {@code true} to use relative redirects and {@code false} to use absolute redirects
     */
    void setUseRelativeRedirects(boolean useRelativeRedirects);

    /**
     * Will HTTP 1.1 and later location headers generated by a call to
     * {@link jakarta.servlet.http.HttpServletResponse#sendRedirect(String)} use relative or absolute redirects.
     *
     * @return {@code true} if relative redirects will be used {@code false} if absolute redirects are used.
     *
     * @see #setUseRelativeRedirects(boolean)
     */
    boolean getUseRelativeRedirects();

    /**
     * Are paths used in calls to obtain a request dispatcher expected to be encoded? This affects both how Tomcat
     * handles calls to obtain a request dispatcher as well as how Tomcat generates paths used to obtain request
     * dispatchers internally.
     *
     * @param dispatchersUseEncodedPaths {@code true} to use encoded paths, otherwise {@code false}
     */
    void setDispatchersUseEncodedPaths(boolean dispatchersUseEncodedPaths);

    /**
     * Are paths used in calls to obtain a request dispatcher expected to be encoded? This applies to both how Tomcat
     * handles calls to obtain a request dispatcher as well as how Tomcat generates paths used to obtain request
     * dispatchers internally.
     *
     * @return {@code true} if encoded paths will be used, otherwise {@code false}
     */
    boolean getDispatchersUseEncodedPaths();

    /**
     * Set the default request body encoding for this web application.
     *
     * @param encoding The default encoding
     */
    void setRequestCharacterEncoding(String encoding);

    /**
     * Get the default request body encoding for this web application.
     *
     * @return The default request body encoding
     */
    String getRequestCharacterEncoding();

    /**
     * Set the default response body encoding for this web application.
     *
     * @param encoding The default encoding
     */
    void setResponseCharacterEncoding(String encoding);

    /**
     * Get the default response body encoding for this web application.
     *
     * @return The default response body encoding
     */
    String getResponseCharacterEncoding();

    /**
     * Configure if, when returning a context path from
     * {@link jakarta.servlet.http.HttpServletRequest#getContextPath()}, the return value is allowed to contain multiple
     * leading '/' characters.
     *
     * @param allowMultipleLeadingForwardSlashInPath The new value for the flag
     */
    void setAllowMultipleLeadingForwardSlashInPath(boolean allowMultipleLeadingForwardSlashInPath);

    /**
     * When returning a context path from {@link jakarta.servlet.http.HttpServletRequest#getContextPath()}, is it
     * allowed to contain multiple leading '/' characters?
     *
     * @return <code>true</code> if multiple leading '/' characters are allowed, otherwise <code>false</code>
     */
    boolean getAllowMultipleLeadingForwardSlashInPath();


    void incrementInProgressAsyncCount();


    void decrementInProgressAsyncCount();


    /**
     * Configure whether Tomcat will attempt to create an upload target used by this web application if it does not
     * exist when the web application attempts to use it.
     *
     * @param createUploadTargets {@code true} if Tomcat should attempt to create the upload target, otherwise
     *                                {@code false}
     */
    void setCreateUploadTargets(boolean createUploadTargets);


    /**
     * Will Tomcat attempt to create an upload target used by this web application if it does not exist when the web
     * application attempts to use it?
     *
     * @return {@code true} if Tomcat will attempt to create an upload target otherwise {@code false}
     */
    boolean getCreateUploadTargets();


    /**
     * If this is <code>true</code>, every request that is associated with a session will cause the session's last
     * accessed time to be updated regardless of whether or not the request explicitly accesses the session. If
     * <code>org.apache.catalina.STRICT_SERVLET_COMPLIANCE</code> is set to <code>true</code>, the default of this
     * setting will be <code>true</code>, else the default value will be <code>false</code>.
     *
     * @return the flag value
     */
    boolean getAlwaysAccessSession();


    /**
     * Set the session access behavior.
     *
     * @param alwaysAccessSession the new flag value
     */
    void setAlwaysAccessSession(boolean alwaysAccessSession);


    /**
     * If this is <code>true</code> then the path passed to <code>ServletContext.getResource()</code> or
     * <code>ServletContext.getResourceAsStream()</code> must start with &quot;/&quot;. If <code>false</code>, code like
     * <code>getResource("myfolder/myresource.txt")</code> will work as Tomcat will prepend &quot;/&quot; to the
     * provided path. If <code>org.apache.catalina.STRICT_SERVLET_COMPLIANCE</code> is set to <code>true</code>, the
     * default of this setting will be <code>true</code>, else the default value will be <code>false</code>.
     *
     * @return the flag value
     */
    boolean getContextGetResourceRequiresSlash();


    /**
     * Allow using <code>ServletContext.getResource()</code> or <code>ServletContext.getResourceAsStream()</code>
     * without a leading &quot;/&quot;.
     *
     * @param contextGetResourceRequiresSlash the new flag value
     */
    void setContextGetResourceRequiresSlash(boolean contextGetResourceRequiresSlash);


    /**
     * If this is <code>true</code> then any wrapped request or response object passed to an application dispatcher will
     * be checked to ensure that it has wrapped the original request or response. If
     * <code>org.apache.catalina.STRICT_SERVLET_COMPLIANCE</code> is set to <code>true</code>, the default of this
     * setting will be <code>true</code>, else the default value will be <code>false</code>.
     *
     * @return the flag value
     */
    boolean getDispatcherWrapsSameObject();


    /**
     * Allow disabling the object wrap check in the request dispatcher.
     *
     * @param dispatcherWrapsSameObject the new flag value
     */
    void setDispatcherWrapsSameObject(boolean dispatcherWrapsSameObject);


    /**
     * If this is <code>true</code>, then following a forward the response will be unwrapped to suspend the Catalina
     * response instead of simply closing the top level response. The default value is <code>true</code>.
     *
     * @return the flag value
     */
    boolean getSuspendWrappedResponseAfterForward();


    /**
     * Allows unwrapping the response object to suspend the response following a forward.
     *
     * @param suspendWrappedResponseAfterForward the new flag value
     */
    void setSuspendWrappedResponseAfterForward(boolean suspendWrappedResponseAfterForward);


    /**
     * Find configuration file with the specified path, first looking into the webapp resources, then delegating to
     * <code>ConfigFileLoader.getSource().getResource</code>. The <code>WEBAPP_PROTOCOL</code> constant prefix is used
     * to denote webapp resources.
     *
     * @param name The resource name
     *
     * @return the resource
     *
     * @throws IOException if an error occurs or if the resource does not exist
     */
    default Resource findConfigFileResource(String name) throws IOException {
        if (name.startsWith(WEBAPP_PROTOCOL)) {
            String path = name.substring(WEBAPP_PROTOCOL.length());
            WebResource resource = getResources().getResource(path);
            if (resource.canRead() && resource.isFile()) {
                InputStream stream = resource.getInputStream();
                try {
                    return new Resource(stream, resource.getURL().toURI());
                } catch (URISyntaxException e) {
                    stream.close();
                }
            }
            throw new FileNotFoundException(name);
        }
        return ConfigFileLoader.getSource().getResource(name);
    }

}