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