Save This Page
Home » mojarra-1.2_09-b02-FCS-source » javax.faces » [javadoc | source]
    1   /*
    2    * $Id: FactoryFinder.java,v 1.37.4.1 2008/06/09 18:32:11 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>FactoryFinder</strong> implements the standard discovery
   74    * algorithm for all factory objects specified in the JavaServer Faces
   75    * APIs.  For a given factory class name, a corresponding implementation
   76    * class is searched for based on the following algorithm.  Items are
   77    * listed in order of decreasing search precedence:</p> <ul>
   78    * <p/>
   79    * <li>If the JavaServer Faces configuration file bundled into the
   80    * <code>WEB-INF</code> directory of the webapp contains a
   81    * <code>factory</code> entry of the given factory class name, that
   82    * factory is used.</li>
   83    * <p/>
   84    * <li>If the JavaServer Faces configuration files named by the
   85    * <code>javax.faces.CONFIG_FILES</code>
   86    * <code>ServletContext</code> init parameter contain any
   87    * <code>factory</code> entries of the given factory class name, those
   88    * factories are used, with the last one taking precedence.</li>
   89    * <p/>
   90    * <li>If there are any JavaServer Faces configuration files bundled
   91    * into the <code>META-INF</code> directory of any jars on the
   92    * <code>ServletContext</code>'s resource paths, the
   93    * <code>factory</code> entries of the given factory class name in those
   94    * files are used, with the last one taking precedence.</li>
   95    * <p/>
   96    * <li>If a <code>META-INF/services/{factory-class-name}</code> resource
   97    * is visible to the web application class loader for the calling
   98    * application (typically as a result of being present in the manifest
   99    * of a JAR file), its first line is read and assumed to be the name of
  100    * the factory implementation class to use.</li>
  101    * <p/>
  102    * <li>If none of the above steps yield a match, the JavaServer Faces
  103    * implementation specific class is used.</li>
  104    * <p/>
  105    * </ul>
  106    * <p/>
  107    * <p>If any of the factories found on any of the steps above happen to
  108    * have a one-argument constructor, with argument the type being the
  109    * abstract factory class, that constructor is invoked, and the previous
  110    * match is passed to the constructor.  For example, say the container
  111    * vendor provided an implementation of {@link
  112    * javax.faces.context.FacesContextFactory}, and identified it in
  113    * <code>META-INF/services/javax.faces.context.FacesContextFactory</code>
  114    * in a jar on the webapp ClassLoader.  Also say this implementation
  115    * provided by the container vendor had a one argument constructor that
  116    * took a <code>FacesContextFactory</code> instance.  The
  117    * <code>FactoryFinder</code> system would call that one-argument
  118    * constructor, passing the implementation of
  119    * <code>FacesContextFactory</code> provided by the JavaServer Faces
  120    * implementation.</p>
  121    * <p/>
  122    * <p>If a Factory implementation does not provide a proper one-argument
  123    * constructor, it must provide a zero-arguments constructor in order to
  124    * be successfully instantiated.</p>
  125    * <p/>
  126    * <p>Once the name of the factory implementation class is located, the
  127    * web application class loader for the calling application is requested
  128    * to load this class, and a corresponding instance of the class will be
  129    * created.  A side effect of this rule is that each web application will
  130    * receive its own instance of each factory class, whether the JavaServer
  131    * Faces implementation is included within the web application or is made
  132    * visible through the container's facilities for shared libraries.</p>
  133    */
  134   
  135   public final class FactoryFinder {
  136   
  137       // ----------------------------------------------------------- Constructors
  138   
  139   
  140       /**
  141        * Package-private constructor to disable instantiation of this class.
  142        */
  143       FactoryFinder() {
  144       }
  145   
  146       // ----------------------------------------------------- Manifest Constants
  147   
  148   
  149       /**
  150        * <p>The property name for the
  151        * {@link javax.faces.application.ApplicationFactory} class name.</p>
  152        */
  153       public final static String APPLICATION_FACTORY =
  154            "javax.faces.application.ApplicationFactory";
  155   
  156   
  157       /**
  158        * <p>The property name for the
  159        * {@link javax.faces.context.FacesContextFactory} class name.</p>
  160        */
  161       public final static String FACES_CONTEXT_FACTORY =
  162            "javax.faces.context.FacesContextFactory";
  163   
  164   
  165       /**
  166        * <p>The property name for the
  167        * {@link javax.faces.lifecycle.LifecycleFactory} class name.</p>
  168        */
  169       public final static String LIFECYCLE_FACTORY =
  170            "javax.faces.lifecycle.LifecycleFactory";
  171   
  172   
  173       /**
  174        * <p>The property name for the
  175        * {@link javax.faces.render.RenderKitFactory} class name.</p>
  176        */
  177       public final static String RENDER_KIT_FACTORY =
  178            "javax.faces.render.RenderKitFactory";
  179   
  180       // ------------------------------------------------------- Static Variables
  181   
  182       private static final FactoryManagerCache FACTORIES_CACHE =
  183             new FactoryManagerCache();
  184   
  185   
  186       /**
  187        * <p>The set of JavaServer Faces factory classes for which the factory
  188        * discovery mechanism is supported.</p>
  189        */
  190       private static final String[] FACTORY_NAMES = {
  191            APPLICATION_FACTORY,
  192            FACES_CONTEXT_FACTORY,
  193            LIFECYCLE_FACTORY,
  194            RENDER_KIT_FACTORY
  195       };
  196   
  197       /**
  198        * <p>Map of Class instances for the our factory names.</p>
  199        */
  200       private static Map<String, Class> factoryClasses = null;
  201   
  202       private static final Logger LOGGER =
  203            Logger.getLogger("javax.faces", "javax.faces.LogStrings");
  204   
  205       // --------------------------------------------------------- Public Methods
  206   
  207   
  208       /**
  209        * <p>Create (if necessary) and return a per-web-application instance of
  210        * the appropriate implementation class for the specified JavaServer Faces
  211        * factory class, based on the discovery algorithm described in the
  212        * class description.</p>
  213        *
  214        * @param factoryName Fully qualified name of the JavaServer Faces factory
  215        *                    for which an implementation instance is requested
  216        * @throws FacesException           if the web application class loader
  217        *                                  cannot be identified
  218        * @throws FacesException           if an instance of the configured factory
  219        *                                  implementation class cannot be loaded
  220        * @throws FacesException           if an instance of the configured factory
  221        *                                  implementation class cannot be instantiated
  222        * @throws IllegalArgumentException if <code>factoryName</code> does not
  223        *                                  identify a standard JavaServer Faces factory name
  224        * @throws IllegalStateException    if there is no configured factory
  225        *                                  implementation class for the specified factory name
  226        * @throws NullPointerException     if <code>factoryname</code>
  227        *                                  is null
  228        */
  229       public static Object getFactory(String factoryName)
  230            throws FacesException {
  231   
  232           validateFactoryName(factoryName);
  233   
  234           // Identify the web application class loader
  235           ClassLoader classLoader = getClassLoader();
  236   
  237           FactoryManager manager =
  238                 FACTORIES_CACHE.getApplicationFactoryManager(classLoader);
  239           return manager.getFactory(classLoader, factoryName);
  240   
  241       }
  242   
  243       /**
  244        * <p>This method will store the argument
  245        * <code>factoryName/implName</code> mapping in such a way that
  246        * {@link #getFactory} will find this mapping when searching for a
  247        * match.</p>
  248        * <p/>
  249        * <p>This method has no effect if <code>getFactory()</code> has
  250        * already been called looking for a factory for this
  251        * <code>factoryName</code>.</p>
  252        * <p/>
  253        * <p>This method can be used by implementations to store a factory
  254        * mapping while parsing the Faces configuration file</p>
  255        *
  256        * @throws IllegalArgumentException if <code>factoryName</code> does not
  257        *                                  identify a standard JavaServer Faces factory name
  258        * @throws NullPointerException     if <code>factoryname</code>
  259        *                                  is null
  260        */
  261       public static void setFactory(String factoryName,
  262                                     String implName) {
  263   
  264           validateFactoryName(factoryName);
  265   
  266           // Identify the web application class loader
  267           ClassLoader classLoader = getClassLoader();
  268   
  269           FactoryManager manager =
  270                 FACTORIES_CACHE.getApplicationFactoryManager(classLoader);
  271           manager.addFactory(factoryName, implName);
  272   
  273       }
  274   
  275   
  276       /**
  277        * <p>Release any references to factory instances associated with the
  278        * class loader for the calling web application.  This method should be
  279        * called as apart of web application shutdown in a container where the
  280        * JavaServer Faces API classes are part of the container itself, rather
  281        * than being included inside the web application.</p>
  282        *
  283        * @throws FacesException if the web application class loader
  284        *                        cannot be identified
  285        */
  286       public static void releaseFactories() throws FacesException {
  287   
  288           // Identify the web application class loader
  289           ClassLoader cl = getClassLoader();
  290   
  291           FACTORIES_CACHE.removeApplicationFactoryManager(cl);
  292   
  293       }
  294   
  295   
  296       // -------------------------------------------------------- Private Methods
  297   
  298   
  299       /**
  300        * <p>Identify and return the class loader that is associated with the
  301        * calling web application.</p>
  302        *
  303        * @throws FacesException if the web application class loader
  304        *                        cannot be identified
  305        */
  306       private static ClassLoader getClassLoader() throws FacesException {
  307   
  308           // J2EE 1.3 (and later) containers are required to make the
  309           // web application class loader visible through the context
  310           // class loader of the current thread.
  311           ClassLoader cl = Thread.currentThread().getContextClassLoader();
  312           if (cl == null) {
  313               throw new FacesException("getContextClassLoader");
  314           }
  315           return (cl);
  316   
  317       }
  318   
  319   
  320       /**
  321        * <p>Load and return an instance of the specified implementation
  322        * class using the following algorithm.</p>
  323        * <p/>
  324        * <ol>
  325        * <p/>
  326        * <li><p>If the argument <code>implementations</code> list has
  327        * more than one element, or exactly one element, interpret the
  328        * last element in the list to be the fully qualified class name of
  329        * a class implementing <code>factoryName</code>.  Instantiate that
  330        * class and save it for return.  If the
  331        * <code>implementations</code> list has only one element, skip
  332        * this step.</p></li>
  333        * <p/>
  334        * <li><p>Look for a resource called
  335        * <code>/META-INF/services/&lt;factoryName&gt;</code>.  If found,
  336        * interpret it as a properties file, and read out the first entry.
  337        * Interpret the first entry as a fully qualify class name of a
  338        * class that implements <code>factoryName</code>.  If we have an
  339        * instantiated factory from the previous step <em>and</em> the
  340        * implementing class has a one arg constructor of the type for
  341        * <code>factoryName</code>, instantiate it, passing the
  342        * instantiated factory from the previous step.  If there is no one
  343        * arg constructor, just instantiate the zero arg constructor.  Save
  344        * the newly instantiated factory for return, replacing the
  345        * instantiated factory from the previous step.</p></li>
  346        * <p/>
  347        * <li><p>Treat each remaining element in the
  348        * <code>implementations</code> list as a fully qualified class name
  349        * of a class implementing <code>factoryName</code>.  If the current
  350        * element has a one arg constructor of the type for
  351        * <code>factoryName</code>, instantiate it, passing the
  352        * instantiated factory from the previous or step iteration.  If
  353        * there is no one arg constructor, just instantiate the zero arg
  354        * constructor, replacing the instantiated factory from the previous
  355        * step or iteration.</p></li>
  356        * <p/>
  357        * <li><p>Return the saved factory</p></li>
  358        * <p/>
  359        * </ol>
  360        *
  361        * @param classLoader     Class loader for the web application that will
  362        *                        be loading the implementation class
  363        * @param implementations A List of implementations for a given
  364        *                        factory class.
  365        * @throws FacesException if the specified implementation class
  366        *                        cannot be loaded
  367        * @throws FacesException if an instance of the specified implementation
  368        *                        class cannot be instantiated
  369        */
  370       private static Object getImplementationInstance(ClassLoader classLoader,
  371                                                       String factoryName,
  372                                                       List implementations)
  373       throws FacesException {
  374   
  375           Object result = null;
  376           String curImplClass;
  377           int len;
  378   
  379           // step 1.
  380           if (null != implementations &&
  381                (1 < (len = implementations.size()) || 1 == len)) {
  382               curImplClass = (String) implementations.remove(len - 1);
  383               // since this is the hard coded implementation default,
  384               // there is no preceding implementation, so don't bother
  385               // with a non-zero-arg ctor.
  386               result = getImplGivenPreviousImpl(classLoader, factoryName,
  387                    curImplClass, null);
  388           }
  389   
  390           // step 2.
  391           List<String> fromServices = getImplNameFromServices(classLoader, factoryName);
  392           if (fromServices != null) {
  393               for (String name : fromServices) {
  394                   result = getImplGivenPreviousImpl(classLoader,
  395                                                     factoryName,
  396                                                     name,
  397                                                     result);
  398               }
  399           }        
  400   
  401           // step 3.
  402           if (null != implementations) {
  403               for (len = (implementations.size() - 1); 0 <= len; len--) {
  404                   curImplClass = (String) implementations.remove(len);
  405                   result = getImplGivenPreviousImpl(classLoader, factoryName,
  406                        curImplClass, result);
  407               }
  408           }
  409   
  410           return result;
  411   
  412       }
  413   
  414   
  415       /**
  416        * <p>Perform the logic to get the implementation class for the
  417        * second step of {@link FactoryFinder#getImplementationInstance(ClassLoader, String, java.util.List)}.</p>
  418        */
  419       private static List<String> getImplNameFromServices(ClassLoader classLoader,
  420                                                           String factoryName) {
  421   
  422           // Check for a services definition
  423           List<String> result = null;
  424           String resourceName = "META-INF/services/" + factoryName;
  425           InputStream stream;
  426           BufferedReader reader = null;
  427           try {
  428               Enumeration<URL> e = classLoader.getResources(resourceName);
  429               while (e.hasMoreElements()) {
  430                   URL url = e.nextElement();
  431                   URLConnection conn = url.openConnection();
  432                   conn.setUseCaches(false);
  433                   stream = conn.getInputStream();
  434                   if (stream != null) {
  435                       // Deal with systems whose native encoding is possibly
  436                       // different from the way that the services entry was created
  437                       try {
  438                           reader =
  439                                 new BufferedReader(new InputStreamReader(stream,
  440                                                                          "UTF-8"));
  441                           if (result == null) {
  442                               result = new ArrayList<String>(3);
  443                           }
  444                           result.add(reader.readLine());
  445                       } catch (UnsupportedEncodingException uee) {
  446                           reader =
  447                                 new BufferedReader(new InputStreamReader(stream));
  448                       } finally {
  449                           if (reader != null) {
  450                               reader.close();
  451                               reader = null;
  452                           }
  453                           if (stream != null) {
  454                               stream.close();
  455                               //noinspection UnusedAssignment
  456                               stream = null;
  457                           }
  458                       }
  459   
  460                   }
  461               }
  462           } catch (IOException e) {
  463               if (LOGGER.isLoggable(Level.SEVERE)) {
  464                   LOGGER.log(Level.SEVERE,
  465                              e.toString(),
  466                              e);
  467               }
  468           } catch (SecurityException e) {
  469               if (LOGGER.isLoggable(Level.SEVERE)) {
  470                   LOGGER.log(Level.SEVERE,
  471                              e.toString(),
  472                              e);
  473               }
  474           }
  475           return result;
  476   
  477       }
  478   
  479   
  480       /**
  481        * <p>Implement the decorator pattern for the factory
  482        * implementation.</p>
  483        * <p/>
  484        * <p>If <code>previousImpl</code> is non-<code>null</code> and the
  485        * class named by the argument <code>implName</code> has a one arg
  486        * contstructor of type <code>factoryName</code>, instantiate it,
  487        * passing previousImpl to the constructor.</p>
  488        * <p/>
  489        * <p>Otherwise, we just instantiate and return
  490        * <code>implName</code>.</p>
  491        *
  492        * @param classLoader  the ClassLoader from which to load the class
  493        * @param factoryName  the fully qualified class name of the factory.
  494        * @param implName     the fully qualified class name of a class that
  495        *                     implements the factory.
  496        * @param previousImpl if non-<code>null</code>, the factory
  497        *                     instance to be passed to the constructor of the new factory.
  498        */
  499       private static Object getImplGivenPreviousImpl(ClassLoader classLoader,
  500                                                      String factoryName,
  501                                                      String implName,
  502                                                      Object previousImpl) {
  503           Class clazz;
  504           Class factoryClass = null;
  505           Class[] getCtorArg;
  506           Object[] newInstanceArgs = new Object[1];
  507           Constructor ctor;
  508           Object result = null;
  509   
  510           // if we have a previousImpl and the appropriate one arg ctor.
  511           if ((null != previousImpl) &&
  512                (null != (factoryClass = getFactoryClass(factoryName)))) {
  513               try {
  514                   clazz = Class.forName(implName, false, classLoader);
  515                   getCtorArg = new Class[1];
  516                   getCtorArg[0] = factoryClass;
  517                   ctor = clazz.getConstructor(getCtorArg);
  518                   newInstanceArgs[0] = previousImpl;
  519                   result = ctor.newInstance(newInstanceArgs);
  520               }
  521               catch (NoSuchMethodException nsme) {
  522                   // fall through to "zero-arg-ctor" case
  523                   factoryClass = null;
  524               }
  525               catch (Exception e) {
  526                   throw new FacesException(implName, e);
  527               }
  528           }
  529           if (null == previousImpl || null == factoryClass) {
  530               // we have either no previousImpl or no appropriate one arg
  531               // ctor.
  532               try {
  533                   clazz = Class.forName(implName, false, classLoader);
  534                   // since this is the hard coded implementation default,
  535                   // there is no preceding implementation, so don't bother
  536                   // with a non-zero-arg ctor.
  537                   result = clazz.newInstance();
  538               } catch (Exception e) {
  539                   throw new FacesException(implName, e);
  540               }
  541           }
  542           return result;
  543   
  544       }
  545   
  546   
  547       /**
  548        * @return the <code>java.lang.Class</code> for the argument
  549        *         factory.
  550        */
  551       private static Class getFactoryClass(String factoryClassName) {
  552   
  553           if (null == factoryClasses) {
  554               factoryClasses = new HashMap<String, Class>(FACTORY_NAMES.length);
  555               factoryClasses.put(APPLICATION_FACTORY,
  556                    javax.faces.application.ApplicationFactory.class);
  557               factoryClasses.put(FACES_CONTEXT_FACTORY,
  558                    javax.faces.context.FacesContextFactory.class);
  559               factoryClasses.put(LIFECYCLE_FACTORY,
  560                    javax.faces.lifecycle.LifecycleFactory.class);
  561               factoryClasses.put(RENDER_KIT_FACTORY,
  562                    javax.faces.render.RenderKitFactory.class);
  563           }
  564           return factoryClasses.get(factoryClassName);
  565   
  566       }
  567   
  568   
  569       /**
  570        * Ensure the provided factory name is valid.
  571        */
  572       private static void validateFactoryName(String factoryName) {
  573   
  574           if (factoryName == null) {
  575               throw new NullPointerException();
  576           }
  577           if (Arrays.binarySearch(FACTORY_NAMES, factoryName) < 0) {
  578               throw new IllegalArgumentException(factoryName);
  579           }
  580   
  581       }
  582   
  583   
  584       // ----------------------------------------------------------- Inner Classes
  585   
  586   
  587       /**
  588        * Managed the mappings between a web application and its configured
  589        * factories.
  590        */
  591       private static final class FactoryManagerCache {
  592   
  593           private ConcurrentMap<ClassLoader,Future<FactoryManager>> applicationMap =
  594                 new ConcurrentHashMap<ClassLoader, Future<FactoryManager>>();
  595   
  596   
  597           // ------------------------------------------------------ Public Methods
  598   
  599   
  600           private FactoryManager getApplicationFactoryManager(ClassLoader cl) {
  601   
  602               while (true) {
  603                   Future<FactoryManager> factories = applicationMap.get(cl);
  604                   if (factories == null) {
  605                       Callable<FactoryManager> callable =
  606                             new Callable<FactoryManager>() {
  607                                 public FactoryManager call()
  608                                       throws Exception {
  609                                     return new FactoryManager();
  610                                 }
  611                             };
  612   
  613                       FutureTask<FactoryManager> ft =
  614                             new FutureTask<FactoryManager>(callable);
  615                       factories = applicationMap.putIfAbsent(cl, ft);
  616                       if (factories == null) {
  617                           factories = ft;
  618                           ft.run();
  619                       }
  620                   }
  621   
  622                   try {
  623                       return factories.get();
  624                   } catch (CancellationException ce) {
  625                       if (LOGGER.isLoggable(Level.FINEST)) {
  626                           LOGGER.log(Level.FINEST,
  627                                      ce.toString(),
  628                                      ce);
  629                       }
  630                       applicationMap.remove(cl);
  631                   } catch (InterruptedException ie) {
  632                       if (LOGGER.isLoggable(Level.FINEST)) {
  633                           LOGGER.log(Level.FINEST,
  634                                      ie.toString(),
  635                                      ie);
  636                       }
  637                       applicationMap.remove(cl);
  638                   } catch (ExecutionException ee) {
  639                       throw new FacesException(ee);
  640                   }
  641   
  642               }
  643   
  644           }
  645   
  646   
  647           public void removeApplicationFactoryManager(ClassLoader cl) {
  648   
  649               applicationMap.remove(cl);
  650   
  651           }
  652   
  653       } // END FactoryCache
  654   
  655   
  656       /**
  657        * Maintains the factories for a single web application.
  658        */
  659       private static final class FactoryManager {
  660   
  661           private final Map<String,Object> factories;
  662           private final ReentrantReadWriteLock lock;
  663   
  664   
  665           // -------------------------------------------------------- Consturctors
  666   
  667   
  668           public FactoryManager() {
  669               factories = new HashMap<String,Object>();
  670               for (String name : FACTORY_NAMES) {
  671                   factories.put(name, new ArrayList(4));
  672               }
  673               lock = new ReentrantReadWriteLock(true);
  674           }
  675   
  676   
  677           // ------------------------------------------------------ Public Methods
  678   
  679   
  680           public void addFactory(String factoryName, String implementation) {
  681   
  682               Object result = factories.get(factoryName);
  683               lock.writeLock().lock();
  684               try {
  685                   if (result instanceof List) {
  686                       TypedCollections.dynamicallyCastList((List) result, String.class).add(0, implementation);
  687                   }
  688               } finally {
  689                   lock.writeLock().unlock();
  690               }
  691           }
  692   
  693   
  694           public Object getFactory(ClassLoader cl, String factoryName) {
  695   
  696               Object factoryOrList;
  697               lock.readLock().lock();
  698               try {
  699                   factoryOrList = factories.get(factoryName);
  700                   if (!(factoryOrList instanceof List)) {
  701                       return factoryOrList;
  702                   }
  703               } finally {
  704                   lock.readLock().unlock();
  705               }
  706   
  707               // factory hasn't been constructed
  708               lock.writeLock().lock();
  709               try {
  710                   // double check the current value.  Another thread
  711                   // may have completed the initialization by the time
  712                   // this thread entered this block
  713                   factoryOrList = factories.get(factoryName);
  714                   if (!(factoryOrList instanceof List)) {
  715                       return factoryOrList;
  716                   }
  717                   Object factory = getImplementationInstance(cl,
  718                                                              factoryName,
  719                                                              (List) factoryOrList);
  720   
  721                   if (factory == null) {
  722                       ResourceBundle rb = LOGGER.getResourceBundle();
  723                       String message = rb.getString("severe.no_factory");
  724                       message = MessageFormat.format(message, factoryName);
  725                       throw new IllegalStateException(message);
  726                   }
  727   
  728                   // Record and return the new instance
  729                   factories.put(factoryName, factory);
  730                   return (factory);
  731               } finally {
  732                   lock.writeLock().unlock();
  733               }
  734           }
  735   
  736       } // END FactoryManager
  737   
  738   
  739   }

Save This Page
Home » mojarra-1.2_09-b02-FCS-source » javax.faces » [javadoc | source]