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.application;
20  
21  import java.beans.BeanDescriptor;
22  import java.beans.BeanInfo;
23  import java.lang.reflect.Constructor;
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.Collection;
27  import java.util.Collections;
28  import java.util.HashMap;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.Locale;
32  import java.util.Map;
33  import java.util.MissingResourceException;
34  import java.util.TimeZone;
35  import java.util.concurrent.ConcurrentHashMap;
36  import java.util.concurrent.CopyOnWriteArrayList;
37  import java.util.logging.Level;
38  import java.util.logging.Logger;
39  
40  import javax.el.CompositeELResolver;
41  import javax.el.ELContext;
42  import javax.el.ELContextListener;
43  import javax.el.ELException;
44  import javax.el.ELResolver;
45  import javax.el.ExpressionFactory;
46  import javax.el.MethodExpression;
47  import javax.el.ValueExpression;
48  import javax.faces.FacesException;
49  import javax.faces.application.Application;
50  import javax.faces.application.NavigationHandler;
51  import javax.faces.application.ProjectStage;
52  import javax.faces.application.Resource;
53  import javax.faces.application.ResourceDependencies;
54  import javax.faces.application.ResourceDependency;
55  import javax.faces.application.ResourceHandler;
56  import javax.faces.application.StateManager;
57  import javax.faces.application.ViewHandler;
58  import javax.faces.component.UIComponent;
59  import javax.faces.component.UIComponentBase;
60  import javax.faces.component.UINamingContainer;
61  import javax.faces.component.UIOutput;
62  import javax.faces.component.UIViewRoot;
63  import javax.faces.component.behavior.Behavior;
64  import javax.faces.component.behavior.ClientBehaviorBase;
65  import javax.faces.context.FacesContext;
66  import javax.faces.convert.Converter;
67  import javax.faces.convert.DateTimeConverter;
68  import javax.faces.el.MethodBinding;
69  import javax.faces.el.PropertyResolver;
70  import javax.faces.el.ReferenceSyntaxException;
71  import javax.faces.el.ValueBinding;
72  import javax.faces.el.VariableResolver;
73  import javax.faces.event.AbortProcessingException;
74  import javax.faces.event.ActionListener;
75  import javax.faces.event.ComponentSystemEventListener;
76  import javax.faces.event.ListenerFor;
77  import javax.faces.event.ListenersFor;
78  import javax.faces.event.SystemEvent;
79  import javax.faces.event.SystemEventListener;
80  import javax.faces.event.SystemEventListenerHolder;
81  import javax.faces.render.ClientBehaviorRenderer;
82  import javax.faces.render.Renderer;
83  import javax.faces.validator.Validator;
84  import javax.faces.view.ViewDeclarationLanguage;
85  import javax.naming.Context;
86  import javax.naming.InitialContext;
87  import javax.naming.NamingException;
88  
89  import org.apache.commons.beanutils.BeanUtils;
90  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
91  import org.apache.myfaces.config.RuntimeConfig;
92  import org.apache.myfaces.config.element.Property;
93  import org.apache.myfaces.config.element.ResourceBundle;
94  import org.apache.myfaces.context.RequestViewContext;
95  import org.apache.myfaces.el.PropertyResolverImpl;
96  import org.apache.myfaces.el.VariableResolverToApplicationELResolverAdapter;
97  import org.apache.myfaces.el.convert.MethodExpressionToMethodBinding;
98  import org.apache.myfaces.el.convert.ValueBindingToValueExpression;
99  import org.apache.myfaces.el.convert.ValueExpressionToValueBinding;
100 import org.apache.myfaces.el.unified.ELResolverBuilder;
101 import org.apache.myfaces.el.unified.ResolverBuilderForFaces;
102 import org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver;
103 import org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver.Scope;
104 import org.apache.myfaces.lifecycle.LifecycleImpl;
105 import org.apache.myfaces.shared.config.MyfacesConfig;
106 import org.apache.myfaces.shared.util.ClassUtils;
107 import org.apache.myfaces.view.facelets.el.ELText;
108 
109 /**
110  * DOCUMENT ME!
111  * 
112  * @author Manfred Geiler (latest modification by $Author: lu4242 $)
113  * @author Anton Koinov
114  * @author Thomas Spiegl
115  * @author Stan Silvert
116  * @version $Revision: 1296050 $ $Date: 2012-03-01 23:48:51 -0500 (Thu, 01 Mar 2012) $
117  */
118 @SuppressWarnings("deprecation")
119 public class ApplicationImpl extends Application
120 {
121     //private static final Log log = LogFactory.getLog(ApplicationImpl.class);
122     private static final Logger log = Logger.getLogger(ApplicationImpl.class.getName());
123 
124     private final static VariableResolver VARIABLERESOLVER = new VariableResolverToApplicationELResolverAdapter();
125 
126     private final static PropertyResolver PROPERTYRESOLVER = new PropertyResolverImpl();
127 
128     // the name for the system property which specifies the current ProjectStage (see MYFACES-2545 for details)
129     public final static String PROJECT_STAGE_SYSTEM_PROPERTY_NAME = "faces.PROJECT_STAGE";
130     
131     // MyFaces specific System Property to set the ProjectStage, if not present via the standard way
132     @Deprecated
133     public final static String MYFACES_PROJECT_STAGE_SYSTEM_PROPERTY_NAME = "org.apache.myfaces.PROJECT_STAGE";
134     
135     /**
136      * Set the default timezone as system timezone when a converter extending from DateTimeConverter is created.
137      */
138     @JSFWebConfigParam(defaultValue="false", expectedValues="true, false", since="2.0", group="validation")
139     public final static String DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE_PARAM_NAME 
140         = "javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE";
141     
142     /**
143      * Indicate the stage of the initialized application.
144      */
145     @JSFWebConfigParam(defaultValue="Production",
146             expectedValues="Development, Production, SystemTest, UnitTest",
147             since="2.0")
148     private static final String PROJECT_STAGE_PARAM_NAME = "javax.faces.PROJECT_STAGE";
149 
150     /**
151      * Indicate if the classes associated to components, converters, validators or behaviors
152      * should be loaded as soon as they are added to the current application instance or instead
153      * loaded in a lazy way.
154      */
155     @JSFWebConfigParam(defaultValue="true",since="2.0",tags="performance")
156     private static final String LAZY_LOAD_CONFIG_OBJECTS_PARAM_NAME = "org.apache.myfaces.LAZY_LOAD_CONFIG_OBJECTS";
157     private static final boolean LAZY_LOAD_CONFIG_OBJECTS_DEFAULT_VALUE = true;
158     private Boolean _lazyLoadConfigObjects = null;
159     
160     // ~ Instance fields
161     // --------------------------------------------------------------------------
162     // --
163 
164     private Collection<Locale> _supportedLocales = Collections.emptySet();
165     private Locale _defaultLocale;
166     private String _messageBundle;
167 
168     private ViewHandler _viewHandler;
169     private NavigationHandler _navigationHandler;
170     private ActionListener _actionListener;
171     private String _defaultRenderKitId;
172     private ResourceHandler _resourceHandler;
173     private StateManager _stateManager;
174 
175     private ArrayList<ELContextListener> _elContextListeners;
176 
177     // components, converters, and validators can be added at runtime--must
178     // synchronize, uses ConcurrentHashMap to allow concurrent read of map
179     private final Map<String, Object> _converterIdToClassMap = new ConcurrentHashMap<String, Object>();
180 
181     private final Map<Class<?>, Object> _converterTargetClassToConverterClassMap
182             = new ConcurrentHashMap<Class<?>, Object>();
183     
184     private final Map<String, Object> _componentClassMap = new ConcurrentHashMap<String, Object>();
185 
186     private final Map<String, Object> _validatorClassMap = new ConcurrentHashMap<String, Object>();
187 
188     private final Map<Class<? extends SystemEvent>, SystemListenerEntry> _systemEventListenerClassMap
189             = new ConcurrentHashMap<Class<? extends SystemEvent>, SystemListenerEntry>();
190 
191     private final Map<String, String> _defaultValidatorsIds = new HashMap<String, String>();
192     
193     private volatile Map<String, String> _cachedDefaultValidatorsIds = null;
194     
195     private final Map<String, Object> _behaviorClassMap = new ConcurrentHashMap<String, Object>();
196 
197     private final RuntimeConfig _runtimeConfig;
198 
199     private ELResolver elResolver;
200 
201     private ELResolverBuilder resolverBuilderForFaces;
202 
203     private ProjectStage _projectStage;
204 
205     private volatile boolean _firstRequestProcessed = false;
206     
207     // MYFACES-3442 If HashMap or other non thread-safe structure is used, it is
208     // possible to fall in a infinite loop under heavy load unless a synchronized block
209     // is used to modify it or a ConcurrentHashMap.
210     private final Map<Class<?>, List<ListenerFor>> _classToListenerForMap
211             = new ConcurrentHashMap<Class<?>, List<ListenerFor>>() ;
212 
213     private final Map<Class<?>, List<ResourceDependency>> _classToResourceDependencyMap
214             = new ConcurrentHashMap<Class<?>, List<ResourceDependency>>() ;
215     
216     private List<Class<? extends Converter>> _noArgConstructorConverterClasses 
217             = new CopyOnWriteArrayList<Class<? extends Converter>>();
218     
219     /** Value of javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE parameter */
220     private boolean _dateTimeConverterDefaultTimeZoneIsSystemTimeZone = false; 
221     
222     /**
223      * Represents semantic null in _componentClassMap. 
224      */
225     private static final UIComponent NOTHING = new UIComponentBase()
226     {
227         @Override
228         public String getFamily()
229         {
230             return null;
231         }
232     };
233     
234     // ~ Constructors
235     // --------------------------------------------------------------------------
236     // -----
237 
238     public ApplicationImpl()
239     {
240         this(getRuntimeConfig());
241     }
242 
243     private static RuntimeConfig getRuntimeConfig()
244     {
245         return RuntimeConfig.getCurrentInstance(
246                 FacesContext.getCurrentInstance().getExternalContext());
247     }
248 
249     ApplicationImpl(final RuntimeConfig runtimeConfig)
250     {
251         if (runtimeConfig == null)
252         {
253             throw new IllegalArgumentException("runtimeConfig must mot be null");
254         }
255         // set default implementation in constructor
256         // pragmatic approach, no syncronizing will be needed in get methods
257         _viewHandler = new ViewHandlerImpl();
258         _navigationHandler = new NavigationHandlerImpl();
259         _actionListener = new ActionListenerImpl();
260         _defaultRenderKitId = "HTML_BASIC";
261         _stateManager = new StateManagerImpl();
262         _elContextListeners = new ArrayList<ELContextListener>();
263         _resourceHandler = new ResourceHandlerImpl();
264         _runtimeConfig = runtimeConfig;
265 
266         if (log.isLoggable(Level.FINEST))
267         {
268             log.finest("New Application instance created");
269         }
270         
271         String configParam = getFaceContext().getExternalContext().
272                 getInitParameter(DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE_PARAM_NAME);
273         if (configParam != null && configParam.toLowerCase().equals("true"))
274         {
275             _dateTimeConverterDefaultTimeZoneIsSystemTimeZone = true;
276         }
277     }
278 
279     // ~ Methods
280     // --------------------------------------------------------------------------
281     // ----------
282 
283     @Override
284     public final void addELResolver(final ELResolver resolver)
285     {
286         if (isFirstRequestProcessed())
287         {
288             throw new IllegalStateException("It is illegal to add a resolver after the first request is processed");
289         }
290         if (resolver != null)
291         {
292             _runtimeConfig.addApplicationElResolver(resolver);
293         }
294     }
295 
296     @Override
297     public void addDefaultValidatorId(String validatorId)
298     {
299         if (_validatorClassMap.containsKey(validatorId))
300         {
301             Object validatorClass = getObjectFromClassMap(validatorId, _validatorClassMap);
302             String className;
303 
304             if (validatorClass instanceof Class)
305             {
306                 className = ((Class<?>)validatorClass).getName();
307             }
308             else
309             {
310                 className = validatorClass.toString();
311             }
312             // Ensure atomicity between _defaultValidatorsIds and _cachedDefaultValidatorsIds
313             synchronized(_defaultValidatorsIds)
314             {
315                 _defaultValidatorsIds.put(validatorId, className);
316                 _cachedDefaultValidatorsIds = null;
317             }
318         }
319     }
320 
321     @Override
322     public Map<String, String> getDefaultValidatorInfo()
323     {
324         // cachedMap ensures we will not return null if after the check for null
325         // _cachedDefaultValidatorsIds is set to null. In theory the unmodifiable map
326         // always has a reference to _defaultValidatorsIds, so any instance set
327         // in _cachedDefaultValidatorsIds is always the same.
328         Map<String, String> cachedMap = _cachedDefaultValidatorsIds;
329         if (cachedMap == null)
330         {
331             synchronized(_defaultValidatorsIds)
332             {
333                 if (_cachedDefaultValidatorsIds == null)
334                 {
335                     _cachedDefaultValidatorsIds = Collections.unmodifiableMap(_defaultValidatorsIds);
336                 }
337                 cachedMap = _cachedDefaultValidatorsIds;
338             }
339         }
340         return cachedMap;
341     }
342 
343     @Override
344     public final ELResolver getELResolver()
345     {
346         // we don't need synchronization here since it is ok to have multiple
347         // instances of the elresolver
348         if (elResolver == null)
349         {
350             elResolver = createFacesResolver();
351         }
352         return elResolver;
353     }
354 
355     private ELResolver createFacesResolver()
356     {
357         boolean supportJSPAndFacesEL = MyfacesConfig.getCurrentInstance(
358                                 getFaceContext().getExternalContext()).isSupportJSPAndFacesEL();
359         CompositeELResolver resolver;
360         if (supportJSPAndFacesEL)
361         {
362             resolver = new FacesCompositeELResolver(Scope.Faces);
363         }
364         else
365         {
366             resolver = new CompositeELResolver();
367         }
368         getResolverBuilderForFaces().build(resolver);
369         return resolver;
370     }
371 
372     protected final ELResolverBuilder getResolverBuilderForFaces()
373     {
374         if (resolverBuilderForFaces == null)
375         {
376             resolverBuilderForFaces = new ResolverBuilderForFaces(_runtimeConfig);
377         }
378         return resolverBuilderForFaces;
379     }
380 
381     public final void setResolverBuilderForFaces(final ELResolverBuilder factory)
382     {
383         resolverBuilderForFaces = factory;
384     }
385 
386     @Override
387     public final java.util.ResourceBundle getResourceBundle(final FacesContext facesContext, final String name)
388             throws FacesException, NullPointerException
389     {
390 
391         checkNull(facesContext, "facesContext");
392         checkNull(name, "name");
393 
394         final String bundleName = getBundleName(facesContext, name);
395 
396         if (bundleName == null)
397         {
398             return null;
399         }
400 
401         Locale locale = Locale.getDefault();
402 
403         final UIViewRoot viewRoot = facesContext.getViewRoot();
404         if (viewRoot != null && viewRoot.getLocale() != null)
405         {
406             locale = viewRoot.getLocale();
407         }
408 
409         try
410         {
411             return getResourceBundle(bundleName, locale, getClassLoader());
412         }
413         catch (MissingResourceException e)
414         {
415             try
416             {
417                 return getResourceBundle(bundleName, locale, this.getClass().getClassLoader());
418             }
419             catch (MissingResourceException e1)
420             {            
421                 throw new FacesException("Could not load resource bundle for name '"
422                                          + name + "': " + e.getMessage(), e1);
423             }
424         }
425     }
426 
427     private ClassLoader getClassLoader()
428     {
429         return ClassUtils.getContextClassLoader();
430     }
431 
432     String getBundleName(final FacesContext facesContext, final String name)
433     {
434         ResourceBundle bundle = getRuntimeConfig(facesContext).getResourceBundle(name);
435         return bundle != null ? bundle.getBaseName() : null;
436     }
437 
438     java.util.ResourceBundle getResourceBundle(final String name, final Locale locale, final ClassLoader loader)
439             throws MissingResourceException
440     {
441         return java.util.ResourceBundle.getBundle(name, locale, loader);
442     }
443 
444     final RuntimeConfig getRuntimeConfig(final FacesContext facesContext)
445     {
446         return RuntimeConfig.getCurrentInstance(facesContext.getExternalContext());
447     }
448 
449     final FacesContext getFaceContext()
450     {
451         return FacesContext.getCurrentInstance();
452     }
453 
454     @Override
455     public final UIComponent createComponent(final ValueExpression componentExpression,
456                                              final FacesContext facesContext, final String componentType)
457             throws FacesException, NullPointerException
458     {
459 
460         /*
461          * Before the component instance is returned, it must be inspected for the presence of a ListenerFor (or
462          * ListenersFor) or ResourceDependency (or ResourceDependencies) annotation. If any of these annotations are
463          * present, the action listed in ListenerFor or ResourceDependency must be taken on the component, 
464          * before it is
465          * returned from this method. This variant of createComponent must not inspect the Renderer for the 
466          * component to
467          * be returned for any of the afore mentioned annotations. Such inspection is the province of
468          */
469 
470         checkNull(componentExpression, "componentExpression");
471         checkNull(facesContext, "facesContext");
472         checkNull(componentType, "componentType");
473 
474         ELContext elContext = facesContext.getELContext();
475 
476         try
477         {
478             Object retVal = componentExpression.getValue(elContext);
479 
480             UIComponent createdComponent;
481 
482             if (retVal instanceof UIComponent)
483             {
484                 createdComponent = (UIComponent) retVal;
485                 _handleAnnotations(facesContext, createdComponent, createdComponent);
486             }
487             else
488             {
489                 createdComponent = createComponent(componentType);
490                 componentExpression.setValue(elContext, createdComponent);
491             }
492 
493             return createdComponent;
494         }
495         catch (FacesException e)
496         {
497             throw e;
498         }
499         catch (Exception e)
500         {
501             throw new FacesException(e);
502         }
503     }
504 
505     @Override
506     public UIComponent createComponent(ValueExpression componentExpression, FacesContext context, 
507                                        String componentType, String rendererType)
508     {
509         // Like createComponent(ValueExpression, FacesContext, String)
510         UIComponent component = createComponent(componentExpression, context, componentType);
511 
512         _inspectRenderer(context, component, componentType, rendererType);
513 
514         return component;
515     }
516 
517     @Override
518     public final ExpressionFactory getExpressionFactory()
519     {
520         return _runtimeConfig.getExpressionFactory();
521     }
522 
523     @SuppressWarnings("unchecked")
524     @Override
525     public final <T> T evaluateExpressionGet(final FacesContext context, final String expression,
526                                              final Class<? extends T> expectedType) throws ELException
527     {
528         ELContext elContext = context.getELContext();
529 
530         ExpressionFactory factory = getExpressionFactory();
531 
532         return (T) factory.createValueExpression(elContext, expression, expectedType).getValue(elContext);
533     }
534 
535     @Override
536     public final void addELContextListener(final ELContextListener listener)
537     {
538         synchronized (_elContextListeners)
539         {
540             _elContextListeners.add(listener);
541         }
542     }
543 
544     @Override
545     public void publishEvent(FacesContext facesContext, Class<? extends SystemEvent> systemEventClass,
546                              Class<?> sourceBaseType, Object source)
547     {
548         checkNull(systemEventClass, "systemEventClass");
549         checkNull(source, "source");
550         
551         //Call events only if event processing is enabled.
552         if (!facesContext.isProcessingEvents())
553         {
554             return;
555         }
556         
557         // spec: If this argument is null the return from source.getClass() must be used as the sourceBaseType. 
558         if (sourceBaseType == null)
559         {
560             sourceBaseType = source.getClass();
561         }
562         
563         try
564         {
565             SystemEvent event = null;
566             if (source instanceof SystemEventListenerHolder)
567             {
568                 SystemEventListenerHolder holder = (SystemEventListenerHolder) source;
569 
570                 // If the source argument implements SystemEventListenerHolder, call
571                 // SystemEventListenerHolder.getListenersForEventClass(java.lang.Class) on it, passing the
572                 // systemEventClass
573                 // argument. If the list is not empty, perform algorithm traverseListenerList on the list.
574                 event = _traverseListenerList(holder.getListenersForEventClass(systemEventClass), systemEventClass,
575                                               source, event);
576             }
577             
578             UIViewRoot uiViewRoot = facesContext.getViewRoot();
579             if (uiViewRoot != null)
580             {
581                 //Call listeners on view level
582                 event = _traverseListenerListWithCopy(uiViewRoot.getViewListenersForEventClass(systemEventClass), 
583                         systemEventClass, source, event);
584             }
585 
586             SystemListenerEntry systemListenerEntry = _systemEventListenerClassMap.get(systemEventClass);
587             if (systemListenerEntry != null)
588             {
589                 systemListenerEntry.publish(systemEventClass, sourceBaseType, source, event);
590             }
591         }
592         catch (AbortProcessingException e)
593         {
594             // If the act of invoking the processListener method causes an AbortProcessingException to be thrown,
595             // processing of the listeners must be aborted, no further processing of the listeners for this event must
596             // take place, and the exception must be logged with Level.SEVERE.
597             log.log(Level.SEVERE, "Event processing was aborted", e);
598         }
599     }
600 
601     @Override
602     public void publishEvent(FacesContext facesContext, Class<? extends SystemEvent> systemEventClass, Object source)
603     {
604         publishEvent(facesContext, systemEventClass, source.getClass(), source);
605     }
606 
607     @Override
608     public final void removeELContextListener(final ELContextListener listener)
609     {
610         synchronized (_elContextListeners)
611         {
612             _elContextListeners.remove(listener);
613         }
614     }
615 
616     @Override
617     public final ELContextListener[] getELContextListeners()
618     {
619         // this gets called on every request, so I can't afford to synchronize
620         // I just have to trust that toArray() with do the right thing if the
621         // list is changing (not likely)
622         return _elContextListeners.toArray(new ELContextListener[_elContextListeners.size()]);
623     }
624 
625     @Override
626     public final void setActionListener(final ActionListener actionListener)
627     {
628         checkNull(actionListener, "actionListener");
629 
630         _actionListener = actionListener;
631         if (log.isLoggable(Level.FINEST))
632         {
633             log.finest("set actionListener = " + actionListener.getClass().getName());
634         }
635     }
636 
637     @Override
638     public final ActionListener getActionListener()
639     {
640         return _actionListener;
641     }
642 
643     @Override
644     public Iterator<String> getBehaviorIds()
645     {
646         return _behaviorClassMap.keySet().iterator();
647     }
648 
649     @Override
650     public final Iterator<String> getComponentTypes()
651     {
652         return _componentClassMap.keySet().iterator();
653     }
654 
655     @Override
656     public final Iterator<String> getConverterIds()
657     {
658         return _converterIdToClassMap.keySet().iterator();
659     }
660 
661     @Override
662     public final Iterator<Class<?>> getConverterTypes()
663     {
664         return _converterTargetClassToConverterClassMap.keySet().iterator();
665     }
666 
667     @Override
668     public final void setDefaultLocale(final Locale locale)
669     {
670         checkNull(locale, "locale");
671 
672         _defaultLocale = locale;
673         if (log.isLoggable(Level.FINEST))
674         {
675             log.finest("set defaultLocale = " + locale.getCountry() + " " + locale.getLanguage());
676         }
677     }
678 
679     @Override
680     public final Locale getDefaultLocale()
681     {
682         return _defaultLocale;
683     }
684 
685     @Override
686     public final void setMessageBundle(final String messageBundle)
687     {
688         checkNull(messageBundle, "messageBundle");
689 
690         _messageBundle = messageBundle;
691         if (log.isLoggable(Level.FINEST))
692         {
693             log.finest("set MessageBundle = " + messageBundle);
694         }
695     }
696 
697     @Override
698     public final String getMessageBundle()
699     {
700         return _messageBundle;
701     }
702 
703     @Override
704     public final void setNavigationHandler(final NavigationHandler navigationHandler)
705     {
706         checkNull(navigationHandler, "navigationHandler");
707 
708         _navigationHandler = navigationHandler;
709         if (log.isLoggable(Level.FINEST))
710         {
711             log.finest("set NavigationHandler = " + navigationHandler.getClass().getName());
712         }
713     }
714 
715     @Override
716     public final NavigationHandler getNavigationHandler()
717     {
718         return _navigationHandler;
719     }
720 
721     /**
722      * @deprecated
723      */
724     @Deprecated
725     @Override
726     public final void setPropertyResolver(final PropertyResolver propertyResolver)
727     {
728         checkNull(propertyResolver, "propertyResolver");
729 
730         if (getFaceContext() != null)
731         {
732             throw new IllegalStateException("propertyResolver must be defined before request processing");
733         }
734 
735         _runtimeConfig.setPropertyResolver(propertyResolver);
736 
737         if (log.isLoggable(Level.FINEST))
738         {
739             log.finest("set PropertyResolver = " + propertyResolver.getClass().getName());
740         }
741     }
742 
743     @Override
744     public ProjectStage getProjectStage()
745     {
746         // If the value has already been determined by a previous call to this
747         // method, simply return that value.
748         if (_projectStage == null)
749         {
750             String stageName = null;
751             
752             // try to obtain the ProjectStage from the system property
753             // faces.PROJECT_STAGE as proposed by Ed Burns
754             stageName = System.getProperty(PROJECT_STAGE_SYSTEM_PROPERTY_NAME);
755             
756             if (stageName == null)
757             {
758                 // if not found check for the "old" System Property
759                 // and print a warning message to the log (just to be 
760                 // sure that everyone recognizes the change in the name).
761                 stageName = System.getProperty(MYFACES_PROJECT_STAGE_SYSTEM_PROPERTY_NAME);
762                 if (stageName != null)
763                 {
764                     log.log(Level.WARNING, "The system property " + MYFACES_PROJECT_STAGE_SYSTEM_PROPERTY_NAME
765                             + " has been replaced by " + PROJECT_STAGE_SYSTEM_PROPERTY_NAME + "!"
766                             + " Please change your settings.");
767                 }
768             }
769             
770             if (stageName == null)
771             {
772                 // Look for a JNDI environment entry under the key given by the
773                 // value of ProjectStage.PROJECT_STAGE_JNDI_NAME (return type of
774                 // java.lang.String).
775                 try
776                 {
777                     Context ctx = new InitialContext();
778                     Object temp = ctx.lookup(ProjectStage.PROJECT_STAGE_JNDI_NAME);
779                     if (temp != null)
780                     {
781                         if (temp instanceof String)
782                         {
783                             stageName = (String) temp;
784                         }
785                         else
786                         {
787                             log.severe("JNDI lookup for key " + ProjectStage.PROJECT_STAGE_JNDI_NAME
788                                     + " should return a java.lang.String value");
789                         }
790                     }
791                 }
792                 catch (NamingException e)
793                 {
794                     // no-op
795                 }
796                 catch (NoClassDefFoundError er)
797                 {
798                     //On Google App Engine, javax.naming.Context is a restricted class.
799                     //In that case, NoClassDefFoundError is thrown. stageName needs to be configured
800                     //below by context parameter.
801                     //It can be done with changing the order to look first at
802                     // context param, but it is defined in the spec.
803                     //http://java.sun.com/javaee/6/docs/api/javax/faces/application/Application.html#getProjectStage()
804                     //no-op
805                 }
806             }
807 
808             /*
809              * If found, continue with the algorithm below, otherwise, look for an entry in the initParamMap of the
810              * ExternalContext from the current FacesContext with the key ProjectStage.PROJECT_STAGE_PARAM_NAME
811              */
812             if (stageName == null)
813             {
814                 FacesContext context = FacesContext.getCurrentInstance();
815                 stageName = context.getExternalContext().getInitParameter(ProjectStage.PROJECT_STAGE_PARAM_NAME);
816             }
817 
818             // If a value is found
819             if (stageName != null)
820             {
821                 /*
822                  * see if an enum constant can be obtained by calling ProjectStage.valueOf(), passing 
823                  * the value from the initParamMap. If this succeeds without exception, save the value 
824                  * and return it.
825                  */
826                 try
827                 {
828                     _projectStage = ProjectStage.valueOf(stageName);
829                     return _projectStage;
830                 }
831                 catch (IllegalArgumentException e)
832                 {
833                     log.log(Level.SEVERE, "Couldn't discover the current project stage", e);
834                 }
835             }
836             else
837             {
838                 if (log.isLoggable(Level.INFO))
839                 {
840                     log.info("Couldn't discover the current project stage, using " + ProjectStage.Production);
841                 }
842             }
843 
844             /*
845              * If not found, or any of the previous attempts to discover the enum constant value have failed, log a
846              * descriptive error message, assign the value as ProjectStage.Production and return it.
847              */
848             
849             _projectStage = ProjectStage.Production;
850         }
851 
852         return _projectStage;
853     }
854 
855     /**
856      * @deprecated
857      */
858     @Deprecated
859     @Override
860     public final PropertyResolver getPropertyResolver()
861     {
862         return PROPERTYRESOLVER;
863     }
864 
865     @Override
866     public final void setResourceHandler(ResourceHandler resourceHandler)
867     {
868         checkNull(resourceHandler, "resourceHandler");
869 
870         if(isFirstRequestProcessed())
871         {
872             throw new IllegalStateException(
873                     "setResourceHandler may not be executed after a lifecycle request has been completed");
874         }
875         _resourceHandler = resourceHandler;
876     }
877 
878     @Override
879     public final ResourceHandler getResourceHandler()
880     {
881         return _resourceHandler;
882     }
883 
884     @Override
885     public final void setSupportedLocales(final Collection<Locale> locales)
886     {
887         checkNull(locales, "locales");
888 
889         _supportedLocales = locales;
890         if (log.isLoggable(Level.FINEST))
891         {
892             log.finest("set SupportedLocales");
893         }
894     }
895 
896     @Override
897     public final Iterator<Locale> getSupportedLocales()
898     {
899         return _supportedLocales.iterator();
900     }
901 
902     @Override
903     public final Iterator<String> getValidatorIds()
904     {
905         return _validatorClassMap.keySet().iterator();
906     }
907 
908     /**
909      * @deprecated
910      */
911     @Deprecated
912     @Override
913     public final void setVariableResolver(final VariableResolver variableResolver)
914     {
915         checkNull(variableResolver, "variableResolver");
916 
917         if (isFirstRequestProcessed())
918         {
919             throw new IllegalStateException("variableResolver must be defined before request processing");
920         }
921 
922         _runtimeConfig.setVariableResolver(variableResolver);
923 
924         if (log.isLoggable(Level.FINEST))
925         {
926             log.finest("set VariableResolver = " + variableResolver.getClass().getName());
927         }
928     }
929 
930     /**
931      * @deprecated
932      */
933     @Deprecated
934     @Override
935     public final VariableResolver getVariableResolver()
936     {
937         return VARIABLERESOLVER;
938     }
939 
940     @Override
941     public final void setViewHandler(final ViewHandler viewHandler)
942     {
943         checkNull(viewHandler, "viewHandler");
944 
945         if(isFirstRequestProcessed())
946         {
947             throw new IllegalStateException(
948                     "setViewHandler may not be executed after a lifecycle request has been completed");
949         }
950         _viewHandler = viewHandler;
951         if (log.isLoggable(Level.FINEST))
952         {
953             log.finest("set ViewHandler = " + viewHandler.getClass().getName());
954         }
955     }
956     
957     @Override
958     public void subscribeToEvent(Class<? extends SystemEvent> systemEventClass, SystemEventListener listener)
959     {
960         subscribeToEvent(systemEventClass, null, listener);
961     }
962 
963     @Override
964     public void subscribeToEvent(Class<? extends SystemEvent> systemEventClass, Class<?> sourceClass,
965                                  SystemEventListener listener)
966     {
967         checkNull(systemEventClass, "systemEventClass");
968         checkNull(listener, "listener");
969 
970         SystemListenerEntry systemListenerEntry;
971         synchronized (_systemEventListenerClassMap)
972         {
973             systemListenerEntry = _systemEventListenerClassMap.get(systemEventClass);
974             if (systemListenerEntry == null)
975             {
976                 systemListenerEntry = new SystemListenerEntry();
977                 _systemEventListenerClassMap.put(systemEventClass, systemListenerEntry);
978             }
979         }
980 
981         systemListenerEntry.addListener(listener, sourceClass);
982     }
983     
984     @Override
985     public void unsubscribeFromEvent(Class<? extends SystemEvent> systemEventClass, SystemEventListener listener)
986     {
987         unsubscribeFromEvent(systemEventClass, null, listener);
988     }
989 
990     @Override
991     public void unsubscribeFromEvent(Class<? extends SystemEvent> systemEventClass, Class<?> sourceClass,
992                                      SystemEventListener listener)
993     {
994         checkNull(systemEventClass, "systemEventClass");
995         checkNull(listener, "listener");
996 
997         SystemListenerEntry systemListenerEntry = _systemEventListenerClassMap.get(systemEventClass);
998         if (systemListenerEntry != null)
999         {
1000             systemListenerEntry.removeListener(listener, sourceClass);
1001         }
1002     }
1003 
1004     @Override
1005     public final ViewHandler getViewHandler()
1006     {
1007         return _viewHandler;
1008     }
1009 
1010     @Override
1011     public void addBehavior(String behaviorId, String behaviorClass)
1012     {
1013         checkNull(behaviorId, "behaviorId");
1014         checkEmpty(behaviorId, "behaviorId");
1015         checkNull(behaviorClass, "behaviorClass");
1016         checkEmpty(behaviorClass, "behaviorClass");
1017 
1018         try
1019         {
1020             if(isLazyLoadConfigObjects())
1021             {
1022                 _behaviorClassMap.put(behaviorId, behaviorClass);
1023             }
1024             else
1025             {
1026                 _behaviorClassMap.put(behaviorId, ClassUtils.simpleClassForName(behaviorClass));
1027             }
1028             
1029             if (log.isLoggable(Level.FINEST))
1030             {
1031                 log.finest("add Behavior class = " + behaviorClass + " for id = " + behaviorId);
1032             }
1033         }
1034         catch (Exception e)
1035         {
1036             log.log(Level.SEVERE, "Behavior class " + behaviorClass + " not found", e);
1037         }
1038 
1039     }
1040 
1041     @Override
1042     public final void addComponent(final String componentType, final String componentClassName)
1043     {
1044         checkNull(componentType, "componentType");
1045         checkEmpty(componentType, "componentType");
1046         checkNull(componentClassName, "componentClassName");
1047         checkEmpty(componentClassName, "componentClassName");
1048 
1049         try
1050         {
1051             if(isLazyLoadConfigObjects())
1052             {
1053                 _componentClassMap.put(componentType, componentClassName);
1054             }
1055             else
1056             {
1057                 _componentClassMap.put(componentType, ClassUtils.simpleClassForName(componentClassName));
1058             }
1059             
1060             if (log.isLoggable(Level.FINEST))
1061             {
1062                 log.finest("add Component class = " + componentClassName + " for type = " + componentType);
1063             }
1064         }
1065         catch (Exception e)
1066         {
1067             log.log(Level.SEVERE, "Component class " + componentClassName + " not found", e);
1068         }
1069     }
1070 
1071     @Override
1072     public final void addConverter(final String converterId, final String converterClass)
1073     {
1074         checkNull(converterId, "converterId");
1075         checkEmpty(converterId, "converterId");
1076         checkNull(converterClass, "converterClass");
1077         checkEmpty(converterClass, "converterClass");
1078 
1079         try
1080         {
1081             if(isLazyLoadConfigObjects())
1082             {
1083                 _converterIdToClassMap.put(converterId, converterClass);
1084             }
1085             else
1086             {
1087                 _converterIdToClassMap.put(converterId, ClassUtils.simpleClassForName(converterClass));
1088             }
1089             if (log.isLoggable(Level.FINEST))
1090             {
1091                 log.finest("add Converter id = " + converterId + " converterClass = " + converterClass);
1092             }
1093         }
1094         catch (Exception e)
1095         {
1096             log.log(Level.SEVERE, "Converter class " + converterClass + " not found", e);
1097         }
1098     }
1099 
1100     @Override
1101     public final void addConverter(final Class<?> targetClass, final String converterClass)
1102     {
1103         checkNull(targetClass, "targetClass");
1104         checkNull(converterClass, "converterClass");
1105         checkEmpty(converterClass, "converterClass");
1106 
1107         try
1108         {
1109             if(isLazyLoadConfigObjects())
1110             {
1111                 _converterTargetClassToConverterClassMap.put(targetClass, converterClass);
1112             }
1113             else
1114             {
1115                 _converterTargetClassToConverterClassMap.put(targetClass,
1116                                                              ClassUtils.simpleClassForName(converterClass));
1117             }
1118 
1119             if (log.isLoggable(Level.FINEST))
1120             {
1121                 log.finest("add Converter for class = " + targetClass + " converterClass = " + converterClass);
1122             }
1123         }
1124         catch (Exception e)
1125         {
1126             log.log(Level.SEVERE, "Converter class " + converterClass + " not found", e);
1127         }
1128     }
1129 
1130     @Override
1131     public final void addValidator(final String validatorId, final String validatorClass)
1132     {
1133         checkNull(validatorId, "validatorId");
1134         checkEmpty(validatorId, "validatorId");
1135         checkNull(validatorClass, "validatorClass");
1136         checkEmpty(validatorClass, "validatorClass");
1137 
1138         try
1139         {
1140             if(isLazyLoadConfigObjects())
1141             {
1142                 _validatorClassMap.put(validatorId, validatorClass);
1143             }
1144             else
1145             {
1146                 _validatorClassMap.put(validatorId, ClassUtils.simpleClassForName(validatorClass));
1147             }
1148             
1149             if (log.isLoggable(Level.FINEST))
1150             {
1151                 log.finest("add Validator id = " + validatorId + " class = " + validatorClass);
1152             }
1153         }
1154         catch (Exception e)
1155         {
1156             log.log(Level.SEVERE, "Validator class " + validatorClass + " not found", e);
1157         }
1158     }
1159 
1160     @Override
1161     public Behavior createBehavior(String behaviorId) throws FacesException
1162     {
1163         checkNull(behaviorId, "behaviorId");
1164         checkEmpty(behaviorId, "behaviorId");
1165 
1166         final Class<?> behaviorClass = getObjectFromClassMap(behaviorId, _behaviorClassMap);
1167         
1168         if (behaviorClass == null)
1169         {
1170             throw new FacesException("Could not find any registered behavior-class for behaviorId : " + behaviorId);
1171         }
1172         
1173         try
1174         {
1175             Behavior behavior = (Behavior)behaviorClass.newInstance();
1176 
1177             _handleAttachedResourceDependencyAnnotations(FacesContext.getCurrentInstance(), behavior);
1178 
1179             if (behavior instanceof ClientBehaviorBase)
1180             {
1181               ClientBehaviorBase clientBehavior = (ClientBehaviorBase) behavior;
1182               String renderType = clientBehavior.getRendererType();
1183               if (renderType != null)
1184               {
1185                 FacesContext ctx = FacesContext.getCurrentInstance();
1186                 ClientBehaviorRenderer cbr = ctx.getRenderKit().getClientBehaviorRenderer(renderType);
1187                 _handleAttachedResourceDependencyAnnotations(FacesContext.getCurrentInstance(), cbr);
1188               }
1189             }
1190 
1191             return behavior;
1192         }
1193         catch (Exception e)
1194         {
1195             log.log(Level.SEVERE, "Could not instantiate behavior " + behaviorClass, e);
1196             throw new FacesException("Could not instantiate behavior: " + behaviorClass, e);
1197         }
1198     }
1199 
1200     @Override
1201     public UIComponent createComponent(FacesContext context, Resource componentResource)
1202     {
1203         checkNull(context, "context");
1204         checkNull(componentResource, "componentResource");
1205         
1206         UIComponent component = null;
1207         Resource resource;
1208         String fqcn;
1209         Class<? extends UIComponent> componentClass = null;
1210 
1211         /*
1212          * Obtain a reference to the ViewDeclarationLanguage for this Application instance by calling
1213          * ViewHandler.getViewDeclarationLanguage(javax.faces.context.FacesContext, java.lang.String), passing the
1214          * viewId found by calling UIViewRoot.getViewId() on the UIViewRoot in the argument FacesContext.
1215          */
1216         UIViewRoot view = context.getViewRoot();
1217         Application application = context.getApplication();
1218         ViewDeclarationLanguage vdl
1219                 = application.getViewHandler().getViewDeclarationLanguage(context, view.getViewId());
1220 
1221         /*
1222          * Obtain a reference to the composite component metadata for this composite component by calling
1223          * ViewDeclarationLanguage.getComponentMetadata(javax.faces.context.FacesContext,
1224          * javax.faces.application.Resource), passing the facesContext and componentResource arguments to this method.
1225          * This version of JSF specification uses JavaBeans as the API to the component metadata.
1226          */
1227         BeanInfo metadata = vdl.getComponentMetadata(context, componentResource);
1228         if (metadata == null)
1229         {
1230             throw new FacesException("Could not get component metadata for " 
1231                     + componentResource.getResourceName()
1232                     + ". Did you forget to specify <composite:interface>?");
1233         }
1234 
1235         /*
1236          * Determine if the component author declared a component-type for this component instance by obtaining the
1237          * BeanDescriptor from the component metadata and calling its getValue() method, passing
1238          * UIComponent.COMPOSITE_COMPONENT_TYPE_KEY as the argument. If non-null, the result must be a ValueExpression
1239          * whose value is the component-type of the UIComponent to be created for this Resource component. Call through
1240          * to createComponent(java.lang.String) to create the component.
1241          */
1242         BeanDescriptor descriptor = metadata.getBeanDescriptor();
1243         ValueExpression componentType = (ValueExpression) descriptor.getValue(
1244                 UIComponent.COMPOSITE_COMPONENT_TYPE_KEY);
1245         boolean annotationsApplied = false;
1246         if (componentType != null)
1247         {
1248             component = application.createComponent((String) componentType.getValue(context.getELContext()));
1249             annotationsApplied = true;
1250         }
1251         else
1252         {
1253             /*
1254              * Otherwise, determine if a script based component for this Resource can be found by calling
1255              * ViewDeclarationLanguage.getScriptComponentResource(javax.faces.context.FacesContext,
1256              * javax.faces.application.Resource). If the result is non-null, and is a script written in one of the
1257              * languages listed in JSF 4.3 of the specification prose document, create a UIComponent instance from the
1258              * script resource.
1259              */
1260             resource = vdl.getScriptComponentResource(context, componentResource);
1261             if (resource != null)
1262             {
1263                 String name = resource.getResourceName();
1264                 String className = name.substring(0, name.lastIndexOf('.'));
1265 
1266                 component = (UIComponent)ClassUtils.newInstance(className);
1267             }
1268             else
1269             {
1270                 /*
1271                  * Otherwise, let library-name be the return from calling Resource.getLibraryName() on the argument
1272                  * componentResource and resource-name be the return from calling Resource.getResourceName() on the
1273                  * argument componentResource. Create a fully qualified Java class name by removing any file extension
1274                  * from resource-name and let fqcn be library-name + "." + resource-name. If a class with the name of
1275                  * fqcn cannot be found, take no action and continue to the next step. If any of 
1276                  * InstantiationException,
1277                  * IllegalAccessException, or ClassCastException are thrown, wrap the exception in a FacesException and
1278                  * re-throw it. If any other exception is thrown, log the exception and continue to the next step.
1279                  */
1280 
1281                 boolean isProduction = FacesContext.getCurrentInstance().isProjectStage(ProjectStage.Production);
1282                 String name = componentResource.getResourceName();
1283                 String className = name.substring(0, name.lastIndexOf('.'));
1284                 fqcn = componentResource.getLibraryName() + "." + className;
1285                 
1286                 if (isProduction)
1287                 {
1288                     componentClass = (Class<? extends UIComponent>) _componentClassMap.get(fqcn);
1289                 }
1290                 if (componentClass == null)
1291                 {
1292                     try
1293                     {
1294                         componentClass = ClassUtils.classForName(fqcn);
1295                         if (isProduction)
1296                         {
1297                             _componentClassMap.put(fqcn, componentClass);
1298                         }
1299                     }
1300                     catch (ClassNotFoundException e)
1301                     {
1302                         // Remember here that classForName did not find Class
1303                         if (isProduction)
1304                         {
1305                             _componentClassMap.put(fqcn, NOTHING.getClass());
1306                         }
1307                     }
1308                 }
1309 
1310                 if (componentClass != null && NOTHING.getClass() != componentClass)
1311                 {
1312                     try
1313                     {
1314                         component = componentClass.newInstance();
1315                     }
1316                     catch (InstantiationException e)
1317                     {
1318                         log.log(Level.SEVERE, "Could not instantiate component class name = " + fqcn, e);
1319                         throw new FacesException("Could not instantiate component class name = " + fqcn, e);
1320                     }
1321                     catch (IllegalAccessException e)
1322                     {
1323                         log.log(Level.SEVERE, "Could not instantiate component class name = " + fqcn, e);
1324                         throw new FacesException("Could not instantiate component class name = " + fqcn, e);
1325                     }
1326                     catch (Exception e)
1327                     {
1328                         log.log(Level.SEVERE, "Could not instantiate component class name = " + fqcn, e);
1329                     }
1330                 }
1331 
1332                 /*
1333                  * If none of the previous steps have yielded a UIComponent instance, call
1334                  * createComponent(java.lang.String) passing "javax.faces.NamingContainer" as the argument.
1335                  */
1336                 if (component == null)
1337                 {
1338                     component = application.createComponent(UINamingContainer.COMPONENT_TYPE);
1339                     annotationsApplied = true;
1340                 }
1341             }
1342         }
1343 
1344         /*
1345          * Call UIComponent.setRendererType(java.lang.String) on the UIComponent instance, passing
1346          * "javax.faces.Composite" as the argument.
1347          */
1348         component.setRendererType("javax.faces.Composite");
1349 
1350         /*
1351          * Store the argument Resource in the attributes Map of the UIComponent under the key,
1352          * Resource.COMPONENT_RESOURCE_KEY.
1353          */
1354         component.getAttributes().put(Resource.COMPONENT_RESOURCE_KEY, componentResource);
1355 
1356         /*
1357          * Store composite component metadata in the attributes Map of the UIComponent under the key,
1358          * UIComponent.BEANINFO_KEY.
1359          */
1360         component.getAttributes().put(UIComponent.BEANINFO_KEY, metadata);
1361 
1362         /*
1363          * Before the component instance is returned, it must be inspected for the presence of a 
1364          * ListenerFor annotation.
1365          * If this annotation is present, the action listed in ListenerFor must be taken on the component, 
1366          * before it is
1367          * returned from this method.
1368          */
1369         if (!annotationsApplied)
1370         {
1371             _handleAnnotations(context, component, component);
1372         }
1373 
1374         return component;
1375     }
1376 
1377     @Override
1378     public UIComponent createComponent(FacesContext context, String componentType, String rendererType)
1379     {
1380         checkNull(context, "context");
1381         checkNull(componentType, "componentType");
1382 
1383         // Like createComponent(String)
1384         UIComponent component = createComponent(componentType);
1385 
1386         _inspectRenderer(context, component, componentType, rendererType);
1387 
1388         return component;
1389     }
1390 
1391     @Override
1392     public final UIComponent createComponent(final String componentType) throws FacesException
1393     {
1394         checkNull(componentType, "componentType");
1395         checkEmpty(componentType, "componentType");
1396 
1397         final Class<?> componentClass = getObjectFromClassMap(componentType, _componentClassMap);
1398         if (componentClass == null)
1399         {
1400             log.log(Level.SEVERE, "Undefined component type " + componentType);
1401             throw new FacesException("Undefined component type " + componentType);
1402         }
1403 
1404         try
1405         {
1406             UIComponent component = (UIComponent)componentClass.newInstance();            
1407             _handleAnnotations(FacesContext.getCurrentInstance(), component, component);
1408             return component;
1409         }
1410         catch (Exception e)
1411         {
1412             log.log(Level.SEVERE, "Could not instantiate component componentType = " + componentType, e);
1413             throw new FacesException("Could not instantiate component componentType = " + componentType, e);
1414         }
1415     }
1416 
1417     /**
1418      * @deprecated Use createComponent(ValueExpression, FacesContext, String) instead.
1419      */
1420     @Deprecated
1421     @Override
1422     public final UIComponent createComponent(final ValueBinding valueBinding, final FacesContext facesContext,
1423                                              final String componentType) throws FacesException
1424     {
1425 
1426         checkNull(valueBinding, "valueBinding");
1427         checkNull(facesContext, "facesContext");
1428         checkNull(componentType, "componentType");
1429         checkEmpty(componentType, "componentType");
1430 
1431         final ValueExpression valExpression = new ValueBindingToValueExpression(valueBinding);
1432 
1433         return createComponent(valExpression, facesContext, componentType);
1434     }
1435 
1436     /**
1437      * Return an instance of the converter class that has been registered under the specified id.
1438      * <p>
1439      * Converters are registered via faces-config.xml files, and can also be registered via the addConverter(String id,
1440      * Class converterClass) method on this class. Here the the appropriate Class definition is found, then an instance
1441      * is created and returned.
1442      * <p>
1443      * A converter registered via a config file can have any number of nested attribute or property tags. The JSF
1444      * specification is very vague about what effect these nested tags have. This method ignores nested attribute
1445      * definitions, but for each nested property tag the corresponding setter is invoked on the new Converter instance
1446      * passing the property's defaultValuer. Basic typeconversion is done so the target properties on the Converter
1447      * instance can be String, int, boolean, etc. Note that:
1448      * <ol>
1449      * <li>the Sun Mojarra JSF implemenation ignores nested property tags completely, so this behaviour cannot be 
1450      * relied on across implementations.
1451      * <li>there is no equivalent functionality for converter classes registered via the Application.addConverter api
1452      * method.
1453      * </ol>
1454      * <p>
1455      * Note that this method is most commonly called from the standard f:attribute tag. As an alternative, most
1456      * components provide a "converter" attribute which uses an EL expression to create a Converter instance, in which
1457      * case this method is not invoked at all. The converter attribute allows the returned Converter instance to be
1458      * configured via normal dependency-injection, and is generally a better choice than using this method.
1459      */
1460     @Override
1461     public final Converter createConverter(final String converterId)
1462     {
1463         checkNull(converterId, "converterId");
1464         checkEmpty(converterId, "converterId");
1465 
1466         final Class<?> converterClass = getObjectFromClassMap(converterId, _converterIdToClassMap);
1467         if (converterClass == null)
1468         {
1469             throw new FacesException("Could not find any registered converter-class by converterId : " + converterId);
1470         }
1471 
1472         try
1473         {
1474             final Converter converter = (Converter)converterClass.newInstance();
1475 
1476             setConverterProperties(converterClass, converter);
1477             
1478             _handleAttachedResourceDependencyAnnotations(FacesContext.getCurrentInstance(), converter);
1479 
1480             return converter;
1481         }
1482         catch (Exception e)
1483         {
1484             log.log(Level.SEVERE, "Could not instantiate converter " + converterClass, e);
1485             throw new FacesException("Could not instantiate converter: " + converterClass, e);
1486         }
1487     }
1488 
1489     @Override
1490     public final Converter createConverter(final Class<?> targetClass)
1491     {
1492         checkNull(targetClass, "targetClass");
1493 
1494         return internalCreateConverter(targetClass);
1495     }
1496 
1497     @SuppressWarnings("unchecked")
1498     private Converter internalCreateConverter(final Class<?> targetClass)
1499     {
1500         // Locate a Converter registered for the target class itself.
1501         Object converterClassOrClassName = _converterTargetClassToConverterClassMap.get(targetClass);
1502         
1503         // Locate a Converter registered for interfaces that are
1504         // implemented by the target class (directly or indirectly).
1505         // Skip if class is String, for performance reasons 
1506         // (save 3 additional lookups over a concurrent map per request). 
1507         if (converterClassOrClassName == null && !String.class.equals(targetClass))
1508         {
1509             final Class<?> interfaces[] = targetClass.getInterfaces();
1510             if (interfaces != null)
1511             {
1512                 for (int i = 0, len = interfaces.length; i < len; i++)
1513                 {
1514                     // search all superinterfaces for a matching converter,
1515                     // create it
1516                     final Converter converter = internalCreateConverter(interfaces[i]);
1517                     if (converter != null)
1518                     {
1519                         return converter;
1520                     }
1521                 }
1522             }
1523         }
1524 
1525         // Get EnumConverter for enum classes with no special converter, check
1526         // here as recursive call with java.lang.Enum will not work
1527         if (converterClassOrClassName == null && targetClass.isEnum())
1528         {
1529             converterClassOrClassName = _converterTargetClassToConverterClassMap.get(Enum.class);
1530         }
1531 
1532         if (converterClassOrClassName != null)
1533         {
1534             try
1535             {
1536                 Class<? extends Converter> converterClass = null;
1537                 if (converterClassOrClassName instanceof Class<?>)
1538                 {
1539                     converterClass = (Class<? extends Converter>) converterClassOrClassName;
1540                 }
1541                 else if (converterClassOrClassName instanceof String)
1542                 {
1543                     converterClass = ClassUtils.simpleClassForName((String) converterClassOrClassName);
1544                     _converterTargetClassToConverterClassMap.put(targetClass, converterClass);
1545                 }
1546                 else
1547                 {
1548                     //object stored in the map for this id is an invalid type.  remove it and return null
1549                     _converterTargetClassToConverterClassMap.remove(targetClass);
1550                 }
1551                 
1552                 Converter converter = null;
1553                 
1554                 // check cached constructor information
1555                 if (!_noArgConstructorConverterClasses.contains(converterClass))
1556                 {
1557                     // the converter class either supports the one-arg constructor
1558                     // or has never been processed before
1559                     try
1560                     {
1561                         // look for a constructor that takes a single Class object
1562                         // See JSF 1.2 javadoc for Converter
1563                         Constructor<? extends Converter> constructor = converterClass
1564                                 .getConstructor(new Class[] { Class.class });
1565 
1566                         converter = constructor.newInstance(new Object[] { targetClass });
1567                     }
1568                     catch (Exception e)
1569                     {
1570                         // the constructor does not exist
1571                         // add the class to the no-arg constructor classes cache
1572                         _noArgConstructorConverterClasses.add(converterClass);
1573                         
1574                         // use no-arg constructor
1575                         converter = converterClass.newInstance();
1576                     }
1577                 }
1578                 else
1579                 {
1580                     // use no-arg constructor
1581                     converter = converterClass.newInstance();
1582                 }
1583 
1584                 setConverterProperties(converterClass, converter);
1585 
1586                 return converter;
1587             }
1588             catch (Exception e)
1589             {
1590                 log.log(Level.SEVERE, "Could not instantiate converter " + converterClassOrClassName.toString(), e);
1591                 throw new FacesException("Could not instantiate converter: " + converterClassOrClassName.toString(), e);
1592             }
1593         }
1594 
1595         // locate converter for primitive types
1596         if (targetClass == Long.TYPE)
1597         {
1598             return internalCreateConverter(Long.class);
1599         }
1600         else if (targetClass == Boolean.TYPE)
1601         {
1602             return internalCreateConverter(Boolean.class);
1603         }
1604         else if (targetClass == Double.TYPE)
1605         {
1606             return internalCreateConverter(Double.class);
1607         }
1608         else if (targetClass == Byte.TYPE)
1609         {
1610             return internalCreateConverter(Byte.class);
1611         }
1612         else if (targetClass == Short.TYPE)
1613         {
1614             return internalCreateConverter(Short.class);
1615         }
1616         else if (targetClass == Integer.TYPE)
1617         {
1618             return internalCreateConverter(Integer.class);
1619         }
1620         else if (targetClass == Float.TYPE)
1621         {
1622             return internalCreateConverter(Float.class);
1623         }
1624         else if (targetClass == Character.TYPE)
1625         {
1626             return internalCreateConverter(Character.class);
1627         }
1628 
1629         // Locate a Converter registered for the superclass (if any) of the
1630         // target class,
1631         // recursively working up the inheritance hierarchy.
1632         Class<?> superClazz = targetClass.getSuperclass();
1633 
1634         return superClazz != null ? internalCreateConverter(superClazz) : null;
1635 
1636     }
1637 
1638     private void setConverterProperties(final Class<?> converterClass, final Converter converter)
1639     {
1640         final org.apache.myfaces.config.element.Converter converterConfig = _runtimeConfig
1641                 .getConverterConfiguration(converterClass.getName());
1642         
1643         // if the converter is a DataTimeConverter, check the init param for the default timezone (since 2.0)
1644         if (converter instanceof DateTimeConverter && _dateTimeConverterDefaultTimeZoneIsSystemTimeZone)
1645         {    
1646             ((DateTimeConverter) converter).setTimeZone(TimeZone.getDefault());
1647         }
1648 
1649         if (converterConfig != null && converterConfig.getProperties().size() > 0)
1650         {
1651             for (Property property : converterConfig.getProperties())
1652             {
1653                 try
1654                 {
1655                     BeanUtils.setProperty(converter, property.getPropertyName(), property.getDefaultValue());
1656                 }
1657                 catch (Throwable th)
1658                 {
1659                     log.log(Level.SEVERE, "Initializing converter : " + converterClass.getName() + " with property : "
1660                             + property.getPropertyName() + " and value : " + property.getDefaultValue() + " failed.");
1661                 }
1662             }
1663         }
1664     }
1665     
1666     private void _handleAttachedResourceDependencyAnnotations(FacesContext context, Object inspected)
1667     {
1668         if (inspected == null)
1669         {
1670             return;
1671         }
1672         
1673         // This and only this method handles @ResourceDependency and @ResourceDependencies annotations
1674         // The source of these annotations is Class<?> inspectedClass.
1675         // Because Class<?> and its annotations cannot change
1676         // during request/response, it is sufficient to process Class<?> only once per view.
1677         RequestViewContext rvc = RequestViewContext.getCurrentInstance(context);
1678         Class<?> inspectedClass = inspected.getClass();
1679         if (rvc.isClassAlreadyProcessed(inspectedClass))
1680         {
1681             return;
1682         }
1683         boolean classAlreadyProcessed = false;
1684 
1685         
1686         List<ResourceDependency> dependencyList = null;
1687         boolean isCachedList = false;
1688         
1689         if(context.isProjectStage(ProjectStage.Production) && _classToResourceDependencyMap.containsKey(inspectedClass))
1690         {
1691             dependencyList = _classToResourceDependencyMap.get(inspectedClass);
1692             if(dependencyList == null)
1693             {
1694                 return; //class has been inspected and did not contain any resource dependency annotations
1695             }
1696             else if (dependencyList.isEmpty())
1697             {
1698                 return;
1699             }
1700             
1701             isCachedList = true;    // else annotations were found in the cache
1702         }
1703         
1704         if(dependencyList == null)  //not in production or the class hasn't been inspected yet
1705         {   
1706             ResourceDependency dependency = inspectedClass.getAnnotation(ResourceDependency.class);
1707             ResourceDependencies dependencies = inspectedClass.getAnnotation(ResourceDependencies.class);
1708             if(dependency != null || dependencies != null)
1709             {
1710                 //resource dependencies were found using one or both annotations, create and build a new list
1711                 dependencyList = new ArrayList<ResourceDependency>();
1712                 
1713                 if(dependency != null)
1714                 {
1715                     dependencyList.add(dependency);
1716                 }
1717                 
1718                 if(dependencies != null)
1719                 {
1720                     dependencyList.addAll(Arrays.asList(dependencies.value()));
1721                 }
1722             }
1723             else
1724             {
1725                 dependencyList = Collections.emptyList();
1726             }
1727         }
1728 
1729         //resource dependencies were found through inspection or from cache, handle them
1730         if (dependencyList != null && !dependencyList.isEmpty()) 
1731         {
1732             for (int i = 0, size = dependencyList.size(); i < size; i++)
1733             {
1734                 ResourceDependency dependency = dependencyList.get(i);
1735                 if (!rvc.isResourceDependencyAlreadyProcessed(dependency))
1736                 {
1737                     _handleAttachedResourceDependency(context, dependency);
1738                     rvc.setResourceDependencyAsProcessed(dependency);
1739                 }
1740             }
1741         }
1742         
1743         //if we're in production and the list is not yet cached, store it
1744         if(context.isProjectStage(ProjectStage.Production) && !isCachedList)   
1745         {
1746             // Note at this point listenerForList cannot be null, but just let this
1747             // as a sanity check.
1748             if (dependencyList != null)
1749             {
1750                 _classToResourceDependencyMap.put(inspectedClass, dependencyList);
1751             }
1752         }
1753         
1754         if (!classAlreadyProcessed)
1755         {
1756             rvc.setClassProcessed(inspectedClass);
1757         }
1758     }
1759     
1760     private void _handleAttachedResourceDependency(FacesContext context, ResourceDependency annotation)
1761     {
1762         // If this annotation is not present on the class in question, no action must be taken. 
1763         if (annotation != null)
1764         {
1765             Application application = context.getApplication();
1766             
1767             // Create a UIOutput instance by passing javax.faces.Output. to 
1768             // Application.createComponent(java.lang.String).
1769             UIOutput output = (UIOutput) application.createComponent(UIOutput.COMPONENT_TYPE);
1770             
1771             // Get the annotation instance from the class and obtain the values of the name, library, and 
1772             // target attributes.
1773             String name = annotation.name();
1774             if (name != null && name.length() > 0)
1775             {
1776                 name = ELText.parse(getExpressionFactory(),
1777                                     context.getELContext(), name).toString(context.getELContext());
1778             }
1779             
1780             // Obtain the renderer-type for the resource name by passing name to 
1781             // ResourceHandler.getRendererTypeForResourceName(java.lang.String).
1782             String rendererType = application.getResourceHandler().getRendererTypeForResourceName(name);
1783             
1784             // Call setRendererType on the UIOutput instance, passing the renderer-type.
1785             output.setRendererType(rendererType);
1786             
1787             // Obtain the Map of attributes from the UIOutput component by calling UIComponent.getAttributes().
1788             Map<String, Object> attributes = output.getAttributes();
1789             
1790             // Store the name into the attributes Map under the key "name".
1791             attributes.put("name", name);
1792             
1793             // If library is the empty string, let library be null.
1794             String library = annotation.library();
1795             if (library != null && library.length() > 0)
1796             {
1797                 library = ELText.parse(getExpressionFactory(),
1798                                        context.getELContext(), library).toString(context.getELContext());
1799                 // If library is non-null, store it under the key "library".
1800                 attributes.put("library", library);
1801             }
1802             
1803             // If target is the empty string, let target be null.
1804             String target = annotation.target();
1805             if (target != null && target.length() > 0)
1806             {
1807                 target = ELText.parse(getExpressionFactory(),
1808                                       context.getELContext(), target).toString(context.getELContext());
1809                 // If target is non-null, store it under the key "target".
1810                 attributes.put("target", target);
1811                 context.getViewRoot().addComponentResource(context, output, target);
1812             }
1813             else
1814             {
1815                 // Otherwise, if target is null, call 
1816                 // UIViewRoot.addComponentResource(javax.faces.context.FacesContext, 
1817                 // javax.faces.component.UIComponent), passing the UIOutput instance as the second argument.
1818                 context.getViewRoot().addComponentResource(context, output);
1819             }
1820         }
1821     }
1822 
1823     // Note: this method used to be synchronized in the JSF 1.1 version. Why?
1824     /**
1825      * @deprecated
1826      */
1827     @Deprecated
1828     @Override
1829     public final MethodBinding createMethodBinding(final String reference, Class<?>[] params)
1830             throws ReferenceSyntaxException
1831     {
1832         checkNull(reference, "reference");
1833         checkEmpty(reference, "reference");
1834 
1835         // TODO: this check should be performed by the expression factory. It is
1836         // a requirement of the TCK
1837         if (!(reference.startsWith("#{") && reference.endsWith("}")))
1838         {
1839             throw new ReferenceSyntaxException("Invalid method reference: '" + reference + "'");
1840         }
1841 
1842         if (params == null)
1843         {
1844             params = new Class[0];
1845         }
1846 
1847         MethodExpression methodExpression;
1848 
1849         try
1850         {
1851             methodExpression = getExpressionFactory().createMethodExpression(threadELContext(), reference,
1852                                                                              Object.class, params);
1853         }
1854         catch (ELException e)
1855         {
1856             throw new ReferenceSyntaxException(e);
1857         }
1858 
1859         return new MethodExpressionToMethodBinding(methodExpression);
1860     }
1861 
1862     @Override
1863     public final Validator createValidator(final String validatorId) throws FacesException
1864     {
1865         checkNull(validatorId, "validatorId");
1866         checkEmpty(validatorId, "validatorId");
1867 
1868         Class<?> validatorClass = getObjectFromClassMap(validatorId, _validatorClassMap);
1869         if (validatorClass == null)
1870         {
1871             String message = "Unknown validator id '" + validatorId + "'.";
1872             log.severe(message);
1873             throw new FacesException(message);
1874         }
1875 
1876         try
1877         {
1878             Validator validator = (Validator) validatorClass.newInstance();
1879             
1880             _handleAttachedResourceDependencyAnnotations(FacesContext.getCurrentInstance(), validator);
1881             
1882             return validator;
1883         }
1884         catch (Exception e)
1885         {
1886             log.log(Level.SEVERE, "Could not instantiate validator " + validatorClass, e);
1887             throw new FacesException("Could not instantiate validator: " + validatorClass, e);
1888         }
1889     }
1890 
1891     /**
1892      * @deprecated
1893      */
1894     @Override
1895     public final ValueBinding createValueBinding(final String reference) throws ReferenceSyntaxException
1896     {
1897         checkNull(reference, "reference");
1898         checkEmpty(reference, "reference");
1899 
1900         ValueExpression valueExpression;
1901 
1902         try
1903         {
1904             valueExpression = getExpressionFactory().createValueExpression(
1905                     threadELContext(), reference, Object.class);
1906         }
1907         catch (ELException e)
1908         {
1909             throw new ReferenceSyntaxException(e);
1910         }
1911 
1912         return new ValueExpressionToValueBinding(valueExpression);
1913     }
1914 
1915     // gets the elContext from the current FacesContext()
1916     private final ELContext threadELContext()
1917     {
1918         return getFaceContext().getELContext();
1919     }
1920 
1921     @Override
1922     public final String getDefaultRenderKitId()
1923     {
1924         return _defaultRenderKitId;
1925     }
1926 
1927     @Override
1928     public final void setDefaultRenderKitId(final String defaultRenderKitId)
1929     {
1930         _defaultRenderKitId = defaultRenderKitId;
1931     }
1932 
1933     @Override
1934     public final StateManager getStateManager()
1935     {
1936         return _stateManager;
1937     }
1938 
1939     @Override
1940     public final void setStateManager(final StateManager stateManager)
1941     {
1942         checkNull(stateManager, "stateManager");
1943 
1944         if(isFirstRequestProcessed())
1945         {
1946             throw new IllegalStateException(
1947                     "setStateManager may not be executed after a lifecycle request has been completed");
1948         }
1949         
1950         _stateManager = stateManager;
1951     }
1952 
1953     private void checkNull(final Object param, final String paramName)
1954     {
1955         if (param == null)
1956         {
1957             throw new NullPointerException(paramName + " cannot be null.");
1958         }
1959     }
1960 
1961     private void checkEmpty(final String param, final String paramName)
1962     {
1963         if (param.length() == 0)
1964         {
1965             throw new NullPointerException("String " + paramName + " cannot be empty.");
1966         }
1967     }
1968 
1969     private static SystemEvent _createEvent(Class<? extends SystemEvent> systemEventClass, Object source,
1970                                             SystemEvent event)
1971     {
1972         if (event == null)
1973         {
1974             try
1975             {
1976                 Constructor<?>[] constructors = systemEventClass.getConstructors();
1977                 Constructor<? extends SystemEvent> constructor = null;
1978                 for (Constructor<?> c : constructors)
1979                 {
1980                     if (c.getParameterTypes().length == 1)
1981                     {
1982                         // Safe cast, since the constructor belongs
1983                         // to a class of type SystemEvent
1984                         constructor = (Constructor<? extends SystemEvent>) c;
1985                         break;
1986                     }
1987                 }
1988                 if (constructor != null)
1989                 {
1990                     event = constructor.newInstance(source);
1991                 }
1992 
1993             }
1994             catch (Exception e)
1995             {
1996                 throw new FacesException("Couldn't instanciate system event of type " + 
1997                         systemEventClass.getName(), e);
1998             }
1999         }
2000 
2001         return event;
2002     }
2003 
2004     private void _handleAnnotations(FacesContext context, Object inspected, UIComponent component)
2005     {   
2006         // determine the ProjectStage setting via the given FacesContext
2007         // note that a local getProjectStage() could cause problems in wrapped environments
2008         boolean isProduction = context.isProjectStage(ProjectStage.Production);
2009         
2010         Class<?> inspectedClass = inspected.getClass();
2011         _handleListenerForAnnotations(context, inspected, inspectedClass, component, isProduction);
2012 
2013         _handleResourceDependencyAnnotations(context, inspectedClass, component, isProduction);
2014     }
2015     
2016     private void _handleListenerForAnnotations(FacesContext context, Object inspected, Class<?> inspectedClass,
2017                                                UIComponent component, boolean isProduction)
2018     {
2019         List<ListenerFor> listenerForList = null;
2020         boolean isCachedList = false;
2021         
2022         if(isProduction && _classToListenerForMap.containsKey(inspectedClass))
2023         {
2024             listenerForList = _classToListenerForMap.get(inspectedClass);
2025             if(listenerForList == null)
2026             {
2027                 return; //class has been inspected and did not contain any listener annotations
2028             }
2029             else if (listenerForList.isEmpty())
2030             {
2031                 return;
2032             }
2033             
2034             isCachedList = true;    // else annotations were found in the cache
2035         }
2036 
2037         if(listenerForList == null) //not in production or the class hasn't been inspected yet
2038         {
2039             ListenerFor listener = inspectedClass.getAnnotation(ListenerFor.class);
2040             ListenersFor listeners = inspectedClass.getAnnotation(ListenersFor.class);
2041             if(listener != null || listeners != null)
2042             {
2043                 //listeners were found using one or both annotations, create and build a new list
2044                 listenerForList = new ArrayList<ListenerFor>();
2045                 
2046                 if(listener != null)
2047                 {
2048                     listenerForList.add(listener);
2049                 }
2050                 
2051                 if(listeners != null)
2052                 {
2053                     listenerForList.addAll(Arrays.asList(listeners.value()));
2054                 }
2055             }
2056             else
2057             {
2058                 listenerForList = Collections.emptyList();
2059             }
2060         }        
2061  
2062         // listeners were found through inspection or from cache, handle them
2063         if (listenerForList != null && !listenerForList.isEmpty()) 
2064         {
2065             for (int i = 0, size = listenerForList.size(); i < size; i++)
2066             {
2067                 ListenerFor listenerFor = listenerForList.get(i);
2068                 _handleListenerFor(context, inspected, component, listenerFor);
2069             }
2070         }
2071         
2072         if(isProduction && !isCachedList) //if we're in production and the list is not yet cached, store it
2073         {
2074             // Note at this point listenerForList cannot be null, but just let this
2075             // as a sanity check.
2076             if (listenerForList != null)
2077             {
2078                 _classToListenerForMap.put(inspectedClass, listenerForList);
2079             }
2080         }
2081     }
2082 
2083     private void _handleListenerFor(FacesContext context, Object inspected, UIComponent component,
2084                                     ListenerFor annotation)
2085     {
2086         // If this annotation is not present on the class in question, no action must be taken.
2087         if (annotation != null)
2088         {
2089             // Determine the "target" on which to call subscribeToEvent.
2090             // If the class to which this annotation is attached implements ComponentSystemEventListener
2091             if (inspected instanceof ComponentSystemEventListener)
2092             {
2093                 // If the class to which this annotation is attached is a UIComponent instance, "target" is the
2094                 // UIComponent instance.
2095 
2096                 // If the class to which this annotation is attached is a Renderer instance, "target" is the
2097                 // UIComponent instance.
2098 
2099                 /*
2100                  * If "target" is a UIComponent call UIComponent.subscribeToEvent(Class, ComponentSystemEventListener)
2101                  * passing the systemEventClass() of the annotation as the first argument and the instance of the class
2102                  * to which this annotation is attached (which must implement ComponentSystemEventListener) as the
2103                  * second argument.
2104                  */
2105                 component.subscribeToEvent(annotation.systemEventClass(), (ComponentSystemEventListener) inspected);
2106             }
2107             // If the class to which this annotation is attached implements SystemEventListener and does not implement
2108             // ComponentSystemEventListener, "target" is the Application instance.
2109             else if (component instanceof SystemEventListener)
2110             {
2111                 // use the Application object from the FacesContext (note that a
2112                 // direct use of subscribeToEvent() could cause problems if the
2113                 // Application is wrapped)
2114                 Application application = context.getApplication();
2115                 
2116                 // If "target" is the Application instance, inspect the value of the sourceClass() annotation attribute
2117                 // value.
2118                 if (Void.class.equals(annotation.sourceClass()))
2119                 {
2120                     /*
2121                      * If the value is Void.class, call Application.subscribeToEvent(Class, SystemEventListener),
2122                      * passing the value of systemEventClass() as the first argument and the instance of the class to
2123                      * which this annotation is attached (which must implement SystemEventListener) as the second
2124                      * argument.
2125                      */
2126                     application.subscribeToEvent(annotation.systemEventClass(), (SystemEventListener) inspected);
2127                 }
2128                 else
2129                 {
2130                     /*
2131                      * Otherwise, call Application.subscribeToEvent(Class, Class, SystemEventListener), passing the
2132                      * value of systemEventClass() as the first argument, the value of sourceClass() as the second
2133                      * argument, and the instance of the class to which this annotation is attached (which must
2134                      * implement SystemEventListener) as the third argument.
2135                      */
2136                     application.subscribeToEvent(annotation.systemEventClass(), annotation.sourceClass(),
2137                                      (SystemEventListener) inspected);
2138                 }
2139             }
2140 
2141             /*
2142              * If the class to which this annotation is attached implements ComponentSystemEventListener and is neither
2143              * an instance of Renderer nor UIComponent, the action taken is unspecified. This case must not trigger any
2144              * kind of error.
2145              */
2146         }
2147     }
2148 
2149     private void _handleResourceDependencyAnnotations(FacesContext context, Class<?> inspectedClass,
2150                                                       UIComponent component, boolean isProduction)
2151     {
2152         // This and only this method handles @ResourceDependency and @ResourceDependencies annotations
2153         // The source of these annotations is Class<?> inspectedClass.
2154         // Because Class<?> and its annotations cannot change
2155         // during request/response, it is sufficient to process Class<?> only once per view.
2156         RequestViewContext rvc = RequestViewContext.getCurrentInstance(context);
2157         if (rvc.isClassAlreadyProcessed(inspectedClass))
2158         {
2159             return;
2160         }
2161         boolean classAlreadyProcessed = false;
2162 
2163         
2164         List<ResourceDependency> dependencyList = null;
2165         boolean isCachedList = false;
2166         
2167         if(isProduction && _classToResourceDependencyMap.containsKey(inspectedClass))
2168         {
2169             dependencyList = _classToResourceDependencyMap.get(inspectedClass);
2170             if(dependencyList == null)
2171             {
2172                 return; //class has been inspected and did not contain any resource dependency annotations
2173             }
2174             else if (dependencyList.isEmpty())
2175             {
2176                 return;
2177             }
2178             
2179             isCachedList = true;    // else annotations were found in the cache
2180         }
2181         
2182         if(dependencyList == null)  //not in production or the class hasn't been inspected yet
2183         {   
2184             ResourceDependency dependency = inspectedClass.getAnnotation(ResourceDependency.class);
2185             ResourceDependencies dependencies = inspectedClass.getAnnotation(ResourceDependencies.class);
2186             if(dependency != null || dependencies != null)
2187             {
2188                 //resource dependencies were found using one or both annotations, create and build a new list
2189                 dependencyList = new ArrayList<ResourceDependency>();
2190                 
2191                 if(dependency != null)
2192                 {
2193                     dependencyList.add(dependency);
2194                 }
2195                 
2196                 if(dependencies != null)
2197                 {
2198                     dependencyList.addAll(Arrays.asList(dependencies.value()));
2199                 }
2200             }
2201             else
2202             {
2203                 dependencyList = Collections.emptyList();
2204             }
2205         }        
2206  
2207         // resource dependencies were found through inspection or from cache, handle them
2208         if (dependencyList != null && !dependencyList.isEmpty()) 
2209         {
2210             for (int i = 0, size = dependencyList.size(); i < size; i++)
2211             {
2212                 ResourceDependency dependency = dependencyList.get(i);
2213                 if (!rvc.isResourceDependencyAlreadyProcessed(dependency))
2214                 {
2215                     _handleResourceDependency(context, component, dependency);
2216                     rvc.setResourceDependencyAsProcessed(dependency);
2217                 }
2218             }
2219         }
2220         
2221         if(isProduction && !isCachedList)   //if we're in production and the list is not yet cached, store it
2222         {
2223             // Note at this point listenerForList cannot be null, but just let this
2224             // as a sanity check.
2225             if (dependencyList != null)
2226             {
2227                 _classToResourceDependencyMap.put(inspectedClass, dependencyList);
2228             }
2229         }
2230         
2231         if (!classAlreadyProcessed)
2232         {
2233             rvc.setClassProcessed(inspectedClass);
2234         }
2235     }
2236     
2237     private void _handleResourceDependency(FacesContext context, UIComponent component, ResourceDependency annotation)
2238     {
2239         // If this annotation is not present on the class in question, no action must be taken.
2240         if (annotation != null)
2241         {
2242             // Create a UIOutput instance by passing javax.faces.Output. to
2243             // Application.createComponent(java.lang.String).
2244             UIOutput output = (UIOutput) createComponent(UIOutput.COMPONENT_TYPE);
2245 
2246             // Get the annotation instance from the class and obtain the values of the name, library, and
2247             // target attributes.
2248             String name = annotation.name();
2249             if (name != null && name.length() > 0)
2250             {
2251                 name = ELText.parse(getExpressionFactory(),
2252                                     context.getELContext(), name).toString(context.getELContext());
2253             }
2254 
2255             // Obtain the renderer-type for the resource name by passing name to
2256             // ResourceHandler.getRendererTypeForResourceName(java.lang.String).
2257             // (note that we can not use this.getResourceHandler(), because the Application might be wrapped)
2258             String rendererType = context.getApplication().getResourceHandler().getRendererTypeForResourceName(name);
2259 
2260             // Call setRendererType on the UIOutput instance, passing the renderer-type.
2261             output.setRendererType(rendererType);
2262 
2263             // Obtain the Map of attributes from the UIOutput component by calling UIComponent.getAttributes().
2264             Map<String, Object> attributes = output.getAttributes();
2265 
2266             // Store the name into the attributes Map under the key "name".
2267             attributes.put("name", name);
2268 
2269             // If library is the empty string, let library be null.
2270             String library = annotation.library();
2271             if (library != null && library.length() > 0)
2272             {
2273                 library = ELText.parse(getExpressionFactory(),
2274                                        context.getELContext(), library).toString(context.getELContext());
2275                 // If library is non-null, store it under the key "library".
2276                 if ("this".equals(library))
2277                 {
2278                     // Special "this" behavior
2279                     Resource resource = (Resource)component.getAttributes().get(Resource.COMPONENT_RESOURCE_KEY);
2280                     if (resource != null)
2281                     {
2282                         attributes.put("library", resource.getLibraryName());
2283                     }
2284                 }
2285                 else
2286                 {
2287                     attributes.put("library", library);
2288                 }
2289             }
2290 
2291             // If target is the empty string, let target be null.
2292             String target = annotation.target();
2293             if (target != null && target.length() > 0)
2294             {
2295                 target = ELText.parse(getExpressionFactory(),
2296                                       context.getELContext(), target).toString(context.getELContext());
2297                 // If target is non-null, store it under the key "target".
2298                 attributes.put("target", target);
2299                 context.getViewRoot().addComponentResource(context, output, target);
2300             }
2301             else
2302             {
2303                 // Otherwise, if target is null, call UIViewRoot.addComponentResource(javax.faces.context.FacesContext,
2304                 // javax.faces.component.UIComponent), passing the UIOutput instance as the second argument.
2305                 context.getViewRoot().addComponentResource(context, output);
2306             }
2307         }
2308     }
2309     
2310     private void _inspectRenderer(FacesContext context, UIComponent component,
2311                                   String componentType, String rendererType)
2312     {
2313         /*
2314          * The Renderer instance to inspect must be obtained by calling FacesContext.getRenderKit() and calling
2315          * RenderKit.getRenderer(java.lang.String, java.lang.String) on the result, passing the argument componentFamily
2316          * of the newly created component as the first argument and the argument rendererType as the second argument.
2317          */
2318         Renderer renderer = context.getRenderKit().getRenderer(component.getFamily(), rendererType);
2319         if (renderer == null)
2320         {
2321             // If no such Renderer can be found, a message must be logged with a helpful error message.
2322             log.severe("renderer cannot be found for component type " + componentType + " and renderer type "
2323                     + rendererType);
2324         }
2325         else
2326         {
2327             // Otherwise, UIComponent.setRendererType(java.lang.String) must be called on the newly created
2328             // UIComponent instance, passing the argument rendererType as the argument.
2329             component.setRendererType(rendererType);
2330 
2331             /*
2332              * except the Renderer for the component to be returned must be inspected for the annotations mentioned in
2333              * createComponent(ValueExpression, FacesContext, String) as specified in the documentation for that method.
2334              */
2335             _handleAnnotations(context, renderer, component);
2336         }
2337     }
2338 
2339     private static SystemEvent _traverseListenerList(List<? extends SystemEventListener> listeners,
2340                                                      Class<? extends SystemEvent> systemEventClass, Object source,
2341                                                      SystemEvent event)
2342     {
2343         if (listeners != null && !listeners.isEmpty())
2344         {
2345             // perf: org.apache.myfaces.application.ApplicationImpl.
2346             //    SystemListenerEntry.getSpecificSourceListenersNotNull(Class<?>)
2347             // or javax.faces.component.UIComponent.subscribeToEvent(
2348             //      Class<? extends SystemEvent>, ComponentSystemEventListener)
2349             // creates a ArrayList:
2350             for (int i  = 0, size = listeners.size(); i < size; i++)
2351             {
2352                 SystemEventListener listener = listeners.get(i);
2353                 // Call SystemEventListener.isListenerForSource(java.lang.Object), passing the source argument.
2354                 // If this returns false, take no action on the listener.
2355                 if (listener.isListenerForSource(source))
2356                 {
2357                     // Otherwise, if the event to be passed to the listener instances has not yet been constructed,
2358                     // construct the event, passing source as the argument to the one-argument constructor that takes
2359                     // an Object. This same event instance must be passed to all listener instances.
2360                     event = _createEvent(systemEventClass, source, event);
2361 
2362                     // Call SystemEvent.isAppropriateListener(javax.faces.event.FacesListener), passing the listener
2363                     // instance as the argument. If this returns false, take no action on the listener.
2364                     if (event.isAppropriateListener(listener))
2365                     {
2366                         // Call SystemEvent.processListener(javax.faces.event.FacesListener), passing the listener
2367                         // instance.
2368                         event.processListener(listener);
2369                     }
2370                 }
2371             }
2372         }
2373 
2374         return event;
2375     }
2376     
2377     private static SystemEvent _traverseListenerListWithCopy(List<? extends SystemEventListener> listeners,
2378             Class<? extends SystemEvent> systemEventClass, Object source,
2379             SystemEvent event)
2380     {
2381         if (listeners != null && !listeners.isEmpty())
2382         {
2383             List<SystemEventListener> listenersCopy = new ArrayList<SystemEventListener>();
2384             int processedListenerIndex = 0;
2385             
2386             for (int i = 0; i < listeners.size(); i++)
2387             {
2388                 listenersCopy.add(listeners.get(i));
2389             }
2390             
2391             // If the inner for is succesful, processedListenerIndex == listenersCopy.size()
2392             // and the loop will be complete.
2393             while (processedListenerIndex < listenersCopy.size())
2394             {                
2395                 for (; processedListenerIndex < listenersCopy.size(); processedListenerIndex++ )
2396                 {
2397                     SystemEventListener listener = listenersCopy.get(processedListenerIndex);
2398                     // Call SystemEventListener.isListenerForSource(java.lang.Object), passing the source argument.
2399                     // If this returns false, take no action on the listener.
2400                     if (listener.isListenerForSource(source))
2401                     {
2402                         // Otherwise, if the event to be passed to the listener instances has not yet been constructed,
2403                         // construct the event, passing source as the argument
2404                         // to the one-argument constructor that takes
2405                         // an Object. This same event instance must be passed to all listener instances.
2406                         event = _createEvent(systemEventClass, source, event);
2407     
2408                         // Call SystemEvent.isAppropriateListener(javax.faces.event.FacesListener), passing the listener
2409                         // instance as the argument. If this returns false, take no action on the listener.
2410                         if (event.isAppropriateListener(listener))
2411                         {
2412                             // Call SystemEvent.processListener(javax.faces.event.FacesListener), passing the listener
2413                             // instance.
2414                             event.processListener(listener);
2415                         }
2416                     }
2417                 }
2418                 
2419                 boolean listChanged = false;
2420                 if (listeners.size() == listenersCopy.size())
2421                 {
2422                     for (int i = 0; i < listenersCopy.size(); i++)
2423                     {
2424                         if (listenersCopy.get(i) != listeners.get(i))
2425                         {
2426                             listChanged = true;
2427                             break;
2428                         }
2429                     }
2430                 }
2431                 else
2432                 {
2433                     listChanged = true;
2434                 }
2435                 
2436                 if (listChanged)
2437                 {
2438                     for (int i = 0; i < listeners.size(); i++)
2439                     {
2440                         SystemEventListener listener = listeners.get(i);
2441                         
2442                         // check if listenersCopy.get(i) is valid
2443                         if (i < listenersCopy.size())
2444                         {
2445                             // The normal case is a listener was added, 
2446                             // so as heuristic, check first
2447                             // if we can find it at the same location
2448                             if (!listener.equals(listenersCopy.get(i)))
2449                             {
2450                                 if (!listenersCopy.contains(listener))
2451                                 {
2452                                     listenersCopy.add(listener);
2453                                 }
2454                             }
2455                         }
2456                         else
2457                         {
2458                             if (!listenersCopy.contains(listener))
2459                             {
2460                                 listenersCopy.add(listener);
2461                             }
2462                         }
2463                     }
2464                 }
2465             }
2466         }
2467 
2468         return event;
2469     }
2470 
2471     /**
2472      * Method to handle determining if the first request has 
2473      * been handled by the associated LifecycleImpl.
2474      * @return true if the first request has already been processed, false otherwise
2475      */
2476     private boolean isFirstRequestProcessed()
2477     {
2478         FacesContext context = FacesContext.getCurrentInstance();
2479         
2480         //if firstRequestProcessed is not set, check the application map
2481         if(!_firstRequestProcessed && context != null 
2482                 && Boolean.TRUE.equals(context.getExternalContext().getApplicationMap()
2483                         .containsKey(LifecycleImpl.FIRST_REQUEST_PROCESSED_PARAM)))
2484         {
2485             _firstRequestProcessed = true;
2486         }
2487         return _firstRequestProcessed;
2488     }
2489     
2490     private static class SystemListenerEntry
2491     {
2492         private List<SystemEventListener> _lstSystemEventListener;
2493         private Map<Class<?>, List<SystemEventListener>> _sourceClassMap;
2494 
2495         public SystemListenerEntry()
2496         {
2497         }
2498 
2499         public void addListener(SystemEventListener listener)
2500         {
2501             assert listener != null;
2502 
2503             addListenerNoDuplicate(getAnySourceListenersNotNull(), listener);
2504         }
2505 
2506         public void addListener(SystemEventListener listener, Class<?> source)
2507         {
2508             assert listener != null;
2509 
2510             if (source == null)
2511             {
2512                 addListener(listener);
2513             }
2514             else
2515             {
2516                 addListenerNoDuplicate(getSpecificSourceListenersNotNull(source), listener);
2517             }
2518         }
2519 
2520         public void removeListener(SystemEventListener listener)
2521         {
2522             assert listener != null;
2523 
2524             if (_lstSystemEventListener != null)
2525             {
2526                 _lstSystemEventListener.remove(listener);
2527             }
2528         }
2529 
2530         public void removeListener(SystemEventListener listener, Class<?> sourceClass)
2531         {
2532             assert listener != null;
2533 
2534             if (sourceClass == null)
2535             {
2536                 removeListener(listener);
2537             }
2538             else
2539             {
2540                 if (_sourceClassMap != null)
2541                 {
2542                     List<SystemEventListener> listeners = _sourceClassMap.get(sourceClass);
2543                     if (listeners != null)
2544                     {
2545                         listeners.remove(listener);
2546                     }
2547                 }
2548             }
2549         }
2550 
2551         public void publish(Class<? extends SystemEvent> systemEventClass, Class<?> classSource, Object source,
2552                             SystemEvent event)
2553         {
2554             if (source != null && _sourceClassMap != null)
2555             {
2556                 event = _traverseListenerList(_sourceClassMap.get(classSource), systemEventClass, source, event);
2557             }
2558 
2559             _traverseListenerList(_lstSystemEventListener, systemEventClass, source, event);
2560         }
2561 
2562         private void addListenerNoDuplicate(List<SystemEventListener> listeners, SystemEventListener listener)
2563         {
2564             if (!listeners.contains(listener))
2565             {
2566                 listeners.add(listener);
2567             }
2568         }
2569 
2570         private synchronized List<SystemEventListener> getAnySourceListenersNotNull()
2571         {
2572             if (_lstSystemEventListener == null)
2573             {
2574                 /*
2575                  * TODO: Check if modification occurs often or not, might have to use a synchronized list instead.
2576                  * 
2577                  * Registrations found:
2578                  */
2579                 _lstSystemEventListener = new CopyOnWriteArrayList<SystemEventListener>();
2580             }
2581 
2582             return _lstSystemEventListener;
2583         }
2584 
2585         private synchronized List<SystemEventListener> getSpecificSourceListenersNotNull(Class<?> sourceClass)
2586         {
2587             if (_sourceClassMap == null)
2588             {
2589                 _sourceClassMap = new ConcurrentHashMap<Class<?>, List<SystemEventListener>>();
2590             }
2591 
2592             List<SystemEventListener> list = _sourceClassMap.get(sourceClass);
2593             if (list == null)
2594             {
2595                 /*
2596                  * TODO: Check if modification occurs often or not, might have to use a synchronized list instead.
2597                  * 
2598                  * Registrations found:
2599                  */
2600                 list = new CopyOnWriteArrayList<SystemEventListener>();
2601                 _sourceClassMap.put(sourceClass, list);
2602             }
2603 
2604             return list;
2605         }
2606     }
2607     
2608     /*
2609      * private method to look for config objects on a classmap.  The objects can be either a type string
2610      * or a Class<?> object.  This is done to facilitate lazy loading of config objects.   
2611      * @param id 
2612      * @param classMap 
2613      * @return
2614      */
2615     private Class<?> getObjectFromClassMap(String id, Map<String, Object> classMap)
2616     {
2617         Object obj = classMap.get(id);
2618         
2619         if(obj == null)
2620         {
2621             return null;    //object for this id wasn't found on the map
2622         }
2623         
2624         if(obj instanceof Class<?>)
2625         {
2626             return (Class<?>)obj;
2627         }
2628         else if (obj instanceof String )
2629         {
2630             Class<?> clazz = ClassUtils.simpleClassForName((String)obj);
2631             classMap.put(id, clazz);
2632             return clazz;
2633         }
2634         
2635         //object stored in the map for this id is an invalid type.  remove it and return null
2636         classMap.remove(id);
2637         return null;        
2638     }
2639     
2640     private boolean isLazyLoadConfigObjects()
2641     {
2642         if (_lazyLoadConfigObjects == null)
2643         {
2644             String configParam
2645                     = getFaceContext().getExternalContext().getInitParameter(LAZY_LOAD_CONFIG_OBJECTS_PARAM_NAME);
2646             _lazyLoadConfigObjects = configParam == null
2647                                      ? LAZY_LOAD_CONFIG_OBJECTS_DEFAULT_VALUE
2648                                      : Boolean.parseBoolean(configParam);
2649         }
2650         return _lazyLoadConfigObjects;
2651     }
2652 }