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