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.config;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.lang.reflect.Constructor;
24  import java.lang.reflect.InvocationTargetException;
25  import java.lang.reflect.Method;
26  import java.net.JarURLConnection;
27  import java.net.URL;
28  import java.net.URLConnection;
29  import java.util.ArrayList;
30  import java.util.Collection;
31  import java.util.Comparator;
32  import java.util.Iterator;
33  import java.util.List;
34  import java.util.Locale;
35  import java.util.Map;
36  import java.util.StringTokenizer;
37  import java.util.logging.Level;
38  import java.util.logging.Logger;
39  
40  import javax.el.ELResolver;
41  import javax.faces.FacesException;
42  import javax.faces.FactoryFinder;
43  import javax.faces.application.Application;
44  import javax.faces.application.ApplicationFactory;
45  import javax.faces.application.ConfigurableNavigationHandler;
46  import javax.faces.application.NavigationHandler;
47  import javax.faces.application.ProjectStage;
48  import javax.faces.application.ResourceHandler;
49  import javax.faces.application.StateManager;
50  import javax.faces.application.ViewHandler;
51  import javax.faces.context.ExternalContext;
52  import javax.faces.context.FacesContext;
53  import javax.faces.el.PropertyResolver;
54  import javax.faces.el.VariableResolver;
55  import javax.faces.event.ActionListener;
56  import javax.faces.event.ComponentSystemEvent;
57  import javax.faces.event.PhaseListener;
58  import javax.faces.event.PostConstructApplicationEvent;
59  import javax.faces.event.PreDestroyCustomScopeEvent;
60  import javax.faces.event.PreDestroyViewMapEvent;
61  import javax.faces.event.SystemEvent;
62  import javax.faces.lifecycle.Lifecycle;
63  import javax.faces.lifecycle.LifecycleFactory;
64  import javax.faces.render.RenderKit;
65  import javax.faces.render.RenderKitFactory;
66  import javax.faces.validator.BeanValidator;
67  import javax.faces.webapp.FacesServlet;
68  
69  import org.apache.myfaces.application.ApplicationFactoryImpl;
70  import org.apache.myfaces.application.BackwardsCompatibleNavigationHandlerWrapper;
71  import org.apache.myfaces.component.visit.VisitContextFactoryImpl;
72  import org.apache.myfaces.config.annotation.AnnotationConfigurator;
73  import org.apache.myfaces.config.annotation.LifecycleProvider;
74  import org.apache.myfaces.config.annotation.LifecycleProviderFactory;
75  import org.apache.myfaces.config.element.Behavior;
76  import org.apache.myfaces.config.element.ClientBehaviorRenderer;
77  import org.apache.myfaces.config.element.FacesConfig;
78  import org.apache.myfaces.config.element.FacesConfigData;
79  import org.apache.myfaces.config.element.ManagedBean;
80  import org.apache.myfaces.config.element.NamedEvent;
81  import org.apache.myfaces.config.element.NavigationRule;
82  import org.apache.myfaces.config.element.Renderer;
83  import org.apache.myfaces.config.element.ResourceBundle;
84  import org.apache.myfaces.config.element.SystemEventListener;
85  import org.apache.myfaces.config.impl.digester.DigesterFacesConfigDispenserImpl;
86  import org.apache.myfaces.config.impl.digester.DigesterFacesConfigUnmarshallerImpl;
87  import org.apache.myfaces.context.ExceptionHandlerFactoryImpl;
88  import org.apache.myfaces.context.ExternalContextFactoryImpl;
89  import org.apache.myfaces.context.FacesContextFactoryImpl;
90  import org.apache.myfaces.context.PartialViewContextFactoryImpl;
91  import org.apache.myfaces.el.DefaultPropertyResolver;
92  import org.apache.myfaces.el.VariableResolverImpl;
93  import org.apache.myfaces.el.unified.ResolverBuilderBase;
94  import org.apache.myfaces.lifecycle.LifecycleFactoryImpl;
95  import org.apache.myfaces.renderkit.RenderKitFactoryImpl;
96  import org.apache.myfaces.renderkit.html.HtmlRenderKitImpl;
97  import org.apache.myfaces.shared.config.MyfacesConfig;
98  import org.apache.myfaces.shared.util.ClassUtils;
99  import org.apache.myfaces.shared.util.LocaleUtils;
100 import org.apache.myfaces.shared.util.StateUtils;
101 import org.apache.myfaces.shared_impl.util.serial.DefaultSerialFactory;
102 import org.apache.myfaces.shared_impl.util.serial.SerialFactory;
103 import org.apache.myfaces.spi.FacesConfigurationMerger;
104 import org.apache.myfaces.spi.FacesConfigurationMergerFactory;
105 import org.apache.myfaces.util.ContainerUtils;
106 import org.apache.myfaces.util.ExternalSpecifications;
107 import org.apache.myfaces.view.ViewDeclarationLanguageFactoryImpl;
108 import org.apache.myfaces.view.facelets.tag.jsf.TagHandlerDelegateFactoryImpl;
109 import org.apache.myfaces.view.facelets.tag.ui.DebugPhaseListener;
110 import org.apache.myfaces.webapp.ManagedBeanDestroyerListener;
111 
112 /**
113  * Configures everything for a given context. The FacesConfigurator is independent of the concrete implementations that
114  * lie behind FacesConfigUnmarshaller and FacesConfigDispenser.
115  *
116  * @author Manfred Geiler (latest modification by $Author: lu4242 $)
117  * @version $Revision: 1518437 $ $Date: 2013-08-28 19:59:38 -0500 (Wed, 28 Aug 2013) $
118  */
119 @SuppressWarnings("deprecation")
120 public class FacesConfigurator
121 {
122     //private static final Log log = LogFactory.getLog(FacesConfigurator.class);
123     private static final Logger log = Logger.getLogger(FacesConfigurator.class.getName());
124 
125     private static final String DEFAULT_RENDER_KIT_CLASS = HtmlRenderKitImpl.class.getName();
126     private static final String DEFAULT_APPLICATION_FACTORY = ApplicationFactoryImpl.class.getName();
127     private static final String DEFAULT_EXTERNAL_CONTEXT_FACTORY = ExternalContextFactoryImpl.class.getName();
128     private static final String DEFAULT_FACES_CONTEXT_FACTORY = FacesContextFactoryImpl.class.getName();
129     private static final String DEFAULT_LIFECYCLE_FACTORY = LifecycleFactoryImpl.class.getName();
130     private static final String DEFAULT_RENDER_KIT_FACTORY = RenderKitFactoryImpl.class.getName();
131     private static final String DEFAULT_PARTIAL_VIEW_CONTEXT_FACTORY = PartialViewContextFactoryImpl.class.getName();
132     private static final String DEFAULT_VISIT_CONTEXT_FACTORY = VisitContextFactoryImpl.class.getName();
133     private static final String DEFAULT_VIEW_DECLARATION_LANGUAGE_FACTORY
134             = ViewDeclarationLanguageFactoryImpl.class.getName();
135     private static final String DEFAULT_EXCEPTION_HANDLER_FACTORY = ExceptionHandlerFactoryImpl.class.getName();
136     private static final String DEFAULT_TAG_HANDLER_DELEGATE_FACTORY = TagHandlerDelegateFactoryImpl.class.getName();
137     private static final String DEFAULT_FACES_CONFIG = "/WEB-INF/faces-config.xml";
138 
139     private final ExternalContext _externalContext;
140     private FacesConfigUnmarshaller<? extends FacesConfig> _unmarshaller;
141     private FacesConfigData _dispenser;
142     private AnnotationConfigurator _annotationConfigurator;
143 
144     private RuntimeConfig _runtimeConfig;
145 
146     private static long lastUpdate;
147 
148     public FacesConfigurator(ExternalContext externalContext)
149     {
150         if (externalContext == null)
151         {
152             throw new IllegalArgumentException("external context must not be null");
153         }
154         _externalContext = externalContext;
155 
156     }
157 
158     /**
159      * @param unmarshaller
160      *            the unmarshaller to set
161      */
162     public void setUnmarshaller(FacesConfigUnmarshaller<? extends FacesConfig> unmarshaller)
163     {
164         _unmarshaller = unmarshaller;
165     }
166 
167     /**
168      * @return the unmarshaller
169      */
170     protected FacesConfigUnmarshaller<? extends FacesConfig> getUnmarshaller()
171     {
172         if (_unmarshaller == null)
173         {
174             _unmarshaller = new DigesterFacesConfigUnmarshallerImpl(_externalContext);
175         }
176 
177         return _unmarshaller;
178     }
179 
180     /**
181      * @param dispenser
182      *            the dispenser to set
183      */
184     public void setDispenser(FacesConfigData dispenser)
185     {
186         _dispenser = dispenser;
187     }
188 
189     /**
190      * @return the dispenser
191      */
192     protected FacesConfigData getDispenser()
193     {
194         if (_dispenser == null)
195         {
196             _dispenser = new DigesterFacesConfigDispenserImpl();
197         }
198 
199         return _dispenser;
200     }
201 
202     public void setAnnotationConfigurator(AnnotationConfigurator configurator)
203     {
204         _annotationConfigurator = configurator;
205     }
206 
207     protected AnnotationConfigurator getAnnotationConfigurator()
208     {
209         if (_annotationConfigurator == null)
210         {
211             _annotationConfigurator = new AnnotationConfigurator();
212         }
213         return _annotationConfigurator;
214     }
215 
216     private long getResourceLastModified(String resource)
217     {
218         try
219         {
220             URL url = _externalContext.getResource(resource);
221             if (url != null)
222             {
223                 return getResourceLastModified(url);
224             }
225         }
226         catch (IOException e)
227         {
228             log.log(Level.SEVERE, "Could not read resource " + resource, e);
229         }
230         return 0;
231     }
232 
233     //Taken from trinidad URLUtils
234     private long getResourceLastModified(URL url) throws IOException
235     {
236         if ("file".equals(url.getProtocol()))
237         {
238             String externalForm = url.toExternalForm();
239             // Remove the "file:"
240             File file = new File(externalForm.substring(5));
241 
242             return file.lastModified();
243         }
244         else
245         {
246             return getResourceLastModified(url.openConnection());
247         }
248     }
249 
250     //Taken from trinidad URLUtils
251     private long getResourceLastModified(URLConnection connection) throws IOException
252     {
253         long modified;
254         if (connection instanceof JarURLConnection)
255         {
256             // The following hack is required to work-around a JDK bug.
257             // getLastModified() on a JAR entry URL delegates to the actual JAR file
258             // rather than the JAR entry.
259             // This opens internally, and does not close, an input stream to the JAR
260             // file.
261             // In turn, you cannot close it by yourself, because it's internal.
262             // The work-around is to get the modification date of the JAR file
263             // manually,
264             // and then close that connection again.
265 
266             URL jarFileUrl = ((JarURLConnection) connection).getJarFileURL();
267             URLConnection jarFileConnection = jarFileUrl.openConnection();
268 
269             try
270             {
271                 modified = jarFileConnection.getLastModified();
272             }
273             finally
274             {
275                 try
276                 {
277                     jarFileConnection.getInputStream().close();
278                 }
279                 catch (Exception exception)
280                 {
281                     // Ignored
282                 }
283             }
284         }
285         else
286         {
287             modified = connection.getLastModified();
288         }
289 
290         return modified;
291     }
292 
293     private long getLastModifiedTime()
294     {
295         long lastModified = 0;
296         long resModified;
297 
298         resModified = getResourceLastModified(DEFAULT_FACES_CONFIG);
299         if (resModified > lastModified)
300         {
301             lastModified = resModified;
302         }
303 
304         // perf: method getConfigFilesList() creates a ArrayList    
305         List<String> configFilesList = getConfigFilesList();
306         for (int i = 0, size = configFilesList.size(); i < size; i++)
307         {
308             String systemId = configFilesList.get(i);
309             resModified = getResourceLastModified(systemId);
310             if (resModified > lastModified)
311             {
312                 lastModified = resModified;
313             }
314         }
315 
316         return lastModified;
317     }
318 
319     public void update()
320     {
321         //Google App Engine does not allow to get last modified time of a file; 
322         //and when an application is running on GAE there is no way to update faces config xml file.
323         //thus, no need to check if the config file is modified.
324         if (ContainerUtils.isRunningOnGoogleAppEngine(_externalContext))
325         {
326             return;
327         }
328         long refreshPeriod = (MyfacesConfig.getCurrentInstance(_externalContext).getConfigRefreshPeriod()) * 1000;
329 
330         if (refreshPeriod > 0)
331         {
332             long ttl = lastUpdate + refreshPeriod;
333             if ((System.currentTimeMillis() > ttl) && (getLastModifiedTime() > ttl))
334             {
335                 try
336                 {
337                     purgeConfiguration();
338                 }
339                 catch (NoSuchMethodException e)
340                 {
341                     log.severe("Configuration objects do not support clean-up. Update aborted");
342 
343                     // We still want to update the timestamp to avoid running purge on every subsequent
344                     // request after this one.
345                     //
346                     lastUpdate = System.currentTimeMillis();
347 
348                     return;
349                 }
350                 catch (IllegalAccessException e)
351                 {
352                     log.severe("Error during configuration clean-up" + e.getMessage());
353                 }
354                 catch (InvocationTargetException e)
355                 {
356                     log.severe("Error during configuration clean-up" + e.getMessage());
357                 }
358                 configure();
359 
360                 // JSF 2.0 Publish PostConstructApplicationEvent after all configuration resources
361                 // has been parsed and processed
362                 FacesContext facesContext = FacesContext.getCurrentInstance();
363                 Application application = facesContext.getApplication();
364 
365                 application.publishEvent(facesContext, PostConstructApplicationEvent.class,
366                         Application.class, application);
367             }
368         }
369     }
370 
371     private void purgeConfiguration() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
372     {
373         final Class<?>[] NO_PARAMETER_TYPES = new Class[]{};
374         final Object[] NO_PARAMETERS = new Object[]{};
375 
376         Method appFactoryPurgeMethod;
377         Method renderKitPurgeMethod;
378         Method lifecyclePurgeMethod;
379 
380         // Check that we have access to all of the necessary purge methods before purging anything
381         //
382         ApplicationFactory applicationFactory
383                 = (ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
384         appFactoryPurgeMethod = applicationFactory.getClass().getMethod("purgeApplication", NO_PARAMETER_TYPES);
385 
386         RenderKitFactory renderKitFactory
387                 = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
388         renderKitPurgeMethod = renderKitFactory.getClass().getMethod("purgeRenderKit", NO_PARAMETER_TYPES);
389 
390         LifecycleFactory lifecycleFactory
391                 = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
392         lifecyclePurgeMethod = lifecycleFactory.getClass().getMethod("purgeLifecycle", NO_PARAMETER_TYPES);
393 
394         // If there was no exception so far, now we can purge
395         //
396         appFactoryPurgeMethod.invoke(applicationFactory, NO_PARAMETERS);
397         renderKitPurgeMethod.invoke(renderKitFactory, NO_PARAMETERS);
398         RuntimeConfig.getCurrentInstance(_externalContext).purge();
399         lifecyclePurgeMethod.invoke(lifecycleFactory, NO_PARAMETERS);
400 
401         // factories and serial factory need not be purged...
402     }
403 
404     public void configure() throws FacesException
405     {
406         // get FacesConfigurationMerger SPI implementation
407         FacesConfigurationMerger facesConfigurationMerger = FacesConfigurationMergerFactory
408                 .getFacesConfigurationMergerFactory(_externalContext).getFacesConfigurationMerger(_externalContext);
409 
410         // get all faces-config data, merge it and set it as Dispenser
411         setDispenser(facesConfigurationMerger.getFacesConfigData(_externalContext));
412 
413         configureFactories();
414         configureApplication();
415         configureRenderKits();
416 
417         //Now we can configure annotations
418         //getAnnotationConfigurator().configure(
419         //        ((ApplicationFactory) FactoryFinder.getFactory(
420         //                FactoryFinder.APPLICATION_FACTORY)).getApplication(),
421         //        getDispenser(), metadataComplete);
422 
423         configureRuntimeConfig();
424         configureLifecycle();
425         handleSerialFactory();
426         configureManagedBeanDestroyer();
427 
428         // record the time of update
429         lastUpdate = System.currentTimeMillis();
430     }
431 
432     private List<String> getConfigFilesList()
433     {
434         String configFiles = _externalContext.getInitParameter(FacesServlet.CONFIG_FILES_ATTR);
435         List<String> configFilesList = new ArrayList<String>();
436         if (configFiles != null)
437         {
438             StringTokenizer st = new StringTokenizer(configFiles, ",", false);
439             while (st.hasMoreTokens())
440             {
441                 String systemId = st.nextToken().trim();
442 
443                 if (DEFAULT_FACES_CONFIG.equals(systemId))
444                 {
445                     if (log.isLoggable(Level.WARNING))
446                     {
447                         log.warning(DEFAULT_FACES_CONFIG + " has been specified in the "
448                                 + FacesServlet.CONFIG_FILES_ATTR
449                                 + " context parameter of "
450                                 + "the deployment descriptor. This will automatically be removed, "
451                                 + "if we wouldn't do this, it would be loaded twice.  See JSF spec 1.1, 10.3.2");
452                     }
453                 }
454                 else
455                 {
456                     configFilesList.add(systemId);
457                 }
458             }
459         }
460         return configFilesList;
461     }
462 
463     private void configureFactories()
464     {
465         FacesConfigData dispenser = getDispenser();
466         setFactories(FactoryFinder.APPLICATION_FACTORY, dispenser.getApplicationFactoryIterator(),
467                 DEFAULT_APPLICATION_FACTORY);
468         setFactories(FactoryFinder.EXCEPTION_HANDLER_FACTORY, dispenser.getExceptionHandlerFactoryIterator(),
469                 DEFAULT_EXCEPTION_HANDLER_FACTORY);
470         setFactories(FactoryFinder.EXTERNAL_CONTEXT_FACTORY, dispenser.getExternalContextFactoryIterator(),
471                 DEFAULT_EXTERNAL_CONTEXT_FACTORY);
472         setFactories(FactoryFinder.FACES_CONTEXT_FACTORY, dispenser.getFacesContextFactoryIterator(),
473                 DEFAULT_FACES_CONTEXT_FACTORY);
474         setFactories(FactoryFinder.LIFECYCLE_FACTORY, dispenser.getLifecycleFactoryIterator(),
475                 DEFAULT_LIFECYCLE_FACTORY);
476         setFactories(FactoryFinder.RENDER_KIT_FACTORY, dispenser.getRenderKitFactoryIterator(),
477                 DEFAULT_RENDER_KIT_FACTORY);
478         setFactories(FactoryFinder.TAG_HANDLER_DELEGATE_FACTORY, dispenser.getTagHandlerDelegateFactoryIterator(),
479                 DEFAULT_TAG_HANDLER_DELEGATE_FACTORY);
480         setFactories(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY, dispenser.getPartialViewContextFactoryIterator(),
481                 DEFAULT_PARTIAL_VIEW_CONTEXT_FACTORY);
482         setFactories(FactoryFinder.VISIT_CONTEXT_FACTORY, dispenser.getVisitContextFactoryIterator(),
483                 DEFAULT_VISIT_CONTEXT_FACTORY);
484         setFactories(FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY,
485                 dispenser.getViewDeclarationLanguageFactoryIterator(),
486                 DEFAULT_VIEW_DECLARATION_LANGUAGE_FACTORY);
487     }
488 
489     private void setFactories(String factoryName, Collection<String> factories, String defaultFactory)
490     {
491         FactoryFinder.setFactory(factoryName, defaultFactory);
492         for (String factory : factories)
493         {
494             if (!factory.equals(defaultFactory))
495             {
496                 FactoryFinder.setFactory(factoryName, factory);
497             }
498         }
499     }
500 
501     private void configureApplication()
502     {
503         Application application = ((ApplicationFactory)
504                 FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY)).getApplication();
505 
506         FacesConfigData dispenser = getDispenser();
507         application.setActionListener(ClassUtils.buildApplicationObject(ActionListener.class,
508                 dispenser.getActionListenerIterator(), null));
509 
510         if (dispenser.getDefaultLocale() != null)
511         {
512             application.setDefaultLocale(LocaleUtils.toLocale(dispenser.getDefaultLocale()));
513         }
514 
515         if (dispenser.getDefaultRenderKitId() != null)
516         {
517             application.setDefaultRenderKitId(dispenser.getDefaultRenderKitId());
518         }
519 
520         if (dispenser.getMessageBundle() != null)
521         {
522             application.setMessageBundle(dispenser.getMessageBundle());
523         }
524 
525         application.setNavigationHandler(ClassUtils.buildApplicationObject(NavigationHandler.class,
526                 ConfigurableNavigationHandler.class,
527                 BackwardsCompatibleNavigationHandlerWrapper.class,
528                 dispenser.getNavigationHandlerIterator(),
529                 application.getNavigationHandler()));
530 
531         application.setStateManager(ClassUtils.buildApplicationObject(StateManager.class,
532                 dispenser.getStateManagerIterator(),
533                 application.getStateManager()));
534 
535         application.setResourceHandler(ClassUtils.buildApplicationObject(ResourceHandler.class,
536                 dispenser.getResourceHandlerIterator(),
537                 application.getResourceHandler()));
538 
539         List<Locale> locales = new ArrayList<Locale>();
540         for (String locale : dispenser.getSupportedLocalesIterator())
541         {
542             locales.add(LocaleUtils.toLocale(locale));
543         }
544 
545         application.setSupportedLocales(locales);
546 
547         application.setViewHandler(ClassUtils.buildApplicationObject(ViewHandler.class,
548                 dispenser.getViewHandlerIterator(),
549                 application.getViewHandler()));
550         for (SystemEventListener systemEventListener : dispenser.getSystemEventListeners())
551         {
552 
553 
554             try
555             {
556                 //note here used to be an instantiation to deal with the explicit source type in the registration,
557                 // that cannot work because all system events need to have the source being passed in the constructor
558                 //instead we now  rely on the standard system event types and map them to their appropriate
559                 // constructor types
560                 Class eventClass = ClassUtils.classForName((systemEventListener.getSystemEventClass() != null)
561                         ? systemEventListener.getSystemEventClass()
562                         : SystemEvent.class.getName());
563                 //application.subscribeToEvent(
564                 //    (Class<? extends SystemEvent>)eventClass ,
565                 //        (Class<?>)ClassUtils.classForName((systemEventListener.getSourceClass() != null) ? systemEventListener.getSourceClass(): getDefaultSourcClassForSystemEvent(eventClass) ), //Application.class???
566                 //        (javax.faces.event.SystemEventListener)ClassUtils.newInstance(systemEventListener.getSystemEventListenerClass()));
567 
568                 if (systemEventListener.getSourceClass() != null && systemEventListener.getSourceClass().length() > 0)
569                 {
570                     application.subscribeToEvent(
571                             (Class<? extends SystemEvent>) eventClass,
572                             ClassUtils.classForName(systemEventListener.getSourceClass()),
573                             (javax.faces.event.SystemEventListener)
574                                     ClassUtils.newInstance(systemEventListener.getSystemEventListenerClass()));
575                 }
576                 else
577                 {
578                     application.subscribeToEvent(
579                             (Class<? extends SystemEvent>) eventClass,
580                             (javax.faces.event.SystemEventListener)
581                                     ClassUtils.newInstance(systemEventListener.getSystemEventListenerClass()));
582                 }
583             }
584             catch (ClassNotFoundException e)
585             {
586                 log.log(Level.SEVERE, "System event listener could not be initialized, reason:", e);
587             }
588         }
589 
590 
591         for (String componentType : dispenser.getComponentTypes())
592         {
593             application.addComponent(componentType, dispenser.getComponentClass(componentType));
594         }
595 
596         for (String converterId : dispenser.getConverterIds())
597         {
598             application.addConverter(converterId, dispenser.getConverterClassById(converterId));
599         }
600 
601         for (String converterClass : dispenser.getConverterClasses())
602         {
603             try
604             {
605                 application.addConverter(ClassUtils.simpleClassForName(converterClass),
606                         dispenser.getConverterClassByClass(converterClass));
607             }
608             catch (Exception ex)
609             {
610                 log.log(Level.SEVERE, "Converter could not be added. Reason:", ex);
611             }
612         }
613 
614         for (String validatorId : dispenser.getValidatorIds())
615         {
616             application.addValidator(validatorId, dispenser.getValidatorClass(validatorId));
617         }
618 
619         // programmatically add the BeanValidator if the following requirements are met:
620         //     - bean validation has not been disabled
621         //     - bean validation is available in the classpath
622         String beanValidatorDisabled = _externalContext.getInitParameter(
623                 BeanValidator.DISABLE_DEFAULT_BEAN_VALIDATOR_PARAM_NAME);
624         final boolean defaultBeanValidatorDisabled = (beanValidatorDisabled != null
625                 && beanValidatorDisabled.toLowerCase().equals("true"));
626         boolean beanValidatorInstalledProgrammatically = false;
627         if (!defaultBeanValidatorDisabled
628                 && ExternalSpecifications.isBeanValidationAvailable())
629         {
630             // add the BeanValidator as default validator
631             application.addDefaultValidatorId(BeanValidator.VALIDATOR_ID);
632             beanValidatorInstalledProgrammatically = true;
633         }
634 
635         // add the default-validators from the config files
636         for (String validatorId : dispenser.getDefaultValidatorIds())
637         {
638             application.addDefaultValidatorId(validatorId);
639         }
640 
641         // do some checks if the BeanValidator was not installed as a
642         // default-validator programmatically, but via a config file.
643         if (!beanValidatorInstalledProgrammatically
644                 && application.getDefaultValidatorInfo()
645                 .containsKey(BeanValidator.VALIDATOR_ID))
646         {
647             if (!ExternalSpecifications.isBeanValidationAvailable())
648             {
649                 // the BeanValidator was installed via a config file,
650                 // but bean validation is not available
651                 log.log(Level.WARNING, "The BeanValidator was installed as a " +
652                         "default-validator from a faces-config file, but bean " +
653                         "validation is not available on the classpath, " +
654                         "thus it will not work!");
655             }
656             else if (defaultBeanValidatorDisabled)
657             {
658                 // the user disabled the default bean validator in web.xml,
659                 // but a config file added it, which is ok with the spec
660                 // (section 11.1.3: "though manual installation is still possible")
661                 // --> inform the user about this scenario
662                 log.log(Level.INFO, "The BeanValidator was disabled as a " +
663                         "default-validator via the config parameter " +
664                         BeanValidator.DISABLE_DEFAULT_BEAN_VALIDATOR_PARAM_NAME +
665                         " in web.xml, but a faces-config file added it, " +
666                         "thus it actually was installed as a default-validator.");
667             }
668         }
669 
670         for (Behavior behavior : dispenser.getBehaviors())
671         {
672             application.addBehavior(behavior.getBehaviorId(), behavior.getBehaviorClass());
673         }
674 
675         RuntimeConfig runtimeConfig = getRuntimeConfig();
676 
677         if (MyfacesConfig.getCurrentInstance(_externalContext).isSupportJSPAndFacesEL())
678         {
679             // If no JSP and old Faces EL, there is no need to initialize PropertyResolver
680             // and VariableResolver stuff.
681             runtimeConfig.setPropertyResolverChainHead(ClassUtils.buildApplicationObject(PropertyResolver.class,
682                     dispenser.getPropertyResolverIterator(),
683                     new DefaultPropertyResolver()));
684     
685             runtimeConfig.setVariableResolverChainHead(ClassUtils.buildApplicationObject(VariableResolver.class,
686                     dispenser.getVariableResolverIterator(),
687                     new VariableResolverImpl()));
688         }
689     }
690 
691     /**
692      * A mapper for the handful of system listener defaults
693      * since every default mapper has the source type embedded
694      * in the constructor we can rely on introspection for the
695      * default mapping
696      *
697      * @param systemEventClass the system listener class which has to be checked
698      * @return
699      */
700     String getDefaultSourcClassForSystemEvent(Class systemEventClass)
701     {
702         Constructor[] constructors = systemEventClass.getConstructors();
703         for (Constructor constr : constructors)
704         {
705             Class[] parms = constr.getParameterTypes();
706             if (parms == null || parms.length != 1)
707             {
708                 //for standard types we have only one parameter representing the type
709                 continue;
710             }
711             return parms[0].getName();
712         }
713         log.warning("The SystemEvent source type for " + systemEventClass.getName()
714                 + " could not be detected, either register it manually or use a constructor argument "
715                 + "for auto detection, defaulting now to java.lang.Object");
716         return "java.lang.Object";
717     }
718 
719 
720     protected RuntimeConfig getRuntimeConfig()
721     {
722         if (_runtimeConfig == null)
723         {
724             _runtimeConfig = RuntimeConfig.getCurrentInstance(_externalContext);
725         }
726         return _runtimeConfig;
727     }
728 
729     public void setRuntimeConfig(RuntimeConfig runtimeConfig)
730     {
731         _runtimeConfig = runtimeConfig;
732     }
733 
734     private void configureRuntimeConfig()
735     {
736         RuntimeConfig runtimeConfig = RuntimeConfig.getCurrentInstance(_externalContext);
737 
738         FacesConfigData dispenser = getDispenser();
739         for (ManagedBean bean : dispenser.getManagedBeans())
740         {
741             if (log.isLoggable(Level.WARNING) && runtimeConfig.getManagedBean(bean.getManagedBeanName()) != null)
742             {
743                 log.warning("More than one managed bean w/ the name of '" + bean.getManagedBeanName()
744                         + "' - only keeping the last ");
745             }
746 
747             runtimeConfig.addManagedBean(bean.getManagedBeanName(), bean);
748 
749         }
750 
751         removePurgedBeansFromSessionAndApplication(runtimeConfig);
752 
753         for (NavigationRule rule : dispenser.getNavigationRules())
754         {
755             runtimeConfig.addNavigationRule(rule);
756         }
757 
758         for (String converterClassName : dispenser.getConverterConfigurationByClassName())
759         {
760             runtimeConfig.addConverterConfiguration(converterClassName,
761                     _dispenser.getConverterConfiguration(converterClassName));
762         }
763 
764         for (ResourceBundle bundle : dispenser.getResourceBundles())
765         {
766             runtimeConfig.addResourceBundle(bundle);
767         }
768 
769         for (String className : dispenser.getElResolvers())
770         {
771             runtimeConfig.addFacesConfigElResolver((ELResolver) ClassUtils.newInstance(className, ELResolver.class));
772         }
773 
774         runtimeConfig.setFacesVersion(dispenser.getFacesVersion());
775 
776         runtimeConfig.setNamedEventManager(new NamedEventManager());
777 
778         for (NamedEvent event : dispenser.getNamedEvents())
779         {
780             try
781             {
782                 Class<? extends ComponentSystemEvent> clazz = ClassUtils.classForName(event.getEventClass());
783                 runtimeConfig.getNamedEventManager().addNamedEvent(event.getShortName(), clazz);
784             }
785             catch (ClassNotFoundException e)
786             {
787                 log.log(Level.SEVERE, "Named event could not be initialized, reason:", e);
788             }
789         }
790 
791         String comparatorClass = _externalContext.getInitParameter(ResolverBuilderBase.EL_RESOLVER_COMPARATOR);
792 
793         if (comparatorClass != null && !"".equals(comparatorClass))
794         {
795             // get the comparator class
796             Class<Comparator<ELResolver>> clazz;
797             try
798             {
799                 clazz = ClassUtils.classForName(comparatorClass);
800                 // create the instance
801                 Comparator<ELResolver> comparator = clazz.newInstance();
802 
803                 runtimeConfig.setELResolverComparator(comparator);
804             }
805             catch (Exception e)
806             {
807                 if (log.isLoggable(Level.SEVERE))
808                 {
809                     log.log(Level.SEVERE, "Cannot instantiate EL Resolver Comparator " + comparatorClass
810                             + " . Check org.apache.myfaces.EL_RESOLVER_COMPARATOR web config param. "
811                             + "Initialization continues with no comparator used.", e);
812                 }
813             }
814         }
815         else
816         {
817             runtimeConfig.setELResolverComparator(null);
818         }
819     }
820 
821     private void removePurgedBeansFromSessionAndApplication(RuntimeConfig runtimeConfig)
822     {
823         Map<String, ManagedBean> oldManagedBeans = runtimeConfig.getManagedBeansNotReaddedAfterPurge();
824         if (oldManagedBeans != null)
825         {
826             for (Map.Entry<String, ManagedBean> entry : oldManagedBeans.entrySet())
827             {
828                 ManagedBean bean = entry.getValue();
829 
830                 String scope = bean.getManagedBeanScope();
831 
832                 if (scope != null && scope.equalsIgnoreCase("session"))
833                 {
834                     _externalContext.getSessionMap().remove(entry.getKey());
835                 }
836                 else if (scope != null && scope.equalsIgnoreCase("application"))
837                 {
838                     _externalContext.getApplicationMap().remove(entry.getKey());
839                 }
840             }
841         }
842 
843         runtimeConfig.resetManagedBeansNotReaddedAfterPurge();
844     }
845 
846     private void configureRenderKits()
847     {
848         RenderKitFactory renderKitFactory
849                 = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
850 
851         FacesConfigData dispenser = getDispenser();
852         for (String renderKitId : dispenser.getRenderKitIds())
853         {
854             Collection<String> renderKitClass = dispenser.getRenderKitClasses(renderKitId);
855 
856             if (renderKitClass.isEmpty())
857             {
858                 renderKitClass = new ArrayList<String>(1);
859                 renderKitClass.add(DEFAULT_RENDER_KIT_CLASS);
860             }
861 
862             //RenderKit renderKit = (RenderKit) ClassUtils.newInstance(renderKitClass);
863             RenderKit renderKit = (RenderKit) ClassUtils.buildApplicationObject(RenderKit.class, renderKitClass, null);
864 
865             for (Renderer element : dispenser.getRenderers(renderKitId))
866             {
867                 javax.faces.render.Renderer renderer;
868 
869                 try
870                 {
871                     renderer = (javax.faces.render.Renderer) ClassUtils.newInstance(element.getRendererClass());
872                 }
873                 catch (Throwable e)
874                 {
875                     // ignore the failure so that the render kit is configured
876                     log.log(Level.SEVERE, "failed to configure class " + element.getRendererClass(), e);
877                     continue;
878                 }
879 
880                 renderKit.addRenderer(element.getComponentFamily(), element.getRendererType(), renderer);
881             }
882             
883             // Add in client behavior renderers.
884             Collection<ClientBehaviorRenderer> clientBehaviorRenderers
885                         = dispenser.getClientBehaviorRenderers(renderKitId);
886 
887             for (ClientBehaviorRenderer clientBehaviorRenderer : clientBehaviorRenderers)
888             {
889                 try
890                 {
891                     javax.faces.render.ClientBehaviorRenderer behaviorRenderer
892                             = (javax.faces.render.ClientBehaviorRenderer)
893                             ClassUtils.newInstance(clientBehaviorRenderer.getRendererClass());
894 
895                     renderKit.addClientBehaviorRenderer(clientBehaviorRenderer.getRendererType(), behaviorRenderer);
896                 }
897 
898                 catch (Throwable e)
899                 {
900                     // Ignore.
901 
902                     if (log.isLoggable(Level.SEVERE))
903                     {
904                         log.log(Level.SEVERE, "failed to configure client behavior renderer class " +
905                                 clientBehaviorRenderer.getRendererClass(), e);
906                     }
907                 }
908             }
909 
910             renderKitFactory.addRenderKit(renderKitId, renderKit);
911         }
912     }
913 
914     private void configureLifecycle()
915     {
916         // create the lifecycle used by the app
917         LifecycleFactory lifecycleFactory
918                 = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
919         
920         //Lifecycle lifecycle = lifecycleFactory.getLifecycle(getLifecycleId());
921         for (Iterator<String> it = lifecycleFactory.getLifecycleIds(); it.hasNext();)
922         {
923             Lifecycle lifecycle = lifecycleFactory.getLifecycle(it.next());
924             
925             // add phase listeners
926             for (String listenerClassName : getDispenser().getLifecyclePhaseListeners())
927             {
928                 try
929                 {
930                     lifecycle.addPhaseListener((PhaseListener)
931                             ClassUtils.newInstance(listenerClassName, PhaseListener.class));
932                 }
933                 catch (ClassCastException e)
934                 {
935                     log.severe("Class " + listenerClassName + " does not implement PhaseListener");
936                 }
937             }
938 
939             // if ProjectStage is Development, install the DebugPhaseListener
940             FacesContext facesContext = FacesContext.getCurrentInstance();
941             if (facesContext.isProjectStage(ProjectStage.Development) &&
942                     MyfacesConfig.getCurrentInstance(facesContext.getExternalContext()).isDebugPhaseListenerEnabled())
943             {
944                 lifecycle.addPhaseListener(new DebugPhaseListener());
945             }
946         }
947     }
948 
949     /*
950     private String getLifecycleId()
951     {
952         String id = _externalContext.getInitParameter(FacesServlet.LIFECYCLE_ID_ATTR);
953 
954         if (id != null)
955         {
956             return id;
957         }
958 
959         return LifecycleFactory.DEFAULT_LIFECYCLE;
960     }*/
961 
962     private void handleSerialFactory()
963     {
964 
965         String serialProvider = _externalContext.getInitParameter(StateUtils.SERIAL_FACTORY);
966         SerialFactory serialFactory = null;
967 
968         if (serialProvider == null)
969         {
970             serialFactory = new DefaultSerialFactory();
971         }
972         else
973         {
974             try
975             {
976                 serialFactory = (SerialFactory) ClassUtils.newInstance(serialProvider);
977 
978             }
979             catch (ClassCastException e)
980             {
981                 log.log(Level.SEVERE, "Make sure '" + serialProvider + "' implements the correct interface", e);
982             }
983             catch (Exception e)
984             {
985                 log.log(Level.SEVERE, "", e);
986             }
987             finally
988             {
989                 if (serialFactory == null)
990                 {
991                     serialFactory = new DefaultSerialFactory();
992                     log.severe("Using default serialization provider");
993                 }
994             }
995 
996         }
997 
998         log.info("Serialization provider : " + serialFactory.getClass());
999         _externalContext.getApplicationMap().put(StateUtils.SERIAL_FACTORY, serialFactory);
1000     }
1001 
1002     private void configureManagedBeanDestroyer()
1003     {
1004         FacesContext facesContext = FacesContext.getCurrentInstance();
1005         ExternalContext externalContext = facesContext.getExternalContext();
1006         Map<String, Object> applicationMap = externalContext.getApplicationMap();
1007         Application application = facesContext.getApplication();
1008 
1009         // get RuntimeConfig and LifecycleProvider
1010         RuntimeConfig runtimeConfig = RuntimeConfig.getCurrentInstance(externalContext);
1011         LifecycleProvider lifecycleProvider = LifecycleProviderFactory
1012                 .getLifecycleProviderFactory(externalContext).getLifecycleProvider(externalContext);
1013 
1014         // create ManagedBeanDestroyer
1015         ManagedBeanDestroyer mbDestroyer
1016                 = new ManagedBeanDestroyer(lifecycleProvider, runtimeConfig);
1017 
1018         // subscribe ManagedBeanDestroyer as listener for needed events 
1019         application.subscribeToEvent(PreDestroyCustomScopeEvent.class, mbDestroyer);
1020         application.subscribeToEvent(PreDestroyViewMapEvent.class, mbDestroyer);
1021 
1022         // get ManagedBeanDestroyerListener instance 
1023         ManagedBeanDestroyerListener listener = (ManagedBeanDestroyerListener)
1024                 applicationMap.get(ManagedBeanDestroyerListener.APPLICATION_MAP_KEY);
1025         if (listener != null)
1026         {
1027             // set the instance on the listener
1028             listener.setManagedBeanDestroyer(mbDestroyer);
1029         }
1030         else
1031         {
1032             log.log(Level.SEVERE, "No ManagedBeanDestroyerListener instance found, thus "
1033                     + "@PreDestroy methods won't get called in every case. "
1034                     + "This instance needs to be published before configuration is started.");
1035         }
1036     }
1037 
1038 }