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.Collections;
32  import java.util.Comparator;
33  import java.util.HashMap;
34  import java.util.Iterator;
35  import java.util.List;
36  import java.util.Locale;
37  import java.util.Map;
38  import java.util.Set;
39  import java.util.StringTokenizer;
40  import java.util.concurrent.CopyOnWriteArrayList;
41  import java.util.logging.Level;
42  import java.util.logging.Logger;
43  
44  import javax.el.ELResolver;
45  import javax.faces.FacesException;
46  import javax.faces.FacesWrapper;
47  import javax.faces.FactoryFinder;
48  import javax.faces.application.Application;
49  import javax.faces.application.ApplicationFactory;
50  import javax.faces.application.ConfigurableNavigationHandler;
51  import javax.faces.application.NavigationHandler;
52  import javax.faces.application.ProjectStage;
53  import javax.faces.application.ResourceHandler;
54  import javax.faces.application.StateManager;
55  import javax.faces.application.ViewHandler;
56  import javax.faces.context.ExternalContext;
57  import javax.faces.context.FacesContext;
58  import javax.faces.el.PropertyResolver;
59  import javax.faces.el.VariableResolver;
60  import javax.faces.event.ActionListener;
61  import javax.faces.event.ComponentSystemEvent;
62  import javax.faces.event.PhaseListener;
63  import javax.faces.event.PostConstructApplicationEvent;
64  import javax.faces.event.PreDestroyCustomScopeEvent;
65  import javax.faces.event.PreDestroyViewMapEvent;
66  import javax.faces.event.SystemEvent;
67  import javax.faces.flow.FlowHandler;
68  import javax.faces.flow.FlowHandlerFactory;
69  import javax.faces.lifecycle.ClientWindow;
70  import javax.faces.lifecycle.Lifecycle;
71  import javax.faces.lifecycle.LifecycleFactory;
72  import javax.faces.render.RenderKit;
73  import javax.faces.render.RenderKitFactory;
74  import javax.faces.validator.BeanValidator;
75  import javax.faces.webapp.FacesServlet;
76  
77  import org.apache.commons.collections.Predicate;
78  import org.apache.myfaces.application.ApplicationFactoryImpl;
79  import org.apache.myfaces.application.BackwardsCompatibleNavigationHandlerWrapper;
80  import org.apache.myfaces.component.visit.VisitContextFactoryImpl;
81  import org.apache.myfaces.config.annotation.AnnotationConfigurator;
82  import org.apache.myfaces.config.annotation.LifecycleProvider;
83  import org.apache.myfaces.config.annotation.LifecycleProviderFactory;
84  import org.apache.myfaces.config.element.Behavior;
85  import org.apache.myfaces.config.element.ClientBehaviorRenderer;
86  import org.apache.myfaces.config.element.ComponentTagDeclaration;
87  import org.apache.myfaces.config.element.ContractMapping;
88  import org.apache.myfaces.config.element.FaceletsProcessing;
89  import org.apache.myfaces.config.element.FacesConfig;
90  import org.apache.myfaces.config.element.FacesConfigData;
91  import org.apache.myfaces.config.element.FacesFlowCall;
92  import org.apache.myfaces.config.element.FacesFlowDefinition;
93  import org.apache.myfaces.config.element.FacesFlowMethodCall;
94  import org.apache.myfaces.config.element.FacesFlowMethodParameter;
95  import org.apache.myfaces.config.element.FacesFlowParameter;
96  import org.apache.myfaces.config.element.FacesFlowReturn;
97  import org.apache.myfaces.config.element.FacesFlowSwitch;
98  import org.apache.myfaces.config.element.FacesFlowView;
99  import org.apache.myfaces.config.element.ManagedBean;
100 import org.apache.myfaces.config.element.NamedEvent;
101 import org.apache.myfaces.config.element.NavigationCase;
102 import org.apache.myfaces.config.element.NavigationRule;
103 import org.apache.myfaces.config.element.Renderer;
104 import org.apache.myfaces.config.element.ResourceBundle;
105 import org.apache.myfaces.config.element.SystemEventListener;
106 import org.apache.myfaces.config.impl.digester.DigesterFacesConfigDispenserImpl;
107 import org.apache.myfaces.config.impl.digester.DigesterFacesConfigUnmarshallerImpl;
108 import org.apache.myfaces.context.ExceptionHandlerFactoryImpl;
109 import org.apache.myfaces.context.ExternalContextFactoryImpl;
110 import org.apache.myfaces.context.FacesContextFactoryImpl;
111 import org.apache.myfaces.context.PartialViewContextFactoryImpl;
112 import org.apache.myfaces.context.servlet.ServletFlashFactoryImpl;
113 import org.apache.myfaces.el.DefaultPropertyResolver;
114 import org.apache.myfaces.el.VariableResolverImpl;
115 import org.apache.myfaces.el.unified.ResolverBuilderBase;
116 import org.apache.myfaces.lifecycle.ClientWindowFactoryImpl;
117 import org.apache.myfaces.flow.FlowCallNodeImpl;
118 import org.apache.myfaces.flow.FlowHandlerFactoryImpl;
119 import org.apache.myfaces.flow.FlowImpl;
120 import org.apache.myfaces.flow.MethodCallNodeImpl;
121 import org.apache.myfaces.flow.ParameterImpl;
122 import org.apache.myfaces.flow.ReturnNodeImpl;
123 import org.apache.myfaces.flow.SwitchCaseImpl;
124 import org.apache.myfaces.flow.SwitchNodeImpl;
125 import org.apache.myfaces.flow.ViewNodeImpl;
126 import org.apache.myfaces.flow.impl.AnnotatedFlowConfigurator;
127 import org.apache.myfaces.lifecycle.LifecycleFactoryImpl;
128 import org.apache.myfaces.renderkit.RenderKitFactoryImpl;
129 import org.apache.myfaces.renderkit.html.HtmlRenderKitImpl;
130 import org.apache.myfaces.shared.config.MyfacesConfig;
131 import org.apache.myfaces.shared.util.ClassUtils;
132 import org.apache.myfaces.shared.util.LocaleUtils;
133 import org.apache.myfaces.shared.util.StateUtils;
134 import org.apache.myfaces.shared.util.StringUtils;
135 import org.apache.myfaces.shared.util.WebConfigParamUtils;
136 import org.apache.myfaces.shared_impl.util.serial.DefaultSerialFactory;
137 import org.apache.myfaces.shared_impl.util.serial.SerialFactory;
138 import org.apache.myfaces.cdi.dependent.BeanEntry;
139 import org.apache.myfaces.config.element.ViewPoolMapping;
140 import org.apache.myfaces.config.element.facelets.FaceletTagLibrary;
141 import org.apache.myfaces.lifecycle.LifecycleImpl;
142 import org.apache.myfaces.renderkit.LazyRenderKit;
143 import org.apache.myfaces.spi.FacesConfigurationMerger;
144 import org.apache.myfaces.spi.FacesConfigurationMergerFactory;
145 import org.apache.myfaces.spi.InjectionProvider;
146 import org.apache.myfaces.spi.InjectionProviderException;
147 import org.apache.myfaces.spi.InjectionProviderFactory;
148 import org.apache.myfaces.spi.ResourceLibraryContractsProvider;
149 import org.apache.myfaces.spi.ResourceLibraryContractsProviderFactory;
150 import org.apache.myfaces.util.ContainerUtils;
151 import org.apache.myfaces.util.ExternalSpecifications;
152 import org.apache.myfaces.util.NavigationUtils;
153 import org.apache.myfaces.view.ViewDeclarationLanguageFactoryImpl;
154 import org.apache.myfaces.view.facelets.el.ELText;
155 import org.apache.myfaces.view.facelets.impl.FaceletCacheFactoryImpl;
156 import org.apache.myfaces.view.facelets.tag.jsf.TagHandlerDelegateFactoryImpl;
157 import org.apache.myfaces.view.facelets.tag.ui.DebugPhaseListener;
158 import org.apache.myfaces.webapp.ManagedBeanDestroyerListener;
159 
160 /**
161  * Configures everything for a given context. The FacesConfigurator is independent of the concrete implementations that
162  * lie behind FacesConfigUnmarshaller and FacesConfigDispenser.
163  *
164  * @author Manfred Geiler (latest modification by $Author$)
165  * @version $Revision$ $Date$
166  */
167 @SuppressWarnings("deprecation")
168 public class FacesConfigurator
169 {
170     private final Class<?>[] NO_PARAMETER_TYPES = new Class[]{};
171     private final Object[] NO_PARAMETERS = new Object[]{};
172 
173     //private static final Log log = LogFactory.getLog(FacesConfigurator.class);
174     private static final Logger log = Logger.getLogger(FacesConfigurator.class.getName());
175 
176     private static final String DEFAULT_RENDER_KIT_CLASS = HtmlRenderKitImpl.class.getName();
177     private static final String DEFAULT_APPLICATION_FACTORY = ApplicationFactoryImpl.class.getName();
178     private static final String DEFAULT_EXTERNAL_CONTEXT_FACTORY = ExternalContextFactoryImpl.class.getName();
179     private static final String DEFAULT_FACES_CONTEXT_FACTORY = FacesContextFactoryImpl.class.getName();
180     private static final String DEFAULT_LIFECYCLE_FACTORY = LifecycleFactoryImpl.class.getName();
181     private static final String DEFAULT_RENDER_KIT_FACTORY = RenderKitFactoryImpl.class.getName();
182     private static final String DEFAULT_PARTIAL_VIEW_CONTEXT_FACTORY = PartialViewContextFactoryImpl.class.getName();
183     private static final String DEFAULT_VISIT_CONTEXT_FACTORY = VisitContextFactoryImpl.class.getName();
184     private static final String DEFAULT_VIEW_DECLARATION_LANGUAGE_FACTORY
185             = ViewDeclarationLanguageFactoryImpl.class.getName();
186     private static final String DEFAULT_EXCEPTION_HANDLER_FACTORY = ExceptionHandlerFactoryImpl.class.getName();
187     private static final String DEFAULT_TAG_HANDLER_DELEGATE_FACTORY = TagHandlerDelegateFactoryImpl.class.getName();
188     private static final String DEFAULT_FACELET_CACHE_FACTORY = FaceletCacheFactoryImpl.class.getName();
189     private static final String DEFAULT_FLASH_FACTORY = ServletFlashFactoryImpl.class.getName();
190     private static final String DEFAULT_CLIENT_WINDOW_FACTORY = ClientWindowFactoryImpl.class.getName();
191     private static final String DEFAULT_FLOW_FACTORY = FlowHandlerFactoryImpl.class.getName();
192     private static final String DEFAULT_FACES_CONFIG = "/WEB-INF/faces-config.xml";
193 
194     private static final String INJECTED_BEAN_STORAGE_KEY = "org.apache.myfaces.spi.BEAN_ENTRY_STORAGE";
195 
196     /**
197      * Set this attribute if the current configuration requires enable window mode
198      */
199     public static final String ENABLE_DEFAULT_WINDOW_MODE = 
200         "org.apache.myfaces.ENABLE_DEFAULT_WINDOW_MODE";
201     
202     private final static String PARAM_FACELETS_LIBRARIES_DEPRECATED = "facelets.LIBRARIES";
203     private final static String[] PARAMS_FACELETS_LIBRARIES = {ViewHandler.FACELETS_LIBRARIES_PARAM_NAME,
204         PARAM_FACELETS_LIBRARIES_DEPRECATED};
205 
206     private final ExternalContext _externalContext;
207     private FacesContext _facesContext;
208     private FacesConfigUnmarshaller<? extends FacesConfig> _unmarshaller;
209     private FacesConfigData _dispenser;
210     private AnnotationConfigurator _annotationConfigurator;
211 
212     private RuntimeConfig _runtimeConfig;
213     
214     private Application _application;
215     
216     private InjectionProvider _injectionProvider;
217 
218     private static long lastUpdate;
219 
220     public FacesConfigurator(ExternalContext externalContext)
221     {
222         if (externalContext == null)
223         {
224             throw new IllegalArgumentException("external context must not be null");
225         }
226         _externalContext = externalContext;
227 
228         // In dev mode a new Faces Configurator is created for every request so only
229         // create a new bean storage list if we don't already have one which will be
230         // the case first time through during init.
231         if (_externalContext.getApplicationMap().get(INJECTED_BEAN_STORAGE_KEY) == null) 
232         {
233             _externalContext.getApplicationMap().put(INJECTED_BEAN_STORAGE_KEY, new CopyOnWriteArrayList());
234         }
235     }
236 
237     /**
238      * @param unmarshaller
239      *            the unmarshaller to set
240      */
241     public void setUnmarshaller(FacesConfigUnmarshaller<? extends FacesConfig> unmarshaller)
242     {
243         _unmarshaller = unmarshaller;
244     }
245 
246     /**
247      * @return the unmarshaller
248      */
249     protected FacesConfigUnmarshaller<? extends FacesConfig> getUnmarshaller()
250     {
251         if (_unmarshaller == null)
252         {
253             _unmarshaller = new DigesterFacesConfigUnmarshallerImpl(_externalContext);
254         }
255 
256         return _unmarshaller;
257     }
258 
259     /**
260      * @param dispenser
261      *            the dispenser to set
262      */
263     public void setDispenser(FacesConfigData dispenser)
264     {
265         _dispenser = dispenser;
266     }
267 
268     /**
269      * @return the dispenser
270      */
271     protected FacesConfigData getDispenser()
272     {
273         if (_dispenser == null)
274         {
275             _dispenser = new DigesterFacesConfigDispenserImpl();
276         }
277 
278         return _dispenser;
279     }
280 
281     public void setAnnotationConfigurator(AnnotationConfigurator configurator)
282     {
283         _annotationConfigurator = configurator;
284     }
285 
286     protected AnnotationConfigurator getAnnotationConfigurator()
287     {
288         if (_annotationConfigurator == null)
289         {
290             _annotationConfigurator = new AnnotationConfigurator();
291         }
292         return _annotationConfigurator;
293     }
294 
295     private long getResourceLastModified(String resource)
296     {
297         try
298         {
299             URL url = _externalContext.getResource(resource);
300             if (url != null)
301             {
302                 return getResourceLastModified(url);
303             }
304         }
305         catch (IOException e)
306         {
307             log.log(Level.SEVERE, "Could not read resource " + resource, e);
308         }
309         return 0;
310     }
311 
312     //Taken from trinidad URLUtils
313     private long getResourceLastModified(URL url) throws IOException
314     {
315         if ("file".equals(url.getProtocol()))
316         {
317             String externalForm = url.toExternalForm();
318             // Remove the "file:"
319             File file = new File(externalForm.substring(5));
320 
321             return file.lastModified();
322         }
323         else
324         {
325             return getResourceLastModified(url.openConnection());
326         }
327     }
328 
329     //Taken from trinidad URLUtils
330     private long getResourceLastModified(URLConnection connection) throws IOException
331     {
332         long modified;
333         if (connection instanceof JarURLConnection)
334         {
335             // The following hack is required to work-around a JDK bug.
336             // getLastModified() on a JAR entry URL delegates to the actual JAR file
337             // rather than the JAR entry.
338             // This opens internally, and does not close, an input stream to the JAR
339             // file.
340             // In turn, you cannot close it by yourself, because it's internal.
341             // The work-around is to get the modification date of the JAR file
342             // manually,
343             // and then close that connection again.
344 
345             URL jarFileUrl = ((JarURLConnection) connection).getJarFileURL();
346             URLConnection jarFileConnection = jarFileUrl.openConnection();
347 
348             try
349             {
350                 modified = jarFileConnection.getLastModified();
351             }
352             finally
353             {
354                 try
355                 {
356                     jarFileConnection.getInputStream().close();
357                 }
358                 catch (Exception exception)
359                 {
360                     // Ignored
361                 }
362             }
363         }
364         else
365         {
366             modified = connection.getLastModified();
367         }
368 
369         return modified;
370     }
371 
372     private long getLastModifiedTime()
373     {
374         long lastModified = 0;
375         long resModified;
376 
377         resModified = getResourceLastModified(DEFAULT_FACES_CONFIG);
378         if (resModified > lastModified)
379         {
380             lastModified = resModified;
381         }
382 
383         // perf: method getConfigFilesList() creates a ArrayList    
384         List<String> configFilesList = getConfigFilesList();
385         for (int i = 0, size = configFilesList.size(); i < size; i++)
386         {
387             String systemId = configFilesList.get(i);
388             resModified = getResourceLastModified(systemId);
389             if (resModified > lastModified)
390             {
391                 lastModified = resModified;
392             }
393         }
394         
395         // get last modified from .taglib.xml
396         String faceletsFiles = WebConfigParamUtils.getStringInitParameter(_externalContext, 
397                 PARAMS_FACELETS_LIBRARIES);
398         if (faceletsFiles != null)
399         {
400             String[] faceletFilesList = StringUtils.trim(faceletsFiles.split(";"));
401             for (int i = 0, size = faceletFilesList.length; i < size; i++)
402             {
403                 String systemId = faceletFilesList[i];
404                 resModified = getResourceLastModified(systemId);
405                 if (resModified > lastModified)
406                 {
407                     lastModified = resModified;
408                 }
409             }
410         }
411         
412         // get last modified from -flow.xml
413         Set<String> directoryPaths = _externalContext.getResourcePaths("/");
414         if (directoryPaths != null)
415         {
416             List<String> contextSpecifiedList = configFilesList;
417             for (String dirPath : directoryPaths)
418             {
419                 if (dirPath.equals("/WEB-INF/"))
420                 {
421                     // Look on /WEB-INF/<flow-Name>/<flowName>-flow.xml
422                     Set<String> webDirectoryPaths = _externalContext.getResourcePaths(dirPath);
423                     for (String webDirPath : webDirectoryPaths)
424                     {
425                         if (webDirPath.endsWith("/") && 
426                             !webDirPath.equals("/WEB-INF/classes/"))
427                         {
428                             String flowName = webDirPath.substring(9, webDirPath.length() - 1);
429                             String filePath = webDirPath+flowName+"-flow.xml";
430                             if (!contextSpecifiedList.contains(filePath))
431                             {
432                                 resModified = getResourceLastModified(filePath);
433                                 if (resModified > lastModified)
434                                 {
435                                     lastModified = resModified;
436                                 }
437                             }
438                         }
439                     }
440                 }
441                 else if (!dirPath.startsWith("/META-INF") && dirPath.endsWith("/"))
442                 {
443                     // Look on /<flowName>/<flowName>-flow.xml
444                     String flowName = dirPath.substring(1, dirPath.length() - 1);
445                     String filePath = dirPath+flowName+"-flow.xml";
446                     if (!contextSpecifiedList.contains(filePath))
447                     {
448                         resModified = getResourceLastModified(filePath);
449                         if (resModified > lastModified)
450                         {
451                             lastModified = resModified;
452                         }
453                     }
454                 }                
455             }
456         }
457         
458         return lastModified;
459     }
460 
461     public void update()
462     {
463         //Google App Engine does not allow to get last modified time of a file; 
464         //and when an application is running on GAE there is no way to update faces config xml file.
465         //thus, no need to check if the config file is modified.
466         if (ContainerUtils.isRunningOnGoogleAppEngine(_externalContext))
467         {
468             return;
469         }
470         long refreshPeriod = (MyfacesConfig.getCurrentInstance(_externalContext).getConfigRefreshPeriod()) * 1000;
471 
472         if (refreshPeriod > 0)
473         {
474             long ttl = lastUpdate + refreshPeriod;
475             if ((System.currentTimeMillis() > ttl) && (getLastModifiedTime() > ttl))
476             {
477                 boolean purged = false;
478                 try
479                 {
480                     purged = purgeConfiguration();
481                 }
482                 catch (NoSuchMethodException e)
483                 {
484                     log.severe("Configuration objects do not support clean-up. Update aborted");
485 
486                     // We still want to update the timestamp to avoid running purge on every subsequent
487                     // request after this one.
488                     //
489                     lastUpdate = System.currentTimeMillis();
490 
491                     return;
492                 }
493                 catch (IllegalAccessException e)
494                 {
495                     log.severe("Error during configuration clean-up" + e.getMessage());
496                 }
497                 catch (InvocationTargetException e)
498                 {
499                     log.severe("Error during configuration clean-up" + e.getMessage());
500                 }
501                 if (purged)
502                 {
503                     configure();
504                     
505                     // JSF 2.0 Publish PostConstructApplicationEvent after all configuration resources
506                     // has been parsed and processed
507                     FacesContext facesContext = getFacesContext();
508                     Application application = facesContext.getApplication();
509 
510                     application.publishEvent(facesContext, PostConstructApplicationEvent.class,
511                             Application.class, application);
512                 }
513             }
514         }
515     }
516 
517     private boolean purgeConfiguration() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
518     {
519 
520         Method appFactoryPurgeMethod;
521         Method renderKitPurgeMethod;
522         Method lifecyclePurgeMethod;
523         Method facesContextPurgeMethod;
524 
525         // Check that we have access to all of the necessary purge methods before purging anything
526         //
527         ApplicationFactory applicationFactory
528                 = (ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
529         //appFactoryPurgeMethod = applicationFactory.getClass().getMethod("purgeApplication", NO_PARAMETER_TYPES);
530         appFactoryPurgeMethod = getPurgeMethod(applicationFactory, "purgeApplication", NO_PARAMETER_TYPES);
531 
532         RenderKitFactory renderKitFactory
533                 = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
534         //renderKitPurgeMethod = renderKitFactory.getClass().getMethod("purgeRenderKit", NO_PARAMETER_TYPES);
535         renderKitPurgeMethod = getPurgeMethod(renderKitFactory, "purgeRenderKit", NO_PARAMETER_TYPES);
536 
537         LifecycleFactory lifecycleFactory
538                 = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
539         //lifecyclePurgeMethod = lifecycleFactory.getClass().getMethod("purgeLifecycle", NO_PARAMETER_TYPES);
540         lifecyclePurgeMethod = getPurgeMethod(lifecycleFactory, "purgeLifecycle", NO_PARAMETER_TYPES);
541 
542         FacesContext facesContext = getFacesContext();
543         facesContextPurgeMethod = getPurgeMethod(facesContext, "purgeFacesContext", NO_PARAMETER_TYPES);
544         
545         // If there was no exception so far, now we can purge
546         //
547         if (appFactoryPurgeMethod != null && renderKitPurgeMethod != null && lifecyclePurgeMethod != null && 
548             facesContextPurgeMethod != null)
549         {
550             appFactoryPurgeMethod.invoke(applicationFactory, NO_PARAMETERS);
551             renderKitPurgeMethod.invoke(renderKitFactory, NO_PARAMETERS);
552             RuntimeConfig.getCurrentInstance(_externalContext).purge();
553             lifecyclePurgeMethod.invoke(lifecycleFactory, NO_PARAMETERS);
554             facesContextPurgeMethod.invoke(facesContext, NO_PARAMETERS);
555 
556             // factories and serial factory need not be purged...
557 
558             // Remove first request processed so we can initialize it again
559             _externalContext.getApplicationMap().remove(LifecycleImpl.FIRST_REQUEST_PROCESSED_PARAM);
560             return true;
561         }
562         return false;
563     }
564     
565     private Method getPurgeMethod(Object instance, String methodName, Class<?>[] parameters)
566     {
567         while (instance != null)
568         {
569             Method purgeMethod = null;
570             try
571             {
572                 purgeMethod = instance.getClass().getMethod(methodName, parameters);
573             }
574             catch (NoSuchMethodException e)
575             {
576                 // No op, it is expected to found this case, so in that case
577                 // look for the parent to do the purge
578             }
579             if (purgeMethod != null)
580             {
581                 return purgeMethod;
582             }
583             if (instance instanceof FacesWrapper)
584             {
585                 instance = ((FacesWrapper)instance).getWrapped();
586             }
587         }
588         return null;
589     }
590 
591     public void configure() throws FacesException
592     {
593         // get FacesConfigurationMerger SPI implementation
594         FacesConfigurationMerger facesConfigurationMerger = FacesConfigurationMergerFactory
595                 .getFacesConfigurationMergerFactory(_externalContext).getFacesConfigurationMerger(_externalContext);
596 
597         // get all faces-config data, merge it and set it as Dispenser
598         setDispenser(facesConfigurationMerger.getFacesConfigData(_externalContext));
599 
600         configureFactories();
601         configureApplication();
602         configureRenderKits();
603 
604         //Now we can configure annotations
605         //getAnnotationConfigurator().configure(
606         //        ((ApplicationFactory) FactoryFinder.getFactory(
607         //                FactoryFinder.APPLICATION_FACTORY)).getApplication(),
608         //        getDispenser(), metadataComplete);
609 
610         configureRuntimeConfig();
611         configureLifecycle();
612         handleSerialFactory();
613         configureManagedBeanDestroyer();
614         configureFlowHandler();
615 
616         configureProtectedViews();
617         
618         // record the time of update
619         lastUpdate = System.currentTimeMillis();
620     }
621 
622     private List<String> getConfigFilesList()
623     {
624         String configFiles = _externalContext.getInitParameter(FacesServlet.CONFIG_FILES_ATTR);
625         List<String> configFilesList = new ArrayList<String>();
626         if (configFiles != null)
627         {
628             StringTokenizer st = new StringTokenizer(configFiles, ",", false);
629             while (st.hasMoreTokens())
630             {
631                 String systemId = st.nextToken().trim();
632 
633                 if (DEFAULT_FACES_CONFIG.equals(systemId))
634                 {
635                     if (log.isLoggable(Level.WARNING))
636                     {
637                         log.warning(DEFAULT_FACES_CONFIG + " has been specified in the "
638                                 + FacesServlet.CONFIG_FILES_ATTR
639                                 + " context parameter of "
640                                 + "the deployment descriptor. This will automatically be removed, "
641                                 + "if we wouldn't do this, it would be loaded twice.  See JSF spec 1.1, 10.3.2");
642                     }
643                 }
644                 else
645                 {
646                     configFilesList.add(systemId);
647                 }
648             }
649         }
650         return configFilesList;
651     }
652 
653     private void configureFactories()
654     {
655         FacesConfigData dispenser = getDispenser();
656         setFactories(FactoryFinder.APPLICATION_FACTORY, dispenser.getApplicationFactoryIterator(),
657                 DEFAULT_APPLICATION_FACTORY);
658         setFactories(FactoryFinder.EXCEPTION_HANDLER_FACTORY, dispenser.getExceptionHandlerFactoryIterator(),
659                 DEFAULT_EXCEPTION_HANDLER_FACTORY);
660         setFactories(FactoryFinder.EXTERNAL_CONTEXT_FACTORY, dispenser.getExternalContextFactoryIterator(),
661                 DEFAULT_EXTERNAL_CONTEXT_FACTORY);
662         setFactories(FactoryFinder.FACES_CONTEXT_FACTORY, dispenser.getFacesContextFactoryIterator(),
663                 DEFAULT_FACES_CONTEXT_FACTORY);
664         setFactories(FactoryFinder.LIFECYCLE_FACTORY, dispenser.getLifecycleFactoryIterator(),
665                 DEFAULT_LIFECYCLE_FACTORY);
666         setFactories(FactoryFinder.RENDER_KIT_FACTORY, dispenser.getRenderKitFactoryIterator(),
667                 DEFAULT_RENDER_KIT_FACTORY);
668         setFactories(FactoryFinder.TAG_HANDLER_DELEGATE_FACTORY, dispenser.getTagHandlerDelegateFactoryIterator(),
669                 DEFAULT_TAG_HANDLER_DELEGATE_FACTORY);
670         setFactories(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY, dispenser.getPartialViewContextFactoryIterator(),
671                 DEFAULT_PARTIAL_VIEW_CONTEXT_FACTORY);
672         setFactories(FactoryFinder.VISIT_CONTEXT_FACTORY, dispenser.getVisitContextFactoryIterator(),
673                 DEFAULT_VISIT_CONTEXT_FACTORY);
674         setFactories(FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY,
675                 dispenser.getViewDeclarationLanguageFactoryIterator(),
676                 DEFAULT_VIEW_DECLARATION_LANGUAGE_FACTORY);
677         setFactories(FactoryFinder.FACELET_CACHE_FACTORY, dispenser.getFaceletCacheFactoryIterator(),
678                 DEFAULT_FACELET_CACHE_FACTORY);
679         setFactories(FactoryFinder.FLASH_FACTORY, dispenser.getFlashFactoryIterator(),
680                 DEFAULT_FLASH_FACTORY);
681         setFactories(FactoryFinder.CLIENT_WINDOW_FACTORY, dispenser.getClientWindowFactoryIterator(),
682                 DEFAULT_CLIENT_WINDOW_FACTORY);
683         setFactories(FactoryFinder.FLOW_HANDLER_FACTORY, dispenser.getFlowHandlerFactoryIterator(),
684                 DEFAULT_FLOW_FACTORY);
685     }
686 
687     private void setFactories(String factoryName, Collection<String> factories, String defaultFactory)
688     {
689         FactoryFinder.setFactory(factoryName, defaultFactory);
690         for (String factory : factories)
691         {
692             if (!factory.equals(defaultFactory))
693             {
694                 FactoryFinder.setFactory(factoryName, factory);
695             }
696         }
697     }
698 
699     private void configureApplication()
700     {
701         Application application = ((ApplicationFactory)
702                 FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY)).getApplication();
703 
704         FacesConfigData dispenser = getDispenser();
705         ActionListener actionListener = ClassUtils.buildApplicationObject(ActionListener.class,
706                 dispenser.getActionListenerIterator(), null);
707         _callInjectAndPostConstruct(actionListener);
708         application.setActionListener(actionListener);
709 
710         if (dispenser.getDefaultLocale() != null)
711         {
712             application.setDefaultLocale(LocaleUtils.toLocale(dispenser.getDefaultLocale()));
713         }
714 
715         if (dispenser.getDefaultRenderKitId() != null)
716         {
717             application.setDefaultRenderKitId(dispenser.getDefaultRenderKitId());
718         }
719 
720         if (dispenser.getMessageBundle() != null)
721         {
722             application.setMessageBundle(dispenser.getMessageBundle());
723         }
724         
725         NavigationHandler navigationHandler = ClassUtils.buildApplicationObject(NavigationHandler.class,
726                 ConfigurableNavigationHandler.class,
727                 BackwardsCompatibleNavigationHandlerWrapper.class,
728                 dispenser.getNavigationHandlerIterator(),
729                 application.getNavigationHandler());
730         _callInjectAndPostConstruct(navigationHandler);
731         application.setNavigationHandler(navigationHandler);
732 
733         StateManager stateManager = ClassUtils.buildApplicationObject(StateManager.class,
734                 dispenser.getStateManagerIterator(),
735                 application.getStateManager());
736         _callInjectAndPostConstruct(stateManager);
737         application.setStateManager(stateManager);
738 
739         ResourceHandler resourceHandler = ClassUtils.buildApplicationObject(ResourceHandler.class,
740                 dispenser.getResourceHandlerIterator(),
741                 application.getResourceHandler());
742         _callInjectAndPostConstruct(resourceHandler);
743         application.setResourceHandler(resourceHandler);
744 
745         List<Locale> locales = new ArrayList<Locale>();
746         for (String locale : dispenser.getSupportedLocalesIterator())
747         {
748             locales.add(LocaleUtils.toLocale(locale));
749         }
750 
751         application.setSupportedLocales(locales);
752 
753         application.setViewHandler(ClassUtils.buildApplicationObject(ViewHandler.class,
754                 dispenser.getViewHandlerIterator(),
755                 application.getViewHandler()));
756         
757         RuntimeConfig runtimeConfig = getRuntimeConfig();
758         
759         for (SystemEventListener systemEventListener : dispenser.getSystemEventListeners())
760         {
761 
762 
763             try
764             {
765                 //note here used to be an instantiation to deal with the explicit source type in the registration,
766                 // that cannot work because all system events need to have the source being passed in the constructor
767                 //instead we now  rely on the standard system event types and map them to their appropriate
768                 // constructor types
769                 Class eventClass = ClassUtils.classForName((systemEventListener.getSystemEventClass() != null)
770                         ? systemEventListener.getSystemEventClass()
771                         : SystemEvent.class.getName());
772 
773                 javax.faces.event.SystemEventListener listener = (javax.faces.event.SystemEventListener) 
774                         ClassUtils.newInstance(systemEventListener.getSystemEventListenerClass());
775                 _callInjectAndPostConstruct(listener);
776                 runtimeConfig.addInjectedObject(listener);
777                 if (systemEventListener.getSourceClass() != null && systemEventListener.getSourceClass().length() > 0)
778                 {
779                     application.subscribeToEvent(
780                             (Class<? extends SystemEvent>) eventClass,
781                             ClassUtils.classForName(systemEventListener.getSourceClass()),
782                                     listener);
783                 }
784                 else
785                 {
786                     application.subscribeToEvent(
787                             (Class<? extends SystemEvent>) eventClass,
788                             listener);
789                 }
790             }
791             catch (ClassNotFoundException e)
792             {
793                 log.log(Level.SEVERE, "System event listener could not be initialized, reason:", e);
794             }
795         }
796 
797         for (Map.Entry<String, String> entry : dispenser.getComponentClassesByType().entrySet())
798         {
799             application.addComponent(entry.getKey(), entry.getValue());
800         }
801 
802         for (Map.Entry<String, String> entry : dispenser.getConverterClassesById().entrySet())
803         {
804             application.addConverter(entry.getKey(), entry.getValue());
805         }
806 
807         for (Map.Entry<String, String> entry : dispenser.getConverterClassesByClass().entrySet())
808         {
809             try
810             {
811                 application.addConverter(ClassUtils.simpleClassForName(entry.getKey()),
812                         entry.getValue());
813             }
814             catch (Exception ex)
815             {
816                 log.log(Level.SEVERE, "Converter could not be added. Reason:", ex);
817             }
818         }
819 
820         for (Map.Entry<String, String> entry : dispenser.getValidatorClassesById().entrySet())
821         {
822             application.addValidator(entry.getKey(), entry.getValue());
823         }
824 
825         // programmatically add the BeanValidator if the following requirements are met:
826         //     - bean validation has not been disabled
827         //     - bean validation is available in the classpath
828         String beanValidatorDisabled = _externalContext.getInitParameter(
829                 BeanValidator.DISABLE_DEFAULT_BEAN_VALIDATOR_PARAM_NAME);
830         final boolean defaultBeanValidatorDisabled = (beanValidatorDisabled != null
831                 && beanValidatorDisabled.toLowerCase().equals("true"));
832         boolean beanValidatorInstalledProgrammatically = false;
833         if (!defaultBeanValidatorDisabled
834                 && ExternalSpecifications.isBeanValidationAvailable())
835         {
836             // add the BeanValidator as default validator
837             application.addDefaultValidatorId(BeanValidator.VALIDATOR_ID);
838             beanValidatorInstalledProgrammatically = true;
839         }
840 
841         // add the default-validators from the config files
842         for (String validatorId : dispenser.getDefaultValidatorIds())
843         {
844             application.addDefaultValidatorId(validatorId);
845         }
846 
847         // do some checks if the BeanValidator was not installed as a
848         // default-validator programmatically, but via a config file.
849         if (!beanValidatorInstalledProgrammatically
850                 && application.getDefaultValidatorInfo()
851                 .containsKey(BeanValidator.VALIDATOR_ID))
852         {
853             if (!ExternalSpecifications.isBeanValidationAvailable())
854             {
855                 // the BeanValidator was installed via a config file,
856                 // but bean validation is not available
857                 log.log(Level.WARNING, "The BeanValidator was installed as a " +
858                         "default-validator from a faces-config file, but bean " +
859                         "validation is not available on the classpath, " +
860                         "thus it will not work!");
861             }
862             else if (defaultBeanValidatorDisabled)
863             {
864                 // the user disabled the default bean validator in web.xml,
865                 // but a config file added it, which is ok with the spec
866                 // (section 11.1.3: "though manual installation is still possible")
867                 // --> inform the user about this scenario
868                 log.log(Level.INFO, "The BeanValidator was disabled as a " +
869                         "default-validator via the config parameter " +
870                         BeanValidator.DISABLE_DEFAULT_BEAN_VALIDATOR_PARAM_NAME +
871                         " in web.xml, but a faces-config file added it, " +
872                         "thus it actually was installed as a default-validator.");
873             }
874         }
875 
876         for (Behavior behavior : dispenser.getBehaviors())
877         {
878             application.addBehavior(behavior.getBehaviorId(), behavior.getBehaviorClass());
879         }
880         
881         //JSF 2.2 set FlowHandler from factory. 
882         FlowHandlerFactory flowHandlerFactory = (FlowHandlerFactory) 
883             FactoryFinder.getFactory(FactoryFinder.FLOW_HANDLER_FACTORY);
884         FlowHandler flowHandler = flowHandlerFactory.createFlowHandler(
885             getFacesContext());
886         application.setFlowHandler(flowHandler);
887 
888         if (MyfacesConfig.getCurrentInstance(_externalContext).isSupportJSPAndFacesEL())
889         {
890             // If no JSP and old Faces EL, there is no need to initialize PropertyResolver
891             // and VariableResolver stuff.
892             runtimeConfig.setPropertyResolverChainHead(ClassUtils.buildApplicationObject(PropertyResolver.class,
893                     dispenser.getPropertyResolverIterator(),
894                     new DefaultPropertyResolver()));
895     
896             runtimeConfig.setVariableResolverChainHead(ClassUtils.buildApplicationObject(VariableResolver.class,
897                     dispenser.getVariableResolverIterator(),
898                     new VariableResolverImpl()));
899         }
900         
901         for (ContractMapping mapping : dispenser.getResourceLibraryContractMappings())
902         {
903             if (mapping.getUrlPattern() != null)
904             {
905                 // Deprecated way
906                 String urlPattern = mapping.getUrlPattern();
907                 String[] contracts = StringUtils.trim(StringUtils.splitShortString(mapping.getContracts(), ' '));
908                 runtimeConfig.addContractMapping(urlPattern, contracts);
909             }
910             else
911             {
912                 List<String> urlMappingsList = mapping.getUrlPatternList();
913                 for (String urlPattern: urlMappingsList)
914                 {
915                     for (String contract : mapping.getContractList())
916                     {
917                         String[] contracts = StringUtils.trim(StringUtils.splitShortString(contract, ' '));
918                         runtimeConfig.addContractMapping(urlPattern, contracts);
919                     }
920                 }
921             }
922         }
923         
924         this.setApplication(application);
925     }
926     
927     private void _callInjectAndPostConstruct(Object instance)
928     {
929         try
930         {
931             //invoke the injection over the inner one first
932             if (instance instanceof FacesWrapper)
933             {
934                 Object innerInstance = ((FacesWrapper)instance).getWrapped();
935                 if (innerInstance != null)
936                 {
937                     _callInjectAndPostConstruct(innerInstance);
938                 }
939             }
940             List<BeanEntry> injectedBeanStorage =
941                     (List<BeanEntry>)_externalContext.getApplicationMap().get(INJECTED_BEAN_STORAGE_KEY);
942 
943             Object creationMetaData = getInjectionProvider().inject(instance);
944 
945             injectedBeanStorage.add(new BeanEntry(instance, creationMetaData));
946 
947             getInjectionProvider().postConstruct(instance, creationMetaData);
948         }
949         catch (InjectionProviderException ex)
950         {
951             log.log(Level.INFO, "Exception on PreDestroy", ex);
952         }
953     }
954 
955     /**
956      * A mapper for the handful of system listener defaults
957      * since every default mapper has the source type embedded
958      * in the constructor we can rely on introspection for the
959      * default mapping
960      *
961      * @param systemEventClass the system listener class which has to be checked
962      * @return
963      */
964     String getDefaultSourcClassForSystemEvent(Class systemEventClass)
965     {
966         Constructor[] constructors = systemEventClass.getConstructors();
967         for (Constructor constr : constructors)
968         {
969             Class[] parms = constr.getParameterTypes();
970             if (parms == null || parms.length != 1)
971             {
972                 //for standard types we have only one parameter representing the type
973                 continue;
974             }
975             return parms[0].getName();
976         }
977         log.warning("The SystemEvent source type for " + systemEventClass.getName()
978                 + " could not be detected, either register it manually or use a constructor argument "
979                 + "for auto detection, defaulting now to java.lang.Object");
980         return "java.lang.Object";
981     }
982 
983 
984     protected RuntimeConfig getRuntimeConfig()
985     {
986         if (_runtimeConfig == null)
987         {
988             _runtimeConfig = RuntimeConfig.getCurrentInstance(_externalContext);
989         }
990         return _runtimeConfig;
991     }
992 
993     public void setRuntimeConfig(RuntimeConfig runtimeConfig)
994     {
995         _runtimeConfig = runtimeConfig;
996     }
997 
998     private void configureRuntimeConfig()
999     {
1000         RuntimeConfig runtimeConfig = RuntimeConfig.getCurrentInstance(_externalContext);
1001         FacesConfigData dispenser = getDispenser();
1002         List<String> knownNamespaces = new ArrayList<String>();
1003         
1004         for (ComponentTagDeclaration declaration : dispenser.getComponentTagDeclarations())
1005         {
1006             runtimeConfig.addComponentTagDeclaration(declaration);
1007             if (declaration.getNamespace() != null)
1008             {
1009                 knownNamespaces.add(declaration.getNamespace());
1010             }
1011         }
1012         
1013         for (ManagedBean bean : dispenser.getManagedBeans())
1014         {
1015             if (log.isLoggable(Level.WARNING) && runtimeConfig.getManagedBean(bean.getManagedBeanName()) != null)
1016             {
1017                 log.warning("More than one managed bean w/ the name of '" + bean.getManagedBeanName()
1018                         + "' - only keeping the last ");
1019             }
1020 
1021             runtimeConfig.addManagedBean(bean.getManagedBeanName(), bean);
1022 
1023         }
1024 
1025         removePurgedBeansFromSessionAndApplication(runtimeConfig);
1026 
1027         for (NavigationRule rule : dispenser.getNavigationRules())
1028         {
1029             runtimeConfig.addNavigationRule(rule);
1030         }
1031 
1032         for (String converterClassName : dispenser.getConverterConfigurationByClassName())
1033         {
1034             runtimeConfig.addConverterConfiguration(converterClassName,
1035                     _dispenser.getConverterConfiguration(converterClassName));
1036         }
1037 
1038         for (ResourceBundle bundle : dispenser.getResourceBundles())
1039         {
1040             runtimeConfig.addResourceBundle(bundle);
1041         }
1042 
1043         List<BeanEntry> injectedBeansAndMetaData =
1044                 (List<BeanEntry>)_externalContext.getApplicationMap().get(INJECTED_BEAN_STORAGE_KEY);
1045 
1046         for (String className : dispenser.getElResolvers())
1047         {
1048             ELResolver elResolver = (ELResolver) ClassUtils.newInstance(className, ELResolver.class);
1049             try
1050             {
1051                 Object creationMetaData = getInjectionProvider().inject(elResolver);
1052 
1053                 injectedBeansAndMetaData.add(new BeanEntry(elResolver, creationMetaData));
1054 
1055                 getInjectionProvider().postConstruct(elResolver, creationMetaData);
1056             }
1057             catch (InjectionProviderException e)
1058             {
1059                 log.log(Level.SEVERE, "Error while injecting ELResolver", e);
1060             }
1061             runtimeConfig.addFacesConfigElResolver(elResolver);
1062         }
1063 
1064         runtimeConfig.setFacesVersion(dispenser.getFacesVersion());
1065 
1066         runtimeConfig.setNamedEventManager(new NamedEventManager());
1067 
1068         for (NamedEvent event : dispenser.getNamedEvents())
1069         {
1070             try
1071             {
1072                 Class<? extends ComponentSystemEvent> clazz = ClassUtils.classForName(event.getEventClass());
1073                 runtimeConfig.getNamedEventManager().addNamedEvent(event.getShortName(), clazz);
1074             }
1075             catch (ClassNotFoundException e)
1076             {
1077                 log.log(Level.SEVERE, "Named event could not be initialized, reason:", e);
1078             }
1079         }
1080 
1081         String comparatorClass = _externalContext.getInitParameter(ResolverBuilderBase.EL_RESOLVER_COMPARATOR);
1082 
1083         if (comparatorClass != null && !"".equals(comparatorClass))
1084         {
1085             // get the comparator class
1086             Class<Comparator<ELResolver>> clazz;
1087             try
1088             {
1089                 clazz = (Class<Comparator<ELResolver>>) ClassUtils.classForName(comparatorClass);
1090                 // create the instance
1091                 Comparator<ELResolver> comparator = ClassUtils.newInstance(clazz);
1092 
1093                 runtimeConfig.setELResolverComparator(comparator);
1094             }
1095             catch (Exception e)
1096             {
1097                 if (log.isLoggable(Level.SEVERE))
1098                 {
1099                     log.log(Level.SEVERE, "Cannot instantiate EL Resolver Comparator " + comparatorClass
1100                             + " . Check org.apache.myfaces.EL_RESOLVER_COMPARATOR web config param. "
1101                             + "Initialization continues with no comparator used.", e);
1102                 }
1103             }
1104         }
1105         else
1106         {
1107             runtimeConfig.setELResolverComparator(null);
1108         }
1109 
1110         String elResolverPredicateClass = _externalContext.getInitParameter(ResolverBuilderBase.EL_RESOLVER_PREDICATE);
1111 
1112         if (elResolverPredicateClass != null && !"".equals(elResolverPredicateClass))
1113         {
1114             // get the comparator class
1115             Class<Predicate> clazz;
1116             try
1117             {
1118                 clazz = (Class<Predicate>) ClassUtils.classForName(elResolverPredicateClass);
1119                 // create the instance
1120                 Predicate elResolverPredicate = ClassUtils.newInstance(clazz);
1121 
1122                 runtimeConfig.setELResolverPredicate(elResolverPredicate);
1123             }
1124             catch (Exception e)
1125             {
1126                 if (log.isLoggable(Level.SEVERE))
1127                 {
1128                     log.log(Level.SEVERE, "Cannot instantiate EL Resolver Comparator " + comparatorClass
1129                             + " . Check org.apache.myfaces.EL_RESOLVER_COMPARATOR web config param. "
1130                             + "Initialization continues with no comparator used.", e);
1131                 }
1132             }
1133         }
1134         else
1135         {
1136             runtimeConfig.setELResolverPredicate(null);
1137         }
1138 
1139         for (FaceletsProcessing faceletsProcessing : dispenser.getFaceletsProcessing())
1140         {
1141             runtimeConfig.addFaceletProcessingConfiguration(faceletsProcessing.getFileExtension(), faceletsProcessing);
1142         }
1143         
1144         ResourceLibraryContractsProvider rlcp = ResourceLibraryContractsProviderFactory.
1145             getFacesConfigResourceProviderFactory(_externalContext).
1146             createResourceLibraryContractsProvider(_externalContext);
1147         
1148         try
1149         {
1150             // JSF 2.2 section 11.4.2.1 scan for available resource library contracts
1151             // and store the result in a internal data structure, so it can be used 
1152             // later in ViewDeclarationLanguage.calculateResourceLibraryContracts(
1153             //   FacesContext context, String viewId)
1154             runtimeConfig.setExternalContextResourceLibraryContracts(
1155                 rlcp.getExternalContextResourceLibraryContracts(_externalContext));
1156             runtimeConfig.setClassLoaderResourceLibraryContracts(
1157                 rlcp.getClassloaderResourceLibraryContracts(_externalContext));
1158         }
1159         catch(Exception e)
1160         {
1161             if (log.isLoggable(Level.SEVERE))
1162             {
1163                 log.log(Level.SEVERE, 
1164                     "An error was found when scanning for resource library contracts", e);
1165             }
1166         }
1167         
1168         
1169         // JSF 2.2 section 11.4.2.1 check all contracts are loaded
1170         if (log.isLoggable(Level.INFO))
1171         {
1172             for (List<String> list : runtimeConfig.getContractMappings().values())
1173             {
1174                 for (String contract : list)
1175                 {
1176                     if (!runtimeConfig.getResourceLibraryContracts().contains(contract))
1177                     {
1178                         log.log(Level.INFO, 
1179                             "Resource Library Contract "+ contract + " was not found while scanning for "
1180                             + "available contracts.");
1181                     }
1182                 }
1183             }
1184         }
1185         
1186         // JSF 2.2 section 11.4.2.1 if no contractMappings set, all available contracts applies
1187         // to all views.
1188         if (runtimeConfig.getContractMappings().isEmpty())
1189         {
1190             String[] contracts = runtimeConfig.getResourceLibraryContracts().toArray(
1191                 new String[runtimeConfig.getResourceLibraryContracts().size()]);
1192             runtimeConfig.addContractMapping("*", contracts);
1193         }
1194         
1195         for (String resourceResolver : dispenser.getResourceResolvers())
1196         {
1197             runtimeConfig.addResourceResolver(resourceResolver);
1198         }
1199         
1200         for (FaceletTagLibrary faceletTagLibrary : dispenser.getTagLibraries())
1201         {
1202             runtimeConfig.addFaceletTagLibrary(faceletTagLibrary);
1203             if (faceletTagLibrary.getNamespace() != null)
1204             {
1205                 knownNamespaces.add(faceletTagLibrary.getNamespace());
1206             }
1207         }
1208         
1209         // Add default namespaces to the known namespaces
1210         knownNamespaces.add("http://xmlns.jcp.org/jsf/core");
1211         knownNamespaces.add("http://java.sun.com/jsf/core");
1212         knownNamespaces.add("http://xmlns.jcp.org/jsf/html");
1213         knownNamespaces.add("http://java.sun.com/jsf/html");
1214         knownNamespaces.add("http://xmlns.jcp.org/jsf/facelets");
1215         knownNamespaces.add("http://java.sun.com/jsf/facelets");
1216         knownNamespaces.add("http://xmlns.jcp.org/jsp/jstl/core");
1217         knownNamespaces.add("http://java.sun.com/jsp/jstl/core");
1218         knownNamespaces.add("http://java.sun.com/jstl/core");
1219         knownNamespaces.add("http://xmlns.jcp.org/jsp/jstl/functions");
1220         knownNamespaces.add("http://java.sun.com/jsp/jstl/functions");
1221         knownNamespaces.add("http://xmlns.jcp.org/jsf/composite");
1222         knownNamespaces.add("http://java.sun.com/jsf/composite");
1223         knownNamespaces.add("http://xmlns.jcp.org/jsf");
1224         knownNamespaces.add("http://java.sun.com/jsf");
1225         knownNamespaces.add("http://xmlns.jcp.org/jsf/passthrough");
1226         knownNamespaces.add("http://java.sun.com/jsf/passthrough");
1227         
1228         Map<Integer, String> namespaceById = new HashMap<Integer, String>();
1229         Map<String, Integer> idByNamespace = new HashMap<String, Integer>();
1230         // Sort them to ensure the same id 
1231         Collections.sort(knownNamespaces);
1232         for (int i = 0; i < knownNamespaces.size(); i++)
1233         {
1234             namespaceById.put(i, knownNamespaces.get(i));
1235             idByNamespace.put(knownNamespaces.get(i), i);
1236         }
1237         runtimeConfig.setNamespaceById(Collections.unmodifiableMap(namespaceById));
1238         runtimeConfig.setIdByNamespace(Collections.unmodifiableMap(idByNamespace));
1239         
1240         for (ViewPoolMapping viewPoolMapping : dispenser.getViewPoolMappings())
1241         {
1242             runtimeConfig.addViewPoolMapping(viewPoolMapping);
1243         }
1244     }
1245 
1246     private void removePurgedBeansFromSessionAndApplication(RuntimeConfig runtimeConfig)
1247     {
1248         Map<String, ManagedBean> oldManagedBeans = runtimeConfig.getManagedBeansNotReaddedAfterPurge();
1249         if (oldManagedBeans != null)
1250         {
1251             for (Map.Entry<String, ManagedBean> entry : oldManagedBeans.entrySet())
1252             {
1253                 ManagedBean bean = entry.getValue();
1254 
1255                 String scope = bean.getManagedBeanScope();
1256 
1257                 if (scope != null && scope.equalsIgnoreCase("session"))
1258                 {
1259                     _externalContext.getSessionMap().remove(entry.getKey());
1260                 }
1261                 else if (scope != null && scope.equalsIgnoreCase("application"))
1262                 {
1263                     _externalContext.getApplicationMap().remove(entry.getKey());
1264                 }
1265             }
1266         }
1267 
1268         runtimeConfig.resetManagedBeansNotReaddedAfterPurge();
1269     }
1270 
1271     private void configureRenderKits()
1272     {
1273         RenderKitFactory renderKitFactory
1274                 = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
1275 
1276         FacesConfigData dispenser = getDispenser();
1277         for (String renderKitId : dispenser.getRenderKitIds())
1278         {
1279             Collection<String> renderKitClass = dispenser.getRenderKitClasses(renderKitId);
1280 
1281             if (renderKitClass.isEmpty())
1282             {
1283                 renderKitClass = new ArrayList<String>(1);
1284                 renderKitClass.add(DEFAULT_RENDER_KIT_CLASS);
1285             }
1286 
1287             //RenderKit renderKit = (RenderKit) ClassUtils.newInstance(renderKitClass);
1288             RenderKit renderKit = (RenderKit) ClassUtils.buildApplicationObject(RenderKit.class, renderKitClass, null);
1289             // If the default html RenderKit instance is wrapped, the top level object will not implement
1290             // LazyRenderKit and all renderers will be added using the standard form.
1291             boolean lazyRenderKit = renderKit instanceof LazyRenderKit;
1292 
1293             for (Renderer element : dispenser.getRenderers(renderKitId))
1294             {
1295                 javax.faces.render.Renderer renderer;
1296                 
1297                 if (element.getRendererClass() != null)
1298                 {
1299                     if (lazyRenderKit)
1300                     {
1301                         // Add renderer using LazyRenderKit interface. This will have the effect of improve startup
1302                         // time avoiding load renderer classes that are not used.
1303                         ((LazyRenderKit)renderKit).addRenderer(element.getComponentFamily(), 
1304                             element.getRendererType(), element.getRendererClass());
1305                     }
1306                     else
1307                     {
1308                         // Use standard form
1309                         try
1310                         {
1311                             renderer = (javax.faces.render.Renderer) ClassUtils.newInstance(
1312                                 element.getRendererClass());
1313                         }
1314                         catch (Throwable e)
1315                         {
1316                             // ignore the failure so that the render kit is configured
1317                             log.log(Level.SEVERE, "failed to configure class " + element.getRendererClass(), e);
1318                             continue;
1319                         }
1320                         if (renderer != null)
1321                         {
1322                             renderKit.addRenderer(element.getComponentFamily(), element.getRendererType(), renderer);
1323                         }
1324                         else
1325                         {
1326                             log.log(Level.INFO, "Renderer instance cannot be created for "+
1327                                     element.getRendererClass()+ ", ignoring..." + 
1328                                     element.getRendererClass());
1329                         }
1330                     }
1331                 }
1332                 else
1333                 {
1334                         log.log(Level.INFO, "Renderer element with no rendererClass found, ignoring..." +
1335                                 element.getRendererClass());
1336                 }
1337 
1338             }
1339             
1340             Collection<ClientBehaviorRenderer> clientBehaviorRenderers
1341                     = dispenser.getClientBehaviorRenderers(renderKitId);
1342 
1343             // Add in client behavior renderers.
1344 
1345             for (ClientBehaviorRenderer clientBehaviorRenderer : clientBehaviorRenderers)
1346             {
1347                 try
1348                 {
1349                     javax.faces.render.ClientBehaviorRenderer behaviorRenderer
1350                             = (javax.faces.render.ClientBehaviorRenderer)
1351                             ClassUtils.newInstance(clientBehaviorRenderer.getRendererClass());
1352 
1353                     renderKit.addClientBehaviorRenderer(clientBehaviorRenderer.getRendererType(), behaviorRenderer);
1354                 }
1355 
1356                 catch (Throwable e)
1357                 {
1358                     // Ignore.
1359 
1360                     if (log.isLoggable(Level.SEVERE))
1361                     {
1362                         log.log(Level.SEVERE, "failed to configure client behavior renderer class " +
1363                                 clientBehaviorRenderer.getRendererClass(), e);
1364                     }
1365                 }
1366             }
1367 
1368             renderKitFactory.addRenderKit(renderKitId, renderKit);
1369         }
1370     }
1371 
1372     private void configureLifecycle()
1373     {
1374         // create the lifecycle used by the app
1375         LifecycleFactory lifecycleFactory
1376                 = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
1377 
1378         List<BeanEntry> injectedBeanStorage =
1379                 (List<BeanEntry>)_externalContext.getApplicationMap().get(INJECTED_BEAN_STORAGE_KEY);
1380 
1381         //Lifecycle lifecycle = lifecycleFactory.getLifecycle(getLifecycleId());
1382         for (Iterator<String> it = lifecycleFactory.getLifecycleIds(); it.hasNext();)
1383         {
1384             Lifecycle lifecycle = lifecycleFactory.getLifecycle(it.next());
1385             
1386             // add phase listeners
1387             for (String listenerClassName : getDispenser().getLifecyclePhaseListeners())
1388             {
1389                 try
1390                 {
1391                     PhaseListener listener = (PhaseListener)
1392                             ClassUtils.newInstance(listenerClassName, PhaseListener.class);
1393 
1394                     Object creationMetaData = getInjectionProvider().inject(listener);
1395 
1396                     injectedBeanStorage.add(new BeanEntry(listener, creationMetaData));
1397 
1398                     getInjectionProvider().postConstruct(listener, creationMetaData);
1399                     lifecycle.addPhaseListener(listener);
1400                 }
1401                 catch (ClassCastException e)
1402                 {
1403                     log.severe("Class " + listenerClassName + " does not implement PhaseListener");
1404                 }
1405                 catch (InjectionProviderException e)
1406                 {
1407                     log.log(Level.SEVERE, "Error while injecting PhaseListener", e);
1408                 }
1409             }
1410 
1411             // if ProjectStage is Development, install the DebugPhaseListener
1412             FacesContext facesContext = getFacesContext();
1413             if (facesContext.isProjectStage(ProjectStage.Development) &&
1414                     MyfacesConfig.getCurrentInstance(facesContext.getExternalContext()).isDebugPhaseListenerEnabled())
1415             {
1416                 lifecycle.addPhaseListener(new DebugPhaseListener());
1417             }
1418         }
1419     }
1420 
1421     /*
1422     private String getLifecycleId()
1423     {
1424         String id = _externalContext.getInitParameter(FacesServlet.LIFECYCLE_ID_ATTR);
1425 
1426         if (id != null)
1427         {
1428             return id;
1429         }
1430 
1431         return LifecycleFactory.DEFAULT_LIFECYCLE;
1432     }*/
1433 
1434     private void handleSerialFactory()
1435     {
1436 
1437         String serialProvider = _externalContext.getInitParameter(StateUtils.SERIAL_FACTORY);
1438         SerialFactory serialFactory = null;
1439 
1440         if (serialProvider == null)
1441         {
1442             serialFactory = new DefaultSerialFactory();
1443         }
1444         else
1445         {
1446             try
1447             {
1448                 serialFactory = (SerialFactory) ClassUtils.newInstance(serialProvider);
1449 
1450             }
1451             catch (ClassCastException e)
1452             {
1453                 log.log(Level.SEVERE, "Make sure '" + serialProvider + "' implements the correct interface", e);
1454             }
1455             catch (Exception e)
1456             {
1457                 log.log(Level.SEVERE, "", e);
1458             }
1459             finally
1460             {
1461                 if (serialFactory == null)
1462                 {
1463                     serialFactory = new DefaultSerialFactory();
1464                     log.severe("Using default serialization provider");
1465                 }
1466             }
1467 
1468         }
1469 
1470         log.info("Serialization provider : " + serialFactory.getClass());
1471         _externalContext.getApplicationMap().put(StateUtils.SERIAL_FACTORY, serialFactory);
1472     }
1473 
1474     private void configureManagedBeanDestroyer()
1475     {
1476         FacesContext facesContext = getFacesContext();
1477         ExternalContext externalContext = facesContext.getExternalContext();
1478         Map<String, Object> applicationMap = externalContext.getApplicationMap();
1479         Application application = facesContext.getApplication();
1480 
1481         // get RuntimeConfig and LifecycleProvider
1482         RuntimeConfig runtimeConfig = RuntimeConfig.getCurrentInstance(externalContext);
1483         LifecycleProvider lifecycleProvider = LifecycleProviderFactory
1484                 .getLifecycleProviderFactory(externalContext).getLifecycleProvider(externalContext);
1485 
1486         // create ManagedBeanDestroyer
1487         ManagedBeanDestroyer mbDestroyer
1488                 = new ManagedBeanDestroyer(lifecycleProvider, runtimeConfig);
1489 
1490         // subscribe ManagedBeanDestroyer as listener for needed events 
1491         application.subscribeToEvent(PreDestroyCustomScopeEvent.class, mbDestroyer);
1492         application.subscribeToEvent(PreDestroyViewMapEvent.class, mbDestroyer);
1493 
1494         // get ManagedBeanDestroyerListener instance 
1495         ManagedBeanDestroyerListener listener = (ManagedBeanDestroyerListener)
1496                 applicationMap.get(ManagedBeanDestroyerListener.APPLICATION_MAP_KEY);
1497         if (listener != null)
1498         {
1499             // set the instance on the listener
1500             listener.setManagedBeanDestroyer(mbDestroyer);
1501         }
1502         else
1503         {
1504             log.log(Level.SEVERE, "No ManagedBeanDestroyerListener instance found, thus "
1505                     + "@PreDestroy methods won't get called in every case. "
1506                     + "This instance needs to be published before configuration is started.");
1507         }
1508     }
1509     
1510     private void configureFlowHandler()
1511     {
1512         FacesContext facesContext = getFacesContext();
1513         Application application = getApplication();
1514         
1515         FacesConfigData dispenser = getDispenser();
1516         
1517         if (!dispenser.getFacesFlowDefinitions().isEmpty())
1518         {
1519             // Faces Flow require client window enabled to work.
1520             FacesConfigurator.enableDefaultWindowMode(facesContext);
1521         }
1522         
1523         for (FacesFlowDefinition flowDefinition : dispenser.getFacesFlowDefinitions())
1524         {
1525             FlowImpl flow = new FlowImpl();
1526             
1527             // TODO: configure flow object
1528             flow.setId(flowDefinition.getId());
1529             flow.setDefiningDocumentId(flowDefinition.getDefiningDocumentId());
1530             
1531             flow.setStartNodeId(flowDefinition.getStartNode());
1532             
1533             if (!isEmptyString(flowDefinition.getInitializer()))
1534             {
1535                 flow.setInitializer(application.getExpressionFactory().createMethodExpression(
1536                     facesContext.getELContext(), flowDefinition.getInitializer(), null, NO_PARAMETER_TYPES));
1537             }
1538             if (!isEmptyString(flowDefinition.getFinalizer()))
1539             {
1540                 flow.setFinalizer(application.getExpressionFactory().createMethodExpression(
1541                     facesContext.getELContext(), flowDefinition.getFinalizer(), null, NO_PARAMETER_TYPES));
1542             }
1543             
1544             for (FacesFlowCall call : flowDefinition.getFlowCallList())
1545             {
1546                 FlowCallNodeImpl node = new FlowCallNodeImpl(call.getId());
1547                 if (call.getFlowReference() != null)
1548                 {
1549                     node.setCalledFlowId(call.getFlowReference().getFlowId());
1550                     node.setCalledFlowDocumentId(call.getFlowReference().getFlowDocumentId());
1551                 }
1552 
1553                 for (FacesFlowParameter parameter : call.getOutboundParameterList())
1554                 {
1555                     node.putOutboundParameter( parameter.getName(),
1556                         new ParameterImpl(parameter.getName(),
1557                         application.getExpressionFactory().createValueExpression(
1558                             facesContext.getELContext(), parameter.getValue(), Object.class)) );
1559                 }
1560                 flow.putFlowCall(node.getId(), node);
1561             }
1562 
1563             for (FacesFlowMethodCall methodCall : flowDefinition.getMethodCallList())
1564             {
1565                 MethodCallNodeImpl node = new MethodCallNodeImpl(methodCall.getId());
1566                 if (!isEmptyString(methodCall.getMethod()))
1567                 {
1568                     node.setMethodExpression(
1569                         application.getExpressionFactory().createMethodExpression(
1570                             facesContext.getELContext(), methodCall.getMethod(), null, NO_PARAMETER_TYPES));
1571                 }
1572                 if (!isEmptyString(methodCall.getDefaultOutcome()))
1573                 {
1574                     node.setOutcome(
1575                         application.getExpressionFactory().createValueExpression(
1576                                 facesContext.getELContext(), methodCall.getDefaultOutcome(), Object.class));
1577                 }
1578                 for (FacesFlowMethodParameter parameter : methodCall.getParameterList())
1579                 {
1580                     node.addParameter(
1581                         new ParameterImpl(parameter.getClassName(),
1582                         application.getExpressionFactory().createValueExpression(
1583                             facesContext.getELContext(), parameter.getValue(), Object.class)) );
1584                 }
1585                 flow.addMethodCall(node);
1586             }
1587             
1588             for (FacesFlowParameter parameter : flowDefinition.getInboundParameterList())
1589             {
1590                 flow.putInboundParameter(parameter.getName(),
1591                     new ParameterImpl(parameter.getName(),
1592                     application.getExpressionFactory().createValueExpression(
1593                         facesContext.getELContext(), parameter.getValue(), Object.class)) );
1594             }
1595             
1596             for (NavigationRule rule : flowDefinition.getNavigationRuleList())
1597             {
1598                 flow.addNavigationCases(rule.getFromViewId(), NavigationUtils.convertNavigationCasesToAPI(rule));
1599             }
1600             
1601             for (FacesFlowSwitch flowSwitch : flowDefinition.getSwitchList())
1602             {
1603                 SwitchNodeImpl node = new SwitchNodeImpl(flowSwitch.getId());
1604                 
1605                 if (flowSwitch.getDefaultOutcome() != null &&
1606                     !isEmptyString(flowSwitch.getDefaultOutcome().getFromOutcome()))
1607                 {
1608                     if (ELText.isLiteral(flowSwitch.getDefaultOutcome().getFromOutcome()))
1609                     {
1610                         node.setDefaultOutcome(flowSwitch.getDefaultOutcome().getFromOutcome());
1611                     }
1612                     else
1613                     {
1614                         node.setDefaultOutcome(
1615                             application.getExpressionFactory().createValueExpression(
1616                                 facesContext.getELContext(), flowSwitch.getDefaultOutcome().getFromOutcome(),
1617                                 Object.class));
1618                     }
1619                 }
1620                 
1621                 for (NavigationCase navCase : flowSwitch.getNavigationCaseList())
1622                 {
1623                     SwitchCaseImpl nodeCase = new SwitchCaseImpl();
1624                     nodeCase.setFromOutcome(navCase.getFromOutcome());
1625                     if (!isEmptyString(navCase.getIf()))
1626                     {
1627                         nodeCase.setCondition(
1628                             application.getExpressionFactory().createValueExpression(
1629                                 facesContext.getELContext(), navCase.getIf(),
1630                                 Object.class));
1631                     }
1632                     node.addCase(nodeCase);
1633                 }
1634                 
1635                 flow.putSwitch(node.getId(), node);
1636             }
1637             
1638             for (FacesFlowView view : flowDefinition.getViewList())
1639             {
1640                 ViewNodeImpl node = new ViewNodeImpl(view.getId(), view.getVdlDocument());
1641                 flow.addView(node);
1642             }
1643 
1644             for (FacesFlowReturn flowReturn : flowDefinition.getReturnList())
1645             {
1646                 ReturnNodeImpl node = new ReturnNodeImpl(flowReturn.getId());
1647                 if (flowReturn.getNavigationCase() != null &&
1648                     !isEmptyString(flowReturn.getNavigationCase().getFromOutcome()))
1649                 {
1650                     if (ELText.isLiteral(flowReturn.getNavigationCase().getFromOutcome()))
1651                     {
1652                         node.setFromOutcome(flowReturn.getNavigationCase().getFromOutcome());
1653                     }
1654                     else
1655                     {
1656                         node.setFromOutcome(
1657                             application.getExpressionFactory().createValueExpression(
1658                                 facesContext.getELContext(), flowReturn.getNavigationCase().getFromOutcome(),
1659                                 Object.class));
1660                     }
1661                 }
1662                 flow.putReturn(node.getId(), node);
1663             }
1664             
1665             flow.freeze();
1666             
1667             // Add the flow, so the config can be processed by the flow system and the
1668             // navigation system.
1669             application.getFlowHandler().addFlow(facesContext, flow);
1670         }
1671         
1672         AnnotatedFlowConfigurator.configureAnnotatedFlows(facesContext);
1673     }
1674     
1675     public static void enableDefaultWindowMode(FacesContext facesContext)
1676     {
1677         if (!isEnableDefaultWindowMode(facesContext))
1678         {
1679             String windowMode = WebConfigParamUtils.getStringInitParameter(
1680                     facesContext.getExternalContext(), 
1681                     ClientWindow.CLIENT_WINDOW_MODE_PARAM_NAME, null);
1682             
1683             if (windowMode == null)
1684             {
1685                 //No window mode set, force window mode to url
1686                 String defaultWindowMode = WebConfigParamUtils.getStringInitParameter(
1687                     facesContext.getExternalContext(), 
1688                     ClientWindowFactoryImpl.INIT_PARAM_DEFAULT_WINDOW_MODE, 
1689                     ClientWindowFactoryImpl.WINDOW_MODE_URL);
1690                 
1691                 log.info("The current configuration requires client window enabled, setting it to '"+
1692                     defaultWindowMode+"'");
1693                 
1694                 facesContext.getExternalContext().getApplicationMap().put(
1695                     ENABLE_DEFAULT_WINDOW_MODE, Boolean.TRUE);
1696             }
1697         }
1698     }
1699     
1700     public static boolean isEnableDefaultWindowMode(FacesContext facesContext)
1701     {
1702         return Boolean.TRUE.equals(facesContext.getExternalContext().
1703             getApplicationMap().get(ENABLE_DEFAULT_WINDOW_MODE));
1704     }
1705     
1706     private boolean isEmptyString(String value)
1707     {
1708         if (value == null)
1709         {
1710             return true;
1711         }
1712         else if (value.length() <= 0)
1713         {
1714             return true;
1715         }
1716         return false;
1717     }
1718 
1719     public void configureProtectedViews()
1720     {
1721         Application application = getApplication();
1722 
1723         FacesConfigData dispenser = getDispenser();
1724         //Protected Views
1725         ViewHandler viewHandler = application.getViewHandler();
1726         for (String urlPattern : dispenser.getProtectedViewUrlPatterns())
1727         {
1728             viewHandler.addProtectedView(urlPattern);
1729         }
1730     }
1731     
1732     protected InjectionProvider getInjectionProvider()
1733     {
1734         if (_injectionProvider == null)
1735         {
1736             _injectionProvider = InjectionProviderFactory.getInjectionProviderFactory(
1737                 _externalContext).getInjectionProvider(_externalContext);
1738         }
1739         return _injectionProvider;
1740     }
1741     
1742     protected FacesContext getFacesContext()
1743     {
1744         if (_facesContext == null)
1745         {
1746             _facesContext = FacesContext.getCurrentInstance();
1747         }
1748         return _facesContext;
1749     }
1750     
1751     protected Application getApplication()
1752     {
1753         if (_application == null)
1754         {
1755             return getFacesContext().getApplication();
1756         }
1757         return _application;
1758     }
1759     
1760     protected void setApplication(Application application)
1761     {
1762         this._application = application;
1763     }
1764 }