View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package javax.faces;
20  
21  import javax.faces.application.ApplicationFactory;
22  import javax.faces.component.visit.VisitContextFactory;
23  import javax.faces.context.ExceptionHandlerFactory;
24  import javax.faces.context.ExternalContextFactory;
25  import javax.faces.context.FacesContext;
26  import javax.faces.context.FacesContextFactory;
27  import javax.faces.context.FlashFactory;
28  import javax.faces.context.PartialViewContextFactory;
29  import javax.faces.flow.FlowHandlerFactory;
30  import javax.faces.lifecycle.ClientWindowFactory;
31  import javax.faces.lifecycle.LifecycleFactory;
32  import javax.faces.render.RenderKitFactory;
33  import javax.faces.view.ViewDeclarationLanguageFactory;
34  import javax.faces.view.facelets.FaceletCacheFactory;
35  import javax.faces.view.facelets.TagHandlerDelegateFactory;
36  import java.lang.reflect.Constructor;
37  import java.lang.reflect.InvocationTargetException;
38  import java.lang.reflect.Method;
39  import java.security.AccessController;
40  import java.util.ArrayList;
41  import java.util.HashMap;
42  import java.util.HashSet;
43  import java.util.Iterator;
44  import java.util.List;
45  import java.util.Map;
46  import java.util.Set;
47  import java.util.concurrent.CopyOnWriteArrayList;
48  import java.util.logging.Level;
49  import java.util.logging.Logger;
50  import javax.faces.component.search.SearchExpressionContextFactory;
51  
52  /**
53   * see Javadoc of <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>
54   */
55  public final class FactoryFinder
56  {
57      public static final String APPLICATION_FACTORY = "javax.faces.application.ApplicationFactory";
58      public static final String EXCEPTION_HANDLER_FACTORY = "javax.faces.context.ExceptionHandlerFactory";
59      public static final String EXTERNAL_CONTEXT_FACTORY = "javax.faces.context.ExternalContextFactory";
60      public static final String FACES_CONTEXT_FACTORY = "javax.faces.context.FacesContextFactory";
61      public static final String LIFECYCLE_FACTORY = "javax.faces.lifecycle.LifecycleFactory";
62      public static final String PARTIAL_VIEW_CONTEXT_FACTORY = "javax.faces.context.PartialViewContextFactory";
63      public static final String RENDER_KIT_FACTORY = "javax.faces.render.RenderKitFactory";
64      public static final String TAG_HANDLER_DELEGATE_FACTORY = "javax.faces.view.facelets.TagHandlerDelegateFactory";
65      public static final String VIEW_DECLARATION_LANGUAGE_FACTORY = "javax.faces.view.ViewDeclarationLanguageFactory";
66      public static final String VISIT_CONTEXT_FACTORY = "javax.faces.component.visit.VisitContextFactory";
67      public static final String FACELET_CACHE_FACTORY = "javax.faces.view.facelets.FaceletCacheFactory";
68      public static final String FLASH_FACTORY = "javax.faces.context.FlashFactory";
69      public static final String FLOW_HANDLER_FACTORY = "javax.faces.flow.FlowHandlerFactory";
70      public static final String CLIENT_WINDOW_FACTORY = "javax.faces.lifecycle.ClientWindowFactory";
71      public static final String SEARCH_EXPRESSION_CONTEXT_FACTORY = 
72              "javax.faces.component.search.SearchExpressionContextFactory";
73  
74      /**
75       * used as a monitor for itself and _factories. Maps in this map are used as monitors for themselves and the
76       * corresponding maps in _factories.
77       */
78      private static Map<ClassLoader, Map<String, List<String>>> registeredFactoryNames
79              = new HashMap<ClassLoader, Map<String, List<String>>>();
80  
81      /**
82       * Maps from classLoader to another map, the container (i.e. Tomcat) will create a class loader for each web app
83       * that it controls (typically anyway) and that class loader is used as the key.
84       * 
85       * The secondary map maps the factory name (i.e. FactoryFinder.APPLICATION_FACTORY) to actual instances that are
86       * created via getFactory. The instances will be of the class specified in the setFactory method for the factory
87       * name, i.e. FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY, MyFactory.class).
88       */
89      private static Map<ClassLoader, Map<String, Object>> factories
90              = new HashMap<ClassLoader, Map<String, Object>>();
91  
92      private static final Set<String> VALID_FACTORY_NAMES = new HashSet<String>();
93      private static final Map<String, Class<?>> ABSTRACT_FACTORY_CLASSES = new HashMap<String, Class<?>>();
94      private static final ClassLoader MYFACES_CLASSLOADER;
95      
96      private static final String INJECTION_PROVIDER_INSTANCE = "oam.spi.INJECTION_PROVIDER_KEY";
97      private static final String INJECTED_BEAN_STORAGE_KEY = "org.apache.myfaces.spi.BEAN_ENTRY_STORAGE";
98      private static final String BEAN_ENTRY_CLASS_NAME = "org.apache.myfaces.cdi.util.BeanEntry";
99  
100     private static final Logger LOGGER = Logger.getLogger(FactoryFinder.class.getName());
101 
102     static
103     {
104         VALID_FACTORY_NAMES.add(APPLICATION_FACTORY);
105         VALID_FACTORY_NAMES.add(EXCEPTION_HANDLER_FACTORY);
106         VALID_FACTORY_NAMES.add(EXTERNAL_CONTEXT_FACTORY);
107         VALID_FACTORY_NAMES.add(FACES_CONTEXT_FACTORY);
108         VALID_FACTORY_NAMES.add(LIFECYCLE_FACTORY);
109         VALID_FACTORY_NAMES.add(PARTIAL_VIEW_CONTEXT_FACTORY);
110         VALID_FACTORY_NAMES.add(RENDER_KIT_FACTORY);
111         VALID_FACTORY_NAMES.add(TAG_HANDLER_DELEGATE_FACTORY);
112         VALID_FACTORY_NAMES.add(VIEW_DECLARATION_LANGUAGE_FACTORY);
113         VALID_FACTORY_NAMES.add(VISIT_CONTEXT_FACTORY);
114         VALID_FACTORY_NAMES.add(FACELET_CACHE_FACTORY);
115         VALID_FACTORY_NAMES.add(FLASH_FACTORY);
116         VALID_FACTORY_NAMES.add(FLOW_HANDLER_FACTORY);
117         VALID_FACTORY_NAMES.add(CLIENT_WINDOW_FACTORY);
118         VALID_FACTORY_NAMES.add(SEARCH_EXPRESSION_CONTEXT_FACTORY);
119         
120         ABSTRACT_FACTORY_CLASSES.put(APPLICATION_FACTORY, ApplicationFactory.class);
121         ABSTRACT_FACTORY_CLASSES.put(EXCEPTION_HANDLER_FACTORY, ExceptionHandlerFactory.class);
122         ABSTRACT_FACTORY_CLASSES.put(EXTERNAL_CONTEXT_FACTORY, ExternalContextFactory.class);
123         ABSTRACT_FACTORY_CLASSES.put(FACES_CONTEXT_FACTORY, FacesContextFactory.class);
124         ABSTRACT_FACTORY_CLASSES.put(LIFECYCLE_FACTORY, LifecycleFactory.class);
125         ABSTRACT_FACTORY_CLASSES.put(PARTIAL_VIEW_CONTEXT_FACTORY, PartialViewContextFactory.class);
126         ABSTRACT_FACTORY_CLASSES.put(RENDER_KIT_FACTORY, RenderKitFactory.class);
127         ABSTRACT_FACTORY_CLASSES.put(TAG_HANDLER_DELEGATE_FACTORY, TagHandlerDelegateFactory.class);
128         ABSTRACT_FACTORY_CLASSES.put(VIEW_DECLARATION_LANGUAGE_FACTORY, ViewDeclarationLanguageFactory.class);
129         ABSTRACT_FACTORY_CLASSES.put(VISIT_CONTEXT_FACTORY, VisitContextFactory.class);
130         ABSTRACT_FACTORY_CLASSES.put(FACELET_CACHE_FACTORY, FaceletCacheFactory.class);
131         ABSTRACT_FACTORY_CLASSES.put(FLASH_FACTORY, FlashFactory.class);
132         ABSTRACT_FACTORY_CLASSES.put(FLOW_HANDLER_FACTORY, FlowHandlerFactory.class);
133         ABSTRACT_FACTORY_CLASSES.put(CLIENT_WINDOW_FACTORY, ClientWindowFactory.class);
134         ABSTRACT_FACTORY_CLASSES.put(SEARCH_EXPRESSION_CONTEXT_FACTORY, SearchExpressionContextFactory.class);
135         try
136         {
137             ClassLoader classLoader;
138             if (System.getSecurityManager() != null)
139             {
140                 classLoader = (ClassLoader) AccessController.doPrivileged(new java.security.PrivilegedExceptionAction()
141                 {
142                     public Object run()
143                     {
144                         return FactoryFinder.class.getClassLoader();
145                     }
146                 });
147             }
148             else
149             {
150                 classLoader = FactoryFinder.class.getClassLoader();
151             }
152 
153             if (classLoader == null)
154             {
155                 throw new FacesException("jsf api class loader cannot be identified", null);
156             }
157             MYFACES_CLASSLOADER = classLoader;
158         }
159         catch (Exception e)
160         {
161             throw new FacesException("jsf api class loader cannot be identified", e);
162         }
163     }
164 
165     // ~ Start FactoryFinderProvider Support
166     
167     private static Object factoryFinderProviderFactoryInstance;
168     
169     private static volatile boolean initialized = false;
170     
171     private static void initializeFactoryFinderProviderFactory()
172     {
173         if (!initialized)
174         {
175             factoryFinderProviderFactoryInstance = _FactoryFinderProviderFactory.getInstance();
176             initialized = true;
177         }
178     }
179 
180     // ~ End FactoryFinderProvider Support
181 
182     // avoid instantiation
183     FactoryFinder()
184     {
185     }
186 
187     /**
188      * <p>
189      * Create (if necessary) and return a per-web-application instance of the appropriate implementation class for the
190      * specified JavaServer Faces factory class, based on the discovery algorithm described in the class description.
191      * </p>
192      * 
193      * <p>
194      * The standard factories and wrappers in JSF all implement the interface {@link FacesWrapper}. If the returned
195      * <code>Object</code> is an implementation of one of the standard factories, it must be legal to cast it to an
196      * instance of <code>FacesWrapper</code> and call {@link FacesWrapper#getWrapped()} on the instance.
197      * </p>
198      * 
199      * @param factoryName
200      *            Fully qualified name of the JavaServer Faces factory for which an implementation instance is requested
201      * 
202      * @return A per-web-application instance of the appropriate implementation class for the specified JavaServer Faces
203      *         factory class
204      * 
205      * @throws FacesException
206      *             if the web application class loader cannot be identified
207      * @throws FacesException
208      *             if an instance of the configured factory implementation class cannot be loaded
209      * @throws FacesException
210      *             if an instance of the configured factory implementation class cannot be instantiated
211      * @throws IllegalArgumentException
212      *             if <code>factoryname</code> does not identify a standard JavaServer Faces factory name
213      * @throws IllegalStateException
214      *             if there is no configured factory implementation class for the specified factory name
215      * @throws NullPointerException
216      *             if <code>factoryname</code> is null
217      */
218     public static Object getFactory(String factoryName) throws FacesException
219     {
220         if (factoryName == null)
221         {
222             throw new NullPointerException("factoryName may not be null");
223         }
224         
225         initializeFactoryFinderProviderFactory();
226         
227         if (factoryFinderProviderFactoryInstance == null)
228         {
229             // Do the typical stuff
230             return _getFactory(factoryName);
231         }
232         else
233         {
234             try
235             {
236                 //Obtain the FactoryFinderProvider instance for this context.
237                 Object ffp = _FactoryFinderProviderFactory
238                         .FACTORY_FINDER_PROVIDER_FACTORY_GET_FACTORY_FINDER_METHOD
239                         .invoke(factoryFinderProviderFactoryInstance, null);
240                 
241                 //Call getFactory method and pass the params
242                 return _FactoryFinderProviderFactory
243                         .FACTORY_FINDER_PROVIDER_GET_FACTORY_METHOD.invoke(ffp, factoryName);
244             }
245             catch (InvocationTargetException e)
246             {
247                 Throwable targetException = e.getCause();
248                 if (targetException instanceof NullPointerException)
249                 {
250                     throw (NullPointerException) targetException;
251                 }
252                 else if (targetException instanceof FacesException)
253                 {
254                     throw (FacesException) targetException;
255                 }
256                 else if (targetException instanceof IllegalArgumentException)
257                 {
258                     throw (IllegalArgumentException) targetException;
259                 }
260                 else if (targetException instanceof IllegalStateException)
261                 {
262                     throw (IllegalStateException) targetException;
263                 }
264                 else if (targetException == null)
265                 {
266                     throw new FacesException(e);
267                 }
268                 else
269                 {
270                     throw new FacesException(targetException);
271                 }
272             }
273             catch (Exception e)
274             {
275                 //No Op
276                 throw new FacesException(e);
277             }
278         }
279     }
280 
281     private static Object _getFactory(String factoryName) throws FacesException
282     {
283         ClassLoader classLoader = getClassLoader();
284 
285         // This code must be synchronized because this could cause a problem when
286         // using update feature each time of myfaces (org.apache.myfaces.CONFIG_REFRESH_PERIOD)
287         // In this moment, a concurrency problem could happen
288         Map<String, List<String>> factoryClassNames = null;
289         Map<String, Object> factoryMap = null;
290 
291         synchronized (registeredFactoryNames)
292         {
293             factoryClassNames = registeredFactoryNames.get(classLoader);
294 
295             if (factoryClassNames == null)
296             {
297                 String message
298                         = "No Factories configured for this Application. This happens if the faces-initialization "
299                         + "does not work at all - make sure that you properly include all configuration "
300                         + "settings necessary for a basic faces application "
301                         + "and that all the necessary libs are included. Also check the logging output of your "
302                         + "web application and your container for any exceptions!"
303                         + "\nIf you did that and find nothing, the mistake might be due to the fact "
304                         + "that you use some special web-containers which "
305                         + "do not support registering context-listeners via TLD files and "
306                         + "a context listener is not setup in your web.xml.\n"
307                         + "A typical config looks like this;\n<listener>\n"
308                         + "  <listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>\n"
309                         + "</listener>\n";
310                 throw new IllegalStateException(message);
311             }
312 
313             if (!factoryClassNames.containsKey(factoryName))
314             {
315                 throw new IllegalArgumentException("no factory " + factoryName + " configured for this application.");
316             }
317 
318             factoryMap = factories.get(classLoader);
319 
320             if (factoryMap == null)
321             {
322                 factoryMap = new HashMap<String, Object>();
323                 factories.put(classLoader, factoryMap);
324             }
325         }
326 
327         List beanEntryStorage;
328 
329         synchronized (factoryClassNames)
330         {
331             beanEntryStorage = (List)factoryMap.get(INJECTED_BEAN_STORAGE_KEY);
332 
333             if (beanEntryStorage == null)
334             {
335                 beanEntryStorage = new CopyOnWriteArrayList();
336                 factoryMap.put(INJECTED_BEAN_STORAGE_KEY, beanEntryStorage);
337             }
338         }
339 
340         List<String> classNames;
341         Object factory;
342         Object injectionProvider;
343         synchronized (factoryClassNames)
344         {
345             factory = factoryMap.get(factoryName);
346             if (factory != null)
347             {
348                 return factory;
349             }
350 
351             classNames = factoryClassNames.get(factoryName);
352             
353             injectionProvider = factoryMap.get(INJECTION_PROVIDER_INSTANCE);
354         }
355 
356         if (injectionProvider == null)
357         {
358             injectionProvider = getInjectionProvider();
359             synchronized (factoryClassNames)
360             {
361                 factoryMap.put(INJECTION_PROVIDER_INSTANCE, injectionProvider);
362             }
363         }
364 
365         // release lock while calling out
366         factory = newFactoryInstance(ABSTRACT_FACTORY_CLASSES.get(factoryName), 
367             classNames.iterator(), classLoader, injectionProvider, beanEntryStorage);
368 
369         synchronized (factoryClassNames)
370         {
371             // check if someone else already installed the factory
372             if (factoryMap.get(factoryName) == null)
373             {
374                 factoryMap.put(factoryName, factory);
375             }
376         }
377 
378         return factory;
379     }
380     
381     private static Object getInjectionProvider()
382     {
383         try
384         {
385             // Remember the first call in a webapp over FactoryFinder.getFactory(...) comes in the 
386             // initialization block, so there is a startup FacesContext active and
387             // also a valid startup ExternalContext. Note after that, we need to cache
388             // the injection provider for the classloader, because in a normal
389             // request there is no active FacesContext in the moment and this call will
390             // surely fail.
391             FacesContext facesContext = FacesContext.getCurrentInstance();
392             if (facesContext != null)
393             {
394                 Object injectionProviderFactory =
395                     _FactoryFinderProviderFactory.INJECTION_PROVIDER_FACTORY_GET_INSTANCE_METHOD
396                         .invoke(_FactoryFinderProviderFactory.INJECTION_PROVIDER_CLASS);
397                 Object injectionProvider = 
398                     _FactoryFinderProviderFactory.INJECTION_PROVIDER_FACTORY_GET_INJECTION_PROVIDER_METHOD
399                         .invoke(injectionProviderFactory, facesContext.getExternalContext());
400                 return injectionProvider;
401             }
402         }
403         catch (Exception e)
404         {
405         }
406         return null;
407     }
408     
409     private static void injectAndPostConstruct(Object injectionProvider, Object instance, List injectedBeanStorage)
410     {
411         if (injectionProvider != null)
412         {
413             try
414             {
415                 Object creationMetaData = _FactoryFinderProviderFactory.INJECTION_PROVIDER_INJECT_METHOD.invoke(
416                     injectionProvider, instance);
417 
418                 addBeanEntry(instance, creationMetaData, injectedBeanStorage);
419 
420                 _FactoryFinderProviderFactory.INJECTION_PROVIDER_POST_CONSTRUCT_METHOD.invoke(
421                     injectionProvider, instance, creationMetaData);
422             }
423             catch (Exception ex)
424             {
425                 throw new FacesException(ex);
426             }
427         }
428     }
429     
430     private static void preDestroy(Object injectionProvider, Object beanEntry)
431     {
432         if (injectionProvider != null)
433         {
434             try
435             {
436                 _FactoryFinderProviderFactory.INJECTION_PROVIDER_PRE_DESTROY_METHOD.invoke(
437                     injectionProvider, getInstance(beanEntry), getCreationMetaData(beanEntry));
438             }
439             catch (Exception ex)
440             {
441                 throw new FacesException(ex);
442             }
443         }
444     }
445 
446     private static Object getInstance(Object beanEntry)
447     {
448         try
449         {
450             Method getterMethod = getMethod(beanEntry, "getInstance");
451             return getterMethod.invoke(beanEntry);
452         }
453         catch (Exception e)
454         {
455             throw new IllegalStateException(e);
456         }
457     }
458 
459     private static Object getCreationMetaData(Object beanEntry)
460     {
461         try
462         {
463             Method getterMethod = getMethod(beanEntry, "getCreationMetaData");
464             return getterMethod.invoke(beanEntry);
465         }
466         catch (Exception e)
467         {
468             throw new IllegalStateException(e);
469         }
470     }
471 
472     private static Method getMethod(Object beanEntry, String methodName) throws NoSuchMethodException
473     {
474         return beanEntry.getClass().getDeclaredMethod(methodName);
475     }
476 
477     private static void addBeanEntry(Object instance, Object creationMetaData, List injectedBeanStorage)
478     {
479         try
480         {
481             Class<?> beanEntryClass = _FactoryFinderProviderFactory.classForName(BEAN_ENTRY_CLASS_NAME);
482             Constructor beanEntryConstructor = beanEntryClass.getDeclaredConstructor(Object.class, Object.class);
483 
484             Object result = beanEntryConstructor.newInstance(instance, creationMetaData);
485             injectedBeanStorage.add(result);
486         }
487         catch (Exception e)
488         {
489             throw new RuntimeException(e);
490         }
491     }
492 
493     private static Object newFactoryInstance(Class<?> interfaceClass, Iterator<String> classNamesIterator,
494                                              ClassLoader classLoader, Object injectionProvider,
495                                              List injectedBeanStorage)
496     {
497         try
498         {
499             Object current = null;
500             
501             while (classNamesIterator.hasNext())
502             {
503                 String implClassName = classNamesIterator.next();
504                 Class<?> implClass = null;
505                 try
506                 {
507                     implClass = classLoader.loadClass(implClassName);
508                 }
509                 catch (ClassNotFoundException e)
510                 {
511                     implClass = MYFACES_CLASSLOADER.loadClass(implClassName);
512                 }
513 
514                 // check, if class is of expected interface type
515                 if (!interfaceClass.isAssignableFrom(implClass))
516                 {
517                     throw new IllegalArgumentException("Class " + implClassName + " is no " + interfaceClass.getName());
518                 }
519 
520                 if (current == null)
521                 {
522                     // nothing to decorate
523                     current = implClass.newInstance();
524                     injectAndPostConstruct(injectionProvider, current, injectedBeanStorage);
525                 }
526                 else
527                 {
528                     // let's check if class supports the decorator pattern
529                     try
530                     {
531                         Constructor<?> delegationConstructor = implClass.getConstructor(new Class[] { interfaceClass });
532                         // impl class supports decorator pattern,
533                         try
534                         {
535                             // create new decorator wrapping current
536                             current = delegationConstructor.newInstance(new Object[] { current });
537                             injectAndPostConstruct(injectionProvider, current, injectedBeanStorage);
538                         }
539                         catch (InstantiationException e)
540                         {
541                             throw new FacesException(e);
542                         }
543                         catch (IllegalAccessException e)
544                         {
545                             throw new FacesException(e);
546                         }
547                         catch (InvocationTargetException e)
548                         {
549                             throw new FacesException(e);
550                         }
551                     }
552                     catch (NoSuchMethodException e)
553                     {
554                         // no decorator pattern support
555                         current = implClass.newInstance();
556                         injectAndPostConstruct(injectionProvider, current, injectedBeanStorage);
557                     }
558                 }
559             }
560 
561             return current;
562         }
563         catch (ClassNotFoundException e)
564         {
565             throw new FacesException(e);
566         }
567         catch (InstantiationException e)
568         {
569             throw new FacesException(e);
570         }
571         catch (IllegalAccessException e)
572         {
573             throw new FacesException(e);
574         }
575     }
576 
577     public static void setFactory(String factoryName, String implName)
578     {
579         if (factoryName == null)
580         {
581             throw new NullPointerException("factoryName may not be null");
582         }
583         
584         initializeFactoryFinderProviderFactory();
585         
586         if (factoryFinderProviderFactoryInstance == null)
587         {
588             // Do the typical stuff
589             _setFactory(factoryName, implName);
590         }
591         else
592         {
593             try
594             {
595                 //Obtain the FactoryFinderProvider instance for this context.
596                 Object ffp = _FactoryFinderProviderFactory
597                         .FACTORY_FINDER_PROVIDER_FACTORY_GET_FACTORY_FINDER_METHOD
598                         .invoke(factoryFinderProviderFactoryInstance, null);
599                 
600                 //Call getFactory method and pass the params
601                 _FactoryFinderProviderFactory
602                         .FACTORY_FINDER_PROVIDER_SET_FACTORY_METHOD.invoke(ffp, factoryName, implName);
603             }
604             catch (InvocationTargetException e)
605             {
606                 Throwable targetException = e.getCause();
607                 if (targetException instanceof NullPointerException)
608                 {
609                     throw (NullPointerException) targetException;
610                 }
611                 else if (targetException instanceof FacesException)
612                 {
613                     throw (FacesException) targetException;
614                 }
615                 else if (targetException instanceof IllegalArgumentException)
616                 {
617                     throw (IllegalArgumentException) targetException;
618                 }
619                 else if (targetException == null)
620                 {
621                     throw new FacesException(e);
622                 }
623                 else
624                 {
625                     throw new FacesException(targetException);
626                 }
627             }
628             catch (Exception e)
629             {
630                 //No Op
631                 throw new FacesException(e);
632             }
633             
634         }
635     }
636 
637     private static void _setFactory(String factoryName, String implName)
638     {
639         checkFactoryName(factoryName);
640 
641         ClassLoader classLoader = getClassLoader();
642         Map<String, List<String>> factoryClassNames = null;
643         synchronized (registeredFactoryNames)
644         {
645             Map<String, Object> factories = FactoryFinder.factories.get(classLoader);
646 
647             if (factories != null && factories.containsKey(factoryName))
648             {
649                 // Javadoc says ... This method has no effect if getFactory() has already been
650                 // called looking for a factory for this factoryName.
651                 return;
652             }
653 
654             factoryClassNames = registeredFactoryNames.get(classLoader);
655 
656             if (factoryClassNames == null)
657             {
658                 factoryClassNames = new HashMap<String, List<String>>();
659                 registeredFactoryNames.put(classLoader, factoryClassNames);
660             }
661         }
662 
663         synchronized (factoryClassNames)
664         {
665             List<String> classNameList = factoryClassNames.get(factoryName);
666 
667             if (classNameList == null)
668             {
669                 classNameList = new ArrayList<String>();
670                 factoryClassNames.put(factoryName, classNameList);
671             }
672 
673             classNameList.add(implName);
674         }
675     }
676 
677     public static void releaseFactories() throws FacesException
678     {
679         initializeFactoryFinderProviderFactory();
680         
681         if (factoryFinderProviderFactoryInstance == null)
682         {
683             // Do the typical stuff
684             _releaseFactories();
685         }
686         else
687         {
688             try
689             {
690                 //Obtain the FactoryFinderProvider instance for this context.
691                 Object ffp = _FactoryFinderProviderFactory
692                         .FACTORY_FINDER_PROVIDER_FACTORY_GET_FACTORY_FINDER_METHOD
693                         .invoke(factoryFinderProviderFactoryInstance, null);
694                 
695                 //Call getFactory method and pass the params
696                 _FactoryFinderProviderFactory.FACTORY_FINDER_PROVIDER_RELEASE_FACTORIES_METHOD.invoke(ffp, null);
697             }
698             catch (InvocationTargetException e)
699             {
700                 Throwable targetException = e.getCause();
701                 if (targetException instanceof FacesException)
702                 {
703                     throw (FacesException) targetException;
704                 }
705                 else if (targetException == null)
706                 {
707                     throw new FacesException(e);
708                 }
709                 else
710                 {
711                     throw new FacesException(targetException);
712                 }
713             }
714             catch (Exception e)
715             {
716                 //No Op
717                 throw new FacesException(e);
718             }
719             
720         }
721     }
722 
723     private static void _releaseFactories() throws FacesException
724     {
725         ClassLoader classLoader = getClassLoader();
726 
727         Map<String, Object> factoryMap;
728         // This code must be synchronized
729         synchronized (registeredFactoryNames)
730         {
731             factoryMap = factories.remove(classLoader);
732 
733             // _registeredFactoryNames has as value type Map<String,List> and this must
734             // be cleaned before release (for gc).
735             Map<String, List<String>> factoryClassNames = registeredFactoryNames.get(classLoader);
736             if (factoryClassNames != null)
737             {
738                 factoryClassNames.clear();
739             }
740 
741             registeredFactoryNames.remove(classLoader);
742         }
743 
744         if (factoryMap != null)
745         {
746             Object injectionProvider = factoryMap.remove(INJECTION_PROVIDER_INSTANCE);
747             if (injectionProvider != null)
748             {
749                 List injectedBeanStorage = (List)factoryMap.get(INJECTED_BEAN_STORAGE_KEY);
750 
751                 FacesException firstException = null;
752                 for (Object entry : injectedBeanStorage)
753                 {
754                     try
755                     {
756                         preDestroy(injectionProvider, entry);
757                     }
758                     catch (FacesException e)
759                     {
760                         LOGGER.log(Level.SEVERE, "#preDestroy failed", e);
761 
762                         if (firstException == null)
763                         {
764                             firstException = e; //all preDestroy callbacks need to get invoked
765                         }
766                     }
767                 }
768                 injectedBeanStorage.clear();
769 
770                 if (firstException != null)
771                 {
772                     throw firstException;
773                 }
774             }
775         }
776     }
777 
778     private static void checkFactoryName(String factoryName)
779     {
780         if (!VALID_FACTORY_NAMES.contains(factoryName))
781         {
782             throw new IllegalArgumentException("factoryName '" + factoryName + "'");
783         }
784     }
785 
786     private static ClassLoader getClassLoader()
787     {
788         try
789         {
790             ClassLoader classLoader = null;
791             if (System.getSecurityManager() != null)
792             {
793                 classLoader = (ClassLoader) AccessController.doPrivileged(new java.security.PrivilegedExceptionAction()
794                 {
795                     public Object run()
796                     {
797                         return Thread.currentThread().getContextClassLoader();
798                     }
799                 });
800             }
801             else
802             {
803                 classLoader = Thread.currentThread().getContextClassLoader();
804             }
805             
806             if (classLoader == null)
807             {
808                 throw new FacesException("web application class loader cannot be identified", null);
809             }
810             return classLoader;
811         }
812         catch (Exception e)
813         {
814             throw new FacesException("web application class loader cannot be identified", e);
815         }
816     }
817 }