/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package javax.faces.application;
import java.io.
IOException;
import javax.faces.context.
FacesContext;
/**
* <p class="changed_added_2_0"><strong
* class="changed_modified_2_0_rev_a
* changed_modified_2_2">ResourceHandler</strong> is the run-time API by
* which {@link javax.faces.component.UIComponent} and {@link
* javax.faces.render.Renderer} instances<span
* class="changed_added_2_2">, and the {@link
* javax.faces.view.ViewDeclarationLanguage} can reference {@link
* Resource} instances.</span> An implementation of this class must be
* thread-safe.</p>
*
* <div class="changed_added_2_0">
*
* <p class="javadocSection">Packaging Resources</p>
*
* <ul>
*
* <p>ResourceHandler defines a path based packaging convention for
* resources. The default implementation of
* <code>ResourceHandler</code> must support packaging resources in the
* classpath or in the web application root. See section JSF.2.6.1 of the
* spec prose document <a
* href="../../../overview-summary.html#prose_document">linked in the
* overview summary</a> for the normative specification of packaging
* resources.</p>
* <p>Briefly, The default implementation must support packaging
* resources in the web application root under the path</p>
*
* <p><code>resources/<resourceIdentifier></code></p>
*
* <p>relative to the web app root. <span
* class="changed_added_2_2">"resources" is the default location, but
* this location can be changed by the value of the {@link
* #WEBAPP_RESOURCES_DIRECTORY_PARAM_NAME}
* <code><context-param></code>.</span></p>
*
* <p>For the default implementation, resources packaged in the
* classpath must reside under the JAR entry name</p>
* <p><code>META-INF/resources/<resourceIdentifier></code></p>
* <div class="changed_added_2_2">
* <p>In the case of Faces Flows packaged
* within jar files, resources packaged in the classpath must reside
* under the jar entry name</p>
* <p><code>META-INF/flows/<resourceIdentifier></code></p>
* </div>
* <p><code><resourceIdentifier></code> consists of several
* segments, specified as follows.</p>
* <p><code>[localePrefix/][libraryName/][libraryVersion/]resourceName[/resourceVersion]</code></p>
* <p class="changed_modified_2_0_rev_a">None of the segments in the
* resourceIdentifier may be relative paths, such as
* ‘../otherLibraryName’. The implementation is not
* required to support the <code>libraryVersion</code> and
* <code>resourceVersion</code> segments for the JAR packaging case.</p>
* <p>Note that <em>resourceName</em> is the only required segment.</p>
*
* </ul>
*
* <p class="javadocSection">Encoding Resources</p>
*
* <ul>
*
* <p>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
* (<code>ScriptRenderer</code>, <code>StylesheetRenderer</code>,
* <code>ImageRenderer</code>), 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.</p>
* <p class="changed_added_2_2">This usage of resources does not apply
* for resources that correspond to VDL resources.</p>
*
* </ul>
*
* <p class="javadocSection">Decoding Resources</p>
*
* <ul>
*
* <p>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.</p>
* <p class="changed_added_2_2">This usage of resources does not apply
* for resources that correspond to VDL resources.</p>
* </ul>
*
* </div>
*
* @since 2.0
*/
public abstract class
ResourceHandler {
/**
* <p class="changed_added_2_0">{@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.</p>
*/
public static final
String RESOURCE_IDENTIFIER = "/javax.faces.resource";
/**
* <p class="changed_added_2_2">The name of the marker file that
* the implementation must scan for, within sub-directories
* <code>META-INF/contracts</code>, to identify the set of available
* resource library contracts.</p>
* @since 2.2
*/
public static final
String RESOURCE_CONTRACT_XML = "javax.faces.contract.xml";
/**
* <p class="changed_added_2_2">If a
* <code><context-param></code> 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 <code><context-param></code> exists, or
* its value is invalid, the value "resources", without the quotes,
* must be used by the runtime as the value.</p>
*
* @since 2.2
*/
public static final
String WEBAPP_RESOURCES_DIRECTORY_PARAM_NAME =
"javax.faces.WEBAPP_RESOURCES_DIRECTORY";
/**
* <p class="changed_added_2_2">If a
* <code><context-param></code> 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 <code><context-param></code> exists, or
* its value is invalid, the value "contracts", without the quotes,
* must be used by the runtime as the value.</p>
*
* @since 2.2
*/
public static final
String WEBAPP_CONTRACTS_DIRECTORY_PARAM_NAME =
"javax.faces.WEBAPP_CONTRACTS_DIRECTORY";
/**
* <p class="changed_added_2_0">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";
/**
* <p class="changed_added_2_0">The <code>ServletContext</code> 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. </p>
*/
public static final
String RESOURCE_EXCLUDES_PARAM_NAME =
"javax.faces.RESOURCE_EXCLUDES";
/**
* <p class="changed_added_2_0 changed_modified_2_1">The default value for the {@link
* #RESOURCE_EXCLUDES_PARAM_NAME} init param.</p>
*/
public static final
String RESOURCE_EXCLUDES_DEFAULT_VALUE =
".class .jsp .jspx .properties .xhtml .groovy";
// ---------------------------------------------------------- Public Methods
/**
* <p class="changed_added_2_0"><span
* class="changed_modified_2_2">Create</span> an instance of
* <code>ViewResource</code> given the argument
* <code>resourceName</code>. The content-type of the resource is
* derived by passing the <em>resourceName</em> to {@link
* javax.faces.context.ExternalContext#getMimeType}</p>
* <div class="changed_added_2_0">
* <p>The algorithm specified in section JSF.2.6.1.4 of the spec
* prose document <a
* href="../../../overview-summary.html#prose_document">linked in
* the overview summary</a> must be executed to create the
* <code>Resource</code>. <span class="changed_added_2_2">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. </span></p>
* </div>
* @param resourceName the name of the resource.
*
* @throws NullPointerException if <code>resourceName</code> is
* <code>null</code>.
*
* @return a newly created <code>Resource</code> instance, suitable
* for use in encoding or decoding the named resource.
*/
public abstract
Resource createResource(
String resourceName);
/**
* <p class="changed_added_2_2">Create an instance of <code>Resource</code>
* given the argument <code>resourceName</code>, 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 <code>ResourceHandler</code> 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)}. </p>
* <div class="changed_added_2_2">
* <p>The default implementation must look for the resource in the
* following places, in this order.</p>
* <ul>
* <li><p>Considering resource library contracts (at the locations
* specified in the spec prose document section <em>Resource Library
* Contracts</em> in the <em>Request Processing Lifecycle</em>
* chapter).</p></li>
* <li><p>Considering the web app root.</p></li>
* <li><p>Considering faces flows (at the locations specified in
* the spec prose document section <em>Faces Flows</em> in the
* <em>Using JSF in Web Applications</em> chapter).</p></li>
* </ul>
* <p>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}.</p>
* </div>
* @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 <code>resourceName</code> 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);
}
/**
* <p class="changed_added_2_2">Create an instance of
* <code>Resource</code> given the argument
* <code>resourceId</code>. The content-type of the resource is
* derived by passing the <em>resourceName</em> to {@link
* javax.faces.context.ExternalContext#getMimeType}</p>
* <div class="changed_added_2_2">
* <p>The resource must be identified according to the specification
* in JSF.2.6.1.3 of the spec prose document <a
* href="../../../overview-summary.html#prose_document">linked in
* the overview summary</a>. New requirements were introduced in
* version 2.2 of the specification.</p>
* </div>
* @param resourceId the resource identifier of the resource.
*
* @throws NullPointerException if <code>resourceId</code> is
* <code>null</code>.
*
* @return a newly created <code>Resource</code> instance, suitable
* for use in encoding or decoding the named resource.
*
* @since 2.2
*/
public
Resource createResourceFromId(
String resourceId) {
return null;
}
/**
* <p class="changed_added_2_0"><span
* class="changed_modified_2_2">Create</span> an instance of
* <code>Resource</code> with a resourceName given by the value of
* the argument <code>resourceName</code> that is a member of the
* library named by the argument <code>libraryName</code>. The
* content-type of the resource is derived by passing the
* <em>resourceName</em> to {@link
* javax.faces.context.ExternalContext#getMimeType}.</p>
*
* <div class="changed_added_2_0">
* <p>The algorithm specified in section JSF.2.6.1.4 of the spec
* prose document <a
* href="../../../overview-summary.html#prose_document">linked in
* the overview summary</a> must be executed to create the
* <code>Resource</code>. <span class="changed_added_2_2">New
* requirements were introduced in version 2.2 of the
* specification.</span></p>
* </div>
* @param resourceName the name of the resource.
*
* @param libraryOrContractName <span class="changed_modified_2_2">the
* name of the library (or contract) in which this resource
* resides, may be <code>null</code>. If there is a conflict between
* the name of a resource library and a resource library contract,
* the resource library takes precedence. <span
* class="changed_modified_2_0_rev_a">May not include relative
* paths, such as "../".</span></span>
*
* @throws <code>NullPointerException</code> if
* <code>resourceName</code> is <code>null</code>
*
* @return a newly created <code>Resource</code> instance, suitable
* for use in encoding or decoding the named resource.
*/
public abstract
Resource createResource(
String resourceName,
String libraryOrContractName);
/**
* <p class="changed_added_2_0"><span
* class="changed_modified_2_2">Create</span> an instance of
* <code>Resource</code> with a <em>resourceName</em> given by the
* value of the argument <code>resourceName</code> that is a member
* of the library named by the argument <code>libraryName</code>
* that claims to have the content-type given by the argument
* <code>content-type</code>.</p>
*
* <div class="changed_added_2_0">
* <p>The algorithm specified in section JSF.2.6.1.4 of the spec
* prose document <a
* href="../../../overview-summary.html#prose_document">linked in
* the overview summary</a> must be executed to create the
* <code>Resource</code>. <span class="changed_added_2_2">New
* requirements were introduced in version 2.2 of the
* specification.</span></p>
* </div>
* @param resourceName the name of the resource.
*
* @param libraryName the name of the library in which this resource
* resides, may be <code>null</code>. <span
* class="changed_modified_2_0_rev_a">May not include relative
* paths, such as "../".</span>
*
* @param contentType the mime content that this
* <code>Resource</code> instance will return from {@link
* Resource#getContentType}. If the value is <code>null</code>, The
* content-type of the resource is derived by passing the
* <em>resourceName</em> to {@link
* javax.faces.context.ExternalContext#getMimeType}</p>
*
* @throws <code>NullPointerException</code> if
* <code>resourceName</code> is <code>null</code>.
*
* @return a newly created <code>Resource</code> instance, suitable
* for use in encoding or decoding the named resource.
*/
public abstract
Resource createResource(
String resourceName,
String libraryName,
String contentType);
/**
* <p class="changed_added_2_0"><span
* class="changed_modified_2_2">Return</span> <code>true</code> if
* the resource library named by the argument
* <code>libraryName</code> can be found. <span
* class="changed_added_2_2">If there is a <code>localePrefix</code>
* 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.</span></p>
*
* @since 2.0
*
*/
public abstract boolean
libraryExists(
String libraryName);
/**
* <p class="changed_added_2_0">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, <code>handleResourceRequest</code>
* may assume that the current request is a resource request.</p>
*
* <div class="changed_added_2_0">
*
* <p>The default implementation must implement an algorithm
* semantically identical to the following algorithm.</p>
*
* 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.
*
* <ul>
*
* <li><p>If the <em>resourceIdentifier</em> ends with any of the
* extensions listed in the value of the {@link
* #RESOURCE_EXCLUDES_PARAM_NAME} init parameter,
* <code>HttpServletRequest.SC_NOT_FOUND</code> must be passed to
* <code>HttpServletResponse.setStatus()</code>, then
* <code>handleResourceRequest</code> must immediately return.</p></li>
*
* <li><p>Extract the <em>resourceName</em> from the
* <em>resourceIdentifier</em> by taking the substring of
* <em>resourceIdentifier</em> that starts at <code>{@link
* #RESOURCE_IDENTIFIER}.length() + 1</code> and goes to the end of
* <em>resourceIdentifier</em>. If no <em>resourceName</em> can be
* extracted, <code>HttpServletRequest.SC_NOT_FOUND</code> must be
* passed to <code>HttpServletResponse.setStatus()</code>, then
* <code>handleResourceRequest</code> must immediately return.</p></li>
*
* <li><p>Extract the <em>libraryName</em> 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
* <em>libraryName</em>.</p></li>
*
* <li><p>If <em>resourceName</em> and <em>libraryName</em> are
* present, call {@link #createResource(String, String)} to create
* the <code>Resource</code>. If only <em>resourceName</em> is
* present, call {@link #createResource(String)} to create the
* <code>Resource</code>. If the <code>Resource</code> cannot be
* successfully created,
* <code>HttpServletRequest.SC_NOT_FOUND</code> must be passed to
* <code>HttpServletResponse.setStatus()</code>, then
* <code>handleResourceRequest</code> must immediately return.</p></li>
*
* <li><p>Call {@link Resource#userAgentNeedsUpdate}. If this
* method returns false,
* <code>HttpServletRequest.SC_NOT_MODIFIED</code> must be passed to
* <code>HttpServletResponse.setStatus()</code>, then
* <code>handleResourceRequest</code> must immediately return.</p></li>
*
* <li><p>Pass the result of {@link Resource#getContentType} to
* <code>HttpServletResponse.setContentType.</code> </p></li>
*
* <li><p>Call {@link Resource#getResponseHeaders}. For each entry
* in this <code>Map</code>, call
* <code>HttpServletResponse.setHeader()</code>, passing the key as
* the first argument and the value as the second argument.</p></li>
*
* <li><p>Call {@link Resource#getInputStream} and serve up the
* bytes of the resource to the response.</p></li>
*
* <li><p>Call <code>HttpServletResponse.setContentLength()</code>
* passing the byte count of the resource.</p></li>
*
* <li><p>If an <code>IOException</code> is thrown during any of the
* previous steps, log a descriptive, localized message, including
* the <em>resourceName</em> and <em>libraryName</em> (if present).
* Then, <code>HttpServletRequest.SC_NOT_FOUND</code> must be passed
* to <code>HttpServletResponse.setStatus()</code>, then
* <code>handleResourceRequest</code> must immediately return.</p></li>
*
* <li><p>In all cases in this method, any streams, channels,
* sockets, or any other IO resources must be closed before this
* method returns.</p></li>
*
* </ul>
*
* </div>
*
* @param context the {@link javax.faces.context.FacesContext} for this
* request
*/
public abstract void
handleResourceRequest(
FacesContext context)
throws
IOException;
/**
* <p class="changed_added_2_0">Return <code>true</code> 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 <em>view request</em> or a <em>resource
* request</em>.</p>
*
* @param context the {@link javax.faces.context.FacesContext} for this
* request
* @return <code>true</code> if the current request is a resource
* request, <code>false</code> otherwise.
*/
public abstract boolean
isResourceRequest(
FacesContext context);
/**
* <p class="changed_added_2_2">Return {@code true} if the argument {@code url}
* contains the string given by the value of the constant
* {@link ResourceHandler#RESOURCE_IDENTIFIER}, false otherwise.</p>
*
* @param url the url to inspect for the presence of {@link ResourceHandler#RESOURCE_IDENTIFIER}.
* @throws NullPointerException if the argument url is {@code null}.
*/
public boolean
isResourceURL(
String url) {
boolean
result = false;
if (null ==
url) {
throw new
NullPointerException("null url");
}
result =
url.
contains(
ResourceHandler.
RESOURCE_IDENTIFIER);
return
result;
}
/**
* <p class="changed_added_2_0">Return the <code>renderer-type</code> 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 <code>renderer-type</code> can be determined,
* <code>null</code> must be returned.</p>
*
* <table border="1">
*
* <tr>
*
* <th>example resource name</th>
*
* <th>renderer-type</th>
*
* </tr>
*
* <tr>
*
* <td>mycomponent.js</td>
*
* <td><code>javax.faces.resource.Script</code></td>
*
* </tr>
*
* <tr>
*
* <td>mystyle.css</td>
*
* <td><code>javax.faces.resource.Stylesheet</code></td>
*
* </tr>
*
* </table>
*/
public abstract
String getRendererTypeForResourceName(
String resourceName);
}