View Javadoc

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