public abstract class FactoryFinderProviderFactory extends Object
FactoryFinder
is a class with three methods:
public final class FactoryFinder
{
public static Object getFactory(String factoryName) throws FacesException {...}
public static void setFactory(String factoryName, String implName) {...}
public static void releaseFactories() throws FacesException {...}
}
The javadoc describe the intention of FactoryFinder class:
"... FactoryFinder implements the standard discovery algorithm for all factory objects specified in the JavaServer Faces APIs. For a given factory class name, a corresponding implementation class is searched for based on the following algorithm...."
In few words, this class allows to find JSF factory classes. The necessary information to create factory instances is loaded on initialization time, but which locations contains such information (for more information see JSF 2.0 spec section 11.4.2) (here the only interest is in jsf factories initialization information) ?
Based on the previous facts, the first conclusion to take into account arise: Configuration information is gathered per "web context". What is a "web context"? In simple terms, is the "space" where a web application is deployed. Let's suppose an EAR file with two WAR files: a.war and b.war. Both contains different "web applications" and when are deployed has different "web context", so both can provide different factory configuration, because both has different WEB-INF/web.xml and WEB-INF/faces-config.xml files.
Now, given a request, how the web container identify a "web context"? At start, it receives the request information and based on that it decides which web application should process it. After that, it assign to a thread from is thread pool to be processed and the control is passed to the proper filters/servlets.
So, if there is not a servlet context/portlet context/whatever context, how to identify a "web context"? The answer is using the thread, but the one who knows how to do that is the web container, not the jsf implementation.
The existing problem is caused by a "shortcut" taken to make things easier. Instead use the current "thread", it is taken as advantage the fact that each web application deployed has a different classloader. That is true for a lot of application servers, so the current implementation of FactoryFinder is based on that fact too and has worked well since the beginning.
Now let's examine in detail how a "single classloader per EAR" option could work. If the EAR has two WAR files (a.war and b.war), we have two web context, and the initialization code is executed twice. When all FactoryFinder methods are called?
Remember all methods of FactoryFinder are static.
One possible solution could be:
This class implements the proposed solution. Note by definition, this factory cannot be configured using SPI standard algorithm (look for META-INF/services/[factory_class_name]).
Constructor and Description |
---|
FactoryFinderProviderFactory() |
Modifier and Type | Method and Description |
---|---|
abstract FactoryFinderProvider |
getFactoryFinderProvider()
Provide the FactoryFinderProvider to be used to resolve factories.
|
static FactoryFinderProviderFactory |
getInstance()
Retrieve the installed instance of this class to be used by
FactoryFinder . |
static void |
setInstance(FactoryFinderProviderFactory instance)
Set the instance to be used by
FactoryFinder to resolve
factories. |
public static void setInstance(FactoryFinderProviderFactory instance)
FactoryFinder
to resolve
factories.
This method should be called before any "web context" is initialized in the current "classloader context". For example, if a EAR file contains two WAR files, this method should be called before initialize any WAR, since each one requires a different "web context"
instance
- public static FactoryFinderProviderFactory getInstance()
FactoryFinder
. If no factory is set, return nullpublic abstract FactoryFinderProvider getFactoryFinderProvider()
Copyright © 2020 The Apache Software Foundation. All rights reserved.