jakarta.faces.FactoryFinder Maven / Gradle / Ivy
/*
* 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 jakarta.faces;
import static jakarta.faces.ServletContextFacesContextFactory.SERVLET_CONTEXT_FINDER_NAME;
/**
*
* FactoryFinder implements the standard discovery algorithm for all factory objects
* specified in the Jakarta Server Faces APIs. For a given factory class name, a corresponding implementation class is
* searched for based on the following algorithm. Items are listed in order of decreasing search precedence:
*
*
*
*
* -
*
* If the Jakarta Server Faces configuration file bundled into the WEB-INF
directory of the webapp contains
* a factory
entry of the given factory class name, that factory is used.
*
*
*
* -
*
* If the Jakarta Server Faces configuration files named by the jakarta.faces.CONFIG_FILES
* ServletContext
init parameter contain any factory
entries of the given factory class name,
* those injectionProvider are used, with the last one taking precedence.
*
*
*
* -
*
* If there are any Jakarta Server Faces configuration files bundled into the META-INF
directory of any
* jars on the ServletContext
's resource paths, the factory
entries of the given factory class
* name in those files are used, with the last one taking precedence.
*
*
*
* -
*
* If a META-INF/services/{factory-class-name}
resource is visible to the web application class loader for
* the calling application (typically as a injectionProvider of being present in the manifest of a JAR file), its first
* line is read and assumed to be the name of the factory implementation class to use.
*
*
*
* -
*
* If none of the above steps yield a match, the Jakarta Server Faces implementation specific class is used.
*
*
*
*
*
*
* If any of the injectionProvider found on any of the steps above happen to have a one-argument constructor, with
* argument the type being the abstract factory class, that constructor is invoked, and the previous match is passed to
* the constructor. For example, say the container vendor provided an implementation of
* {@link jakarta.faces.context.FacesContextFactory}, and identified it in
* META-INF/services/jakarta.faces.context.FacesContextFactory
in a jar on the webapp ClassLoader. Also say
* this implementation provided by the container vendor had a one argument constructor that took a
* FacesContextFactory
instance. The FactoryFinder
system would call that one-argument
* constructor, passing the implementation of FacesContextFactory
provided by the Jakarta Server Faces
* implementation.
*
*
*
* If a Factory implementation does not provide a proper one-argument constructor, it must provide a zero-arguments
* constructor in order to be successfully instantiated.
*
*
*
* Once the name of the factory implementation class is located, the web application class loader for the calling
* application is requested to load this class, and a corresponding instance of the class will be created. A side effect
* of this rule is that each web application will receive its own instance of each factory class, whether the Jakarta
* Server Faces implementation is included within the web application or is made visible through the container's
* facilities for shared libraries.
*
*/
public final class FactoryFinder {
// ----------------------------------------------------------- Constructors
/**
* Package-private constructor to disable instantiation of this class.
*/
FactoryFinder() {
}
// ----------------------------------------------------- Manifest Constants
/**
*
* The property name for the {@link jakarta.faces.application.ApplicationFactory} class name.
*
*/
public final static String APPLICATION_FACTORY = "jakarta.faces.application.ApplicationFactory";
/**
*
* The property name for the {@link jakarta.faces.lifecycle.ClientWindowFactory} class name.
*
*
* @since 2.2
*/
public final static String CLIENT_WINDOW_FACTORY = "jakarta.faces.lifecycle.ClientWindowFactory";
/**
*
* The property name for the {@link jakarta.faces.context.ExceptionHandlerFactory} class name.
*
*/
public final static String EXCEPTION_HANDLER_FACTORY = "jakarta.faces.context.ExceptionHandlerFactory";
/**
*
* The property name for the {@link jakarta.faces.context.ExternalContextFactory} class name.
*
*/
public final static String EXTERNAL_CONTEXT_FACTORY = "jakarta.faces.context.ExternalContextFactory";
/**
*
* The property name for the {@link jakarta.faces.context.FacesContextFactory} class name.
*
*/
public final static String FACES_CONTEXT_FACTORY = "jakarta.faces.context.FacesContextFactory";
/**
*
* The property name for the {@link jakarta.faces.view.facelets.FaceletCacheFactory} class name.
*
*
* @since 2.1
*/
public final static String FACELET_CACHE_FACTORY = "jakarta.faces.view.facelets.FaceletCacheFactory";
/**
*
* The property name for the {@link jakarta.faces.context.FlashFactory} class name.
*
*
* @since 2.2
*/
public final static String FLASH_FACTORY = "jakarta.faces.context.FlashFactory";
/**
*
* The property name for the {@link jakarta.faces.flow.FlowHandlerFactory} class name.
*
*
* @since 2.2
*/
public final static String FLOW_HANDLER_FACTORY = "jakarta.faces.flow.FlowHandlerFactory";
/**
*
* The property name for the {@link jakarta.faces.context.PartialViewContextFactory} class name.
*
*/
public final static String PARTIAL_VIEW_CONTEXT_FACTORY = "jakarta.faces.context.PartialViewContextFactory";
/**
*
* The property name for the {@link jakarta.faces.component.visit.VisitContextFactory} class name.
*
*/
public final static String VISIT_CONTEXT_FACTORY = "jakarta.faces.component.visit.VisitContextFactory";
/**
*
* The property name for the {@link jakarta.faces.lifecycle.LifecycleFactory} class name.
*
*/
public final static String LIFECYCLE_FACTORY = "jakarta.faces.lifecycle.LifecycleFactory";
/**
*
* The property name for the {@link jakarta.faces.render.RenderKitFactory} class name.
*
*/
public final static String RENDER_KIT_FACTORY = "jakarta.faces.render.RenderKitFactory";
/**
*
* The property name for the {@link jakarta.faces.view.ViewDeclarationLanguage} class name.
*
*/
public final static String VIEW_DECLARATION_LANGUAGE_FACTORY = "jakarta.faces.view.ViewDeclarationLanguageFactory";
/**
*
* The property name for the {@link jakarta.faces.view.facelets.TagHandlerDelegate} class name.
*
*/
public final static String TAG_HANDLER_DELEGATE_FACTORY = "jakarta.faces.view.facelets.TagHandlerDelegateFactory";
/**
*
* The property name for the {@link jakarta.faces.component.search.SearchExpressionContext} class name.
*
*/
public static final String SEARCH_EXPRESSION_CONTEXT_FACTORY = "jakarta.faces.component.search.SearchExpressionContextFactory";
// ------------------------------------------------------- Static Variables
static final CurrentThreadToServletContext FACTORIES_CACHE = new CurrentThreadToServletContext();
// --------------------------------------------------------- Public Methods
/**
*
* Create (if necessary) and return a per-web-application instance of the
* appropriate implementation class for the specified Jakarta Server Faces factory class, based on the discovery
* algorithm described in the class description.
*
*
*
* The standard injectionProvider and wrappers in Jakarta Server Faces all implement the interface {@link FacesWrapper}.
* If the returned Object
is an implementation of one of the standard injectionProvider, it must be legal
* to cast it to an instance of FacesWrapper
and call {@link FacesWrapper#getWrapped} on the instance.
*
*
* @param factoryName Fully qualified name of the Jakarta Server Faces factory for which an implementation instance is
* requested
* @throws FacesException if the web application class loader cannot be identified
* @throws FacesException if an instance of the configured factory implementation class cannot be loaded
* @throws FacesException if an instance of the configured factory implementation class cannot be instantiated
* @throws IllegalArgumentException if factoryName
does not identify a standard Jakarta Server Faces
* factory name
* @throws IllegalStateException if there is no configured factory implementation class for the specified factory name
* @throws NullPointerException if factoryname
is null
*
* @return the found factory instance
*/
public static Object getFactory(String factoryName) throws FacesException {
FactoryFinderInstance factoryFinder;
// Bug 20458755: If the factory being requested is the special
// SERVLET_CONTEXT_FINDER, do not lazily create the FactoryFinderInstance.
if (SERVLET_CONTEXT_FINDER_NAME.equals(factoryName)) {
factoryFinder = FACTORIES_CACHE.getFactoryFinder(false);
} else {
factoryFinder = FACTORIES_CACHE.getFactoryFinder();
}
if (factoryFinder != null) {
return factoryFinder.getFactory(factoryName);
}
return null;
}
/**
*
* This method will store the argument factoryName/implName
mapping in such a way that {@link #getFactory}
* will find this mapping when searching for a match.
*
*
*
* This method has no effect if getFactory()
has already been called looking for a factory for this
* factoryName
.
*
*
*
* This method can be used by implementations to store a factory mapping while parsing the Faces configuration file
*
*
* @throws IllegalArgumentException if factoryName
does not identify a standard Jakarta Server Faces
* factory name
* @throws NullPointerException if factoryname
is null
*
* @param factoryName the name to be used in a subsequent call to {@link #getFactory}.
*
* @param implName the fully qualified class name of the factory corresponding to {@code factoryName}.
*/
public static void setFactory(String factoryName, String implName) {
FACTORIES_CACHE.getFactoryFinder().addFactory(factoryName, implName);
}
/**
*
* Release any references to factory instances associated with the class
* loader for the calling web application. This method must be called during of web
* application shutdown.
*
*
* @throws FacesException if the web application class loader cannot be identified
*/
public static void releaseFactories() throws FacesException {
synchronized (FACTORIES_CACHE) {
if (!FACTORIES_CACHE.factoryFinderMap.isEmpty()) {
FACTORIES_CACHE.getFactoryFinder().releaseFactories();
}
FACTORIES_CACHE.removeFactoryFinder();
}
}
// -------------------------------------------------------- Private Methods
// Called via reflection from automated tests.
@SuppressWarnings("unused")
private static void reInitializeFactoryManager() {
FACTORIES_CACHE.resetSpecialInitializationCaseFlags();
}
}