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