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

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

Go to download

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

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

package javax.faces.application;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;

import javax.faces.context.FacesContext;

/**
 * 

* ResourceHandler is the run-time API by which * {@link javax.faces.component.UIComponent} and {@link javax.faces.render.Renderer} * instances, and the * {@link javax.faces.view.ViewDeclarationLanguage} can reference {@link Resource} instances. * An implementation of this class must be thread-safe. *

* *
* *

* Packaging Resources *

* *
* *

* ResourceHandler defines a path based packaging convention for resources. The default * implementation of ResourceHandler must support packaging resources in the classpath * or in the web application root. See section JSF.2.6.1 of the spec prose document * linked in the overview summary for * the normative specification of packaging resources. *

* *

* Briefly, The default implementation must support packaging resources in the web application root * under the path *

* *

* resources/<resourceIdentifier> *

* *

* relative to the web app root. "resources" is the default * location, but this location can be changed by the value of the * {@link #WEBAPP_RESOURCES_DIRECTORY_PARAM_NAME} <context-param>. *

* *

* For the default implementation, resources packaged in the classpath must reside under the JAR * entry name *

* *

* META-INF/resources/<resourceIdentifier> *

* *
* *

* In the case of Faces Flows packaged within jar files, resources packaged in the classpath must * reside under the jar entry name *

* *

* META-INF/flows/<resourceIdentifier> *

* *
* *

* <resourceIdentifier> consists of several segments, specified as follows. *

* *

* [localePrefix/][libraryName/][libraryVersion/]resourceName[/resourceVersion] *

* *

* None of the segments in the resourceIdentifier may be relative paths, such as * ‘../otherLibraryName’. The implementation is not required to support the * libraryVersion and resourceVersion segments for the JAR packaging case. *

* *

* Note that resourceName is the only required segment. *

* *
* *

* Encoding Resources *

* *
* *

* During the handling of view requests, the JSF run-time may be called upon to encode a resource in * such a way as to instruct the user-agent to make a subsequent resource request. This behavior is * orchestrated by one of the resource renderers (ScriptRenderer, * StylesheetRenderer, ImageRenderer), which all call * {@link Resource#getRequestPath} to obtain the encoded URI for the resource. See * {@link Resource#getRequestPath} and the Standard HTML RenderKit specification for the complete * specification. *

* *

* This usage of resources does not apply for resources that correspond to VDL resources. *

* *
* *

* Decoding Resources *

* *
* *

* During the handling of resource requests, the JSF run-time will be called upon to decode a * resource in such a way as to serve up the bytes of the resource to the user-agent. This behavior * is orchestrated by {@link #handleResourceRequest}, which calls {@link Resource#getInputStream} to * obtain bytes of the resource. See {@link #handleResourceRequest} for the complete specification. *

* *

* This usage of resources does not apply for resources that correspond to VDL resources. *

* *
* *
* * @since 2.0 */ public abstract class ResourceHandler { /** *

* {@link Resource#getRequestPath} returns the value of this constant as the prefix of the URI. * {@link #handleResourceRequest(javax.faces.context.FacesContext)} looks for the value of this * constant within the request URI to determine if the request is a resource request or a view * request. *

*/ public static final String RESOURCE_IDENTIFIER = "/javax.faces.resource"; /** *

* Resource name of JSF script resource. *

* * @since 2.3 */ public static final String JSF_SCRIPT_RESOURCE_NAME = "jsf.js"; /** *

* Library name of JSF script resource. *

* * @since 2.3 */ public static final String JSF_SCRIPT_LIBRARY_NAME = "javax.faces"; /** *

* This file must be located in META-INF/contracts/<contractName>/ in a jar * file that contains a resource library contract, where <contractName> is * the name of the contract. If the jar file contains multiple contracts, the marker file must * be present in each one. See “constant field values” for the name of the file that * must be placed at that location. *

* * @since 2.2 */ public static final String RESOURCE_CONTRACT_XML = "javax.faces.contract.xml"; /** *

* If a <context-param> with the param name equal to the value of * {@link #WEBAPP_RESOURCES_DIRECTORY_PARAM_NAME} exists, the runtime must interpret its value * as a path, relative to the web app root, where resources are to be located. This param value * must not start with a "/", though it may contain "/" characters. If no such * <context-param> exists, or its value is invalid, the value "resources", * without the quotes, must be used by the runtime as the value. *

* * @since 2.2 */ public static final String WEBAPP_RESOURCES_DIRECTORY_PARAM_NAME = "javax.faces.WEBAPP_RESOURCES_DIRECTORY"; /** *

* If a <context-param> with the param name equal to the value of * {@link #WEBAPP_CONTRACTS_DIRECTORY_PARAM_NAME} exists, the runtime must interpret its value * as a path, relative to the web app root, where resource library contracts are to be located. * This param value must not start with a "/", though it may contain "/" characters. If no such * <context-param> exists, or its value is invalid, the value "contracts", * without the quotes, must be used by the runtime as the value. *

* * @since 2.2 */ public static final String WEBAPP_CONTRACTS_DIRECTORY_PARAM_NAME = "javax.faces.WEBAPP_CONTRACTS_DIRECTORY"; /** *

* The name of a key within the application message bundle named by the return from * {@link Application#getMessageBundle} whose value is the locale prefix used to find a packaged * resource to return from {@link #createResource} (or one of its variants). */ public static final String LOCALE_PREFIX = "javax.faces.resource.localePrefix"; /** *

* The ServletContext init parameter consulted by the * {@link #handleResourceRequest} to tell which kinds of resources must never be served up in * response to a resource request. The value of this parameter is a single space separated list * of file extensions, including the leading '.' character (without the quotes). If not * specified, the default value given in the value of the * {@link #RESOURCE_EXCLUDES_DEFAULT_VALUE} constant is used. If manually specified, the given * value entirely overrides the default one and does not supplement it. *

*/ public static final String RESOURCE_EXCLUDES_PARAM_NAME = "javax.faces.RESOURCE_EXCLUDES"; /** *

* The default value for the {@link #RESOURCE_EXCLUDES_PARAM_NAME} init param. *

*/ public static final String RESOURCE_EXCLUDES_DEFAULT_VALUE = ".class .jsp .jspx .properties .xhtml .groovy"; // ---------------------------------------------------------- Public Methods /** *

* Create an instance of ViewResource * given the argument resourceName. The content-type of the resource is derived by * passing the resourceName to {@link javax.faces.context.ExternalContext#getMimeType} *

* *
* *

* The algorithm specified in section JSF.2.6.1.4 of the spec prose document * linked in the overview summary * must be executed to create the Resource. New * requirements were introduced in version 2.2 of the specification. For historical reasons, * this method operate correctly when the argument {@code resourceName} is of the form * {@code libraryName/resourceName}, even when {@code resourceName} contains '/' characters. * *

* *
* * @param resourceName the name of the resource. * * @throws NullPointerException if resourceName is null. * * @return a newly created Resource instance, suitable for use in encoding or * decoding the named resource. */ public abstract Resource createResource(String resourceName); /** *

* Create an instance of Resource given the argument resourceName, * which may contain "/" characters. The {@link javax.faces.view.ViewDeclarationLanguage} calls * this method when it needs to load a view from a persistent store, such as a filesystem. This * method is functionality equivalent to {@link #createResource(java.lang.String)}, but all * callsites that need to load VDL views must use this method so that classes that want to * decorate the ResourceHandler in order to only affect the loading of views may do * so without affecting the processing of other kinds of resources, such as scripts and * stylesheets. A {@link javax.faces.context.FacesContext} must be present before calling this * method. To preserve compatibility with prior revisions of the specification, a default * implementation must be provided that calls {@link #createResource(java.lang.String)}. *

* *
* *

* The default implementation must look for the resource in the following places, in this order. *

* *
    * *
  • *

    * Considering resource library contracts (at the locations specified in the spec prose document * section Resource Library Contracts in the Request Processing Lifecycle * chapter). *

    *
  • * *
  • *

    * Considering the web app root. *

    *
  • * *
  • *

    * Considering faces flows (at the locations specified in the spec prose document section * Faces Flows in the Using JSF in Web Applications chapter). *

    *
  • * *
* *

* Call {@link FacesContext#getResourceLibraryContracts}. If the result is non-{@code null} and * not empty, for each value in the list, treat the value as the name of a resource library * contract. If the argument {@code resoureName} exists as a resource in the resource library * contract, return it. Otherwise, return the resource (not in the resource library contract), * if found. Otherwise, return {@code null}. *

*
* * @param context the {@link FacesContext} for this request. * @param resourceName the name of the resource to be interpreted as a view by the * {@link javax.faces.view.ViewDeclarationLanguage}. * * @throws NullPointerException if resourceName is {@code null}. * * @return a newly created {@link ViewResource} instance, suitable for use by the * {@link javax.faces.view.ViewDeclarationLanguage}. * * @since 2.2 */ public ViewResource createViewResource(FacesContext context, String resourceName) { return context.getApplication().getResourceHandler().createResource(resourceName); } /** *

* Return a {@code Stream} possibly lazily populated by walking the resource tree rooted at a * given initial path. The resource tree is traversed breadth-first, the elements in * the stream are view resource names that would yield a {@code ViewResource} when passed into * {@link ResourceHandler#createViewResource} as the {@code resourceName} parameter. *

* *

* The {@code maxDepth} parameter is the maximum depth of directory levels to visit 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. * * @param facesContext The {@link FacesContext} for this request. * @param path The initial path from which to start looking for view resources * @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 ResourceVisitOption} for * details on those. * * @return the {@link Stream} of view resource names * * @since 2.3 */ public Stream getViewResources(FacesContext facesContext, String path, int maxDepth, ResourceVisitOption... options) { return Stream.empty(); } /** *

* Return a {@code Stream} possibly lazily populated by walking the resource tree rooted at a * given initial path. The resource tree is traversed breadth-first, the elements in * the stream are view resource names that would yield a {@code ViewResource} when passed into * {@link ResourceHandler#createViewResource} as the {@code resourceName} parameter. *

* *

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

* *
     * getViewResources(facesContext, start, Integer.MAX_VALUE, options)
     * 
* *
Put differently, it visits all levels of the resource tree. * * @param facesContext The {@link FacesContext} for this request. * @param path The initial path from which to start looking for view resources * @param options The options to influence the traversal. See {@link ResourceVisitOption} for * details on those. * * @return the {@link Stream} of view resource names * * @since 2.3 */ public Stream getViewResources(FacesContext facesContext, String path, ResourceVisitOption... options) { return Stream.empty(); } /** *

* Create an instance of Resource given the argument resourceId. The * content-type of the resource is derived by passing the resourceName to * {@link javax.faces.context.ExternalContext#getMimeType} *

* *
* *

* The resource must be identified according to the specification in JSF.2.6.1.3 of the spec * prose document linked in the overview * summary. New requirements were introduced in version 2.2 of the specification. *

* *
* * @param resourceId the resource identifier of the resource. * * @throws NullPointerException if resourceId is null. * * @return a newly created Resource instance, suitable for use in encoding or * decoding the named resource. * * @since 2.2 */ public Resource createResourceFromId(String resourceId) { return null; } /** *

* Create an instance of Resource with a * resourceName given by the value of the argument resourceName that is a member of * the library named by the argument libraryName. The content-type of the resource * is derived by passing the resourceName to * {@link javax.faces.context.ExternalContext#getMimeType}. *

* *
* *

* The algorithm specified in section JSF.2.6.1.4 of the spec prose document * linked in the overview summary * must be executed to create the Resource. New * requirements were introduced in version 2.2 of the specification. *

* *
* * @param resourceName the name of the resource. * * @param libraryOrContractName the name of the library (or * contract) in which this resource resides, may be null. If there is a * conflict between the name of a resource library and a resource library contract, * the resource library takes precedence. * May not include relative paths, such as * "../". * * @throws NullPointerException if resourceName is null * * @return a newly created Resource instance, suitable for use in encoding or * decoding the named resource. */ public abstract Resource createResource(String resourceName, String libraryOrContractName); /** *

* Create an instance of Resource with a * resourceName given by the value of the argument resourceName that is a * member of the library named by the argument libraryName that claims to have the * content-type given by the argument content-type. *

* *
* *

* The algorithm specified in section JSF.2.6.1.4 of the spec prose document * linked in the overview summary * must be executed to create the Resource. New * requirements were introduced in version 2.2 of the specification. *

* *
* * @param resourceName the name of the resource. * * @param libraryName the name of the library in which this resource resides, may be * null. May not include * relative paths, such as "../". * * @param contentType the mime content that this Resource instance will return from * {@link Resource#getContentType}. If the value is null, The * content-type of the resource is derived by passing the resourceName to * {@link javax.faces.context.ExternalContext#getMimeType} * * @throws NullPointerException if resourceName is null. * * @return a newly created Resource instance, suitable for use in encoding or * decoding the named resource. */ public abstract Resource createResource(String resourceName, String libraryName, String contentType); /** *

* Return true if the resource library * named by the argument libraryName can be found. * If there is a localePrefix for this application, * as defined in {@link #LOCALE_PREFIX}, first look for the library with the prefix. If no such * library is found, look for the library without the prefix. This allows developers to avoid * duplication of files. For example, consider the case where the developer wants to have a * resource library containing a localized image resource and a non-localized script resource. * By checking both locations for the existence of the library, along with other spec changes in * section 2.6.1.4, this scenario is enabled. *

* * @param libraryName the library name. * @return true if the library exists, false otherwise. * @since 2.0 * */ public abstract boolean libraryExists(String libraryName); /** *

* This method specifies the contract for satisfying resource requests. This method is called * from {@link javax.faces.webapp.FacesServlet#service} after that method determines the current * request is a resource request by calling {@link #isResourceRequest}. Thus, * handleResourceRequest may assume that the current request is a resource request. *

* *
* *

* The default implementation must implement an algorithm semantically identical to the * following algorithm. *

* * For discussion, in all cases when a status code is to be set, this spec talks only using the * Servlet API, but it is understood that in a portlet environment the appropriate equivalent * API must be used. * *
    * *
  • *

    * If the resourceIdentifier ends with any of the extensions listed in the value of the * {@link #RESOURCE_EXCLUDES_PARAM_NAME} init parameter, * HttpServletRequest.SC_NOT_FOUND must be passed to * HttpServletResponse.setStatus(), then handleResourceRequest must * immediately return. *

    *
  • * *
  • *

    * Extract the resourceName from the resourceIdentifier by taking the * substring of resourceIdentifier that starts at {@link * #RESOURCE_IDENTIFIER}.length() + 1 and goes to the end of resourceIdentifier. * If no resourceName can be extracted, HttpServletRequest.SC_NOT_FOUND * must be passed to HttpServletResponse.setStatus(), then * handleResourceRequest must immediately return. *

    *
  • * *
  • *

    * Extract the libraryName from the request by looking in the request parameter map for * an entry under the key "ln", without the quotes. If found, use its value as the * libraryName. *

    *
  • * *
  • *

    * If resourceName and libraryName are present, call * {@link #createResource(String, String)} to create the Resource. If only * resourceName is present, call {@link #createResource(String)} to create the * Resource. If the Resource cannot be successfully created, * HttpServletRequest.SC_NOT_FOUND must be passed to * HttpServletResponse.setStatus(), then handleResourceRequest must * immediately return. *

    *
  • * *
  • *

    * Call {@link Resource#userAgentNeedsUpdate}. If this method returns false, * HttpServletRequest.SC_NOT_MODIFIED must be passed to * HttpServletResponse.setStatus(), then handleResourceRequest must * immediately return. *

    *
  • * *
  • *

    * Pass the result of {@link Resource#getContentType} to * HttpServletResponse.setContentType. *

    *
  • * *
  • *

    * Call {@link Resource#getResponseHeaders}. For each entry in this Map, call * HttpServletResponse.setHeader(), passing the key as the first argument and the * value as the second argument. *

    *
  • * *
  • *

    * Call {@link Resource#getInputStream} and serve up the bytes of the resource to the response. *

    *
  • * *
  • *

    * Call HttpServletResponse.setContentLength() passing the byte count of the * resource. *

    *
  • * *
  • *

    * If an IOException is thrown during any of the previous steps, log a descriptive, * localized message, including the resourceName and libraryName (if present). * Then, HttpServletRequest.SC_NOT_FOUND must be passed to * HttpServletResponse.setStatus(), then handleResourceRequest must * immediately return. *

    *
  • * *
  • *

    * In all cases in this method, any streams, channels, sockets, or any other IO resources must * be closed before this method returns. *

    *
  • * *
* *
* * @param context the {@link javax.faces.context.FacesContext} for this request * @throws IOException when an I/O error occurs. */ public abstract void handleResourceRequest(FacesContext context) throws IOException; /** *

* Return true if the current request is a resource request. This method is called * by {@link javax.faces.webapp.FacesServlet#service} to determine if this request is a view * request or a resource request. *

* * @param context the {@link javax.faces.context.FacesContext} for this request * @return true if the current request is a resource request, false * otherwise. */ public abstract boolean isResourceRequest(FacesContext context); /** *

* Return {@code true} if the argument {@code url} contains the string given by the value of the * constant {@link ResourceHandler#RESOURCE_IDENTIFIER}, false otherwise. *

* * @param url the url to inspect for the presence of * {@link ResourceHandler#RESOURCE_IDENTIFIER}. * @return true if this is a resource URL, false otherwise. * @throws NullPointerException if the argument url is {@code null}. */ public boolean isResourceURL(String url) { if (url == null) { throw new NullPointerException("null url"); } return url.contains(RESOURCE_IDENTIFIER); } /** *

* Return the renderer-type for a {@link javax.faces.render.Renderer} that is * capable of rendering this resource. The default implementation must return values according * to the following table. If no renderer-type can be determined, null * must be returned. *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
resource name to renderer-type mapping
example resource namerenderer-type
mycomponent.jsjavax.faces.resource.Script
mystyle.cssjavax.faces.resource.Stylesheet
* * @param resourceName the resource name. * @return the renderer type. */ public abstract String getRendererTypeForResourceName(String resourceName); /** *

* Mark the resource as identified by given resource and library name as rendered. The default * implementation must ensure that {@link #isResourceRendered(FacesContext, String, String)} * will return true when the resource has already been rendered during the render * response phase of the current view. *

* * @param context The {@link FacesContext} for this request. * @param resourceName The name of the resource. * @param libraryName The name of the library in which the resource resides, may be * null. * @since 2.3 */ @SuppressWarnings("unchecked") public void markResourceRendered(FacesContext context, String resourceName, String libraryName) { String resourceIdentifier = libraryName + ":" + resourceName; Set resourceIdentifiers = (Set) context.getAttributes().computeIfAbsent(RESOURCE_IDENTIFIER, k -> new HashSet<>()); resourceIdentifiers.add(resourceIdentifier); } /** *

* Returns whether the resource as identified by given resource and library name has been * rendered. The default implementation must during the render response phase of the current * view return true when the resource has been marked as rendered via * {@link #markResourceRendered(FacesContext, String, String)}. *

* * @param context The {@link FacesContext} for this request. * @param resourceName The name of the resource. * @param libraryName The name of the library in which this resource resides, may be * null. * @return Whether the resource as identified by given resource and library name has been * rendered. * @since 2.3 */ @SuppressWarnings("unchecked") public boolean isResourceRendered(FacesContext context, String resourceName, String libraryName) { String resourceIdentifier = libraryName + ":" + resourceName; Set resourceIdentifiers = (Set) context.getAttributes().get(RESOURCE_IDENTIFIER); return resourceIdentifiers != null && resourceIdentifiers.contains(resourceIdentifier); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy