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