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

com.sun.faces.config.ConfigManager Maven / Gradle / Ivy

There is a newer version: 4.1.1
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 com.sun.faces.config;

import static com.sun.faces.RIConstants.FACES_PREFIX;
import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.DisableFaceletJSFViewHandler;
import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.DisableFaceletJSFViewHandlerDeprecated;
import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.EnableThreading;
import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.ValidateFacesConfigFiles;
import static com.sun.faces.config.manager.Documents.getProgrammaticDocuments;
import static com.sun.faces.config.manager.Documents.getXMLDocuments;
import static com.sun.faces.config.manager.Documents.mergeDocuments;
import static com.sun.faces.config.manager.Documents.sortDocuments;
import static com.sun.faces.spi.ConfigurationResourceProviderFactory.createProviders;
import static com.sun.faces.spi.ConfigurationResourceProviderFactory.ProviderType.FaceletConfig;
import static com.sun.faces.spi.ConfigurationResourceProviderFactory.ProviderType.FacesConfig;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.unmodifiableList;
import static java.util.logging.Level.FINE;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.logging.Logger;

import javax.el.ELContext;
import javax.el.ELContextEvent;
import javax.el.ELContextListener;
import javax.el.ExpressionFactory;
import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.application.Application;
import javax.faces.application.ApplicationConfigurationPopulator;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.PostConstructApplicationEvent;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;

import com.sun.faces.config.configprovider.MetaInfFaceletTaglibraryConfigProvider;
import com.sun.faces.config.configprovider.MetaInfFacesConfigResourceProvider;
import com.sun.faces.config.configprovider.WebAppFlowConfigResourceProvider;
import com.sun.faces.config.configprovider.WebFaceletTaglibResourceProvider;
import com.sun.faces.config.configprovider.WebFacesConfigResourceProvider;
import com.sun.faces.config.manager.DbfFactory;
import com.sun.faces.config.manager.FacesConfigInfo;
import com.sun.faces.config.manager.documents.DocumentInfo;
import com.sun.faces.config.manager.tasks.FindAnnotatedConfigClasses;
import com.sun.faces.config.manager.tasks.ProvideMetadataToAnnotationScanTask;
import com.sun.faces.config.processor.ApplicationConfigProcessor;
import com.sun.faces.config.processor.BehaviorConfigProcessor;
import com.sun.faces.config.processor.ComponentConfigProcessor;
import com.sun.faces.config.processor.ConfigProcessor;
import com.sun.faces.config.processor.ConverterConfigProcessor;
import com.sun.faces.config.processor.FaceletTaglibConfigProcessor;
import com.sun.faces.config.processor.FacesConfigExtensionProcessor;
import com.sun.faces.config.processor.FacesFlowDefinitionConfigProcessor;
import com.sun.faces.config.processor.FactoryConfigProcessor;
import com.sun.faces.config.processor.LifecycleConfigProcessor;
import com.sun.faces.config.processor.ManagedBeanConfigProcessor;
import com.sun.faces.config.processor.NavigationConfigProcessor;
import com.sun.faces.config.processor.ProtectedViewsConfigProcessor;
import com.sun.faces.config.processor.RenderKitConfigProcessor;
import com.sun.faces.config.processor.ResourceLibraryContractsConfigProcessor;
import com.sun.faces.config.processor.ValidatorConfigProcessor;
import com.sun.faces.el.ELContextImpl;
import com.sun.faces.el.ELUtils;
import com.sun.faces.spi.ConfigurationResourceProvider;
import com.sun.faces.spi.ConfigurationResourceProviderFactory;
import com.sun.faces.spi.HighAvailabilityEnabler;
import com.sun.faces.spi.InjectionProvider;
import com.sun.faces.spi.InjectionProviderFactory;
import com.sun.faces.spi.ThreadContext;
import com.sun.faces.util.FacesLogger;
import com.sun.faces.config.configpopulator.JsfRIRuntimePopulator;

/**
 * 

* This class manages the initialization of each web application that uses * JSF. *

*/ public class ConfigManager { private static final Logger LOGGER = FacesLogger.CONFIG.getLogger(); /** * The initialization time FacesContext scoped key under which the * InjectionProvider is stored. */ public static final String INJECTION_PROVIDER_KEY = ConfigManager.class.getName() + "_INJECTION_PROVIDER_TASK"; /** *

* The ConfigManager will multithread the calls to the * ConfigurationResourceProviders as well as any calls * to parse a resources into a DOM. By default, we'll use only 5 threads * per web application. *

*/ private static final int NUMBER_OF_TASK_THREADS = 5; private static final String CONFIG_MANAGER_INSTANCE_KEY = FACES_PREFIX + "CONFIG_MANAGER_KEY"; /** * The application-scoped key under which the Future responsible for annotation * scanning is associated with. */ private static final String ANNOTATIONS_SCAN_TASK_KEY = ConfigManager.class.getName() + "_ANNOTATION_SCAN_TASK"; /** *

* Contains each ServletContext that we've initialized. * The ServletContext will be removed when the application * is destroyed. *

*/ private List initializedContexts = new CopyOnWriteArrayList<>(); private final List configProcessors = unmodifiableList(asList( new FactoryConfigProcessor(), new LifecycleConfigProcessor(), new ApplicationConfigProcessor(), new ComponentConfigProcessor(), new ConverterConfigProcessor(), new ValidatorConfigProcessor(), new ManagedBeanConfigProcessor(), new RenderKitConfigProcessor(), new NavigationConfigProcessor(), new BehaviorConfigProcessor(), new FacesConfigExtensionProcessor(), new ProtectedViewsConfigProcessor(), new FacesFlowDefinitionConfigProcessor(), new ResourceLibraryContractsConfigProcessor())); /** *

* A List of resource providers that search for faces-config documents. * By default, this contains a provider for the Mojarra, and two other * providers to satisfy the requirements of the specification. *

*/ private final List facesConfigProviders = unmodifiableList(asList( new MetaInfFacesConfigResourceProvider(), new WebAppFlowConfigResourceProvider(), new WebFacesConfigResourceProvider() )); /** *

* A List of resource providers that search for faces-config documents. * By default, this contains a provider for the Mojarra, and one other * providers to satisfy the requirements of the specification. *

*/ private final List facesletsTagLibConfigProviders = unmodifiableList(asList( new MetaInfFaceletTaglibraryConfigProvider(), new WebFaceletTaglibResourceProvider() )); /** *

* The chain of {@link ConfigProcessor} instances to processing of * facelet-taglib documents. *

*/ private final ConfigProcessor faceletTaglibConfigProcessor = new FaceletTaglibConfigProcessor(); // ---------------------------------------------------------- Public STATIC Methods public static ConfigManager createInstance(ServletContext servletContext) { ConfigManager result = new ConfigManager(); servletContext.setAttribute(CONFIG_MANAGER_INSTANCE_KEY, result); return result; } /** * @return a ConfigManager instance */ public static ConfigManager getInstance(ServletContext servletContext) { return (ConfigManager) servletContext.getAttribute(CONFIG_MANAGER_INSTANCE_KEY); } /** * @return the results of the annotation scan task */ public static Map, Set>> getAnnotatedClasses(FacesContext ctx) { Map appMap = ctx.getExternalContext().getApplicationMap(); @SuppressWarnings("unchecked") Future, Set>>> scanTask = (Future, Set>>>) appMap.get(ANNOTATIONS_SCAN_TASK_KEY); try { return scanTask != null ? scanTask.get() : emptyMap(); } catch (InterruptedException | ExecutionException e) { throw new FacesException(e); } } public static void removeInstance(ServletContext servletContext) { servletContext.removeAttribute(CONFIG_MANAGER_INSTANCE_KEY); } // ---------------------------------------------------------- Public instance Methods /** *

* This method bootstraps JSF based on the parsed configuration resources. *

* * @param servletContext the ServletContext for the application that * requires initialization */ public void initialize(ServletContext servletContext, InitFacesContext facesContext) { if (!hasBeenInitialized(servletContext)) { initializedContexts.add(servletContext); initializeConfigProcessers(servletContext, facesContext); ExecutorService executor = null; try { WebConfiguration webConfig = WebConfiguration.getInstance(servletContext); boolean validating = webConfig.isOptionEnabled(ValidateFacesConfigFiles); if (useThreads(servletContext)) { executor = createExecutorService(); } // Obtain and merge the XML and Programmatic documents DocumentInfo[] facesDocuments = mergeDocuments( getXMLDocuments(servletContext, getFacesConfigResourceProviders(), executor, validating), getProgrammaticDocuments(getConfigPopulators())); FacesConfigInfo lastFacesConfigInfo = new FacesConfigInfo(facesDocuments[facesDocuments.length - 1]); facesDocuments = sortDocuments(facesDocuments, lastFacesConfigInfo); InjectionProvider containerConnector = InjectionProviderFactory.createInstance(facesContext.getExternalContext()); facesContext.getAttributes().put(INJECTION_PROVIDER_KEY, containerConnector); boolean isFaceletsDisabled = isFaceletsDisabled(webConfig, lastFacesConfigInfo); if (!lastFacesConfigInfo.isWebInfFacesConfig() || !lastFacesConfigInfo.isMetadataComplete()) { findAnnotations(facesDocuments, containerConnector, servletContext, facesContext, executor); } // See if the app is running in a HA enabled env if (containerConnector instanceof HighAvailabilityEnabler) { ((HighAvailabilityEnabler)containerConnector).enableHighAvailability(servletContext); } // Process the ordered and merged documents // This invokes a chain or processors where each processor grabs its own elements of interest // from each document. DocumentInfo[] facesDocuments2 = facesDocuments; configProcessors.subList(0, 3).stream().forEach(e -> { try { e.process(servletContext, facesContext, facesDocuments2); } catch (Exception e2) { // TODO Auto-generated catch block e2.printStackTrace(); } }); long parentThreadId = Thread.currentThread().getId(); ClassLoader parentContextClassLoader = Thread.currentThread().getContextClassLoader(); ThreadContext threadContext = getThreadContext(containerConnector); Object parentWebContext = threadContext != null ? threadContext.getParentWebContext() : null; configProcessors.subList(3, configProcessors.size()).stream().forEach(e -> { long currentThreadId = Thread.currentThread().getId(); InitFacesContext initFacesContext = null; if (currentThreadId != parentThreadId) { Thread.currentThread().setContextClassLoader(parentContextClassLoader); initFacesContext = InitFacesContext.getInstance(servletContext); if (parentWebContext != null) { threadContext.propagateWebContextToChild(parentWebContext); } } else { initFacesContext = facesContext; } try { e.process(servletContext, initFacesContext, facesDocuments2); } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } finally { if (currentThreadId != parentThreadId) { Thread.currentThread().setContextClassLoader(null); if (parentWebContext != null) { threadContext.clearChildContext(); } } } }); if (!isFaceletsDisabled) { faceletTaglibConfigProcessor.process( servletContext, facesContext, getXMLDocuments( servletContext, getFaceletConfigResourceProviders(), executor, validating)); } } catch (Exception e) { // Clear out any configured factories releaseFactories(); Throwable t = e; if (!(e instanceof ConfigurationException)) { t = new ConfigurationException("CONFIGURATION FAILED! " + t.getMessage(), t); } throw (ConfigurationException)t; } finally { if (executor != null) { executor.shutdown(); } servletContext.removeAttribute(ANNOTATIONS_SCAN_TASK_KEY); } } DbfFactory.removeSchemaMap(servletContext); } /** * @param servletContext * the ServletContext for the application in question * @return true if this application has already been initialized, otherwise returns
fase */ public boolean hasBeenInitialized(ServletContext servletContext) { return initializedContexts.contains(servletContext); } // --------------------------------------------------------- Private Methods /** * Execute the Task responsible for finding annotation classes * */ private void findAnnotations(DocumentInfo[] facesDocuments, InjectionProvider containerConnector, ServletContext servletContext, InitFacesContext context, ExecutorService executor) { ProvideMetadataToAnnotationScanTask taskMetadata = new ProvideMetadataToAnnotationScanTask(facesDocuments, containerConnector); Future, Set>>> annotationScan; if (executor != null) { annotationScan = executor.submit(new FindAnnotatedConfigClasses(servletContext, context, taskMetadata)); } else { annotationScan = new FutureTask<>(new FindAnnotatedConfigClasses(servletContext, context, taskMetadata)); ((FutureTask, Set>>>) annotationScan).run(); } pushTaskToContext(servletContext, annotationScan); } /** * Push the provided Future to the specified ServletContext. */ private void pushTaskToContext(ServletContext sc, Future, Set>>> scanTask) { sc.setAttribute(ANNOTATIONS_SCAN_TASK_KEY, scanTask); } private boolean useThreads(ServletContext ctx) { return WebConfiguration.getInstance(ctx).isOptionEnabled(EnableThreading); } private List getFacesConfigResourceProviders() { return getConfigurationResourceProviders(facesConfigProviders, FacesConfig); } private List getFaceletConfigResourceProviders() { return getConfigurationResourceProviders(facesletsTagLibConfigProviders, FaceletConfig); } private List getConfigurationResourceProviders(List defaultProviders, ConfigurationResourceProviderFactory.ProviderType providerType) { ConfigurationResourceProvider[] customProviders = createProviders(providerType); if (customProviders.length == 0) { return defaultProviders; } List providers = new ArrayList<>(defaultProviders); // Insert the custom providers after the META-INF providers and // before those that scan /WEB-INF providers.addAll((defaultProviders.size() - 1), asList(customProviders)); return unmodifiableList(providers); } private void initializeConfigProcessers(ServletContext servletContext, FacesContext facesContext) { configProcessors.stream().parallel().forEach(e -> e.initializeClassMetadataMap(servletContext, facesContext)); } private List getConfigPopulators() { List configPopulators = new ArrayList<>(); configPopulators.add(new JsfRIRuntimePopulator()); ServiceLoader.load(ApplicationConfigurationPopulator.class) .forEach(e -> configPopulators.add(e)); return configPopulators; } /** * Utility method to check if JSF 2.0 Facelets should be disabled, but that doesn't perform the * check unless lastFacesConfigInfo is indeed *the* WEB-INF/faces-config.xml * * @param webConfig configuration for this application * @param lastFacesConfigInfo object representing WEB-INF/faces-config.xml * @return true if Facelets should be disabled */ private boolean isFaceletsDisabled(WebConfiguration webConfig, FacesConfigInfo lastFacesConfigInfo) { if (lastFacesConfigInfo.isWebInfFacesConfig()) { return _isFaceletsDisabled(webConfig, lastFacesConfigInfo); } return webConfig.isOptionEnabled(DisableFaceletJSFViewHandler) || webConfig.isOptionEnabled(DisableFaceletJSFViewHandlerDeprecated); } /** * Utility method to check if JSF 2.0 Facelets should be disabled. * *

* If it's not explicitly disabled by the context init parameter, then * check the version of the WEB-INF/faces-config.xml document. If the version * is less than 2.0, then override the default value for the context init * parameter so that other parts of the system that use that config option * will know it has been disabled. *

* *

* NOTE: Since this method overrides a configuration value, it should * be called before *any* document parsing is performed the configuration * value may be queried by the ConfigParsers. *

* * @param webconfig configuration for this application * @param facesConfigInfo object representing WEB-INF/faces-config.xml * @return true if Facelets should be disabled */ private boolean _isFaceletsDisabled(WebConfiguration webconfig, FacesConfigInfo facesConfigInfo) { boolean isFaceletsDisabled = webconfig.isOptionEnabled(DisableFaceletJSFViewHandler) || webconfig.isOptionEnabled(DisableFaceletJSFViewHandlerDeprecated); if (!isFaceletsDisabled) { // if not explicitly disabled, make a sanity check against // /WEB-INF/faces-config.xml isFaceletsDisabled = !facesConfigInfo.isVersionGreaterOrEqual(2.0); webconfig.overrideContextInitParameter(DisableFaceletJSFViewHandler, isFaceletsDisabled); } return isFaceletsDisabled; } /** * Publishes a {@link javax.faces.event.PostConstructApplicationEvent} event for the current * {@link Application} instance. */ void publishPostConfigEvent() { FacesContext ctx = FacesContext.getCurrentInstance(); Application app = ctx.getApplication(); if (null == ((InitFacesContext) ctx).getELContext()) { ELContext elContext = new ELContextImpl(app.getELResolver()); elContext.putContext(FacesContext.class, ctx); ExpressionFactory exFactory = ELUtils.getDefaultExpressionFactory(ctx); if (null != exFactory) { elContext.putContext(ExpressionFactory.class, exFactory); } UIViewRoot root = ctx.getViewRoot(); if (null != root) { elContext.setLocale(root.getLocale()); } ELContextListener[] listeners = app.getELContextListeners(); if (listeners.length > 0) { ELContextEvent event = new ELContextEvent(elContext); for (ELContextListener listener : listeners) { listener.contextCreated(event); } } ((InitFacesContext) ctx).setELContext(elContext); } app.publishEvent(ctx, PostConstructApplicationEvent.class, Application.class, app); } /** * Create a new ExecutorService with * {@link #NUMBER_OF_TASK_THREADS} threads. */ private static ExecutorService createExecutorService() { int tc = Runtime.getRuntime().availableProcessors(); if (tc > NUMBER_OF_TASK_THREADS) { tc = NUMBER_OF_TASK_THREADS; } try { return (ExecutorService) new InitialContext().lookup("java:comp/env/concurrent/ThreadPool"); } catch (NamingException e) { // Ignore } return Executors.newFixedThreadPool(tc); } private ThreadContext getThreadContext(InjectionProvider containerConnector) { if (containerConnector instanceof ThreadContext) { return (ThreadContext) containerConnector; } return null; } /** * Calls through to {@link javax.faces.FactoryFinder#releaseFactories()} * ignoring any exceptions. */ private void releaseFactories() { try { FactoryFinder.releaseFactories(); } catch (FacesException ignored) { LOGGER.log(FINE, "Exception thrown from FactoryFinder.releaseFactories()", ignored); } } /** * This method will remove any information about the application. * * @param facesContext * the FacesContext for the application that needs to be removed * @param servletContext * the ServletContext for the application that needs to be removed */ public void destroy(ServletContext servletContext, FacesContext facesContext) { configProcessors.stream().forEach(e -> e.destroy(servletContext, facesContext)); initializedContexts.remove(servletContext); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy