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 org.apache.myfaces.webapp;
20  
21  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
22  import org.apache.myfaces.config.FacesConfigValidator;
23  import org.apache.myfaces.config.FacesConfigurator;
24  import org.apache.myfaces.config.ManagedBeanBuilder;
25  import org.apache.myfaces.config.RuntimeConfig;
26  import org.apache.myfaces.config.element.ManagedBean;
27  import org.apache.myfaces.context.ReleaseableExternalContext;
28  import org.apache.myfaces.context.servlet.StartupFacesContextImpl;
29  import org.apache.myfaces.context.servlet.StartupServletExternalContextImpl;
30  import org.apache.myfaces.shared.util.StateUtils;
31  import org.apache.myfaces.shared.util.WebConfigParamUtils;
32  import org.apache.myfaces.cdi.dependent.BeanEntry;
33  import org.apache.myfaces.spi.InjectionProvider;
34  import org.apache.myfaces.spi.InjectionProviderException;
35  import org.apache.myfaces.spi.InjectionProviderFactory;
36  import org.apache.myfaces.spi.ViewScopeProvider;
37  import org.apache.myfaces.spi.ViewScopeProviderFactory;
38  import org.apache.myfaces.spi.WebConfigProvider;
39  import org.apache.myfaces.spi.WebConfigProviderFactory;
40  import org.apache.myfaces.util.ExternalSpecifications;
41  import org.apache.myfaces.view.facelets.tag.MetaRulesetImpl;
42  
43  import javax.el.ExpressionFactory;
44  import javax.faces.application.Application;
45  import javax.faces.application.ProjectStage;
46  import javax.faces.component.UIViewRoot;
47  import javax.faces.context.ExceptionHandler;
48  import javax.faces.context.ExternalContext;
49  import javax.faces.context.FacesContext;
50  import javax.faces.event.PostConstructApplicationEvent;
51  import javax.faces.event.PreDestroyApplicationEvent;
52  import javax.faces.event.SystemEvent;
53  import javax.servlet.ServletContext;
54  import java.lang.reflect.InvocationTargetException;
55  import java.lang.reflect.Method;
56  import java.util.ArrayList;
57  import java.util.List;
58  import java.util.Locale;
59  import java.util.Map;
60  import java.util.logging.Level;
61  import java.util.logging.Logger;
62  import org.apache.myfaces.shared.context.ExceptionHandlerImpl;
63  import org.apache.myfaces.shared.util.ClassUtils;
64  import org.apache.myfaces.spi.ServiceProviderFinder;
65  import org.apache.myfaces.spi.ServiceProviderFinderFactory;
66  import org.apache.myfaces.view.facelets.ViewPoolProcessor;
67  
68  /**
69   * Performs common initialization tasks.
70   */
71  public abstract class AbstractFacesInitializer implements FacesInitializer
72  {
73      /**
74       * The logger instance for this class.
75       */
76      //private static final Log log = LogFactory.getLog(AbstractFacesInitializer.class);
77      private static final Logger log = Logger.getLogger(AbstractFacesInitializer.class.getName());
78      
79      /**
80       * If the servlet mapping for the FacesServlet is added dynamically, Boolean.TRUE 
81       * is stored under this key in the ServletContext.
82       * ATTENTION: this constant is duplicate in MyFacesContainerInitializer.
83       */
84      private static final String FACES_SERVLET_ADDED_ATTRIBUTE = "org.apache.myfaces.DYNAMICALLY_ADDED_FACES_SERVLET";
85  
86      /**
87       * If the servlet mapping for the FacesServlet is found on the ServletContext, Boolean.TRUE 
88       * is stored under this key in the ServletContext.
89       * ATTENTION: this constant is duplicate in MyFacesContainerInitializer.
90       */
91      private static final String FACES_SERVLET_FOUND = "org.apache.myfaces.FACES_SERVLET_FOUND"; 
92  
93      /**
94       * This parameter specifies the ExpressionFactory implementation to use.
95       */
96      @JSFWebConfigParam(since="1.2.7", group="EL")
97      protected static final String EXPRESSION_FACTORY = "org.apache.myfaces.EXPRESSION_FACTORY";
98      
99      /**
100      * If this param is set to true, the check for faces servlet mapping is not done 
101      */
102     @JSFWebConfigParam(since="2.0.3", defaultValue="false")
103     protected static final String INITIALIZE_ALWAYS_STANDALONE = "org.apache.myfaces.INITIALIZE_ALWAYS_STANDALONE";
104     
105     /**
106      * Indicate if log all web config params should be done before initialize the webapp. 
107      * <p>
108      * If is set in "auto" mode, web config params are only logged on "Development" and "Production" project stages.
109      * </p> 
110      */
111     @JSFWebConfigParam(expectedValues="true, auto, false", defaultValue="auto")
112     public static final String INIT_PARAM_LOG_WEB_CONTEXT_PARAMS = "org.apache.myfaces.LOG_WEB_CONTEXT_PARAMS";
113     public static final String INIT_PARAM_LOG_WEB_CONTEXT_PARAMS_DEFAULT ="auto";
114     
115     public static final String CDI_BEAN_MANAGER_INSTANCE = "oam.cdi.BEAN_MANAGER_INSTANCE";
116     
117     private static final String CDI_SERVLET_CONTEXT_BEAN_MANAGER_ATTRIBUTE = 
118         "javax.enterprise.inject.spi.BeanManager";
119 
120     private static final String INJECTED_BEAN_STORAGE_KEY = "org.apache.myfaces.spi.BEAN_ENTRY_STORAGE";
121 
122     /**
123      * Performs all necessary initialization tasks like configuring this JSF
124      * application.
125      */
126     public void initFaces(ServletContext servletContext)
127     {
128         try
129         {
130             if (log.isLoggable(Level.FINEST))
131             {
132                 log.finest("Initializing MyFaces");
133             }
134 
135             // Some parts of the following configuration tasks have been implemented 
136             // by using an ExternalContext. However, that's no problem as long as no 
137             // one tries to call methods depending on either the ServletRequest or 
138             // the ServletResponse.
139             // JSF 2.0: FacesInitializer now has some new methods to
140             // use proper startup FacesContext and ExternalContext instances.
141             FacesContext facesContext = FacesContext.getCurrentInstance();
142             ExternalContext externalContext = facesContext.getExternalContext();
143 
144             // Setup ServiceProviderFinder
145             ServiceProviderFinder spf = ServiceProviderFinderFactory.getServiceProviderFinder(
146                 externalContext);
147             Map<String, List<String>> spfConfig = spf.calculateKnownServiceProviderMapInfo(
148                 externalContext, ServiceProviderFinder.KNOWN_SERVICES);
149             if (spfConfig != null)
150             {
151                 spf.initKnownServiceProviderMapInfo(externalContext, spfConfig);
152             }
153             
154             // Parse and validate the web.xml configuration file
155             
156             if (!WebConfigParamUtils.getBooleanInitParameter(externalContext, INITIALIZE_ALWAYS_STANDALONE, false))
157             {
158                 WebConfigProvider webConfigProvider = WebConfigProviderFactory.getWebConfigProviderFactory(
159                         facesContext.getExternalContext()).getWebConfigProvider(facesContext.getExternalContext());
160 
161                 if (webConfigProvider.getFacesServletMappings(facesContext.getExternalContext()).isEmpty())
162                 {
163                     // check to see if the FacesServlet was found by MyFacesContainerInitializer
164                     Boolean mappingAdded = (Boolean) servletContext.getAttribute(FACES_SERVLET_FOUND);
165 
166                     if (mappingAdded == null || !mappingAdded)
167                     {
168                         // check if the FacesServlet has been added dynamically
169                         // in a Servlet 3.0 environment by MyFacesContainerInitializer
170                         mappingAdded = (Boolean) servletContext.getAttribute(FACES_SERVLET_ADDED_ATTRIBUTE);
171 
172                         if (mappingAdded == null || !mappingAdded)
173                         {
174                             if (log.isLoggable(Level.WARNING))
175                             {
176                                 log.warning("No mappings of FacesServlet found. Abort initializing MyFaces.");
177                             }
178                             return;
179                         }
180                     }
181                 }
182             }
183 
184             initCDIIntegration(servletContext, externalContext);
185             
186             initContainerIntegration(servletContext, externalContext);
187             
188             ViewScopeProviderFactory factory = ViewScopeProviderFactory.getViewScopeHandlerFactory(
189                 externalContext);
190             
191             ViewScopeProvider viewScopeHandler = factory.getViewScopeHandler(
192                 externalContext);
193             
194             ManagedBeanDestroyerListener listener = (ManagedBeanDestroyerListener)
195                 externalContext.getApplicationMap().get(
196                     ManagedBeanDestroyerListener.APPLICATION_MAP_KEY);
197             
198             listener.setViewScopeHandler(viewScopeHandler);
199 
200             String useEncryption = servletContext.getInitParameter(StateUtils.USE_ENCRYPTION);
201             if (!"false".equals(useEncryption)) // the default value is true
202             {
203                 StateUtils.initSecret(servletContext);
204             }
205 
206             // initialize eager managed beans
207             _createEagerBeans(facesContext);
208 
209             _dispatchApplicationEvent(servletContext, PostConstructApplicationEvent.class);
210 
211             if ( (facesContext.isProjectStage(ProjectStage.Development) || 
212                   facesContext.isProjectStage(ProjectStage.Production)) &&
213                  log.isLoggable(Level.INFO))
214             {
215                 log.info("ServletContext initialized.");
216             }
217 
218             WebConfigParamsLogger.logWebContextParams(facesContext);
219             
220             //Force output EL message
221             ExternalSpecifications.isUnifiedELAvailable();
222             ExternalSpecifications.isBeanValidationAvailable();
223             
224             //Start ViewPoolProcessor if necessary
225             ViewPoolProcessor.initialize(facesContext);
226 
227             // print out a very prominent log message if the project stage is != Production
228             if (!facesContext.isProjectStage(ProjectStage.Production) &&
229                 !facesContext.isProjectStage(ProjectStage.UnitTest))
230             {
231                 ProjectStage projectStage = facesContext.getApplication().getProjectStage();
232                 StringBuilder message = new StringBuilder("\n\n");
233                 message.append("*******************************************************************\n");
234                 message.append("*** WARNING: Apache MyFaces-2 is running in ");
235                 message.append(projectStage.name().toUpperCase());        
236                 message.append(" mode.");
237                 int length = projectStage.name().length();
238                 for (int i = 0; i < 11 - length; i++)
239                 {
240                     message.append(" ");
241                 }
242                 message.append("   ***\n");
243                 message.append("***                                         ");
244                 for (int i = 0; i < length; i++)
245                 {
246                     message.append("^");
247                 }
248                 for (int i = 0; i < 20 - length; i++)
249                 {
250                     message.append(" ");
251                 }
252                 message.append("***\n");
253                 message.append("*** Do NOT deploy to your live server(s) without changing this. ***\n");
254                 message.append("*** See Application#getProjectStage() for more information.     ***\n");
255                 message.append("*******************************************************************\n");
256                 log.log(Level.WARNING, message.toString());
257             }
258 
259         }
260         catch (Exception ex)
261         {
262             log.log(Level.SEVERE, "An error occured while initializing MyFaces: "
263                       + ex.getMessage(), ex);
264         }
265     }
266     
267     /**
268      * Checks for application scoped managed-beans with eager=true,
269      * creates them and stores them in the application map.
270      * @param facesContext
271      */
272     private void _createEagerBeans(FacesContext facesContext)
273     {
274         ExternalContext externalContext = facesContext.getExternalContext();
275         RuntimeConfig runtimeConfig = RuntimeConfig.getCurrentInstance(externalContext);
276         List<ManagedBean> eagerBeans = new ArrayList<ManagedBean>();
277         
278         // check all registered managed-beans
279         for (ManagedBean bean : runtimeConfig.getManagedBeans().values())
280         {
281             String eager = bean.getEager();
282             if (eager != null && "true".equals(eager))
283             {
284                 // eager beans are only allowed for application scope
285                 if (ManagedBeanBuilder.APPLICATION.equals(bean.getManagedBeanScope()))
286                 {
287                     // add to eager beans
288                     eagerBeans.add(bean);
289                 }
290                 else
291                 {
292                     // log warning and continue (the bean will be lazy loaded)
293                     log.log(Level.WARNING, "The managed-bean with name "
294                             + bean.getManagedBeanName()
295                             + " must be application scoped to support eager=true.");
296                 }
297             }
298         }
299         
300         // check if there are any eager beans
301         if (!eagerBeans.isEmpty())
302         {
303             ManagedBeanBuilder managedBeanBuilder = new ManagedBeanBuilder();
304             Map<String, Object> applicationMap = externalContext.getApplicationMap();
305             
306             for (ManagedBean bean : eagerBeans)
307             {
308                 // check application scope for bean instance
309                 if (applicationMap.containsKey(bean.getManagedBeanName()))
310                 {
311                     // do not build bean, because it already exists
312                     // (e.g. @ManagedProperty from previous managed bean already created it)
313                     continue;
314                 }
315 
316                 // create instance
317                 Object beanInstance = managedBeanBuilder.buildManagedBean(facesContext, bean);
318                 
319                 // put in application scope
320                 applicationMap.put(bean.getManagedBeanName(), beanInstance);
321             }
322         }
323     }
324 
325     /**
326      * Eventually we can use our plugin infrastructure for this as well
327      * it would be a cleaner interception point than the base class
328      * but for now this position is valid as well
329      * <p/>
330      * Note we add it for now here because the application factory object
331      * leaves no possibility to have a destroy interceptor
332      * and applications are per web application singletons
333      * Note if this does not work out
334      * move the event handler into the application factory
335      *
336      * @param servletContext the servlet context to be passed down
337      * @param eventClass     the class to be passed down into the dispatching
338      *                       code
339      */
340     private void _dispatchApplicationEvent(ServletContext servletContext, Class<? extends SystemEvent> eventClass)
341     {
342         FacesContext facesContext = FacesContext.getCurrentInstance();
343         Application application = facesContext.getApplication();
344         application.publishEvent(facesContext, eventClass, Application.class, application);
345     }
346     
347     /**
348      * Cleans up all remaining resources (well, theoretically).
349      */
350     public void destroyFaces(ServletContext servletContext)
351     {
352 
353         FacesContext facesContext = FacesContext.getCurrentInstance();
354 
355         if (!WebConfigParamUtils.getBooleanInitParameter(facesContext.getExternalContext(),
356                                                          INITIALIZE_ALWAYS_STANDALONE, false))
357         {
358             //We need to check if the current application was initialized by myfaces
359             WebConfigProvider webConfigProvider = WebConfigProviderFactory.getWebConfigProviderFactory(
360                     facesContext.getExternalContext()).getWebConfigProvider(facesContext.getExternalContext());
361 
362             if (webConfigProvider.getFacesServletMappings(facesContext.getExternalContext()).isEmpty())
363             {
364                 // check to see if the FacesServlet was found by MyFacesContainerInitializer
365                 Boolean mappingAdded = (Boolean) servletContext.getAttribute(FACES_SERVLET_FOUND);
366 
367                 if (mappingAdded == null || !mappingAdded)
368                 {
369                     // check if the FacesServlet has been added dynamically
370                     // in a Servlet 3.0 environment by MyFacesContainerInitializer
371                     mappingAdded = (Boolean) servletContext.getAttribute(FACES_SERVLET_ADDED_ATTRIBUTE);
372 
373                     if (mappingAdded == null || !mappingAdded)
374                     {
375                         if (log.isLoggable(Level.WARNING))
376                         {
377                             log.warning("No mappings of FacesServlet found. Abort destroy MyFaces.");
378                         }
379                         return;
380                     }
381                 }
382             }
383         }
384 
385         _dispatchApplicationEvent(servletContext, PreDestroyApplicationEvent.class);
386 
387         _callPreDestroyOnInjectedJSFArtifacts(facesContext);
388         
389         // clear the cache of MetaRulesetImpl in order to prevent a memory leak
390         MetaRulesetImpl.clearMetadataTargetCache();
391         
392         // clear UIViewParameter default renderer map
393         try
394         {
395             Class<?> c = Class.forName("javax.faces.component.UIViewParameter");
396             Method m = c.getDeclaredMethod("releaseRenderer");
397             m.setAccessible(true);
398             m.invoke(null);
399         }
400         catch(ClassNotFoundException e)
401         {
402             log.log(Level.SEVERE, e.getMessage(), e);
403         }
404         catch(NoSuchMethodException e)
405         {
406             log.log(Level.SEVERE, e.getMessage(), e);
407         }
408         catch(IllegalAccessException e)
409         {
410             log.log(Level.SEVERE, e.getMessage(), e);
411         }
412         catch(InvocationTargetException e)
413         {
414             log.log(Level.SEVERE, e.getMessage(), e);
415         }
416 
417         // TODO is it possible to make a real cleanup?
418     }
419 
420     /**
421      * Configures this JSF application. It's required that every
422      * FacesInitializer (i.e. every subclass) calls this method during
423      * initialization.
424      *
425      * @param servletContext    the current ServletContext
426      * @param externalContext   the current ExternalContext
427      * @param expressionFactory the ExpressionFactory to use
428      * @return the current runtime configuration
429      */
430     protected RuntimeConfig buildConfiguration(ServletContext servletContext,
431                                                ExternalContext externalContext, ExpressionFactory expressionFactory)
432     {
433         RuntimeConfig runtimeConfig = RuntimeConfig.getCurrentInstance(externalContext);
434         runtimeConfig.setExpressionFactory(expressionFactory);
435 
436         // And configure everything
437         new FacesConfigurator(externalContext).configure();
438 
439         validateFacesConfig(servletContext, externalContext);
440 
441         return runtimeConfig;
442     }
443 
444     protected void validateFacesConfig(ServletContext servletContext, ExternalContext externalContext)
445     {
446         String validate = servletContext.getInitParameter(FacesConfigValidator.VALIDATE_CONTEXT_PARAM);
447         if ("true".equals(validate) && log.isLoggable(Level.WARNING))
448         { // the default value is false
449             List<String> warnings = FacesConfigValidator.validate(
450                     externalContext);
451 
452             for (String warning : warnings)
453             {
454                 log.warning(warning);
455             }
456         }
457     }
458 
459     /**
460      * Try to load user-definied ExpressionFactory. Returns <code>null</code>,
461      * if no custom ExpressionFactory was specified.
462      *
463      * @param externalContext the current ExternalContext
464      * @return User-specified ExpressionFactory, or
465      *         <code>null</code>, if no no custom implementation was specified
466      */
467     protected static ExpressionFactory getUserDefinedExpressionFactory(ExternalContext externalContext)
468     {
469         String expressionFactoryClassName
470                 = WebConfigParamUtils.getStringInitParameter(externalContext, EXPRESSION_FACTORY);
471         if (expressionFactoryClassName != null
472                 && expressionFactoryClassName.trim().length() > 0)
473         {
474             if (log.isLoggable(Level.FINE))
475             {
476                 log.fine("Attempting to load the ExpressionFactory implementation "
477                         + "you've specified: '" + expressionFactoryClassName + "'.");
478             }
479 
480             return loadExpressionFactory(expressionFactoryClassName);
481         }
482 
483         return null;
484     }
485 
486     /**
487      * Loads and instantiates the given ExpressionFactory implementation.
488      *
489      * @param expressionFactoryClassName the class name of the ExpressionFactory implementation
490      * @return the newly created ExpressionFactory implementation, or
491      *         <code>null</code>, if an error occurred
492      */
493     protected static ExpressionFactory loadExpressionFactory(String expressionFactoryClassName)
494     {
495         try
496         {
497             ClassLoader cl = ClassUtils.getContextClassLoader();
498             if (cl == null)
499             {
500                 cl = AbstractFacesInitializer.class.getClassLoader();
501             }
502 
503             Class<?> expressionFactoryClass = cl.loadClass(expressionFactoryClassName);
504             return (ExpressionFactory) expressionFactoryClass.newInstance();
505         }
506         catch (Exception ex)
507         {
508             if (log.isLoggable(Level.FINE))
509             {
510                 log.log(Level.FINE, "An error occured while instantiating a new ExpressionFactory. "
511                         + "Attempted to load class '" + expressionFactoryClassName + "'.", ex);
512             }
513         }
514 
515         return null;
516     }
517 
518     public FacesContext initStartupFacesContext(ServletContext servletContext)
519     {
520         // We cannot use FacesContextFactory, because it is necessary to initialize 
521         // before Application and RenderKit factories, so we should use different object. 
522         return _createFacesContext(servletContext, true);
523     }
524         
525     public void destroyStartupFacesContext(FacesContext facesContext)
526     {
527         _releaseFacesContext(facesContext);
528     }
529     
530     public FacesContext initShutdownFacesContext(ServletContext servletContext)
531     {
532         return _createFacesContext(servletContext, false);
533     }
534         
535     public void destroyShutdownFacesContext(FacesContext facesContext)
536     {
537         _releaseFacesContext(facesContext);
538     }
539     
540     private FacesContext _createFacesContext(ServletContext servletContext, boolean startup)
541     {
542         ExternalContext externalContext = new StartupServletExternalContextImpl(servletContext, startup);
543         ExceptionHandler exceptionHandler = new ExceptionHandlerImpl();
544         FacesContext facesContext = new StartupFacesContextImpl(externalContext, 
545                 (ReleaseableExternalContext) externalContext, exceptionHandler, startup);
546         
547         // If getViewRoot() is called during application startup or shutdown, 
548         // it should return a new UIViewRoot with its locale set to Locale.getDefault().
549         UIViewRoot startupViewRoot = new UIViewRoot();
550         startupViewRoot.setLocale(Locale.getDefault());
551         facesContext.setViewRoot(startupViewRoot);
552         
553         return facesContext;
554     }
555     
556     private void _releaseFacesContext(FacesContext facesContext)
557     {        
558         // make sure that the facesContext gets released.
559         // This is important in an OSGi environment 
560         if (facesContext != null)
561         {
562             facesContext.release();
563         }        
564     }
565     
566     /**
567      * Performs initialization tasks depending on the current environment.
568      *
569      * @param servletContext  the current ServletContext
570      * @param externalContext the current ExternalContext
571      */
572     protected abstract void initContainerIntegration(
573             ServletContext servletContext, ExternalContext externalContext);
574 
575     /**
576      * The intention of this method is provide a point where CDI integration is done.
577      * Faces Flow and javax.faces.view.ViewScope requires CDI in order to work, so
578      * this method should set a BeanManager instance on application map under
579      * the key "oam.cdi.BEAN_MANAGER_INSTANCE". The default implementation look on
580      * ServletContext first and then use JNDI.
581      * 
582      * @param servletContext
583      * @param externalContext 
584      */
585     protected void initCDIIntegration(
586             ServletContext servletContext, ExternalContext externalContext)
587     {
588         // Lookup bean manager and put it into an application scope attribute to 
589         // access it later. Remember the trick here is do not call any CDI api 
590         // directly, so if no CDI api is on the classpath no exception will be thrown.
591         
592         // Try with servlet context
593         Object beanManager = servletContext.getAttribute(
594             CDI_SERVLET_CONTEXT_BEAN_MANAGER_ATTRIBUTE);
595         if (beanManager == null)
596         {
597             beanManager = lookupBeanManagerFromCDI();
598         }
599         if (beanManager == null)
600         {
601             beanManager = lookupBeanManagerFromJndi();
602         }
603         if (beanManager != null)
604         {
605             externalContext.getApplicationMap().put(CDI_BEAN_MANAGER_INSTANCE,
606                 beanManager);
607         }
608     }
609 
610     /**
611      * This method tries to use the CDI-1.1 CDI.current() method to lookup the CDI BeanManager.
612      * We do all this via reflection to not blow up if CDI-1.1 is not on the classpath.
613      * @return the BeanManager or {@code null} if either not in a CDI-1.1 environment
614      *         or the BeanManager doesn't exist yet.
615      */
616     private Object lookupBeanManagerFromCDI()
617     {
618         try
619         {
620             Class cdiClass = null;
621             Method cdiCurrentMethod = null;
622             Method cdiGetBeanManagerMethod = null;
623             cdiClass = simpleClassForNameNoException("javax.enterprise.inject.spi.CDI");
624             if (cdiClass != null)
625             {
626                 cdiCurrentMethod = cdiClass.getMethod("current");
627 
628                 Object cdiInstance = cdiCurrentMethod.invoke(null);
629 
630                 cdiGetBeanManagerMethod = cdiClass.getMethod("getBeanManager");
631                 return cdiGetBeanManagerMethod.invoke(cdiInstance);
632             }
633         }
634         catch (Exception e)
635         {
636             // ignore
637         }
638         return null;
639     }
640     
641     private static Class simpleClassForNameNoException(String type)
642     {
643         try
644         {
645             return ClassUtils.classForName(type);
646         }
647         catch (ClassNotFoundException e)
648         {
649             //log.log(Level.SEVERE, "Class " + type + " not found", e);
650             //Ignore
651             return null;
652         }
653     }
654 
655     /**
656      * Try to lookup the CDI BeanManager from JNDI.
657      * We do all this via reflection to not blow up if CDI is not available.
658      */
659     private Object lookupBeanManagerFromJndi()
660     {
661         Object beanManager = null;
662         // Use reflection to avoid restricted API in GAE
663         Class icclazz = null;
664         Method lookupMethod = null;
665         try
666         {
667             icclazz = ClassUtils.simpleClassForName("javax.naming.InitialContext");
668             if (icclazz != null)
669             {
670                 lookupMethod = icclazz.getMethod("doLookup", String.class);
671             }
672         }
673         catch (Throwable t)
674         {
675             //
676         }
677         if (lookupMethod != null)
678         {
679             // Try with JNDI
680             try
681             {
682                 // in an application server
683                 //beanManager = InitialContext.doLookup("java:comp/BeanManager");
684                 beanManager = lookupMethod.invoke(icclazz, "java:comp/BeanManager");
685             }
686             catch (Exception e)
687             {
688                 // silently ignore
689             }
690             catch (NoClassDefFoundError e)
691             {
692                 //On Google App Engine, javax.naming.Context is a restricted class.
693                 //In that case, NoClassDefFoundError is thrown. stageName needs to be configured
694                 //below by context parameter.
695             }
696 
697             if (beanManager == null)
698             {
699                 try
700                 {
701                     // in a servlet container
702                     //beanManager = InitialContext.doLookup("java:comp/env/BeanManager");
703                     beanManager = lookupMethod.invoke(icclazz, "java:comp/env/BeanManager");
704                 }
705                 catch (Exception e)
706                 {
707                     // silently ignore
708                 }
709                 catch (NoClassDefFoundError e)
710                 {
711                     //On Google App Engine, javax.naming.Context is a restricted class.
712                     //In that case, NoClassDefFoundError is thrown. stageName needs to be configured
713                     //below by context parameter.
714                 }
715             }
716         }
717 
718         return beanManager;
719     }
720 
721     public void _callPreDestroyOnInjectedJSFArtifacts(FacesContext facesContext)
722     {
723         InjectionProvider injectionProvider = InjectionProviderFactory.getInjectionProviderFactory(
724             facesContext.getExternalContext()).getInjectionProvider(facesContext.getExternalContext());
725         List<BeanEntry> injectedBeanStorage =
726                 (List<BeanEntry>)facesContext.getExternalContext().getApplicationMap().get(INJECTED_BEAN_STORAGE_KEY);
727 
728         if (injectedBeanStorage != null)
729         {
730             for (BeanEntry entry : injectedBeanStorage)
731             {
732                 try
733                 {
734                     injectionProvider.preDestroy(entry.getInstance(), entry.getCreationMetaData());
735                 }
736                 catch (InjectionProviderException ex)
737                 {
738                     log.log(Level.INFO, "Exception on PreDestroy", ex);
739                 }
740             }
741             injectedBeanStorage.clear();
742         }
743     }
744 }