Home » Mojarra-2.0.1 » javax » faces » [javadoc | source]

    1   /*
    2    * $Id: FactoryFinder.java,v 1.37 2007/05/21 21:23:29 rlubke Exp $
    3    */
    4   
    5   /*
    6    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    7    * 
    8    * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
    9    * 
   10    * The contents of this file are subject to the terms of either the GNU
   11    * General Public License Version 2 only ("GPL") or the Common Development
   12    * and Distribution License("CDDL") (collectively, the "License").  You
   13    * may not use this file except in compliance with the License. You can obtain
   14    * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
   15    * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
   16    * language governing permissions and limitations under the License.
   17    * 
   18    * When distributing the software, include this License Header Notice in each
   19    * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
   20    * Sun designates this particular file as subject to the "Classpath" exception
   21    * as provided by Sun in the GPL Version 2 section of the License file that
   22    * accompanied this code.  If applicable, add the following below the License
   23    * Header, with the fields enclosed by brackets [] replaced by your own
   24    * identifying information: "Portions Copyrighted [year]
   25    * [name of copyright owner]"
   26    * 
   27    * Contributor(s):
   28    * 
   29    * If you wish your version of this file to be governed by only the CDDL or
   30    * only the GPL Version 2, indicate your decision by adding "[Contributor]
   31    * elects to include this software in this distribution under the [CDDL or GPL
   32    * Version 2] license."  If you don't indicate a single choice of license, a
   33    * recipient has the option to distribute your version of this file under
   34    * either the CDDL, the GPL Version 2 or to extend the choice of license to
   35    * its licensees as provided above.  However, if you add GPL Version 2 code
   36    * and therefore, elected the GPL Version 2 license, then the option applies
   37    * only if the new code is made subject to such option by the copyright
   38    * holder.
   39    */
   40   
   41   package javax.faces;
   42   
   43   
   44   import java.io.BufferedReader;
   45   import java.io.InputStream;
   46   import java.io.InputStreamReader;
   47   import java.io.IOException;
   48   import java.io.UnsupportedEncodingException;
   49   import java.text.MessageFormat;
   50   import java.util.ArrayList;
   51   import java.util.HashMap;
   52   import java.util.List;
   53   import java.util.Map;
   54   import java.util.ResourceBundle;
   55   import java.util.Arrays;
   56   import java.util.Enumeration;
   57   import java.util.concurrent.ConcurrentMap;
   58   import java.util.concurrent.ConcurrentHashMap;
   59   import java.util.concurrent.Callable;
   60   import java.util.concurrent.FutureTask;
   61   import java.util.concurrent.Future;
   62   import java.util.concurrent.CancellationException;
   63   import java.util.concurrent.ExecutionException;
   64   import java.util.concurrent.locks.ReentrantReadWriteLock;
   65   import java.util.logging.Logger;
   66   import java.util.logging.Level;
   67   import java.lang.reflect.Constructor;
   68   import java.net.URL;
   69   import java.net.URLConnection;
   70   
   71   
   72   /**
   73    * <p><strong class="changed_modified_2_0">FactoryFinder</strong>
   74    * implements the standard discovery algorithm for all factory objects
   75    * specified in the JavaServer Faces APIs.  For a given factory class
   76    * name, a corresponding implementation class is searched for based on
   77    * the following algorithm.  Items are listed in order of decreasing
   78    * search precedence:</p> 
   79   
   80    * <ul> 
   81   
   82    * <li><p>If the JavaServer Faces configuration file bundled into the
   83    * <code>WEB-INF</code> directory of the webapp contains a
   84    * <code>factory</code> entry of the given factory class name, that
   85    * factory is used.<p></li>
   86   
   87    * <li><p>If the JavaServer Faces configuration files named by the
   88    * <code>javax.faces.CONFIG_FILES</code> <code>ServletContext</code> init
   89    * parameter contain any <code>factory</code> entries of the given
   90    * factory class name, those factories are used, with the last one taking
   91    * precedence.</p></li> 
   92   
   93    * <li><p>If there are any JavaServer Faces configuration files bundled
   94    * into the <code>META-INF</code> directory of any jars on the
   95    * <code>ServletContext</code>'s resource paths, the
   96    * <code>factory</code> entries of the given factory class name in those
   97    * files are used, with the last one taking precedence.</p></li>
   98   
   99    * <li><p>If a <code>META-INF/services/{factory-class-name}</code>
  100    * resource is visible to the web application class loader for the
  101    * calling application (typically as a result of being present in the
  102    * manifest of a JAR file), its first line is read and assumed to be the
  103    * name of the factory implementation class to use.</p></li>
  104   
  105    * <li><p>If none of the above steps yield a match, the JavaServer Faces
  106    * implementation specific class is used.</p></li>
  107   
  108    * </ul>
  109   
  110    * <p>If any of the factories found on any of the steps above happen to
  111    * have a one-argument constructor, with argument the type being the
  112    * abstract factory class, that constructor is invoked, and the previous
  113    * match is passed to the constructor.  For example, say the container
  114    * vendor provided an implementation of {@link
  115    * javax.faces.context.FacesContextFactory}, and identified it in
  116    * <code>META-INF/services/javax.faces.context.FacesContextFactory</code>
  117    * in a jar on the webapp ClassLoader.  Also say this implementation
  118    * provided by the container vendor had a one argument constructor that
  119    * took a <code>FacesContextFactory</code> instance.  The
  120    * <code>FactoryFinder</code> system would call that one-argument
  121    * constructor, passing the implementation of
  122    * <code>FacesContextFactory</code> provided by the JavaServer Faces
  123    * implementation.</p>
  124   
  125    * <p>If a Factory implementation does not provide a proper one-argument
  126    * constructor, it must provide a zero-arguments constructor in order to
  127    * be successfully instantiated.</p>
  128   
  129    * <p>Once the name of the factory implementation class is located, the
  130    * web application class loader for the calling application is requested
  131    * to load this class, and a corresponding instance of the class will be
  132    * created.  A side effect of this rule is that each web application
  133    * will receive its own instance of each factory class, whether the
  134    * JavaServer Faces implementation is included within the web
  135    * application or is made visible through the container's facilities for
  136    * shared libraries.</p>
  137    */
  138   
  139   public final class FactoryFinder {
  140   
  141       // ----------------------------------------------------------- Constructors
  142   
  143   
  144       /**
  145        * Package-private constructor to disable instantiation of this class.
  146        */
  147       FactoryFinder() {
  148       }
  149   
  150       // ----------------------------------------------------- Manifest Constants
  151   
  152   
  153       /**
  154        * <p>The property name for the
  155        * {@link javax.faces.application.ApplicationFactory} class name.</p>
  156        */
  157       public final static String APPLICATION_FACTORY =
  158            "javax.faces.application.ApplicationFactory";
  159   
  160       /**
  161        * <p class="changed_added_2_0">The property name for the {@link
  162        * javax.faces.context.ExceptionHandlerFactory} class name.</p>
  163        */
  164       public final static String EXCEPTION_HANDLER_FACTORY =
  165            "javax.faces.context.ExceptionHandlerFactory";
  166   
  167       /**
  168        * <p class="changed_added_2_0">The property name for the {@link
  169        * javax.faces.context.ExternalContextFactory} class name.</p>
  170        */
  171       public final static String EXTERNAL_CONTEXT_FACTORY =
  172            "javax.faces.context.ExternalContextFactory";
  173   
  174       /**
  175        * <p>The property name for the
  176        * {@link javax.faces.context.FacesContextFactory} class name.</p>
  177        */
  178       public final static String FACES_CONTEXT_FACTORY =
  179            "javax.faces.context.FacesContextFactory";
  180   
  181       /**
  182        * <p class="changed_added_2_0">The property name for the {@link
  183        * javax.faces.context.PartialViewContextFactory} class name.</p>
  184        */
  185       public final static String PARTIAL_VIEW_CONTEXT_FACTORY =
  186             "javax.faces.context.PartialViewContextFactory";
  187   
  188       /**
  189        * <p class="changed_added_2_0">The property name for the {@link
  190        * javax.faces.component.visit.VisitContextFactory} class name.</p>
  191        */
  192       public final static String VISIT_CONTEXT_FACTORY =
  193            "javax.faces.component.visit.VisitContextFactory";
  194   
  195       /**
  196        * <p>The property name for the
  197        * {@link javax.faces.lifecycle.LifecycleFactory} class name.</p>
  198        */
  199       public final static String LIFECYCLE_FACTORY =
  200            "javax.faces.lifecycle.LifecycleFactory";
  201   
  202       /**
  203        * <p>The property name for the
  204        * {@link javax.faces.render.RenderKitFactory} class name.</p>
  205        */
  206       public final static String RENDER_KIT_FACTORY =
  207            "javax.faces.render.RenderKitFactory";
  208   
  209       /**
  210        * <p class="changed_added_2_0">The property name for the {@link
  211        * javax.faces.view.ViewDeclarationLanguage} class name.</p>
  212        */
  213       public final static String VIEW_DECLARATION_LANGUAGE_FACTORY =
  214            "javax.faces.view.ViewDeclarationLanguageFactory";
  215   
  216       /**
  217        * <p class="changed_added_2_0">The property name for the {@link
  218        * javax.faces.view.facelets.TagHandlerDelegate} class name.</p>
  219        */
  220       public final static String TAG_HANDLER_DELEGATE_FACTORY =
  221            "javax.faces.view.facelets.TagHandlerDelegateFactory";
  222   
  223       // ------------------------------------------------------- Static Variables
  224   
  225       private static final FactoryManagerCache FACTORIES_CACHE =
  226             new FactoryManagerCache();
  227   
  228   
  229       /**
  230        * <p>The set of JavaServer Faces factory classes for which the factory
  231        * discovery mechanism is supported.  The entries in this list must be 
  232        * alphabetically ordered according to the entire string, not just
  233        * the last part!</p>
  234        */
  235       private static final String[] FACTORY_NAMES = {
  236            APPLICATION_FACTORY,
  237            VISIT_CONTEXT_FACTORY,
  238            EXCEPTION_HANDLER_FACTORY,
  239            EXTERNAL_CONTEXT_FACTORY,
  240            FACES_CONTEXT_FACTORY,
  241            LIFECYCLE_FACTORY,
  242            VIEW_DECLARATION_LANGUAGE_FACTORY,
  243            PARTIAL_VIEW_CONTEXT_FACTORY,
  244            RENDER_KIT_FACTORY,
  245            TAG_HANDLER_DELEGATE_FACTORY
  246       
  247       };
  248   
  249       /**
  250        * <p>Map of Class instances for the our factory names.</p>
  251        */
  252       private static Map<String, Class> factoryClasses = null;
  253   
  254       private static final Logger LOGGER =
  255            Logger.getLogger("javax.faces", "javax.faces.LogStrings");
  256   
  257       // Ensure the factory names are sorted.
  258       //
  259       static {
  260           Arrays.sort(FACTORY_NAMES);
  261       }
  262   
  263   
  264       // --------------------------------------------------------- Public Methods
  265   
  266   
  267       /**
  268        * <p><span class="changed_modified_2_0">Create</span> (if
  269        * necessary) and return a per-web-application instance of the
  270        * appropriate implementation class for the specified JavaServer
  271        * Faces factory class, based on the discovery algorithm described
  272        * in the class description.</p>
  273        *
  274        * <p class="changed_added_2_0">The standard factories and wrappers
  275        * in JSF all implement the interface {@link FacesWrapper}.  If the
  276        * returned <code>Object</code> is an implementation of one of the
  277        * standard factories, it must be legal to cast it to an instance of
  278        * <code>FacesWrapper</code> and call {@link
  279        * FacesWrapper#getWrapped} on the instance.</p>
  280        *
  281        * @param factoryName Fully qualified name of the JavaServer Faces factory
  282        *                    for which an implementation instance is requested
  283        * @throws FacesException           if the web application class loader
  284        *                                  cannot be identified
  285        * @throws FacesException           if an instance of the configured factory
  286        *                                  implementation class cannot be loaded
  287        * @throws FacesException           if an instance of the configured factory
  288        *                                  implementation class cannot be instantiated
  289        * @throws IllegalArgumentException if <code>factoryName</code> does not
  290        *                                  identify a standard JavaServer Faces factory name
  291        * @throws IllegalStateException    if there is no configured factory
  292        *                                  implementation class for the specified factory name
  293        * @throws NullPointerException     if <code>factoryname</code>
  294        *                                  is null
  295        */
  296       public static Object getFactory(String factoryName)
  297            throws FacesException {
  298   
  299           validateFactoryName(factoryName);
  300   
  301           // Identify the web application class loader
  302           ClassLoader classLoader = getClassLoader();
  303   
  304           FactoryManager manager =
  305                 FACTORIES_CACHE.getApplicationFactoryManager(classLoader);
  306           return manager.getFactory(classLoader, factoryName);
  307   
  308       }
  309   
  310       /**
  311        * <p>This method will store the argument
  312        * <code>factoryName/implName</code> mapping in such a way that
  313        * {@link #getFactory} will find this mapping when searching for a
  314        * match.</p>
  315        * <p/>
  316        * <p>This method has no effect if <code>getFactory()</code> has
  317        * already been called looking for a factory for this
  318        * <code>factoryName</code>.</p>
  319        * <p/>
  320        * <p>This method can be used by implementations to store a factory
  321        * mapping while parsing the Faces configuration file</p>
  322        *
  323        * @throws IllegalArgumentException if <code>factoryName</code> does not
  324        *                                  identify a standard JavaServer Faces factory name
  325        * @throws NullPointerException     if <code>factoryname</code>
  326        *                                  is null
  327        */
  328       public static void setFactory(String factoryName,
  329                                     String implName) {
  330   
  331           validateFactoryName(factoryName);
  332   
  333           // Identify the web application class loader
  334           ClassLoader classLoader = getClassLoader();
  335   
  336           FactoryManager manager =
  337                 FACTORIES_CACHE.getApplicationFactoryManager(classLoader);
  338           manager.addFactory(factoryName, implName);
  339   
  340       }
  341   
  342   
  343       /**
  344        * <p><span class="changed_modified_2_0">Release</span> any
  345        * references to factory instances associated with the class loader
  346        * for the calling web application.  <span
  347        * class="changed_modified_2_0">This method must be called during of
  348        * web application shutdown.</span></p>
  349        *
  350        * @throws FacesException if the web application class loader
  351        *                        cannot be identified
  352        */
  353       public static void releaseFactories() throws FacesException {
  354   
  355           // Identify the web application class loader
  356           ClassLoader cl = getClassLoader();
  357   
  358           FACTORIES_CACHE.removeApplicationFactoryManager(cl);
  359   
  360       }
  361   
  362   
  363       // -------------------------------------------------------- Private Methods
  364   
  365   
  366       /**
  367        * <p>Identify and return the class loader that is associated with the
  368        * calling web application.</p>
  369        *
  370        * @throws FacesException if the web application class loader
  371        *                        cannot be identified
  372        */
  373       private static ClassLoader getClassLoader() throws FacesException {
  374   
  375           // J2EE 1.3 (and later) containers are required to make the
  376           // web application class loader visible through the context
  377           // class loader of the current thread.
  378           ClassLoader cl = Thread.currentThread().getContextClassLoader();
  379           if (cl == null) {
  380               throw new FacesException("getContextClassLoader");
  381           }
  382           return (cl);
  383   
  384       }
  385   
  386   
  387       /**
  388        * <p>Load and return an instance of the specified implementation
  389        * class using the following algorithm.</p>
  390        * <p/>
  391        * <ol>
  392        * <p/>
  393        * <li><p>If the argument <code>implementations</code> list has
  394        * more than one element, or exactly one element, interpret the
  395        * last element in the list to be the fully qualified class name of
  396        * a class implementing <code>factoryName</code>.  Instantiate that
  397        * class and save it for return.  If the
  398        * <code>implementations</code> list has only one element, skip
  399        * this step.</p></li>
  400        * <p/>
  401        * <li><p>Look for a resource called
  402        * <code>/META-INF/services/&lt;factoryName&gt;</code>.  If found,
  403        * interpret it as a properties file, and read out the first entry.
  404        * Interpret the first entry as a fully qualify class name of a
  405        * class that implements <code>factoryName</code>.  If we have an
  406        * instantiated factory from the previous step <em>and</em> the
  407        * implementing class has a one arg constructor of the type for
  408        * <code>factoryName</code>, instantiate it, passing the
  409        * instantiated factory from the previous step.  If there is no one
  410        * arg constructor, just instantiate the zero arg constructor.  Save
  411        * the newly instantiated factory for return, replacing the
  412        * instantiated factory from the previous step.</p></li>
  413        * <p/>
  414        * <li><p>Treat each remaining element in the
  415        * <code>implementations</code> list as a fully qualified class name
  416        * of a class implementing <code>factoryName</code>.  If the current
  417        * element has a one arg constructor of the type for
  418        * <code>factoryName</code>, instantiate it, passing the
  419        * instantiated factory from the previous or step iteration.  If
  420        * there is no one arg constructor, just instantiate the zero arg
  421        * constructor, replacing the instantiated factory from the previous
  422        * step or iteration.</p></li>
  423        * <p/>
  424        * <li><p>Return the saved factory</p></li>
  425        * <p/>
  426        * </ol>
  427        *
  428        * @param classLoader     Class loader for the web application that will
  429        *                        be loading the implementation class
  430        * @param implementations A List of implementations for a given
  431        *                        factory class.
  432        * @throws FacesException if the specified implementation class
  433        *                        cannot be loaded
  434        * @throws FacesException if an instance of the specified implementation
  435        *                        class cannot be instantiated
  436        */
  437       private static Object getImplementationInstance(ClassLoader classLoader,
  438                                                       String factoryName,
  439                                                       List implementations)
  440       throws FacesException {
  441   
  442           Object result = null;
  443           String curImplClass;
  444           int len;
  445   
  446           // step 1.
  447           if (null != implementations &&
  448                (1 < (len = implementations.size()) || 1 == len)) {
  449               curImplClass = (String) implementations.remove(len - 1);
  450               // since this is the hard coded implementation default,
  451               // there is no preceding implementation, so don't bother
  452               // with a non-zero-arg ctor.
  453               result = getImplGivenPreviousImpl(classLoader, factoryName,
  454                    curImplClass, null);
  455           }
  456   
  457           // step 2.
  458           List<String> fromServices = getImplNameFromServices(classLoader, factoryName);
  459           if (fromServices != null) {
  460               for (String name : fromServices) {
  461                   result = getImplGivenPreviousImpl(classLoader,
  462                                                     factoryName,
  463                                                     name,
  464                                                     result);
  465               }
  466           }        
  467   
  468           // step 3.
  469           if (null != implementations) {
  470               for (len = (implementations.size() - 1); 0 <= len; len--) {
  471                   curImplClass = (String) implementations.remove(len);
  472                   result = getImplGivenPreviousImpl(classLoader, factoryName,
  473                        curImplClass, result);
  474               }
  475           }
  476   
  477           return result;
  478   
  479       }
  480   
  481   
  482       /**
  483        * <p>Perform the logic to get the implementation class for the
  484        * second step of {@link FactoryFinder#getImplementationInstance(ClassLoader, String, java.util.List)}.</p>
  485        */
  486       private static List<String> getImplNameFromServices(ClassLoader classLoader,
  487                                                           String factoryName) {
  488   
  489           // Check for a services definition
  490           List<String> result = null;
  491           String resourceName = "META-INF/services/" + factoryName;
  492           InputStream stream;
  493           BufferedReader reader = null;
  494           try {
  495               Enumeration<URL> e = classLoader.getResources(resourceName);
  496               while (e.hasMoreElements()) {
  497                   URL url = e.nextElement();
  498                   URLConnection conn = url.openConnection();
  499                   conn.setUseCaches(false);
  500                   stream = conn.getInputStream();
  501                   if (stream != null) {
  502                       // Deal with systems whose native encoding is possibly
  503                       // different from the way that the services entry was created
  504                       try {
  505                           reader =
  506                                 new BufferedReader(new InputStreamReader(stream,
  507                                                                          "UTF-8"));
  508                           if (result == null) {
  509                               result = new ArrayList<String>(3);
  510                           }
  511                           result.add(reader.readLine());
  512                       } catch (UnsupportedEncodingException uee) {
  513                           reader =
  514                                 new BufferedReader(new InputStreamReader(stream));
  515                       } finally {
  516                           if (reader != null) {
  517                               reader.close();
  518                               reader = null;
  519                           }
  520                           if (stream != null) {
  521                               stream.close();
  522                               //noinspection UnusedAssignment
  523                               stream = null;
  524                           }
  525                       }
  526   
  527                   }
  528               }
  529           } catch (IOException e) {
  530               if (LOGGER.isLoggable(Level.SEVERE)) {
  531                   LOGGER.log(Level.SEVERE,
  532                              e.toString(),
  533                              e);
  534               }
  535           } catch (SecurityException e) {
  536               if (LOGGER.isLoggable(Level.SEVERE)) {
  537                   LOGGER.log(Level.SEVERE,
  538                              e.toString(),
  539                              e);
  540               }
  541           }
  542           return result;
  543   
  544       }
  545   
  546   
  547       /**
  548        * <p>Implement the decorator pattern for the factory
  549        * implementation.</p>
  550        * <p/>
  551        * <p>If <code>previousImpl</code> is non-<code>null</code> and the
  552        * class named by the argument <code>implName</code> has a one arg
  553        * contstructor of type <code>factoryName</code>, instantiate it,
  554        * passing previousImpl to the constructor.</p>
  555        * <p/>
  556        * <p>Otherwise, we just instantiate and return
  557        * <code>implName</code>.</p>
  558        *
  559        * @param classLoader  the ClassLoader from which to load the class
  560        * @param factoryName  the fully qualified class name of the factory.
  561        * @param implName     the fully qualified class name of a class that
  562        *                     implements the factory.
  563        * @param previousImpl if non-<code>null</code>, the factory
  564        *                     instance to be passed to the constructor of the new factory.
  565        */
  566       private static Object getImplGivenPreviousImpl(ClassLoader classLoader,
  567                                                      String factoryName,
  568                                                      String implName,
  569                                                      Object previousImpl) {
  570           Class clazz;
  571           Class factoryClass = null;
  572           Class[] getCtorArg;
  573           Object[] newInstanceArgs = new Object[1];
  574           Constructor ctor;
  575           Object result = null;
  576   
  577           // if we have a previousImpl and the appropriate one arg ctor.
  578           if ((null != previousImpl) &&
  579                (null != (factoryClass = getFactoryClass(factoryName)))) {
  580               try {
  581                   clazz = Class.forName(implName, false, classLoader);
  582                   getCtorArg = new Class[1];
  583                   getCtorArg[0] = factoryClass;
  584                   ctor = clazz.getConstructor(getCtorArg);
  585                   newInstanceArgs[0] = previousImpl;
  586                   result = ctor.newInstance(newInstanceArgs);
  587               }
  588               catch (NoSuchMethodException nsme) {
  589                   // fall through to "zero-arg-ctor" case
  590                   factoryClass = null;
  591               }
  592               catch (Exception e) {
  593                   throw new FacesException(implName, e);
  594               }
  595           }
  596           if (null == previousImpl || null == factoryClass) {
  597               // we have either no previousImpl or no appropriate one arg
  598               // ctor.
  599               try {
  600                   clazz = Class.forName(implName, false, classLoader);
  601                   // since this is the hard coded implementation default,
  602                   // there is no preceding implementation, so don't bother
  603                   // with a non-zero-arg ctor.
  604                   result = clazz.newInstance();
  605               } catch (Exception e) {
  606                   throw new FacesException(implName, e);
  607               }
  608           }
  609           return result;
  610   
  611       }
  612   
  613   
  614       /**
  615        * @return the <code>java.lang.Class</code> for the argument
  616        *         factory.
  617        */
  618       private static Class getFactoryClass(String factoryClassName) {
  619   
  620           if (null == factoryClasses) {
  621               factoryClasses = new HashMap<String, Class>(FACTORY_NAMES.length);
  622               factoryClasses.put(APPLICATION_FACTORY,
  623                    javax.faces.application.ApplicationFactory.class);
  624               factoryClasses.put(EXCEPTION_HANDLER_FACTORY,
  625                    javax.faces.context.ExceptionHandlerFactory.class);
  626               factoryClasses.put(EXTERNAL_CONTEXT_FACTORY,
  627                    javax.faces.context.ExternalContextFactory.class);
  628               factoryClasses.put(FACES_CONTEXT_FACTORY,
  629                    javax.faces.context.FacesContextFactory.class);
  630               factoryClasses.put(VISIT_CONTEXT_FACTORY,
  631                    javax.faces.component.visit.VisitContextFactory.class);
  632               factoryClasses.put(LIFECYCLE_FACTORY,
  633                    javax.faces.lifecycle.LifecycleFactory.class);
  634               factoryClasses.put(PARTIAL_VIEW_CONTEXT_FACTORY,
  635                    javax.faces.context.PartialViewContextFactory.class);
  636               factoryClasses.put(RENDER_KIT_FACTORY,
  637                    javax.faces.render.RenderKitFactory.class);
  638               factoryClasses.put(VIEW_DECLARATION_LANGUAGE_FACTORY,
  639                    javax.faces.view.ViewDeclarationLanguageFactory.class);
  640               factoryClasses.put(TAG_HANDLER_DELEGATE_FACTORY,
  641                    javax.faces.view.facelets.TagHandlerDelegateFactory.class);
  642           }
  643           return factoryClasses.get(factoryClassName);
  644   
  645       }
  646   
  647   
  648       /**
  649        * Ensure the provided factory name is valid.
  650        */
  651       private static void validateFactoryName(String factoryName) {
  652   
  653           if (factoryName == null) {
  654               throw new NullPointerException();
  655           }
  656           if (Arrays.binarySearch(FACTORY_NAMES, factoryName) < 0) {
  657               throw new IllegalArgumentException(factoryName);
  658           }
  659   
  660       }
  661   
  662   
  663       // ----------------------------------------------------------- Inner Classes
  664   
  665   
  666       /**
  667        * Managed the mappings between a web application and its configured
  668        * factories.
  669        */
  670       private static final class FactoryManagerCache {
  671   
  672           private ConcurrentMap<ClassLoader,Future<FactoryManager>> applicationMap =
  673                 new ConcurrentHashMap<ClassLoader, Future<FactoryManager>>();
  674   
  675   
  676           // ------------------------------------------------------ Public Methods
  677   
  678   
  679           private FactoryManager getApplicationFactoryManager(ClassLoader cl) {
  680   
  681               while (true) {
  682                   Future<FactoryManager> factories = applicationMap.get(cl);
  683                   if (factories == null) {
  684                       Callable<FactoryManager> callable =
  685                             new Callable<FactoryManager>() {
  686                                 public FactoryManager call()
  687                                       throws Exception {
  688                                     return new FactoryManager();
  689                                 }
  690                             };
  691   
  692                       FutureTask<FactoryManager> ft =
  693                             new FutureTask<FactoryManager>(callable);
  694                       factories = applicationMap.putIfAbsent(cl, ft);
  695                       if (factories == null) {
  696                           factories = ft;
  697                           ft.run();
  698                       }
  699                   }
  700   
  701                   try {
  702                       return factories.get();
  703                   } catch (CancellationException ce) {
  704                       if (LOGGER.isLoggable(Level.FINEST)) {
  705                           LOGGER.log(Level.FINEST,
  706                                      ce.toString(),
  707                                      ce);
  708                       }
  709                       applicationMap.remove(cl);
  710                   } catch (InterruptedException ie) {
  711                       if (LOGGER.isLoggable(Level.FINEST)) {
  712                           LOGGER.log(Level.FINEST,
  713                                      ie.toString(),
  714                                      ie);
  715                       }
  716                       applicationMap.remove(cl);
  717                   } catch (ExecutionException ee) {
  718                       throw new FacesException(ee);
  719                   }
  720   
  721               }
  722   
  723           }
  724   
  725   
  726           public void removeApplicationFactoryManager(ClassLoader cl) {
  727   
  728               applicationMap.remove(cl);
  729   
  730           }
  731   
  732       } // END FactoryCache
  733   
  734   
  735       /**
  736        * Maintains the factories for a single web application.
  737        */
  738       private static final class FactoryManager {
  739   
  740           private final Map<String,Object> factories;
  741           private final ReentrantReadWriteLock lock;
  742   
  743   
  744           // -------------------------------------------------------- Consturctors
  745   
  746   
  747           public FactoryManager() {
  748               factories = new HashMap<String,Object>();
  749               for (String name : FACTORY_NAMES) {
  750                   factories.put(name, new ArrayList(4));
  751               }
  752               lock = new ReentrantReadWriteLock(true);
  753           }
  754   
  755   
  756           // ------------------------------------------------------ Public Methods
  757   
  758   
  759           public void addFactory(String factoryName, String implementation) {
  760   
  761               Object result = factories.get(factoryName);
  762               lock.writeLock().lock();
  763               try {
  764                   if (result instanceof List) {
  765                       TypedCollections.dynamicallyCastList((List) result, String.class).add(0, implementation);
  766                   }
  767               } finally {
  768                   lock.writeLock().unlock();
  769               }
  770           }
  771   
  772   
  773           public Object getFactory(ClassLoader cl, String factoryName) {
  774   
  775               Object factoryOrList;
  776               lock.readLock().lock();
  777               try {
  778                   factoryOrList = factories.get(factoryName);
  779                   if (!(factoryOrList instanceof List)) {
  780                       return factoryOrList;
  781                   }
  782               } finally {
  783                   lock.readLock().unlock();
  784               }
  785   
  786               // factory hasn't been constructed
  787               lock.writeLock().lock();
  788               try {
  789                   // double check the current value.  Another thread
  790                   // may have completed the initialization by the time
  791                   // this thread entered this block
  792                   factoryOrList = factories.get(factoryName);
  793                   if (!(factoryOrList instanceof List)) {
  794                       return factoryOrList;
  795                   }
  796                   Object factory = getImplementationInstance(cl,
  797                                                              factoryName,
  798                                                              (List) factoryOrList);
  799   
  800                   if (factory == null) {
  801                       ResourceBundle rb = LOGGER.getResourceBundle();
  802                       String message = rb.getString("severe.no_factory");
  803                       message = MessageFormat.format(message, factoryName);
  804                       throw new IllegalStateException(message);
  805                   }
  806   
  807                   // Record and return the new instance
  808                   factories.put(factoryName, factory);
  809                   return (factory);
  810               } finally {
  811                   lock.writeLock().unlock();
  812               }
  813           }
  814   
  815       } // END FactoryManager
  816   
  817   
  818   }

Home » Mojarra-2.0.1 » javax » faces » [javadoc | source]