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

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

package com.sun.faces.application.resource;

import static com.sun.faces.RIConstants.FLOW_IN_JAR_PREFIX;
import static com.sun.faces.config.WebConfiguration.META_INF_CONTRACTS_DIR;
import static com.sun.faces.config.WebConfiguration.WebContextInitParameter.FaceletsSuffix;
import static jakarta.faces.application.ResourceVisitOption.TOP_LEVEL_VIEWS_ONLY;
import static java.util.Spliterator.DISTINCT;
import static java.util.Spliterators.spliteratorUnknownSize;
import static java.util.stream.StreamSupport.stream;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.stream.Stream;

import com.sun.faces.application.ApplicationAssociate;
import com.sun.faces.config.WebConfiguration;
import com.sun.faces.util.Util;

import jakarta.enterprise.inject.Any;
import jakarta.faces.FacesException;
import jakarta.faces.annotation.View;
import jakarta.faces.application.ResourceVisitOption;
import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext;
import jakarta.faces.flow.Flow;

public class FaceletWebappResourceHelper extends ResourceHelper {

    private static final String[] RESTRICTED_DIRECTORIES = { "/WEB-INF/", "/META-INF/" };

    private final ResourceHelper webappResourceHelper;
    private final String[] configuredExtensions;

    public FaceletWebappResourceHelper(WebappResourceHelper webappResourceHelper) {
        this.webappResourceHelper = webappResourceHelper;
        WebConfiguration webConfig = WebConfiguration.getInstance();
        configuredExtensions = webConfig.getOptionValue(FaceletsSuffix, " ");
    }

    @Override
    public boolean equals(Object obj) {
        return obj instanceof FaceletWebappResourceHelper;
    }

    @Override
    public int hashCode() {
        return 3;
    }

    @Override
    public LibraryInfo findLibrary(String libraryName, String localePrefix, String contract, FacesContext ctx) {
        // FCAPUTO libraries are handled by WebappResourceHelper
        return null;
    }

    @Override
    public ResourceInfo findResource(LibraryInfo library, String resourceName, String localePrefix, boolean compressable, FacesContext ctx) {
        if (localePrefix != null) {
            // FCAPUTO localized facelets are not yet allowed
            return null;
        }

        FaceletResourceInfo result = null;
        try {

            List contracts = ctx.getResourceLibraryContracts();
            ContractInfo[] outContract = new ContractInfo[1];
            boolean[] outDoNotCache = new boolean[1];

            URL url = null;

            // if the library is not null, we must not consider contracts here!
            if (library == null && !contracts.isEmpty()) {
                url = findResourceInfoConsideringContracts(ctx, resourceName, outContract, contracts);
            }

            if (url == null) {
                url = Resource.getResourceUrl(ctx, createPath(library, resourceName));
            }

            if (url == null) {
                url = findResourceUrlConsideringFlows(resourceName, outDoNotCache);
            }

            if (url != null) {
                result = new FaceletResourceInfo(outContract[0], resourceName, null, this, url);
                result.setDoNotCache(outDoNotCache[0]);
            }
        } catch (IOException ex) {
            throw new FacesException(ex);
        }

        return result;
    }

    public Stream getViewResources(FacesContext facesContext, String path, int maxDepth, ResourceVisitOption... options) {
        Stream physicalViewResources = stream(spliteratorUnknownSize(
                new ResourcePathsIterator(path, maxDepth, configuredExtensions, getRestrictedDirectories(options), facesContext.getExternalContext()),
                DISTINCT), false);
        Stream programmaticViewResources = Util.getCdiBeanManager(facesContext)
                .getBeans(Object.class, Any.Literal.INSTANCE).stream()
                .map(bean -> bean.getBeanClass().getAnnotation(View.class))
                .filter(Objects::nonNull)
                .map(View::value);

        return Stream.concat(physicalViewResources, programmaticViewResources);
    }

    private static String[] getRestrictedDirectories(final ResourceVisitOption... options) {
        for (ResourceVisitOption option : options) {
            if (option == TOP_LEVEL_VIEWS_ONLY) {
                return RESTRICTED_DIRECTORIES;
            }
        }

        return null;
    }

    private String createPath(LibraryInfo library, String resourceName) {
        String path = resourceName;
        if (library != null) {
            path = library.getPath() + "/" + resourceName;
        } else {
            // prepend the leading '/' if necessary.
            if (path.charAt(0) != '/') {
                path = "/" + path;
            }
        }

        return path;
    }

    private URL findResourceInfoConsideringContracts(FacesContext ctx, String baseResourceName, ContractInfo[] outContract, List contracts)
            throws MalformedURLException {
        URL url = null;
        String resourceName;

        for (String contract : contracts) {
            if (baseResourceName.startsWith("/")) {
                resourceName = getBaseContractsPath() + "/" + contract + baseResourceName;
            } else {
                resourceName = getBaseContractsPath() + "/" + contract + "/" + baseResourceName;
            }

            url = Resource.getResourceUrl(ctx, resourceName);

            if (url != null) {
                outContract[0] = new ContractInfo(contract);
                break;
            } else {
                if (baseResourceName.startsWith("/")) {
                    resourceName = META_INF_CONTRACTS_DIR + "/" + contract + baseResourceName;
                } else {
                    resourceName = META_INF_CONTRACTS_DIR + "/" + contract + "/" + baseResourceName;
                }
                url = Util.getCurrentLoader(this).getResource(resourceName);
                if (url != null) {
                    outContract[0] = new ContractInfo(contract);
                    break;
                }
            }

        }

        return url;
    }

    private URL findResourceUrlConsideringFlows(String resourceName, boolean[] outDoNotCache) throws IOException {

        URL url = null;

        ClassLoader cl = Util.getCurrentLoader(this);
        Enumeration matches = cl.getResources(FLOW_IN_JAR_PREFIX + resourceName);
        try {
            url = matches.nextElement();
        } catch (NoSuchElementException nsee) {
            url = null;
        }

        if (url != null && matches.hasMoreElements()) {
            boolean keepGoing = true;
            FacesContext context = FacesContext.getCurrentInstance();
            Flow currentFlow = context.getApplication().getFlowHandler().getCurrentFlow(context);

            do {
                if (currentFlow != null && 0 < currentFlow.getDefiningDocumentId().length()) {
                    String definingDocumentId = currentFlow.getDefiningDocumentId();
                    ExternalContext extContext = context.getExternalContext();
                    ApplicationAssociate associate = ApplicationAssociate.getInstance(extContext);
                    if (associate.urlIsRelatedToDefiningDocumentInJar(url, definingDocumentId)) {
                        keepGoing = false;
                        outDoNotCache[0] = true;
                    } else {
                        if (matches.hasMoreElements()) {
                            url = matches.nextElement();
                        } else {
                            keepGoing = false;
                        }
                    }
                } else {
                    keepGoing = false;
                }
            } while (keepGoing);
        }

        return url;
    }

    @Override
    public String getBaseResourcePath() {
        return "";
    }

    @Override
    public String getBaseContractsPath() {
        return webappResourceHelper.getBaseContractsPath();
    }

    @Override
    protected InputStream getNonCompressedInputStream(ResourceInfo info, FacesContext ctx) throws IOException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public URL getURL(ResourceInfo resource, FacesContext ctx) {
        return ((FaceletResourceInfo) resource).getUrl();
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy