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

org.omnifaces.resourcehandler.ViewResourceHandler Maven / Gradle / Ivy

There is a newer version: 4.5.1
Show newest version
/*
 * Copyright OmniFaces
 *
 * Licensed 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
 *
 *     https://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.omnifaces.resourcehandler;

import static java.lang.String.format;
import static org.omnifaces.util.FacesLocal.getContextAttribute;
import static org.omnifaces.util.FacesLocal.getRequest;
import static org.omnifaces.util.FacesLocal.getRequestServletPath;
import static org.omnifaces.util.FacesLocal.getResource;
import static org.omnifaces.util.Platform.getFacesServletRegistration;
import static org.omnifaces.util.Utils.isEmpty;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import jakarta.faces.application.ResourceHandler;
import jakarta.faces.application.ViewResource;
import jakarta.faces.context.FacesContext;
import jakarta.faces.webapp.FacesServlet;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletRegistration;

import org.omnifaces.ApplicationListener;
import org.omnifaces.util.Faces;
import org.omnifaces.viewhandler.OmniViewHandler;

/**
 * This {@link ResourceHandler} basically turns any concrete non-Facelets file into a Faces view, so that you can use EL expressions and even Faces components in them.
 * The response content type will default to {@link Faces#getMimeType(String)} which is configureable in web.xml and overrideable via <f:view contentType="...">.
 * 

* Real world examples are /sitemap.xml and /robots.txt. * *

Installation

*

* To get it to run, this handler needs be registered as follows in faces-config.xml: *

 * <application>
 *     <resource-handler>org.omnifaces.resourcehandler.ViewResourceHandler</resource-handler>
 * </application>
 * 
*

* To configure the Faces view resources, a {@value org.omnifaces.resourcehandler.ViewResourceHandler#PARAM_NAME_VIEW_RESOURCES} * context parameter has to be provided wherein the view resources are specified as a comma separated string of context-relative URIs. *

* Here is an example configuration: *

 * <context-param>
 *     <param-name>org.omnifaces.VIEW_RESOURCE_HANDLER_URIS</param-name>
 *     <param-value>/sitemap.xml, /products/sitemap.xml, /reviews/sitemap.xml, /robots.txt</param-value>
 * </context-param>
 * 
*

* Wildcards in URIs are at the moment not supported. *

* The {@link OmniViewHandler} will take care of rendering the view. * * * @author Bauke Scholtz * @since 3.10 * @see DefaultResourceHandler * @see OmniViewHandler */ public class ViewResourceHandler extends DefaultResourceHandler { /** The context parameter name to specify URIs to treat as Faces views. */ public static final String PARAM_NAME_VIEW_RESOURCES = "org.omnifaces.VIEW_RESOURCE_HANDLER_URIS"; private static final String ERROR_MISSING_FORWARD_SLASH = "View resource '%s' must start with a forward slash '/'."; private static final String ERROR_UNKNOWN_VIEW_RESOURCE = "View resource '%s' does not exist."; private static final Set VIEW_RESOURCES = new HashSet<>(); private static final ViewResource VIEW_RESOURCE = new ViewResource() { @Override public URL getURL() { try { FacesContext context = Faces.getContext(); return getResource(context, getRequestServletPath(context)); } catch (MalformedURLException e) { throw new IllegalStateException(e); } } }; /** * This will map the {@link FacesServlet} to the URIs specified in {@value org.omnifaces.resourcehandler.ViewResourceHandler#PARAM_NAME_VIEW_RESOURCES} * context parameter. * This is invoked by {@link ApplicationListener}, because the faces servlet registration has to be available for adding new mappings. * @param servletContext The involved servlet context. * @throws MalformedURLException When one of the URIs specified in context parameter is malformed. */ public static void addFacesServletMappingsIfNecessary(ServletContext servletContext) throws MalformedURLException { String viewResourcesParam = servletContext.getInitParameter(PARAM_NAME_VIEW_RESOURCES); if (isEmpty(viewResourcesParam)) { return; } ServletRegistration facesServletRegistration = getFacesServletRegistration(servletContext); if (facesServletRegistration != null) { Collection existingMappings = facesServletRegistration.getMappings(); for (String viewResource : viewResourcesParam.split("\\s*,\\s*")) { if (!viewResource.startsWith("/")) { throw new IllegalArgumentException(format(ERROR_MISSING_FORWARD_SLASH, viewResource)); } if (servletContext.getResource(viewResource) == null) { throw new IllegalArgumentException(format(ERROR_UNKNOWN_VIEW_RESOURCE, viewResource)); } VIEW_RESOURCES.add(viewResource); if (!existingMappings.contains(viewResource)) { facesServletRegistration.addMapping(viewResource); } } } } /** * Returns true if the current HTTP request is requesting for a view resource managed by this resource handler. * @param context The involved faces context. * @return true if the current HTTP request is requesting for a view resource managed by this resource handler. */ public static boolean isViewResourceRequest(FacesContext context) { return !VIEW_RESOURCES.isEmpty() && getContextAttribute(context, ViewResourceHandler.class.getName(), () -> getRequest(context) != null && VIEW_RESOURCES.contains(getRequest(context).getServletPath())); } /** * Creates a new instance of this view resource handler which wraps the given resource handler. * @param wrapped The resource handler to be wrapped. */ public ViewResourceHandler(ResourceHandler wrapped) { super(wrapped); } /** * This override ensures that {@link Faces#getRequestServletPath()} is returned as concrete resource rather than the provided resourceName * when the {@link #isViewResourceRequest(FacesContext)} returns true. */ @Override public ViewResource createViewResource(FacesContext context, String resourceName) { if (isViewResourceRequest(context)) { return VIEW_RESOURCE; } else { return super.createViewResource(context, resourceName); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy