org.apache.myfaces.spi
Class FactoryFinderProviderFactory

java.lang.Object
  extended by org.apache.myfaces.spi.FactoryFinderProviderFactory

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:

  1. Create a class called FactoryFinderProvider, that has the same three method but in a non static version.
  2. A singleton component is provided that holds the information of the FactoryFinderProviderFactory. This one works per classloader, so the singleton is implemented using an static variable. To configure it, the static method should be called when the "classloader realm" is initialized, before any web context is started (the WAR is deployed). Usually the EAR is started as a single entity, so this should occur when the EAR starts, but before the WAR files are started (or the web context are created). The singleton will be responsible to decide which FactoryFinderProvider should be used, based on the current thread information.
  3. Add utility methods to retrieve the required objects and call the methods using reflection from javax.faces.FactoryFinder

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]).

Since:
2.0.5
Author:
Leonardo Uribe

Constructor Summary
FactoryFinderProviderFactory()
           
 
Method Summary
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.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

FactoryFinderProviderFactory

public FactoryFinderProviderFactory()
Method Detail

setInstance

public static void setInstance(FactoryFinderProviderFactory instance)
Set the instance to be used by 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"

Parameters:
instance -

getInstance

public static FactoryFinderProviderFactory getInstance()
Retrieve the installed instance of this class to be used by FactoryFinder. If no factory is set, return null

Returns:

getFactoryFinderProvider

public abstract FactoryFinderProvider getFactoryFinderProvider()
Provide the FactoryFinderProvider to be used to resolve factories. Subclasses must implement this method.

Returns:


Copyright © 2014 The Apache Software Foundation. All Rights Reserved.